diff --git a/app/src/androidTest/java/com/owncloud/android/FileIT.java b/app/src/androidTest/java/com/owncloud/android/FileIT.java index 9f251d65c857..2ba362250cdf 100644 --- a/app/src/androidTest/java/com/owncloud/android/FileIT.java +++ b/app/src/androidTest/java/com/owncloud/android/FileIT.java @@ -106,7 +106,8 @@ public void testRenameFolder() throws IOException { assertTrue(new SynchronizeFolderOperation(targetContext, folderPath, user, - fileDataStorageManager) + fileDataStorageManager, + false) .execute(targetContext) .isSuccess()); diff --git a/app/src/gplay/AndroidManifest.xml b/app/src/gplay/AndroidManifest.xml index 8d9ec96b73c8..9e2d78552bcf 100644 --- a/app/src/gplay/AndroidManifest.xml +++ b/app/src/gplay/AndroidManifest.xml @@ -13,6 +13,11 @@ android:name="android.permission.REQUEST_INSTALL_PACKAGES" tools:node="remove"/> + + + * SPDX-License-Identifier: AGPL-3.0-or-later + */ +package com.nextcloud.utils + +object BuildHelper { + const val GPLAY: String = "gplay" +} diff --git a/app/src/main/java/com/owncloud/android/MainApp.java b/app/src/main/java/com/owncloud/android/MainApp.java index be156896b52c..8751bf429c2e 100644 --- a/app/src/main/java/com/owncloud/android/MainApp.java +++ b/app/src/main/java/com/owncloud/android/MainApp.java @@ -834,6 +834,8 @@ private static void updateToAutoUpload(Context context) { } } + + private static void showAutoUploadAlertDialog(Context context) { new MaterialAlertDialogBuilder(context, R.style.Theme_ownCloud_Dialog) .setTitle(R.string.drawer_synced_folders) diff --git a/app/src/main/java/com/owncloud/android/datamodel/OCFile.java b/app/src/main/java/com/owncloud/android/datamodel/OCFile.java index d811ef55b7e5..0b272a671c29 100644 --- a/app/src/main/java/com/owncloud/android/datamodel/OCFile.java +++ b/app/src/main/java/com/owncloud/android/datamodel/OCFile.java @@ -20,6 +20,7 @@ import android.os.Parcelable; import android.text.TextUtils; +import com.nextcloud.utils.BuildHelper; import com.owncloud.android.BuildConfig; import com.owncloud.android.R; import com.owncloud.android.lib.common.network.WebdavEntry; @@ -1084,7 +1085,7 @@ public void setInternalFolderSyncResult(String internalFolderSyncResult) { } public boolean isAPKorAAB() { - if ("gplay".equals(BuildConfig.FLAVOR)) { + if (BuildHelper.GPLAY.equals(BuildConfig.FLAVOR)) { return getFileName().endsWith(".apk") || getFileName().endsWith(".aab"); } else { return false; diff --git a/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.java b/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.java index f569a74fb0b7..52f5ad739879 100644 --- a/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.java +++ b/app/src/main/java/com/owncloud/android/ui/activity/FileDisplayActivity.java @@ -13,6 +13,7 @@ */ package com.owncloud.android.ui.activity; +import android.Manifest; import android.accounts.Account; import android.accounts.AuthenticatorException; import android.annotation.SuppressLint; @@ -50,6 +51,7 @@ import com.nextcloud.client.account.User; import com.nextcloud.client.appinfo.AppInfo; import com.nextcloud.client.core.AsyncRunner; +import com.nextcloud.client.core.Clock; import com.nextcloud.client.di.Injectable; import com.nextcloud.client.editimage.EditImageActivity; import com.nextcloud.client.files.DeepLinkHandler; @@ -64,17 +66,21 @@ import com.nextcloud.client.utils.IntentUtil; import com.nextcloud.model.WorkerState; import com.nextcloud.model.WorkerStateLiveData; +import com.nextcloud.utils.BuildHelper; import com.nextcloud.utils.extensions.ActivityExtensionsKt; import com.nextcloud.utils.extensions.BundleExtensionsKt; import com.nextcloud.utils.extensions.FileExtensionsKt; import com.nextcloud.utils.extensions.IntentExtensionsKt; import com.nextcloud.utils.fileNameValidator.FileNameValidator; import com.nextcloud.utils.view.FastScrollUtils; +import com.owncloud.android.BuildConfig; import com.owncloud.android.MainApp; import com.owncloud.android.R; import com.owncloud.android.databinding.FilesBinding; import com.owncloud.android.datamodel.FileDataStorageManager; import com.owncloud.android.datamodel.OCFile; +import com.owncloud.android.datamodel.SyncedFolder; +import com.owncloud.android.datamodel.SyncedFolderProvider; import com.owncloud.android.datamodel.VirtualFolderType; import com.owncloud.android.files.services.NameCollisionPolicy; import com.owncloud.android.lib.common.OwnCloudClient; @@ -241,6 +247,8 @@ public class FileDisplayActivity extends FileActivity @Inject FastScrollUtils fastScrollUtils; @Inject AsyncRunner asyncRunner; + @Inject Clock clock; + @Inject SyncedFolderProvider syncedFolderProvider; public static Intent openFileIntent(Context context, User user, OCFile file) { final Intent intent = new Intent(context, PreviewImageActivity.class); @@ -275,12 +283,55 @@ protected void onCreate(Bundle savedInstanceState) { mPlayerConnection = new PlayerServiceConnection(this); checkStoragePath(); + checkAutoUploadOnGPlay(); initSyncBroadcastReceiver(); observeWorkerState(); registerRefreshFolderEventReceiver(); } + private void checkAutoUploadOnGPlay() { + if (!BuildHelper.GPLAY.equals(BuildConfig.FLAVOR)) { + return; + } + + // only show on Android11+ + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.R) { + return; + } + + if (PermissionUtil.checkSelfPermission(this, Manifest.permission.MANAGE_EXTERNAL_STORAGE)) { + return; + } + + if (preferences.isAutoUploadGPlayWarningShown()) { + return; + } + + boolean showInfoDialog = false; + for (SyncedFolder syncedFolder : syncedFolderProvider.getSyncedFolders()) { + // move or delete after success + if (syncedFolder.getUploadAction() == 1 || syncedFolder.getUploadAction() == 2) { + showInfoDialog = true; + break; + } + } + + if (showInfoDialog) { + new MaterialAlertDialogBuilder(this, R.style.Theme_ownCloud_Dialog) + .setTitle(R.string.auto_upload_gplay) + .setMessage(R.string.auto_upload_gplay_desc) + .setNegativeButton(R.string.dialog_close, (dialog, which) -> { + dialog.dismiss(); + }) + .setIcon(R.drawable.nav_synced_folders) + .create() + .show(); + } + + preferences.setAutoUploadGPlayWarningShown(true); + } + @SuppressWarnings("unchecked") private void loadSavedInstanceState(Bundle savedInstanceState) { if (savedInstanceState != null) { diff --git a/app/src/main/java/com/owncloud/android/ui/activity/UploadFilesActivity.java b/app/src/main/java/com/owncloud/android/ui/activity/UploadFilesActivity.java index 01d93439542a..09f537f66f31 100644 --- a/app/src/main/java/com/owncloud/android/ui/activity/UploadFilesActivity.java +++ b/app/src/main/java/com/owncloud/android/ui/activity/UploadFilesActivity.java @@ -50,6 +50,7 @@ import com.owncloud.android.ui.fragment.LocalFileListFragment; import com.owncloud.android.utils.DisplayUtils; import com.owncloud.android.utils.FileSortOrder; +import com.owncloud.android.utils.FileStorageUtils; import com.owncloud.android.utils.PermissionUtil; import java.io.File; @@ -567,7 +568,8 @@ public void onDirectoryClick(File directory) { } private void checkWritableFolder(File folder) { - boolean canWriteIntoFolder = folder.canWrite(); + boolean canWriteIntoFolder = FileStorageUtils.isFolderWritable(folder); + binding.uploadFilesSpinnerBehaviour.setEnabled(canWriteIntoFolder); TextView textView = findViewById(R.id.upload_files_upload_files_behaviour_text); diff --git a/app/src/main/java/com/owncloud/android/ui/dialog/SyncedFolderPreferencesDialogFragment.kt b/app/src/main/java/com/owncloud/android/ui/dialog/SyncedFolderPreferencesDialogFragment.kt index aba0d565d8f6..556dac4db784 100644 --- a/app/src/main/java/com/owncloud/android/ui/dialog/SyncedFolderPreferencesDialogFragment.kt +++ b/app/src/main/java/com/owncloud/android/ui/dialog/SyncedFolderPreferencesDialogFragment.kt @@ -277,7 +277,9 @@ class SyncedFolderPreferencesDialogFragment : DialogFragment(), Injectable { binding?.settingInstantBehaviourContainer?.alpha = ALPHA_DISABLED return } - if (syncedFolder!!.localPath != null && File(syncedFolder!!.localPath).canWrite()) { + if (syncedFolder!!.localPath != null && + FileStorageUtils.isFolderWritable(File(syncedFolder!!.localPath)) + ) { binding?.settingInstantBehaviourContainer?.isEnabled = true binding?.settingInstantBehaviourContainer?.alpha = ALPHA_ENABLED binding?.settingInstantBehaviourSummary?.text = diff --git a/app/src/main/java/com/owncloud/android/utils/FileStorageUtils.java b/app/src/main/java/com/owncloud/android/utils/FileStorageUtils.java index eaf81854b867..11f95da1d19d 100644 --- a/app/src/main/java/com/owncloud/android/utils/FileStorageUtils.java +++ b/app/src/main/java/com/owncloud/android/utils/FileStorageUtils.java @@ -680,6 +680,16 @@ public static boolean checkIfEnoughSpace(OCFile file) { return checkIfEnoughSpace(availableSpaceOnDevice, file); } + + public static boolean isFolderWritable(File folder) { + File[] children = folder.listFiles(); + + if (children != null && children.length > 0) { + return children[0].canWrite(); + } else { + return folder.canWrite(); + } + } @VisibleForTesting public static boolean checkIfEnoughSpace(long availableSpaceOnDevice, OCFile file) { diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index f43b79d34765..e541d34a9c19 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -1253,4 +1253,6 @@ To set up a two way sync folder, please enable it in the details tab of the folder in question. Internal two way sync Disable for all folders + Auto upload behaviour changed + Due to new restrictions imposed by Google, the auto upload feature will no longer be able to automatically remove uploaded files.