diff --git a/MediaServiceCore b/MediaServiceCore index e7db3678f..27b4d7f26 160000 --- a/MediaServiceCore +++ b/MediaServiceCore @@ -1 +1 @@ -Subproject commit e7db3678fa6b27669769d52c392ee363147aea0a +Subproject commit 27b4d7f26bf01a5e23350794b82a85ac7f7c1ded diff --git a/SharedModules b/SharedModules index 696bebf51..d84e21431 160000 --- a/SharedModules +++ b/SharedModules @@ -1 +1 @@ -Subproject commit 696bebf51fbbda5ed2fca5a36bec8d1471143eec +Subproject commit d84e21431c3ee7e9658f9d10a8a9a828c9c2de11 diff --git a/common/src/main/java/com/liskovsoft/smartyoutubetv2/common/misc/BackupAndRestoreHelper.java b/common/src/main/java/com/liskovsoft/smartyoutubetv2/common/misc/BackupAndRestoreHelper.java index e93c95ff9..f88802264 100644 --- a/common/src/main/java/com/liskovsoft/smartyoutubetv2/common/misc/BackupAndRestoreHelper.java +++ b/common/src/main/java/com/liskovsoft/smartyoutubetv2/common/misc/BackupAndRestoreHelper.java @@ -7,12 +7,12 @@ import android.content.pm.PackageManager; import android.database.Cursor; import android.net.Uri; import android.os.Build.VERSION; -import android.os.Environment; import android.provider.OpenableColumns; import android.widget.Toast; import androidx.core.content.FileProvider; +import com.liskovsoft.sharedutils.helpers.FileHelpers; import com.liskovsoft.smartyoutubetv2.common.R; import com.liskovsoft.smartyoutubetv2.common.app.presenters.settings.BackupSettingsPresenter; import com.liskovsoft.smartyoutubetv2.common.misc.MotherActivity.OnResult; @@ -27,8 +27,8 @@ public class BackupAndRestoreHelper implements OnResult { private final Context mContext; private Runnable mOnSuccess; private final String[] mPreferredFileManagers = { - "com.lonelycatgames.Xplore", "com.ghisler.android.TotalCommander", + "com.lonelycatgames.Xplore", "com.alphainventor.filemanager", "pl.solidexplorer2" }; @@ -42,7 +42,7 @@ public class BackupAndRestoreHelper implements OnResult { // return; //} - File mediaDir = getExternalMediaDirectory(); + File mediaDir = FileHelpers.getExternalMediaDirectory(mContext); File dataDir = new File(mediaDir, "data"); if (!dataDir.exists()) return; @@ -60,7 +60,8 @@ public class BackupAndRestoreHelper implements OnResult { private void openFileManager(Uri uri) { Intent intent = new Intent(Intent.ACTION_SEND); - intent.setType("*/*"); // intent.setType("application/zip"); + //intent.setType("application/zip"); + intent.setType("*/*"); intent.putExtra(Intent.EXTRA_STREAM, uri); intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); @@ -111,7 +112,7 @@ public class BackupAndRestoreHelper implements OnResult { if (data == null) return; - File mediaDir = getExternalMediaDirectory(); + File mediaDir = FileHelpers.getExternalMediaDirectory(mContext); File dataDir = new File(mediaDir, "data"); if (!mediaDir.exists()) mediaDir.mkdirs(); @@ -126,7 +127,8 @@ public class BackupAndRestoreHelper implements OnResult { copyUriToDir(uri, zipFile); // Cleanup previous data - deleteRecursive(dataDir); + //deleteRecursive(dataDir); + FileHelpers.delete(dataDir); dataDir.mkdirs(); if (ZipHelper2.hasRootDir(zipFile, "data")) { @@ -152,11 +154,12 @@ public class BackupAndRestoreHelper implements OnResult { try { // Target folder: /Android/media//data - File mediaDir = getExternalMediaDirectory(); + File mediaDir = FileHelpers.getExternalMediaDirectory(mContext); File dataDir = new File(mediaDir, "data"); // Remove old data - if (dataDir.exists()) deleteRecursive(dataDir); + //if (dataDir.exists()) deleteRecursive(dataDir); + if (dataDir.exists()) FileHelpers.delete(dataDir); // Copy ZIP from URI to temporary file File tempZip = new File(mediaDir, "imported_backup.zip"); @@ -238,56 +241,4 @@ public class BackupAndRestoreHelper implements OnResult { } return null; } - - @SuppressWarnings("deprecation") - private File getExternalStorageDirectory() { - File result; - - if (VERSION.SDK_INT > 29) { - result = mContext.getExternalMediaDirs()[0]; - - if (!result.exists()) { - result.mkdirs(); - } - } else { - result = Environment.getExternalStorageDirectory(); - } - - return result; - } - - private File getExternalMediaDirectory() { - File result = null; - - if (VERSION.SDK_INT >= 21) { - File[] dirs = mContext.getExternalMediaDirs(); - if (dirs != null && dirs.length > 0) { - result = dirs[0]; - } - } - - if (result == null) { - result = new File( - Environment.getExternalStorageDirectory(), - "Android/media/" + mContext.getPackageName() - ); - } - - if (!result.exists()) { - result.mkdirs(); - } - - return result; - } - - private void deleteRecursive(File f) { - if (!f.exists()) return; - if (f.isDirectory()) { - File[] children = f.listFiles(); - if (children != null) { - for (File c : children) deleteRecursive(c); - } - } - f.delete(); - } } diff --git a/common/src/main/java/com/liskovsoft/smartyoutubetv2/common/misc/BackupAndRestoreManager.java b/common/src/main/java/com/liskovsoft/smartyoutubetv2/common/misc/BackupAndRestoreManager.java index 0eb6b3fda..51a78fa60 100644 --- a/common/src/main/java/com/liskovsoft/smartyoutubetv2/common/misc/BackupAndRestoreManager.java +++ b/common/src/main/java/com/liskovsoft/smartyoutubetv2/common/misc/BackupAndRestoreManager.java @@ -92,12 +92,8 @@ public class BackupAndRestoreManager implements MotherActivity.OnPermissions { private File getExternalStorageDirectory() { File result; - if (hasAccessOnlyToAppFolders() && VERSION.SDK_INT >= 21) { - result = mContext.getExternalMediaDirs()[0]; - - if (!result.exists()) { - result.mkdirs(); - } + if (hasAccessOnlyToAppFolders()) { + result = FileHelpers.getExternalMediaDirectory(mContext); } else { result = Environment.getExternalStorageDirectory(); } @@ -149,8 +145,12 @@ public class BackupAndRestoreManager implements MotherActivity.OnPermissions { return; } - // remove old backup - if (currentBackup.isDirectory()) { + if (hasAccessOnlyToAppFolders()) { + File mediaDir = FileHelpers.getExternalMediaDirectory(mContext); + File dataDir = new File(mediaDir, "data"); + FileHelpers.delete(dataDir); + } else if (currentBackup.isDirectory()) { // plain sdcard storage + // remove old backup FileHelpers.delete(currentBackup); } @@ -283,10 +283,7 @@ public class BackupAndRestoreManager implements MotherActivity.OnPermissions { } public String getBackupRootPath() { - if (hasAccessOnlyToAppFolders()) { - return null; // Android 11+: only backup through the file manager (no shared dir) - } - + // NOTE: Android 11+ only backup through the file manager (no shared dir) return String.format("%s/data", getExternalStorageDirectory()); } diff --git a/common/src/main/java/com/liskovsoft/smartyoutubetv2/common/misc/BackupReceiverActivity.java b/common/src/main/java/com/liskovsoft/smartyoutubetv2/common/misc/BackupReceiverActivity.java index 48ce41eed..c2294bbd5 100644 --- a/common/src/main/java/com/liskovsoft/smartyoutubetv2/common/misc/BackupReceiverActivity.java +++ b/common/src/main/java/com/liskovsoft/smartyoutubetv2/common/misc/BackupReceiverActivity.java @@ -2,19 +2,33 @@ package com.liskovsoft.smartyoutubetv2.common.misc; import android.app.Activity; import android.content.Intent; +import android.content.pm.PackageManager; +import android.os.Build.VERSION; import android.os.Bundle; +import androidx.annotation.NonNull; + +import com.liskovsoft.sharedutils.helpers.PermissionHelpers; + public class BackupReceiverActivity extends Activity { private BackupAndRestoreHelper mRestoreHelper; + private Runnable mPendingHandler; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - mRestoreHelper = new BackupAndRestoreHelper(this); - - mRestoreHelper.handleIncomingZip(getIntent()); - finish(); + // Android 11+ (API 30+) removed the need for storage permission + // when accessing files via content:// URIs. Apps are granted temporary + // access to the URI by the sender, so you can read the file without + // READ_EXTERNAL_STORAGE. + if (PermissionHelpers.hasStoragePermissions(this) || VERSION.SDK_INT > 29) { + restoreData(); + finish(); + } else { + mPendingHandler = this::restoreData; + PermissionHelpers.verifyStoragePermissions(this); + } } @Override @@ -23,4 +37,22 @@ public class BackupReceiverActivity extends Activity { mRestoreHelper.handleIncomingZip(intent); } + + @Override + public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { + if (requestCode == PermissionHelpers.REQUEST_EXTERNAL_STORAGE) { + if (grantResults.length >= 1 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { + if (mPendingHandler != null) { + mPendingHandler.run(); + mPendingHandler = null; + } + } + finish(); + } + } + + private void restoreData() { + mRestoreHelper = new BackupAndRestoreHelper(this); + mRestoreHelper.handleIncomingZip(getIntent()); + } } diff --git a/smarttubetv/build.gradle b/smarttubetv/build.gradle index b87fcbb44..a430352bb 100644 --- a/smarttubetv/build.gradle +++ b/smarttubetv/build.gradle @@ -127,7 +127,7 @@ android { productFlavors { stbeta { applicationId "org.smarttube.beta" - //targetSdkVersion project.properties.compileSdkVersion + targetSdkVersion project.properties.compileSdkVersion } ststable { applicationId "org.smarttube.stable"