diff options
author | Ryo Hashimoto <hashimoto@google.com> | 2015-03-17 19:56:42 +0900 |
---|---|---|
committer | Ryo Hashimoto <hashimoto@google.com> | 2015-03-23 18:28:01 +0900 |
commit | dd98034edce7ebbfefadf3f8a351c1b7ee7c2a73 (patch) | |
tree | 2b9d731271225db44896992c6d7b0909d4246648 /packages/Shell | |
parent | bf2673384cdea54eef2ca1c3e6ee35f5a3ce0e8a (diff) | |
download | frameworks_base-dd98034edce7ebbfefadf3f8a351c1b7ee7c2a73.zip frameworks_base-dd98034edce7ebbfefadf3f8a351c1b7ee7c2a73.tar.gz frameworks_base-dd98034edce7ebbfefadf3f8a351c1b7ee7c2a73.tar.bz2 |
Add BugreportStorageProvider
BugreportStorageProvider provides storage backend for bugreports.
BUG:18070208
Change-Id: I8506dd90d69907090295d99df7427fc747b83698
Diffstat (limited to 'packages/Shell')
-rw-r--r-- | packages/Shell/AndroidManifest.xml | 12 | ||||
-rw-r--r-- | packages/Shell/res/values/strings.xml | 3 | ||||
-rw-r--r-- | packages/Shell/src/com/android/shell/BugreportStorageProvider.java | 164 |
3 files changed, 179 insertions, 0 deletions
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml index 3c44245..9d16501 100644 --- a/packages/Shell/AndroidManifest.xml +++ b/packages/Shell/AndroidManifest.xml @@ -105,6 +105,18 @@ android:resource="@xml/file_provider_paths" /> </provider> + <provider + android:name=".BugreportStorageProvider" + android:authorities="com.android.shell.documents" + android:grantUriPermissions="true" + android:exported="true" + android:permission="android.permission.MANAGE_DOCUMENTS" + android:enabled="false"> + <intent-filter> + <action android:name="android.content.action.DOCUMENTS_PROVIDER" /> + </intent-filter> + </provider> + <activity android:name=".BugreportWarningActivity" android:theme="@*android:style/Theme.DeviceDefault.Light.Dialog.Alert" diff --git a/packages/Shell/res/values/strings.xml b/packages/Shell/res/values/strings.xml index 51e2c95..3db0848 100644 --- a/packages/Shell/res/values/strings.xml +++ b/packages/Shell/res/values/strings.xml @@ -30,4 +30,7 @@ <string name="bugreport_confirm">Bug reports contain data from the system\'s various log files, including personal and private information. Only share bug reports with apps and people you trust.</string> <!-- Checkbox that indicates this dialog should be shown again when the next bugreport is taken. [CHAR LIMIT=50] --> <string name="bugreport_confirm_repeat">Show this message next time</string> + + <!-- Title for documents backend that offers bugreports. --> + <string name="bugreport_storage_title">Bug reports</string> </resources> diff --git a/packages/Shell/src/com/android/shell/BugreportStorageProvider.java b/packages/Shell/src/com/android/shell/BugreportStorageProvider.java new file mode 100644 index 0000000..814aa8c --- /dev/null +++ b/packages/Shell/src/com/android/shell/BugreportStorageProvider.java @@ -0,0 +1,164 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.shell; + +import android.database.Cursor; +import android.database.MatrixCursor; +import android.database.MatrixCursor.RowBuilder; +import android.os.CancellationSignal; +import android.os.FileUtils; +import android.os.ParcelFileDescriptor; +import android.provider.DocumentsContract.Document; +import android.provider.DocumentsContract.Root; +import android.provider.DocumentsProvider; +import android.webkit.MimeTypeMap; + +import java.io.File; +import java.io.FileNotFoundException; + +public class BugreportStorageProvider extends DocumentsProvider { + private static final String DOC_ID_ROOT = "bugreport"; + + private static final String[] DEFAULT_ROOT_PROJECTION = new String[] { + Root.COLUMN_ROOT_ID, Root.COLUMN_FLAGS, Root.COLUMN_ICON, Root.COLUMN_TITLE, + Root.COLUMN_DOCUMENT_ID, + }; + + private static final String[] DEFAULT_DOCUMENT_PROJECTION = new String[] { + Document.COLUMN_DOCUMENT_ID, Document.COLUMN_MIME_TYPE, Document.COLUMN_DISPLAY_NAME, + Document.COLUMN_LAST_MODIFIED, Document.COLUMN_FLAGS, Document.COLUMN_SIZE, + }; + + private File mRoot; + + @Override + public boolean onCreate() { + mRoot = new File(getContext().getFilesDir(), "bugreports"); + return true; + } + + @Override + public Cursor queryRoots(String[] projection) throws FileNotFoundException { + final MatrixCursor result = new MatrixCursor(resolveRootProjection(projection)); + final RowBuilder row = result.newRow(); + row.add(Root.COLUMN_ROOT_ID, DOC_ID_ROOT); + row.add(Root.COLUMN_FLAGS, Root.FLAG_LOCAL_ONLY | Root.FLAG_ADVANCED); + row.add(Root.COLUMN_ICON, android.R.mipmap.sym_def_app_icon); + row.add(Root.COLUMN_TITLE, getContext().getString(R.string.bugreport_storage_title)); + row.add(Root.COLUMN_DOCUMENT_ID, DOC_ID_ROOT); + return result; + } + + @Override + public Cursor queryDocument(String documentId, String[] projection) + throws FileNotFoundException { + final MatrixCursor result = new MatrixCursor(resolveDocumentProjection(projection)); + if (DOC_ID_ROOT.equals(documentId)) { + final RowBuilder row = result.newRow(); + row.add(Document.COLUMN_DOCUMENT_ID, documentId); + row.add(Document.COLUMN_MIME_TYPE, Document.MIME_TYPE_DIR); + row.add(Document.COLUMN_DISPLAY_NAME, mRoot.getName()); + row.add(Document.COLUMN_LAST_MODIFIED, mRoot.lastModified()); + row.add(Document.COLUMN_FLAGS, Document.FLAG_DIR_PREFERS_LAST_MODIFIED); + } else { + addFileRow(result, getFileForDocId(documentId)); + } + return result; + } + + @Override + public Cursor queryChildDocuments( + String parentDocumentId, String[] projection, String sortOrder) + throws FileNotFoundException { + final MatrixCursor result = new MatrixCursor(resolveDocumentProjection(projection)); + if (DOC_ID_ROOT.equals(parentDocumentId)) { + final File[] files = mRoot.listFiles(); + if (files != null) { + for (File file : files) { + addFileRow(result, file); + } + } + } + return result; + } + + @Override + public ParcelFileDescriptor openDocument( + String documentId, String mode, CancellationSignal signal) + throws FileNotFoundException { + if (ParcelFileDescriptor.parseMode(mode) != ParcelFileDescriptor.MODE_READ_ONLY) { + throw new FileNotFoundException("Failed to open: " + documentId + ", mode = " + mode); + } + return ParcelFileDescriptor.open(getFileForDocId(documentId), + ParcelFileDescriptor.MODE_READ_ONLY); + } + + @Override + public void deleteDocument(String documentId) throws FileNotFoundException { + if (!getFileForDocId(documentId).delete()) { + throw new FileNotFoundException("Failed to delete: " + documentId); + } + } + + private static String[] resolveRootProjection(String[] projection) { + return projection != null ? projection : DEFAULT_ROOT_PROJECTION; + } + + private static String[] resolveDocumentProjection(String[] projection) { + return projection != null ? projection : DEFAULT_DOCUMENT_PROJECTION; + } + + private static String getTypeForName(String name) { + final int lastDot = name.lastIndexOf('.'); + if (lastDot >= 0) { + final String extension = name.substring(lastDot + 1).toLowerCase(); + final String mime = MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension); + if (mime != null) { + return mime; + } + } + return "application/octet-stream"; + } + + private String getDocIdForFile(File file) { + return DOC_ID_ROOT + ":" + file.getName(); + } + + private File getFileForDocId(String documentId) throws FileNotFoundException { + final int splitIndex = documentId.indexOf(':', 1); + final String name = documentId.substring(splitIndex + 1); + if (splitIndex == -1 || !DOC_ID_ROOT.equals(documentId.substring(0, splitIndex)) || + !FileUtils.isValidExtFilename(name)) { + throw new FileNotFoundException("Invalid document ID: " + documentId); + } + final File file = new File(mRoot, name); + if (!file.exists()) { + throw new FileNotFoundException("File not found: " + documentId); + } + return file; + } + + private void addFileRow(MatrixCursor result, File file) { + final RowBuilder row = result.newRow(); + row.add(Document.COLUMN_DOCUMENT_ID, getDocIdForFile(file)); + row.add(Document.COLUMN_MIME_TYPE, getTypeForName(file.getName())); + row.add(Document.COLUMN_DISPLAY_NAME, file.getName()); + row.add(Document.COLUMN_LAST_MODIFIED, file.lastModified()); + row.add(Document.COLUMN_FLAGS, Document.FLAG_SUPPORTS_DELETE); + row.add(Document.COLUMN_SIZE, file.length()); + } +} |