1/* 2 * Copyright (C) 2016 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package com.android.documentsui.archives; 18 19import com.android.documentsui.tests.R; 20 21import android.content.Context; 22import android.content.res.AssetFileDescriptor; 23import android.database.Cursor; 24import android.database.MatrixCursor; 25import android.database.MatrixCursor.RowBuilder; 26import android.net.Uri; 27import android.os.CancellationSignal; 28import android.os.ParcelFileDescriptor; 29import android.provider.DocumentsContract; 30import android.provider.DocumentsContract.Document; 31import android.provider.DocumentsContract.Root; 32import android.provider.DocumentsProvider; 33import android.webkit.MimeTypeMap; 34 35import libcore.io.IoUtils; 36 37import java.io.File; 38import java.io.FileNotFoundException; 39import java.util.HashMap; 40import java.util.Map; 41import java.util.concurrent.ExecutorService; 42import java.util.concurrent.Executors; 43 44 45public class ResourcesProvider extends DocumentsProvider { 46 public static final String AUTHORITY = "com.android.documentsui.archives.resourcesprovider"; 47 48 private static final String[] DEFAULT_ROOT_PROJECTION = new String[] { 49 Root.COLUMN_ROOT_ID, Root.COLUMN_FLAGS, Root.COLUMN_TITLE, Root.COLUMN_DOCUMENT_ID 50 }; 51 private static final String[] DEFAULT_DOCUMENT_PROJECTION = new String[] { 52 Document.COLUMN_DOCUMENT_ID, Document.COLUMN_MIME_TYPE, Document.COLUMN_DISPLAY_NAME, 53 Document.COLUMN_LAST_MODIFIED, Document.COLUMN_FLAGS, Document.COLUMN_SIZE, 54 }; 55 56 private static final Map<String, Integer> RESOURCES = new HashMap<>(); 57 static { 58 RESOURCES.put("archive.zip", R.raw.archive); 59 RESOURCES.put("broken.zip", R.raw.broken); 60 RESOURCES.put("empty_dirs.zip", R.raw.empty_dirs); 61 RESOURCES.put("images.zip", R.raw.images); 62 RESOURCES.put("no_dirs.zip", R.raw.no_dirs); 63 } 64 65 private ExecutorService mExecutor = null; 66 private TestUtils mTestUtils = null; 67 68 @Override 69 public boolean onCreate() { 70 mExecutor = Executors.newSingleThreadExecutor(); 71 mTestUtils = new TestUtils(getContext(), getContext(), mExecutor); 72 return true; 73 } 74 75 @Override 76 public Cursor queryRoots(String[] projection) throws FileNotFoundException { 77 final MatrixCursor result = new MatrixCursor(projection != null ? projection 78 : DEFAULT_ROOT_PROJECTION); 79 final RowBuilder row = result.newRow(); 80 row.add(Root.COLUMN_ROOT_ID, "root-id"); 81 row.add(Root.COLUMN_FLAGS, 0); 82 row.add(Root.COLUMN_TITLE, "ResourcesProvider"); 83 row.add(Root.COLUMN_DOCUMENT_ID, "root-document-id"); 84 return result; 85 } 86 87 @Override 88 public Cursor queryDocument(String documentId, String[] projection) 89 throws FileNotFoundException { 90 final MatrixCursor result = new MatrixCursor(projection != null ? projection 91 : DEFAULT_DOCUMENT_PROJECTION); 92 if ("root-document-id".equals(documentId)) { 93 final RowBuilder row = result.newRow(); 94 row.add(Document.COLUMN_DOCUMENT_ID, "root-document-id"); 95 row.add(Document.COLUMN_FLAGS, 0); 96 row.add(Document.COLUMN_DISPLAY_NAME, "ResourcesProvider"); 97 row.add(Document.COLUMN_SIZE, 0); 98 row.add(Document.COLUMN_MIME_TYPE, Document.MIME_TYPE_DIR); 99 return result; 100 } 101 102 includeDocument(result, documentId); 103 return result; 104 } 105 106 @Override 107 public Cursor queryChildDocuments( 108 String parentDocumentId, String[] projection, String sortOrder) 109 throws FileNotFoundException { 110 if (!"root-document-id".equals(parentDocumentId)) { 111 throw new FileNotFoundException(); 112 } 113 114 final MatrixCursor result = new MatrixCursor(projection != null ? projection 115 : DEFAULT_DOCUMENT_PROJECTION); 116 for (String documentId : RESOURCES.keySet()) { 117 includeDocument(result, documentId); 118 } 119 return result; 120 } 121 122 @Override 123 public ParcelFileDescriptor openDocument(String docId, String mode, CancellationSignal signal) 124 throws FileNotFoundException { 125 final Integer resourceId = RESOURCES.get(docId); 126 if (resourceId == null) { 127 throw new FileNotFoundException(); 128 } 129 return mTestUtils.getSeekableDescriptor(resourceId); 130 } 131 132 void includeDocument(MatrixCursor result, String documentId) throws FileNotFoundException { 133 final Integer resourceId = RESOURCES.get(documentId); 134 if (resourceId == null) { 135 throw new FileNotFoundException(); 136 } 137 138 AssetFileDescriptor fd = null; 139 try { 140 fd = getContext().getResources().openRawResourceFd(resourceId); 141 final RowBuilder row = result.newRow(); 142 row.add(Document.COLUMN_DOCUMENT_ID, documentId); 143 row.add(Document.COLUMN_FLAGS, 0); 144 row.add(Document.COLUMN_DISPLAY_NAME, documentId); 145 146 final int lastDot = documentId.lastIndexOf('.'); 147 assert(lastDot > 0); 148 final String extension = documentId.substring(lastDot + 1).toLowerCase(); 149 final String mimeType = MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension); 150 151 row.add(Document.COLUMN_MIME_TYPE, mimeType); 152 row.add(Document.COLUMN_SIZE, fd.getLength()); 153 } 154 finally { 155 IoUtils.closeQuietly(fd); 156 } 157 } 158} 159