diff --git a/app/build.gradle b/app/build.gradle index ed7d513e8d3ab40d2f5f9845c2bd319eadc6a574..1c308d3f010990db764fb9ab8badd5064146c2a9 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -56,7 +56,7 @@ dependencies { coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:1.1.6' // Nextcloud SSO - implementation 'foundation.e.lib:Android-SingleSignOn:1.0.3-alpha' + implementation 'foundation.e.lib:Android-SingleSignOn:1.0.4-alpha' implementation ('com.github.stefan-niedermann:android-commons:0.2.7') { exclude group: 'com.github.nextcloud', module: 'Android-SingleSignOn' } diff --git a/app/src/main/java/it/niedermann/owncloud/notes/importaccount/ImportAccountActivity.java b/app/src/main/java/it/niedermann/owncloud/notes/importaccount/ImportAccountActivity.java index 1f5143665266d00e5c8a52198ea9b8ca5bf708c6..1d2e02e778fd66f3e756225e46a4d3d6e9214a9f 100644 --- a/app/src/main/java/it/niedermann/owncloud/notes/importaccount/ImportAccountActivity.java +++ b/app/src/main/java/it/niedermann/owncloud/notes/importaccount/ImportAccountActivity.java @@ -3,6 +3,8 @@ package it.niedermann.owncloud.notes.importaccount; import android.accounts.NetworkErrorException; import android.content.Intent; import android.os.Bundle; + +import it.niedermann.owncloud.notes.main.MainActivity; import trikita.log.Log; import android.view.View; @@ -14,7 +16,9 @@ import androidx.preference.PreferenceManager; import com.nextcloud.android.sso.AccountImporter; import com.nextcloud.android.sso.exceptions.AccountImportCancelledException; import com.nextcloud.android.sso.exceptions.AndroidGetAccountsPermissionNotGranted; +import com.nextcloud.android.sso.exceptions.NextcloudFilesAppAccountPermissionNotGrantedException; import com.nextcloud.android.sso.exceptions.NextcloudFilesAppNotInstalledException; +import com.nextcloud.android.sso.exceptions.NextcloudFilesAppNotSupportedException; import com.nextcloud.android.sso.exceptions.NextcloudHttpRequestFailedException; import com.nextcloud.android.sso.exceptions.UnknownErrorException; import com.nextcloud.android.sso.helper.SingleAccountHelper; @@ -44,6 +48,8 @@ public class ImportAccountActivity extends AppCompatActivity { private final ExecutorService executor = Executors.newSingleThreadExecutor(); private ImportAccountViewModel importAccountViewModel; + private ImportMurenaAccountViewModel importMurenaAccountViewModel; + private ActivityImportAccountBinding binding; @Override @@ -54,6 +60,7 @@ public class ImportAccountActivity extends AppCompatActivity { binding = ActivityImportAccountBinding.inflate(getLayoutInflater()); importAccountViewModel = new ViewModelProvider(this).get(ImportAccountViewModel.class); + importMurenaAccountViewModel = new ViewModelProvider(this).get(ImportMurenaAccountViewModel.class); setContentView(binding.getRoot()); @@ -75,6 +82,8 @@ public class ImportAccountActivity extends AppCompatActivity { AccountImporter.requestAndroidAccountPermissionsAndPickAccount(this); } }); + + handleAutoMurenaAccountSetup(); } @Override @@ -111,6 +120,9 @@ public class ImportAccountActivity extends AppCompatActivity { Log.i(TAG, capabilities.toString()); BrandingUtil.saveBrandColors(ImportAccountActivity.this, capabilities.getColor(), capabilities.getTextColor()); setResult(RESULT_OK); + Intent intent = new Intent(ImportAccountActivity.this, MainActivity.class); + intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK); + startActivity(intent); finish(); }); SyncWorker.update(ImportAccountActivity.this, PreferenceManager.getDefaultSharedPreferences(ImportAccountActivity.this) @@ -178,4 +190,31 @@ public class ImportAccountActivity extends AppCompatActivity { binding.progressText.setVisibility(View.GONE); }); } + + private void handleAutoMurenaAccountSetup() { + if (importMurenaAccountViewModel.isMurenaAccountPresent()) { + binding.addButton.setEnabled(false); + binding.addButton.setVisibility(View.INVISIBLE); + binding.status.setVisibility(View.GONE); + + pickMurenaAccount(); + } + } + + private void pickMurenaAccount() { + try { + AccountImporter.pickAccount(this, importMurenaAccountViewModel.getMurenaAccount()); + } catch (NextcloudFilesAppNotInstalledException | + NextcloudFilesAppNotSupportedException e) { + UiExceptionManager.showDialogForException(this, e); + Log.w(TAG, "============================================================="); + Log.w(TAG, "Nextcloud app is not installed. Cannot choose account"); + e.printStackTrace(); + } catch (AndroidGetAccountsPermissionNotGranted | + NextcloudFilesAppAccountPermissionNotGrantedException e) { + binding.addButton.setEnabled(true); + binding.addButton.setVisibility(View.VISIBLE); + AccountImporter.requestAndroidAccountPermissionsAndPickAccount(this); + } + } } \ No newline at end of file diff --git a/app/src/main/java/it/niedermann/owncloud/notes/importaccount/ImportMurenaAccountViewModel.java b/app/src/main/java/it/niedermann/owncloud/notes/importaccount/ImportMurenaAccountViewModel.java new file mode 100644 index 0000000000000000000000000000000000000000..002e794b64b3e27dab0d4cbc50f52608fb2a9b9b --- /dev/null +++ b/app/src/main/java/it/niedermann/owncloud/notes/importaccount/ImportMurenaAccountViewModel.java @@ -0,0 +1,70 @@ +/* + * Copyright MURENA SAS 2023 + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package it.niedermann.owncloud.notes.importaccount; + +import android.accounts.Account; +import android.app.Application; + +import androidx.annotation.NonNull; +import androidx.lifecycle.AndroidViewModel; + +import java.util.List; +import java.util.Objects; + +import it.niedermann.owncloud.notes.shared.util.AccountSyncUtil; + +public class ImportMurenaAccountViewModel extends AndroidViewModel { + + private Account account; + + public ImportMurenaAccountViewModel(@NonNull Application application) { + super(application); + retrieveAccount(); + } + + private void retrieveAccount() { + List accounts = AccountSyncUtil.getMurenaAccounts(getApplication()); + + if (accounts.isEmpty()) { + return; + } + + Account murenaAccount = accounts.get(0); // retrieve the first account, as we have policy that one murena account per device + + if (AccountSyncUtil.isSyncEnable(murenaAccount)) { + account = murenaAccount; + } + } + + public boolean isMurenaAccountPresent() { + return account != null; + } + + public Account getMurenaAccount() { + return account; + } + + public boolean shouldLoadMurenaAccount(List noteAccounts) { + if (!isMurenaAccountPresent()) { + return false; + } + + return noteAccounts.stream() + .filter(Objects::nonNull) + .noneMatch(noteAccount -> noteAccount.getAccountName().equals(account.name)); + } +} diff --git a/app/src/main/java/it/niedermann/owncloud/notes/main/MainActivity.java b/app/src/main/java/it/niedermann/owncloud/notes/main/MainActivity.java index ebdfaa795ec5f6503d38bf2cb2e4aed9196d202b..c1d4a119db2c0673cae304191c2ee48ad48123c4 100644 --- a/app/src/main/java/it/niedermann/owncloud/notes/main/MainActivity.java +++ b/app/src/main/java/it/niedermann/owncloud/notes/main/MainActivity.java @@ -23,6 +23,8 @@ import android.graphics.PorterDuff; import android.net.Uri; import android.os.Bundle; import android.text.TextUtils; + +import it.niedermann.owncloud.notes.importaccount.ImportMurenaAccountViewModel; import trikita.log.Log; import android.view.View; @@ -107,6 +109,8 @@ public class MainActivity extends LockedActivity implements NoteClickListener, A protected final ExecutorService executor = Executors.newCachedThreadPool(); protected MainViewModel mainViewModel; + + private ImportMurenaAccountViewModel importMurenaAccountViewModel; private CategoryViewModel categoryViewModel; private boolean gridView = true; @@ -142,6 +146,7 @@ public class MainActivity extends LockedActivity implements NoteClickListener, A super.onCreate(savedInstanceState); mainViewModel = new ViewModelProvider(this).get(MainViewModel.class); + importMurenaAccountViewModel = new ViewModelProvider(this).get(ImportMurenaAccountViewModel.class); categoryViewModel = new ViewModelProvider(this).get(CategoryViewModel.class); CapabilitiesWorker.update(this); binding = DrawerLayoutBinding.inflate(getLayoutInflater()); @@ -160,9 +165,12 @@ public class MainActivity extends LockedActivity implements NoteClickListener, A setupNavigationList(); setupNotesList(); - mainViewModel.getAccountsCount().observe(this, (count) -> { - if (count == 0) { - startActivityForResult(new Intent(this, ImportAccountActivity.class), ImportAccountActivity.REQUEST_CODE_IMPORT_ACCOUNT); + mainViewModel.getAccounts$().observe(this, (accounts) -> { + if (accounts.isEmpty() || importMurenaAccountViewModel.shouldLoadMurenaAccount(accounts)) { + Intent intent = new Intent(this, ImportAccountActivity.class); + intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK); + startActivity(intent); + finish(); } else { executor.submit(() -> { try { diff --git a/app/src/main/java/it/niedermann/owncloud/notes/main/MainViewModel.java b/app/src/main/java/it/niedermann/owncloud/notes/main/MainViewModel.java index 4b721e8984ec2e4e7739897c06c2f9ef8e0f64a4..5ce45bd3e492a73f7fdcdfc383f4fe73f7f0cae9 100644 --- a/app/src/main/java/it/niedermann/owncloud/notes/main/MainViewModel.java +++ b/app/src/main/java/it/niedermann/owncloud/notes/main/MainViewModel.java @@ -603,8 +603,8 @@ public class MainViewModel extends AndroidViewModel { return repo.getLocalModifiedNotes(accountId); } - public LiveData getAccountsCount() { - return repo.countAccounts$(); + public LiveData> getAccounts$() { + return repo.getAccounts$(); } @WorkerThread diff --git a/app/src/main/java/it/niedermann/owncloud/notes/shared/constant/MurenaAccountConstants.java b/app/src/main/java/it/niedermann/owncloud/notes/shared/constant/MurenaAccountConstants.java new file mode 100644 index 0000000000000000000000000000000000000000..3bbd3f7600e0f721388002b5606a42ff229e1fb1 --- /dev/null +++ b/app/src/main/java/it/niedermann/owncloud/notes/shared/constant/MurenaAccountConstants.java @@ -0,0 +1,23 @@ +/* + * Copyright MURENA SAS 2023 + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package it.niedermann.owncloud.notes.shared.constant; + +public final class MurenaAccountConstants { + + public static final String MURENA_ACCOUNT_TYPE = "e.foundation.webdav.eelo"; + public static final String NOTES_CONTENT_AUTHORITY = "foundation.e.notes.android.providers.AppContentProvider"; +} diff --git a/app/src/main/java/it/niedermann/owncloud/notes/shared/util/AccountSyncUtil.java b/app/src/main/java/it/niedermann/owncloud/notes/shared/util/AccountSyncUtil.java index 45cd0964611c6fe7d06b79b2f989d3aa27ce9fb3..c3429987b1c228e47a9c78182329420e3d73167e 100644 --- a/app/src/main/java/it/niedermann/owncloud/notes/shared/util/AccountSyncUtil.java +++ b/app/src/main/java/it/niedermann/owncloud/notes/shared/util/AccountSyncUtil.java @@ -19,33 +19,32 @@ package it.niedermann.owncloud.notes.shared.util; import android.accounts.AccountManager; import android.content.ContentResolver; import android.content.Context; + +import java.util.Arrays; +import java.util.List; +import java.util.Objects; +import java.util.stream.Collectors; + +import it.niedermann.owncloud.notes.shared.constant.MurenaAccountConstants; import trikita.log.Log; import it.niedermann.owncloud.notes.persistence.entity.Account; -public class AccountSyncUtil { +public final class AccountSyncUtil { private static final String TAG = AccountSyncUtil.class.getSimpleName(); - private static final String murena_account_type = "e.foundation.webdav.eelo"; - private static final String notes_content_authority = "foundation.e.notes.android.providers.AppContentProvider"; private AccountSyncUtil() { throw new UnsupportedOperationException("Do not instantiate this util class."); } - private static android.accounts.Account[] getMurenaAccountsOnDevice(AccountManager accountManager) { - return accountManager.getAccountsByType(murena_account_type); - } - - private static boolean isSyncEnable(android.accounts.Account account) { - return ContentResolver.getMasterSyncAutomatically() && ContentResolver.getSyncAutomatically(account, notes_content_authority); + public static boolean isSyncEnable(android.accounts.Account account) { + return ContentResolver.getMasterSyncAutomatically() && ContentResolver.getSyncAutomatically(account, MurenaAccountConstants.NOTES_CONTENT_AUTHORITY); } public static boolean isSyncEnable(Context context, Account account) { - AccountManager accountManager = AccountManager.get(context); - try { - android.accounts.Account[] murenaAccounts = getMurenaAccountsOnDevice(accountManager); + List murenaAccounts = getMurenaAccounts(context); for (android.accounts.Account murenaAccount : murenaAccounts) { if (account.getAccountName().equals(murenaAccount.name)) { @@ -59,4 +58,10 @@ public class AccountSyncUtil { return true; } + public static List getMurenaAccounts(Context context) { + AccountManager accountManager = AccountManager.get(context); + return Arrays.stream(accountManager.getAccountsByType(MurenaAccountConstants.MURENA_ACCOUNT_TYPE)) + .filter(Objects::nonNull) + .collect(Collectors.toList()); + } }