From 45c73c0211e51a083fe8dd8736166035affb9ddd Mon Sep 17 00:00:00 2001 From: cmeng-git Date: Mon, 29 Jul 2024 09:28:48 +0800 Subject: [PATCH] See RN5.1.1 (20240729) - Change NotificationActionService to extend Service to work in foreground; to resolve unhandled markAsRead with JobIntentService. - Remove unused permissions: ACCESS_MEDIA_LOCATION, GET_ACCOUNTS, and WRITE_CONTACTS. - Need to add READ_EXTERNAL_STORAGE permission (Files and Media) request for android API-32. - Implement newly added READ_MEDIA_VISUAL_USER_SELECTED permission for android API-34. - Do not launch BatteryOptimization permission request within a dialog, else parseResult is based on dialog click. - ActivityResultContract#parseResult on BatteryOptimization request must return isOptimizingBattery() state. - Must set both shrinkResources and minifyEnabled to false for release build under API-34; else xmail crashes in Moshi with cannot serialize abstract class MessagingControllerCommands$PendingDelete - UpdateServiceImpl#isLatestVersion need to close inputStream after access end. - Update all app used libraries to the latest releases. --- README.md | 1 - XryptoMail/ReleaseNotes.txt | 14 + XryptoMail/build.gradle | 32 +- XryptoMail/release/version.properties | 6 +- XryptoMail/src/main/AndroidManifest.xml | 21 +- .../java/org/atalk/xryptomail/XryptoMail.java | 8 +- .../atalk/xryptomail/activity/Accounts.java | 122 +++-- .../atalk/xryptomail/activity/FolderList.java | 2 +- .../xryptomail/activity/MessageCompose.java | 328 +++++-------- .../xryptomail/activity/UpgradeDatabases.java | 21 +- .../activity/setup/AccountSetupActivity.java | 457 ++++++------------ .../activity/setup/AccountSetupPresenter.java | 450 ++++++----------- .../impl/appupdate/UpdateServiceImpl.java | 5 +- .../mail/autoconfiguration/DNSOperation.java | 3 - .../mail/autoconfiguration/DnsHelper.java | 4 + .../xryptomail/mail/internet/MimeUtility.java | 95 ++-- .../mail/store/webdav/WebDavStore.java | 14 +- .../xryptomail/mailstore/LocalStore.java | 296 +++++------- .../NotificationActionService.java | 30 +- .../permissions/PermissionsActivity.java | 140 +++--- .../provider/AttachmentTempFileProvider.java | 2 +- .../service/DatabaseUpgradeService.java | 55 +-- .../atalk/xryptomail/service/PushService.java | 0 .../xryptomail/view/XMWebViewClient.java | 3 + .../src/main/res/layout/permissions_ui.xml | 16 +- .../src/main/res/xml/changelog_master.xml | 12 + 26 files changed, 892 insertions(+), 1245 deletions(-) mode change 100644 => 100755 XryptoMail/src/main/java/org/atalk/xryptomail/mail/autoconfiguration/DNSOperation.java mode change 100644 => 100755 XryptoMail/src/main/java/org/atalk/xryptomail/service/DatabaseUpgradeService.java mode change 100644 => 100755 XryptoMail/src/main/java/org/atalk/xryptomail/service/PushService.java diff --git a/README.md b/README.md index 2f68757..31b8c39 100755 --- a/README.md +++ b/README.md @@ -35,7 +35,6 @@ XryptoMail is an email client designed for android with the following features: Libraries used in this project ------------------------------ * [Android Support Library](https://developer.android.com/topic/libraries/support-library/index.html) -* [butterknife](https://github.com/JakeWharton/butterknife) * [ckChangeLog](https://github.com/cketti/ckChangeLog) * [Commons IO](http://commons.apache.org/io/) * [Dexter](https://github.com/Karumi/Dexter) diff --git a/XryptoMail/ReleaseNotes.txt b/XryptoMail/ReleaseNotes.txt index 6e8b62b..ec38943 100755 --- a/XryptoMail/ReleaseNotes.txt +++ b/XryptoMail/ReleaseNotes.txt @@ -1,4 +1,18 @@ XryptoMail Release Notes: +============================= +Version: 5.1.1 +Upload Date: 07/29/2024 +- Change NotificationActionService to extend Service to work in foreground; to resolve unhandled markAsRead with JobIntentService. +- Remove unused permissions: ACCESS_MEDIA_LOCATION, GET_ACCOUNTS, and WRITE_CONTACTS. +- Need to add READ_EXTERNAL_STORAGE permission (Files and Media) request for android API-32. +- Implement newly added READ_MEDIA_VISUAL_USER_SELECTED permission for android API-34. +- Do not launch BatteryOptimization permission request within a dialog, else parseResult is based on dialog click. +- ActivityResultContract#parseResult on BatteryOptimization request must return isOptimizingBattery() state. +- Must set both shrinkResources and minifyEnabled to false for release build under API-34; + else xmail crashes in Moshi with cannot serialize abstract class MessagingControllerCommands$PendingDelete +- UpdateServiceImpl#isLatestVersion need to close inputStream after access end. +- Update all app used libraries to the latest releases. + ============================= Version: 5.1.0 Upload Date: 07/20/2024 diff --git a/XryptoMail/build.gradle b/XryptoMail/build.gradle index 5a22681..677f982 100755 --- a/XryptoMail/build.gradle +++ b/XryptoMail/build.gradle @@ -36,8 +36,8 @@ android { applicationId "org.atalk.xryptomail" testApplicationId "org.atalk.xryptomail.tests" - versionCode 19101 - versionName '5.1.0' + versionCode 19110 + versionName '5.1.1' minSdkVersion rootProject.minSdk targetSdkVersion rootProject.compileSdk @@ -65,8 +65,10 @@ android { buildTypes { release { - shrinkResources true - minifyEnabled true + // Must set below two to flase in API-34 release, else crashes in Moshi with + // Cannot serialize abstract class MessagingControllerCommands$PendingDelete + shrinkResources false + minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' buildConfigField "boolean", "DEVELOPER_MODE", "false" } @@ -146,23 +148,21 @@ dependencies { implementation fileTree(dir: 'libs', include: '*.jar') implementation "androidx.legacy:legacy-support-v4:1.0.0" - implementation "androidx.annotation:annotation:1.8.0" + implementation "androidx.annotation:annotation:1.8.1" implementation 'androidx.constraintlayout:constraintlayout:2.1.4' implementation "com.google.android.material:material:1.12.0" implementation project(':plugins:openpgp-api-lib:openpgp-api') // implementation 'org.sufficientlysecure:openpgp-api:11.0' - implementation 'commons-io:commons-io:2.16.0' + implementation 'commons-io:commons-io:2.16.1' implementation 'com.beetstra.jutf7:jutf7:1.0.0' implementation 'com.github.amlcurran.showcaseview:library:5.4.1' // ContactPictureLoader source is not compatible with v4.x.x implementation 'com.github.bumptech.glide:glide:3.8.0' - implementation 'com.jakewharton:butterknife:10.2.3' implementation 'com.google.firebase:firebase-crashlytics-buildtools:3.0.2' - implementation('com.jakewharton.timber:timber:5.0.1') { transitive = false } @@ -172,8 +172,8 @@ dependencies { // ImapConnection.open().enableCompressionIfRequested() does not work with jzlib version 1.1.3 implementation 'com.jcraft:jzlib:1.0.7' - implementation 'com.squareup.moshi:moshi:1.13.0' - implementation 'com.squareup.okio:okio:3.1.0' + implementation 'com.squareup.moshi:moshi:1.15.1' + implementation 'com.squareup.okio:okio:3.9.0' implementation 'com.squareup.retrofit2:retrofit:2.9.0' implementation 'com.squareup.retrofit2:converter-gson:2.9.0' implementation 'com.splitwise:tokenautocomplete:2.0.8' @@ -184,18 +184,18 @@ dependencies { implementation 'dnsjava:dnsjava:3.0.2' implementation 'me.zhanghai.android.materialprogressbar:library:1.4.1' - implementation "me.leolin:ShortcutBadger:1.1.22@aar" + implementation "me.leolin:ShortcutBadger:1.1.22" implementation 'net.jcip:jcip-annotations:1.0' - implementation 'org.apache.james:apache-mime4j-core:0.8.7' - implementation 'org.apache.james:apache-mime4j-dom:0.8.6' - compileOnly "org.apache.httpcomponents:httpclient:4.5.6" - implementation 'org.apache.httpcomponents.client5:httpclient5:5.1.3' + implementation 'org.apache.james:apache-mime4j-core:0.8.9' + implementation 'org.apache.james:apache-mime4j-dom:0.8.9' + compileOnly "org.apache.httpcomponents:httpclient:4.5.14" + implementation 'org.apache.httpcomponents.client5:httpclient5:5.3.1' implementation 'org.apache.httpcomponents:httpcore:4.4.16' // implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.6.21" - implementation 'org.jsoup:jsoup:1.15.1' + implementation 'org.jsoup:jsoup:1.17.2' // androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.1' // testImplementation "com.google.truth:truth:${truthVersion}" diff --git a/XryptoMail/release/version.properties b/XryptoMail/release/version.properties index 5a952e3..e5dd82b 100755 --- a/XryptoMail/release/version.properties +++ b/XryptoMail/release/version.properties @@ -1,4 +1,4 @@ -Date: Sat Jul 20 08:47:24 SGT 2024 +Date: Mon Jul 29 09:02:43 SGT 2024 -last_version=5.1.0 -last_version_code=19101 \ No newline at end of file +last_version=5.1.1 +last_version_code=19110 \ No newline at end of file diff --git a/XryptoMail/src/main/AndroidManifest.xml b/XryptoMail/src/main/AndroidManifest.xml index 09cf0a6..85f6b0e 100755 --- a/XryptoMail/src/main/AndroidManifest.xml +++ b/XryptoMail/src/main/AndroidManifest.xml @@ -15,29 +15,31 @@ android:name="android.hardware.wifi" android:required="false" /> - - - + + + + + + + + + - - - + + { - if (toast != null) + if (toast != null && toast.getView() != null) { toast.cancel(); + } toast = Toast.makeText(mInstance, message, Toast.LENGTH_LONG); toast.show(); }); diff --git a/XryptoMail/src/main/java/org/atalk/xryptomail/activity/Accounts.java b/XryptoMail/src/main/java/org/atalk/xryptomail/activity/Accounts.java index bafc34b..25d5e6c 100755 --- a/XryptoMail/src/main/java/org/atalk/xryptomail/activity/Accounts.java +++ b/XryptoMail/src/main/java/org/atalk/xryptomail/activity/Accounts.java @@ -155,7 +155,8 @@ private void setViewTitle() { if (mUnreadMessageCount == 0) { mActionBarUnread.setVisibility(View.GONE); - } else { + } + else { mActionBarUnread.setText(String.format(Locale.US, "%d", mUnreadMessageCount)); mActionBarUnread.setVisibility(View.VISIBLE); } @@ -164,7 +165,8 @@ private void setViewTitle() { operation = operation.trim(); if (operation.isEmpty()) { mActionBarSubTitle.setVisibility(View.GONE); - } else { + } + else { mActionBarSubTitle.setVisibility(View.VISIBLE); mActionBarSubTitle.setText(operation); } @@ -232,7 +234,8 @@ public void showProgressIndicator(boolean enable) { mActionBarProgress.setVisibility(ProgressBar.GONE); if (enable) { mRefreshMenuItem.setActionView(R.layout.actionbar_indeterminate_progress_actionview); - } else { + } + else { mRefreshMenuItem.setActionView(null); } } @@ -250,7 +253,8 @@ public void folderStatusChanged(Account account, String folderName, int unreadMe AccountStats stats = account.getStats(Accounts.this); if (stats == null) { Timber.w("Unable to get account stats"); - } else { + } + else { accountStatusChanged(account, stats); } } catch (Exception e) { @@ -291,7 +295,8 @@ public void accountStatusChanged(BaseAccount account, AccountStats stats) { if (pendingWork.isEmpty()) { mHandler.progress(Window.PROGRESS_END); mHandler.refreshTitle(); - } else { + } + else { int level = (Window.PROGRESS_END / mAdapter.getCount()) * (mAdapter.getCount() - pendingWork.size()); mHandler.progress(level); } @@ -352,7 +357,8 @@ public static LocalSearch createUnreadSearch(Context context, BaseAccount accoun if (account instanceof SearchAccount) { search = ((SearchAccount) account).getRelatedSearch().clone(); search.setName(searchTitle); - } else { + } + else { search = new LocalSearch(searchTitle); search.addAccountUuid(account.getUuid()); @@ -381,7 +387,8 @@ public void onCreate(Bundle icicle) { // see if we should show the welcome message if (ACTION_IMPORT_SETTINGS.equals(intent.getAction())) { onImport(); - } else if (accounts.isEmpty()) { + } + else if (accounts.isEmpty()) { WelcomeMessage.showWelcomeMessage(this); finish(); return; @@ -576,7 +583,8 @@ private void refresh() { newAccounts = new ArrayList<>(accounts.size() + SPECIAL_ACCOUNTS_COUNT); newAccounts.add(mUnifiedInboxAccount); newAccounts.add(mAllMessagesAccount); - } else { + } + else { newAccounts = new ArrayList<>(accounts.size()); } @@ -595,7 +603,8 @@ private void refresh() { if (account instanceof Account) { Account realAccount = (Account) account; controller.getAccountStats(this, realAccount, mListener); - } else if (XryptoMail.countSearchMessages() && account instanceof SearchAccount) { + } + else if (XryptoMail.countSearchMessages() && account instanceof SearchAccount) { final SearchAccount searchAccount = (SearchAccount) account; controller.getSearchAccountStats(searchAccount, mListener); } @@ -631,7 +640,8 @@ private void onCompose() { Account defaultAccount = Preferences.getPreferences(this).getDefaultAccount(); if (defaultAccount != null) { MessageActions.actionCompose(this, defaultAccount); - } else { + } + else { onAddNewAccount(); } } @@ -641,18 +651,21 @@ private void onCompose() { * is not available. * * @param account the account to open ({@link SearchAccount} or {@link Account}) + * * @return false if unsuccessful */ private boolean onOpenAccount(BaseAccount account) { if (account instanceof SearchAccount) { SearchAccount searchAccount = (SearchAccount) account; MessageList.actionDisplaySearch(this, searchAccount.getRelatedSearch(), false, false); - } else { + } + else { Account realAccount = (Account) account; if (!realAccount.isEnabled()) { onActivateAccount(realAccount); return false; - } else if (!realAccount.isAvailable(this)) { + } + else if (!realAccount.isAvailable(this)) { String toastText = getString(R.string.account_unavailable, account.getDescription()); Toast toast = Toast.makeText(getApplication(), toastText, Toast.LENGTH_SHORT); toast.show(); @@ -662,7 +675,8 @@ private boolean onOpenAccount(BaseAccount account) { } if (XryptoMail.FOLDER_NONE.equals(realAccount.getAutoExpandFolder())) { FolderList.actionHandleAccount(this, realAccount); - } else { + } + else { LocalSearch search = new LocalSearch(realAccount.getAutoExpandFolder()); search.addAllowedFolder(realAccount.getAutoExpandFolder()); search.addAccountUuid(realAccount.getUuid()); @@ -819,7 +833,8 @@ private void show(final Accounts activity, boolean restore) { mIncomingPasswordView = layout.findViewById(R.id.incoming_server_password); mIncomingPasswordView.addTextChangedListener(this); - } else { + } + else { layout.findViewById(R.id.incoming_server_prompt).setVisibility(View.GONE); } @@ -837,17 +852,20 @@ private void show(final Accounts activity, boolean restore) { if (isChecked) { mOutgoingPasswordView.setText(null); mOutgoingPasswordView.setEnabled(false); - } else { + } + else { mOutgoingPasswordView.setText(mIncomingPasswordView.getText()); mOutgoingPasswordView.setEnabled(true); } }); - } else { + } + else { mUseIncomingView.setChecked(false); mUseIncomingView.setVisibility(View.GONE); mOutgoingPasswordView.setEnabled(true); } - } else { + } + else { layout.findViewById(R.id.outgoing_server_prompt).setVisibility(View.GONE); } @@ -864,7 +882,8 @@ private void show(final Accounts activity, boolean restore) { mOutgoingPasswordView.setText(mOutgoingPassword); mUseIncomingView.setChecked(mUseIncoming); } - } else { + } + else { // Trigger afterTextChanged() being called // Work around this bug: https://code.google.com/p/android/issues/detail?id=6360 if (configureIncomingServer) { @@ -893,7 +912,8 @@ else if (mUseIncomingView.isChecked() enable = true; } } - } else { + } + else { enable = mOutgoingPasswordView.getText().length() > 0; } @@ -991,7 +1011,8 @@ protected void onPostExecute(Void result) { if (!mRemainingAccounts.isEmpty()) { activity.promptForServerPasswords(mRemainingAccounts); - } else { + } + else { System.exit(0); } } @@ -1264,7 +1285,8 @@ public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuIn if ((account instanceof Account) && !((Account) account).isEnabled()) { getMenuInflater().inflate(R.menu.disabled_accounts_context, menu); - } else { + } + else { getMenuInflater().inflate(R.menu.accounts_context, menu); } @@ -1273,16 +1295,19 @@ public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuIn android.view.MenuItem item = menu.getItem(i); item.setVisible(false); } - } else { + } + else { EnumSet accountLocation = accountLocation(account); if (accountLocation.contains(ACCOUNT_LOCATION.TOP)) { menu.findItem(R.id.move_up).setEnabled(false); - } else { + } + else { menu.findItem(R.id.move_up).setEnabled(true); } if (accountLocation.contains(ACCOUNT_LOCATION.BOTTOM)) { menu.findItem(R.id.move_down).setEnabled(false); - } else { + } + else { menu.findItem(R.id.move_down).setEnabled(true); } } @@ -1304,7 +1329,8 @@ private void onImport() { if (!infos.isEmpty()) { startActivityForResult(Intent.createChooser(intent, null), ACTIVITY_REQUEST_PICK_SETTINGS_FILE); - } else { + } + else { showDialog(DIALOG_NO_FILE_MANAGER); } } @@ -1389,6 +1415,7 @@ public void show(final Accounts activity) { * Returns the message the dialog should display. * * @param activity The {@code Activity} this dialog belongs to. + * * @return The message the dialog should display */ protected String generateMessage(Accounts activity) { @@ -1460,7 +1487,8 @@ protected void okayAction(Accounts activity) { } if (!disabledAccounts.isEmpty()) { activity.promptForServerPasswords(disabledAccounts); - } else { + } + else { activity.setNonConfigurationInstance(null); } } @@ -1532,7 +1560,8 @@ public void show(final Accounts activity, SparseBooleanArray selection) { for (int i = 0; i < count; i++) { checkedItems[i] = selection.get(i); } - } else { + } + else { for (int i = 0; i < count; i++) { checkedItems[i] = true; } @@ -1606,7 +1635,8 @@ public View getView(int position, View convertView, ViewGroup parent) { View view; if (convertView != null) { view = convertView; - } else { + } + else { view = getLayoutInflater().inflate(R.layout.accounts_item, parent, false); } AccountViewHolder holder = (AccountViewHolder) view.getTag(); @@ -1633,10 +1663,12 @@ public View getView(int position, View convertView, ViewGroup parent) { if (stats != null && account instanceof Account && stats.size >= 0) { holder.email.setText(SizeFormatter.formatSize(Accounts.this, stats.size)); holder.email.setVisibility(View.VISIBLE); - } else { + } + else { if (account.getEmail().equals(account.getDescription())) { holder.email.setVisibility(View.GONE); - } else { + } + else { holder.email.setVisibility(View.VISIBLE); holder.email.setText(account.getEmail()); } @@ -1666,7 +1698,8 @@ public View getView(int position, View convertView, ViewGroup parent) { holder.activeIcons.setOnClickListener(v -> Toast.makeText(getApplication(), getString(R.string.tap_hint), Toast.LENGTH_SHORT).show()); - } else { + } + else { holder.newMessageCountWrapper.setVisibility(View.GONE); holder.flaggedMessageCountWrapper.setVisibility(View.GONE); } @@ -1678,7 +1711,8 @@ public View getView(int position, View convertView, ViewGroup parent) { holder.flaggedMessageCountIcon.setBackground(realAccount.generateColorChip(false, true).drawable()); holder.newMessageCountIcon.setBackground(realAccount.generateColorChip(false, false).drawable()); - } else { + } + else { holder.chip.setBackgroundColor(0xff999999); holder.newMessageCountIcon.setBackground(new ColorChip(0xff999999, false, ColorChip.CIRCULAR).drawable()); holder.flaggedMessageCountIcon.setBackground(new ColorChip(0xff999999, false, ColorChip.STAR).drawable()); @@ -1689,7 +1723,8 @@ public View getView(int position, View convertView, ViewGroup parent) { if (account instanceof SearchAccount) { holder.folders.setVisibility(View.GONE); - } else { + } + else { holder.folders.setVisibility(View.VISIBLE); holder.folders.setOnClickListener(v -> FolderList.actionHandleAccount(Accounts.this, (Account) account)); } @@ -1703,7 +1738,8 @@ private OnClickListener createFlaggedSearchListener(BaseAccount account) { if (account instanceof SearchAccount) { search = ((SearchAccount) account).getRelatedSearch().clone(); search.setName(searchTitle); - } else { + } + else { search = new LocalSearch(searchTitle); search.addAccountUuid(account.getUuid()); @@ -1808,7 +1844,8 @@ protected Boolean doInBackground(Void... params) { try { if (mUri == null) { mFileName = SettingsExporter.exportToFile(mContext, mIncludeGlobals, mAccountUuids); - } else { + } + else { SettingsExporter.exportToUri(mContext, mIncludeGlobals, mAccountUuids, mUri); } } catch (SettingsImportExportException e) { @@ -1830,11 +1867,13 @@ protected void onPostExecute(Boolean success) { if (mFileName != null) { activity.showSimpleDialog(R.string.settings_export_success_header, R.string.settings_export_success, mFileName); - } else { + } + else { activity.showSimpleDialog(R.string.settings_export_success_header, R.string.settings_export_success_generic); } - } else { + } + else { //TODO: better error messages activity.showSimpleDialog(R.string.settings_export_failed_header, R.string.settings_export_failure); @@ -1904,12 +1943,14 @@ protected void onPostExecute(Boolean success) { if (imported == 0) { activity.showSimpleDialog(R.string.settings_import_success_header, R.string.settings_import_global_settings_success, filename); - } else { + } + else { activity.showAccountsImportedDialog(mImportResults, filename); } activity.refresh(); - } else { + } + else { // TODO: better error messages activity.showSimpleDialog(R.string.settings_import_failed_header, R.string.settings_import_failure, filename); @@ -1967,7 +2008,8 @@ protected void onPostExecute(Boolean success) { if (success) { activity.showImportSelectionDialog(mImportContents, mUri); - } else { + } + else { String filename = mUri.getLastPathSegment(); // TODO: better error messages activity.showSimpleDialog(R.string.settings_import_failed_header, diff --git a/XryptoMail/src/main/java/org/atalk/xryptomail/activity/FolderList.java b/XryptoMail/src/main/java/org/atalk/xryptomail/activity/FolderList.java index fbd9136..eb91e71 100755 --- a/XryptoMail/src/main/java/org/atalk/xryptomail/activity/FolderList.java +++ b/XryptoMail/src/main/java/org/atalk/xryptomail/activity/FolderList.java @@ -83,7 +83,7 @@ public void refreshTitle() } String operation = mAdapter.mListener.getOperation(FolderList.this); - if (operation.length() < 1) { + if (operation.isEmpty()) { mActionBarSubTitle.setText(mAccount.getEmail()); } else { diff --git a/XryptoMail/src/main/java/org/atalk/xryptomail/activity/MessageCompose.java b/XryptoMail/src/main/java/org/atalk/xryptomail/activity/MessageCompose.java index 63af294..85dfc1b 100755 --- a/XryptoMail/src/main/java/org/atalk/xryptomail/activity/MessageCompose.java +++ b/XryptoMail/src/main/java/org/atalk/xryptomail/activity/MessageCompose.java @@ -1,9 +1,16 @@ package org.atalk.xryptomail.activity; import android.annotation.SuppressLint; -import android.app.*; +import android.app.ActionBar; +import android.app.Activity; +import android.app.AlertDialog; import android.app.AlertDialog.Builder; -import android.content.*; +import android.app.Dialog; +import android.app.PendingIntent; +import android.app.ProgressDialog; +import android.content.Context; +import android.content.Intent; +import android.content.IntentSender; import android.content.IntentSender.SendIntentException; import android.content.pm.ActivityInfo; import android.net.Uri; @@ -11,10 +18,6 @@ import android.os.Bundle; import android.os.Handler; import android.os.Parcelable; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import androidx.annotation.StringRes; import android.text.TextUtils; import android.text.TextWatcher; import android.util.TypedValue; @@ -32,6 +35,17 @@ import android.widget.TextView; import android.widget.Toast; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.annotation.StringRes; + +import java.util.Date; +import java.util.HashMap; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.regex.Pattern; + import org.atalk.xryptomail.Account; import org.atalk.xryptomail.Account.MessageFormat; import org.atalk.xryptomail.FontSizes; @@ -92,13 +106,6 @@ import org.atalk.xryptomail.ui.compose.QuotedMessagePresenter; import org.openintents.openpgp.util.OpenPgpApi; -import java.util.Date; -import java.util.HashMap; -import java.util.List; -import java.util.Locale; -import java.util.Map; -import java.util.regex.Pattern; - import timber.log.Timber; @SuppressWarnings("deprecation") // TODO get rid of activity dialogs and indeterminate progress bars @@ -106,8 +113,7 @@ public class MessageCompose extends XMActivity implements OnClickListener, CancelListener, AttachmentDownloadCancelListener, OnFocusChangeListener, OnOpenPgpInlineChangeListener, OnOpenPgpSignOnlyChangeListener, MessageBuilder.Callback, AttachmentPresenter.AttachmentsChangedListener, RecipientPresenter.RecipientsChangedListener, - OnOpenPgpDisableListener -{ + OnOpenPgpDisableListener { private static final int DIALOG_SAVE_OR_DISCARD_DRAFT_MESSAGE = 1; private static final int DIALOG_CONFIRM_DISCARD_ON_BACK = 2; @@ -152,7 +158,6 @@ public class MessageCompose extends XMActivity implements OnClickListener, /** * Regular expression to remove the first localized "Re:" prefix in subjects. - * * Currently: * - "Aw:" (german: abbreviation for "Antwort") */ @@ -220,7 +225,6 @@ public class MessageCompose extends XMActivity implements OnClickListener, /** * The currently used message format. - * * Note: * Don't modify this field directly. Use {@link #updateMessageFormat()}. */ @@ -233,8 +237,7 @@ public class MessageCompose extends XMActivity implements OnClickListener, private MenuItem mButtonStealth; @Override - public void onCreate(Bundle savedInstanceState) - { + public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); if (UpgradeDatabases.actionUpgradeDatabases(this, getIntent())) { finish(); @@ -246,7 +249,7 @@ public void onCreate(Bundle savedInstanceState) ContextThemeWrapper themeContext = new ContextThemeWrapper(this, XryptoMail.getXMThemeResourceId(XryptoMail.getXMComposerTheme())); @SuppressLint("InflateParams") // this is the top level activity element, it has no root - View v = LayoutInflater.from(themeContext).inflate(R.layout.message_compose, null); + View v = LayoutInflater.from(themeContext).inflate(R.layout.message_compose, null); TypedValue outValue = new TypedValue(); // background color needs to be forced themeContext.getTheme().resolveAttribute(R.attr.messageViewBackgroundColor, outValue, true); @@ -311,20 +314,16 @@ public void onCreate(Bundle savedInstanceState) attachmentsView = findViewById(R.id.attachments); - TextWatcher draftNeedsChangingTextWatcher = new SimpleTextWatcher() - { + TextWatcher draftNeedsChangingTextWatcher = new SimpleTextWatcher() { @Override - public void onTextChanged(CharSequence s, int start, int before, int count) - { + public void onTextChanged(CharSequence s, int start, int before, int count) { changesMadeSinceLastSave = true; } }; - TextWatcher signTextWatcher = new SimpleTextWatcher() - { + TextWatcher signTextWatcher = new SimpleTextWatcher() { @Override - public void onTextChanged(CharSequence s, int start, int before, int count) - { + public void onTextChanged(CharSequence s, int start, int before, int count) { changesMadeSinceLastSave = true; mSignatureChanged = true; } @@ -459,8 +458,7 @@ else if (ACTION_EDIT_DRAFT.equals(action)) { } @Override - public void onDestroy() - { + public void onDestroy() { super.onDestroy(); if (recipientPresenter != null) { recipientPresenter.onActivityDestroy(); @@ -481,11 +479,11 @@ public void onDestroy() *

