Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 6a5ea7ea authored by Daichi Hirono's avatar Daichi Hirono
Browse files

Move logic to skip single storage.

The tree structure of MTP model looks like /device/storage/objects. But
almost all MTP device has only single storage, so it's redundant to show
a single storage as a child of device in UI.

MtpDocumentsProvider has a special logic to skip single storage, and
shows storage's object as a children of device in such case. Previously
the logic was applied when MtpDocumentsProvider returned a root
list. The provider returns a storage as a Documents.Root, instead of
device if the device has only one storage.

However the number of root cannot be obtain for closed device. Thus the
previous logic did not work for closed devices that have a single
storage. The CL moves the logic from queryRoot to
queryChildDocuments. Now MtpDocumentsProvider always returns a device as
root, then it returns storage's objects as the device's children, where
we has already opened the device.

BUG=26481574

Change-Id: I25af0fc220410e321a378d67f226798ec4bba19c
parent b8bcd199
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -74,7 +74,7 @@ class DocumentLoader {
            int parentHandle = parent.mObjectHandle;
            // Need to pass the special value MtpManager.OBJECT_HANDLE_ROOT_CHILDREN to
            // getObjectHandles if we would like to obtain children under the root.
            if (parentHandle == Identifier.DUMMY_HANDLE_FOR_ROOT) {
            if (parent.mDocumentType == MtpDatabaseConstants.DOCUMENT_TYPE_STORAGE) {
                parentHandle = MtpManager.OBJECT_HANDLE_ROOT_CHILDREN;
            }
            // TODO: Handle nit race around here.
+7 −5
Original line number Diff line number Diff line
@@ -17,23 +17,25 @@
package com.android.mtp;

import java.util.Objects;
import static com.android.mtp.MtpDatabaseConstants.DocumentType;

/**
 * Static utilities for ID.
 */
class Identifier {
    final static int DUMMY_HANDLE_FOR_ROOT = 0;

    final int mDeviceId;
    final int mStorageId;
    final int mObjectHandle;
    final String mDocumentId;
    final @DocumentType int mDocumentType;

    Identifier(int deviceId, int storageId, int objectHandle, String documentId) {
    Identifier(int deviceId, int storageId, int objectHandle, String documentId,
            @DocumentType int documentType) {
        mDeviceId = deviceId;
        mStorageId = storageId;
        mObjectHandle = objectHandle;
        mDocumentId = documentId;
        mDocumentType = documentType;
    }

    @Override
@@ -42,7 +44,7 @@ class Identifier {
            return false;
        final Identifier other = (Identifier) obj;
        return mDeviceId == other.mDeviceId && mStorageId == other.mStorageId &&
                mObjectHandle == other.mObjectHandle;
                mObjectHandle == other.mObjectHandle && mDocumentId == other.mDocumentId;
    }

    @Override
+86 −48
Original line number Diff line number Diff line
@@ -143,11 +143,7 @@ class MtpDatabase {
                        null);
                try {
                    values.clear();
                    if (storageCursor.getCount() == 1) {
                        storageCursor.moveToNext();
                        DatabaseUtils.cursorRowToContentValues(storageCursor, values);
                    } else {
                        final Cursor cursor = builder.query(
                    try (final Cursor deviceRoot = builder.query(
                            mDatabase,
                            columnNames,
                            selection + " AND " + COLUMN_DEVICE_ID + " = ?",
@@ -157,27 +153,26 @@ class MtpDatabase {
                                    deviceId),
                            null,
                            null,
                                null);
                        try {
                            cursor.moveToNext();
                            DatabaseUtils.cursorRowToContentValues(cursor, values);
                        } finally {
                            cursor.close();
                            null)) {
                        deviceRoot.moveToNext();
                        DatabaseUtils.cursorRowToContentValues(deviceRoot, values);
                    }

                    if (storageCursor.getCount() != 0) {
                        long capacityBytes = 0;
                        long availableBytes = 0;
                            int capacityIndex = cursor.getColumnIndex(Root.COLUMN_CAPACITY_BYTES);
                            int availableIndex = cursor.getColumnIndex(Root.COLUMN_AVAILABLE_BYTES);
                        final int capacityIndex =
                                storageCursor.getColumnIndex(Root.COLUMN_CAPACITY_BYTES);
                        final int availableIndex =
                                storageCursor.getColumnIndex(Root.COLUMN_AVAILABLE_BYTES);
                        while (storageCursor.moveToNext()) {
                            // If requested columnNames does not include COLUMN_XXX_BYTES, we
                            // don't calculate corresponding values.
                            if (capacityIndex != -1) {
                                    capacityBytes += cursor.getLong(capacityIndex);
                                capacityBytes += storageCursor.getLong(capacityIndex);
                            }
                            if (availableIndex != -1) {
                                    availableBytes += cursor.getLong(availableIndex);
                                availableBytes += storageCursor.getLong(availableIndex);
                            }
                        }
                        values.put(Root.COLUMN_CAPACITY_BYTES, capacityBytes);
@@ -186,6 +181,12 @@ class MtpDatabase {
                        values.putNull(Root.COLUMN_CAPACITY_BYTES);
                        values.putNull(Root.COLUMN_AVAILABLE_BYTES);
                    }
                    if (storageCursor.getCount() == 1 && values.containsKey(Root.COLUMN_TITLE)) {
                        storageCursor.moveToFirst();
                        values.put(
                                Root.COLUMN_TITLE,
                                storageCursor.getString(
                                        storageCursor.getColumnIndex(Root.COLUMN_TITLE)));
                    }
                } finally {
                    storageCursor.close();
@@ -238,13 +239,46 @@ class MtpDatabase {
                null);
    }

    /**
     * Returns identifier of single storage if given document points device and it has only one
     * storage. Otherwise null.
     *
     * @param documentId Document ID that may point a device.
     * @return Identifier for single storage or null.
     * @throws FileNotFoundException The given document ID is not registered in database.
     */
    @Nullable Identifier getSingleStorageIdentifier(String documentId)
            throws FileNotFoundException {
        // Check if the parent document is device that has single storage.
        try (final Cursor cursor = mDatabase.query(
                TABLE_DOCUMENTS,
                strings(Document.COLUMN_DOCUMENT_ID),
                COLUMN_ROW_STATE + " IN (?, ?) AND " +
                COLUMN_PARENT_DOCUMENT_ID + " = ? AND " +
                COLUMN_DOCUMENT_TYPE + " = ?",
                strings(ROW_STATE_VALID,
                        ROW_STATE_INVALIDATED,
                        documentId,
                        DOCUMENT_TYPE_STORAGE),
                null,
                null,
                null)) {
            if (cursor.getCount() == 1) {
                cursor.moveToNext();
                return createIdentifier(cursor.getString(0));
            } else {
                return null;
            }
        }
    }

    /**
     * Queries a single document.
     * @param documentId
     * @param projection
     * @return Database cursor.
     */
    public Cursor queryDocument(String documentId, String[] projection) {
    Cursor queryDocument(String documentId, String[] projection) {
        return mDatabase.query(
                TABLE_DOCUMENTS,
                projection,
@@ -287,12 +321,12 @@ class MtpDatabase {
    }

    /**
     * Obtains parent document ID.
     * Obtains parent identifier.
     * @param documentId
     * @return parent document ID.
     * @return parent identifier.
     * @throws FileNotFoundException
     */
    String getParentId(String documentId) throws FileNotFoundException {
    Identifier getParentIdentifier(String documentId) throws FileNotFoundException {
        final Cursor cursor = mDatabase.query(
                TABLE_DOCUMENTS,
                strings(COLUMN_PARENT_DOCUMENT_ID),
@@ -304,7 +338,7 @@ class MtpDatabase {
                "1");
        try {
            if (cursor.moveToNext()) {
                return cursor.getString(0);
                return createIdentifier(cursor.getString(0));
            } else {
                throw new FileNotFoundException("Cannot find a row having ID=" + documentId);
            }
@@ -352,7 +386,10 @@ class MtpDatabase {
        // Currently documentId is old format.
        final Cursor cursor = mDatabase.query(
                TABLE_DOCUMENTS,
                strings(COLUMN_DEVICE_ID, COLUMN_STORAGE_ID, COLUMN_OBJECT_HANDLE),
                strings(COLUMN_DEVICE_ID,
                        COLUMN_STORAGE_ID,
                        COLUMN_OBJECT_HANDLE,
                        COLUMN_DOCUMENT_TYPE),
                SELECTION_DOCUMENT_ID,
                strings(documentId),
                null,
@@ -367,8 +404,9 @@ class MtpDatabase {
                return new Identifier(
                        cursor.getInt(0),
                        cursor.getInt(1),
                        cursor.isNull(2) ? Identifier.DUMMY_HANDLE_FOR_ROOT : cursor.getInt(2),
                        documentId);
                        cursor.getInt(2),
                        documentId,
                        cursor.getInt(3));
            }
        } finally {
            cursor.close();
+7 −0
Original line number Diff line number Diff line
@@ -16,10 +16,13 @@

package com.android.mtp;

import android.annotation.IntDef;
import android.database.sqlite.SQLiteQueryBuilder;
import android.provider.DocumentsContract.Document;
import android.provider.DocumentsContract.Root;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.HashMap;
import java.util.Map;

@@ -92,6 +95,10 @@ class MtpDatabaseConstants {
     */
    static final int MAP_BY_NAME = 1;

    @IntDef(value = { DOCUMENT_TYPE_DEVICE, DOCUMENT_TYPE_STORAGE, DOCUMENT_TYPE_OBJECT })
    @Retention(RetentionPolicy.SOURCE)
    public @interface DocumentType {}

    /**
     * Document that represents a MTP device.
     */
+24 −4
Original line number Diff line number Diff line
@@ -150,11 +150,22 @@ public class MtpDocumentsProvider extends DocumentsProvider {
        if (projection == null) {
            projection = MtpDocumentsProvider.DEFAULT_DOCUMENT_PROJECTION;
        }
        final Identifier parentIdentifier = mDatabase.createIdentifier(parentDocumentId);
        Identifier parentIdentifier = mDatabase.createIdentifier(parentDocumentId);
        try {
            if (parentIdentifier.mDocumentType == MtpDatabaseConstants.DOCUMENT_TYPE_DEVICE) {
                final Identifier singleStorageIdentifier =
                        mDatabase.getSingleStorageIdentifier(parentDocumentId);
                if (singleStorageIdentifier == null) {
                    // Returns storage list from database.
                    return mDatabase.queryChildDocuments(projection, parentDocumentId);
                }
                parentIdentifier = singleStorageIdentifier;
            }
            // Returns object list from document loader.
            return getDocumentLoader(parentIdentifier).queryChildDocuments(
                    projection, parentIdentifier);
        } catch (IOException exception) {
            Log.e(MtpDocumentsProvider.TAG, "queryChildDocuments", exception);
            throw new FileNotFoundException(exception.getMessage());
        }
    }
@@ -190,6 +201,7 @@ public class MtpDocumentsProvider extends DocumentsProvider {
                    throw new IllegalArgumentException("Unknown mode for openDocument: " + mode);
            }
        } catch (IOException error) {
            Log.e(MtpDocumentsProvider.TAG, "openDocument", error);
            throw new FileNotFoundException(error.getMessage());
        }
    }
@@ -206,6 +218,7 @@ public class MtpDocumentsProvider extends DocumentsProvider {
                    0,  // Start offset.
                    AssetFileDescriptor.UNKNOWN_LENGTH);
        } catch (IOException error) {
            Log.e(MtpDocumentsProvider.TAG, "openDocumentThumbnail", error);
            throw new FileNotFoundException(error.getMessage());
        }
    }
@@ -214,13 +227,20 @@ public class MtpDocumentsProvider extends DocumentsProvider {
    public void deleteDocument(String documentId) throws FileNotFoundException {
        try {
            final Identifier identifier = mDatabase.createIdentifier(documentId);
            final Identifier parentIdentifier =
                    mDatabase.createIdentifier(mDatabase.getParentId(documentId));
            final Identifier parentIdentifier = mDatabase.getParentIdentifier(documentId);
            mMtpManager.deleteDocument(identifier.mDeviceId, identifier.mObjectHandle);
            mDatabase.deleteDocument(documentId);
            getDocumentLoader(parentIdentifier).clearTask(parentIdentifier);
            notifyChildDocumentsChange(parentIdentifier.mDocumentId);
            if (parentIdentifier.mDocumentType == MtpDatabaseConstants.DOCUMENT_TYPE_STORAGE) {
                // If the parent is storage, the object might be appeared as child of device because
                // we skip storage when the device has only one storage.
                final Identifier deviceIdentifier = mDatabase.getParentIdentifier(
                        parentIdentifier.mDocumentId);
                notifyChildDocumentsChange(deviceIdentifier.mDocumentId);
            }
        } catch (IOException error) {
            Log.e(MtpDocumentsProvider.TAG, "deleteDocument", error);
            throw new FileNotFoundException(error.getMessage());
        }
    }
@@ -259,7 +279,7 @@ public class MtpDocumentsProvider extends DocumentsProvider {
            notifyChildDocumentsChange(parentDocumentId);
            return documentId;
        } catch (IOException error) {
            Log.e(TAG, error.getMessage());
            Log.e(TAG, "createDocument", error);
            throw new FileNotFoundException(error.getMessage());
        }
    }
Loading