());
private final ExecutorService mExecutorService = Executors.newFixedThreadPool(1);
@@ -214,7 +215,7 @@ public static Uri createAuthorizationUri(RegularFile file) {
AUTHORIZATIONS.put(uuid, resource);
break;
}
- } while(true);
+ } while (true);
// Post a message to clear authorization after an interval of time
Message msg = Message.obtain(CLEAR_AUTH_HANDLER, MSG_CLEAR_AUTHORIZATIONS);
@@ -226,8 +227,10 @@ public static Uri createAuthorizationUri(RegularFile file) {
}
/**
- * Method that register the {@link FileSystemObject} that allow external apps to access
- * private files. An authorization MUST be explicit done by this app. Third party apps
+ * Method that register the {@link FileSystemObject} that allow external apps to
+ * access
+ * private files. An authorization MUST be explicit done by this app. Third
+ * party apps
* can register
*
* @param uri The authorized uri
@@ -272,7 +275,6 @@ public static AuthorizationResource revertAuthorization(Uri uri) {
return AUTHORIZATIONS.remove(uuid);
}
-
@Override
public boolean onCreate() {
return true;
@@ -395,10 +397,11 @@ public void run() {
/**
* Method that returns an authorization for the passed Uri.
*
- * @param uri The uri to check
+ * @param uri The uri to check
* @param revoke Whether revoke the grant
- * @return AuthorizationResource The authorization resource or null if not there is not
- * authorization
+ * @return AuthorizationResource The authorization resource or null if not there
+ * is not
+ * authorization
*/
private static AuthorizationResource getAuthorizacionResourceForUri(Uri uri) {
UUID uuid = UUID.fromString(uri.getLastPathSegment());
diff --git a/src/com/cyanogenmod/filemanager/providers/secure/SecureCacheCleanupService.java b/src/com/cyanogenmod/filemanager/providers/secure/SecureCacheCleanupService.java
index 6accb438..1b6326da 100644
--- a/src/com/cyanogenmod/filemanager/providers/secure/SecureCacheCleanupService.java
+++ b/src/com/cyanogenmod/filemanager/providers/secure/SecureCacheCleanupService.java
@@ -30,6 +30,7 @@
/**
* SecureCacheCleanupService
+ *
*
* Service that cleans up cache
*
@@ -39,11 +40,12 @@
public class SecureCacheCleanupService extends IntentService {
// Constants
- private static final String ACTION_START = "com.cyanogenmod.filemanager.ACTION_START_CLEANUP";
+ private static final String ACTION_START = com.cyanogenmod.filemanager.BuildConfig.APPLICATION_ID
+ + ".ACTION_START_CLEANUP";
private static final String NAME = "cleanup-service";
/**
- * Creates an IntentService. Invoked by your subclass's constructor.
+ * Creates an IntentService. Invoked by your subclass's constructor.
*/
public SecureCacheCleanupService() {
super(NAME);
@@ -110,7 +112,7 @@ public static void scheduleCleanup(Context context) throws IllegalArgumentExcept
AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
Intent intent = new Intent(context, SecureCacheCleanupService.class);
intent.setAction(ACTION_START);
- PendingIntent pendingIntent = PendingIntent.getService(context, 0, intent, 0);
+ PendingIntent pendingIntent = PendingIntent.getService(context, 0, intent, PendingIntent.FLAG_IMMUTABLE);
alarmManager.setInexactRepeating(AlarmManager.ELAPSED_REALTIME, 1000,
AlarmManager.INTERVAL_HOUR, pendingIntent);
}
@@ -129,7 +131,7 @@ public static void cancelAlarm(Context context) throws IllegalArgumentException
AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
Intent intent = new Intent(context, SecureCacheCleanupService.class);
intent.setAction(ACTION_START);
- PendingIntent pendingIntent = PendingIntent.getService(context, 0, intent, 0);
+ PendingIntent pendingIntent = PendingIntent.getService(context, 0, intent, PendingIntent.FLAG_IMMUTABLE);
alarmManager.cancel(pendingIntent);
}
}
diff --git a/src/com/cyanogenmod/filemanager/service/MimeTypeIndexService.java b/src/com/cyanogenmod/filemanager/service/MimeTypeIndexService.java
index ad7192e5..c679a293 100644
--- a/src/com/cyanogenmod/filemanager/service/MimeTypeIndexService.java
+++ b/src/com/cyanogenmod/filemanager/service/MimeTypeIndexService.java
@@ -33,6 +33,7 @@
/**
* MimeTypeIndexService
+ *
*
* Service intended to index space used by mime type
*
@@ -43,7 +44,7 @@ public class MimeTypeIndexService extends IntentService {
// Constants
private static final String TAG = MimeTypeIndexService.class.getSimpleName();
- public static final String ACTION_START_INDEX = "com.cyanogenmod.filemanager" +
+ public static final String ACTION_START_INDEX = com.cyanogenmod.filemanager.BuildConfig.APPLICATION_ID +
".ACTION_START_INDEX";
public static final String EXTRA_FILE_ROOT = "extra_file_root";
@@ -86,8 +87,7 @@ private void performIndexAction(String fileRoot) {
Log.i(TAG, "Starting mime type usage indexing on '" + fileRoot + "'");
fileRoot = fileRoot.trim();
File rootFile = new File(fileRoot);
- Map spaceCalculationMap =
- new HashMap();
+ Map spaceCalculationMap = new HashMap();
calculateUsageByType(rootFile, spaceCalculationMap);
ContentValues[] valuesList = new ContentValues[spaceCalculationMap.keySet().size()];
int i = 0;
@@ -157,8 +157,7 @@ private void calculateUsageByType(File root, Map groupUs
*
* @throws IllegalArgumentException {@link java.lang.IllegalArgumentException}
*/
- public static void indexFileRoot(Context context, String fileRoot) throws
- IllegalArgumentException {
+ public static void indexFileRoot(Context context, String fileRoot) throws IllegalArgumentException {
if (context == null) {
throw new IllegalArgumentException("'context' cannot be null");
}
diff --git a/src/com/cyanogenmod/filemanager/ui/IconHolder.java b/src/com/cyanogenmod/filemanager/ui/IconHolder.java
index 2a8e0993..dd180057 100644
--- a/src/com/cyanogenmod/filemanager/ui/IconHolder.java
+++ b/src/com/cyanogenmod/filemanager/ui/IconHolder.java
@@ -26,6 +26,7 @@
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.media.ThumbnailUtils;
+import android.provider.MediaStore;
import android.net.Uri;
import android.os.Handler;
import android.os.HandlerThread;
@@ -155,7 +156,7 @@ private Drawable getAppDrawable(FileSystemObject fso) {
private Drawable getImageDrawable(String file) {
Bitmap thumb = ThumbnailUtils.createImageThumbnail(
MediaHelper.normalizeMediaPath(file),
- ThumbnailUtils.TARGET_SIZE_MICRO_THUMBNAIL);
+ MediaStore.Images.Thumbnails.MICRO_KIND);
if (thumb == null) {
return null;
}
@@ -171,7 +172,7 @@ private Drawable getImageDrawable(String file) {
private Drawable getVideoDrawable(String file) {
Bitmap thumb = ThumbnailUtils.createVideoThumbnail(
MediaHelper.normalizeMediaPath(file),
- ThumbnailUtils.TARGET_SIZE_MICRO_THUMBNAIL);
+ MediaStore.Video.Thumbnails.MICRO_KIND);
if (thumb == null) {
return null;
}
@@ -190,7 +191,7 @@ private Drawable getAlbumDrawable(long albumId) {
return null;
}
Bitmap thumb = ThumbnailUtils.createImageThumbnail(path,
- ThumbnailUtils.TARGET_SIZE_MICRO_THUMBNAIL);
+ MediaStore.Images.Thumbnails.MICRO_KIND);
if (thumb == null) {
return null;
}
@@ -341,8 +342,11 @@ public void handleMessage(Message msg) {
switch (msg.what) {
case MSG_LOAD:
Loadable l = (Loadable) msg.obj;
- if (l.load()) {
- mHandler.obtainMessage(MSG_LOADED, l).sendToTarget();
+ try {
+ if (l.load()) {
+ mHandler.obtainMessage(MSG_LOADED, l).sendToTarget();
+ }
+ } catch (RuntimeException ignored) {
}
break;
}
diff --git a/src/com/cyanogenmod/filemanager/ui/policy/PrintActionPolicy.java b/src/com/cyanogenmod/filemanager/ui/policy/PrintActionPolicy.java
index 791d6dbe..f0d024bf 100644
--- a/src/com/cyanogenmod/filemanager/ui/policy/PrintActionPolicy.java
+++ b/src/com/cyanogenmod/filemanager/ui/policy/PrintActionPolicy.java
@@ -281,7 +281,6 @@ public void onLayout(PrintAttributes oldAttributes, PrintAttributes newAttribute
.setContentType(PrintDocumentInfo.CONTENT_TYPE_DOCUMENT)
.setPageCount(calculatePageCount(rowsPerPage))
.build();
- info.setDataSize(size);
boolean changed = !newAttributes.equals(oldAttributes);
callback.onLayoutFinished(info, changed);
}
diff --git a/src/com/cyanogenmod/filemanager/ui/widgets/NavigationView.java b/src/com/cyanogenmod/filemanager/ui/widgets/NavigationView.java
index 17504dae..16816840 100755
--- a/src/com/cyanogenmod/filemanager/ui/widgets/NavigationView.java
+++ b/src/com/cyanogenmod/filemanager/ui/widgets/NavigationView.java
@@ -1437,7 +1437,7 @@ public void createChRooted() {
StorageVolume[] volumes =
StorageHelper.getStorageVolumes(getContext(), false);
if (volumes != null && volumes.length > 0) {
- changeCurrentDir(volumes[0].getPath(), false, true, false, null, null);
+ changeCurrentDir(StorageHelper.getStorageVolumePath(volumes[0]), false, true, false, null, null);
}
}
@@ -1468,7 +1468,7 @@ private String checkChRootedNavigation(String newDir) {
if (!StorageHelper.isPathInStorageVolume(newDir)) {
StorageVolume[] volumes = StorageHelper.getStorageVolumes(getContext(), false);
if (volumes != null && volumes.length > 0) {
- return volumes[0].getPath();
+ return StorageHelper.getStorageVolumePath(volumes[0]);
}
}
return newDir;
diff --git a/src/com/cyanogenmod/filemanager/ui/widgets/ScrimInsetsFrameLayout.java b/src/com/cyanogenmod/filemanager/ui/widgets/ScrimInsetsFrameLayout.java
index 56741558..a0d12621 100644
--- a/src/com/cyanogenmod/filemanager/ui/widgets/ScrimInsetsFrameLayout.java
+++ b/src/com/cyanogenmod/filemanager/ui/widgets/ScrimInsetsFrameLayout.java
@@ -21,7 +21,7 @@
import android.graphics.Canvas;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
-import android.support.v4.view.ViewCompat;
+import androidx.core.view.ViewCompat;
import android.util.AttributeSet;
import android.widget.FrameLayout;
import com.cyanogenmod.filemanager.R;
diff --git a/src/com/cyanogenmod/filemanager/util/AmbiguousExtensionHelper.java b/src/com/cyanogenmod/filemanager/util/AmbiguousExtensionHelper.java
index 3b09367b..129c870f 100644
--- a/src/com/cyanogenmod/filemanager/util/AmbiguousExtensionHelper.java
+++ b/src/com/cyanogenmod/filemanager/util/AmbiguousExtensionHelper.java
@@ -75,7 +75,10 @@ public String getMimeType(String absolutePath, String extension) {
} catch (RuntimeException e) {
Log.e(TAG, "Unable to open 3GP file to determine mimetype");
} finally {
- retriever.release();
+ try {
+ retriever.release();
+ } catch (Exception e) {
+ }
}
// Default to video 3gp if the file is unreadable as this was the default before
// ambiguous resolution support was added.
diff --git a/src/com/cyanogenmod/filemanager/util/AndroidHelper.java b/src/com/cyanogenmod/filemanager/util/AndroidHelper.java
index 891e6e3a..92ffaace 100644
--- a/src/com/cyanogenmod/filemanager/util/AndroidHelper.java
+++ b/src/com/cyanogenmod/filemanager/util/AndroidHelper.java
@@ -27,13 +27,15 @@
import android.content.res.Configuration;
import android.content.res.Resources;
import android.os.UserHandle;
+import android.os.Process;
import android.os.UserManager;
import android.util.DisplayMetrics;
+import com.cyanogenmod.filemanager.util.HexDump;
import android.view.ViewConfiguration;
-import com.android.internal.util.HexDump;
import java.io.ByteArrayInputStream;
+import java.lang.reflect.Method;
import java.security.GeneralSecurityException;
import java.security.MessageDigest;
import java.security.cert.CertificateFactory;
@@ -150,8 +152,20 @@ public static boolean hasSupportForMultipleUsers(Context context) {
return UserManager.supportsMultipleUsers();
}
+ public static int getMyUserId() {
+ try {
+ Method myUserId = UserHandle.class.getMethod("myUserId");
+ Object value = myUserId.invoke(null);
+ if (value instanceof Integer) {
+ return ((Integer) value).intValue();
+ }
+ } catch (Exception ignored) {
+ }
+ return Process.myUid() / 100000;
+ }
+
public static boolean isUserOwner() {
- return UserHandle.myUserId() == UserHandle.USER_OWNER;
+ return getMyUserId() == 0;
}
public static boolean isSecondaryUser(Context context) {
diff --git a/src/com/cyanogenmod/filemanager/util/CommandHelper.java b/src/com/cyanogenmod/filemanager/util/CommandHelper.java
index abb45ce8..00ce6ab3 100644
--- a/src/com/cyanogenmod/filemanager/util/CommandHelper.java
+++ b/src/com/cyanogenmod/filemanager/util/CommandHelper.java
@@ -16,8 +16,8 @@
package com.cyanogenmod.filemanager.util;
-import android.annotation.NonNull;
-import android.annotation.Nullable;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
import android.content.Context;
import android.content.Intent;
import android.media.MediaScannerConnection;
diff --git a/src/com/cyanogenmod/filemanager/util/HexDump.java b/src/com/cyanogenmod/filemanager/util/HexDump.java
new file mode 100644
index 00000000..e8e6e989
--- /dev/null
+++ b/src/com/cyanogenmod/filemanager/util/HexDump.java
@@ -0,0 +1,24 @@
+package com.cyanogenmod.filemanager.util;
+
+/** Simple replacement for android internal HexDump utility. */
+public class HexDump {
+ /** Convert entire byte array to hex string. */
+ public static String toHexString(byte[] bytes) {
+ return toHexString(bytes, 0, bytes.length);
+ }
+
+ /** Convert a range of a byte array to hex string. */
+ public static String toHexString(byte[] bytes, int offset, int length) {
+ StringBuilder sb = new StringBuilder();
+ for (int i = offset; i < offset + length; i++) {
+ sb.append(String.format("%02x", bytes[i]));
+ }
+ return sb.toString();
+ }
+
+ /** Convert an integer offset to an 8‑character hex string (like internal HexDump). */
+ public static String toHexString(int value) {
+ return String.format("%08x", value);
+ }
+}
+
diff --git a/src/com/cyanogenmod/filemanager/util/MediaHelper.java b/src/com/cyanogenmod/filemanager/util/MediaHelper.java
index f00db57f..7239f21b 100644
--- a/src/com/cyanogenmod/filemanager/util/MediaHelper.java
+++ b/src/com/cyanogenmod/filemanager/util/MediaHelper.java
@@ -20,7 +20,7 @@
import android.content.Context;
import android.database.Cursor;
import android.net.Uri;
-import android.os.UserHandle;
+import android.os.Environment;
import android.provider.BaseColumns;
import android.provider.MediaStore;
import android.provider.MediaStore.MediaColumns;
@@ -59,24 +59,66 @@ public final class MediaHelper {
*/
public static Map getAllAlbums(ContentResolver cr) {
Map albums = new HashMap();
- final String[] projection =
- {
- "distinct " + MediaStore.Audio.Media.ALBUM_ID,
- "substr(" + MediaStore.Audio.Media.DATA + ", 0, length(" +
- MediaStore.Audio.Media.DATA + ") - length(" +
- MediaStore.Audio.Media.DISPLAY_NAME + "))"
- };
final String where = MediaStore.Audio.Media.IS_MUSIC + " = ?";
- Cursor c = cr.query(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,
- projection, where, new String[]{"1"}, null);
- if (c != null) {
+ Cursor c = null;
+ try {
try {
+ final String[] projection = {
+ MediaStore.Audio.Media.ALBUM_ID,
+ MediaColumns.RELATIVE_PATH
+ };
+ c = cr.query(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,
+ projection, where, new String[]{"1"}, null);
+ if (c != null) {
+ while (c.moveToNext()) {
+ long albumId = c.getLong(0);
+ String relativePath = c.getString(1);
+ if (!TextUtils.isEmpty(relativePath)) {
+ String absPath = new File(Environment.getExternalStorageDirectory(),
+ relativePath).getAbsolutePath();
+ albums.put(normalizeMediaPath(absPath), albumId);
+ }
+ }
+ }
+ return albums;
+ } catch (RuntimeException ignored) {
+ if (c != null) {
+ c.close();
+ c = null;
+ }
+ albums.clear();
+ }
+
+ final String[] projection = {
+ MediaStore.Audio.Media.ALBUM_ID,
+ MediaStore.Audio.Media.DATA,
+ MediaStore.Audio.Media.DISPLAY_NAME
+ };
+ c = cr.query(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,
+ projection, where, new String[]{"1"}, null);
+ if (c != null) {
while (c.moveToNext()) {
long albumId = c.getLong(0);
- String albumPath = c.getString(1);
- albums.put(albumPath, albumId);
+ String data = c.getString(1);
+ String displayName = c.getString(2);
+ if (TextUtils.isEmpty(data)) {
+ continue;
+ }
+ String albumPath;
+ if (!TextUtils.isEmpty(displayName) && data.endsWith(displayName)) {
+ albumPath = data.substring(0, data.length() - displayName.length());
+ } else {
+ File parent = new File(data).getParentFile();
+ albumPath = parent != null ? parent.getAbsolutePath() : null;
+ }
+ if (!TextUtils.isEmpty(albumPath)) {
+ albums.put(normalizeMediaPath(albumPath), albumId);
+ }
}
- } finally {
+ }
+ } catch (RuntimeException ignored) {
+ } finally {
+ if (c != null) {
c.close();
}
}
@@ -267,7 +309,7 @@ public static String normalizeMediaPath(String path) {
}
// We need to convert EXTERNAL_STORAGE -> EMULATED_STORAGE_TARGET / userId
if (path.startsWith(EXTERNAL_STORAGE)) {
- final String userId = String.valueOf(UserHandle.myUserId());
+ final String userId = String.valueOf(AndroidHelper.getMyUserId());
final String target = new File(EMULATED_STORAGE_TARGET, userId).getAbsolutePath();
path = path.replace(EXTERNAL_STORAGE, target);
}
diff --git a/src/com/cyanogenmod/filemanager/util/StorageHelper.java b/src/com/cyanogenmod/filemanager/util/StorageHelper.java
index ed07fd5e..87afac06 100644
--- a/src/com/cyanogenmod/filemanager/util/StorageHelper.java
+++ b/src/com/cyanogenmod/filemanager/util/StorageHelper.java
@@ -35,6 +35,24 @@ public final class StorageHelper {
private static StorageVolume[] sStorageVolumes;
+ public static String getStorageVolumePath(StorageVolume volume) {
+ if (volume == null) {
+ return null;
+ }
+ try {
+ Method method = volume.getClass().getMethod("getPath"); //$NON-NLS-1$
+ return (String) method.invoke(volume);
+ } catch (Exception ignored) {
+ }
+ try {
+ Method method = volume.getClass().getMethod("getDirectory"); //$NON-NLS-1$
+ File dir = (File) method.invoke(volume);
+ return dir != null ? dir.getAbsolutePath() : null;
+ } catch (Exception ignored) {
+ }
+ return null;
+ }
+
/**
* Method that returns the storage volumes defined in the system. This method uses
* reflection to retrieve the method because CM10 has a {@link Context}
@@ -117,7 +135,7 @@ public static String getStorageVolumeDescription(Context ctx, StorageVolume volu
} catch (Throwable _throw) {
// Returns the volume storage path
- return volume.getPath();
+ return getStorageVolumePath(volume);
}
}
@@ -135,7 +153,8 @@ public static boolean isPathInStorageVolume(String path) {
int cc = volumes.length;
for (int i = 0; i < cc; i++) {
StorageVolume vol = volumes[i];
- if (fso.startsWith(vol.getPath())) {
+ String vPath = getStorageVolumePath(vol);
+ if (vPath != null && fso.startsWith(vPath)) {
return true;
}
}
@@ -156,7 +175,11 @@ public static boolean isStorageVolume(String path) {
for (int i = 0; i < cc; i++) {
StorageVolume vol = volumes[i];
String p = new File(path).getAbsolutePath();
- String v = new File(vol.getPath()).getAbsolutePath();
+ String vPath = getStorageVolumePath(vol);
+ if (vPath == null) {
+ continue;
+ }
+ String v = new File(vPath).getAbsolutePath();
if (p.compareTo(v) == 0) {
return true;
}
@@ -178,7 +201,11 @@ public static String getChrootedPath(String path) {
for (int i = 0; i < cc; i++) {
StorageVolume vol = volumes[i];
File p = new File(path);
- File v = new File(vol.getPath());
+ String vPath = getStorageVolumePath(vol);
+ if (vPath == null) {
+ continue;
+ }
+ File v = new File(vPath);
if (p.getAbsolutePath().startsWith(v.getAbsolutePath())) {
return v.getName() + path.substring(v.getAbsolutePath().length());
}
diff --git a/src/com/cyanogenmod/filemanager/util/StringHelper.java b/src/com/cyanogenmod/filemanager/util/StringHelper.java
index 89d7d2f0..e0aa53f9 100644
--- a/src/com/cyanogenmod/filemanager/util/StringHelper.java
+++ b/src/com/cyanogenmod/filemanager/util/StringHelper.java
@@ -18,7 +18,7 @@
import android.text.TextUtils;
-import com.android.internal.util.HexDump;
+import com.cyanogenmod.filemanager.util.HexDump;
import java.io.ByteArrayInputStream;
import java.util.Arrays;
diff --git a/src/com/cyanogenmod/filemanager/util/XmlUtils.java b/src/com/cyanogenmod/filemanager/util/XmlUtils.java
new file mode 100644
index 00000000..fd4e9e2e
--- /dev/null
+++ b/src/com/cyanogenmod/filemanager/util/XmlUtils.java
@@ -0,0 +1,35 @@
+package com.cyanogenmod.filemanager.util;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.IOException;
+
+public final class XmlUtils {
+
+ private XmlUtils() {
+ }
+
+ public static void beginDocument(XmlPullParser parser, String firstElementName)
+ throws XmlPullParserException, IOException {
+ int type;
+ while ((type = parser.next()) != XmlPullParser.START_TAG
+ && type != XmlPullParser.END_DOCUMENT) {
+ }
+ if (type != XmlPullParser.START_TAG) {
+ throw new XmlPullParserException("No start tag found");
+ }
+ if (!firstElementName.equals(parser.getName())) {
+ throw new XmlPullParserException(
+ "Unexpected start tag: found " + parser.getName() + ", expected " + firstElementName);
+ }
+ }
+
+ public static void nextElement(XmlPullParser parser)
+ throws XmlPullParserException, IOException {
+ int type;
+ while ((type = parser.next()) != XmlPullParser.START_TAG
+ && type != XmlPullParser.END_DOCUMENT) {
+ }
+ }
+}