* * @param intent The (external) intent that started the activity. + * * @return {@code true}, if this activity was started by an external intent. {@code false}, * otherwise. */ - private boolean initFromIntent(final Intent intent) - { + private boolean initFromIntent(final Intent intent) { boolean startedByExternalIntent = false; final String action = intent.getAction(); @@ -562,15 +560,13 @@ private boolean initFromIntent(final Intent intent) } @Override - protected void onResume() - { + protected void onResume() { super.onResume(); MessagingController.getInstance(this).addListener(messagingListener); } @Override - public void onPause() - { + public void onPause() { super.onPause(); MessagingController.getInstance(this).removeListener(messagingListener); @@ -593,8 +589,7 @@ public void onPause() * Quoted text, */ @Override - protected void onSaveInstanceState(@NonNull Bundle outState) - { + protected void onSaveInstanceState(@NonNull Bundle outState) { super.onSaveInstanceState(outState); outState.putBoolean(STATE_KEY_SOURCE_MESSAGE_PROCED, relatedMessageProcessed); @@ -621,8 +616,7 @@ public Object onRetainCustomNonConfigurationInstance() { } @Override - protected void onRestoreInstanceState(Bundle savedInstanceState) - { + protected void onRestoreInstanceState(Bundle savedInstanceState) { super.onRestoreInstanceState(savedInstanceState); attachmentsView.removeAllViews(); @@ -644,14 +638,12 @@ protected void onRestoreInstanceState(Bundle savedInstanceState) updateMessageFormat(); } - private void setTitle() - { + private void setTitle() { setTitle(mAction.getTitleResource()); } @Nullable - private MessageBuilder createMessageBuilder(boolean isDraft) - { + private MessageBuilder createMessageBuilder(boolean isDraft) { MessageBuilder builder; ComposeCryptoStatus cryptoStatus = recipientPresenter.getCurrentCachedCryptoStatus(); if (cryptoStatus == null) { @@ -697,8 +689,7 @@ private MessageBuilder createMessageBuilder(boolean isDraft) return builder; } - private void checkToSendMessage() - { + private void checkToSendMessage() { if (mSubjectView.getText().length() == 0 && !alreadyNotifiedUserOfEmptySubject) { Toast.makeText(this, R.string.empty_subject, Toast.LENGTH_LONG).show(); alreadyNotifiedUserOfEmptySubject = true; @@ -715,8 +706,7 @@ private void checkToSendMessage() performSendAfterChecks(); } - private void checkToSaveDraftAndSave() - { + private void checkToSaveDraftAndSave() { if (!mAccount.hasDraftsFolder()) { Toast.makeText(this, R.string.compose_error_no_draft_folder, Toast.LENGTH_SHORT).show(); return; @@ -730,8 +720,7 @@ private void checkToSaveDraftAndSave() performSaveAfterChecks(); } - private void checkToSaveDraftImplicitly() - { + private void checkToSaveDraftImplicitly() { if (!mAccount.hasDraftsFolder()) { return; } @@ -744,8 +733,7 @@ private void checkToSaveDraftImplicitly() performSaveAfterChecks(); } - private void performSaveAfterChecks() - { + private void performSaveAfterChecks() { currentMessageBuilder = createMessageBuilder(true); if (currentMessageBuilder != null) { setProgressBarIndeterminateVisibility(true); @@ -753,8 +741,7 @@ private void performSaveAfterChecks() } } - public void performSendAfterChecks() - { + public void performSendAfterChecks() { currentMessageBuilder = createMessageBuilder(false); if (currentMessageBuilder != null) { changesMadeSinceLastSave = false; @@ -763,8 +750,7 @@ public void performSendAfterChecks() } } - private void onDiscard() - { + private void onDiscard() { if (mDraftId != INVALID_DRAFT_ID) { MessagingController.getInstance(getApplication()).deleteDraft(mAccount, mDraftId); mDraftId = INVALID_DRAFT_ID; @@ -779,8 +765,7 @@ private void onDiscard() } } - private void onReadReceipt() - { + private void onReadReceipt() { CharSequence txt; if (!requestReadReceipt) { txt = getString(R.string.read_receipt_enabled); @@ -795,16 +780,14 @@ private void onReadReceipt() toast.show(); } - public void showContactPicker(int requestCode) - { + public void showContactPicker(int requestCode) { requestCode |= REQUEST_MASK_RECIPIENT_PRESENTER; isInSubActivity = true; startActivityForResult(mContacts.contactPickerIntent(), requestCode); } @Override - protected void onActivityResult(int requestCode, int resultCode, Intent data) - { + protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); isInSubActivity = false; @@ -837,8 +820,7 @@ protected void onActivityResult(int requestCode, int resultCode, Intent data) } } - private void onAccountChosen(Account account, Identity identity) - { + private void onAccountChosen(Account account, Identity identity) { if (!mAccount.equals(account)) { Timber.v("Switching account from %s to %s", mAccount, account); @@ -883,8 +865,7 @@ private void onAccountChosen(Account account, Identity identity) switchToIdentity(identity); } - private void switchToIdentity(Identity identity) - { + private void switchToIdentity(Identity identity) { mIdentity = identity; mIdentityChanged = true; changesMadeSinceLastSave = true; @@ -894,13 +875,11 @@ private void switchToIdentity(Identity identity) recipientPresenter.onSwitchIdentity(identity); } - private void updateFrom() - { + private void updateFrom() { mChooseIdentityButton.setText(mIdentity.getEmail()); } - private void updateSignature() - { + private void updateSignature() { if (mIdentity.getSignatureUse()) { mSignatureView.setCharacters(mIdentity.getSignature()); mSignatureView.setVisibility(View.VISIBLE); @@ -911,8 +890,7 @@ private void updateSignature() } @Override - public void onFocusChange(View v, boolean hasFocus) - { + public void onFocusChange(View v, boolean hasFocus) { switch (v.getId()) { case R.id.message_content: case R.id.subject: @@ -924,51 +902,43 @@ public void onFocusChange(View v, boolean hasFocus) } @Override - public void onOpenPgpInlineChange(boolean enabled) - { + public void onOpenPgpInlineChange(boolean enabled) { recipientPresenter.onCryptoPgpInlineChanged(enabled); } @Override - public void onOpenPgpSignOnlyChange(boolean enabled) - { + public void onOpenPgpSignOnlyChange(boolean enabled) { recipientPresenter.onCryptoPgpSignOnlyDisabled(); } @Override - public void onOpenPgpClickDisable() - { + public void onOpenPgpClickDisable() { recipientPresenter.onCryptoPgpClickDisable(); } @Override - public void onAttachmentAdded() - { + public void onAttachmentAdded() { changesMadeSinceLastSave = true; } @Override - public void onAttachmentRemoved() - { + public void onAttachmentRemoved() { changesMadeSinceLastSave = true; } @Override - public void onRecipientsChanged() - { + public void onRecipientsChanged() { changesMadeSinceLastSave = true; } @Override - public void onClick(View view) - { + public void onClick(View view) { if (view.getId() == R.id.identity) { showDialog(DIALOG_CHOOSE_IDENTITY); } } - private void askBeforeDiscard() - { + private void askBeforeDiscard() { if (XryptoMail.confirmDiscardMessage()) { showDialog(DIALOG_CONFIRM_DISCARD); } @@ -982,8 +952,7 @@ private void askBeforeDiscard() // } @Override - public boolean onOptionsItemSelected(MenuItem item) - { + public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case android.R.id.home: prepareToFinish(true); @@ -1056,8 +1025,7 @@ public boolean onOptionsItemSelected(MenuItem item) } @Override - public boolean onCreateOptionsMenu(Menu menu) - { + public boolean onCreateOptionsMenu(Menu menu) { super.onCreateOptionsMenu(menu); if (isFinishing()) { @@ -1075,8 +1043,7 @@ public boolean onCreateOptionsMenu(Menu menu) } @Override - public boolean onPrepareOptionsMenu(Menu menu) - { + public boolean onPrepareOptionsMenu(Menu menu) { super.onPrepareOptionsMenu(menu); // cmeng - recipientPresenter can be null under race condition @@ -1087,14 +1054,13 @@ public boolean onPrepareOptionsMenu(Menu menu) return false; } + @SuppressLint("MissingSuperCall") @Override - public void onBackPressed() - { + public void onBackPressed() { prepareToFinish(false); } - private void prepareToFinish(boolean shouldNavigateUp) - { + private void prepareToFinish(boolean shouldNavigateUp) { navigateUp = shouldNavigateUp; if (changesMadeSinceLastSave && draftIsNotEmpty()) { @@ -1121,8 +1087,7 @@ private void prepareToFinish(boolean shouldNavigateUp) } } - private void openAutoExpandFolder() - { + private void openAutoExpandFolder() { String folder = mAccount.getAutoExpandFolder(); LocalSearch search = new LocalSearch(folder); search.addAccountUuid(mAccount.getUuid()); @@ -1131,8 +1096,7 @@ private void openAutoExpandFolder() finish(); } - private boolean draftIsNotEmpty() - { + private boolean draftIsNotEmpty() { if (mMessageContentView.getText().length() != 0) { return true; } @@ -1148,19 +1112,16 @@ private boolean draftIsNotEmpty() } @Override - public void onProgressCancel(AttachmentDownloadDialogFragment fragment) - { + public void onProgressCancel(AttachmentDownloadDialogFragment fragment) { attachmentPresenter.attachmentProgressDialogCancelled(); } - public void onProgressCancel(ProgressDialogFragment fragment) - { + public void onProgressCancel(ProgressDialogFragment fragment) { attachmentPresenter.attachmentProgressDialogCancelled(); } @Override - public Dialog onCreateDialog(int id) - { + public Dialog onCreateDialog(int id) { switch (id) { case DIALOG_SAVE_OR_DISCARD_DRAFT_MESSAGE: return new AlertDialog.Builder(this) @@ -1218,13 +1179,11 @@ public Dialog onCreateDialog(int id) return super.onCreateDialog(id); } - public void saveDraftEventually() - { + public void saveDraftEventually() { changesMadeSinceLastSave = true; } - public void loadQuotedTextForEdit() - { + public void loadQuotedTextForEdit() { if (relatedMessageReference == null) { // shouldn't happen... throw new IllegalStateException("tried to edit quoted message with no referenced message"); } @@ -1237,8 +1196,7 @@ public void loadQuotedTextForEdit() * * @param messageViewInfo The source message used to populate the various text fields. */ - private void processSourceMessage(MessageViewInfo messageViewInfo) - { + private void processSourceMessage(MessageViewInfo messageViewInfo) { try { switch (mAction) { case REPLY: @@ -1277,8 +1235,7 @@ private void processSourceMessage(MessageViewInfo messageViewInfo) } private void processMessageToReplyTo(MessageViewInfo messageViewInfo) - throws MessagingException - { + throws MessagingException { Message message = messageViewInfo.message; if (message.getSubject() != null) { @@ -1302,7 +1259,7 @@ private void processMessageToReplyTo(MessageViewInfo messageViewInfo) boolean isReplyAll = mAction == Action.REPLY_ALL; recipientPresenter.initFromReplyToMessage(message, isReplyAll); - if (message.getMessageId() != null && message.getMessageId().length() > 0) { + if (message.getMessageId() != null && !message.getMessageId().isEmpty()) { repliedToMessageId = message.getMessageId(); String[] refs = message.getReferences(); @@ -1331,8 +1288,7 @@ private void processMessageToReplyTo(MessageViewInfo messageViewInfo) } private void processMessageToForward(MessageViewInfo messageViewInfo, boolean asAttachment) - throws MessagingException - { + throws MessagingException { Message message = messageViewInfo.message; String subject = message.getSubject(); @@ -1365,8 +1321,7 @@ private void processMessageToForward(MessageViewInfo messageViewInfo, boolean as } } - private void processDraftMessage(MessageViewInfo messageViewInfo) - { + private void processDraftMessage(MessageViewInfo messageViewInfo) { Message message = messageViewInfo.message; mDraftId = MessagingController.getInstance(getApplication()).getId(message); mSubjectView.setText(message.getSubject()); @@ -1447,8 +1402,7 @@ private void processDraftMessage(MessageViewInfo messageViewInfo) quotedMessagePresenter.processDraftMessage(messageViewInfo, k9identity); } - static class SendMessageTask extends AsyncTask - { + static class SendMessageTask extends AsyncTask { final Context context; final Account account; final Contacts contacts; @@ -1457,8 +1411,7 @@ static class SendMessageTask extends AsyncTask final MessageReference messageReference; SendMessageTask(Context context, Account account, Contacts contacts, Message message, - Long draftId, MessageReference messageReference) - { + Long draftId, MessageReference messageReference) { this.context = context; this.account = account; this.contacts = contacts; @@ -1468,8 +1421,7 @@ static class SendMessageTask extends AsyncTask } @Override - protected Void doInBackground(Void... params) - { + protected Void doInBackground(Void... params) { try { contacts.markAsContacted(message.getRecipients(RecipientType.TO)); contacts.markAsContacted(message.getRecipients(RecipientType.CC)); @@ -1490,8 +1442,7 @@ protected Void doInBackground(Void... params) /** * Set the flag on the referenced message(indicated we replied / forwarded the message) **/ - private void updateReferencedMessage() - { + private void updateReferencedMessage() { if (messageReference != null && messageReference.getFlag() != null) { Timber.d("Setting referenced message (%s, %s) flag to %s", messageReference.getFolderServerId(), @@ -1514,8 +1465,7 @@ private void updateReferencedMessage() * * @param mailTo The MailTo object we use to initialize message field */ - private void initializeFromMailto(MailTo mailTo) - { + private void initializeFromMailto(MailTo mailTo) { recipientPresenter.initFromMailto(mailTo); String subject = mailTo.getSubject(); @@ -1529,14 +1479,12 @@ private void initializeFromMailto(MailTo mailTo) } } - private void setCurrentMessageFormat(SimpleMessageFormat format) - { + private void setCurrentMessageFormat(SimpleMessageFormat format) { // This method will later be used to enable/disable the rich text editing mode. currentMessageFormat = format; } - public void updateMessageFormat() - { + public void updateMessageFormat() { MessageFormat origMessageFormat = mAccount.getMessageFormat(); SimpleMessageFormat messageFormat; if (origMessageFormat == MessageFormat.TEXT) { @@ -1575,8 +1523,7 @@ else if (origMessageFormat == MessageFormat.AUTO) { } @Override - public void onMessageBuildSuccess(MimeMessage message, boolean isDraft) - { + public void onMessageBuildSuccess(MimeMessage message, boolean isDraft) { currentMessageBuilder = null; if (isDraft) { changesMadeSinceLastSave = false; @@ -1608,8 +1555,7 @@ public void onMessageBuildSuccess(MimeMessage message, boolean isDraft) * * @param message the Message to send */ - public void launchSendProgressDialog(final MimeMessage message) - { + public void launchSendProgressDialog(final MimeMessage message) { StringBuilder recipients = new StringBuilder(); Address[] addresses = message.getRecipients(RecipientType.TO); @@ -1640,8 +1586,7 @@ public void launchSendProgressDialog(final MimeMessage message) * Hide the soft keyboard when user clicks the send button; * to allow display of the SendProgressDialog */ - private void hideKeyboard() - { + private void hideKeyboard() { Activity activity = MessageCompose.this; InputMethodManager imm = (InputMethodManager) activity.getSystemService(Context.INPUT_METHOD_SERVICE); View decorView = activity.getWindow().getDecorView(); @@ -1651,15 +1596,13 @@ private void hideKeyboard() } @Override - public void onMessageBuildCancel() - { + public void onMessageBuildCancel() { currentMessageBuilder = null; setProgressBarIndeterminateVisibility(false); } @Override - public void onMessageBuildException(MessagingException me) - { + public void onMessageBuildException(MessagingException me) { Timber.e(me, "Error sending message"); Toast.makeText(MessageCompose.this, getString(R.string.send_failed_reason, me.getLocalizedMessage()), Toast.LENGTH_LONG).show(); @@ -1668,8 +1611,7 @@ public void onMessageBuildException(MessagingException me) } @Override - public void onMessageBuildReturnPendingIntent(PendingIntent pendingIntent, int requestCode) - { + public void onMessageBuildReturnPendingIntent(PendingIntent pendingIntent, int requestCode) { requestCode |= REQUEST_MASK_MESSAGE_BUILDER; try { startIntentSenderForResult(pendingIntent.getIntentSender(), requestCode, null, 0, 0, 0); @@ -1678,8 +1620,7 @@ public void onMessageBuildReturnPendingIntent(PendingIntent pendingIntent, int r } } - public void launchUserInteractionPendingIntent(PendingIntent pendingIntent, int requestCode) - { + public void launchUserInteractionPendingIntent(PendingIntent pendingIntent, int requestCode) { requestCode |= REQUEST_MASK_RECIPIENT_PRESENTER; try { startIntentSenderForResult(pendingIntent.getIntentSender(), requestCode, null, 0, 0, 0); @@ -1688,8 +1629,7 @@ public void launchUserInteractionPendingIntent(PendingIntent pendingIntent, int } } - public void loadLocalMessageForDisplay(MessageViewInfo messageViewInfo, Action action) - { + public void loadLocalMessageForDisplay(MessageViewInfo messageViewInfo, Action action) { // We check to see if we've previously processed the source message since this // could be called when switching from HTML to text replies. If that happens, we // only want to update the UI with quoted text (which picks the appropriate @@ -1710,48 +1650,41 @@ public void loadLocalMessageForDisplay(MessageViewInfo messageViewInfo, Action a } } - private MessageLoaderCallbacks messageLoaderCallbacks; + private final MessageLoaderCallbacks messageLoaderCallbacks; { - messageLoaderCallbacks = new MessageLoaderCallbacks() - { + messageLoaderCallbacks = new MessageLoaderCallbacks() { @Override - public void onMessageDataLoadFinished(LocalMessage message) - { + public void onMessageDataLoadFinished(LocalMessage message) { // nothing to do here, we don't care about message headers } @Override - public void onMessageDataLoadFailed() - { + public void onMessageDataLoadFailed() { internalMessageHandler.sendEmptyMessage(MSG_PROGRESS_OFF); Toast.makeText(MessageCompose.this, R.string.status_invalid_id_error, Toast.LENGTH_LONG).show(); } @Override - public void onMessageViewInfoLoadFinished(MessageViewInfo messageViewInfo) - { + public void onMessageViewInfoLoadFinished(MessageViewInfo messageViewInfo) { internalMessageHandler.sendEmptyMessage(MSG_PROGRESS_OFF); loadLocalMessageForDisplay(messageViewInfo, mAction); } @Override - public void onMessageViewInfoLoadFailed(MessageViewInfo messageViewInfo) - { + public void onMessageViewInfoLoadFailed(MessageViewInfo messageViewInfo) { internalMessageHandler.sendEmptyMessage(MSG_PROGRESS_OFF); Toast.makeText(MessageCompose.this, R.string.status_invalid_id_error, Toast.LENGTH_LONG).show(); } @Override - public void setLoadingProgress(int current, int max) - { + public void setLoadingProgress(int current, int max) { // nvm - we don't have a progress bar } @Override public void startIntentSenderForMessageLoaderHelper(IntentSender si, int requestCode, Intent fillIntent, - int flagsMask, int flagValues, int extraFlags) - { + int flagsMask, int flagValues, int extraFlags) { try { requestCode |= REQUEST_MASK_LOADER_HELPER; startIntentSenderForResult(si, requestCode, fillIntent, flagsMask, flagValues, extraFlags); @@ -1761,33 +1694,28 @@ public void startIntentSenderForMessageLoaderHelper(IntentSender si, int request } @Override - public void onDownloadErrorMessageNotFound() - { + public void onDownloadErrorMessageNotFound() { runOnUiThread(() -> Toast.makeText(MessageCompose.this, R.string.status_invalid_id_error, Toast.LENGTH_LONG).show()); } @Override - public void onDownloadErrorNetworkError() - { + public void onDownloadErrorNetworkError() { runOnUiThread(() -> Toast.makeText(MessageCompose.this, R.string.status_network_error, Toast.LENGTH_LONG).show()); } }; } - private void initializeActionBar() - { + private void initializeActionBar() { ActionBar actionBar = getActionBar(); if (actionBar != null) actionBar.setDisplayHomeAsUpEnabled(true); } // TODO We miss callbacks for this listener if they happens while we are paused! - public MessagingListener messagingListener = new SimpleMessagingListener() - { + public MessagingListener messagingListener = new SimpleMessagingListener() { @Override - public void messageUidChanged(Account account, String folder, String oldUid, String newUid) - { + public void messageUidChanged(Account account, String folder, String oldUid, String newUid) { if (relatedMessageReference == null) { return; } @@ -1805,13 +1733,11 @@ public void messageUidChanged(Account account, String folder, String oldUid, Str } }; - AttachmentMvpView attachmentMvpView = new AttachmentMvpView() - { + AttachmentMvpView attachmentMvpView = new AttachmentMvpView() { private final HashMap attachmentViews = new HashMap<>(); @Override - public void showWaitingForAttachmentDialog(WaitingAction waitingAction) - { + public void showWaitingForAttachmentDialog(WaitingAction waitingAction) { String title; switch (waitingAction) { @@ -1834,8 +1760,7 @@ public void showWaitingForAttachmentDialog(WaitingAction waitingAction) } @Override - public void dismissWaitingForAttachmentDialog() - { + public void dismissWaitingForAttachmentDialog() { ProgressDialogFragment fragment = (ProgressDialogFragment) getSupportFragmentManager().findFragmentByTag(FRAGMENT_WAITING_FOR_ATTACHMENT); @@ -1846,8 +1771,7 @@ public void dismissWaitingForAttachmentDialog() @Override @SuppressLint("InlinedApi") - public void showPickAttachmentDialog(int requestCode) - { + public void showPickAttachmentDialog(int requestCode) { requestCode |= REQUEST_MASK_ATTACHMENT_PRESENTER; Intent i = new Intent(Intent.ACTION_GET_CONTENT); @@ -1860,8 +1784,7 @@ public void showPickAttachmentDialog(int requestCode) } @Override - public void addAttachmentView(final Attachment attachment) - { + public void addAttachmentView(final Attachment attachment) { View view = getLayoutInflater().inflate(R.layout.message_compose_attachment, attachmentsView, false); attachmentViews.put(attachment.uri, view); @@ -1873,8 +1796,7 @@ public void addAttachmentView(final Attachment attachment) } @Override - public void updateAttachmentView(Attachment attachment) - { + public void updateAttachmentView(Attachment attachment) { View view = attachmentViews.get(attachment.uri); if (view == null) { throw new IllegalArgumentException(); @@ -1895,45 +1817,38 @@ public void updateAttachmentView(Attachment attachment) } @Override - public void removeAttachmentView(Attachment attachment) - { + public void removeAttachmentView(Attachment attachment) { View view = attachmentViews.get(attachment.uri); attachmentsView.removeView(view); attachmentViews.remove(attachment.uri); } @Override - public void performSendAfterChecks() - { + public void performSendAfterChecks() { MessageCompose.this.performSendAfterChecks(); } @Override - public void performSaveAfterChecks() - { + public void performSaveAfterChecks() { MessageCompose.this.performSaveAfterChecks(); } @Override - public void showMissingAttachmentsPartialMessageWarning() - { + public void showMissingAttachmentsPartialMessageWarning() { Toast.makeText(MessageCompose.this, getString(R.string.message_compose_attachments_skipped_toast), Toast.LENGTH_LONG).show(); } @Override - public void showMissingAttachmentsPartialMessageForwardWarning() - { + public void showMissingAttachmentsPartialMessageForwardWarning() { Toast.makeText(MessageCompose.this, getString(R.string.message_compose_attachments_forward_toast), Toast.LENGTH_LONG).show(); } }; - private Handler internalMessageHandler = new Handler() - { + private final Handler internalMessageHandler = new Handler() { @Override - public void handleMessage(android.os.Message msg) - { + public void handleMessage(android.os.Message msg) { switch (msg.what) { case MSG_PROGRESS_ON: setProgressBarIndeterminateVisibility(true); @@ -1955,8 +1870,7 @@ public void handleMessage(android.os.Message msg) } }; - public enum Action - { + public enum Action { COMPOSE(R.string.compose_title_compose), REPLY(R.string.compose_title_reply), REPLY_ALL(R.string.compose_title_reply_all), @@ -1966,14 +1880,12 @@ public enum Action private final int titleResource; - Action(@StringRes int titleResource) - { + Action(@StringRes int titleResource) { this.titleResource = titleResource; } @StringRes - public int getTitleResource() - { + public int getTitleResource() { return titleResource; } } diff --git a/XryptoMail/src/main/java/org/atalk/xryptomail/activity/UpgradeDatabases.java b/XryptoMail/src/main/java/org/atalk/xryptomail/activity/UpgradeDatabases.java index b27db10..5c0b0ba 100755 --- a/XryptoMail/src/main/java/org/atalk/xryptomail/activity/UpgradeDatabases.java +++ b/XryptoMail/src/main/java/org/atalk/xryptomail/activity/UpgradeDatabases.java @@ -9,6 +9,7 @@ import android.os.Bundle; import android.widget.TextView; +import androidx.core.content.IntentCompat; import androidx.localbroadcastmanager.content.LocalBroadcastManager; import org.atalk.xryptomail.Account; @@ -16,6 +17,7 @@ import org.atalk.xryptomail.R; import org.atalk.xryptomail.XryptoMail; import org.atalk.xryptomail.controller.MessagingController; +import org.atalk.xryptomail.mail.Store; import org.atalk.xryptomail.service.DatabaseUpgradeService; /** @@ -65,6 +67,7 @@ public class UpgradeDatabases extends XMActivity { * @param context The {@link Context} used to start the activity. * @param startIntent After the database upgrade is complete an activity is started using this intent. * Usually this is the intent that was used to start the calling activity. Never {@code null}. + * * @return {@code true}, if the {@code UpgradeDatabases} activity was started. In this case the * calling activity is expected to finish itself.
* {@code false}, if the account databases don't need upgrading. @@ -77,7 +80,7 @@ public static boolean actionUpgradeDatabases(Context context, Intent startIntent Intent intent = new Intent(context, UpgradeDatabases.class); intent.setAction(ACTION_UPGRADE_DATABASES); intent.putExtra(EXTRA_START_INTENT, startIntent); - + intent.setPackage(context.getPackageName()); // Make sure this activity is only running once intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_SINGLE_TOP); @@ -96,7 +99,6 @@ public static boolean actionUpgradeDatabases(Context context, Intent startIntent @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - decodeExtras(); // If the databases have already been upgraded there's no point in displaying this activity. @@ -106,9 +108,7 @@ public void onCreate(Bundle savedInstanceState) { } mPreferences = Preferences.getPreferences(getApplicationContext()); - initializeLayout(); - setupBroadcastReceiver(); } @@ -126,7 +126,7 @@ private void initializeLayout() { */ private void decodeExtras() { Intent intent = getIntent(); - mStartIntent = intent.getParcelableExtra(EXTRA_START_INTENT); + mStartIntent = IntentCompat.getParcelableExtra(intent, EXTRA_START_INTENT, Intent.class); } /** @@ -182,7 +182,6 @@ private void launchOriginalActivity() { * Receiver for broadcasts send by {@link DatabaseUpgradeService}. */ class UpgradeDatabaseBroadcastReceiver extends BroadcastReceiver { - @Override public void onReceive(Context context, final Intent intent) { String action = intent.getAction(); @@ -191,23 +190,19 @@ public void onReceive(Context context, final Intent intent) { /* * Information on the current upgrade progress */ - - String accountUuid = intent.getStringExtra( - DatabaseUpgradeService.EXTRA_ACCOUNT_UUID); + String accountUuid = intent.getStringExtra(DatabaseUpgradeService.EXTRA_ACCOUNT_UUID); Account account = mPreferences.getAccount(accountUuid); - if (account != null) { String formatString = getString(R.string.upgrade_database_format); String upgradeStatus = String.format(formatString, account.getDescription()); mUpgradeText.setText(upgradeStatus); } - - } else if (DatabaseUpgradeService.ACTION_UPGRADE_COMPLETE.equals(action)) { + } + else if (DatabaseUpgradeService.ACTION_UPGRADE_COMPLETE.equals(action)) { /* * Upgrade complete */ - launchOriginalActivity(); } } diff --git a/XryptoMail/src/main/java/org/atalk/xryptomail/activity/setup/AccountSetupActivity.java b/XryptoMail/src/main/java/org/atalk/xryptomail/activity/setup/AccountSetupActivity.java index a870238..6f99c47 100755 --- a/XryptoMail/src/main/java/org/atalk/xryptomail/activity/setup/AccountSetupActivity.java +++ b/XryptoMail/src/main/java/org/atalk/xryptomail/activity/setup/AccountSetupActivity.java @@ -1,19 +1,15 @@ package org.atalk.xryptomail.activity.setup; +import static org.atalk.xryptomail.mail.ServerSettings.Type.IMAP; +import static org.atalk.xryptomail.mail.ServerSettings.Type.POP3; +import static org.atalk.xryptomail.mail.ServerSettings.Type.WebDAV; + import android.app.Activity; import android.app.AlertDialog; import android.app.Dialog; import android.content.Context; import android.content.Intent; import android.os.Bundle; -import androidx.annotation.LayoutRes; -import androidx.annotation.Nullable; -import androidx.annotation.StringRes; -import androidx.coordinatorlayout.widget.CoordinatorLayout; -import com.google.android.material.snackbar.Snackbar; -import com.google.android.material.textfield.TextInputEditText; -import com.google.android.material.textfield.TextInputLayout; -import androidx.appcompat.app.AppCompatActivity; import android.text.Editable; import android.text.TextWatcher; import android.text.method.DigitsKeyListener; @@ -35,6 +31,18 @@ import android.widget.Toast; import android.widget.ViewFlipper; +import androidx.annotation.LayoutRes; +import androidx.annotation.Nullable; +import androidx.annotation.StringRes; +import androidx.appcompat.app.AppCompatActivity; +import androidx.coordinatorlayout.widget.CoordinatorLayout; + +import java.security.cert.X509Certificate; + +import com.google.android.material.snackbar.Snackbar; +import com.google.android.material.textfield.TextInputEditText; +import com.google.android.material.textfield.TextInputLayout; + import org.atalk.xryptomail.Account; import org.atalk.xryptomail.BuildConfig; import org.atalk.xryptomail.Preferences; @@ -51,18 +59,11 @@ import org.atalk.xryptomail.view.ClientCertificateSpinner; import org.atalk.xryptomail.view.ClientCertificateSpinner.OnClientCertificateChangedListener; -import java.security.cert.X509Certificate; - import me.zhanghai.android.materialprogressbar.MaterialProgressBar; import timber.log.Timber; -import static org.atalk.xryptomail.mail.ServerSettings.Type.IMAP; -import static org.atalk.xryptomail.mail.ServerSettings.Type.POP3; -import static org.atalk.xryptomail.mail.ServerSettings.Type.WebDAV; - public class AccountSetupActivity extends AppCompatActivity implements AccountSetupContract.View, - ConfirmationDialogFragmentListener, OnClickListener, OnCheckedChangeListener -{ + ConfirmationDialogFragmentListener, OnClickListener, OnCheckedChangeListener { private static final String EXTRA_ACCOUNT = "account"; private static final String EXTRA_STAGE = "stage"; private static final String EXTRA_EDIT_SETTINGS = "edit_settings"; @@ -135,8 +136,7 @@ public class AccountSetupActivity extends AppCompatActivity implements AccountSe Stage stage; @Override - protected void onCreate(@Nullable Bundle savedInstanceState) - { + protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.account_setup); @@ -199,8 +199,7 @@ protected void onCreate(@Nullable Bundle savedInstanceState) } @Override - protected void onSaveInstanceState(Bundle outState) - { + protected void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); outState.putSerializable(STATE_STAGE, stage); @@ -215,15 +214,13 @@ protected void onSaveInstanceState(Bundle outState) } @Override - protected void onRestoreInstanceState(Bundle savedInstanceState) - { + protected void onRestoreInstanceState(Bundle savedInstanceState) { presenter.onRestoreStart(); super.onRestoreInstanceState(savedInstanceState); presenter.onRestoreEnd(); } - private void basicsStart() - { + private void basicsStart() { coordinatorLayout = findViewById(R.id.basics_coordinator_layout); emailView = findViewById(R.id.account_email); passwordViewLayout = findViewById(R.id.password_input_layout); @@ -239,75 +236,63 @@ private void basicsStart() onInputChangedInBasics(); } - private void onInputChangedInBasics() - { + private void onInputChangedInBasics() { if (presenter == null) return; presenter.onInputChangedInBasics(emailView.getText().toString(), passwordView.getText().toString()); } - private TextWatcher validationTextWatcherInBasics = new TextWatcher() - { + private TextWatcher validationTextWatcherInBasics = new TextWatcher() { @Override - public void beforeTextChanged(CharSequence s, int start, int count, int after) - { + public void beforeTextChanged(CharSequence s, int start, int count, int after) { } @Override - public void onTextChanged(CharSequence s, int start, int before, int count) - { + public void onTextChanged(CharSequence s, int start, int before, int count) { } @Override - public void afterTextChanged(Editable s) - { + public void afterTextChanged(Editable s) { presenter.onInputChangedInBasics(emailView.getText().toString(), passwordView.getText().toString()); } }; - private void initializeViewListenersInBasics() - { + private void initializeViewListenersInBasics() { emailView.addTextChangedListener(validationTextWatcherInBasics); passwordView.addTextChangedListener(validationTextWatcherInBasics); } @Override - public void setPasswordInBasicsEnabled(boolean enabled) - { + public void setPasswordInBasicsEnabled(boolean enabled) { passwordViewLayout.setEnabled(enabled); } @Override - public void setPasswordHintInBasics(String hint) - { + public void setPasswordHintInBasics(String hint) { passwordViewLayout.setHint(hint); } @Override - public void setManualSetupButtonInBasicsVisibility(int visibility) - { + public void setManualSetupButtonInBasicsVisibility(int visibility) { manualSetupButton.setVisibility(visibility); } - private void checkingStart() - { + private void checkingStart() { messageView = findViewById(R.id.message); progressBar = findViewById(R.id.progress); progressBar.setIndeterminate(true); } - private void accountTypeStart() - { + private void accountTypeStart() { accountTypeRadioGroup = findViewById(R.id.account_type_radio_group); findViewById(R.id.account_type_next).setOnClickListener(this); presenter.onAccountTypeStart(); } - private int getPositionFromLayoutId(@LayoutRes int layoutId) - { + private int getPositionFromLayoutId(@LayoutRes int layoutId) { for (int i = 0; i < layoutIds.length; i++) { if (layoutIds[i] == layoutId) { return i; @@ -318,32 +303,28 @@ private int getPositionFromLayoutId(@LayoutRes int layoutId) private static long mLastClickTime = 0; - private static boolean isActionValid() - { + private static boolean isActionValid() { long now = System.currentTimeMillis(); boolean valid = (now - mLastClickTime > 1000); mLastClickTime = now; return valid; } - public static void actionNewAccount(Context context) - { + public static void actionNewAccount(Context context) { if (isActionValid()) { Intent i = new Intent(context, AccountSetupActivity.class); context.startActivity(i); } } - public void goToBasics() - { + public void goToBasics() { stage = Stage.BASICS; setSelection(getPositionFromLayoutId(R.layout.account_setup_basics)); basicsStart(); } - public void goToOutgoing() - { + public void goToOutgoing() { stage = Stage.OUTGOING; setSelection(getPositionFromLayoutId(R.layout.account_setup_outgoing)); outgoingStart(); @@ -351,8 +332,7 @@ public void goToOutgoing() @Override - public void goToIncoming() - { + public void goToIncoming() { stage = Stage.INCOMING; setSelection(getPositionFromLayoutId(R.layout.account_setup_incoming)); incomingStart(); @@ -360,8 +340,7 @@ public void goToIncoming() @Override - public void goToAutoConfiguration() - { + public void goToAutoConfiguration() { stage = Stage.AUTOCONFIGURATION; setSelection(getPositionFromLayoutId(R.layout.account_setup_check_settings)); checkingStart(); @@ -370,24 +349,21 @@ public void goToAutoConfiguration() @Override - public void goToAccountType() - { + public void goToAccountType() { stage = Stage.ACCOUNT_TYPE; setSelection(getPositionFromLayoutId(R.layout.account_setup_account_type)); accountTypeStart(); } @Override - public void goToAccountNames() - { + public void goToAccountNames() { stage = Stage.ACCOUNT_NAMES; setSelection(getPositionFromLayoutId(R.layout.account_setup_names)); namesStart(); } @Override - public void goToOutgoingChecking() - { + public void goToOutgoingChecking() { stage = Stage.OUTGOING_CHECKING; setSelection(getPositionFromLayoutId(R.layout.account_setup_check_settings)); checkingStart(); @@ -395,40 +371,33 @@ public void goToOutgoingChecking() } @Override - public void end() - { + public void end() { finish(); } @Override - public void goToIncomingChecking() - { + public void goToIncomingChecking() { stage = Stage.INCOMING_CHECKING; setSelection(getPositionFromLayoutId(R.layout.account_setup_check_settings)); checkingStart(); presenter.onCheckingStart(stage); } - public void listAccounts() - { + public void listAccounts() { Accounts.listAccounts(this); } - private void setSelection(int position) - { + private void setSelection(int position) { if (position == -1) return; this.position = position; flipper.setDisplayedChild(position); - } - @Override public void showAcceptKeyDialog(final int msgResId, final String exMessage, final String message, - final X509Certificate certificate) - { + final X509Certificate certificate) { // TODO: refactor with DialogFragment. // This is difficult because we need to pass through chain[0] for onClick() @@ -446,81 +415,67 @@ public void showAcceptKeyDialog(final int msgResId, final String exMessage, fina } @Override - public void showErrorDialog(@StringRes final int msgResId, final Object... args) - { + public void showErrorDialog(@StringRes final int msgResId, final Object... args) { // TODO: 8/13/17 add a "detail" button and show exception details here Snackbar.make(coordinatorLayout, getString(msgResId, args), Snackbar.LENGTH_LONG).show(); } @Override - public void showErrorDialog(String errorMessage) - { + public void showErrorDialog(String errorMessage) { Snackbar.make(coordinatorLayout, errorMessage, Snackbar.LENGTH_LONG).show(); } @Override - public void setMessage(@StringRes int id) - { + public void setMessage(@StringRes int id) { messageView.setText(getString(id)); } @Override - public Context getContext() - { + public Context getContext() { return this; } @Override - public void doPositiveClick(int dialogId) - { + public void doPositiveClick(int dialogId) { presenter.onPositiveClickedInConfirmationDialog(); } @Override - public void doNegativeClick(int dialogId) - { + public void doNegativeClick(int dialogId) { presenter.onNegativeClickedInConfirmationDialog(); } @Override - public void dialogCancelled(int dialogId) - { + public void dialogCancelled(int dialogId) { } // ------ - private void initializeViewListenersInIncoming() - { - securityTypeView.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() - { + private void initializeViewListenersInIncoming() { + securityTypeView.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() { @Override public void onItemSelected(AdapterView parent, View view, int position, - long id) - { + long id) { onInputChangedInIncoming(); } @Override - public void onNothingSelected(AdapterView parent) - { /* unused */ } + public void onNothingSelected(AdapterView parent) { /* unused */ } }); - authTypeView.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() - { + authTypeView.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() { @Override public void onItemSelected(AdapterView parent, View view, int position, - long id) - { + long id) { onInputChangedInIncoming(); } @Override - public void onNothingSelected(AdapterView parent) - { /* unused */ } + public void onNothingSelected(AdapterView parent) { /* unused */ } }); clientCertificateSpinner.setOnClientCertificateChangedListener(clientCertificateChangedListenerInIncoming); @@ -530,8 +485,7 @@ public void onNothingSelected(AdapterView parent) portView.addTextChangedListener(validationTextWatcherInIncoming); } - private void onInputChangedInIncoming() - { + private void onInputChangedInIncoming() { if (presenter == null) return; @@ -548,8 +502,7 @@ private void onInputChangedInIncoming() } - protected void onNextInIncoming() - { + protected void onNextInIncoming() { try { ConnectionSecurity connectionSecurity = getSelectedSecurity(); @@ -582,8 +535,7 @@ protected void onNextInIncoming() } } - public void onClick(View v) - { + public void onClick(View v) { try { switch (v.getId()) { case R.id.basics_next: @@ -606,7 +558,6 @@ public void onClick(View v) serverType = null; break; } - presenter.onNextButtonInAccountTypeClicked(serverType); break; @@ -629,8 +580,7 @@ public void onClick(View v) } } - private void failure(Exception use) - { + private void failure(Exception use) { Timber.e(use, "Failure"); String toastText = getString(R.string.account_setup_bad_uri, use.getMessage()); @@ -639,19 +589,15 @@ private void failure(Exception use) } - private TextWatcher validationTextWatcherInIncoming = new TextWatcher() - { - public void afterTextChanged(Editable s) - { + private TextWatcher validationTextWatcherInIncoming = new TextWatcher() { + public void afterTextChanged(Editable s) { onInputChangedInIncoming(); } - public void beforeTextChanged(CharSequence s, int start, int count, int after) - { + public void beforeTextChanged(CharSequence s, int start, int count, int after) { } - public void onTextChanged(CharSequence s, int start, int before, int count) - { + public void onTextChanged(CharSequence s, int start, int before, int count) { } }; @@ -659,8 +605,7 @@ public void onTextChanged(CharSequence s, int start, int before, int count) = alias -> onInputChangedInIncoming(); @Override - public void setAuthTypeInIncoming(AuthType authType) - { + public void setAuthTypeInIncoming(AuthType authType) { OnItemSelectedListener onItemSelectedListener = authTypeView.getOnItemSelectedListener(); authTypeView.setOnItemSelectedListener(null); int authTypePosition = @@ -670,8 +615,7 @@ public void setAuthTypeInIncoming(AuthType authType) } @Override - public void setSecurityTypeInIncoming(ConnectionSecurity security) - { + public void setSecurityTypeInIncoming(ConnectionSecurity security) { OnItemSelectedListener onItemSelectedListener = securityTypeView.getOnItemSelectedListener(); securityTypeView.setOnItemSelectedListener(null); int connectionSecurityPosition = ((ConnectionSecurityAdapter) @@ -681,24 +625,21 @@ public void setSecurityTypeInIncoming(ConnectionSecurity security) } @Override - public void setUsernameInIncoming(String username) - { + public void setUsernameInIncoming(String username) { usernameView.removeTextChangedListener(validationTextWatcherInIncoming); usernameView.setText(username); usernameView.addTextChangedListener(validationTextWatcherInIncoming); } @Override - public void setPasswordInIncoming(String password) - { + public void setPasswordInIncoming(String password) { passwordView.removeTextChangedListener(validationTextWatcherInIncoming); passwordView.setText(password); passwordView.addTextChangedListener(validationTextWatcherInIncoming); } @Override - public void setCertificateAliasInIncoming(String alias) - { + public void setCertificateAliasInIncoming(String alias) { clientCertificateSpinner.setOnClientCertificateChangedListener(null); clientCertificateSpinner.setAlias(alias); clientCertificateSpinner. @@ -706,30 +647,26 @@ public void setCertificateAliasInIncoming(String alias) } @Override - public void setServerInIncoming(String server) - { + public void setServerInIncoming(String server) { serverView.removeTextChangedListener(validationTextWatcherInIncoming); serverView.setText(server); serverView.addTextChangedListener(validationTextWatcherInIncoming); } @Override - public void setPortInIncoming(String port) - { + public void setPortInIncoming(String port) { portView.removeTextChangedListener(validationTextWatcherInIncoming); portView.setText(port); portView.addTextChangedListener(validationTextWatcherInIncoming); } @Override - public void setServerLabel(String label) - { + public void setServerLabel(String label) { serverViewLayout.setHint(label); } @Override - public void hideViewsWhenPop3() - { + public void hideViewsWhenPop3() { findViewById(R.id.imap_path_prefix_section).setVisibility(View.GONE); findViewById(R.id.webdav_advanced_header).setVisibility(View.GONE); findViewById(R.id.webdav_mailbox_alias_section).setVisibility(View.GONE); @@ -741,8 +678,7 @@ public void hideViewsWhenPop3() } @Override - public void hideViewsWhenImap() - { + public void hideViewsWhenImap() { findViewById(R.id.webdav_advanced_header).setVisibility(View.GONE); findViewById(R.id.webdav_mailbox_alias_section).setVisibility(View.GONE); findViewById(R.id.webdav_owa_path_section).setVisibility(View.GONE); @@ -750,14 +686,12 @@ public void hideViewsWhenImap() } @Override - public void hideViewsWhenImapAndNotEdit() - { + public void hideViewsWhenImapAndNotEdit() { findViewById(R.id.imap_folder_setup_section).setVisibility(View.GONE); } @Override - public void hideViewsWhenWebDav() - { + public void hideViewsWhenWebDav() { findViewById(R.id.imap_path_prefix_section).setVisibility(View.GONE); findViewById(R.id.incoming_account_auth_type_label).setVisibility(View.GONE); findViewById(R.id.incoming_account_auth_type).setVisibility(View.GONE); @@ -767,37 +701,31 @@ public void hideViewsWhenWebDav() } @Override - public void setImapAutoDetectNamespace(boolean autoDetectNamespace) - { + public void setImapAutoDetectNamespace(boolean autoDetectNamespace) { imapAutoDetectNamespaceView.setChecked(autoDetectNamespace); } @Override - public void setImapPathPrefix(String imapPathPrefix) - { + public void setImapPathPrefix(String imapPathPrefix) { imapPathPrefixView.setText(imapPathPrefix); } @Override - public void setWebDavPathPrefix(String webDavPathPrefix) - { + public void setWebDavPathPrefix(String webDavPathPrefix) { webdavPathPrefixView.setText(webDavPathPrefix); } @Override - public void setWebDavAuthPath(String authPath) - { + public void setWebDavAuthPath(String authPath) { webdavAuthPathView.setText(authPath); } @Override - public void setWebDavMailboxPath(String mailboxPath) - { + public void setWebDavMailboxPath(String mailboxPath) { webdavMailboxPathView.setText(mailboxPath); } - private void incomingStart() - { + private void incomingStart() { View incomingView = findViewById(R.id.account_setup_incoming); coordinatorLayout = findViewById(R.id.incoming_coordinator_layout); usernameView = incomingView.findViewById(R.id.incoming_account_username); @@ -848,54 +776,46 @@ else if (!isChecked) { } @Override - public void setImapPathPrefixSectionVisibility(int visibility) - { + public void setImapPathPrefixSectionVisibility(int visibility) { findViewById(R.id.imap_path_prefix_section).setVisibility(visibility); } @Override - public void setCompressionSectionVisibility(int visibility) - { + public void setCompressionSectionVisibility(int visibility) { findViewById(R.id.compression_label).setVisibility(visibility); findViewById(R.id.compression_section).setVisibility(visibility); } @Override - public void setNextButtonInIncomingEnabled(boolean enabled) - { + public void setNextButtonInIncomingEnabled(boolean enabled) { nextButton.setEnabled(enabled); } @Override - public void goToIncomingSettings() - { + public void goToIncomingSettings() { goToIncoming(); } @Override - public void setNextButtonInBasicsEnabled(boolean enabled) - { + public void setNextButtonInBasicsEnabled(boolean enabled) { nextButton.setEnabled(enabled); Utility.setCompoundDrawablesAlpha(nextButton, nextButton.isEnabled() ? 255 : 128); } @Override - public void setSecurityChoices(ConnectionSecurity[] choices) - { + public void setSecurityChoices(ConnectionSecurity[] choices) { // Note that connectionSecurityChoices is configured above based on server type ConnectionSecurityAdapter securityTypesAdapter = ConnectionSecurityAdapter.get(this, choices); securityTypeView.setAdapter(securityTypesAdapter); } @Override - public void setAuthTypeInsecureText(boolean insecure) - { + public void setAuthTypeInsecureText(boolean insecure) { authTypeAdapter.useInsecureText(insecure); } @Override - public void setViewNotExternalInIncoming() - { + public void setViewNotExternalInIncoming() { passwordViewLayout.setVisibility(View.VISIBLE); clientCertificateLabelView.setVisibility(View.GONE); clientCertificateSpinner.setVisibility(View.GONE); @@ -907,8 +827,7 @@ public void setViewNotExternalInIncoming() } @Override - public void setViewExternalInIncoming() - { + public void setViewExternalInIncoming() { passwordViewLayout.setVisibility(View.GONE); clientCertificateLabelView.setVisibility(View.VISIBLE); clientCertificateSpinner.setVisibility(View.VISIBLE); @@ -920,8 +839,7 @@ public void setViewExternalInIncoming() } @Override - public void setViewOAuth2InIncoming() - { + public void setViewOAuth2InIncoming() { imapAutoDetectNamespaceView.setEnabled(false); passwordViewLayout.setEnabled(false); securityTypeView.setEnabled(false); @@ -929,38 +847,32 @@ public void setViewOAuth2InIncoming() } @Override - public void showFailureToast(Exception use) - { + public void showFailureToast(Exception use) { failure(use); } @Override - public void setCompressionMobile(boolean compressionMobileBoolean) - { + public void setCompressionMobile(boolean compressionMobileBoolean) { compressionMobile.setChecked(compressionMobileBoolean); } @Override - public void setCompressionWifi(boolean compressionWifiBoolean) - { + public void setCompressionWifi(boolean compressionWifiBoolean) { compressionWifi.setChecked(compressionWifiBoolean); } @Override - public void setCompressionOther(boolean compressionOtherBoolean) - { + public void setCompressionOther(boolean compressionOtherBoolean) { compressionOther.setChecked(compressionOtherBoolean); } @Override - public void setSubscribedFoldersOnly(boolean subscribedFoldersOnlyBoolean) - { + public void setSubscribedFoldersOnly(boolean subscribedFoldersOnlyBoolean) { subscribedFoldersOnly.setChecked(subscribedFoldersOnlyBoolean); } @Override - public void showInvalidSettingsToast() - { + public void showInvalidSettingsToast() { String toastText = getString(R.string.account_setup_outgoing_invalid_setting_combo_notice, getString(R.string.account_setup_incoming_auth_type_label), AuthType.EXTERNAL.toString(), @@ -970,42 +882,35 @@ public void showInvalidSettingsToast() } @Override - public void showInvalidOAuthError() - { + public void showInvalidOAuthError() { usernameViewLayout.setErrorEnabled(true); usernameViewLayout.setError(getString(R.string.OAuth2_not_supported)); } @Override - public void clearInvalidOAuthError() - { + public void clearInvalidOAuthError() { usernameViewLayout.setError(""); } // names - public void namesStart() - { + public void namesStart() { doneButton = findViewById(R.id.done); doneButton.setOnClickListener(this); description = findViewById(R.id.account_description); name = findViewById(R.id.account_name); - name.addTextChangedListener(new TextWatcher() - { + name.addTextChangedListener(new TextWatcher() { @Override - public void beforeTextChanged(CharSequence s, int start, int count, int after) - { + public void beforeTextChanged(CharSequence s, int start, int count, int after) { } @Override - public void onTextChanged(CharSequence s, int start, int before, int count) - { + public void onTextChanged(CharSequence s, int start, int before, int count) { } @Override - public void afterTextChanged(Editable s) - { + public void afterTextChanged(Editable s) { onInputChangeInNames(); } }); @@ -1013,22 +918,18 @@ public void afterTextChanged(Editable s) } @Override - public void setDoneButtonInNamesEnabled(boolean enabled) - { + public void setDoneButtonInNamesEnabled(boolean enabled) { doneButton.setEnabled(enabled); } - private void onInputChangeInNames() - { + private void onInputChangeInNames() { presenter.onInputChangedInNames(name.getText().toString(), description.getText().toString()); } @Override - public void goToListAccounts() - { + public void goToListAccounts() { listAccounts(); } - // outgoing /** @@ -1038,40 +939,33 @@ public void goToListAccounts() * This avoids needless calls to {@code onInputChangedInOutgoing()} which is called * immediately after this is called. */ - private void initializeViewListenersInOutgoing() - { + private void initializeViewListenersInOutgoing() { /* * Updates the port when the user changes the security type. This allows * us to show a reasonable default which the user can change. */ - securityTypeView.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() - { + securityTypeView.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() { @Override - public void onItemSelected(AdapterView parent, View view, int position, long id) - { + public void onItemSelected(AdapterView parent, View view, int position, long id) { onInputChangedInOutgoing(); } @Override - public void onNothingSelected(AdapterView parent) - { /* unused */ } + public void onNothingSelected(AdapterView parent) { /* unused */ } }); - authTypeView.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() - { + authTypeView.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() { @Override - public void onItemSelected(AdapterView parent, View view, int position, long id) - { + public void onItemSelected(AdapterView parent, View view, int position, long id) { onInputChangedInOutgoing(); } @Override - public void onNothingSelected(AdapterView parent) - { /* unused */ } + public void onNothingSelected(AdapterView parent) { /* unused */ } }); requireLoginView.setOnCheckedChangeListener(this); @@ -1087,8 +981,7 @@ public void onNothingSelected(AdapterView parent) * widgets are changed programmatically. (The logic is simpler when you know * that this is the last thing called after an input change.) */ - private void onInputChangedInOutgoing() - { + private void onInputChangedInOutgoing() { if (presenter == null) return; @@ -1100,8 +993,7 @@ private void onInputChangedInOutgoing() } - protected void onNextInOutgoing() - { + protected void onNextInOutgoing() { ConnectionSecurity securityType = getSelectedSecurity(); String username = usernameView.getText().toString(); String password = passwordView.getText().toString(); @@ -1117,8 +1009,7 @@ protected void onNextInOutgoing() } @Override - public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) - { + public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { requireLoginSettingsView.setVisibility(isChecked ? View.VISIBLE : View.GONE); onInputChangedInOutgoing(); } @@ -1128,43 +1019,36 @@ public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) * Calls onInputChangedInOutgoing() which enables or disables the Next button * based on the fields' validity. */ - private TextWatcher validationTextWatcherInOutgoing = new TextWatcher() - { - public void afterTextChanged(Editable s) - { + private TextWatcher validationTextWatcherInOutgoing = new TextWatcher() { + public void afterTextChanged(Editable s) { onInputChangedInOutgoing(); } - public void beforeTextChanged(CharSequence s, int start, int count, int after) - { + public void beforeTextChanged(CharSequence s, int start, int count, int after) { } - public void onTextChanged(CharSequence s, int start, int before, int count) - { + public void onTextChanged(CharSequence s, int start, int before, int count) { } }; private OnClientCertificateChangedListener clientCertificateChangedListenerInOutgoing = alias -> onInputChangedInOutgoing(); - private AuthType getSelectedAuthType() - { + private AuthType getSelectedAuthType() { AuthTypeHolder holder = (AuthTypeHolder) authTypeView.getSelectedItem(); if (holder == null) return null; return holder.getAuthType(); } - private ConnectionSecurity getSelectedSecurity() - { + private ConnectionSecurity getSelectedSecurity() { ConnectionSecurityHolder holder = (ConnectionSecurityHolder) securityTypeView.getSelectedItem(); if (holder == null) return null; return holder.getConnectionSecurity(); } - private void outgoingStart() - { + private void outgoingStart() { final View outgoingView = findViewById(R.id.account_setup_outgoing); coordinatorLayout = outgoingView.findViewById(R.id.outgoing_coordinator_layout); usernameView = outgoingView.findViewById(R.id.outgoing_account_username); @@ -1199,15 +1083,13 @@ private void outgoingStart() } @Override - public void setNextButtonInOutgoingEnabled(boolean enabled) - { + public void setNextButtonInOutgoingEnabled(boolean enabled) { nextButton.setEnabled(enabled); Utility.setCompoundDrawablesAlpha(nextButton, nextButton.isEnabled() ? 255 : 128); } @Override - public void setAuthTypeInOutgoing(AuthType authType) - { + public void setAuthTypeInOutgoing(AuthType authType) { OnItemSelectedListener onItemSelectedListener = authTypeView.getOnItemSelectedListener(); authTypeView.setOnItemSelectedListener(null); authTypeView.setSelection(authTypeAdapter.getAuthPosition(authType), false); @@ -1215,8 +1097,7 @@ public void setAuthTypeInOutgoing(AuthType authType) } @Override - public void setSecurityTypeInOutgoing(ConnectionSecurity security) - { + public void setSecurityTypeInOutgoing(ConnectionSecurity security) { OnItemSelectedListener onItemSelectedListener = securityTypeView.getOnItemSelectedListener(); securityTypeView.setOnItemSelectedListener(null); securityTypeView.setSelection(security.ordinal(), false); @@ -1224,8 +1105,7 @@ public void setSecurityTypeInOutgoing(ConnectionSecurity security) } @Override - public void setUsernameInOutgoing(String username) - { + public void setUsernameInOutgoing(String username) { usernameView.removeTextChangedListener(validationTextWatcherInOutgoing); usernameView.setText(username); requireLoginView.setChecked(true); @@ -1234,16 +1114,14 @@ public void setUsernameInOutgoing(String username) } @Override - public void setPasswordInOutgoing(String password) - { + public void setPasswordInOutgoing(String password) { passwordView.removeTextChangedListener(validationTextWatcherInOutgoing); passwordView.setText(password); passwordView.addTextChangedListener(validationTextWatcherInOutgoing); } @Override - public void setCertificateAliasInOutgoing(String alias) - { + public void setCertificateAliasInOutgoing(String alias) { clientCertificateSpinner.setOnClientCertificateChangedListener(null); clientCertificateSpinner.setAlias(alias); clientCertificateSpinner. @@ -1251,24 +1129,21 @@ public void setCertificateAliasInOutgoing(String alias) } @Override - public void setServerInOutgoing(String server) - { + public void setServerInOutgoing(String server) { serverView.removeTextChangedListener(validationTextWatcherInOutgoing); serverView.setText(server); serverView.addTextChangedListener(validationTextWatcherInOutgoing); } @Override - public void setPortInOutgoing(String port) - { + public void setPortInOutgoing(String port) { portView.removeTextChangedListener(validationTextWatcherInOutgoing); portView.setText(port); portView.addTextChangedListener(validationTextWatcherInOutgoing); } @Override - public void showInvalidSettingsToastInOutgoing() - { + public void showInvalidSettingsToastInOutgoing() { String toastText = getString(R.string.account_setup_outgoing_invalid_setting_combo_notice, getString(R.string.account_setup_incoming_auth_type_label), AuthType.EXTERNAL.toString(), @@ -1278,14 +1153,12 @@ public void showInvalidSettingsToastInOutgoing() } @Override - public void updateAuthPlainTextInOutgoing(boolean insecure) - { + public void updateAuthPlainTextInOutgoing(boolean insecure) { authTypeAdapter.useInsecureText(insecure); } @Override - public void setViewNotExternalInOutgoing() - { + public void setViewNotExternalInOutgoing() { // show password fields, hide client certificate fields passwordViewLayout.setVisibility(View.VISIBLE); clientCertificateLabelView.setVisibility(View.GONE); @@ -1298,8 +1171,7 @@ public void setViewNotExternalInOutgoing() } @Override - public void setViewExternalInOutgoing() - { + public void setViewExternalInOutgoing() { // hide password fields, show client certificate fields passwordViewLayout.setVisibility(View.GONE); clientCertificateLabelView.setVisibility(View.VISIBLE); @@ -1313,20 +1185,17 @@ public void setViewExternalInOutgoing() } @Override - public void setViewOAuth2InOutgoing() - { + public void setViewOAuth2InOutgoing() { passwordViewLayout.setEnabled(false); securityTypeView.setEnabled(false); portView.setEnabled(false); } - public static void actionEditIncomingSettings(Activity context, Account account) - { + public static void actionEditIncomingSettings(Activity context, Account account) { context.startActivity(intentActionEditIncomingSettings(context, account)); } - public static Intent intentActionEditIncomingSettings(Context context, Account account) - { + public static Intent intentActionEditIncomingSettings(Context context, Account account) { Intent i = new Intent(context, AccountSetupActivity.class); i.setAction(Intent.ACTION_EDIT); i.putExtra(EXTRA_ACCOUNT, account.getUuid()); @@ -1334,13 +1203,11 @@ public static Intent intentActionEditIncomingSettings(Context context, Account a return i; } - public static void actionEditOutgoingSettings(Context context, Account account) - { + public static void actionEditOutgoingSettings(Context context, Account account) { context.startActivity(intentActionEditOutgoingSettings(context, account)); } - public static Intent intentActionEditOutgoingSettings(Context context, Account account) - { + public static Intent intentActionEditOutgoingSettings(Context context, Account account) { Intent i = new Intent(context, AccountSetupActivity.class); i.setAction(Intent.ACTION_EDIT); i.putExtra(EXTRA_ACCOUNT, account.getUuid()); @@ -1349,26 +1216,22 @@ public static Intent intentActionEditOutgoingSettings(Context context, Account a } @Override - public void onBackPressed() - { + public void onBackPressed() { presenter.onBackPressed(); } @Override - public void goBack() - { + public void goBack() { onBackPressed(); } @Override - public void startIntentForResult(Intent intent, int requestCode) - { + public void startIntentForResult(Intent intent, int requestCode) { startActivityForResult(intent, requestCode); } @Override - public void openGmailUrl(String url) - { + public void openGmailUrl(String url) { CookieManager cookieManager = CookieManager.getInstance(); //noinspection deprecation cookieManager.removeAllCookie(); @@ -1389,8 +1252,7 @@ public void openGmailUrl(String url) } @Override - public void openOutlookUrl(String url) - { + public void openOutlookUrl(String url) { CookieManager cookieManager = CookieManager.getInstance(); //noinspection deprecation cookieManager.removeAllCookie(); @@ -1412,8 +1274,7 @@ public void openOutlookUrl(String url) } @Override - public void closeAuthDialog() - { + public void closeAuthDialog() { if (authDialog != null) { authDialog.dismiss(); } @@ -1426,29 +1287,25 @@ protected void onActivityResult(int requestCode, int resultCode, Intent data) { } @Override - protected void onResume() - { + protected void onResume() { super.onResume(); presenter.onResume(); } @Override - protected void onPause() - { + protected void onPause() { super.onPause(); presenter.onPause(); } @Override - protected void onStop() - { + protected void onStop() { super.onStop(); presenter.onStop(); } @Override - protected void onDestroy() - { + protected void onDestroy() { super.onDestroy(); presenter.onDestroy(); } diff --git a/XryptoMail/src/main/java/org/atalk/xryptomail/activity/setup/AccountSetupPresenter.java b/XryptoMail/src/main/java/org/atalk/xryptomail/activity/setup/AccountSetupPresenter.java index 0219455..fe23bc4 100755 --- a/XryptoMail/src/main/java/org/atalk/xryptomail/activity/setup/AccountSetupPresenter.java +++ b/XryptoMail/src/main/java/org/atalk/xryptomail/activity/setup/AccountSetupPresenter.java @@ -1,5 +1,10 @@ package org.atalk.xryptomail.activity.setup; +import static org.atalk.xryptomail.mail.ServerSettings.Type.IMAP; +import static org.atalk.xryptomail.mail.ServerSettings.Type.POP3; +import static org.atalk.xryptomail.mail.ServerSettings.Type.SMTP; +import static org.atalk.xryptomail.mail.ServerSettings.Type.WebDAV; + import android.app.Activity; import android.content.Context; import android.content.Intent; @@ -7,9 +12,25 @@ import android.os.AsyncTask; import android.os.Handler; import android.os.Looper; +import android.text.TextUtils; + import androidx.annotation.NonNull; import androidx.annotation.Nullable; -import android.text.TextUtils; + +import java.io.Serializable; +import java.net.URI; +import java.net.URISyntaxException; +import java.net.UnknownHostException; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.security.cert.CertificateEncodingException; +import java.security.cert.CertificateException; +import java.security.cert.X509Certificate; +import java.util.Collection; +import java.util.HashMap; +import java.util.List; +import java.util.Locale; +import java.util.Map; import org.atalk.xryptomail.Account; import org.atalk.xryptomail.Account.FolderMode; @@ -53,30 +74,9 @@ import org.atalk.xryptomail.service.MailService; import org.atalk.xryptomail.setup.ServerNameSuggester; -import java.io.Serializable; -import java.net.URI; -import java.net.URISyntaxException; -import java.net.UnknownHostException; -import java.security.MessageDigest; -import java.security.NoSuchAlgorithmException; -import java.security.cert.CertificateEncodingException; -import java.security.cert.CertificateException; -import java.security.cert.X509Certificate; -import java.util.Collection; -import java.util.HashMap; -import java.util.List; -import java.util.Locale; -import java.util.Map; - import timber.log.Timber; -import static org.atalk.xryptomail.mail.ServerSettings.Type.IMAP; -import static org.atalk.xryptomail.mail.ServerSettings.Type.POP3; -import static org.atalk.xryptomail.mail.ServerSettings.Type.SMTP; -import static org.atalk.xryptomail.mail.ServerSettings.Type.WebDAV; - -public class AccountSetupPresenter implements AccountSetupContract.Presenter, Oauth2PromptRequestHandler -{ +public class AccountSetupPresenter implements AccountSetupContract.Presenter, Oauth2PromptRequestHandler { private final Context context; private final Preferences preferences; @@ -93,8 +93,7 @@ public class AccountSetupPresenter implements AccountSetupContract.Presenter, Oa private boolean oAuth2CodeGotten = false; - enum Stage - { + enum Stage { BASICS, AUTOCONFIGURATION, AUTOCONFIGURATION_INCOMING_CHECKING, @@ -129,8 +128,7 @@ enum Stage private boolean canceled; private boolean destroyed; - public AccountSetupPresenter(Context context, Preferences preferences, View view) - { + public AccountSetupPresenter(Context context, Preferences preferences, View view) { this.context = context; this.preferences = preferences; this.view = view; @@ -141,14 +139,12 @@ public AccountSetupPresenter(Context context, Preferences preferences, View view // region basics @Override - public void onBasicsStart() - { + public void onBasicsStart() { stage = Stage.BASICS; } @Override - public void onInputChangedInBasics(String email, String password) - { + public void onInputChangedInBasics(String email, String password) { EmailAddressValidator emailValidator = new EmailAddressValidator(); boolean valid = !TextUtils.isEmpty(email) && (canOAuth2(email) || !TextUtils.isEmpty(password)) @@ -169,21 +165,18 @@ public void onInputChangedInBasics(String email, String password) view.setNextButtonInBasicsEnabled(valid); } - private boolean canOAuth2(String email) - { + private boolean canOAuth2(String email) { String domain = EmailHelper.getDomainFromEmailAddress(email); return domain != null && (domain.equals("gmail.com") || domain.equals("outlook.com")); } @Override - public void onManualSetupButtonClicked(String email, String password) - { + public void onManualSetupButtonClicked(String email, String password) { manualSetup(email, password); } @Override - public void onNextButtonInBasicViewClicked(String email, String password) - { + public void onNextButtonInBasicViewClicked(String email, String password) { if (accountConfig == null) { accountConfig = new AccountConfigImpl(preferences); } @@ -195,8 +188,7 @@ public void onNextButtonInBasicViewClicked(String email, String password) // endregion basics // region checking @Override - public void onNegativeClickedInConfirmationDialog() - { + public void onNegativeClickedInConfirmationDialog() { if (direction == CheckDirection.BOTH && currentDirection == CheckDirection.INCOMING) { checkOutgoing(); } @@ -220,18 +212,14 @@ else if (currentDirection == CheckDirection.OUTGOING) { } } - private void autoConfiguration() - { + private void autoConfiguration() { findProvider(accountConfig.getEmail()); } - private void findProvider(final String email) - { - findProviderTask = new AsyncTask() - { + private void findProvider(final String email) { + findProviderTask = new AsyncTask() { @Override - protected ProviderInfo doInBackground(Void... params) - { + protected ProviderInfo doInBackground(Void... params) { publishProgress(R.string.account_setup_check_settings_retr_info_msg); incomingReady = false; @@ -263,8 +251,7 @@ protected ProviderInfo doInBackground(Void... params) } @Nullable - private ProviderInfo autoconfigureDomain(String domain) - { + private ProviderInfo autoconfigureDomain(String domain) { ProviderInfo providerInfo; AutoconfigureMozilla autoconfigureMozilla = new AutoconfigureMozilla(); AutoconfigureSrv autoconfigureSrv = new AutoconfigureSrv(); @@ -292,8 +279,7 @@ private ProviderInfo autoconfigureDomain(String domain) return null; } - private void testDomain(String domain) - { + private void testDomain(String domain) { String guessedDomainForMailPrefix; //noinspection ConstantConditions if (domain.startsWith("mail.")) { @@ -324,8 +310,7 @@ private void testDomain(String domain) testOutgoing(domainWithSmtpPrefix, ConnectionSecurity.SSL_TLS_REQUIRED, false); } - private void testIncoming(String domain, boolean useLocalPart) - { + private void testIncoming(String domain, boolean useLocalPart) { if (!incomingReady) { try { accountConfig.setStoreUri(getDefaultStoreURI( @@ -348,8 +333,7 @@ private void testIncoming(String domain, boolean useLocalPart) } } - private void testOutgoing(String domain, ConnectionSecurity connectionSecurity, boolean useLocalPart) - { + private void testOutgoing(String domain, ConnectionSecurity connectionSecurity, boolean useLocalPart) { if (!outgoingReady) { try { accountConfig.setTransportUri(getDefaultTransportURI( @@ -380,15 +364,13 @@ private void testOutgoing(String domain, ConnectionSecurity connectionSecurity, } @Override - protected void onProgressUpdate(Integer... values) - { + protected void onProgressUpdate(Integer... values) { super.onProgressUpdate(values); view.setMessage(values[0]); } @Override - protected void onPostExecute(ProviderInfo providerInfo) - { + protected void onPostExecute(ProviderInfo providerInfo) { super.onPostExecute(providerInfo); if (canceled) { @@ -433,15 +415,13 @@ else if (incomingReady) { }.execute(); } - private void checkIncomingAndOutgoing() - { + private void checkIncomingAndOutgoing() { direction = CheckDirection.BOTH; currentDirection = CheckDirection.INCOMING; new CheckIncomingTask(accountConfig, this::checkOutgoing).execute(); } - private void checkIncoming() - { + private void checkIncoming() { direction = CheckDirection.INCOMING; currentDirection = CheckDirection.INCOMING; new CheckIncomingTask(accountConfig, () -> { @@ -473,10 +453,10 @@ private void checkIncoming() String transportUri = TransportUris.createTransportUri(transportServer); accountConfig.setTransportUri(transportUri); } catch (URISyntaxException use) { - /* - * If we can't set up the URL we just continue. It's only for - * convenience. - */ + /* + * If we can't set up the URL we just continue. It's only for + * convenience. + */ } view.goToOutgoing(); @@ -484,8 +464,7 @@ private void checkIncoming() }).execute(); } - private void checkOutgoing() - { + private void checkOutgoing() { direction = CheckDirection.OUTGOING; currentDirection = CheckDirection.OUTGOING; @@ -504,8 +483,7 @@ private void checkOutgoing() } @Override - public void onCheckingStart(Stage stage) - { + public void onCheckingStart(Stage stage) { this.stage = stage; switch (stage) { @@ -522,22 +500,18 @@ public void onCheckingStart(Stage stage) } - private class CheckOutgoingTask extends CheckAccountTask - { - private CheckOutgoingTask(AccountConfig accountConfig) - { + private class CheckOutgoingTask extends CheckAccountTask { + private CheckOutgoingTask(AccountConfig accountConfig) { super(accountConfig); } - private CheckOutgoingTask(AccountConfig accountConfig, CheckSettingsSuccessCallback callback) - { + private CheckOutgoingTask(AccountConfig accountConfig, CheckSettingsSuccessCallback callback) { super(accountConfig, callback); } @Override void checkSettings() - throws Exception - { + throws Exception { Transport transport; if (editSettings) { @@ -558,28 +532,23 @@ void checkSettings() } } - private class CheckIncomingTask extends CheckAccountTask - { - private CheckIncomingTask(AccountConfig accountConfig) - { + private class CheckIncomingTask extends CheckAccountTask { + private CheckIncomingTask(AccountConfig accountConfig) { super(accountConfig); } - private CheckIncomingTask(AccountConfig accountConfig, CheckSettingsSuccessCallback callback) - { + private CheckIncomingTask(AccountConfig accountConfig, CheckSettingsSuccessCallback callback) { super(accountConfig, callback); } @Override void checkSettings() - throws Exception - { + throws Exception { checkIncomingSettings(); } private void checkIncomingSettings() - throws MessagingException - { + throws MessagingException { if (editSettings) { clearCertificateErrorNotifications(CheckDirection.INCOMING); } @@ -609,18 +578,15 @@ private void checkIncomingSettings() * FIXME: Don't use an AsyncTask to perform network operations. * See also discussion in https://github.com/k9mail/k-9/pull/560 */ - private abstract class CheckAccountTask extends AsyncTask - { + private abstract class CheckAccountTask extends AsyncTask { private final AccountConfig accountConfig; private final CheckSettingsSuccessCallback callback; - private CheckAccountTask(AccountConfig accountConfig) - { + private CheckAccountTask(AccountConfig accountConfig) { this(accountConfig, null); } - private CheckAccountTask(AccountConfig accountConfig, CheckSettingsSuccessCallback callback) - { + private CheckAccountTask(AccountConfig accountConfig, CheckSettingsSuccessCallback callback) { this.accountConfig = accountConfig; this.callback = callback; } @@ -629,8 +595,7 @@ abstract void checkSettings() throws Exception; @Override - protected Boolean doInBackground(CheckDirection... params) - { + protected Boolean doInBackground(CheckDirection... params) { try { checkSettings(); return true; @@ -661,8 +626,7 @@ protected Boolean doInBackground(CheckDirection... params) } @Override - protected void onPostExecute(Boolean bool) - { + protected void onPostExecute(Boolean bool) { super.onPostExecute(bool); /* @@ -679,22 +643,19 @@ protected void onPostExecute(Boolean bool) } } - void clearCertificateErrorNotifications(CheckDirection direction) - { + void clearCertificateErrorNotifications(CheckDirection direction) { final MessagingController ctrl = MessagingController.getInstance(context); ctrl.clearCertificateErrorNotifications((Account) accountConfig, direction); } @Override - protected void onProgressUpdate(Integer... values) - { + protected void onProgressUpdate(Integer... values) { view.setMessage(values[0]); } } - private String getXmlAttribute(XmlResourceParser xml, String name) - { + private String getXmlAttribute(XmlResourceParser xml, String name) { int resId = xml.getAttributeResourceValue(null, name, 0); if (resId == 0) { return xml.getAttributeValue(null, name); @@ -704,8 +665,7 @@ private String getXmlAttribute(XmlResourceParser xml, String name) } } - private Provider findProviderForDomain(String domain) - { + private Provider findProviderForDomain(String domain) { try { XmlResourceParser xml = context.getResources().getXml(R.xml.providers); int xmlEventType; @@ -745,8 +705,7 @@ else if (xmlEventType == XmlResourceParser.END_TAG } private URI getDefaultStoreURI(String username, String password, String server) - throws URISyntaxException - { + throws URISyntaxException { String passwordEnc = UrlEncodingHelper.encodeUtf8(password); String userInfo = username + ":" + passwordEnc; @@ -754,8 +713,7 @@ private URI getDefaultStoreURI(String username, String password, String server) } private URI getDefaultTransportURI(String username, String password, String server, ConnectionSecurity connectionSecurity) - throws URISyntaxException - { + throws URISyntaxException { String passwordEnc = UrlEncodingHelper.encodeUtf8(password); String userInfo = username + ":" + passwordEnc; @@ -768,8 +726,7 @@ private URI getDefaultTransportURI(String username, String password, String serv } private void modifyAccount(String email, String password, @NonNull Provider provider, boolean usingOAuth2) - throws URISyntaxException - { + throws URISyntaxException { accountConfig.init(email, password); String[] emailParts = EmailHelper.splitEmail(email); @@ -823,8 +780,7 @@ private void modifyAccount(String email, String password, @NonNull Provider prov accountConfig.setDeletePolicy(AccountCreator.getDefaultDeletePolicy(incomingSettings.type)); } - private void setupFolderNames(String domain) - { + private void setupFolderNames(String domain) { accountConfig.setDraftsFolder(XryptoMail.getResString(R.string.special_mailbox_name_drafts)); accountConfig.setTrashFolder(XryptoMail.getResString(R.string.special_mailbox_name_trash)); accountConfig.setSentFolder(XryptoMail.getResString(R.string.special_mailbox_name_sent)); @@ -840,8 +796,7 @@ private void setupFolderNames(String domain) } @Override - public void onCertificateAccepted(X509Certificate certificate) - { + public void onCertificateAccepted(X509Certificate certificate) { try { accountConfig.addCertificate(currentDirection, certificate); } catch (CertificateException e) { @@ -853,8 +808,7 @@ public void onCertificateAccepted(X509Certificate certificate) } @Override - public void onCertificateRefused() - { + public void onCertificateRefused() { if (stage == Stage.INCOMING_CHECKING) { view.goToIncoming(); } @@ -864,8 +818,7 @@ else if (stage == Stage.OUTGOING_CHECKING) { } @Override - public void onPositiveClickedInConfirmationDialog() - { + public void onPositiveClickedInConfirmationDialog() { if (stage == Stage.INCOMING_CHECKING) { view.goToIncoming(); } @@ -877,8 +830,7 @@ else if (stage == Stage.OUTGOING_CHECKING) { } } - private void replayChecking() - { + private void replayChecking() { if (direction == CheckDirection.BOTH && currentDirection == CheckDirection.INCOMING) { checkIncomingAndOutgoing(); } @@ -890,8 +842,7 @@ else if (currentDirection == CheckDirection.INCOMING) { } } - private String errorMessageForCertificateException(CertificateValidationException e) - { + private String errorMessageForCertificateException(CertificateValidationException e) { switch (e.getReason()) { case Expired: return XryptoMail.getResString(R.string.client_certificate_expired, e.getAlias(), e.getMessage()); @@ -907,8 +858,7 @@ private String errorMessageForCertificateException(CertificateValidationExceptio } } - private void acceptKeyDialog(final int msgResId, final CertificateValidationException ex) - { + private void acceptKeyDialog(final int msgResId, final CertificateValidationException ex) { String exMessage = "Unknown Error"; if (ex != null) { if (ex.getCause() != null) { @@ -1023,8 +973,7 @@ else if (name.startsWith("*.") handler.post(() -> view.showAcceptKeyDialog(msgResId, finalExMessage, chainInfo.toString(), chain[0])); } - private void handleCertificateValidationException(CertificateValidationException cve) - { + private void handleCertificateValidationException(CertificateValidationException cve) { Timber.e(cve, "Error while testing settings"); X509Certificate[] chain = cve.getCertChain(); // Avoid NullPointerException in acceptKeyDialog() @@ -1036,8 +985,7 @@ private void handleCertificateValidationException(CertificateValidationException } } - private static class Provider implements Serializable - { + private static class Provider implements Serializable { private static final long serialVersionUID = 8511656164616538989L; public String id; @@ -1057,8 +1005,7 @@ private static class Provider implements Serializable public String note; public static Provider newInstanceFromProviderInfo(@Nullable AutoConfigure.ProviderInfo providerInfo) - throws URISyntaxException - { + throws URISyntaxException { if (providerInfo == null) return null; @@ -1076,8 +1023,7 @@ public static Provider newInstanceFromProviderInfo(@Nullable AutoConfigure.Provi } } - private interface CheckSettingsSuccessCallback - { + private interface CheckSettingsSuccessCallback { void onCheckSuccess(); } @@ -1086,8 +1032,7 @@ private interface CheckSettingsSuccessCallback // region incoming @Override - public void onIncomingStart(boolean editSettings) - { + public void onIncomingStart(boolean editSettings) { this.editSettings = editSettings; stage = Stage.INCOMING; ConnectionSecurity[] connectionSecurityChoices = ConnectionSecurity.values(); @@ -1188,13 +1133,11 @@ else if (Type.WebDAV == incomingSettings.type) { } @Override - public void onIncomingStart() - { + public void onIncomingStart() { onIncomingStart(editSettings); } - private void updatePortFromSecurityTypeInIncoming(ConnectionSecurity securityType) - { + private void updatePortFromSecurityTypeInIncoming(ConnectionSecurity securityType) { if (restoring) return; @@ -1203,16 +1146,14 @@ private void updatePortFromSecurityTypeInIncoming(ConnectionSecurity securityTyp currentIncomingPort = port; } - private void updateAuthPlainTextFromSecurityType(ConnectionSecurity securityType) - { + private void updateAuthPlainTextFromSecurityType(ConnectionSecurity securityType) { view.setAuthTypeInsecureText(securityType == ConnectionSecurity.NONE); } @Override public void onInputChangedInIncoming(String certificateAlias, String server, String port, String username, String password, AuthType authType, - ConnectionSecurity connectionSecurity) - { + ConnectionSecurity connectionSecurity) { revokeInvalidSettingsAndUpdateViewInIncoming(authType, connectionSecurity, port); validateFieldInIncoming(certificateAlias, server, currentIncomingPort, username, password, currentIncomingAuthType, currentIncomingSecurityType); @@ -1223,8 +1164,7 @@ public void onNextInIncomingClicked(String username, String password, String cli boolean autoDetectNamespace, String imapPathPrefix, String webdavPathPrefix, String webdavAuthPath, String webdavMailboxPath, String host, int port, ConnectionSecurity connectionSecurity, AuthType authType, boolean compressMobile, boolean compressWifi, boolean compressOther, - boolean subscribedFoldersOnly) - { + boolean subscribedFoldersOnly) { if (authType == AuthType.EXTERNAL) { password = null; @@ -1262,8 +1202,7 @@ else if (WebDAV == incomingSettings.type) { private void revokeInvalidSettingsAndUpdateViewInIncoming(AuthType authType, ConnectionSecurity connectionSecurity, - String port) - { + String port) { boolean isAuthTypeExternal = (AuthType.EXTERNAL == authType); boolean hasConnectionSecurity = (connectionSecurity != ConnectionSecurity.NONE); @@ -1284,28 +1223,24 @@ private void revokeInvalidSettingsAndUpdateViewInIncoming(AuthType authType, } } - private void onAuthTypeSelectedInIncoming(AuthType authType) - { + private void onAuthTypeSelectedInIncoming(AuthType authType) { if (authType != currentIncomingAuthType) { setAuthTypeInIncoming(authType); } } - private void onSecuritySelectedInIncoming(ConnectionSecurity securityType) - { + private void onSecuritySelectedInIncoming(ConnectionSecurity securityType) { if (securityType != currentIncomingSecurityType) { setSecurityTypeInIncoming(securityType); } } - private void setAuthTypeInIncoming(AuthType authType) - { + private void setAuthTypeInIncoming(AuthType authType) { view.setAuthTypeInIncoming(authType); updateViewFromAuthTypeInIncoming(authType); } - private void setSecurityTypeInIncoming(ConnectionSecurity securityType) - { + private void setSecurityTypeInIncoming(ConnectionSecurity securityType) { view.setSecurityTypeInIncoming(securityType); updatePortFromSecurityTypeInIncoming(securityType); updateAuthPlainTextFromSecurityType(securityType); @@ -1313,8 +1248,7 @@ private void setSecurityTypeInIncoming(ConnectionSecurity securityType) private void validateFieldInIncoming(String certificateAlias, String server, String port, - String username, String password, AuthType authType, ConnectionSecurity connectionSecurity) - { + String username, String password, AuthType authType, ConnectionSecurity connectionSecurity) { boolean isAuthTypeOAuth = (AuthType.XOAUTH2 == authType); boolean isOAuthValid = canOAuth2(username); boolean isAuthTypeExternal = (AuthType.EXTERNAL == authType); @@ -1345,8 +1279,7 @@ private void validateFieldInIncoming(String certificateAlias, String server, Str view.setNextButtonInIncomingEnabled(enabled); } - private void checkInvalidOAuthError(boolean isAuthTypeOAuth, boolean isOAuthValid) - { + private void checkInvalidOAuthError(boolean isAuthTypeOAuth, boolean isOAuthValid) { if (isAuthTypeOAuth && !isOAuthValid) { view.showInvalidOAuthError(); } @@ -1355,8 +1288,7 @@ private void checkInvalidOAuthError(boolean isAuthTypeOAuth, boolean isOAuthVali } } - private void updateAccount() - { + private void updateAccount() { Account account = (Account) accountConfig; boolean isPushCapable = false; @@ -1372,8 +1304,7 @@ private void updateAccount() account.save(preferences); } - private void updateViewFromAuthTypeInIncoming(AuthType authType) - { + private void updateViewFromAuthTypeInIncoming(AuthType authType) { if (authType == AuthType.EXTERNAL) { view.setViewExternalInIncoming(); } @@ -1385,8 +1316,7 @@ else if (authType == AuthType.XOAUTH2) { } } - private String getString(int id) - { + private String getString(int id) { return context.getString(id); } @@ -1395,26 +1325,21 @@ private String getString(int id) // region names @Override - public void onNamesStart() - { + public void onNamesStart() { stage = Stage.ACCOUNT_NAMES; } @Override - public void onInputChangedInNames(String name, String description) - { + public void onInputChangedInNames(String name, String description) { view.setDoneButtonInNamesEnabled(Utility.requiredFieldValid(name)); } @Override - public void onNextButtonInNamesClicked(String name, String description) - { + public void onNextButtonInNamesClicked(String name, String description) { if (Utility.requiredFieldValid(description)) { accountConfig.setDescription(description); } - accountConfig.setName(name); - Account account = preferences.newAccount(); account.loadConfig(accountConfig); @@ -1425,7 +1350,6 @@ public void onNextButtonInNamesClicked(String name, String description) if (account.equals(preferences.getDefaultAccount()) || makeDefault) { preferences.setDefaultAccount(account); } - XryptoMail.setServicesEnabled(context); view.goToListAccounts(); } @@ -1434,21 +1358,18 @@ public void onNextButtonInNamesClicked(String name, String description) // region outgoing @Override - public void onOutgoingStart() - { + public void onOutgoingStart() { onOutgoingStart(editSettings); } @Override - public void onOutgoingStart(boolean editSettings) - { + public void onOutgoingStart(boolean editSettings) { this.editSettings = editSettings; stage = Stage.OUTGOING; analysisAccount(); } - private void analysisAccount() - { + private void analysisAccount() { try { if (new URI(accountConfig.getStoreUri()).getScheme().startsWith("webdav")) { accountConfig.setTransportUri(accountConfig.getStoreUri()); @@ -1494,27 +1415,23 @@ private void analysisAccount() } - private void setAuthTypeInOutgoing(AuthType authType) - { + private void setAuthTypeInOutgoing(AuthType authType) { view.setAuthTypeInOutgoing(authType); updateViewFromAuthTypeInOutgoing(authType); } - private void setSecurityTypeInOutgoing(ConnectionSecurity securityType) - { + private void setSecurityTypeInOutgoing(ConnectionSecurity securityType) { view.setSecurityTypeInOutgoing(securityType); updateViewFromSecurityTypeInOutgoing(securityType); } - private void onSecuritySelectedInOutgoing(ConnectionSecurity securityType) - { + private void onSecuritySelectedInOutgoing(ConnectionSecurity securityType) { if (securityType != currentOutgoingSecurityType) { updateViewFromSecurityTypeInOutgoing(securityType); } } - private void onAuthTypeSelectedInOutgoing(AuthType authType) - { + private void onAuthTypeSelectedInOutgoing(AuthType authType) { if (authType != currentOutgoingAuthType) { setAuthTypeInOutgoing(authType); } @@ -1523,8 +1440,7 @@ private void onAuthTypeSelectedInOutgoing(AuthType authType) @Override public void onNextInOutgoingClicked(String username, String password, String clientCertificateAlias, String host, int port, ConnectionSecurity connectionSecurity, - AuthType authType, boolean requireLogin) - { + AuthType authType, boolean requireLogin) { if (!requireLogin) { username = null; @@ -1545,8 +1461,7 @@ public void onNextInOutgoingClicked(String username, String password, String cli @Override public void onInputChangedInOutgoing(String certificateAlias, String server, String port, String username, String password, AuthType authType, - ConnectionSecurity connectionSecurity, boolean requireLogin) - { + ConnectionSecurity connectionSecurity, boolean requireLogin) { if (currentOutgoingSecurityType != connectionSecurity) { boolean isAuthTypeExternal = (AuthType.EXTERNAL == authType); @@ -1568,8 +1483,7 @@ public void onInputChangedInOutgoing(String certificateAlias, String server, Str private void validateFieldInOutgoing(String certificateAlias, String server, String port, String username, String password, AuthType authType, ConnectionSecurity connectionSecurity, - boolean requireLogin) - { + boolean requireLogin) { boolean isAuthTypeOAuth = (AuthType.XOAUTH2 == authType); boolean isAuthTypeExternal = (AuthType.EXTERNAL == authType); @@ -1605,8 +1519,7 @@ private void validateFieldInOutgoing(String certificateAlias, String server, Str private void revokeInvalidSettingsAndUpdateViewInOutgoing(AuthType authType, ConnectionSecurity connectionSecurity, - String port) - { + String port) { boolean isAuthTypeExternal = (AuthType.EXTERNAL == authType); boolean hasConnectionSecurity = (connectionSecurity != ConnectionSecurity.NONE); @@ -1627,8 +1540,7 @@ private void revokeInvalidSettingsAndUpdateViewInOutgoing(AuthType authType, } } - private void updateViewFromSecurityTypeInOutgoing(ConnectionSecurity securityType) - { + private void updateViewFromSecurityTypeInOutgoing(ConnectionSecurity securityType) { view.updateAuthPlainTextInOutgoing(securityType == ConnectionSecurity.NONE); if (restoring) return; @@ -1637,8 +1549,7 @@ private void updateViewFromSecurityTypeInOutgoing(ConnectionSecurity securityTyp currentOutgoingPort = port; } - private void updateViewFromAuthTypeInOutgoing(AuthType authType) - { + private void updateViewFromAuthTypeInOutgoing(AuthType authType) { if (authType == AuthType.EXTERNAL) { view.setViewExternalInOutgoing(); } @@ -1654,15 +1565,13 @@ else if (authType == AuthType.XOAUTH2) { // region account type @Override - public void onAccountTypeStart() - { + public void onAccountTypeStart() { stage = Stage.ACCOUNT_TYPE; } @Override public void onNextButtonInAccountTypeClicked(Type serverType) - throws URISyntaxException - { + throws URISyntaxException { switch (serverType) { case IMAP: onImapOrPop3Selected(IMAP, "imap+ssl+"); @@ -1677,8 +1586,7 @@ public void onNextButtonInAccountTypeClicked(Type serverType) } private void onImapOrPop3Selected(Type serverType, String schemePrefix) - throws URISyntaxException - { + throws URISyntaxException { ServerNameSuggester serverNameSuggester = new ServerNameSuggester(); String domainPart = EmailHelper.getDomainFromEmailAddress(accountConfig.getEmail()); String suggestedStoreServerName = serverNameSuggester.suggestServerName(serverType, domainPart); @@ -1696,8 +1604,7 @@ private void onImapOrPop3Selected(Type serverType, String schemePrefix) } private void onWebdavSelected() - throws URISyntaxException - { + throws URISyntaxException { ServerNameSuggester serverNameSuggester = new ServerNameSuggester(); URI uriForDecode = new URI(accountConfig.getStoreUri()); @@ -1728,8 +1635,7 @@ private void onWebdavSelected() // endregion account type @Override - public void onBackPressed() - { + public void onBackPressed() { if (findProviderTask != null && !findProviderTask.isCancelled()) { findProviderTask.cancel(true); } @@ -1781,49 +1687,41 @@ public void onBackPressed() } @Override - public void setAccount(Account account) - { + public void setAccount(Account account) { this.accountConfig = account; } @Override - public Account getAccount() - { + public Account getAccount() { return (Account) accountConfig; } - public boolean isEditSettings() - { + public boolean isEditSettings() { return editSettings; } @Override - public void onGetAccountUuid(@Nullable String accountUuid) - { + public void onGetAccountUuid(@Nullable String accountUuid) { accountConfig = preferences.getAccount(accountUuid); } @Override - public void onGetAccountConfig(@Nullable AccountConfigImpl accountConfig) - { + public void onGetAccountConfig(@Nullable AccountConfigImpl accountConfig) { this.accountConfig = accountConfig; } @Override - public void onRestoreStart() - { + public void onRestoreStart() { restoring = true; } @Override - public void onRestoreEnd() - { + public void onRestoreEnd() { restoring = false; } @Override - public AccountSetupStatus getStatus() - { + public AccountSetupStatus getStatus() { return new AccountSetupStatus(currentIncomingSecurityType, currentIncomingAuthType, currentIncomingPort, currentOutgoingSecurityType, currentOutgoingAuthType, currentOutgoingPort, accountConfig.isNotifyNewMail(), accountConfig.isShowOngoing(), @@ -1832,19 +1730,16 @@ public AccountSetupStatus getStatus() } @Override - public AccountConfig getAccountConfig() - { + public AccountConfig getAccountConfig() { return accountConfig; } @Override - public void onGetMakeDefault(boolean makeDefault) - { + public void onGetMakeDefault(boolean makeDefault) { this.makeDefault = makeDefault; } - private void manualSetup(String email, String password) - { + private void manualSetup(String email, String password) { autoconfiguration = false; if (accountConfig == null) { @@ -1857,26 +1752,22 @@ private void manualSetup(String email, String password) } @Override - public void handleGmailXOAuth2Intent(Intent intent) - { + public void handleGmailXOAuth2Intent(Intent intent) { view.startIntentForResult(intent, REQUEST_CODE_GMAIL); } @Override - public void handleGmailRedirectUrl(final String url) - { + public void handleGmailRedirectUrl(final String url) { handler.post(() -> view.openGmailUrl(url)); } @Override - public void handleOutlookRedirectUrl(final String url) - { + public void handleOutlookRedirectUrl(final String url) { handler.post(() -> view.openOutlookUrl(url)); } @Override - public void onActivityResult(int requestCode, int resultCode, Intent data) - { + public void onActivityResult(int requestCode, int resultCode, Intent data) { if (requestCode == REQUEST_CODE_GMAIL) { if (resultCode == Activity.RESULT_OK) { checkIncomingAndOutgoing(); @@ -1888,15 +1779,12 @@ public void onActivityResult(int requestCode, int resultCode, Intent data) } @Override - public void onOAuthCodeGot(final String code) - { + public void onOAuthCodeGot(final String code) { oAuth2CodeGotten = true; view.closeAuthDialog(); - new AsyncTask() - { + new AsyncTask() { @Override - protected Boolean doInBackground(Void... params) - { + protected Boolean doInBackground(Void... params) { try { Globals.getOAuth2TokenProvider().getAuthorizationCodeFlowTokenProvider().exchangeCode(accountConfig.getEmail(), code); } catch (AuthenticationFailedException e) { @@ -1906,8 +1794,7 @@ protected Boolean doInBackground(Void... params) } @Override - protected void onPostExecute(Boolean result) - { + protected void onPostExecute(Boolean result) { if (result) { checkIncomingAndOutgoing(); } @@ -1921,8 +1808,7 @@ protected void onPostExecute(Boolean result) } @Override - public void onErrorWhenGettingOAuthCode(String errorMessage) - { + public void onErrorWhenGettingOAuthCode(String errorMessage) { oAuth2CodeGotten = false; view.closeAuthDialog(); view.goToBasics(); @@ -1930,8 +1816,7 @@ public void onErrorWhenGettingOAuthCode(String errorMessage) } @Override - public void onWebViewDismiss() - { + public void onWebViewDismiss() { if (!oAuth2CodeGotten) { view.goToBasics(); view.showErrorDialog("Please connect us with Gmail"); // TODO: 8/18/17 A better error message? @@ -1939,33 +1824,28 @@ public void onWebViewDismiss() } @Override - public void onPause() - { + public void onPause() { canceled = true; } @Override - public void onStop() - { + public void onStop() { canceled = true; } @Override - public void onDestroy() - { + public void onDestroy() { canceled = true; destroyed = true; } @Override - public void onResume() - { + public void onResume() { canceled = false; destroyed = false; } - static class AccountSetupStatus - { + static class AccountSetupStatus { private final ConnectionSecurity incomingSecurityType; private final AuthType incomingAuthType; private final String incomingPort; @@ -1987,8 +1867,7 @@ static class AccountSetupStatus String incomingPort, ConnectionSecurity outgoingSecurityType, AuthType outgoingAuthType, String outgoingPort, boolean notifyNewMail, boolean showOngoing, int automaticCheckIntervalMinutes, int displayCount, Account.FolderMode folderPushMode, - String name, String description) - { + String name, String description) { this.incomingSecurityType = incomingSecurityType; this.incomingAuthType = incomingAuthType; this.incomingPort = incomingPort; @@ -2004,68 +1883,55 @@ static class AccountSetupStatus this.description = description; } - public ConnectionSecurity getIncomingSecurityType() - { + public ConnectionSecurity getIncomingSecurityType() { return incomingSecurityType; } - public AuthType getIncomingAuthType() - { + public AuthType getIncomingAuthType() { return incomingAuthType; } - public String getIncomingPort() - { + public String getIncomingPort() { return incomingPort; } - public ConnectionSecurity getOutgoingSecurityType() - { + public ConnectionSecurity getOutgoingSecurityType() { return outgoingSecurityType; } - public AuthType getOutgoingAuthType() - { + public AuthType getOutgoingAuthType() { return outgoingAuthType; } - public String getOutgoingPort() - { + public String getOutgoingPort() { return outgoingPort; } - public boolean isNotifyNewMail() - { + public boolean isNotifyNewMail() { return notifyNewMail; } - public boolean isShowOngoing() - { + public boolean isShowOngoing() { return showOngoing; } - public int getAutomaticCheckIntervalMinutes() - { + public int getAutomaticCheckIntervalMinutes() { return automaticCheckIntervalMinutes; } - public int getDisplayCount() - { + public int getDisplayCount() { return displayCount; } - public FolderMode getFolderPushMode() - { + public FolderMode getFolderPushMode() { return folderPushMode; } - public String getName() - { + public String getName() { return name; } - public String getDescription() - { + public String getDescription() { return description; } } diff --git a/XryptoMail/src/main/java/org/atalk/xryptomail/impl/appupdate/UpdateServiceImpl.java b/XryptoMail/src/main/java/org/atalk/xryptomail/impl/appupdate/UpdateServiceImpl.java index 7aaee06..2ae435f 100755 --- a/XryptoMail/src/main/java/org/atalk/xryptomail/impl/appupdate/UpdateServiceImpl.java +++ b/XryptoMail/src/main/java/org/atalk/xryptomail/impl/appupdate/UpdateServiceImpl.java @@ -407,9 +407,10 @@ public boolean isLatestVersion() { for (String aLink : updateLinks) { try { if (isValidateLink(aLink)) { - InputStream in = mHttpConnection.getInputStream(); + InputStream inputStream = mHttpConnection.getInputStream(); Properties mProperties = new Properties(); - mProperties.load(in); + mProperties.load(inputStream); + inputStream.close(); latestVersion = mProperties.getProperty("last_version"); latestVersionCode = Long.parseLong(mProperties.getProperty("last_version_code")); diff --git a/XryptoMail/src/main/java/org/atalk/xryptomail/mail/autoconfiguration/DNSOperation.java b/XryptoMail/src/main/java/org/atalk/xryptomail/mail/autoconfiguration/DNSOperation.java old mode 100644 new mode 100755 index 3e245ca..c83c98a --- a/XryptoMail/src/main/java/org/atalk/xryptomail/mail/autoconfiguration/DNSOperation.java +++ b/XryptoMail/src/main/java/org/atalk/xryptomail/mail/autoconfiguration/DNSOperation.java @@ -21,7 +21,6 @@ /** * Util class for DNS operations */ - class DNSOperation { MXRecord mxLookup(String domain) throws TextParseException, UnknownHostException { Lookup lookup = new Lookup(domain, Type.MX, DClass.IN); @@ -32,7 +31,6 @@ MXRecord mxLookup(String domain) throws TextParseException, UnknownHostException if (records == null) return null; MXRecord[] mxRecords = Arrays.copyOf(records, records.length, MXRecord[].class); - MXRecord res = null; if (lookup.getResult() == Lookup.SUCCESSFUL) { for (MXRecord record : mxRecords) { @@ -41,7 +39,6 @@ MXRecord mxLookup(String domain) throws TextParseException, UnknownHostException } } } - return res; } diff --git a/XryptoMail/src/main/java/org/atalk/xryptomail/mail/autoconfiguration/DnsHelper.java b/XryptoMail/src/main/java/org/atalk/xryptomail/mail/autoconfiguration/DnsHelper.java index 2b25fa8..ef79fa3 100755 --- a/XryptoMail/src/main/java/org/atalk/xryptomail/mail/autoconfiguration/DnsHelper.java +++ b/XryptoMail/src/main/java/org/atalk/xryptomail/mail/autoconfiguration/DnsHelper.java @@ -1,8 +1,11 @@ package org.atalk.xryptomail.mail.autoconfiguration; +import android.net.TrafficStats; + import java.net.UnknownHostException; +import org.atalk.xryptomail.XryptoMail; import org.xbill.DNS.MXRecord; import org.xbill.DNS.TextParseException; @@ -11,6 +14,7 @@ public class DnsHelper { public static String getMxDomain(String domain) throws UnknownHostException { DNSOperation dnsOperation = new DNSOperation(); MXRecord mxRecord; + TrafficStats.setThreadStatsTag(XryptoMail.THREAD_ID); try { mxRecord = dnsOperation.mxLookup(domain); } catch (TextParseException e) { diff --git a/XryptoMail/src/main/java/org/atalk/xryptomail/mail/internet/MimeUtility.java b/XryptoMail/src/main/java/org/atalk/xryptomail/mail/internet/MimeUtility.java index f492442..cb16f83 100755 --- a/XryptoMail/src/main/java/org/atalk/xryptomail/mail/internet/MimeUtility.java +++ b/XryptoMail/src/main/java/org/atalk/xryptomail/mail/internet/MimeUtility.java @@ -2,6 +2,13 @@ import androidx.annotation.NonNull; +import java.io.IOException; +import java.io.InputStream; +import java.util.HashMap; +import java.util.Locale; +import java.util.Map; +import java.util.regex.Pattern; + import org.apache.james.mime4j.codec.Base64InputStream; import org.apache.james.mime4j.codec.QuotedPrintableInputStream; import org.apache.james.mime4j.util.MimeUtil; @@ -12,17 +19,9 @@ import org.atalk.xryptomail.mail.Multipart; import org.atalk.xryptomail.mail.Part; -import java.io.IOException; -import java.io.InputStream; -import java.util.HashMap; -import java.util.Locale; -import java.util.Map; -import java.util.regex.Pattern; - import timber.log.Timber; -public class MimeUtility -{ +public class MimeUtility { public static final String DEFAULT_ATTACHMENT_MIME_TYPE = "application/octet-stream"; public static final String XRYPTOMAIL_SETTINGS_MIME_TYPE = "application/x-XryptoMailsettings"; /* @@ -884,16 +883,14 @@ public class MimeUtility {"zmm", "application/vnd.handheld-entertainment+xml"} }; - public static String unfold(String s) - { + public static String unfold(String s) { if (s == null) { return null; } return s.replaceAll("[\r\n]", ""); } - private static String decode(String s, Message message) - { + private static String decode(String s, Message message) { if (s == null) { return null; } @@ -902,19 +899,16 @@ private static String decode(String s, Message message) } } - public static String unfoldAndDecode(String s) - { + public static String unfoldAndDecode(String s) { return unfoldAndDecode(s, null); } - public static String unfoldAndDecode(String s, Message message) - { + public static String unfoldAndDecode(String s, Message message) { return decode(unfold(s), message); } // TODO implement proper foldAndEncode - public static String foldAndEncode(String s) - { + public static String foldAndEncode(String s) { return s; } @@ -928,10 +922,10 @@ public static String foldAndEncode(String s) * * @param headerBody The header body. * @param name The parameter name. Might be {@code null}. + * * @return the (parameter) value. if the parameter cannot be found the method returns null. */ - public static String getHeaderParameter(String headerBody, String name) - { + public static String getHeaderParameter(String headerBody, String name) { if (headerBody == null) { return null; } @@ -950,8 +944,7 @@ public static String getHeaderParameter(String headerBody, String name) } } - public static Map getAllHeaderParameters(String headerBody) - { + public static Map getAllHeaderParameters(String headerBody) { Map result = new HashMap<>(); headerBody = headerBody.replaceAll("[\r\n]", ""); @@ -968,8 +961,7 @@ public static Map getAllHeaderParameters(String headerBody) } - public static Part findFirstPartByMimeType(Part part, String mimeType) - { + public static Part findFirstPartByMimeType(Part part, String mimeType) { if (part.getBody() instanceof Multipart) { Multipart multipart = (Multipart) part.getBody(); for (BodyPart bodyPart : multipart.getBodyParts()) { @@ -990,16 +982,15 @@ else if (isSameMimeType(part.getMimeType(), mimeType)) { * * @param mimeType A MIME type to check. * @param matchAgainst A MIME type to check against. May include wildcards such as image/* or * /*. + * * @return */ - public static boolean mimeTypeMatches(String mimeType, String matchAgainst) - { + public static boolean mimeTypeMatches(String mimeType, String matchAgainst) { Pattern p = Pattern.compile(matchAgainst.replaceAll("\\*", "\\.\\*"), Pattern.CASE_INSENSITIVE); return p.matcher(mimeType).matches(); } - public static boolean isDefaultMimeType(String mimeType) - { + public static boolean isDefaultMimeType(String mimeType) { return isSameMimeType(mimeType, DEFAULT_ATTACHMENT_MIME_TYPE); } @@ -1014,8 +1005,7 @@ public static boolean isDefaultMimeType(String mimeType) * {@code RawDataBody} can be merged into {@link Body}. */ public static InputStream decodeBody(Body body) - throws MessagingException - { + throws MessagingException { InputStream inputStream; if (body instanceof RawDataBody) { RawDataBody rawDataBody = (RawDataBody) body; @@ -1027,26 +1017,26 @@ public static InputStream decodeBody(Body body) inputStream = rawInputStream; } else if (MimeUtil.ENC_BASE64.equalsIgnoreCase(encoding)) { - inputStream = new Base64InputStream(rawInputStream, false) - { + inputStream = new Base64InputStream(rawInputStream, false) { @Override public void close() - throws IOException - { + throws IOException { super.close(); closeInputStreamWithoutDeletingTemporaryFiles(rawInputStream); } }; } else if (MimeUtil.ENC_QUOTED_PRINTABLE.equalsIgnoreCase(encoding)) { - inputStream = new QuotedPrintableInputStream(rawInputStream) - { + inputStream = new QuotedPrintableInputStream(rawInputStream) { @Override - public void close() - throws IOException + public void close() // throws IOException { super.close(); - closeInputStreamWithoutDeletingTemporaryFiles(rawInputStream); + try { + closeInputStreamWithoutDeletingTemporaryFiles(rawInputStream); + } catch (IOException e) { + throw new RuntimeException(e); + } } }; } @@ -1062,8 +1052,7 @@ public void close() } public static void closeInputStreamWithoutDeletingTemporaryFiles(InputStream rawInputStream) - throws IOException - { + throws IOException { if (rawInputStream instanceof BinaryTempFileBody.BinaryTempFileBodyInputStream) { ((BinaryTempFileBody.BinaryTempFileBodyInputStream) rawInputStream).closeWithoutDeleting(); } @@ -1072,8 +1061,7 @@ public static void closeInputStreamWithoutDeletingTemporaryFiles(InputStream raw } } - public static String getMimeTypeByExtension(String filename) - { + public static String getMimeTypeByExtension(String filename) { String returnedType = null; String extension = null; @@ -1096,8 +1084,7 @@ else if (extension != null) { return DEFAULT_ATTACHMENT_MIME_TYPE; } - public static String getExtensionByMimeType(@NonNull String mimeType) - { + public static String getExtensionByMimeType(@NonNull String mimeType) { String lowerCaseMimeType = mimeType.toLowerCase(Locale.US); for (String[] contentTypeMapEntry : MIME_TYPE_BY_EXTENSION_MAP) { if (contentTypeMapEntry[1].equals(lowerCaseMimeType)) { @@ -1121,10 +1108,10 @@ public static String getExtensionByMimeType(@NonNull String mimeType) * * * @param type A String representing a MIME content-type + * * @return A String representing a MIME content-transfer-encoding */ - public static String getEncodingforType(String type) - { + public static String getEncodingforType(String type) { if (type == null) { return (MimeUtil.ENC_BASE64); } @@ -1142,23 +1129,19 @@ else if (isMultipart(type)) { } } - public static boolean isMultipart(String mimeType) - { + public static boolean isMultipart(String mimeType) { return ((mimeType != null) && mimeType.toLowerCase(Locale.US).startsWith("multipart/")); } - public static boolean isMessage(String mimeType) - { + public static boolean isMessage(String mimeType) { return isSameMimeType(mimeType, "message/rfc822"); } - public static boolean isMessageType(String mimeType) - { + public static boolean isMessageType(String mimeType) { return mimeType != null && mimeType.toLowerCase(Locale.ROOT).startsWith("message/"); } - public static boolean isSameMimeType(String mimeType, String otherMimeType) - { + public static boolean isSameMimeType(String mimeType, String otherMimeType) { return ((mimeType != null) && mimeType.equalsIgnoreCase(otherMimeType)); } } diff --git a/XryptoMail/src/main/java/org/atalk/xryptomail/mail/store/webdav/WebDavStore.java b/XryptoMail/src/main/java/org/atalk/xryptomail/mail/store/webdav/WebDavStore.java index bd82df6..52fef02 100755 --- a/XryptoMail/src/main/java/org/atalk/xryptomail/mail/store/webdav/WebDavStore.java +++ b/XryptoMail/src/main/java/org/atalk/xryptomail/mail/store/webdav/WebDavStore.java @@ -89,7 +89,7 @@ public static String createUri(ServerSettings server) private String mCachedLoginUrl; private Folder mSendFolder = null; - private Map mFolderList = new HashMap<>(); + private final Map mFolderList = new HashMap<>(); public WebDavStore(StoreConfig storeConfig, WebDavHttpClient.WebDavHttpClientFactory clientFactory) throws MessagingException @@ -120,14 +120,14 @@ public WebDavStore(StoreConfig storeConfig, WebDavHttpClient.WebDavHttpClientFac String mMailboxPath = serverSettings.mailboxPath; - if (mPath == null || mPath.equals("")) { + if (mPath == null || mPath.isEmpty()) { mPath = "/Exchange"; } else if (!mPath.startsWith("/")) { mPath = "/" + mPath; } - if (mMailboxPath == null || mMailboxPath.equals("")) { + if (mMailboxPath == null || mMailboxPath.isEmpty()) { mMailboxPath = "/" + mAlias; } else if (!mMailboxPath.startsWith("/")) { @@ -135,7 +135,7 @@ else if (!mMailboxPath.startsWith("/")) { } if (mFormBasedAuthPath != null && - !mFormBasedAuthPath.equals("") && + !mFormBasedAuthPath.isEmpty() && !mFormBasedAuthPath.startsWith("/")) { mFormBasedAuthPath = "/" + mFormBasedAuthPath; } @@ -597,7 +597,7 @@ else if ((info.statusCode >= 200 && info.statusCode < 300) || // Success // authorization URL. info.requiredAuthType = WebDavConstants.AUTH_TYPE_FORM_BASED; - if (mFormBasedAuthPath != null && !mFormBasedAuthPath.equals("")) { + if (mFormBasedAuthPath != null && !mFormBasedAuthPath.isEmpty()) { // The user specified their own authentication path, use that. info.guessedAuthUrl = getRoot() + mFormBasedAuthPath; } @@ -642,7 +642,7 @@ private void performFormBasedAuthentication(ConnectionInfo info) if (info != null) { loginUrl = info.guessedAuthUrl; } - else if (mCachedLoginUrl != null && !mCachedLoginUrl.equals("")) { + else if (mCachedLoginUrl != null && !mCachedLoginUrl.isEmpty()) { loginUrl = mCachedLoginUrl; } else { @@ -672,7 +672,7 @@ else if (mCachedLoginUrl != null && !mCachedLoginUrl.equals("")) { String formAction = findFormAction(WebDavHttpClient.getUngzippedContent(response.getEntity())); if (formAction == null) { // If there is no form action, try using our redirect URL from the initial connection. - if (info != null && info.redirectUrl != null && !info.redirectUrl.equals("")) { + if (info != null && info.redirectUrl != null && !info.redirectUrl.isEmpty()) { loginUrl = info.redirectUrl; request = new HttpGeneric(loginUrl); diff --git a/XryptoMail/src/main/java/org/atalk/xryptomail/mailstore/LocalStore.java b/XryptoMail/src/main/java/org/atalk/xryptomail/mailstore/LocalStore.java index 0957871..b87dbed 100755 --- a/XryptoMail/src/main/java/org/atalk/xryptomail/mailstore/LocalStore.java +++ b/XryptoMail/src/main/java/org/atalk/xryptomail/mailstore/LocalStore.java @@ -6,9 +6,28 @@ import android.database.Cursor; import android.database.sqlite.SQLiteDatabase; import android.net.Uri; -import androidx.annotation.Nullable; import android.text.TextUtils; +import androidx.annotation.Nullable; + +import java.io.ByteArrayInputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.Stack; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; + import org.apache.james.mime4j.codec.Base64InputStream; import org.apache.james.mime4j.codec.QuotedPrintableInputStream; import org.apache.james.mime4j.util.MimeUtil; @@ -47,24 +66,6 @@ import org.atalk.xryptomail.search.SqlQueryBuilder; import org.openintents.openpgp.util.OpenPgpApi.OpenPgpDataSource; -import java.io.ByteArrayInputStream; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.LinkedList; -import java.util.List; -import java.util.Locale; -import java.util.Map; -import java.util.Stack; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentMap; - import timber.log.Timber; /** @@ -72,8 +73,7 @@ * Implements a SQLite database backed local store for Messages. * */ -public class LocalStore extends Store -{ +public class LocalStore extends Store { /** * Immutable empty {@link String} array */ @@ -196,11 +196,11 @@ public class LocalStore extends Store * * @param account * @param context + * * @throws UnavailableStorageException if not {@link StorageProvider#isReady(Context)} */ private LocalStore(final Account account, final Context context) - throws MessagingException - { + throws MessagingException { mContext = context; mContentResolver = context.getContentResolver(); mAccount = account; @@ -223,8 +223,7 @@ private LocalStore(final Account account, final Context context) * @throws UnavailableStorageException if not {@link StorageProvider#isReady(Context)} */ public static LocalStore getInstance(Account account, Context context) - throws MessagingException - { + throws MessagingException { String accountUuid = account.getUuid(); // Create new per-account lock object if necessary sAccountLocks.putIfAbsent(accountUuid, new Object()); @@ -242,8 +241,7 @@ public static LocalStore getInstance(Account account, Context context) } } - public static void removeAccount(Account account) - { + public static void removeAccount(Account account) { try { removeInstance(account); } catch (Exception e) { @@ -251,35 +249,29 @@ public static void removeAccount(Account account) } } - private static void removeInstance(Account account) - { + private static void removeInstance(Account account) { sLocalStores.remove(account.getUuid()); } public void switchLocalStorage(final String newStorageProviderId) - throws MessagingException - { + throws MessagingException { database.switchProvider(newStorageProviderId); } - Context getContext() - { + Context getContext() { return mContext; } - Account getAccount() - { + Account getAccount() { return mAccount; } - protected Storage getStorage() - { + protected Storage getStorage() { return Preferences.getPreferences(mContext).getStorage(); } public long getSize() - throws MessagingException - { + throws MessagingException { final StorageManager storageManager = StorageManager.getInstance(mContext); final File attachmentDirectory = storageManager.getAttachmentDirectory(mAccountUuid, database.getStorageProviderId()); @@ -299,8 +291,7 @@ public long getSize() } public void compact() - throws MessagingException - { + throws MessagingException { if (XryptoMail.isDebug()) { Timber.i("Before compaction size = %d", getSize()); } @@ -316,8 +307,7 @@ public void compact() } public void clear() - throws MessagingException - { + throws MessagingException { if (XryptoMail.isDebug()) { Timber.i("Before prune size = %d", getSize()); } @@ -352,8 +342,7 @@ public void clear() } private int getMessageCount() - throws MessagingException - { + throws MessagingException { return database.execute(false, db -> { Cursor cursor = null; try { @@ -367,8 +356,7 @@ private int getMessageCount() } private int getFolderCount() - throws MessagingException - { + throws MessagingException { return database.execute(false, db -> { Cursor cursor = null; try { @@ -381,15 +369,13 @@ private int getFolderCount() }); } - public LocalFolder getFolder(String name) - { + public LocalFolder getFolder(String name) { return new LocalFolder(this, name); } // TODO this takes about 260-300ms, seems slow. public List getPersonalNamespaces(boolean forceListAll) - throws MessagingException - { + throws MessagingException { final List folders = new LinkedList<>(); try { database.execute(false, (DbCallback>) db -> { @@ -421,32 +407,27 @@ public List getPersonalNamespaces(boolean forceListAll) @Override public void checkSettings() - throws MessagingException - { + throws MessagingException { } public void delete() - throws UnavailableStorageException - { + throws UnavailableStorageException { database.delete(); } public void recreate() - throws UnavailableStorageException - { + throws UnavailableStorageException { database.recreate(); } private void deleteAllMessageDataFromDisk() - throws MessagingException - { + throws MessagingException { markAllMessagePartsDataAsMissing(); deleteAllMessagePartsDataFromDisk(); } private void markAllMessagePartsDataAsMissing() - throws MessagingException - { + throws MessagingException { database.execute(false, (DbCallback) db -> { ContentValues cv = new ContentValues(); cv.put("data_location", DataLocation.MISSING); @@ -455,8 +436,7 @@ private void markAllMessagePartsDataAsMissing() }); } - private void deleteAllMessagePartsDataFromDisk() - { + private void deleteAllMessagePartsDataFromDisk() { final StorageManager storageManager = StorageManager.getInstance(mContext); File attachmentDirectory = storageManager.getAttachmentDirectory(mAccountUuid, database.getStorageProviderId()); File[] files = attachmentDirectory.listFiles(); @@ -472,8 +452,7 @@ private void deleteAllMessagePartsDataFromDisk() } public void resetVisibleLimits(int visibleLimit) - throws MessagingException - { + throws MessagingException { final ContentValues cv = new ContentValues(); cv.put("visible_limit", Integer.toString(visibleLimit)); cv.put("more_messages", MoreMessages.UNKNOWN.getDatabaseName()); @@ -484,8 +463,7 @@ public void resetVisibleLimits(int visibleLimit) } public List getPendingCommands() - throws MessagingException - { + throws MessagingException { return database.execute(false, db -> { Cursor cursor = null; try { @@ -509,8 +487,7 @@ public List getPendingCommands() } public void addPendingCommand(PendingCommand command) - throws MessagingException - { + throws MessagingException { final ContentValues cv = new ContentValues(); cv.put("command", command.getCommandName()); cv.put("data", pendingCommandSerializer.serialize(command)); @@ -521,8 +498,7 @@ public void addPendingCommand(PendingCommand command) } public void removePendingCommand(final PendingCommand command) - throws MessagingException - { + throws MessagingException { database.execute(false, (DbCallback) db -> { db.delete("pending_commands", "id = ?", new String[]{Long.toString(command.databaseId)}); return null; @@ -530,8 +506,7 @@ public void removePendingCommand(final PendingCommand command) } public void removePendingCommands() - throws MessagingException - { + throws MessagingException { database.execute(false, (DbCallback) db -> { db.delete("pending_commands", null, null); return null; @@ -539,20 +514,17 @@ public void removePendingCommands() } @Override - public boolean isMoveCapable() - { + public boolean isMoveCapable() { return true; } @Override - public boolean isCopyCapable() - { + public boolean isCopyCapable() { return true; } public List searchForMessages(MessageRetrievalListener retrievalListener, LocalSearch search) - throws MessagingException - { + throws MessagingException { StringBuilder query = new StringBuilder(); List queryArgs = new ArrayList<>(); SqlQueryBuilder.buildWhereClause(mAccount, search.getConditions(), query, queryArgs); @@ -582,8 +554,7 @@ List getMessages( final MessageRetrievalListener listener, final LocalFolder folder, final String queryString, final String[] placeHolders ) - throws MessagingException - { + throws MessagingException { final List messages = new ArrayList<>(); final int j = database.execute(false, db -> { Cursor cursor = null; @@ -628,8 +599,7 @@ List getMessages( } public List getMessagesInThread(final long rootId) - throws MessagingException - { + throws MessagingException { String rootIdString = Long.toString(rootId); LocalSearch search = new LocalSearch(); @@ -639,8 +609,7 @@ public List getMessagesInThread(final long rootId) } public AttachmentInfo getAttachmentInfo(final String attachmentId) - throws MessagingException - { + throws MessagingException { return database.execute(false, db -> { try (Cursor cursor = db.query("message_parts", new String[]{"display_name", "decoded_body_size", "mime_type"}, @@ -664,22 +633,18 @@ public AttachmentInfo getAttachmentInfo(final String attachmentId) @Nullable public OpenPgpDataSource getAttachmentDataSource(final String partId) - throws MessagingException - { - return new OpenPgpDataSource() - { + throws MessagingException { + return new OpenPgpDataSource() { @Override public void writeTo(OutputStream os) - throws IOException - { + throws IOException { writeAttachmentDataToOutputStream(partId, os); } }; } private void writeAttachmentDataToOutputStream(final String partId, final OutputStream outputStream) - throws IOException - { + throws IOException { try { database.execute(false, (DbCallback) db -> { Cursor cursor = db.query("message_parts", @@ -704,8 +669,7 @@ private void writeAttachmentDataToOutputStream(final String partId, final Output } private void writeCursorPartsToOutputStream(SQLiteDatabase db, Cursor cursor, OutputStream outputStream) - throws IOException, MessagingException - { + throws IOException, MessagingException { while (cursor.moveToNext()) { String partId = cursor.getString(ATTACH_PART_ID_INDEX); int location = cursor.getInt(ATTACH_LOCATION_INDEX); @@ -720,8 +684,7 @@ else if (location == DataLocation.CHILD_PART_CONTAINS_DATA) { } private void writeRawBodyToStream(Cursor cursor, SQLiteDatabase db, OutputStream outputStream) - throws IOException, MessagingException - { + throws IOException, MessagingException { long partId = cursor.getLong(ATTACH_PART_ID_INDEX); String rootPart = cursor.getString(ATTACH_ROOT_INDEX); LocalMessage message = loadLocalMessageByRootPartId(db, rootPart); @@ -743,8 +706,7 @@ private void writeRawBodyToStream(Cursor cursor, SQLiteDatabase db, OutputStream body.writeTo(outputStream); } - static Part findPartById(Part searchRoot, long partId) - { + static Part findPartById(Part searchRoot, long partId) { if (searchRoot instanceof LocalMessage) { LocalMessage localMessage = (LocalMessage) searchRoot; if (localMessage.getMessagePartId() == partId) { @@ -778,8 +740,7 @@ static Part findPartById(Part searchRoot, long partId) } private LocalMessage loadLocalMessageByRootPartId(SQLiteDatabase db, String rootPart) - throws MessagingException - { + throws MessagingException { Cursor cursor = db.query("messages", new String[]{"id"}, "message_part_id = ?", new String[]{rootPart}, @@ -799,8 +760,7 @@ private LocalMessage loadLocalMessageByRootPartId(SQLiteDatabase db, String root @Nullable private LocalMessage loadLocalMessageByMessageId(long messageId) - throws MessagingException - { + throws MessagingException { Map> foldersAndUids = getFoldersAndUids(Collections.singletonList(messageId), false); if (foldersAndUids.isEmpty()) { @@ -822,8 +782,7 @@ private LocalMessage loadLocalMessageByMessageId(long messageId) } private void writeSimplePartToOutputStream(String partId, Cursor cursor, OutputStream outputStream) - throws IOException - { + throws IOException { int location = cursor.getInt(ATTACH_LOCATION_INDEX); InputStream inputStream = getRawAttachmentInputStream(partId, location, cursor); try { @@ -836,8 +795,7 @@ private void writeSimplePartToOutputStream(String partId, Cursor cursor, OutputS } private InputStream getRawAttachmentInputStream(String partId, int location, Cursor cursor) - throws FileNotFoundException - { + throws FileNotFoundException { switch (location) { case DataLocation.IN_DATABASE: { byte[] data = cursor.getBlob(ATTACH_DATA_INDEX); @@ -852,29 +810,28 @@ private InputStream getRawAttachmentInputStream(String partId, int location, Cur } } - InputStream getDecodingInputStream(final InputStream rawInputStream, @Nullable String encoding) - { + InputStream getDecodingInputStream(final InputStream rawInputStream, @Nullable String encoding) { if (MimeUtil.ENC_BASE64.equals(encoding)) { - return new Base64InputStream(rawInputStream) - { + return new Base64InputStream(rawInputStream) { @Override public void close() - throws IOException - { + throws IOException { super.close(); rawInputStream.close(); } }; } if (MimeUtil.ENC_QUOTED_PRINTABLE.equals(encoding)) { - return new QuotedPrintableInputStream(rawInputStream) - { + return new QuotedPrintableInputStream(rawInputStream) { @Override - public void close() - throws IOException + public void close() // throws IOException { super.close(); - rawInputStream.close(); + try { + rawInputStream.close(); + } catch (IOException e) { + throw new RuntimeException(e); + } } }; } @@ -882,23 +839,20 @@ public void close() return rawInputStream; } - File getAttachmentFile(String attachmentId) - { + File getAttachmentFile(String attachmentId) { final StorageManager storageManager = StorageManager.getInstance(mContext); final File attachmentDirectory = storageManager.getAttachmentDirectory(mAccountUuid, database.getStorageProviderId()); return new File(attachmentDirectory, attachmentId); } - public static class AttachmentInfo - { + public static class AttachmentInfo { public String name; public long size; public String type; } public void createFolders(final List foldersToCreate, final int visibleLimit) - throws MessagingException - { + throws MessagingException { database.execute(true, (DbCallback) db -> { for (LocalFolder folder : foldersToCreate) { String name = folder.getServerId(); @@ -945,8 +899,7 @@ public void createFolders(final List foldersToCreate, final int vis }); } - static String serializeFlags(Iterable flags) - { + static String serializeFlags(Iterable flags) { List extraFlags = new ArrayList<>(); for (Flag flag : flags) { @@ -967,33 +920,27 @@ static String serializeFlags(Iterable flags) } // TODO: database should not be exposed! - public LockableDatabase getDatabase() - { + public LockableDatabase getDatabase() { return database; } - MessagePreviewCreator getMessagePreviewCreator() - { + MessagePreviewCreator getMessagePreviewCreator() { return messagePreviewCreator; } - public MessageFulltextCreator getMessageFulltextCreator() - { + public MessageFulltextCreator getMessageFulltextCreator() { return messageFulltextCreator; } - AttachmentCounter getAttachmentCounter() - { + AttachmentCounter getAttachmentCounter() { return attachmentCounter; } - AttachmentInfoExtractor getAttachmentInfoExtractor() - { + AttachmentInfoExtractor getAttachmentInfoExtractor() { return attachmentInfoExtractor; } - void notifyChange() - { + void notifyChange() { Uri uri = Uri.withAppendedPath(EmailProvider.CONTENT_URI, "account/" + mAccountUuid + "/messages"); mContentResolver.notifyChange(uri, null); } @@ -1007,11 +954,11 @@ void notifyChange() * * @param selectionCallback Supplies the argument set and the code to query/update the database. * @param batchSize The maximum size of the selection set in each SQL statement. + * * @throws MessagingException */ private void doBatchSetSelection(final BatchSetSelection selectionCallback, final int batchSize) - throws MessagingException - { + throws MessagingException { final List selectionArgs = new ArrayList<>(); int start = 0; @@ -1048,8 +995,7 @@ private void doBatchSetSelection(final BatchSetSelection selectionCallback, fina /** * Defines the behavior of {@link LocalStore#doBatchSetSelection(BatchSetSelection, int)}. */ - interface BatchSetSelection - { + interface BatchSetSelection { /** * @return The size of the argument list. */ @@ -1059,6 +1005,7 @@ interface BatchSetSelection * Get a specific item of the argument list. * * @param index The index of the item. + * * @return Item at position {@code i} of the argument list. */ String getListItem(int index); @@ -1070,6 +1017,7 @@ interface BatchSetSelection * @param selectionSet A partial selection string containing place holders for the argument list, e.g. * {@code " IN (?,?,?)"} (starts with a space). * @param selectionArgs The current subset of the argument list. + * * @throws UnavailableStorageException */ void doDbWork(SQLiteDatabase db, String selectionSet, String[] selectionArgs) @@ -1092,38 +1040,33 @@ void doDbWork(SQLiteDatabase db, String selectionSet, String[] selectionArgs) * @param messageIds A list of primary keys in the "messages" table. * @param flag The flag to change. This must be a flag with a separate column in the database. * @param newState {@code true}, if the flag should be set. {@code false}, otherwise. + * * @throws MessagingException */ public void setFlag(final List messageIds, final Flag flag, final boolean newState) - throws MessagingException - { + throws MessagingException { final ContentValues cv = new ContentValues(); cv.put(getColumnNameForFlag(flag), newState); - doBatchSetSelection(new BatchSetSelection() - { + doBatchSetSelection(new BatchSetSelection() { @Override - public int getListSize() - { + public int getListSize() { return messageIds.size(); } @Override - public String getListItem(int index) - { + public String getListItem(int index) { return Long.toString(messageIds.get(index)); } @Override public void doDbWork(SQLiteDatabase db, String selectionSet, String[] selectionArgs) - throws UnavailableStorageException - { + throws UnavailableStorageException { db.update("messages", cv, "empty = 0 AND id" + selectionSet, selectionArgs); } @Override - public void postDbWork() - { + public void postDbWork() { notifyChange(); } }, FLAG_UPDATE_BATCH_SIZE); @@ -1138,30 +1081,26 @@ public void postDbWork() * @param threadRootIds A list of root thread IDs. * @param flag The flag to change. This must be a flag with a separate column in the database. * @param newState {@code true}, if the flag should be set. {@code false}, otherwise. + * * @throws MessagingException */ public void setFlagForThreads(final List threadRootIds, Flag flag, final boolean newState) - throws MessagingException - { + throws MessagingException { final String flagColumn = getColumnNameForFlag(flag); - doBatchSetSelection(new BatchSetSelection() - { + doBatchSetSelection(new BatchSetSelection() { @Override - public int getListSize() - { + public int getListSize() { return threadRootIds.size(); } @Override - public String getListItem(int index) - { + public String getListItem(int index) { return Long.toString(threadRootIds.get(index)); } @Override public void doDbWork(SQLiteDatabase db, String selectionSet, String[] selectionArgs) - throws UnavailableStorageException - { + throws UnavailableStorageException { db.execSQL("UPDATE messages SET " + flagColumn + " = " + ((newState) ? "1" : "0") + " WHERE id IN (" + "SELECT m.id FROM threads t " + @@ -1172,8 +1111,7 @@ public void doDbWork(SQLiteDatabase db, String selectionSet, String[] selectionA } @Override - public void postDbWork() - { + public void postDbWork() { notifyChange(); } }, THREAD_FLAG_UPDATE_BATCH_SIZE); @@ -1187,32 +1125,29 @@ public void postDbWork() * at the root of a thread. In that case return UIDs for all messages in these threads. * If this is {@code false} only the UIDs for messages in {@code messageIds} are * returned. + * * @return The list of UIDs for the messages grouped by folder name. + * * @throws MessagingException */ public Map> getFoldersAndUids(final List messageIds, final boolean threadedList) - throws MessagingException - { + throws MessagingException { final Map> folderMap = new HashMap<>(); - doBatchSetSelection(new BatchSetSelection() - { + doBatchSetSelection(new BatchSetSelection() { @Override - public int getListSize() - { + public int getListSize() { return messageIds.size(); } @Override - public String getListItem(int index) - { + public String getListItem(int index) { return Long.toString(messageIds.get(index)); } @Override public void doDbWork(SQLiteDatabase db, String selectionSet, String[] selectionArgs) - throws UnavailableStorageException - { + throws UnavailableStorageException { if (threadedList) { String sql = "SELECT m.uid, f.name FROM threads t " + "LEFT JOIN messages m ON (t.message_id = m.id) " + @@ -1230,8 +1165,7 @@ public void doDbWork(SQLiteDatabase db, String selectionSet, String[] selectionA } } - private void getDataFromCursor(Cursor cursor) - { + private void getDataFromCursor(Cursor cursor) { try { while (cursor.moveToNext()) { String uid = cursor.getString(0); @@ -1250,16 +1184,14 @@ private void getDataFromCursor(Cursor cursor) } @Override - public void postDbWork() - { + public void postDbWork() { notifyChange(); } }, UID_CHECK_BATCH_SIZE); return folderMap; } - public static String getColumnNameForFlag(Flag flag) - { + public static String getColumnNameForFlag(Flag flag) { switch (flag) { case SEEN: { return MessageColumns.READ; diff --git a/XryptoMail/src/main/java/org/atalk/xryptomail/notification/NotificationActionService.java b/XryptoMail/src/main/java/org/atalk/xryptomail/notification/NotificationActionService.java index ad70668..97f477f 100755 --- a/XryptoMail/src/main/java/org/atalk/xryptomail/notification/NotificationActionService.java +++ b/XryptoMail/src/main/java/org/atalk/xryptomail/notification/NotificationActionService.java @@ -3,11 +3,12 @@ import static org.atalk.xryptomail.activity.MessageReferenceHelper.toMessageReferenceList; import static org.atalk.xryptomail.activity.MessageReferenceHelper.toMessageReferenceStringList; +import android.app.Service; import android.content.Context; import android.content.Intent; +import android.os.IBinder; -import androidx.annotation.NonNull; -import androidx.core.app.JobIntentService; +import androidx.annotation.Nullable; import java.util.ArrayList; import java.util.List; @@ -22,7 +23,7 @@ import timber.log.Timber; -public class NotificationActionService extends JobIntentService { +public class NotificationActionService extends Service { private static final String ACTION_MARK_AS_READ = "ACTION_MARK_AS_READ"; private static final String ACTION_DELETE = "ACTION_DELETE"; private static final String ACTION_ARCHIVE = "ACTION_ARCHIVE"; @@ -112,17 +113,23 @@ private static ArrayList createSingleItemArrayList(MessageReference mess return messageReferenceStrings; } - /** - * Unique job ID for this service. - */ - static final int JOB_ID = 1500; +// /** +// * Unique job ID for this service. +// */ +// static final int JOB_ID = 1500; +// +// public static void enqueueWork(Context context, Intent work) { +// enqueueWork(context, PollService.class, JOB_ID, work); +// } - public static void enqueueWork(Context context, Intent work) { - enqueueWork(context, PollService.class, JOB_ID, work); + @Nullable + @Override + public IBinder onBind(Intent intent) { + return null; } @Override - protected void onHandleWork(@NonNull Intent intent) { + public int onStartCommand(Intent intent, int flags, int startId) { Timber.i("NotificationActionService started"); Account account = null; if (intent.hasExtra(EXTRA_ACCOUNT_UUID)) { @@ -132,7 +139,7 @@ protected void onHandleWork(@NonNull Intent intent) { } if (account == null) { Timber.w("Could not find account for notification action."); - return; + return START_NOT_STICKY; } MessagingController controller = MessagingController.getInstance(getApplication()); @@ -153,6 +160,7 @@ else if (ACTION_DISMISS.equals(action)) { Timber.i("Notification dismissed"); } cancelNotifications(intent, account, controller); + return START_NOT_STICKY; } private void markMessagesAsRead(Intent intent, Account account, MessagingController controller) { diff --git a/XryptoMail/src/main/java/org/atalk/xryptomail/permissions/PermissionsActivity.java b/XryptoMail/src/main/java/org/atalk/xryptomail/permissions/PermissionsActivity.java index 1684335..84065d9 100755 --- a/XryptoMail/src/main/java/org/atalk/xryptomail/permissions/PermissionsActivity.java +++ b/XryptoMail/src/main/java/org/atalk/xryptomail/permissions/PermissionsActivity.java @@ -18,6 +18,7 @@ import android.Manifest; import android.annotation.SuppressLint; +import android.app.Activity; import android.app.AlertDialog; import android.content.Context; import android.content.Intent; @@ -31,12 +32,12 @@ import android.view.View; import android.widget.TextView; +import androidx.activity.result.ActivityResultCallback; import androidx.activity.result.ActivityResultLauncher; import androidx.activity.result.contract.ActivityResultContract; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.annotation.RequiresApi; -import androidx.appcompat.app.AppCompatActivity; import androidx.core.app.ActivityCompat; import androidx.core.content.ContextCompat; import androidx.fragment.app.FragmentActivity; @@ -77,7 +78,7 @@ public class PermissionsActivity extends FragmentActivity { private PermissionsUiBinding mBinding; private MultiplePermissionsListener allPermissionsListener; private MultiplePermissionsListener dialogMultiplePermissionsListener; - private MultiplePermissionsListener contactsPermissionListener; + private PermissionListener contactsPermissionListener; private PermissionListener musicPermissionListener; private MultiplePermissionsListener videoPermissionListener; private PermissionListener notificationsPermissionListener; @@ -95,24 +96,28 @@ public class PermissionsActivity extends FragmentActivity { protected static List permissionList = new LinkedList<>(); static { - permissionList.add(Manifest.permission.CAMERA); permissionList.add(Manifest.permission.READ_CONTACTS); - permissionList.add(Manifest.permission.WRITE_CONTACTS); permissionList.add(permission_DELETE_MESSAGES); permissionList.add(permission_READ_MESSAGES); permissionList.add(permission_REMOTE_CONTROL); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) { + permissionList.add(Manifest.permission.READ_MEDIA_VISUAL_USER_SELECTED); + } + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { + permissionList.add(Manifest.permission.POST_NOTIFICATIONS); permissionList.add(Manifest.permission.READ_MEDIA_AUDIO); - permissionList.add(Manifest.permission.READ_MEDIA_VIDEO); permissionList.add(Manifest.permission.READ_MEDIA_IMAGES); - permissionList.add(Manifest.permission.POST_NOTIFICATIONS); - } - else if (Build.VERSION.SDK_INT == Build.VERSION_CODES.Q) { - permissionList.add(Manifest.permission.ACCESS_MEDIA_LOCATION); + permissionList.add(Manifest.permission.READ_MEDIA_VIDEO); } - else if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) { - permissionList.add(Manifest.permission.WRITE_EXTERNAL_STORAGE); + else { + if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.Q) { + permissionList.add(Manifest.permission.WRITE_EXTERNAL_STORAGE); + } + else { + permissionList.add(Manifest.permission.READ_EXTERNAL_STORAGE); + } } } @@ -172,24 +177,28 @@ private void initView() { mBinding.remoteControlPermissionButton.setOnClickListener(v -> onRemoteControlPermissionButtonClicked()); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { - mBinding.musicPermissionButton.setOnClickListener(v -> onMusicPermissionButtonClicked()); - mBinding.videoPermissionButton.setOnClickListener(v -> onVideoPermissionButtonClicked()); mBinding.notificationsPermissionButton.setOnClickListener(v -> onNotificationsPermissionButtonClicked()); - + mBinding.musicPermissionButton.setOnClickListener(v -> onMusicPermissionButtonClicked()); mBinding.storageView.setVisibility(View.GONE); + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) { + mBinding.videoPermissionButton.setOnClickListener(v -> onMediaUserSelectedPermissionButtonClicked()); + } + else { + mBinding.videoPermissionButton.setOnClickListener(v -> onVideoPermissionButtonClicked()); + } } else { - if (Build.VERSION.SDK_INT > Build.VERSION_CODES.P) { - mBinding.storageView.setVisibility(View.GONE); + if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.Q) { + mBinding.storagePermissionButton.setOnClickListener(v -> onWriteStoragePermissionButtonClicked()); } else { - mBinding.storagePermissionButton.setOnClickListener(v -> onStoragePermissionButtonClicked()); + mBinding.storagePermissionButton.setOnClickListener(v -> onReadStoragePermissionButtonClicked()); } + mBinding.notificationsView.setVisibility(View.GONE); mBinding.musicView.setVisibility(View.GONE); mBinding.videoView.setVisibility(View.GONE); - mBinding.notificationsView.setVisibility(View.GONE); } - mBinding.allPermissionsButton.setOnClickListener(v -> onAllPermissionsButtonClicked()); mBinding.appInfoPermissionsButton.setOnClickListener(v -> onInfoButtonClicked(this)); mBinding.buttonDone.setOnClickListener(v -> onDoneButtonClicked()); @@ -226,12 +235,21 @@ public void onAllPermissionsButtonClicked() { public void onContactsPermissionButtonClicked() { Dexter.withContext(this) - .withPermissions(Manifest.permission.READ_CONTACTS, Manifest.permission.WRITE_CONTACTS) + .withPermission(Manifest.permission.READ_CONTACTS) .withListener(contactsPermissionListener) .withErrorListener(errorListener) .check(); } + @RequiresApi(api = Build.VERSION_CODES.TIRAMISU) + public void onNotificationsPermissionButtonClicked() { + Dexter.withContext(this) + .withPermission(Manifest.permission.POST_NOTIFICATIONS) + .withListener(notificationsPermissionListener) + .withErrorListener(errorListener) + .check(); + } + @RequiresApi(api = Build.VERSION_CODES.TIRAMISU) public void onMusicPermissionButtonClicked() { Dexter.withContext(this) @@ -241,17 +259,17 @@ public void onMusicPermissionButtonClicked() { .check(); } - @RequiresApi(api = Build.VERSION_CODES.TIRAMISU) - public void onNotificationsPermissionButtonClicked() { + @RequiresApi(api = Build.VERSION_CODES.UPSIDE_DOWN_CAKE) + public void onMediaUserSelectedPermissionButtonClicked() { Dexter.withContext(this) - .withPermission(Manifest.permission.POST_NOTIFICATIONS) - .withListener(notificationsPermissionListener) + .withPermissions(Manifest.permission.READ_MEDIA_VISUAL_USER_SELECTED, + Manifest.permission.READ_MEDIA_VIDEO, Manifest.permission.READ_MEDIA_IMAGES) + .withListener(videoPermissionListener) .withErrorListener(errorListener) .check(); } @RequiresApi(api = Build.VERSION_CODES.TIRAMISU) - // READ_MEDIA_VIDEO and READ_MEDIA_IMAGES; need to request only one. public void onVideoPermissionButtonClicked() { Dexter.withContext(this) .withPermissions(Manifest.permission.READ_MEDIA_VIDEO, Manifest.permission.READ_MEDIA_IMAGES) @@ -260,7 +278,15 @@ public void onVideoPermissionButtonClicked() { .check(); } - public void onStoragePermissionButtonClicked() { + public void onReadStoragePermissionButtonClicked() { + Dexter.withContext(this) + .withPermission(Manifest.permission.READ_EXTERNAL_STORAGE) + .withListener(storagePermissionListener) + .withErrorListener(errorListener) + .check(); + } + + public void onWriteStoragePermissionButtonClicked() { Dexter.withContext(this) .withPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE) .withListener(storagePermissionListener) @@ -283,6 +309,7 @@ public void onReadMailPermissionButtonClicked() { .withErrorListener(errorListener) .check(); } + public void onRemoteControlPermissionButtonClicked() { Dexter.withContext(this) .withPermission(permission_REMOTE_CONTROL) @@ -435,32 +462,32 @@ private void createPermissionListeners() { .build(); dialogMultiplePermissionsListener = new CompositeMultiplePermissionsListener(fbMultiplePermissionListener, anyDeniedPermissionListener); - anyDeniedPermissionListener = DialogOnAnyDeniedMultiplePermissionsListener.Builder + deniedPermissionListener = DialogOnDeniedPermissionListener.Builder .withContext(this) .withTitle(R.string.contacts_permission_denied_dialog_title) .withMessage(R.string.contacts_permission_denied_feedback) .withButtonText(android.R.string.ok) .withIcon(R.drawable.ic_icon) .build(); - contactsPermissionListener = new CompositeMultiplePermissionsListener(fbMultiplePermissionListener, anyDeniedPermissionListener); + contactsPermissionListener = new CompositePermissionListener(fbPermissionListener, deniedPermissionListener); deniedPermissionListener = DialogOnDeniedPermissionListener.Builder .withContext(this) - .withTitle(R.string.music_permission_denied_dialog_title) - .withMessage(R.string.music_permission_denied_feedback) + .withTitle(R.string.notifications_permission_denied_dialog_title) + .withMessage(R.string.notifications_permission_denied_feedback) .withButtonText(android.R.string.ok) .withIcon(R.drawable.ic_icon) .build(); - musicPermissionListener = new CompositePermissionListener(fbPermissionListener, deniedPermissionListener); + notificationsPermissionListener = new CompositePermissionListener(fbPermissionListener, deniedPermissionListener); deniedPermissionListener = DialogOnDeniedPermissionListener.Builder .withContext(this) - .withTitle(R.string.notifications_permission_denied_dialog_title) - .withMessage(R.string.notifications_permission_denied_feedback) + .withTitle(R.string.music_permission_denied_dialog_title) + .withMessage(R.string.music_permission_denied_feedback) .withButtonText(android.R.string.ok) .withIcon(R.drawable.ic_icon) .build(); - notificationsPermissionListener = new CompositePermissionListener(fbPermissionListener, deniedPermissionListener); + musicPermissionListener = new CompositePermissionListener(fbPermissionListener, deniedPermissionListener); anyDeniedPermissionListener = DialogOnAnyDeniedMultiplePermissionsListener.Builder .withContext(this) @@ -521,23 +548,24 @@ private TextView getFeedbackViewForPermission(String name) { TextView feedbackView; switch (name) { case Manifest.permission.READ_CONTACTS: - case Manifest.permission.WRITE_CONTACTS: feedbackView = mBinding.contactsPermissionFeedback; break; - case Manifest.permission.READ_MEDIA_AUDIO: - feedbackView = mBinding.musicPermissionFeedback; - break; - case Manifest.permission.POST_NOTIFICATIONS: feedbackView = mBinding.notificationsPermissionFeedback; break; + case Manifest.permission.READ_MEDIA_AUDIO: + feedbackView = mBinding.musicPermissionFeedback; + break; + case Manifest.permission.READ_MEDIA_IMAGES: case Manifest.permission.READ_MEDIA_VIDEO: + case Manifest.permission.READ_MEDIA_VISUAL_USER_SELECTED: feedbackView = mBinding.videoPermissionFeedback; break; + case Manifest.permission.READ_EXTERNAL_STORAGE: case Manifest.permission.WRITE_EXTERNAL_STORAGE: feedbackView = mBinding.storagePermissionFeedback; break; @@ -566,18 +594,21 @@ private TextView getFeedbackViewForPermission(String name) { private boolean openBatteryOptimizationDialogIfNeeded() { // Will always request for battery optimization disable for XryptoMail if not so on XryptoMail new launch if (isOptimizingBattery()) { - AlertDialog.Builder builder = new AlertDialog.Builder(this); - builder.setTitle(R.string.battery_optimizations); - builder.setMessage(R.string.battery_optimizations_dialog); - - builder.setPositiveButton(R.string.next, (dialog, which) -> { - dialog.dismiss(); - mBatteryOptimization.launch(null); - }); - - AlertDialog dialog = builder.create(); - dialog.setCanceledOnTouchOutside(false); - dialog.show(); + // Do not launch this within a dialog, else result return on dialog user click + mBatteryOptimization.launch(null); + +// AlertDialog.Builder builder = new AlertDialog.Builder(this); +// builder.setTitle(R.string.battery_optimizations); +// builder.setMessage(R.string.battery_optimizations_dialog); +// +// builder.setPositiveButton(R.string.next, (dialog, which) -> { +// dialog.dismiss(); +// mBatteryOptimization.launch(null); +// }); +// +// AlertDialog dialog = builder.create(); +// dialog.setCanceledOnTouchOutside(false); +// dialog.show(); return true; } else { @@ -599,6 +630,7 @@ public class GetBatteryOptimization extends ActivityResultContract requestBatteryOptimization() { - return registerForActivityResult(new GetBatteryOptimization(), success -> { - if (!success) { + return registerForActivityResult(new GetBatteryOptimization(), isOptimizingBattery -> { + if (isOptimizingBattery) { XryptoMail.showToastMessage(R.string.battery_optimization_on); } }); diff --git a/XryptoMail/src/main/java/org/atalk/xryptomail/provider/AttachmentTempFileProvider.java b/XryptoMail/src/main/java/org/atalk/xryptomail/provider/AttachmentTempFileProvider.java index e5a59e3..8f803eb 100755 --- a/XryptoMail/src/main/java/org/atalk/xryptomail/provider/AttachmentTempFileProvider.java +++ b/XryptoMail/src/main/java/org/atalk/xryptomail/provider/AttachmentTempFileProvider.java @@ -198,7 +198,7 @@ private static void registerFileCleanupReceiver(Context context) IntentFilter intentFilter = new IntentFilter(); intentFilter.addAction(Intent.ACTION_SCREEN_OFF); - ContextCompat.registerReceiver(context, cleanupReceiver, intentFilter, ContextCompat.RECEIVER_EXPORTED); + ContextCompat.registerReceiver(context, cleanupReceiver, intentFilter, ContextCompat.RECEIVER_NOT_EXPORTED); } } diff --git a/XryptoMail/src/main/java/org/atalk/xryptomail/service/DatabaseUpgradeService.java b/XryptoMail/src/main/java/org/atalk/xryptomail/service/DatabaseUpgradeService.java old mode 100644 new mode 100755 index 858e17a..f61711b --- a/XryptoMail/src/main/java/org/atalk/xryptomail/service/DatabaseUpgradeService.java +++ b/XryptoMail/src/main/java/org/atalk/xryptomail/service/DatabaseUpgradeService.java @@ -5,16 +5,19 @@ import android.content.Intent; import android.os.IBinder; import android.os.PowerManager; + import androidx.localbroadcastmanager.content.LocalBroadcastManager; -import org.atalk.xryptomail.*; +import java.util.List; +import java.util.concurrent.atomic.AtomicBoolean; + +import org.atalk.xryptomail.Account; +import org.atalk.xryptomail.Preferences; +import org.atalk.xryptomail.XryptoMail; import org.atalk.xryptomail.activity.UpgradeDatabases; +import org.atalk.xryptomail.mailstore.UnavailableStorageException; import org.atalk.xryptomail.power.TracingPowerManager; import org.atalk.xryptomail.power.TracingPowerManager.TracingWakeLock; -import org.atalk.xryptomail.mailstore.UnavailableStorageException; - -import java.util.List; -import java.util.concurrent.atomic.AtomicBoolean; import timber.log.Timber; @@ -25,8 +28,7 @@ * See {@link UpgradeDatabases} for a detailed explanation of the database upgrade process. *

*/ -public class DatabaseUpgradeService extends Service -{ +public class DatabaseUpgradeService extends Service { /** * Broadcast intent reporting the current progress of the database upgrade. * @@ -78,8 +80,7 @@ public class DatabaseUpgradeService extends Service * * @param context The {@link Context} used to start this service. */ - public static void startService(Context context) - { + public static void startService(Context context) { Intent i = new Intent(); i.setClass(context, DatabaseUpgradeService.class); i.setAction(DatabaseUpgradeService.ACTION_START_SERVICE); @@ -101,21 +102,18 @@ public static void startService(Context context) private TracingWakeLock mWakeLock; @Override - public IBinder onBind(Intent intent) - { + public IBinder onBind(Intent intent) { // unused return null; } @Override - public void onCreate() - { + public void onCreate() { mLocalBroadcastManager = LocalBroadcastManager.getInstance(this); } @Override - public final int onStartCommand(Intent intent, int flags, int startId) - { + public final int onStartCommand(Intent intent, int flags, int startId) { boolean success = mRunning.compareAndSet(false, true); if (success) { // The service wasn't running yet. @@ -137,8 +135,7 @@ public final int onStartCommand(Intent intent, int flags, int startId) /** * Acquire a partial wake lock so the CPU won't go to sleep when the screen is turned off. */ - private void acquireWakelock() - { + private void acquireWakelock() { TracingPowerManager pm = TracingPowerManager.getPowerManager(this); mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, WAKELOCK_TAG); mWakeLock.setReferenceCounted(false); @@ -148,16 +145,14 @@ private void acquireWakelock() /** * Release the wake lock. */ - private void releaseWakelock() - { + private void releaseWakelock() { mWakeLock.release(); } /** * Stop this service. */ - private void stopService() - { + private void stopService() { stopSelf(); Timber.i("DatabaseUpgradeService stopped"); @@ -169,13 +164,10 @@ private void stopService() /** * Start a background thread for upgrading the databases. */ - private void startUpgradeInBackground() - { - new Thread("DatabaseUpgradeService") - { + private void startUpgradeInBackground() { + new Thread("DatabaseUpgradeService") { @Override - public void run() - { + public void run() { upgradeDatabases(); stopService(); } @@ -185,8 +177,7 @@ public void run() /** * Upgrade the accounts' databases. */ - private void upgradeDatabases() - { + private void upgradeDatabases() { Preferences preferences = Preferences.getPreferences(this); List accounts = preferences.getAccounts(); @@ -212,8 +203,7 @@ private void upgradeDatabases() sendUpgradeCompleteBroadcast(); } - private void sendProgressBroadcast(String accountUuid, int progress, int progressEnd) - { + private void sendProgressBroadcast(String accountUuid, int progress, int progressEnd) { Intent intent = new Intent(); intent.setAction(ACTION_UPGRADE_PROGRESS); intent.putExtra(EXTRA_ACCOUNT_UUID, accountUuid); @@ -222,8 +212,7 @@ private void sendProgressBroadcast(String accountUuid, int progress, int progres mLocalBroadcastManager.sendBroadcast(intent); } - private void sendUpgradeCompleteBroadcast() - { + private void sendUpgradeCompleteBroadcast() { Intent intent = new Intent(); intent.setAction(ACTION_UPGRADE_COMPLETE); mLocalBroadcastManager.sendBroadcast(intent); diff --git a/XryptoMail/src/main/java/org/atalk/xryptomail/service/PushService.java b/XryptoMail/src/main/java/org/atalk/xryptomail/service/PushService.java old mode 100644 new mode 100755 diff --git a/XryptoMail/src/main/java/org/atalk/xryptomail/view/XMWebViewClient.java b/XryptoMail/src/main/java/org/atalk/xryptomail/view/XMWebViewClient.java index 72f8448..6d89417 100755 --- a/XryptoMail/src/main/java/org/atalk/xryptomail/view/XMWebViewClient.java +++ b/XryptoMail/src/main/java/org/atalk/xryptomail/view/XMWebViewClient.java @@ -4,6 +4,7 @@ import android.content.ContentResolver; import android.content.Context; import android.content.Intent; +import android.net.TrafficStats; import android.net.Uri; import android.provider.Browser; import android.text.TextUtils; @@ -22,6 +23,7 @@ import java.util.Map; import org.atalk.xryptomail.R; +import org.atalk.xryptomail.XryptoMail; import org.atalk.xryptomail.mailstore.AttachmentResolver; import org.atalk.xryptomail.view.MessageWebView.OnPageFinishedListener; @@ -93,6 +95,7 @@ public WebResourceResponse shouldInterceptRequest(WebView webView, WebResourceRe url = url.replace("http://", "https://"); URL httpsUrl = new URL(url); URLConnection connection = httpsUrl.openConnection(); + TrafficStats.setThreadStatsTag(XryptoMail.THREAD_ID); return new WebResourceResponse(connection.getContentType(), connection.getContentEncoding(), connection.getInputStream()); } catch (Exception e) { Timber.e("http to https exception: %s", e.getMessage()); diff --git a/XryptoMail/src/main/res/layout/permissions_ui.xml b/XryptoMail/src/main/res/layout/permissions_ui.xml index cb96feb..84e5897 100644 --- a/XryptoMail/src/main/res/layout/permissions_ui.xml +++ b/XryptoMail/src/main/res/layout/permissions_ui.xml @@ -45,35 +45,35 @@