diff options
| -rwxr-xr-x | media/java/android/mtp/MtpDatabase.java | 57 | ||||
| -rw-r--r-- | media/java/android/mtp/MtpPropertyGroup.java | 15 | ||||
| -rw-r--r-- | media/java/android/mtp/MtpStorage.java | 12 | ||||
| -rw-r--r-- | media/java/android/mtp/MtpStorageManager.java | 16 |
4 files changed, 56 insertions, 44 deletions
diff --git a/media/java/android/mtp/MtpDatabase.java b/media/java/android/mtp/MtpDatabase.java index 6361fd81d2af..4ac6d35e351f 100755 --- a/media/java/android/mtp/MtpDatabase.java +++ b/media/java/android/mtp/MtpDatabase.java @@ -36,6 +36,7 @@ import android.system.ErrnoException; import android.system.Os; import android.system.OsConstants; import android.util.Log; +import android.util.SparseArray; import android.view.Display; import android.view.WindowManager; @@ -69,8 +70,6 @@ public class MtpDatabase implements AutoCloseable { private final Context mContext; private final ContentProviderClient mMediaProvider; - private final String mVolumeName; - private final Uri mObjectsUri; private final AtomicBoolean mClosed = new AtomicBoolean(); private final CloseGuard mCloseGuard = CloseGuard.get(); @@ -78,10 +77,10 @@ public class MtpDatabase implements AutoCloseable { private final HashMap<String, MtpStorage> mStorageMap = new HashMap<>(); // cached property groups for single properties - private final HashMap<Integer, MtpPropertyGroup> mPropertyGroupsByProperty = new HashMap<>(); + private final SparseArray<MtpPropertyGroup> mPropertyGroupsByProperty = new SparseArray<>(); // cached property groups for all properties for a given format - private final HashMap<Integer, MtpPropertyGroup> mPropertyGroupsByFormat = new HashMap<>(); + private final SparseArray<MtpPropertyGroup> mPropertyGroupsByFormat = new SparseArray<>(); // SharedPreferences for writable MTP device properties private SharedPreferences mDeviceProperties; @@ -271,14 +270,11 @@ public class MtpDatabase implements AutoCloseable { } }; - public MtpDatabase(Context context, String volumeName, - String[] subDirectories) { + public MtpDatabase(Context context, String[] subDirectories) { native_setup(); mContext = Objects.requireNonNull(context); mMediaProvider = context.getContentResolver() .acquireContentProviderClient(MediaStore.AUTHORITY); - mVolumeName = volumeName; - mObjectsUri = Files.getMtpObjectsUri(volumeName); mManager = new MtpStorageManager(new MtpStorageManager.MtpNotifier() { @Override public void sendObjectAdded(int id) { @@ -526,8 +522,7 @@ public class MtpDatabase implements AutoCloseable { propertyGroup = mPropertyGroupsByFormat.get(format); if (propertyGroup == null) { final int[] propertyList = getSupportedObjectProperties(format); - propertyGroup = new MtpPropertyGroup(mMediaProvider, mVolumeName, - propertyList); + propertyGroup = new MtpPropertyGroup(propertyList); mPropertyGroupsByFormat.put(format, propertyGroup); } } else { @@ -535,12 +530,11 @@ public class MtpDatabase implements AutoCloseable { propertyGroup = mPropertyGroupsByProperty.get(property); if (propertyGroup == null) { final int[] propertyList = new int[]{property}; - propertyGroup = new MtpPropertyGroup(mMediaProvider, mVolumeName, - propertyList); + propertyGroup = new MtpPropertyGroup(propertyList); mPropertyGroupsByProperty.put(property, propertyGroup); } } - int err = propertyGroup.getPropertyList(obj, ret); + int err = propertyGroup.getPropertyList(mMediaProvider, obj.getVolumeName(), obj, ret); if (err != MtpConstants.RESPONSE_OK) { return new MtpPropertyList(err); } @@ -581,7 +575,8 @@ public class MtpDatabase implements AutoCloseable { try { // note - we are relying on a special case in MediaProvider.update() to update // the paths for all children in the case where this is a directory. - mMediaProvider.update(mObjectsUri, values, PATH_WHERE, whereArgs); + final Uri objectsUri = MediaStore.Files.getMtpObjectsUri(obj.getVolumeName()); + mMediaProvider.update(objectsUri, values, PATH_WHERE, whereArgs); } catch (RemoteException e) { Log.e(TAG, "RemoteException in mMediaProvider.update", e); } @@ -640,12 +635,12 @@ public class MtpDatabase implements AutoCloseable { if (obj.getParent().isRoot()) { values.put(Files.FileColumns.PARENT, 0); } else { - int parentId = findInMedia(path.getParent()); + int parentId = findInMedia(newParentObj, path.getParent()); if (parentId != -1) { values.put(Files.FileColumns.PARENT, parentId); } else { // The new parent isn't in MediaProvider, so delete the object instead - deleteFromMedia(oldPath, obj.isDir()); + deleteFromMedia(obj, oldPath, obj.isDir()); return; } } @@ -655,13 +650,14 @@ public class MtpDatabase implements AutoCloseable { try { int parentId = -1; if (!oldParentObj.isRoot()) { - parentId = findInMedia(oldPath.getParent()); + parentId = findInMedia(oldParentObj, oldPath.getParent()); } if (oldParentObj.isRoot() || parentId != -1) { // Old parent exists in MediaProvider - perform a move // note - we are relying on a special case in MediaProvider.update() to update // the paths for all children in the case where this is a directory. - mMediaProvider.update(mObjectsUri, values, PATH_WHERE, whereArgs); + final Uri objectsUri = MediaStore.Files.getMtpObjectsUri(obj.getVolumeName()); + mMediaProvider.update(objectsUri, values, PATH_WHERE, whereArgs); } else { // Old parent doesn't exist - add the object MediaStore.scanFile(mContext, path.toFile()); @@ -823,14 +819,16 @@ public class MtpDatabase implements AutoCloseable { if (!mManager.endRemoveObject(obj, success)) Log.e(TAG, "Failed to end remove object"); if (success) - deleteFromMedia(obj.getPath(), obj.isDir()); + deleteFromMedia(obj, obj.getPath(), obj.isDir()); } - private int findInMedia(Path path) { + private int findInMedia(MtpStorageManager.MtpObject obj, Path path) { + final Uri objectsUri = MediaStore.Files.getMtpObjectsUri(obj.getVolumeName()); + int ret = -1; Cursor c = null; try { - c = mMediaProvider.query(mObjectsUri, ID_PROJECTION, PATH_WHERE, + c = mMediaProvider.query(objectsUri, ID_PROJECTION, PATH_WHERE, new String[]{path.toString()}, null, null); if (c != null && c.moveToNext()) { ret = c.getInt(0); @@ -844,12 +842,13 @@ public class MtpDatabase implements AutoCloseable { return ret; } - private void deleteFromMedia(Path path, boolean isDir) { + private void deleteFromMedia(MtpStorageManager.MtpObject obj, Path path, boolean isDir) { + final Uri objectsUri = MediaStore.Files.getMtpObjectsUri(obj.getVolumeName()); try { // Delete the object(s) from MediaProvider, but ignore errors. if (isDir) { // recursive case - delete all children first - mMediaProvider.delete(mObjectsUri, + mMediaProvider.delete(objectsUri, // the 'like' makes it use the index, the 'lower()' makes it correct // when the path contains sqlite wildcard characters "_data LIKE ?1 AND lower(substr(_data,1,?2))=lower(?3)", @@ -858,7 +857,7 @@ public class MtpDatabase implements AutoCloseable { } String[] whereArgs = new String[]{path.toString()}; - if (mMediaProvider.delete(mObjectsUri, PATH_WHERE, whereArgs) > 0) { + if (mMediaProvider.delete(objectsUri, PATH_WHERE, whereArgs) > 0) { if (!isDir && path.toString().toLowerCase(Locale.US).endsWith(NO_MEDIA)) { MediaStore.scanFile(mContext, path.getParent().toFile()); } @@ -876,10 +875,10 @@ public class MtpDatabase implements AutoCloseable { if (obj == null) return null; // Translate this handle to the MediaProvider Handle - handle = findInMedia(obj.getPath()); + handle = findInMedia(obj, obj.getPath()); if (handle == -1) return null; - Uri uri = Files.getMtpReferencesUri(mVolumeName, handle); + Uri uri = Files.getMtpReferencesUri(obj.getVolumeName(), handle); Cursor c = null; try { c = mMediaProvider.query(uri, PATH_PROJECTION, null, null, null, null); @@ -912,17 +911,17 @@ public class MtpDatabase implements AutoCloseable { if (obj == null) return MtpConstants.RESPONSE_INVALID_OBJECT_HANDLE; // Translate this handle to the MediaProvider Handle - handle = findInMedia(obj.getPath()); + handle = findInMedia(obj, obj.getPath()); if (handle == -1) return MtpConstants.RESPONSE_GENERAL_ERROR; - Uri uri = Files.getMtpReferencesUri(mVolumeName, handle); + Uri uri = Files.getMtpReferencesUri(obj.getVolumeName(), handle); ArrayList<ContentValues> valuesList = new ArrayList<>(); for (int id : references) { // Translate each reference id to the MediaProvider Id MtpStorageManager.MtpObject refObj = mManager.getObject(id); if (refObj == null) continue; - int refHandle = findInMedia(refObj.getPath()); + int refHandle = findInMedia(refObj, refObj.getPath()); if (refHandle == -1) continue; ContentValues values = new ContentValues(); diff --git a/media/java/android/mtp/MtpPropertyGroup.java b/media/java/android/mtp/MtpPropertyGroup.java index 6d5be8ef6985..5bb0c1b4ef27 100644 --- a/media/java/android/mtp/MtpPropertyGroup.java +++ b/media/java/android/mtp/MtpPropertyGroup.java @@ -46,9 +46,6 @@ class MtpPropertyGroup { } } - private final ContentProviderClient mProvider; - private final String mVolumeName; - // list of all properties in this group private final Property[] mProperties; @@ -58,10 +55,7 @@ class MtpPropertyGroup { private static final String PATH_WHERE = Files.FileColumns.DATA + "=?"; // constructs a property group for a list of properties - public MtpPropertyGroup(ContentProviderClient provider, String volumeName, int[] properties) { - mProvider = provider; - mVolumeName = volumeName; - + public MtpPropertyGroup(int[] properties) { int count = properties.length; ArrayList<String> columns = new ArrayList<>(count); columns.add(Files.FileColumns._ID); @@ -175,7 +169,8 @@ class MtpPropertyGroup { * object and adds them to the given property list. * @return Response_OK if the operation succeeded. */ - public int getPropertyList(MtpStorageManager.MtpObject object, MtpPropertyList list) { + public int getPropertyList(ContentProviderClient provider, String volumeName, + MtpStorageManager.MtpObject object, MtpPropertyList list) { Cursor c = null; int id = object.getId(); String path = object.getPath().toString(); @@ -184,8 +179,8 @@ class MtpPropertyGroup { try { // Look up the entry in MediaProvider only if one of those properties is needed. final Uri uri = MtpDatabase.getObjectPropertiesUri(object.getFormat(), - mVolumeName); - c = mProvider.query(uri, mColumns, + volumeName); + c = provider.query(uri, mColumns, PATH_WHERE, new String[] {path}, null, null); if (c != null && !c.moveToNext()) { c.close(); diff --git a/media/java/android/mtp/MtpStorage.java b/media/java/android/mtp/MtpStorage.java index c714b3cad296..65d0fef74b25 100644 --- a/media/java/android/mtp/MtpStorage.java +++ b/media/java/android/mtp/MtpStorage.java @@ -18,6 +18,7 @@ package android.mtp; import android.annotation.UnsupportedAppUsage; import android.os.storage.StorageVolume; +import android.provider.MediaStore; /** * This class represents a storage unit on an MTP device. @@ -27,12 +28,12 @@ import android.os.storage.StorageVolume; * @hide */ public class MtpStorage { - private final int mStorageId; private final String mPath; private final String mDescription; private final boolean mRemovable; private final long mMaxFileSize; + private final String mVolumeName; public MtpStorage(StorageVolume volume, int storageId) { mStorageId = storageId; @@ -40,6 +41,11 @@ public class MtpStorage { mDescription = volume.getDescription(null); mRemovable = volume.isRemovable(); mMaxFileSize = volume.getMaxFileSize(); + if (volume.isPrimary()) { + mVolumeName = MediaStore.VOLUME_EXTERNAL_PRIMARY; + } else { + mVolumeName = volume.getNormalizedUuid(); + } } /** @@ -88,4 +94,8 @@ public class MtpStorage { public long getMaxFileSize() { return mMaxFileSize; } + + public String getVolumeName() { + return mVolumeName; + } } diff --git a/media/java/android/mtp/MtpStorageManager.java b/media/java/android/mtp/MtpStorageManager.java index f14e7d704ea1..e783788d0158 100644 --- a/media/java/android/mtp/MtpStorageManager.java +++ b/media/java/android/mtp/MtpStorageManager.java @@ -21,6 +21,8 @@ import android.os.FileObserver; import android.os.storage.StorageVolume; import android.util.Log; +import com.android.internal.util.Preconditions; + import java.io.IOException; import java.nio.file.DirectoryIteratorException; import java.nio.file.DirectoryStream; @@ -131,6 +133,7 @@ public class MtpStorageManager { /** MtpObject represents either a file or directory in an associated storage. **/ public static class MtpObject { + private MtpStorage mStorage; // null for root objects private MtpObject mParent; @@ -147,9 +150,10 @@ public class MtpStorageManager { // null if not both a directory and visited private FileObserver mObserver; - MtpObject(String name, int id, MtpObject parent, boolean isDir) { + MtpObject(String name, int id, MtpStorage storage, MtpObject parent, boolean isDir) { mId = id; mName = name; + mStorage = Preconditions.checkNotNull(storage); mParent = parent; mObserver = null; mVisited = false; @@ -206,6 +210,10 @@ public class MtpStorageManager { return mParent == null; } + public String getVolumeName() { + return mStorage.getVolumeName(); + } + /** For MtpStorageManager only **/ private void setName(String name) { @@ -278,7 +286,7 @@ public class MtpStorageManager { } private MtpObject copy(boolean recursive) { - MtpObject copy = new MtpObject(mName, mId, mParent, mIsDir); + MtpObject copy = new MtpObject(mName, mId, mStorage, mParent, mIsDir); copy.mIsDir = mIsDir; copy.mVisited = mVisited; copy.mState = mState; @@ -408,7 +416,7 @@ public class MtpStorageManager { public synchronized MtpStorage addMtpStorage(StorageVolume volume) { int storageId = ((getNextStorageId() & 0x0000FFFF) << 16) + 1; MtpStorage storage = new MtpStorage(volume, storageId); - MtpObject root = new MtpObject(storage.getPath(), storageId, null, true); + MtpObject root = new MtpObject(storage.getPath(), storageId, storage, null, true); mRoots.put(storageId, root); return storage; } @@ -608,7 +616,7 @@ public class MtpStorageManager { return null; } - MtpObject obj = new MtpObject(newName, getNextObjectId(), parent, isDir); + MtpObject obj = new MtpObject(newName, getNextObjectId(), parent.mStorage, parent, isDir); mObjects.put(obj.getId(), obj); parent.addChild(obj); return obj; |