Loading core/java/android/content/ContentProviderClient.java +4 −0 Original line number Diff line number Diff line Loading @@ -72,6 +72,7 @@ public class ContentProviderClient { throws RemoteException { ICancellationSignal remoteCancellationSignal = null; if (cancellationSignal != null) { cancellationSignal.throwIfCanceled(); remoteCancellationSignal = mContentProvider.createCancellationSignal(); cancellationSignal.setRemote(remoteCancellationSignal); } Loading Loading @@ -208,6 +209,7 @@ public class ContentProviderClient { throws RemoteException, FileNotFoundException { ICancellationSignal remoteSignal = null; if (signal != null) { signal.throwIfCanceled(); remoteSignal = mContentProvider.createCancellationSignal(); signal.setRemote(remoteSignal); } Loading Loading @@ -244,6 +246,7 @@ public class ContentProviderClient { throws RemoteException, FileNotFoundException { ICancellationSignal remoteSignal = null; if (signal != null) { signal.throwIfCanceled(); remoteSignal = mContentProvider.createCancellationSignal(); signal.setRemote(remoteSignal); } Loading @@ -269,6 +272,7 @@ public class ContentProviderClient { throws RemoteException, FileNotFoundException { ICancellationSignal remoteSignal = null; if (signal != null) { signal.throwIfCanceled(); remoteSignal = mContentProvider.createCancellationSignal(); signal.setRemote(remoteSignal); } Loading core/java/android/provider/DocumentsContract.java +68 −22 Original line number Diff line number Diff line Loading @@ -19,6 +19,7 @@ package android.provider; import static android.net.TrafficStats.KB_IN_BYTES; import static libcore.io.OsConstants.SEEK_SET; import android.content.ContentProviderClient; import android.content.ContentResolver; import android.content.Context; import android.content.Intent; Loading @@ -34,16 +35,18 @@ import android.os.Bundle; import android.os.CancellationSignal; import android.os.ParcelFileDescriptor; import android.os.ParcelFileDescriptor.OnCloseListener; import android.os.RemoteException; import android.util.Log; import com.google.android.collect.Lists; import libcore.io.ErrnoException; import libcore.io.IoBridge; import libcore.io.IoUtils; import libcore.io.Libcore; import java.io.BufferedInputStream; import java.io.FileDescriptor; import java.io.FileInputStream; import java.io.IOException; import java.util.List; Loading Loading @@ -76,6 +79,11 @@ public final class DocumentsContract { /** {@hide} */ public static final String ACTION_MANAGE_DOCUMENT = "android.provider.action.MANAGE_DOCUMENT"; /** * Buffer is large enough to rewind past any EXIF headers. */ private static final int THUMBNAIL_BUFFER_SIZE = (int) (128 * KB_IN_BYTES); /** * Constants related to a document, including {@link Cursor} columns names * and flags. Loading Loading @@ -642,35 +650,47 @@ public final class DocumentsContract { */ public static Bitmap getDocumentThumbnail( ContentResolver resolver, Uri documentUri, Point size, CancellationSignal signal) { final ContentProviderClient client = resolver.acquireUnstableContentProviderClient( documentUri.getAuthority()); try { return getDocumentThumbnail(client, documentUri, size, signal); } catch (RemoteException e) { return null; } finally { ContentProviderClient.closeQuietly(client); } } /** {@hide} */ public static Bitmap getDocumentThumbnail( ContentProviderClient client, Uri documentUri, Point size, CancellationSignal signal) throws RemoteException { final Bundle openOpts = new Bundle(); openOpts.putParcelable(DocumentsContract.EXTRA_THUMBNAIL_SIZE, size); AssetFileDescriptor afd = null; try { afd = resolver.openTypedAssetFileDescriptor(documentUri, "image/*", openOpts, signal); afd = client.openTypedAssetFileDescriptor(documentUri, "image/*", openOpts, signal); final FileDescriptor fd = afd.getFileDescriptor(); final long offset = afd.getStartOffset(); final long length = afd.getDeclaredLength(); // Some thumbnails might be a region inside a larger file, such as // an EXIF thumbnail. Since BitmapFactory aggressively seeks around // the entire file, we read the region manually. byte[] region = null; if (offset > 0 && length <= 64 * KB_IN_BYTES) { region = new byte[(int) length]; // Try seeking on the returned FD, since it gives us the most // optimal decode path; otherwise fall back to buffering. BufferedInputStream is = null; try { Libcore.os.lseek(fd, offset, SEEK_SET); if (IoBridge.read(fd, region, 0, region.length) != region.length) { region = null; } } catch (ErrnoException e) { is = new BufferedInputStream(new FileInputStream(fd), THUMBNAIL_BUFFER_SIZE); is.mark(THUMBNAIL_BUFFER_SIZE); } // We requested a rough thumbnail size, but the remote size may have // returned something giant, so defensively scale down as needed. final BitmapFactory.Options opts = new BitmapFactory.Options(); opts.inJustDecodeBounds = true; if (region != null) { BitmapFactory.decodeByteArray(region, 0, region.length, opts); if (is != null) { BitmapFactory.decodeStream(is, null, opts); } else { BitmapFactory.decodeFileDescriptor(fd, null, opts); } Loading @@ -681,14 +701,17 @@ public final class DocumentsContract { opts.inJustDecodeBounds = false; opts.inSampleSize = Math.min(widthSample, heightSample); Log.d(TAG, "Decoding with sample size " + opts.inSampleSize); if (region != null) { return BitmapFactory.decodeByteArray(region, 0, region.length, opts); if (is != null) { is.reset(); return BitmapFactory.decodeStream(is, null, opts); } else { try { Libcore.os.lseek(fd, offset, SEEK_SET); } catch (ErrnoException e) { e.rethrowAsIOException(); } return BitmapFactory.decodeFileDescriptor(fd, null, opts); } } catch (ErrnoException e) { Log.w(TAG, "Failed to load thumbnail for " + documentUri + ": " + e); return null; } catch (IOException e) { Log.w(TAG, "Failed to load thumbnail for " + documentUri + ": " + e); return null; Loading @@ -709,13 +732,25 @@ public final class DocumentsContract { */ public static Uri createDocument(ContentResolver resolver, Uri parentDocumentUri, String mimeType, String displayName) { final ContentProviderClient client = resolver.acquireUnstableContentProviderClient( parentDocumentUri.getAuthority()); try { return createDocument(client, parentDocumentUri, mimeType, displayName); } finally { ContentProviderClient.closeQuietly(client); } } /** {@hide} */ public static Uri createDocument(ContentProviderClient client, Uri parentDocumentUri, String mimeType, String displayName) { final Bundle in = new Bundle(); in.putString(Document.COLUMN_DOCUMENT_ID, getDocumentId(parentDocumentUri)); in.putString(Document.COLUMN_MIME_TYPE, mimeType); in.putString(Document.COLUMN_DISPLAY_NAME, displayName); try { final Bundle out = resolver.call(parentDocumentUri, METHOD_CREATE_DOCUMENT, null, in); final Bundle out = client.call(METHOD_CREATE_DOCUMENT, null, in); return buildDocumentUri( parentDocumentUri.getAuthority(), out.getString(Document.COLUMN_DOCUMENT_ID)); } catch (Exception e) { Loading @@ -730,11 +765,22 @@ public final class DocumentsContract { * @param documentUri document with {@link Document#FLAG_SUPPORTS_DELETE} */ public static boolean deleteDocument(ContentResolver resolver, Uri documentUri) { final ContentProviderClient client = resolver.acquireUnstableContentProviderClient( documentUri.getAuthority()); try { return deleteDocument(client, documentUri); } finally { ContentProviderClient.closeQuietly(client); } } /** {@hide} */ public static boolean deleteDocument(ContentProviderClient client, Uri documentUri) { final Bundle in = new Bundle(); in.putString(Document.COLUMN_DOCUMENT_ID, getDocumentId(documentUri)); try { final Bundle out = resolver.call(documentUri, METHOD_DELETE_DOCUMENT, null, in); final Bundle out = client.call(METHOD_DELETE_DOCUMENT, null, in); return true; } catch (Exception e) { Log.w(TAG, "Failed to delete document", e); Loading packages/ExternalStorageProvider/src/com/android/externalstorage/TestDocumentsProvider.java +66 −14 Original line number Diff line number Diff line Loading @@ -17,10 +17,18 @@ package com.android.externalstorage; import android.content.ContentResolver; import android.content.res.AssetFileDescriptor; import android.database.Cursor; import android.database.MatrixCursor; import android.database.MatrixCursor.RowBuilder; import android.graphics.Bitmap; import android.graphics.Bitmap.CompressFormat; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.Point; import android.net.Uri; import android.os.AsyncTask; import android.os.Bundle; import android.os.CancellationSignal; import android.os.ParcelFileDescriptor; Loading @@ -31,7 +39,14 @@ import android.provider.DocumentsContract.Root; import android.provider.DocumentsProvider; import android.util.Log; import libcore.io.IoUtils; import libcore.io.Streams; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.lang.ref.WeakReference; public class TestDocumentsProvider extends DocumentsProvider { Loading Loading @@ -85,7 +100,7 @@ public class TestDocumentsProvider extends DocumentsProvider { if (CRASH_DOCUMENT) System.exit(12); final MatrixCursor result = new MatrixCursor(resolveDocumentProjection(projection)); includeFile(result, documentId); includeFile(result, documentId, 0); return result; } Loading Loading @@ -122,12 +137,12 @@ public class TestDocumentsProvider extends DocumentsProvider { public boolean includeIfFinished(MatrixCursor result) { Log.d(TAG, hashCode() + ": includeIfFinished() found " + mFinished); if (mFinished) { includeFile(result, "_networkfile1"); includeFile(result, "_networkfile2"); includeFile(result, "_networkfile3"); includeFile(result, "_networkfile4"); includeFile(result, "_networkfile5"); includeFile(result, "_networkfile6"); includeFile(result, "_networkfile1", 0); includeFile(result, "_networkfile2", 0); includeFile(result, "_networkfile3", 0); includeFile(result, "_networkfile4", 0); includeFile(result, "_networkfile5", 0); includeFile(result, "_networkfile6", 0); return true; } else { return false; Loading Loading @@ -162,11 +177,11 @@ public class TestDocumentsProvider extends DocumentsProvider { result.setNotificationUri(resolver, notifyUri); // Always include local results includeFile(result, MY_DOC_NULL); includeFile(result, "localfile1"); includeFile(result, "localfile2"); includeFile(result, "localfile3"); includeFile(result, "localfile4"); includeFile(result, MY_DOC_NULL, 0); includeFile(result, "localfile1", 0); includeFile(result, "localfile2", Document.FLAG_SUPPORTS_THUMBNAIL); includeFile(result, "localfile3", 0); includeFile(result, "localfile4", 0); synchronized (this) { // Try picking up an existing network fetch Loading Loading @@ -217,7 +232,8 @@ public class TestDocumentsProvider extends DocumentsProvider { SystemClock.sleep(3000); final MatrixCursor result = new MatrixCursor(resolveDocumentProjection(projection)); includeFile(result, "It was /worth/ the_wait for?the file:with the&incredibly long name"); includeFile( result, "It was /worth/ the_wait for?the file:with the&incredibly long name", 0); return result; } Loading @@ -227,16 +243,52 @@ public class TestDocumentsProvider extends DocumentsProvider { throw new FileNotFoundException(); } @Override public AssetFileDescriptor openDocumentThumbnail( String docId, Point sizeHint, CancellationSignal signal) throws FileNotFoundException { final Bitmap bitmap = Bitmap.createBitmap(32, 32, Bitmap.Config.ARGB_8888); final Canvas canvas = new Canvas(bitmap); final Paint paint = new Paint(); paint.setColor(Color.BLUE); canvas.drawColor(Color.RED); canvas.drawLine(0, 0, 32, 32, paint); final ByteArrayOutputStream bos = new ByteArrayOutputStream(); bitmap.compress(CompressFormat.JPEG, 50, bos); final ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray()); try { final ParcelFileDescriptor[] fds = ParcelFileDescriptor.createReliablePipe(); new AsyncTask<Object, Object, Object>() { @Override protected Object doInBackground(Object... params) { final FileOutputStream fos = new FileOutputStream(fds[1].getFileDescriptor()); try { Streams.copy(bis, fos); } catch (IOException e) { throw new RuntimeException(e); } IoUtils.closeQuietly(fds[1]); return null; } }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); return new AssetFileDescriptor(fds[0], 0, AssetFileDescriptor.UNKNOWN_LENGTH); } catch (IOException e) { throw new FileNotFoundException(e.getMessage()); } } @Override public boolean onCreate() { return true; } private static void includeFile(MatrixCursor result, String docId) { private static void includeFile(MatrixCursor result, String docId, int flags) { final RowBuilder row = result.newRow(); row.add(Document.COLUMN_DOCUMENT_ID, docId); row.add(Document.COLUMN_DISPLAY_NAME, docId); row.add(Document.COLUMN_LAST_MODIFIED, System.currentTimeMillis()); row.add(Document.COLUMN_FLAGS, flags); if (MY_DOC_ID.equals(docId)) { row.add(Document.COLUMN_MIME_TYPE, Document.MIME_TYPE_DIR); Loading Loading
core/java/android/content/ContentProviderClient.java +4 −0 Original line number Diff line number Diff line Loading @@ -72,6 +72,7 @@ public class ContentProviderClient { throws RemoteException { ICancellationSignal remoteCancellationSignal = null; if (cancellationSignal != null) { cancellationSignal.throwIfCanceled(); remoteCancellationSignal = mContentProvider.createCancellationSignal(); cancellationSignal.setRemote(remoteCancellationSignal); } Loading Loading @@ -208,6 +209,7 @@ public class ContentProviderClient { throws RemoteException, FileNotFoundException { ICancellationSignal remoteSignal = null; if (signal != null) { signal.throwIfCanceled(); remoteSignal = mContentProvider.createCancellationSignal(); signal.setRemote(remoteSignal); } Loading Loading @@ -244,6 +246,7 @@ public class ContentProviderClient { throws RemoteException, FileNotFoundException { ICancellationSignal remoteSignal = null; if (signal != null) { signal.throwIfCanceled(); remoteSignal = mContentProvider.createCancellationSignal(); signal.setRemote(remoteSignal); } Loading @@ -269,6 +272,7 @@ public class ContentProviderClient { throws RemoteException, FileNotFoundException { ICancellationSignal remoteSignal = null; if (signal != null) { signal.throwIfCanceled(); remoteSignal = mContentProvider.createCancellationSignal(); signal.setRemote(remoteSignal); } Loading
core/java/android/provider/DocumentsContract.java +68 −22 Original line number Diff line number Diff line Loading @@ -19,6 +19,7 @@ package android.provider; import static android.net.TrafficStats.KB_IN_BYTES; import static libcore.io.OsConstants.SEEK_SET; import android.content.ContentProviderClient; import android.content.ContentResolver; import android.content.Context; import android.content.Intent; Loading @@ -34,16 +35,18 @@ import android.os.Bundle; import android.os.CancellationSignal; import android.os.ParcelFileDescriptor; import android.os.ParcelFileDescriptor.OnCloseListener; import android.os.RemoteException; import android.util.Log; import com.google.android.collect.Lists; import libcore.io.ErrnoException; import libcore.io.IoBridge; import libcore.io.IoUtils; import libcore.io.Libcore; import java.io.BufferedInputStream; import java.io.FileDescriptor; import java.io.FileInputStream; import java.io.IOException; import java.util.List; Loading Loading @@ -76,6 +79,11 @@ public final class DocumentsContract { /** {@hide} */ public static final String ACTION_MANAGE_DOCUMENT = "android.provider.action.MANAGE_DOCUMENT"; /** * Buffer is large enough to rewind past any EXIF headers. */ private static final int THUMBNAIL_BUFFER_SIZE = (int) (128 * KB_IN_BYTES); /** * Constants related to a document, including {@link Cursor} columns names * and flags. Loading Loading @@ -642,35 +650,47 @@ public final class DocumentsContract { */ public static Bitmap getDocumentThumbnail( ContentResolver resolver, Uri documentUri, Point size, CancellationSignal signal) { final ContentProviderClient client = resolver.acquireUnstableContentProviderClient( documentUri.getAuthority()); try { return getDocumentThumbnail(client, documentUri, size, signal); } catch (RemoteException e) { return null; } finally { ContentProviderClient.closeQuietly(client); } } /** {@hide} */ public static Bitmap getDocumentThumbnail( ContentProviderClient client, Uri documentUri, Point size, CancellationSignal signal) throws RemoteException { final Bundle openOpts = new Bundle(); openOpts.putParcelable(DocumentsContract.EXTRA_THUMBNAIL_SIZE, size); AssetFileDescriptor afd = null; try { afd = resolver.openTypedAssetFileDescriptor(documentUri, "image/*", openOpts, signal); afd = client.openTypedAssetFileDescriptor(documentUri, "image/*", openOpts, signal); final FileDescriptor fd = afd.getFileDescriptor(); final long offset = afd.getStartOffset(); final long length = afd.getDeclaredLength(); // Some thumbnails might be a region inside a larger file, such as // an EXIF thumbnail. Since BitmapFactory aggressively seeks around // the entire file, we read the region manually. byte[] region = null; if (offset > 0 && length <= 64 * KB_IN_BYTES) { region = new byte[(int) length]; // Try seeking on the returned FD, since it gives us the most // optimal decode path; otherwise fall back to buffering. BufferedInputStream is = null; try { Libcore.os.lseek(fd, offset, SEEK_SET); if (IoBridge.read(fd, region, 0, region.length) != region.length) { region = null; } } catch (ErrnoException e) { is = new BufferedInputStream(new FileInputStream(fd), THUMBNAIL_BUFFER_SIZE); is.mark(THUMBNAIL_BUFFER_SIZE); } // We requested a rough thumbnail size, but the remote size may have // returned something giant, so defensively scale down as needed. final BitmapFactory.Options opts = new BitmapFactory.Options(); opts.inJustDecodeBounds = true; if (region != null) { BitmapFactory.decodeByteArray(region, 0, region.length, opts); if (is != null) { BitmapFactory.decodeStream(is, null, opts); } else { BitmapFactory.decodeFileDescriptor(fd, null, opts); } Loading @@ -681,14 +701,17 @@ public final class DocumentsContract { opts.inJustDecodeBounds = false; opts.inSampleSize = Math.min(widthSample, heightSample); Log.d(TAG, "Decoding with sample size " + opts.inSampleSize); if (region != null) { return BitmapFactory.decodeByteArray(region, 0, region.length, opts); if (is != null) { is.reset(); return BitmapFactory.decodeStream(is, null, opts); } else { try { Libcore.os.lseek(fd, offset, SEEK_SET); } catch (ErrnoException e) { e.rethrowAsIOException(); } return BitmapFactory.decodeFileDescriptor(fd, null, opts); } } catch (ErrnoException e) { Log.w(TAG, "Failed to load thumbnail for " + documentUri + ": " + e); return null; } catch (IOException e) { Log.w(TAG, "Failed to load thumbnail for " + documentUri + ": " + e); return null; Loading @@ -709,13 +732,25 @@ public final class DocumentsContract { */ public static Uri createDocument(ContentResolver resolver, Uri parentDocumentUri, String mimeType, String displayName) { final ContentProviderClient client = resolver.acquireUnstableContentProviderClient( parentDocumentUri.getAuthority()); try { return createDocument(client, parentDocumentUri, mimeType, displayName); } finally { ContentProviderClient.closeQuietly(client); } } /** {@hide} */ public static Uri createDocument(ContentProviderClient client, Uri parentDocumentUri, String mimeType, String displayName) { final Bundle in = new Bundle(); in.putString(Document.COLUMN_DOCUMENT_ID, getDocumentId(parentDocumentUri)); in.putString(Document.COLUMN_MIME_TYPE, mimeType); in.putString(Document.COLUMN_DISPLAY_NAME, displayName); try { final Bundle out = resolver.call(parentDocumentUri, METHOD_CREATE_DOCUMENT, null, in); final Bundle out = client.call(METHOD_CREATE_DOCUMENT, null, in); return buildDocumentUri( parentDocumentUri.getAuthority(), out.getString(Document.COLUMN_DOCUMENT_ID)); } catch (Exception e) { Loading @@ -730,11 +765,22 @@ public final class DocumentsContract { * @param documentUri document with {@link Document#FLAG_SUPPORTS_DELETE} */ public static boolean deleteDocument(ContentResolver resolver, Uri documentUri) { final ContentProviderClient client = resolver.acquireUnstableContentProviderClient( documentUri.getAuthority()); try { return deleteDocument(client, documentUri); } finally { ContentProviderClient.closeQuietly(client); } } /** {@hide} */ public static boolean deleteDocument(ContentProviderClient client, Uri documentUri) { final Bundle in = new Bundle(); in.putString(Document.COLUMN_DOCUMENT_ID, getDocumentId(documentUri)); try { final Bundle out = resolver.call(documentUri, METHOD_DELETE_DOCUMENT, null, in); final Bundle out = client.call(METHOD_DELETE_DOCUMENT, null, in); return true; } catch (Exception e) { Log.w(TAG, "Failed to delete document", e); Loading
packages/ExternalStorageProvider/src/com/android/externalstorage/TestDocumentsProvider.java +66 −14 Original line number Diff line number Diff line Loading @@ -17,10 +17,18 @@ package com.android.externalstorage; import android.content.ContentResolver; import android.content.res.AssetFileDescriptor; import android.database.Cursor; import android.database.MatrixCursor; import android.database.MatrixCursor.RowBuilder; import android.graphics.Bitmap; import android.graphics.Bitmap.CompressFormat; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.Point; import android.net.Uri; import android.os.AsyncTask; import android.os.Bundle; import android.os.CancellationSignal; import android.os.ParcelFileDescriptor; Loading @@ -31,7 +39,14 @@ import android.provider.DocumentsContract.Root; import android.provider.DocumentsProvider; import android.util.Log; import libcore.io.IoUtils; import libcore.io.Streams; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.lang.ref.WeakReference; public class TestDocumentsProvider extends DocumentsProvider { Loading Loading @@ -85,7 +100,7 @@ public class TestDocumentsProvider extends DocumentsProvider { if (CRASH_DOCUMENT) System.exit(12); final MatrixCursor result = new MatrixCursor(resolveDocumentProjection(projection)); includeFile(result, documentId); includeFile(result, documentId, 0); return result; } Loading Loading @@ -122,12 +137,12 @@ public class TestDocumentsProvider extends DocumentsProvider { public boolean includeIfFinished(MatrixCursor result) { Log.d(TAG, hashCode() + ": includeIfFinished() found " + mFinished); if (mFinished) { includeFile(result, "_networkfile1"); includeFile(result, "_networkfile2"); includeFile(result, "_networkfile3"); includeFile(result, "_networkfile4"); includeFile(result, "_networkfile5"); includeFile(result, "_networkfile6"); includeFile(result, "_networkfile1", 0); includeFile(result, "_networkfile2", 0); includeFile(result, "_networkfile3", 0); includeFile(result, "_networkfile4", 0); includeFile(result, "_networkfile5", 0); includeFile(result, "_networkfile6", 0); return true; } else { return false; Loading Loading @@ -162,11 +177,11 @@ public class TestDocumentsProvider extends DocumentsProvider { result.setNotificationUri(resolver, notifyUri); // Always include local results includeFile(result, MY_DOC_NULL); includeFile(result, "localfile1"); includeFile(result, "localfile2"); includeFile(result, "localfile3"); includeFile(result, "localfile4"); includeFile(result, MY_DOC_NULL, 0); includeFile(result, "localfile1", 0); includeFile(result, "localfile2", Document.FLAG_SUPPORTS_THUMBNAIL); includeFile(result, "localfile3", 0); includeFile(result, "localfile4", 0); synchronized (this) { // Try picking up an existing network fetch Loading Loading @@ -217,7 +232,8 @@ public class TestDocumentsProvider extends DocumentsProvider { SystemClock.sleep(3000); final MatrixCursor result = new MatrixCursor(resolveDocumentProjection(projection)); includeFile(result, "It was /worth/ the_wait for?the file:with the&incredibly long name"); includeFile( result, "It was /worth/ the_wait for?the file:with the&incredibly long name", 0); return result; } Loading @@ -227,16 +243,52 @@ public class TestDocumentsProvider extends DocumentsProvider { throw new FileNotFoundException(); } @Override public AssetFileDescriptor openDocumentThumbnail( String docId, Point sizeHint, CancellationSignal signal) throws FileNotFoundException { final Bitmap bitmap = Bitmap.createBitmap(32, 32, Bitmap.Config.ARGB_8888); final Canvas canvas = new Canvas(bitmap); final Paint paint = new Paint(); paint.setColor(Color.BLUE); canvas.drawColor(Color.RED); canvas.drawLine(0, 0, 32, 32, paint); final ByteArrayOutputStream bos = new ByteArrayOutputStream(); bitmap.compress(CompressFormat.JPEG, 50, bos); final ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray()); try { final ParcelFileDescriptor[] fds = ParcelFileDescriptor.createReliablePipe(); new AsyncTask<Object, Object, Object>() { @Override protected Object doInBackground(Object... params) { final FileOutputStream fos = new FileOutputStream(fds[1].getFileDescriptor()); try { Streams.copy(bis, fos); } catch (IOException e) { throw new RuntimeException(e); } IoUtils.closeQuietly(fds[1]); return null; } }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); return new AssetFileDescriptor(fds[0], 0, AssetFileDescriptor.UNKNOWN_LENGTH); } catch (IOException e) { throw new FileNotFoundException(e.getMessage()); } } @Override public boolean onCreate() { return true; } private static void includeFile(MatrixCursor result, String docId) { private static void includeFile(MatrixCursor result, String docId, int flags) { final RowBuilder row = result.newRow(); row.add(Document.COLUMN_DOCUMENT_ID, docId); row.add(Document.COLUMN_DISPLAY_NAME, docId); row.add(Document.COLUMN_LAST_MODIFIED, System.currentTimeMillis()); row.add(Document.COLUMN_FLAGS, flags); if (MY_DOC_ID.equals(docId)) { row.add(Document.COLUMN_MIME_TYPE, Document.MIME_TYPE_DIR); Loading