1dd98034edce7ebbfefadf3f8a351c1b7ee7c2a73Ryo Hashimoto/* 2dd98034edce7ebbfefadf3f8a351c1b7ee7c2a73Ryo Hashimoto * Copyright (C) 2015 The Android Open Source Project 3dd98034edce7ebbfefadf3f8a351c1b7ee7c2a73Ryo Hashimoto * 4dd98034edce7ebbfefadf3f8a351c1b7ee7c2a73Ryo Hashimoto * Licensed under the Apache License, Version 2.0 (the "License"); 5dd98034edce7ebbfefadf3f8a351c1b7ee7c2a73Ryo Hashimoto * you may not use this file except in compliance with the License. 6dd98034edce7ebbfefadf3f8a351c1b7ee7c2a73Ryo Hashimoto * You may obtain a copy of the License at 7dd98034edce7ebbfefadf3f8a351c1b7ee7c2a73Ryo Hashimoto * 8dd98034edce7ebbfefadf3f8a351c1b7ee7c2a73Ryo Hashimoto * http://www.apache.org/licenses/LICENSE-2.0 9dd98034edce7ebbfefadf3f8a351c1b7ee7c2a73Ryo Hashimoto * 10dd98034edce7ebbfefadf3f8a351c1b7ee7c2a73Ryo Hashimoto * Unless required by applicable law or agreed to in writing, software 11dd98034edce7ebbfefadf3f8a351c1b7ee7c2a73Ryo Hashimoto * distributed under the License is distributed on an "AS IS" BASIS, 12dd98034edce7ebbfefadf3f8a351c1b7ee7c2a73Ryo Hashimoto * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13dd98034edce7ebbfefadf3f8a351c1b7ee7c2a73Ryo Hashimoto * See the License for the specific language governing permissions and 14dd98034edce7ebbfefadf3f8a351c1b7ee7c2a73Ryo Hashimoto * limitations under the License. 15dd98034edce7ebbfefadf3f8a351c1b7ee7c2a73Ryo Hashimoto */ 16dd98034edce7ebbfefadf3f8a351c1b7ee7c2a73Ryo Hashimoto 17dd98034edce7ebbfefadf3f8a351c1b7ee7c2a73Ryo Hashimotopackage com.android.shell; 18dd98034edce7ebbfefadf3f8a351c1b7ee7c2a73Ryo Hashimoto 19dd98034edce7ebbfefadf3f8a351c1b7ee7c2a73Ryo Hashimotoimport android.database.Cursor; 20dd98034edce7ebbfefadf3f8a351c1b7ee7c2a73Ryo Hashimotoimport android.database.MatrixCursor; 21dd98034edce7ebbfefadf3f8a351c1b7ee7c2a73Ryo Hashimotoimport android.database.MatrixCursor.RowBuilder; 22c6905cfb1133627dfd500491c60b6528a3e593e0Ben Linimport android.net.Uri; 23dd98034edce7ebbfefadf3f8a351c1b7ee7c2a73Ryo Hashimotoimport android.os.CancellationSignal; 24dd98034edce7ebbfefadf3f8a351c1b7ee7c2a73Ryo Hashimotoimport android.os.FileUtils; 25dd98034edce7ebbfefadf3f8a351c1b7ee7c2a73Ryo Hashimotoimport android.os.ParcelFileDescriptor; 26c6905cfb1133627dfd500491c60b6528a3e593e0Ben Linimport android.provider.DocumentsContract; 27dd98034edce7ebbfefadf3f8a351c1b7ee7c2a73Ryo Hashimotoimport android.provider.DocumentsContract.Document; 28dd98034edce7ebbfefadf3f8a351c1b7ee7c2a73Ryo Hashimotoimport android.provider.DocumentsContract.Root; 29d8235e2647a1d7fbe3c1717cb235cf2518478cbdBen Lin 30d8235e2647a1d7fbe3c1717cb235cf2518478cbdBen Linimport com.android.internal.content.FileSystemProvider; 31dd98034edce7ebbfefadf3f8a351c1b7ee7c2a73Ryo Hashimoto 32dd98034edce7ebbfefadf3f8a351c1b7ee7c2a73Ryo Hashimotoimport java.io.File; 33dd98034edce7ebbfefadf3f8a351c1b7ee7c2a73Ryo Hashimotoimport java.io.FileNotFoundException; 34dd98034edce7ebbfefadf3f8a351c1b7ee7c2a73Ryo Hashimoto 35d8235e2647a1d7fbe3c1717cb235cf2518478cbdBen Linpublic class BugreportStorageProvider extends FileSystemProvider { 36c6905cfb1133627dfd500491c60b6528a3e593e0Ben Lin private static final String AUTHORITY = "com.android.shell.documents"; 37dd98034edce7ebbfefadf3f8a351c1b7ee7c2a73Ryo Hashimoto private static final String DOC_ID_ROOT = "bugreport"; 38dd98034edce7ebbfefadf3f8a351c1b7ee7c2a73Ryo Hashimoto 39d8235e2647a1d7fbe3c1717cb235cf2518478cbdBen Lin private static final String[] DEFAULT_ROOT_PROJECTION = new String[]{ 40dd98034edce7ebbfefadf3f8a351c1b7ee7c2a73Ryo Hashimoto Root.COLUMN_ROOT_ID, Root.COLUMN_FLAGS, Root.COLUMN_ICON, Root.COLUMN_TITLE, 41dd98034edce7ebbfefadf3f8a351c1b7ee7c2a73Ryo Hashimoto Root.COLUMN_DOCUMENT_ID, 42dd98034edce7ebbfefadf3f8a351c1b7ee7c2a73Ryo Hashimoto }; 43dd98034edce7ebbfefadf3f8a351c1b7ee7c2a73Ryo Hashimoto 44d8235e2647a1d7fbe3c1717cb235cf2518478cbdBen Lin private static final String[] DEFAULT_DOCUMENT_PROJECTION = new String[]{ 45dd98034edce7ebbfefadf3f8a351c1b7ee7c2a73Ryo Hashimoto Document.COLUMN_DOCUMENT_ID, Document.COLUMN_MIME_TYPE, Document.COLUMN_DISPLAY_NAME, 46dd98034edce7ebbfefadf3f8a351c1b7ee7c2a73Ryo Hashimoto Document.COLUMN_LAST_MODIFIED, Document.COLUMN_FLAGS, Document.COLUMN_SIZE, 47dd98034edce7ebbfefadf3f8a351c1b7ee7c2a73Ryo Hashimoto }; 48dd98034edce7ebbfefadf3f8a351c1b7ee7c2a73Ryo Hashimoto 49dd98034edce7ebbfefadf3f8a351c1b7ee7c2a73Ryo Hashimoto private File mRoot; 50dd98034edce7ebbfefadf3f8a351c1b7ee7c2a73Ryo Hashimoto 51dd98034edce7ebbfefadf3f8a351c1b7ee7c2a73Ryo Hashimoto @Override 52dd98034edce7ebbfefadf3f8a351c1b7ee7c2a73Ryo Hashimoto public boolean onCreate() { 53d8235e2647a1d7fbe3c1717cb235cf2518478cbdBen Lin super.onCreate(DEFAULT_DOCUMENT_PROJECTION); 54dd98034edce7ebbfefadf3f8a351c1b7ee7c2a73Ryo Hashimoto mRoot = new File(getContext().getFilesDir(), "bugreports"); 55dd98034edce7ebbfefadf3f8a351c1b7ee7c2a73Ryo Hashimoto return true; 56dd98034edce7ebbfefadf3f8a351c1b7ee7c2a73Ryo Hashimoto } 57dd98034edce7ebbfefadf3f8a351c1b7ee7c2a73Ryo Hashimoto 58dd98034edce7ebbfefadf3f8a351c1b7ee7c2a73Ryo Hashimoto @Override 59dd98034edce7ebbfefadf3f8a351c1b7ee7c2a73Ryo Hashimoto public Cursor queryRoots(String[] projection) throws FileNotFoundException { 60dd98034edce7ebbfefadf3f8a351c1b7ee7c2a73Ryo Hashimoto final MatrixCursor result = new MatrixCursor(resolveRootProjection(projection)); 61dd98034edce7ebbfefadf3f8a351c1b7ee7c2a73Ryo Hashimoto final RowBuilder row = result.newRow(); 62dd98034edce7ebbfefadf3f8a351c1b7ee7c2a73Ryo Hashimoto row.add(Root.COLUMN_ROOT_ID, DOC_ID_ROOT); 63774cc932fc29705c9580775abf7c1e7a80c2bbe3Aga Wronska row.add(Root.COLUMN_FLAGS, Root.FLAG_LOCAL_ONLY | Root.FLAG_ADVANCED); 64dd98034edce7ebbfefadf3f8a351c1b7ee7c2a73Ryo Hashimoto row.add(Root.COLUMN_ICON, android.R.mipmap.sym_def_app_icon); 65dd98034edce7ebbfefadf3f8a351c1b7ee7c2a73Ryo Hashimoto row.add(Root.COLUMN_TITLE, getContext().getString(R.string.bugreport_storage_title)); 66dd98034edce7ebbfefadf3f8a351c1b7ee7c2a73Ryo Hashimoto row.add(Root.COLUMN_DOCUMENT_ID, DOC_ID_ROOT); 67dd98034edce7ebbfefadf3f8a351c1b7ee7c2a73Ryo Hashimoto return result; 68dd98034edce7ebbfefadf3f8a351c1b7ee7c2a73Ryo Hashimoto } 69dd98034edce7ebbfefadf3f8a351c1b7ee7c2a73Ryo Hashimoto 70dd98034edce7ebbfefadf3f8a351c1b7ee7c2a73Ryo Hashimoto @Override 71dd98034edce7ebbfefadf3f8a351c1b7ee7c2a73Ryo Hashimoto public Cursor queryDocument(String documentId, String[] projection) 72dd98034edce7ebbfefadf3f8a351c1b7ee7c2a73Ryo Hashimoto throws FileNotFoundException { 73dd98034edce7ebbfefadf3f8a351c1b7ee7c2a73Ryo Hashimoto if (DOC_ID_ROOT.equals(documentId)) { 74d8235e2647a1d7fbe3c1717cb235cf2518478cbdBen Lin final MatrixCursor result = new MatrixCursor(resolveDocumentProjection(projection)); 75d8235e2647a1d7fbe3c1717cb235cf2518478cbdBen Lin includeDefaultDocument(result); 76d8235e2647a1d7fbe3c1717cb235cf2518478cbdBen Lin return result; 77dd98034edce7ebbfefadf3f8a351c1b7ee7c2a73Ryo Hashimoto } else { 78d8235e2647a1d7fbe3c1717cb235cf2518478cbdBen Lin return super.queryDocument(documentId, projection); 79dd98034edce7ebbfefadf3f8a351c1b7ee7c2a73Ryo Hashimoto } 80dd98034edce7ebbfefadf3f8a351c1b7ee7c2a73Ryo Hashimoto } 81dd98034edce7ebbfefadf3f8a351c1b7ee7c2a73Ryo Hashimoto 82dd98034edce7ebbfefadf3f8a351c1b7ee7c2a73Ryo Hashimoto @Override 83dd98034edce7ebbfefadf3f8a351c1b7ee7c2a73Ryo Hashimoto public ParcelFileDescriptor openDocument( 84dd98034edce7ebbfefadf3f8a351c1b7ee7c2a73Ryo Hashimoto String documentId, String mode, CancellationSignal signal) 85dd98034edce7ebbfefadf3f8a351c1b7ee7c2a73Ryo Hashimoto throws FileNotFoundException { 86dd98034edce7ebbfefadf3f8a351c1b7ee7c2a73Ryo Hashimoto if (ParcelFileDescriptor.parseMode(mode) != ParcelFileDescriptor.MODE_READ_ONLY) { 87dd98034edce7ebbfefadf3f8a351c1b7ee7c2a73Ryo Hashimoto throw new FileNotFoundException("Failed to open: " + documentId + ", mode = " + mode); 88dd98034edce7ebbfefadf3f8a351c1b7ee7c2a73Ryo Hashimoto } 89dd98034edce7ebbfefadf3f8a351c1b7ee7c2a73Ryo Hashimoto return ParcelFileDescriptor.open(getFileForDocId(documentId), 90dd98034edce7ebbfefadf3f8a351c1b7ee7c2a73Ryo Hashimoto ParcelFileDescriptor.MODE_READ_ONLY); 91dd98034edce7ebbfefadf3f8a351c1b7ee7c2a73Ryo Hashimoto } 92dd98034edce7ebbfefadf3f8a351c1b7ee7c2a73Ryo Hashimoto 93dd98034edce7ebbfefadf3f8a351c1b7ee7c2a73Ryo Hashimoto @Override 94d8235e2647a1d7fbe3c1717cb235cf2518478cbdBen Lin protected Uri buildNotificationUri(String docId) { 95d8235e2647a1d7fbe3c1717cb235cf2518478cbdBen Lin return DocumentsContract.buildChildDocumentsUri(AUTHORITY, docId); 96c6905cfb1133627dfd500491c60b6528a3e593e0Ben Lin } 97c6905cfb1133627dfd500491c60b6528a3e593e0Ben Lin 98dd98034edce7ebbfefadf3f8a351c1b7ee7c2a73Ryo Hashimoto private static String[] resolveRootProjection(String[] projection) { 99dd98034edce7ebbfefadf3f8a351c1b7ee7c2a73Ryo Hashimoto return projection != null ? projection : DEFAULT_ROOT_PROJECTION; 100dd98034edce7ebbfefadf3f8a351c1b7ee7c2a73Ryo Hashimoto } 101dd98034edce7ebbfefadf3f8a351c1b7ee7c2a73Ryo Hashimoto 102dd98034edce7ebbfefadf3f8a351c1b7ee7c2a73Ryo Hashimoto private static String[] resolveDocumentProjection(String[] projection) { 103dd98034edce7ebbfefadf3f8a351c1b7ee7c2a73Ryo Hashimoto return projection != null ? projection : DEFAULT_DOCUMENT_PROJECTION; 104dd98034edce7ebbfefadf3f8a351c1b7ee7c2a73Ryo Hashimoto } 105dd98034edce7ebbfefadf3f8a351c1b7ee7c2a73Ryo Hashimoto 106d8235e2647a1d7fbe3c1717cb235cf2518478cbdBen Lin @Override 107d8235e2647a1d7fbe3c1717cb235cf2518478cbdBen Lin protected String getDocIdForFile(File file) { 108dd98034edce7ebbfefadf3f8a351c1b7ee7c2a73Ryo Hashimoto return DOC_ID_ROOT + ":" + file.getName(); 109dd98034edce7ebbfefadf3f8a351c1b7ee7c2a73Ryo Hashimoto } 110dd98034edce7ebbfefadf3f8a351c1b7ee7c2a73Ryo Hashimoto 111d8235e2647a1d7fbe3c1717cb235cf2518478cbdBen Lin @Override 112d8235e2647a1d7fbe3c1717cb235cf2518478cbdBen Lin protected File getFileForDocId(String documentId, boolean visible) 113d8235e2647a1d7fbe3c1717cb235cf2518478cbdBen Lin throws FileNotFoundException { 114d8235e2647a1d7fbe3c1717cb235cf2518478cbdBen Lin if (DOC_ID_ROOT.equals(documentId)) { 115d8235e2647a1d7fbe3c1717cb235cf2518478cbdBen Lin return mRoot; 116d8235e2647a1d7fbe3c1717cb235cf2518478cbdBen Lin } else { 117d8235e2647a1d7fbe3c1717cb235cf2518478cbdBen Lin final int splitIndex = documentId.indexOf(':', 1); 118d8235e2647a1d7fbe3c1717cb235cf2518478cbdBen Lin final String name = documentId.substring(splitIndex + 1); 119d8235e2647a1d7fbe3c1717cb235cf2518478cbdBen Lin if (splitIndex == -1 || !DOC_ID_ROOT.equals(documentId.substring(0, splitIndex)) || 120d8235e2647a1d7fbe3c1717cb235cf2518478cbdBen Lin !FileUtils.isValidExtFilename(name)) { 121d8235e2647a1d7fbe3c1717cb235cf2518478cbdBen Lin throw new FileNotFoundException("Invalid document ID: " + documentId); 122d8235e2647a1d7fbe3c1717cb235cf2518478cbdBen Lin } 123d8235e2647a1d7fbe3c1717cb235cf2518478cbdBen Lin final File file = new File(mRoot, name); 124d8235e2647a1d7fbe3c1717cb235cf2518478cbdBen Lin if (!file.exists()) { 125d8235e2647a1d7fbe3c1717cb235cf2518478cbdBen Lin throw new FileNotFoundException("File not found: " + documentId); 126d8235e2647a1d7fbe3c1717cb235cf2518478cbdBen Lin } 127d8235e2647a1d7fbe3c1717cb235cf2518478cbdBen Lin return file; 128dd98034edce7ebbfefadf3f8a351c1b7ee7c2a73Ryo Hashimoto } 129dd98034edce7ebbfefadf3f8a351c1b7ee7c2a73Ryo Hashimoto } 130dd98034edce7ebbfefadf3f8a351c1b7ee7c2a73Ryo Hashimoto 131d8235e2647a1d7fbe3c1717cb235cf2518478cbdBen Lin @Override 132d8235e2647a1d7fbe3c1717cb235cf2518478cbdBen Lin protected RowBuilder includeFile(MatrixCursor result, String docId, File file) 133d8235e2647a1d7fbe3c1717cb235cf2518478cbdBen Lin throws FileNotFoundException { 134d8235e2647a1d7fbe3c1717cb235cf2518478cbdBen Lin RowBuilder row = super.includeFile(result, docId, file); 135d8235e2647a1d7fbe3c1717cb235cf2518478cbdBen Lin row.add(Document.COLUMN_FLAGS, Document.FLAG_SUPPORTS_DELETE); 136d8235e2647a1d7fbe3c1717cb235cf2518478cbdBen Lin return row; 137d8235e2647a1d7fbe3c1717cb235cf2518478cbdBen Lin } 138d8235e2647a1d7fbe3c1717cb235cf2518478cbdBen Lin 139d8235e2647a1d7fbe3c1717cb235cf2518478cbdBen Lin private void includeDefaultDocument(MatrixCursor result) { 140dd98034edce7ebbfefadf3f8a351c1b7ee7c2a73Ryo Hashimoto final RowBuilder row = result.newRow(); 141d8235e2647a1d7fbe3c1717cb235cf2518478cbdBen Lin row.add(Document.COLUMN_DOCUMENT_ID, DOC_ID_ROOT); 142d8235e2647a1d7fbe3c1717cb235cf2518478cbdBen Lin row.add(Document.COLUMN_MIME_TYPE, Document.MIME_TYPE_DIR); 143d8235e2647a1d7fbe3c1717cb235cf2518478cbdBen Lin row.add(Document.COLUMN_DISPLAY_NAME, mRoot.getName()); 144d8235e2647a1d7fbe3c1717cb235cf2518478cbdBen Lin row.add(Document.COLUMN_LAST_MODIFIED, mRoot.lastModified()); 145d8235e2647a1d7fbe3c1717cb235cf2518478cbdBen Lin row.add(Document.COLUMN_FLAGS, Document.FLAG_DIR_PREFERS_LAST_MODIFIED); 146dd98034edce7ebbfefadf3f8a351c1b7ee7c2a73Ryo Hashimoto } 147dd98034edce7ebbfefadf3f8a351c1b7ee7c2a73Ryo Hashimoto} 148