MtpDocumentsProvider.java revision b80a3cfd05fc7492dd59b7f8d4337eb5e29088c2
1c00d5d4d82620beba271e63875b93ad9cc39523fDaichi Hirono/* 2c00d5d4d82620beba271e63875b93ad9cc39523fDaichi Hirono * Copyright (C) 2015 The Android Open Source Project 3c00d5d4d82620beba271e63875b93ad9cc39523fDaichi Hirono * 4c00d5d4d82620beba271e63875b93ad9cc39523fDaichi Hirono * Licensed under the Apache License, Version 2.0 (the "License"); 5c00d5d4d82620beba271e63875b93ad9cc39523fDaichi Hirono * you may not use this file except in compliance with the License. 6c00d5d4d82620beba271e63875b93ad9cc39523fDaichi Hirono * You may obtain a copy of the License at 7c00d5d4d82620beba271e63875b93ad9cc39523fDaichi Hirono * 8c00d5d4d82620beba271e63875b93ad9cc39523fDaichi Hirono * http://www.apache.org/licenses/LICENSE-2.0 9c00d5d4d82620beba271e63875b93ad9cc39523fDaichi Hirono * 10c00d5d4d82620beba271e63875b93ad9cc39523fDaichi Hirono * Unless required by applicable law or agreed to in writing, software 11c00d5d4d82620beba271e63875b93ad9cc39523fDaichi Hirono * distributed under the License is distributed on an "AS IS" BASIS, 12c00d5d4d82620beba271e63875b93ad9cc39523fDaichi Hirono * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13c00d5d4d82620beba271e63875b93ad9cc39523fDaichi Hirono * See the License for the specific language governing permissions and 14c00d5d4d82620beba271e63875b93ad9cc39523fDaichi Hirono * limitations under the License. 15c00d5d4d82620beba271e63875b93ad9cc39523fDaichi Hirono */ 16c00d5d4d82620beba271e63875b93ad9cc39523fDaichi Hirono 17c00d5d4d82620beba271e63875b93ad9cc39523fDaichi Hironopackage com.android.mtp; 18c00d5d4d82620beba271e63875b93ad9cc39523fDaichi Hirono 19d5152429e11d3a831a7993dc67ddf69f69bd3912Daichi Hironoimport android.content.ContentResolver; 203faa43a4a6f270e2e1e2ec55b77508084af16757Daichi Hironoimport android.content.res.AssetFileDescriptor; 21c00d5d4d82620beba271e63875b93ad9cc39523fDaichi Hironoimport android.database.Cursor; 2250d17aa871d9ca645a8e7af64df8866b85aee245Daichi Hironoimport android.database.MatrixCursor; 233faa43a4a6f270e2e1e2ec55b77508084af16757Daichi Hironoimport android.graphics.Point; 24c00d5d4d82620beba271e63875b93ad9cc39523fDaichi Hironoimport android.os.CancellationSignal; 25c00d5d4d82620beba271e63875b93ad9cc39523fDaichi Hironoimport android.os.ParcelFileDescriptor; 26d5152429e11d3a831a7993dc67ddf69f69bd3912Daichi Hironoimport android.provider.DocumentsContract; 27c00d5d4d82620beba271e63875b93ad9cc39523fDaichi Hironoimport android.provider.DocumentsContract.Document; 28c00d5d4d82620beba271e63875b93ad9cc39523fDaichi Hironoimport android.provider.DocumentsContract.Root; 29c00d5d4d82620beba271e63875b93ad9cc39523fDaichi Hironoimport android.provider.DocumentsProvider; 30d5152429e11d3a831a7993dc67ddf69f69bd3912Daichi Hironoimport android.util.Log; 31d5152429e11d3a831a7993dc67ddf69f69bd3912Daichi Hirono 32d5152429e11d3a831a7993dc67ddf69f69bd3912Daichi Hironoimport com.android.internal.annotations.VisibleForTesting; 33d5152429e11d3a831a7993dc67ddf69f69bd3912Daichi Hirono 34c00d5d4d82620beba271e63875b93ad9cc39523fDaichi Hironoimport java.io.FileNotFoundException; 35d5152429e11d3a831a7993dc67ddf69f69bd3912Daichi Hironoimport java.io.IOException; 36c00d5d4d82620beba271e63875b93ad9cc39523fDaichi Hirono 37d5152429e11d3a831a7993dc67ddf69f69bd3912Daichi Hirono/** 38d5152429e11d3a831a7993dc67ddf69f69bd3912Daichi Hirono * DocumentsProvider for MTP devices. 39d5152429e11d3a831a7993dc67ddf69f69bd3912Daichi Hirono */ 40c00d5d4d82620beba271e63875b93ad9cc39523fDaichi Hironopublic class MtpDocumentsProvider extends DocumentsProvider { 412efe4cac49efd87c5f14f48051a5556f437cedc9Daichi Hirono static final String AUTHORITY = "com.android.mtp.documents"; 422efe4cac49efd87c5f14f48051a5556f437cedc9Daichi Hirono static final String TAG = "MtpDocumentsProvider"; 436baa16e9109046661fef8dcc25b8754ac68bcdaeDaichi Hirono static final String[] DEFAULT_ROOT_PROJECTION = new String[] { 44c00d5d4d82620beba271e63875b93ad9cc39523fDaichi Hirono Root.COLUMN_ROOT_ID, Root.COLUMN_FLAGS, Root.COLUMN_ICON, 45c00d5d4d82620beba271e63875b93ad9cc39523fDaichi Hirono Root.COLUMN_TITLE, Root.COLUMN_DOCUMENT_ID, 46c00d5d4d82620beba271e63875b93ad9cc39523fDaichi Hirono Root.COLUMN_AVAILABLE_BYTES, 47c00d5d4d82620beba271e63875b93ad9cc39523fDaichi Hirono }; 486baa16e9109046661fef8dcc25b8754ac68bcdaeDaichi Hirono static final String[] DEFAULT_DOCUMENT_PROJECTION = new String[] { 49c00d5d4d82620beba271e63875b93ad9cc39523fDaichi Hirono Document.COLUMN_DOCUMENT_ID, Document.COLUMN_MIME_TYPE, 50c00d5d4d82620beba271e63875b93ad9cc39523fDaichi Hirono Document.COLUMN_DISPLAY_NAME, Document.COLUMN_LAST_MODIFIED, 51c00d5d4d82620beba271e63875b93ad9cc39523fDaichi Hirono Document.COLUMN_FLAGS, Document.COLUMN_SIZE, 52c00d5d4d82620beba271e63875b93ad9cc39523fDaichi Hirono }; 53c00d5d4d82620beba271e63875b93ad9cc39523fDaichi Hirono 542efe4cac49efd87c5f14f48051a5556f437cedc9Daichi Hirono private static MtpDocumentsProvider sSingleton; 552efe4cac49efd87c5f14f48051a5556f437cedc9Daichi Hirono 562efe4cac49efd87c5f14f48051a5556f437cedc9Daichi Hirono private MtpManager mMtpManager; 57d5152429e11d3a831a7993dc67ddf69f69bd3912Daichi Hirono private ContentResolver mResolver; 588ba419119d50a031160cab54bef6899bd0051ea9Daichi Hirono private PipeManager mPipeManager; 596baa16e9109046661fef8dcc25b8754ac68bcdaeDaichi Hirono private DocumentLoader mDocumentLoader; 608b9024f0c20b1b79df1f2d0bc2f1a82f726b1176Daichi Hirono private RootScanner mRootScanner; 61d5152429e11d3a831a7993dc67ddf69f69bd3912Daichi Hirono 622efe4cac49efd87c5f14f48051a5556f437cedc9Daichi Hirono /** 632efe4cac49efd87c5f14f48051a5556f437cedc9Daichi Hirono * Provides singleton instance to MtpDocumentsService. 642efe4cac49efd87c5f14f48051a5556f437cedc9Daichi Hirono */ 652efe4cac49efd87c5f14f48051a5556f437cedc9Daichi Hirono static MtpDocumentsProvider getInstance() { 662efe4cac49efd87c5f14f48051a5556f437cedc9Daichi Hirono return sSingleton; 672efe4cac49efd87c5f14f48051a5556f437cedc9Daichi Hirono } 682efe4cac49efd87c5f14f48051a5556f437cedc9Daichi Hirono 69c00d5d4d82620beba271e63875b93ad9cc39523fDaichi Hirono @Override 70c00d5d4d82620beba271e63875b93ad9cc39523fDaichi Hirono public boolean onCreate() { 712efe4cac49efd87c5f14f48051a5556f437cedc9Daichi Hirono sSingleton = this; 722efe4cac49efd87c5f14f48051a5556f437cedc9Daichi Hirono mMtpManager = new MtpManager(getContext()); 73d5152429e11d3a831a7993dc67ddf69f69bd3912Daichi Hirono mResolver = getContext().getContentResolver(); 748ba419119d50a031160cab54bef6899bd0051ea9Daichi Hirono mPipeManager = new PipeManager(); 756baa16e9109046661fef8dcc25b8754ac68bcdaeDaichi Hirono mDocumentLoader = new DocumentLoader(mMtpManager, mResolver); 768b9024f0c20b1b79df1f2d0bc2f1a82f726b1176Daichi Hirono mRootScanner = new RootScanner(mResolver, mMtpManager); 77c00d5d4d82620beba271e63875b93ad9cc39523fDaichi Hirono return true; 78c00d5d4d82620beba271e63875b93ad9cc39523fDaichi Hirono } 79c00d5d4d82620beba271e63875b93ad9cc39523fDaichi Hirono 80d5152429e11d3a831a7993dc67ddf69f69bd3912Daichi Hirono @VisibleForTesting 812efe4cac49efd87c5f14f48051a5556f437cedc9Daichi Hirono void onCreateForTesting(MtpManager mtpManager, ContentResolver resolver) { 826baa16e9109046661fef8dcc25b8754ac68bcdaeDaichi Hirono mMtpManager = mtpManager; 836baa16e9109046661fef8dcc25b8754ac68bcdaeDaichi Hirono mResolver = resolver; 846baa16e9109046661fef8dcc25b8754ac68bcdaeDaichi Hirono mDocumentLoader = new DocumentLoader(mMtpManager, mResolver); 858b9024f0c20b1b79df1f2d0bc2f1a82f726b1176Daichi Hirono mRootScanner = new RootScanner(mResolver, mMtpManager); 86d5152429e11d3a831a7993dc67ddf69f69bd3912Daichi Hirono } 87d5152429e11d3a831a7993dc67ddf69f69bd3912Daichi Hirono 88c00d5d4d82620beba271e63875b93ad9cc39523fDaichi Hirono @Override 89c00d5d4d82620beba271e63875b93ad9cc39523fDaichi Hirono public Cursor queryRoots(String[] projection) throws FileNotFoundException { 9050d17aa871d9ca645a8e7af64df8866b85aee245Daichi Hirono if (projection == null) { 9150d17aa871d9ca645a8e7af64df8866b85aee245Daichi Hirono projection = MtpDocumentsProvider.DEFAULT_ROOT_PROJECTION; 9250d17aa871d9ca645a8e7af64df8866b85aee245Daichi Hirono } 9350d17aa871d9ca645a8e7af64df8866b85aee245Daichi Hirono final MatrixCursor cursor = new MatrixCursor(projection); 948b9024f0c20b1b79df1f2d0bc2f1a82f726b1176Daichi Hirono final MtpRoot[] roots = mRootScanner.getRoots(); 958b9024f0c20b1b79df1f2d0bc2f1a82f726b1176Daichi Hirono for (final MtpRoot root : roots) { 968b9024f0c20b1b79df1f2d0bc2f1a82f726b1176Daichi Hirono final Identifier rootIdentifier = new Identifier(root.mDeviceId, root.mStorageId); 978b9024f0c20b1b79df1f2d0bc2f1a82f726b1176Daichi Hirono final MatrixCursor.RowBuilder builder = cursor.newRow(); 988b9024f0c20b1b79df1f2d0bc2f1a82f726b1176Daichi Hirono builder.add(Root.COLUMN_ROOT_ID, rootIdentifier.toRootId()); 9987763e6a91a54e7995cfda9b7e80162f02ac4cbcTomasz Mikolajewski builder.add(Root.COLUMN_FLAGS, Root.FLAG_SUPPORTS_IS_CHILD | Root.FLAG_SUPPORTS_CREATE); 1008b9024f0c20b1b79df1f2d0bc2f1a82f726b1176Daichi Hirono builder.add(Root.COLUMN_TITLE, root.mDescription); 1018b9024f0c20b1b79df1f2d0bc2f1a82f726b1176Daichi Hirono builder.add( 1028b9024f0c20b1b79df1f2d0bc2f1a82f726b1176Daichi Hirono Root.COLUMN_DOCUMENT_ID, 1038b9024f0c20b1b79df1f2d0bc2f1a82f726b1176Daichi Hirono rootIdentifier.toDocumentId()); 1048b9024f0c20b1b79df1f2d0bc2f1a82f726b1176Daichi Hirono builder.add(Root.COLUMN_AVAILABLE_BYTES , root.mFreeSpace); 10550d17aa871d9ca645a8e7af64df8866b85aee245Daichi Hirono } 10650d17aa871d9ca645a8e7af64df8866b85aee245Daichi Hirono cursor.setNotificationUri( 10750d17aa871d9ca645a8e7af64df8866b85aee245Daichi Hirono mResolver, DocumentsContract.buildRootsUri(MtpDocumentsProvider.AUTHORITY)); 10850d17aa871d9ca645a8e7af64df8866b85aee245Daichi Hirono return cursor; 109c00d5d4d82620beba271e63875b93ad9cc39523fDaichi Hirono } 110c00d5d4d82620beba271e63875b93ad9cc39523fDaichi Hirono 111c00d5d4d82620beba271e63875b93ad9cc39523fDaichi Hirono @Override 112c00d5d4d82620beba271e63875b93ad9cc39523fDaichi Hirono public Cursor queryDocument(String documentId, String[] projection) 113c00d5d4d82620beba271e63875b93ad9cc39523fDaichi Hirono throws FileNotFoundException { 114e5323b7493f2bc1537d7e6b2d4595d69fd01d72eDaichi Hirono if (projection == null) { 115e5323b7493f2bc1537d7e6b2d4595d69fd01d72eDaichi Hirono projection = MtpDocumentsProvider.DEFAULT_DOCUMENT_PROJECTION; 116e5323b7493f2bc1537d7e6b2d4595d69fd01d72eDaichi Hirono } 117e5323b7493f2bc1537d7e6b2d4595d69fd01d72eDaichi Hirono final Identifier identifier = Identifier.createFromDocumentId(documentId); 118e5323b7493f2bc1537d7e6b2d4595d69fd01d72eDaichi Hirono 119e5323b7493f2bc1537d7e6b2d4595d69fd01d72eDaichi Hirono MtpDocument document = null; 120e5323b7493f2bc1537d7e6b2d4595d69fd01d72eDaichi Hirono if (identifier.mObjectHandle != MtpDocument.DUMMY_HANDLE_FOR_ROOT) { 121e5323b7493f2bc1537d7e6b2d4595d69fd01d72eDaichi Hirono try { 122e5323b7493f2bc1537d7e6b2d4595d69fd01d72eDaichi Hirono document = mMtpManager.getDocument(identifier.mDeviceId, identifier.mObjectHandle); 123e5323b7493f2bc1537d7e6b2d4595d69fd01d72eDaichi Hirono } catch (IOException e) { 124e5323b7493f2bc1537d7e6b2d4595d69fd01d72eDaichi Hirono throw new FileNotFoundException(e.getMessage()); 125e5323b7493f2bc1537d7e6b2d4595d69fd01d72eDaichi Hirono } 126e5323b7493f2bc1537d7e6b2d4595d69fd01d72eDaichi Hirono } else { 127e5323b7493f2bc1537d7e6b2d4595d69fd01d72eDaichi Hirono MtpRoot[] roots; 128e5323b7493f2bc1537d7e6b2d4595d69fd01d72eDaichi Hirono try { 129e5323b7493f2bc1537d7e6b2d4595d69fd01d72eDaichi Hirono roots = mMtpManager.getRoots(identifier.mDeviceId); 130e5323b7493f2bc1537d7e6b2d4595d69fd01d72eDaichi Hirono if (roots != null) { 131e5323b7493f2bc1537d7e6b2d4595d69fd01d72eDaichi Hirono for (final MtpRoot root : roots) { 132e5323b7493f2bc1537d7e6b2d4595d69fd01d72eDaichi Hirono if (identifier.mStorageId == root.mStorageId) { 133e5323b7493f2bc1537d7e6b2d4595d69fd01d72eDaichi Hirono document = new MtpDocument(root); 134e5323b7493f2bc1537d7e6b2d4595d69fd01d72eDaichi Hirono break; 135e5323b7493f2bc1537d7e6b2d4595d69fd01d72eDaichi Hirono } 136e5323b7493f2bc1537d7e6b2d4595d69fd01d72eDaichi Hirono } 137e5323b7493f2bc1537d7e6b2d4595d69fd01d72eDaichi Hirono } 138e5323b7493f2bc1537d7e6b2d4595d69fd01d72eDaichi Hirono if (document == null) { 139e5323b7493f2bc1537d7e6b2d4595d69fd01d72eDaichi Hirono throw new FileNotFoundException(); 140e5323b7493f2bc1537d7e6b2d4595d69fd01d72eDaichi Hirono } 141e5323b7493f2bc1537d7e6b2d4595d69fd01d72eDaichi Hirono } catch (IOException e) { 142e5323b7493f2bc1537d7e6b2d4595d69fd01d72eDaichi Hirono throw new FileNotFoundException(e.getMessage()); 143e5323b7493f2bc1537d7e6b2d4595d69fd01d72eDaichi Hirono } 144e5323b7493f2bc1537d7e6b2d4595d69fd01d72eDaichi Hirono } 145e5323b7493f2bc1537d7e6b2d4595d69fd01d72eDaichi Hirono 146e5323b7493f2bc1537d7e6b2d4595d69fd01d72eDaichi Hirono final MatrixCursor cursor = new MatrixCursor(projection); 147124d060bc980c7555616ff9d07a4dc3b8f3cd341Daichi Hirono document.addToCursor( 148124d060bc980c7555616ff9d07a4dc3b8f3cd341Daichi Hirono new Identifier(identifier.mDeviceId, identifier.mStorageId), cursor.newRow()); 149e5323b7493f2bc1537d7e6b2d4595d69fd01d72eDaichi Hirono return cursor; 150c00d5d4d82620beba271e63875b93ad9cc39523fDaichi Hirono } 151c00d5d4d82620beba271e63875b93ad9cc39523fDaichi Hirono 152c00d5d4d82620beba271e63875b93ad9cc39523fDaichi Hirono @Override 153124d060bc980c7555616ff9d07a4dc3b8f3cd341Daichi Hirono public Cursor queryChildDocuments(String parentDocumentId, 154124d060bc980c7555616ff9d07a4dc3b8f3cd341Daichi Hirono String[] projection, String sortOrder) throws FileNotFoundException { 155124d060bc980c7555616ff9d07a4dc3b8f3cd341Daichi Hirono if (projection == null) { 156124d060bc980c7555616ff9d07a4dc3b8f3cd341Daichi Hirono projection = MtpDocumentsProvider.DEFAULT_DOCUMENT_PROJECTION; 157124d060bc980c7555616ff9d07a4dc3b8f3cd341Daichi Hirono } 158124d060bc980c7555616ff9d07a4dc3b8f3cd341Daichi Hirono final Identifier parentIdentifier = Identifier.createFromDocumentId(parentDocumentId); 159124d060bc980c7555616ff9d07a4dc3b8f3cd341Daichi Hirono try { 1606baa16e9109046661fef8dcc25b8754ac68bcdaeDaichi Hirono return mDocumentLoader.queryChildDocuments(projection, parentIdentifier); 161124d060bc980c7555616ff9d07a4dc3b8f3cd341Daichi Hirono } catch (IOException exception) { 162124d060bc980c7555616ff9d07a4dc3b8f3cd341Daichi Hirono throw new FileNotFoundException(exception.getMessage()); 163124d060bc980c7555616ff9d07a4dc3b8f3cd341Daichi Hirono } 164c00d5d4d82620beba271e63875b93ad9cc39523fDaichi Hirono } 165c00d5d4d82620beba271e63875b93ad9cc39523fDaichi Hirono 166c00d5d4d82620beba271e63875b93ad9cc39523fDaichi Hirono @Override 1678ba419119d50a031160cab54bef6899bd0051ea9Daichi Hirono public ParcelFileDescriptor openDocument( 1688ba419119d50a031160cab54bef6899bd0051ea9Daichi Hirono String documentId, String mode, CancellationSignal signal) 1698ba419119d50a031160cab54bef6899bd0051ea9Daichi Hirono throws FileNotFoundException { 1708ba419119d50a031160cab54bef6899bd0051ea9Daichi Hirono final Identifier identifier = Identifier.createFromDocumentId(documentId); 1718ba419119d50a031160cab54bef6899bd0051ea9Daichi Hirono try { 172b80a3cfd05fc7492dd59b7f8d4337eb5e29088c2Tomasz Mikolajewski switch (mode) { 173b80a3cfd05fc7492dd59b7f8d4337eb5e29088c2Tomasz Mikolajewski case "r": 174b80a3cfd05fc7492dd59b7f8d4337eb5e29088c2Tomasz Mikolajewski return mPipeManager.readDocument(mMtpManager, identifier); 175b80a3cfd05fc7492dd59b7f8d4337eb5e29088c2Tomasz Mikolajewski case "w": 176b80a3cfd05fc7492dd59b7f8d4337eb5e29088c2Tomasz Mikolajewski return mPipeManager.writeDocument(getContext(), mMtpManager, identifier); 177b80a3cfd05fc7492dd59b7f8d4337eb5e29088c2Tomasz Mikolajewski default: 178b80a3cfd05fc7492dd59b7f8d4337eb5e29088c2Tomasz Mikolajewski // TODO: Add support for seekable files. 179b80a3cfd05fc7492dd59b7f8d4337eb5e29088c2Tomasz Mikolajewski throw new UnsupportedOperationException( 180b80a3cfd05fc7492dd59b7f8d4337eb5e29088c2Tomasz Mikolajewski "The provider does not support seekable file."); 181b80a3cfd05fc7492dd59b7f8d4337eb5e29088c2Tomasz Mikolajewski } 1828ba419119d50a031160cab54bef6899bd0051ea9Daichi Hirono } catch (IOException error) { 1838ba419119d50a031160cab54bef6899bd0051ea9Daichi Hirono throw new FileNotFoundException(error.getMessage()); 1848ba419119d50a031160cab54bef6899bd0051ea9Daichi Hirono } 185d5152429e11d3a831a7993dc67ddf69f69bd3912Daichi Hirono } 186d5152429e11d3a831a7993dc67ddf69f69bd3912Daichi Hirono 1873faa43a4a6f270e2e1e2ec55b77508084af16757Daichi Hirono @Override 1883faa43a4a6f270e2e1e2ec55b77508084af16757Daichi Hirono public AssetFileDescriptor openDocumentThumbnail( 1893faa43a4a6f270e2e1e2ec55b77508084af16757Daichi Hirono String documentId, 1903faa43a4a6f270e2e1e2ec55b77508084af16757Daichi Hirono Point sizeHint, 1913faa43a4a6f270e2e1e2ec55b77508084af16757Daichi Hirono CancellationSignal signal) throws FileNotFoundException { 1923faa43a4a6f270e2e1e2ec55b77508084af16757Daichi Hirono final Identifier identifier = Identifier.createFromDocumentId(documentId); 1933faa43a4a6f270e2e1e2ec55b77508084af16757Daichi Hirono try { 1943faa43a4a6f270e2e1e2ec55b77508084af16757Daichi Hirono return new AssetFileDescriptor( 1953faa43a4a6f270e2e1e2ec55b77508084af16757Daichi Hirono mPipeManager.readThumbnail(mMtpManager, identifier), 196573c1fbc5f98f033681e378ec965136bce49c899Daichi Hirono 0, // Start offset. 1973faa43a4a6f270e2e1e2ec55b77508084af16757Daichi Hirono AssetFileDescriptor.UNKNOWN_LENGTH); 1983faa43a4a6f270e2e1e2ec55b77508084af16757Daichi Hirono } catch (IOException error) { 1993faa43a4a6f270e2e1e2ec55b77508084af16757Daichi Hirono throw new FileNotFoundException(error.getMessage()); 2003faa43a4a6f270e2e1e2ec55b77508084af16757Daichi Hirono } 2013faa43a4a6f270e2e1e2ec55b77508084af16757Daichi Hirono } 2023faa43a4a6f270e2e1e2ec55b77508084af16757Daichi Hirono 2033faa43a4a6f270e2e1e2ec55b77508084af16757Daichi Hirono @Override 2043faa43a4a6f270e2e1e2ec55b77508084af16757Daichi Hirono public void deleteDocument(String documentId) throws FileNotFoundException { 2053faa43a4a6f270e2e1e2ec55b77508084af16757Daichi Hirono try { 2063faa43a4a6f270e2e1e2ec55b77508084af16757Daichi Hirono final Identifier identifier = Identifier.createFromDocumentId(documentId); 2073faa43a4a6f270e2e1e2ec55b77508084af16757Daichi Hirono final int parentHandle = 2083faa43a4a6f270e2e1e2ec55b77508084af16757Daichi Hirono mMtpManager.getParent(identifier.mDeviceId, identifier.mObjectHandle); 2093faa43a4a6f270e2e1e2ec55b77508084af16757Daichi Hirono mMtpManager.deleteDocument(identifier.mDeviceId, identifier.mObjectHandle); 2103faa43a4a6f270e2e1e2ec55b77508084af16757Daichi Hirono notifyChildDocumentsChange(new Identifier( 2113faa43a4a6f270e2e1e2ec55b77508084af16757Daichi Hirono identifier.mDeviceId, identifier.mStorageId, parentHandle).toDocumentId()); 2123faa43a4a6f270e2e1e2ec55b77508084af16757Daichi Hirono } catch (IOException error) { 2133faa43a4a6f270e2e1e2ec55b77508084af16757Daichi Hirono throw new FileNotFoundException(error.getMessage()); 2143faa43a4a6f270e2e1e2ec55b77508084af16757Daichi Hirono } 2153faa43a4a6f270e2e1e2ec55b77508084af16757Daichi Hirono } 2163faa43a4a6f270e2e1e2ec55b77508084af16757Daichi Hirono 2176baa16e9109046661fef8dcc25b8754ac68bcdaeDaichi Hirono @Override 2186baa16e9109046661fef8dcc25b8754ac68bcdaeDaichi Hirono public void onTrimMemory(int level) { 2196baa16e9109046661fef8dcc25b8754ac68bcdaeDaichi Hirono mDocumentLoader.clearCache(); 2206baa16e9109046661fef8dcc25b8754ac68bcdaeDaichi Hirono } 2216baa16e9109046661fef8dcc25b8754ac68bcdaeDaichi Hirono 22287763e6a91a54e7995cfda9b7e80162f02ac4cbcTomasz Mikolajewski @Override 22387763e6a91a54e7995cfda9b7e80162f02ac4cbcTomasz Mikolajewski public String createDocument(String parentDocumentId, String mimeType, String displayName) 22487763e6a91a54e7995cfda9b7e80162f02ac4cbcTomasz Mikolajewski throws FileNotFoundException { 22587763e6a91a54e7995cfda9b7e80162f02ac4cbcTomasz Mikolajewski try { 22687763e6a91a54e7995cfda9b7e80162f02ac4cbcTomasz Mikolajewski final Identifier parentId = Identifier.createFromDocumentId(parentDocumentId); 22787763e6a91a54e7995cfda9b7e80162f02ac4cbcTomasz Mikolajewski final int objectHandle = mMtpManager.createDocument( 22887763e6a91a54e7995cfda9b7e80162f02ac4cbcTomasz Mikolajewski parentId.mDeviceId, parentId.mStorageId, parentId.mObjectHandle, mimeType, 22987763e6a91a54e7995cfda9b7e80162f02ac4cbcTomasz Mikolajewski displayName); 23087763e6a91a54e7995cfda9b7e80162f02ac4cbcTomasz Mikolajewski final String documentId = new Identifier(parentId.mDeviceId, parentId.mStorageId, 23187763e6a91a54e7995cfda9b7e80162f02ac4cbcTomasz Mikolajewski objectHandle).toDocumentId(); 23287763e6a91a54e7995cfda9b7e80162f02ac4cbcTomasz Mikolajewski notifyChildDocumentsChange(parentDocumentId); 23387763e6a91a54e7995cfda9b7e80162f02ac4cbcTomasz Mikolajewski return documentId; 23487763e6a91a54e7995cfda9b7e80162f02ac4cbcTomasz Mikolajewski } catch (IOException error) { 23587763e6a91a54e7995cfda9b7e80162f02ac4cbcTomasz Mikolajewski Log.e(TAG, error.getMessage()); 23687763e6a91a54e7995cfda9b7e80162f02ac4cbcTomasz Mikolajewski throw new FileNotFoundException(error.getMessage()); 23787763e6a91a54e7995cfda9b7e80162f02ac4cbcTomasz Mikolajewski } 23887763e6a91a54e7995cfda9b7e80162f02ac4cbcTomasz Mikolajewski } 23987763e6a91a54e7995cfda9b7e80162f02ac4cbcTomasz Mikolajewski 2402efe4cac49efd87c5f14f48051a5556f437cedc9Daichi Hirono void openDevice(int deviceId) throws IOException { 2412efe4cac49efd87c5f14f48051a5556f437cedc9Daichi Hirono mMtpManager.openDevice(deviceId); 2428b9024f0c20b1b79df1f2d0bc2f1a82f726b1176Daichi Hirono mRootScanner.scanNow(); 243d5152429e11d3a831a7993dc67ddf69f69bd3912Daichi Hirono } 244d5152429e11d3a831a7993dc67ddf69f69bd3912Daichi Hirono 2452efe4cac49efd87c5f14f48051a5556f437cedc9Daichi Hirono void closeDevice(int deviceId) throws IOException { 2462efe4cac49efd87c5f14f48051a5556f437cedc9Daichi Hirono mMtpManager.closeDevice(deviceId); 2476baa16e9109046661fef8dcc25b8754ac68bcdaeDaichi Hirono mDocumentLoader.clearCache(deviceId); 2488b9024f0c20b1b79df1f2d0bc2f1a82f726b1176Daichi Hirono mRootScanner.scanNow(); 249d5152429e11d3a831a7993dc67ddf69f69bd3912Daichi Hirono } 250d5152429e11d3a831a7993dc67ddf69f69bd3912Daichi Hirono 251d5152429e11d3a831a7993dc67ddf69f69bd3912Daichi Hirono void closeAllDevices() { 252d5152429e11d3a831a7993dc67ddf69f69bd3912Daichi Hirono boolean closed = false; 2532efe4cac49efd87c5f14f48051a5556f437cedc9Daichi Hirono for (int deviceId : mMtpManager.getOpenedDeviceIds()) { 254d5152429e11d3a831a7993dc67ddf69f69bd3912Daichi Hirono try { 2552efe4cac49efd87c5f14f48051a5556f437cedc9Daichi Hirono mMtpManager.closeDevice(deviceId); 2566baa16e9109046661fef8dcc25b8754ac68bcdaeDaichi Hirono mDocumentLoader.clearCache(deviceId); 257d5152429e11d3a831a7993dc67ddf69f69bd3912Daichi Hirono closed = true; 258d5152429e11d3a831a7993dc67ddf69f69bd3912Daichi Hirono } catch (IOException d) { 259d5152429e11d3a831a7993dc67ddf69f69bd3912Daichi Hirono Log.d(TAG, "Failed to close the MTP device: " + deviceId); 260d5152429e11d3a831a7993dc67ddf69f69bd3912Daichi Hirono } 261d5152429e11d3a831a7993dc67ddf69f69bd3912Daichi Hirono } 262d5152429e11d3a831a7993dc67ddf69f69bd3912Daichi Hirono if (closed) { 2638b9024f0c20b1b79df1f2d0bc2f1a82f726b1176Daichi Hirono mRootScanner.scanNow(); 264d5152429e11d3a831a7993dc67ddf69f69bd3912Daichi Hirono } 265d5152429e11d3a831a7993dc67ddf69f69bd3912Daichi Hirono } 266d5152429e11d3a831a7993dc67ddf69f69bd3912Daichi Hirono 26750d17aa871d9ca645a8e7af64df8866b85aee245Daichi Hirono boolean hasOpenedDevices() { 26850d17aa871d9ca645a8e7af64df8866b85aee245Daichi Hirono return mMtpManager.getOpenedDeviceIds().length != 0; 26950d17aa871d9ca645a8e7af64df8866b85aee245Daichi Hirono } 27050d17aa871d9ca645a8e7af64df8866b85aee245Daichi Hirono 2715fecc6cf032bbbc2616dd2342a50656bf2857832Daichi Hirono private void notifyChildDocumentsChange(String parentDocumentId) { 2725fecc6cf032bbbc2616dd2342a50656bf2857832Daichi Hirono mResolver.notifyChange( 2735fecc6cf032bbbc2616dd2342a50656bf2857832Daichi Hirono DocumentsContract.buildChildDocumentsUri(AUTHORITY, parentDocumentId), 2745fecc6cf032bbbc2616dd2342a50656bf2857832Daichi Hirono null, 2755fecc6cf032bbbc2616dd2342a50656bf2857832Daichi Hirono false); 2765fecc6cf032bbbc2616dd2342a50656bf2857832Daichi Hirono } 277c00d5d4d82620beba271e63875b93ad9cc39523fDaichi Hirono} 278