diff --git a/app/build.gradle b/app/build.gradle index 54dd930c00..724763dadc 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -128,8 +128,6 @@ android { testInstrumentationRunnerArgument "TEST_SERVER_PASSWORD", "${NC_TEST_SERVER_PASSWORD}" testInstrumentationRunnerArguments disableAnalytics: 'true' - multiDexEnabled true - versionCode versionMajor * 10000000 + versionMinor * 10000 + versionPatch * 100 + versionBuild if (versionBuild > 89) { @@ -265,8 +263,6 @@ android { } dependencies { - // dependencies for app building - implementation 'androidx.multidex:multidex:2.0.1' implementation("com.github.nextcloud:android-library:$androidLibraryVersion") { exclude group: 'org.ogce', module: 'xpp3' // unused in Android and brings wrong Junit version } diff --git a/app/src/main/java/com/nextcloud/client/account/UserAccountManagerImpl.java b/app/src/main/java/com/nextcloud/client/account/UserAccountManagerImpl.java index c6d00ce8de..40709c984c 100644 --- a/app/src/main/java/com/nextcloud/client/account/UserAccountManagerImpl.java +++ b/app/src/main/java/com/nextcloud/client/account/UserAccountManagerImpl.java @@ -18,6 +18,7 @@ import android.content.Intent; import android.content.SharedPreferences; import android.preference.PreferenceManager; import android.text.TextUtils; +import android.util.Log; import com.nextcloud.common.NextcloudClient; import com.owncloud.android.MainApp; @@ -52,10 +53,10 @@ public class UserAccountManagerImpl implements UserAccountManager { private static final String PREF_SELECT_OC_ACCOUNT = "select_oc_account"; private Context context; - private AccountManager accountManager; + private final AccountManager accountManager; public static UserAccountManagerImpl fromContext(Context context) { - AccountManager am = (AccountManager)context.getSystemService(Context.ACCOUNT_SERVICE); + AccountManager am = (AccountManager) context.getSystemService(Context.ACCOUNT_SERVICE); return new UserAccountManagerImpl(context, am); } @@ -181,7 +182,12 @@ public class UserAccountManagerImpl implements UserAccountManager { return null; } - OwnCloudAccount ownCloudAccount = null; + if (context == null) { + Log_OC.d(TAG, "Context is null MainApp.getAppContext() used"); + context = MainApp.getAppContext(); + } + + OwnCloudAccount ownCloudAccount; try { ownCloudAccount = new OwnCloudAccount(account, context); } catch (AccountUtils.AccountNotFoundException ex) { diff --git a/app/src/main/java/com/owncloud/android/MainApp.java b/app/src/main/java/com/owncloud/android/MainApp.java index f8088eaae4..049b25c7ca 100644 --- a/app/src/main/java/com/owncloud/android/MainApp.java +++ b/app/src/main/java/com/owncloud/android/MainApp.java @@ -91,6 +91,7 @@ import com.owncloud.android.utils.theme.ViewThemeUtils; import org.conscrypt.Conscrypt; import org.greenrobot.eventbus.EventBus; +import java.lang.ref.WeakReference; import java.lang.reflect.Method; import java.security.NoSuchAlgorithmException; import java.security.Security; @@ -114,7 +115,6 @@ import androidx.core.util.Pair; import androidx.lifecycle.Lifecycle; import androidx.lifecycle.LifecycleEventObserver; import androidx.lifecycle.ProcessLifecycleOwner; -import androidx.multidex.MultiDexApplication; import dagger.android.AndroidInjector; import dagger.android.DispatchingAndroidInjector; import dagger.android.HasAndroidInjector; @@ -129,14 +129,14 @@ import static com.owncloud.android.ui.activity.ContactsPreferenceActivity.PREFER * Main Application of the project. * Contains methods to build the "static" strings. These strings were before constants in different classes. */ -public class MainApp extends MultiDexApplication implements HasAndroidInjector { +public class MainApp extends Application implements HasAndroidInjector { public static final OwnCloudVersion OUTDATED_SERVER_VERSION = NextcloudVersion.nextcloud_26; public static final OwnCloudVersion MINIMUM_SUPPORTED_SERVER_VERSION = OwnCloudVersion.nextcloud_16; private static final String TAG = MainApp.class.getSimpleName(); public static final String DOT = "."; - private static Context mContext; + private static WeakReference appContext; private static String storagePath; @@ -208,7 +208,7 @@ public class MainApp extends MultiDexApplication implements HasAndroidInjector { * Temporary hack */ private static void initGlobalContext(Context context) { - mContext = context; + appContext = new WeakReference<>(context); } /** @@ -491,7 +491,7 @@ public class MainApp extends MultiDexApplication implements HasAndroidInjector { } public static void initContactsBackup(UserAccountManager accountManager, BackgroundJobManager backgroundJobManager) { - ArbitraryDataProvider arbitraryDataProvider = new ArbitraryDataProviderImpl(mContext); + ArbitraryDataProvider arbitraryDataProvider = new ArbitraryDataProviderImpl(appContext.get()); List users = accountManager.getAllUsers(); for (User user : users) { if (arbitraryDataProvider.getBooleanValue(user, PREFERENCE_CONTACTS_AUTOMATIC_BACKUP)) { @@ -609,7 +609,7 @@ public class MainApp extends MultiDexApplication implements HasAndroidInjector { preferences.setAutoUploadInit(true); } - FilesSyncHelper.scheduleFilesSyncForAllFoldersIfNeeded(mContext, syncedFolderProvider, backgroundJobManager); + FilesSyncHelper.scheduleFilesSyncForAllFoldersIfNeeded(appContext.get(), syncedFolderProvider, backgroundJobManager); FilesSyncHelper.restartUploadsIfNeeded( uploadsStorageManager, accountManager, @@ -705,11 +705,11 @@ public class MainApp extends MultiDexApplication implements HasAndroidInjector { } public static Context getAppContext() { - return MainApp.mContext; + return MainApp.appContext.get(); } public static void setAppContext(Context context) { - MainApp.mContext = context; + MainApp.appContext = new WeakReference<>(context); } public static String getStoragePath() { @@ -831,7 +831,7 @@ public class MainApp extends MultiDexApplication implements HasAndroidInjector { if (!preferences.isAutoUploadPathsUpdateEnabled()) { SyncedFolderProvider syncedFolderProvider = new SyncedFolderProvider(MainApp.getAppContext().getContentResolver(), preferences, clock); - syncedFolderProvider.updateAutoUploadPaths(mContext); + syncedFolderProvider.updateAutoUploadPaths(appContext.get()); } } diff --git a/app/src/main/java/com/owncloud/android/ui/activity/ReceiveExternalFilesActivity.java b/app/src/main/java/com/owncloud/android/ui/activity/ReceiveExternalFilesActivity.java index 883ba034c5..0370aadb3b 100755 --- a/app/src/main/java/com/owncloud/android/ui/activity/ReceiveExternalFilesActivity.java +++ b/app/src/main/java/com/owncloud/android/ui/activity/ReceiveExternalFilesActivity.java @@ -804,7 +804,8 @@ public class ReceiveExternalFilesActivity extends FileActivity private void startSyncFolderOperation(OCFile folder) { if (folder == null) { - throw new IllegalArgumentException("Folder must not be null"); + DisplayUtils.showSnackMessage(this, R.string.receive_external_files_activity_start_sync_folder_is_not_exists_message); + return; } long currentSyncTime = System.currentTimeMillis(); diff --git a/app/src/main/java/com/owncloud/android/ui/adapter/CertificateCombinedExceptionViewAdapter.java b/app/src/main/java/com/owncloud/android/ui/adapter/CertificateCombinedExceptionViewAdapter.java index 90e22f79c4..c19e9fc5d4 100644 --- a/app/src/main/java/com/owncloud/android/ui/adapter/CertificateCombinedExceptionViewAdapter.java +++ b/app/src/main/java/com/owncloud/android/ui/adapter/CertificateCombinedExceptionViewAdapter.java @@ -16,18 +16,20 @@ import com.owncloud.android.databinding.SslUntrustedCertLayoutBinding; import com.owncloud.android.lib.common.network.CertificateCombinedException; import com.owncloud.android.ui.dialog.SslUntrustedCertDialog; +import androidx.annotation.NonNull; + public class CertificateCombinedExceptionViewAdapter implements SslUntrustedCertDialog.ErrorViewAdapter { //private final static String TAG = CertificateCombinedExceptionViewAdapter.class.getSimpleName(); - private CertificateCombinedException mSslException; + private final CertificateCombinedException mSslException; public CertificateCombinedExceptionViewAdapter(CertificateCombinedException sslException) { mSslException = sslException; } @Override - public void updateErrorView(SslUntrustedCertLayoutBinding binding) { + public void updateErrorView(@NonNull SslUntrustedCertLayoutBinding binding) { /// clean binding.reasonNoInfoAboutError.setVisibility(View.GONE); diff --git a/app/src/main/java/com/owncloud/android/ui/adapter/SslCertificateViewAdapter.java b/app/src/main/java/com/owncloud/android/ui/adapter/SslCertificateViewAdapter.java index 2f44b0c111..1e12f3dbef 100644 --- a/app/src/main/java/com/owncloud/android/ui/adapter/SslCertificateViewAdapter.java +++ b/app/src/main/java/com/owncloud/android/ui/adapter/SslCertificateViewAdapter.java @@ -24,7 +24,7 @@ public class SslCertificateViewAdapter implements SslUntrustedCertDialog.Certifi //private final static String TAG = SslCertificateViewAdapter.class.getSimpleName(); - private SslCertificate mCertificate; + private final SslCertificate mCertificate; /** * Constructor @@ -36,7 +36,7 @@ public class SslCertificateViewAdapter implements SslUntrustedCertDialog.Certifi } @Override - public void updateCertificateView(SslUntrustedCertLayoutBinding binding) { + public void updateCertificateView(@NonNull SslUntrustedCertLayoutBinding binding) { if (mCertificate != null) { binding.nullCert.setVisibility(View.GONE); showSubject(mCertificate.getIssuedTo(), binding); diff --git a/app/src/main/java/com/owncloud/android/ui/adapter/SslErrorViewAdapter.java b/app/src/main/java/com/owncloud/android/ui/adapter/SslErrorViewAdapter.java index faffd2ada5..c03ac5d03e 100644 --- a/app/src/main/java/com/owncloud/android/ui/adapter/SslErrorViewAdapter.java +++ b/app/src/main/java/com/owncloud/android/ui/adapter/SslErrorViewAdapter.java @@ -14,6 +14,8 @@ import android.view.View; import com.owncloud.android.databinding.SslUntrustedCertLayoutBinding; import com.owncloud.android.ui.dialog.SslUntrustedCertDialog; +import androidx.annotation.NonNull; + /** * Dialog to show an Untrusted Certificate */ @@ -21,14 +23,14 @@ public class SslErrorViewAdapter implements SslUntrustedCertDialog.ErrorViewAdap //private final static String TAG = SslErrorViewAdapter.class.getSimpleName(); - private SslError mSslError; + private final SslError mSslError; public SslErrorViewAdapter(SslError sslError) { mSslError = sslError; } @Override - public void updateErrorView(SslUntrustedCertLayoutBinding binding) { + public void updateErrorView(@NonNull SslUntrustedCertLayoutBinding binding) { /// clean binding.reasonNoInfoAboutError.setVisibility(View.GONE); diff --git a/app/src/main/java/com/owncloud/android/ui/adapter/X509CertificateViewAdapter.java b/app/src/main/java/com/owncloud/android/ui/adapter/X509CertificateViewAdapter.java index ac4c1a8af8..76834bdf78 100644 --- a/app/src/main/java/com/owncloud/android/ui/adapter/X509CertificateViewAdapter.java +++ b/app/src/main/java/com/owncloud/android/ui/adapter/X509CertificateViewAdapter.java @@ -37,7 +37,7 @@ import androidx.annotation.NonNull; */ public class X509CertificateViewAdapter implements SslUntrustedCertDialog.CertificateViewAdapter { - private X509Certificate mCertificate; + private final X509Certificate mCertificate; private static final String TAG = X509CertificateViewAdapter.class.getSimpleName(); @@ -46,7 +46,7 @@ public class X509CertificateViewAdapter implements SslUntrustedCertDialog.Certif } @Override - public void updateCertificateView(SslUntrustedCertLayoutBinding binding) { + public void updateCertificateView(@NonNull SslUntrustedCertLayoutBinding binding) { if (mCertificate != null) { binding.nullCert.setVisibility(View.GONE); showSubject(mCertificate.getSubjectX500Principal(), binding); @@ -97,7 +97,7 @@ public class X509CertificateViewAdapter implements SslUntrustedCertDialog.Certif private String getDigestHexBytesWithColonsAndNewLines(Context context, final String digestType, final byte [] cert) { final byte[] rawDigest; - final String newLine = System.getProperty("line.separator"); + final String newLine = System.lineSeparator(); rawDigest = getDigest(digestType, cert); diff --git a/app/src/main/java/com/owncloud/android/ui/dialog/SslUntrustedCertDialog.java b/app/src/main/java/com/owncloud/android/ui/dialog/SslUntrustedCertDialog.java deleted file mode 100644 index 0ed7a785eb..0000000000 --- a/app/src/main/java/com/owncloud/android/ui/dialog/SslUntrustedCertDialog.java +++ /dev/null @@ -1,215 +0,0 @@ -/* - * Nextcloud - Android Client - * - * SPDX-FileCopyrightText: 2022 Álvaro Brey - * SPDX-FileCopyrightText: 2018-2022 Andy Scherzinger - * SPDX-FileCopyrightText: 2020 Stefan Niedermann - * SPDX-FileCopyrightText: 2018 Tobias Kaminsky - * SPDX-FileCopyrightText: 2015 ownCloud Inc. - * SPDX-FileCopyrightText: 2014 David A. Velasco - * SPDX-FileCopyrightText: 2014 María Asensio Valverde - * SPDX-License-Identifier: GPL-2.0-only AND (AGPL-3.0-or-later OR GPL-2.0-only) - */ -package com.owncloud.android.ui.dialog; - -import android.app.Activity; -import android.app.Dialog; -import android.net.http.SslError; -import android.os.Bundle; -import android.view.View; -import android.view.View.OnClickListener; -import android.view.Window; -import android.webkit.SslErrorHandler; -import android.widget.Button; - -import com.google.android.material.dialog.MaterialAlertDialogBuilder; -import com.nextcloud.client.di.Injectable; -import com.owncloud.android.R; -import com.owncloud.android.databinding.SslUntrustedCertLayoutBinding; -import com.owncloud.android.lib.common.network.CertificateCombinedException; -import com.owncloud.android.lib.common.network.NetworkUtils; -import com.owncloud.android.lib.common.utils.Log_OC; -import com.owncloud.android.ui.adapter.CertificateCombinedExceptionViewAdapter; -import com.owncloud.android.ui.adapter.SslCertificateViewAdapter; -import com.owncloud.android.ui.adapter.SslErrorViewAdapter; -import com.owncloud.android.ui.adapter.X509CertificateViewAdapter; -import com.owncloud.android.utils.theme.ViewThemeUtils; - -import java.io.IOException; -import java.security.GeneralSecurityException; -import java.security.cert.X509Certificate; - -import javax.inject.Inject; - -import androidx.annotation.NonNull; -import androidx.fragment.app.DialogFragment; - -/** - * Dialog to show information about an untrusted certificate and allow the user to decide trust on it or not. - * Abstract implementation of common functionality for different dialogs that get the information about the error and - * the certificate from different classes. - */ -public class SslUntrustedCertDialog extends DialogFragment implements Injectable { - - private final static String TAG = SslUntrustedCertDialog.class.getSimpleName(); - - @Inject ViewThemeUtils viewThemeUtils; - - protected SslUntrustedCertLayoutBinding binding; - protected SslErrorHandler mHandler; - protected X509Certificate m509Certificate; - - private ErrorViewAdapter mErrorViewAdapter; - private CertificateViewAdapter mCertificateViewAdapter; - - public static SslUntrustedCertDialog newInstanceForEmptySslError(SslError error, SslErrorHandler handler) { - if (error == null) { - throw new IllegalArgumentException("Trying to create instance with parameter error == null"); - } - if (handler == null) { - throw new IllegalArgumentException("Trying to create instance with parameter handler == null"); - } - SslUntrustedCertDialog dialog = new SslUntrustedCertDialog(); - dialog.mHandler = handler; - dialog.mErrorViewAdapter = new SslErrorViewAdapter(error); - dialog.mCertificateViewAdapter = new SslCertificateViewAdapter(error.getCertificate()); - return dialog; - } - - public static SslUntrustedCertDialog newInstanceForFullSslError(CertificateCombinedException sslException) { - if (sslException == null) { - throw new IllegalArgumentException("Trying to create instance with parameter sslException == null"); - } - SslUntrustedCertDialog dialog = new SslUntrustedCertDialog(); - dialog.m509Certificate = sslException.getServerCertificate(); - dialog.mErrorViewAdapter = new CertificateCombinedExceptionViewAdapter(sslException); - dialog.mCertificateViewAdapter = new X509CertificateViewAdapter(sslException.getServerCertificate()); - return dialog; - } - - public static SslUntrustedCertDialog newInstanceForFullSslError(X509Certificate cert, SslError error, SslErrorHandler handler) { - if (cert == null) { - throw new IllegalArgumentException("Trying to create instance with parameter cert == null"); - } - if (error == null) { - throw new IllegalArgumentException("Trying to create instance with parameter error == null"); - } - if (handler == null) { - throw new IllegalArgumentException("Trying to create instance with parameter handler == null"); - } - SslUntrustedCertDialog dialog = new SslUntrustedCertDialog(); - dialog.m509Certificate = cert; - dialog.mHandler = handler; - dialog.mErrorViewAdapter = new SslErrorViewAdapter(error); - dialog.mCertificateViewAdapter = new X509CertificateViewAdapter(cert); - return dialog; - } - - @Override - public void onAttach(@NonNull Activity activity) { - Log_OC.d(TAG, "onAttach"); - super.onAttach(activity); - if (!(activity instanceof OnSslUntrustedCertListener)) { - throw new IllegalArgumentException("The host activity must implement " + OnSslUntrustedCertListener.class.getCanonicalName()); - } - } - - @Override - public void onCreate(Bundle savedInstanceState) { - Log_OC.d(TAG, "onCreate, savedInstanceState is " + savedInstanceState); - super.onCreate(savedInstanceState); - setRetainInstance(true); // force to keep the state of the fragment on configuration changes (such as device rotations) - setCancelable(false); - binding = null; - } - - @NonNull - @Override - public Dialog onCreateDialog(Bundle savedInstanceState) { - Log_OC.d(TAG, "onCreateDialog, savedInstanceState is " + savedInstanceState); - - binding = SslUntrustedCertLayoutBinding.inflate(getLayoutInflater(), null, false); - binding.detailsScroll.setVisibility(View.GONE); - mErrorViewAdapter.updateErrorView(binding); - - binding.ok.setOnClickListener(new OnCertificateTrusted()); - - binding.cancel.setOnClickListener(new OnCertificateNotTrusted()); - - binding.detailsBtn.setOnClickListener(v -> { - if (binding.detailsScroll.getVisibility() == View.VISIBLE) { - binding.detailsScroll.setVisibility(View.GONE); - ((Button) v).setText(R.string.ssl_validator_btn_details_see); - - } else { - binding.detailsScroll.setVisibility(View.VISIBLE); - ((Button) v).setText(R.string.ssl_validator_btn_details_hide); - mCertificateViewAdapter.updateCertificateView(binding); - } - }); - - - MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(binding.getRoot().getContext()); - builder.setView(binding.getRoot()); - - viewThemeUtils.dialog.colorMaterialAlertDialogBackground(binding.getRoot().getContext(), builder); - - final Dialog dialog = builder.create(); - dialog.requestWindowFeature(Window.FEATURE_NO_TITLE); - return dialog; - } - - @Override - public void onDestroyView() { - Log_OC.d(TAG, "onDestroyView"); - if (getDialog() != null && getRetainInstance()) { - getDialog().setDismissMessage(null); - } - super.onDestroyView(); - } - - private class OnCertificateNotTrusted implements OnClickListener { - - @Override - public void onClick(View v) { - getDialog().cancel(); - if (mHandler != null) { - mHandler.cancel(); - } - } - } - - private class OnCertificateTrusted implements OnClickListener { - - @Override - public void onClick(View v) { - dismiss(); - if (mHandler != null) { - mHandler.proceed(); - } - if (m509Certificate != null) { - Activity activity = getActivity(); - try { - NetworkUtils.addCertToKnownServersStore(m509Certificate, activity); // TODO make this asynchronously, it can take some time - ((OnSslUntrustedCertListener)activity).onSavedCertificate(); - } catch (GeneralSecurityException | IOException e) { - ((OnSslUntrustedCertListener)activity).onFailedSavingCertificate(); - Log_OC.e(TAG, "Server certificate could not be saved in the known-servers trust store ", e); - } - } - } - } - - public interface OnSslUntrustedCertListener { - void onSavedCertificate(); - void onFailedSavingCertificate(); - } - - public interface ErrorViewAdapter { - void updateErrorView(SslUntrustedCertLayoutBinding binding); - } - - public interface CertificateViewAdapter { - void updateCertificateView(SslUntrustedCertLayoutBinding binding); - } -} diff --git a/app/src/main/java/com/owncloud/android/ui/dialog/SslUntrustedCertDialog.kt b/app/src/main/java/com/owncloud/android/ui/dialog/SslUntrustedCertDialog.kt new file mode 100644 index 0000000000..76bd0aaea8 --- /dev/null +++ b/app/src/main/java/com/owncloud/android/ui/dialog/SslUntrustedCertDialog.kt @@ -0,0 +1,213 @@ +/* + * Nextcloud - Android Client + * + * SPDX-FileCopyrightText: 2022 Álvaro Brey + * SPDX-FileCopyrightText: 2018-2022 Andy Scherzinger + * SPDX-FileCopyrightText: 2020 Stefan Niedermann + * SPDX-FileCopyrightText: 2018 Tobias Kaminsky + * SPDX-FileCopyrightText: 2015 ownCloud Inc. + * SPDX-FileCopyrightText: 2014 David A. Velasco + * SPDX-FileCopyrightText: 2014 María Asensio Valverde + * SPDX-License-Identifier: GPL-2.0-only AND (AGPL-3.0-or-later OR GPL-2.0-only) + */ +package com.owncloud.android.ui.dialog + +import android.app.Dialog +import android.content.Context +import android.net.http.SslError +import android.os.Bundle +import android.view.View +import android.view.Window +import android.webkit.SslErrorHandler +import android.widget.Button +import androidx.fragment.app.DialogFragment +import com.google.android.material.dialog.MaterialAlertDialogBuilder +import com.nextcloud.client.di.Injectable +import com.owncloud.android.R +import com.owncloud.android.databinding.SslUntrustedCertLayoutBinding +import com.owncloud.android.lib.common.network.CertificateCombinedException +import com.owncloud.android.lib.common.network.NetworkUtils +import com.owncloud.android.lib.common.utils.Log_OC +import com.owncloud.android.ui.adapter.CertificateCombinedExceptionViewAdapter +import com.owncloud.android.ui.adapter.SslCertificateViewAdapter +import com.owncloud.android.ui.adapter.SslErrorViewAdapter +import com.owncloud.android.ui.adapter.X509CertificateViewAdapter +import com.owncloud.android.utils.theme.ViewThemeUtils +import java.io.IOException +import java.security.GeneralSecurityException +import java.security.cert.X509Certificate +import javax.inject.Inject + +/** + * Dialog to show information about an untrusted certificate and allow the user to decide trust on it or not. + * Abstract implementation of common functionality for different dialogs that get the information about the error and + * the certificate from different classes. + */ +open class SslUntrustedCertDialog : DialogFragment(), Injectable { + + @JvmField + @Inject + var viewThemeUtils: ViewThemeUtils? = null + + protected var binding: SslUntrustedCertLayoutBinding? = null + protected var sslErrorHandler: SslErrorHandler? = null + protected var x509Certificate: X509Certificate? = null + private var errorViewAdapter: ErrorViewAdapter? = null + private var certificateViewAdapter: CertificateViewAdapter? = null + + override fun onAttach(context: Context) { + Log_OC.d(TAG, "onAttach") + super.onAttach(context) + require(activity is OnSslUntrustedCertListener) { + "The host activity must implement " + OnSslUntrustedCertListener::class.java.canonicalName + } + } + + override fun onCreate(savedInstanceState: Bundle?) { + Log_OC.d(TAG, "onCreate, savedInstanceState is $savedInstanceState") + super.onCreate(savedInstanceState) + + // force to keep the state of the fragment on configuration changes (such as device rotations) + retainInstance = true + isCancelable = false + binding = null + } + + override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { + Log_OC.d(TAG, "onCreateDialog, savedInstanceState is $savedInstanceState") + + val layoutBinding = SslUntrustedCertLayoutBinding.inflate(layoutInflater, null, false) + this.binding = layoutBinding + + layoutBinding.run { + detailsScroll.visibility = View.GONE + errorViewAdapter?.updateErrorView(layoutBinding) + + ok.setOnClickListener(OnCertificateTrusted()) + + cancel.setOnClickListener(OnCertificateNotTrusted()) + + detailsBtn.setOnClickListener { v: View -> + if (detailsScroll.visibility == View.VISIBLE) { + detailsScroll.visibility = View.GONE + (v as Button).setText(R.string.ssl_validator_btn_details_see) + } else { + detailsScroll.visibility = View.VISIBLE + (v as Button).setText(R.string.ssl_validator_btn_details_hide) + certificateViewAdapter?.updateCertificateView(layoutBinding) + } + } + } + + val builder = MaterialAlertDialogBuilder(requireContext()).apply { + setView(layoutBinding.getRoot()) + } + + viewThemeUtils?.dialog?.colorMaterialAlertDialogBackground(requireContext(), builder) + + return builder.create().apply { + requestWindowFeature(Window.FEATURE_NO_TITLE) + } + } + + override fun onDestroyView() { + Log_OC.d(TAG, "onDestroyView") + if (retainInstance) { + dialog?.setDismissMessage(null) + } + super.onDestroyView() + } + + private inner class OnCertificateNotTrusted : View.OnClickListener { + override fun onClick(v: View) { + dialog?.cancel() + sslErrorHandler?.cancel() + } + } + + private inner class OnCertificateTrusted : View.OnClickListener { + override fun onClick(v: View) { + dismiss() + sslErrorHandler?.proceed() + + if (x509Certificate == null) { + Log_OC.d(TAG, "m509Certificate is null onClick dismissed") + return + } + + if (activity == null) { + Log_OC.d(TAG, "activity is null onClick dismissed") + return + } + + try { + // TODO make this asynchronously, it can take some time + NetworkUtils.addCertToKnownServersStore(x509Certificate, activity) + (activity as OnSslUntrustedCertListener?)?.onSavedCertificate() + } catch (e: GeneralSecurityException) { + (activity as OnSslUntrustedCertListener?)?.onFailedSavingCertificate() + Log_OC.e(TAG, "Server certificate could not be saved in the known-servers trust store ", e) + } catch (e: IOException) { + (activity as OnSslUntrustedCertListener?)?.onFailedSavingCertificate() + Log_OC.e(TAG, "Server certificate could not be saved in the known-servers trust store ", e) + } + } + } + + interface OnSslUntrustedCertListener { + fun onSavedCertificate() + fun onFailedSavingCertificate() + } + + interface ErrorViewAdapter { + fun updateErrorView(binding: SslUntrustedCertLayoutBinding) + } + + interface CertificateViewAdapter { + fun updateCertificateView(binding: SslUntrustedCertLayoutBinding) + } + + companion object { + private val TAG: String = SslUntrustedCertDialog::class.java.simpleName + + @JvmStatic + fun newInstanceForEmptySslError(error: SslError?, handler: SslErrorHandler?): SslUntrustedCertDialog { + requireNotNull(error) { "Trying to create instance with parameter error == null" } + requireNotNull(handler) { "Trying to create instance with parameter handler == null" } + + return SslUntrustedCertDialog().apply { + sslErrorHandler = handler + errorViewAdapter = SslErrorViewAdapter(error) + certificateViewAdapter = SslCertificateViewAdapter(error.certificate) + } + } + + @JvmStatic + fun newInstanceForFullSslError(sslException: CertificateCombinedException?): SslUntrustedCertDialog { + requireNotNull(sslException) { "Trying to create instance with parameter sslException == null" } + + return SslUntrustedCertDialog().apply { + x509Certificate = sslException.serverCertificate + errorViewAdapter = CertificateCombinedExceptionViewAdapter(sslException) + certificateViewAdapter = X509CertificateViewAdapter(sslException.serverCertificate) + } + } + + fun newInstanceForFullSslError( + cert: X509Certificate?, + error: SslError?, + handler: SslErrorHandler? + ): SslUntrustedCertDialog { + requireNotNull(cert) { "Trying to create instance with parameter cert == null" } + requireNotNull(error) { "Trying to create instance with parameter error == null" } + requireNotNull(handler) { "Trying to create instance with parameter handler == null" } + + return SslUntrustedCertDialog().apply { + x509Certificate = cert + sslErrorHandler = handler + errorViewAdapter = SslErrorViewAdapter(error) + certificateViewAdapter = X509CertificateViewAdapter(cert) + } + } + } +} diff --git a/app/src/main/res/values-lv/strings.xml b/app/src/main/res/values-lv/strings.xml index 12cca01b27..155081a0d9 100644 --- a/app/src/main/res/values-lv/strings.xml +++ b/app/src/main/res/values-lv/strings.xml @@ -484,7 +484,7 @@ Augšupielādē datnes Dzēst Augšupielādes nav pieejamas. - Augšupielādē kaut ko vai ieslēdz automātisko augšupielādi. + Augšupielādē kaut ko vai ieslēdz automātisko augšupielādi! Nepietiekama atmiņa neatļauj izvēlētās datnes kopēt uz %1$s mapi. Vai jūs gribat tās tur pārvietot? Nezināma kļūda Izvēlies diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index a9697e5e2d..63679a057b 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -448,6 +448,8 @@ Unexpected error while copying to clipboard Text copied from %1$s + Folder cannot be found, sync operation is cancelled + Critical error: Unable to perform operations An error occurred during connection to the server diff --git a/scripts/analysis/lint-results.txt b/scripts/analysis/lint-results.txt index e53927d3c7..3e0520e4c5 100644 --- a/scripts/analysis/lint-results.txt +++ b/scripts/analysis/lint-results.txt @@ -1,2 +1,2 @@ DO NOT TOUCH; GENERATED BY DRONE - Lint Report: 3 errors and 70 warnings + Lint Report: 3 errors and 69 warnings