Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -82,15 +82,13 @@ class MediaFoldersDetectionWork constructor(
contentResolver,
1,
null,
true,
viewThemeUtils
true
)
val videoMediaFolders = MediaProvider.getVideoFolders(
contentResolver,
1,
null,
true,
viewThemeUtils
true
)
val imageMediaFolderPaths: MutableList<String> = ArrayList()
val videoMediaFolderPaths: MutableList<String> = ArrayList()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -376,6 +376,10 @@ default void onDarkThemeModeChanged(DarkMode mode) {

void setStoragePermissionRequested(boolean value);

boolean showStoragePermissionBanner();

void setShowStoragePermissionBanner(boolean value);

void setInAppReviewData(@NonNull AppReviewShownModel appReviewShownModel);

@Nullable
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -100,8 +100,8 @@ public final class AppPreferencesImpl implements AppPreferences {

private static final String PREF__PDF_ZOOM_TIP_SHOWN = "pdf_zoom_tip_shown";
private static final String PREF__MEDIA_FOLDER_LAST_PATH = "media_folder_last_path";

private static final String PREF__STORAGE_PERMISSION_REQUESTED = "storage_permission_requested";
private static final String PREF__SHOW_STORAGE_PERMISSION_BANNER = "show_storage_permission_banner";
private static final String PREF__IN_APP_REVIEW_DATA = "in_app_review_data";

private static final String PREF__TWO_WAY_STATUS = "two_way_sync_status";
Expand Down Expand Up @@ -776,6 +776,16 @@ public void setStoragePermissionRequested(boolean value) {
preferences.edit().putBoolean(PREF__STORAGE_PERMISSION_REQUESTED, value).apply();
}

@Override
public boolean showStoragePermissionBanner() {
return preferences.getBoolean(PREF__SHOW_STORAGE_PERMISSION_BANNER, true);
}

@Override
public void setShowStoragePermissionBanner(boolean value) {
preferences.edit().putBoolean(PREF__SHOW_STORAGE_PERMISSION_BANNER, value).apply();
}

@VisibleForTesting
public int computeBruteForceDelay(int count) {
return (int) Math.min(count / 3d, 10);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat
import com.owncloud.android.R
import com.owncloud.android.datamodel.ReceiverFlag
import android.net.Uri
import android.provider.Settings

fun Context.hourPlural(hour: Int): String = resources.getQuantityString(R.plurals.hours, hour, hour)

Expand Down Expand Up @@ -69,3 +71,22 @@ fun Context.getActivity(): Activity? = when (this) {
is ContextWrapper -> baseContext.getActivity()
else -> null
}

fun Context.openMediaPermissions() {
val intent = Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS).apply {
data = Uri.fromParts("package", packageName, null)
}
startActivity(intent)
}

fun Context.openAllFilesAccessSettings() {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.R) {
openMediaPermissions()
return
}

val intent = Intent(Settings.ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION).apply {
data = Uri.parse("package:$packageName")
}
startActivity(intent)
}
8 changes: 3 additions & 5 deletions app/src/main/java/com/owncloud/android/MainApp.java
Original file line number Diff line number Diff line change
Expand Up @@ -628,7 +628,7 @@ public static void initSyncOperations(
updateAutoUploadEntries(clock);

if (getAppContext() != null) {
if (PermissionUtil.checkExternalStoragePermission(getAppContext())) {
if (PermissionUtil.checkStoragePermission(getAppContext())) {
splitOutAutoUploadEntries(clock, viewThemeUtils);
} else {
preferences.setAutoUploadSplitEntriesEnabled(true);
Expand Down Expand Up @@ -904,13 +904,11 @@ private static void splitOutAutoUploadEntries(Clock clock,
final List<MediaFolder> imageMediaFolders = MediaProvider.getImageFolders(contentResolver,
1,
null,
true,
viewThemeUtils);
true);
final List<MediaFolder> videoMediaFolders = MediaProvider.getVideoFolders(contentResolver,
1,
null,
true,
viewThemeUtils);
true);

ArrayList<Long> idsToDelete = new ArrayList<>();
List<SyncedFolder> syncedFolders = syncedFolderProvider.getSyncedFolders();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,14 +59,13 @@ private MediaProvider() {
public static List<MediaFolder> getImageFolders(ContentResolver contentResolver,
int itemLimit,
@Nullable final AppCompatActivity activity,
boolean getWithoutActivity,
final ViewThemeUtils viewThemeUtils) {
boolean getWithoutActivity) {
// check permissions
checkPermissions(activity, viewThemeUtils);
checkPermissions(activity);

// query media/image folders
Cursor cursorFolders = null;
if (activity != null && PermissionUtil.checkExternalStoragePermission(activity.getApplicationContext())
if (activity != null && PermissionUtil.checkStoragePermission(activity.getApplicationContext())
|| getWithoutActivity) {
cursorFolders = ContentResolverHelper.queryResolver(contentResolver, IMAGES_MEDIA_URI,
IMAGES_FOLDER_PROJECTION, null, null,
Expand Down Expand Up @@ -159,25 +158,23 @@ private static boolean isValidAndExistingFilePath(String filePath) {
return filePath != null && filePath.lastIndexOf('/') > 0 && new File(filePath).exists();
}

private static void checkPermissions(@Nullable AppCompatActivity activity,
final ViewThemeUtils viewThemeUtils) {
private static void checkPermissions(@Nullable AppCompatActivity activity) {
if (activity != null &&
!PermissionUtil.checkExternalStoragePermission(activity.getApplicationContext())) {
PermissionUtil.requestExternalStoragePermission(activity, viewThemeUtils, true);
!PermissionUtil.checkStoragePermission(activity.getApplicationContext())) {
PermissionUtil.requestStoragePermissionIfNeeded(activity);
}
}

public static List<MediaFolder> getVideoFolders(ContentResolver contentResolver,
int itemLimit,
@Nullable final AppCompatActivity activity,
boolean getWithoutActivity,
final ViewThemeUtils viewThemeUtils) {
boolean getWithoutActivity) {
// check permissions
checkPermissions(activity, viewThemeUtils);
checkPermissions(activity);

// query media/image folders
Cursor cursorFolders = null;
if ((activity != null && PermissionUtil.checkExternalStoragePermission(activity.getApplicationContext()))
if ((activity != null && PermissionUtil.checkStoragePermission(activity.getApplicationContext()))
|| getWithoutActivity) {
cursorFolders = contentResolver.query(MediaStore.Video.Media.EXTERNAL_CONTENT_URI, VIDEOS_FOLDER_PROJECTION,
null, null, null);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
import android.net.ConnectivityManager;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.os.IBinder;
import android.text.TextUtils;
Expand Down Expand Up @@ -100,6 +101,7 @@
import com.owncloud.android.utils.DisplayUtils;
import com.owncloud.android.utils.ErrorMessageAdapter;
import com.owncloud.android.utils.FilesSyncHelper;
import com.owncloud.android.utils.PermissionUtil;
import com.owncloud.android.utils.theme.ViewThemeUtils;

import org.greenrobot.eventbus.Subscribe;
Expand All @@ -110,6 +112,8 @@

import javax.inject.Inject;

import androidx.activity.result.ActivityResultLauncher;
import androidx.activity.result.contract.ActivityResultContracts;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.StringRes;
Expand Down Expand Up @@ -195,6 +199,18 @@ public abstract class FileActivity extends DrawerActivity

private FilesRepository filesRepository;

private final ActivityResultLauncher<Intent> manageAllFilesLauncher = registerForActivityResult(new ActivityResultContracts.StartActivityForResult(), result -> {
if (Environment.isExternalStorageManager()) {
// User granted MANAGE_EXTERNAL_STORAGE
// Now request media permissions to get MEDIA_LOCATION
PermissionUtil.INSTANCE.requestRequiredStoragePermissions(this);
}
});

public ActivityResultLauncher<Intent> getManageAllFilesLauncher() {
return manageAllFilesLauncher;
}

private void registerNetworkChangeReceiver() {
IntentFilter filter = new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION);
registerReceiver(networkChangeReceiver, filter);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@ import com.owncloud.android.utils.ErrorMessageAdapter
import com.owncloud.android.utils.FileSortOrder
import com.owncloud.android.utils.MimeTypeUtil
import com.owncloud.android.utils.PermissionUtil
import com.owncloud.android.utils.PermissionUtil.requestExternalStoragePermission
import com.owncloud.android.utils.PermissionUtil.requestStoragePermissionIfNeeded
import com.owncloud.android.utils.PermissionUtil.requestNotificationPermission
import com.owncloud.android.utils.PushUtils
import com.owncloud.android.utils.StringUtils
Expand Down Expand Up @@ -363,7 +363,7 @@ class FileDisplayActivity :
if (dialog != null && dialog.isShowing) {
dialog.dismiss()
supportFragmentManager.beginTransaction().remove(fragment).commitNowAllowingStateLoss()
requestExternalStoragePermission(this, viewThemeUtils)
requestStoragePermissionIfNeeded(this)
}
}
}
Expand All @@ -378,7 +378,7 @@ class FileDisplayActivity :
// storage permissions handled in onRequestPermissionsResult
requestNotificationPermission(this)
} else {
requestExternalStoragePermission(this, viewThemeUtils)
requestStoragePermissionIfNeeded(this)
}

if (intent.getParcelableArgument(
Expand Down Expand Up @@ -461,7 +461,7 @@ class FileDisplayActivity :
// handle notification permission on API level >= 33
PermissionUtil.PERMISSIONS_POST_NOTIFICATIONS ->
// dialogue was dismissed -> prompt for storage permissions
requestExternalStoragePermission(this, viewThemeUtils)
requestStoragePermissionIfNeeded(this)

// If request is cancelled, result arrays are empty.
PermissionUtil.PERMISSIONS_EXTERNAL_STORAGE ->
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,11 @@ import com.nextcloud.client.jobs.upload.FileUploadWorker
import com.nextcloud.client.preferences.SubFolderRule
import com.nextcloud.utils.extensions.getParcelableArgument
import com.nextcloud.utils.extensions.isDialogFragmentReady
import com.nextcloud.utils.extensions.setVisibleIf
import com.owncloud.android.BuildConfig
import com.owncloud.android.MainApp
import com.owncloud.android.R
import com.owncloud.android.databinding.StoragePermissionWarningBannerBinding
import com.owncloud.android.databinding.SyncedFoldersLayoutBinding
import com.owncloud.android.datamodel.ArbitraryDataProviderImpl
import com.owncloud.android.datamodel.MediaFolder
Expand All @@ -53,6 +55,7 @@ import com.owncloud.android.datamodel.SyncedFolderProvider
import com.owncloud.android.files.services.NameCollisionPolicy
import com.owncloud.android.lib.common.utils.Log_OC
import com.owncloud.android.ui.adapter.SyncedFolderAdapter
import com.owncloud.android.ui.adapter.storagePermissionBanner.setup
import com.owncloud.android.ui.decoration.MediaGridItemDecoration
import com.owncloud.android.ui.dialog.ConfirmationDialogFragment
import com.owncloud.android.ui.dialog.SyncedFolderPreferencesDialogFragment
Expand Down Expand Up @@ -197,9 +200,20 @@ class SyncedFoldersActivity :
setTheme(R.style.FallbackThemingTheme)
}
binding.emptyList.emptyListViewAction.setOnClickListener { showHiddenItems() }
PermissionUtil.requestExternalStoragePermission(this, viewThemeUtils, true)
setupStoragePermissionWarningBanner()
}

private fun setupStoragePermissionWarningBanner() {
val storagePermissionWarningBanner = binding.storagePermissionWarningBanner.root
StoragePermissionWarningBannerBinding.bind(storagePermissionWarningBanner).apply {
setup(appPreferences)
}
storagePermissionWarningBanner.setVisibleIf(shouldShowStoragePermissionWarningBanner())
}

private fun shouldShowStoragePermissionWarningBanner(): Boolean = !PermissionUtil.checkStoragePermission(this) &&
preferences.showStoragePermissionBanner()

override fun onCreateOptionsMenu(menu: Menu): Boolean {
val inflater = menuInflater
inflater.inflate(R.menu.activity_synced_folders, menu)
Expand Down Expand Up @@ -274,16 +288,14 @@ class SyncedFoldersActivity :
contentResolver,
perFolderMediaItemLimit,
this@SyncedFoldersActivity,
false,
viewThemeUtils
false
)
mediaFolders.addAll(
MediaProvider.getVideoFolders(
contentResolver,
perFolderMediaItemLimit,
this@SyncedFoldersActivity,
false,
viewThemeUtils
false
)
)

Expand Down Expand Up @@ -519,7 +531,7 @@ class SyncedFoldersActivity :
android.R.id.home -> finish()
R.id.action_create_custom_folder -> {
Log_OC.d(TAG, "Show custom folder dialog")
if (PermissionUtil.checkExternalStoragePermission(this)) {
if (PermissionUtil.checkStoragePermission(this)) {
val emptyCustomFolder = SyncedFolderDisplayItem(
SyncedFolder.UNPERSISTED_ID,
null,
Expand All @@ -542,7 +554,7 @@ class SyncedFoldersActivity :
)
onSyncFolderSettingsClick(0, emptyCustomFolder)
} else {
PermissionUtil.requestExternalStoragePermission(this, viewThemeUtils, true)
PermissionUtil.requestStoragePermissionIfNeeded(this)
}
result = super.onOptionsItemSelected(item)
}
Expand Down
Loading
Loading