diff options
9 files changed, 306 insertions, 69 deletions
diff --git a/api/current.txt b/api/current.txt index 5a3c7db..2a81469 100644 --- a/api/current.txt +++ b/api/current.txt @@ -8051,6 +8051,7 @@ package android.database { public class MatrixCursor.RowBuilder { method public android.database.MatrixCursor.RowBuilder add(java.lang.Object); + method public android.database.MatrixCursor.RowBuilder offer(java.lang.String, java.lang.Object); } public class MergeCursor extends android.database.AbstractCursor { diff --git a/core/java/android/database/MatrixCursor.java b/core/java/android/database/MatrixCursor.java index 6e68b6b..2a0d9b9 100644 --- a/core/java/android/database/MatrixCursor.java +++ b/core/java/android/database/MatrixCursor.java @@ -83,11 +83,10 @@ public class MatrixCursor extends AbstractCursor { * row */ public RowBuilder newRow() { - rowCount++; - int endIndex = rowCount * columnCount; + final int row = rowCount++; + final int endIndex = rowCount * columnCount; ensureCapacity(endIndex); - int start = endIndex - columnCount; - return new RowBuilder(start, endIndex); + return new RowBuilder(row); } /** @@ -180,18 +179,29 @@ public class MatrixCursor extends AbstractCursor { } /** - * Builds a row, starting from the left-most column and adding one column - * value at a time. Follows the same ordering as the column names specified - * at cursor construction time. + * Builds a row of values using either of these approaches: + * <ul> + * <li>Values can be added with explicit column ordering using + * {@link #add(Object)}, which starts from the left-most column and adds one + * column value at a time. This follows the same ordering as the column + * names specified at cursor construction time. + * <li>Column and value pairs can be offered for possible inclusion using + * {@link #offer(String, Object)}. If the cursor includes the given column, + * the value will be set for that column, otherwise the value is ignored. + * This approach is useful when matching data to a custom projection. + * </ul> + * Undefined values are left as {@code null}. */ public class RowBuilder { + private final int row; + private final int endIndex; private int index; - private final int endIndex; - RowBuilder(int index, int endIndex) { - this.index = index; - this.endIndex = endIndex; + RowBuilder(int row) { + this.row = row; + this.index = row * columnCount; + this.endIndex = index + columnCount; } /** @@ -210,6 +220,21 @@ public class MatrixCursor extends AbstractCursor { data[index++] = columnValue; return this; } + + /** + * Offer value for possible inclusion if this cursor defines the given + * column. Columns not defined by the cursor are silently ignored. + * + * @return this builder to support chaining + */ + public RowBuilder offer(String columnName, Object value) { + for (int i = 0; i < columnNames.length; i++) { + if (columnName.equals(columnNames[i])) { + data[(row * columnCount) + i] = value; + } + } + return this; + } } // AbstractCursor implementation. diff --git a/core/java/android/provider/DocumentsContract.java b/core/java/android/provider/DocumentsContract.java index e1810ca..91d349a 100644 --- a/core/java/android/provider/DocumentsContract.java +++ b/core/java/android/provider/DocumentsContract.java @@ -36,6 +36,7 @@ import com.google.android.collect.Lists; import libcore.io.IoUtils; +import java.io.FileDescriptor; import java.io.IOException; import java.io.InputStream; import java.util.List; @@ -461,16 +462,27 @@ public final class DocumentsContract { final Bundle opts = new Bundle(); opts.putParcelable(EXTRA_THUMBNAIL_SIZE, size); - InputStream is = null; + AssetFileDescriptor afd = null; try { - is = new AssetFileDescriptor.AutoCloseInputStream( - resolver.openTypedAssetFileDescriptor(documentUri, "image/*", opts)); - return BitmapFactory.decodeStream(is); + afd = resolver.openTypedAssetFileDescriptor(documentUri, "image/*", opts); + + final FileDescriptor fd = afd.getFileDescriptor(); + final BitmapFactory.Options bitmapOpts = new BitmapFactory.Options(); + + bitmapOpts.inJustDecodeBounds = true; + BitmapFactory.decodeFileDescriptor(fd, null, bitmapOpts); + + final int widthSample = bitmapOpts.outWidth / size.x; + final int heightSample = bitmapOpts.outHeight / size.y; + + bitmapOpts.inJustDecodeBounds = false; + bitmapOpts.inSampleSize = Math.min(widthSample, heightSample); + return BitmapFactory.decodeFileDescriptor(fd, null, bitmapOpts); } catch (IOException e) { Log.w(TAG, "Failed to load thumbnail for " + documentUri + ": " + e); return null; } finally { - IoUtils.closeQuietly(is); + IoUtils.closeQuietly(afd); } } diff --git a/core/java/android/provider/MediaStore.java b/core/java/android/provider/MediaStore.java index cb6300f..ad6839b 100644 --- a/core/java/android/provider/MediaStore.java +++ b/core/java/android/provider/MediaStore.java @@ -19,8 +19,8 @@ package android.provider; import android.annotation.SdkConstant; import android.annotation.SdkConstant.SdkConstantType; import android.content.ContentResolver; -import android.content.ContentValues; import android.content.ContentUris; +import android.content.ContentValues; import android.content.Context; import android.database.Cursor; import android.database.DatabaseUtils; @@ -532,7 +532,8 @@ public final class MediaStore { private static final Object sThumbBufLock = new Object(); private static byte[] sThumbBuf; - private static Bitmap getMiniThumbFromFile(Cursor c, Uri baseUri, ContentResolver cr, BitmapFactory.Options options) { + private static Bitmap getMiniThumbFromFile( + Cursor c, Uri baseUri, ContentResolver cr, BitmapFactory.Options options) { Bitmap bitmap = null; Uri thumbUri = null; try { @@ -577,6 +578,7 @@ public final class MediaStore { if (c != null) c.close(); } } + /** * This method ensure thumbnails associated with origId are generated and decode the byte * stream from database (MICRO_KIND) or file (MINI_KIND). diff --git a/core/tests/coretests/src/android/database/MatrixCursorTest.java b/core/tests/coretests/src/android/database/MatrixCursorTest.java index cdab638..fc48c17 100644 --- a/core/tests/coretests/src/android/database/MatrixCursorTest.java +++ b/core/tests/coretests/src/android/database/MatrixCursorTest.java @@ -128,6 +128,56 @@ public class MatrixCursorTest extends TestCase { } catch (IllegalArgumentException e) { /* expected */ } } + public void testRowBuilderOffer() { + MatrixCursor cursor = newMatrixCursor(); + + cursor.newRow() + .offer("float", 4.2f) + .offer("string", "foobar") + .offer("blob", new byte[] {(byte) 0xaa, (byte) 0x55}) + .offer("lolwat", "kittens"); + + cursor.newRow(); + + cursor.newRow() + .offer("string", "zero") + .offer("string", "one") + .offer("string", "two") + .offer("lolwat", "kittens"); + + assertTrue(cursor.moveToFirst()); + assertEquals("foobar", cursor.getString(0)); + assertEquals(null, cursor.getString(1)); + assertEquals(0, cursor.getShort(1)); + assertEquals(0, cursor.getInt(2)); + assertEquals(0, cursor.getLong(3)); + assertEquals(4.2f, cursor.getFloat(4)); + assertEquals(0.0d, cursor.getDouble(5)); + MoreAsserts.assertEquals(new byte[] {(byte) 0xaa, (byte) 0x55}, cursor.getBlob(6)); + + assertTrue(cursor.moveToNext()); + assertEquals(null, cursor.getString(0)); + assertEquals(0, cursor.getShort(1)); + assertEquals(0, cursor.getInt(2)); + assertEquals(0, cursor.getLong(3)); + assertEquals(0.0f, cursor.getFloat(4)); + assertEquals(0.0d, cursor.getDouble(5)); + assertEquals(null, cursor.getBlob(6)); + + assertTrue(cursor.moveToNext()); + assertEquals("two", cursor.getString(0)); + assertEquals(0, cursor.getShort(1)); + assertEquals(0, cursor.getInt(2)); + assertEquals(0, cursor.getLong(3)); + assertEquals(0.0f, cursor.getFloat(4)); + assertEquals(0.0d, cursor.getDouble(5)); + assertEquals(null, cursor.getBlob(6)); + + assertTrue(cursor.isLast()); + assertFalse(cursor.moveToNext()); + assertTrue(cursor.isAfterLast()); + } + static class NonIterableArrayList<T> extends ArrayList<T> { NonIterableArrayList() {} diff --git a/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java b/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java index ac5629e..fbdb3a7 100644 --- a/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java +++ b/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java @@ -16,17 +16,24 @@ package com.android.documentsui; +import static com.android.documentsui.DocumentsActivity.TAG; + import android.app.Fragment; import android.app.FragmentManager; import android.app.FragmentTransaction; import android.app.LoaderManager.LoaderCallbacks; import android.content.Context; import android.content.Loader; +import android.graphics.Bitmap; +import android.graphics.Point; import android.net.Uri; +import android.os.AsyncTask; import android.os.Bundle; import android.provider.DocumentsContract; import android.text.format.DateUtils; import android.text.format.Formatter; +import android.text.format.Time; +import android.util.Log; import android.util.SparseBooleanArray; import android.view.ActionMode; import android.view.LayoutInflater; @@ -75,6 +82,8 @@ public class DirectoryFragment extends Fragment { private int mType = TYPE_NORMAL; + private Point mThumbSize; + private DocumentsAdapter mAdapter; private LoaderCallbacks<List<Document>> mCallbacks; @@ -217,7 +226,9 @@ public class DirectoryFragment extends Fragment { choiceMode = ListView.CHOICE_MODE_NONE; } + final int thumbSize; if (state.mode == DisplayState.MODE_GRID) { + thumbSize = getResources().getDimensionPixelSize(R.dimen.grid_width); mListView.setAdapter(null); mListView.setChoiceMode(ListView.CHOICE_MODE_NONE); mGridView.setAdapter(mAdapter); @@ -226,6 +237,7 @@ public class DirectoryFragment extends Fragment { mGridView.setChoiceMode(choiceMode); mCurrentView = mGridView; } else if (state.mode == DisplayState.MODE_LIST) { + thumbSize = getResources().getDimensionPixelSize(android.R.dimen.app_icon_size); mGridView.setAdapter(null); mGridView.setChoiceMode(ListView.CHOICE_MODE_NONE); mListView.setAdapter(mAdapter); @@ -234,6 +246,8 @@ public class DirectoryFragment extends Fragment { } else { throw new IllegalStateException(); } + + mThumbSize = new Point(thumbSize, thumbSize); } private OnItemClickListener mItemListener = new OnItemClickListener() { @@ -349,9 +363,21 @@ public class DirectoryFragment extends Fragment { final TextView date = (TextView) convertView.findViewById(R.id.date); final TextView size = (TextView) convertView.findViewById(R.id.size); + final ThumbnailAsyncTask oldTask = (ThumbnailAsyncTask) icon.getTag(); + if (oldTask != null) { + oldTask.cancel(false); + } + if (doc.isThumbnailSupported()) { - // TODO: load thumbnails async - icon.setImageURI(doc.uri); + final Bitmap cachedResult = ThumbnailCache.get(context).get(doc.uri); + if (cachedResult != null) { + icon.setImageBitmap(cachedResult); + } else { + final ThumbnailAsyncTask task = new ThumbnailAsyncTask(icon, mThumbSize); + icon.setImageBitmap(null); + icon.setTag(task); + task.execute(doc.uri); + } } else { icon.setImageDrawable(RootsCache.resolveDocumentIcon( context, doc.uri.getAuthority(), doc.mimeType)); @@ -380,10 +406,11 @@ public class DirectoryFragment extends Fragment { (summary.getVisibility() == View.VISIBLE) ? View.VISIBLE : View.GONE); } - // TODO: omit year from format - date.setText(DateUtils.formatSameDayTime( - doc.lastModified, System.currentTimeMillis(), DateFormat.SHORT, - DateFormat.SHORT)); + if (doc.lastModified == -1) { + date.setText(null); + } else { + date.setText(formatTime(context, doc.lastModified)); + } if (state.showSize) { size.setVisibility(View.VISIBLE); @@ -414,4 +441,66 @@ public class DirectoryFragment extends Fragment { return getItem(position).uri.hashCode(); } } + + private static class ThumbnailAsyncTask extends AsyncTask<Uri, Void, Bitmap> { + private final ImageView mTarget; + private final Point mSize; + + public ThumbnailAsyncTask(ImageView target, Point size) { + mTarget = target; + mSize = size; + } + + @Override + protected void onPreExecute() { + mTarget.setTag(this); + } + + @Override + protected Bitmap doInBackground(Uri... params) { + final Context context = mTarget.getContext(); + final Uri uri = params[0]; + + Bitmap result = null; + try { + result = DocumentsContract.getThumbnail( + context.getContentResolver(), uri, mSize); + if (result != null) { + ThumbnailCache.get(context).put(uri, result); + } + } catch (Exception e) { + Log.w(TAG, "Failed to load thumbnail: " + e); + } + return result; + } + + @Override + protected void onPostExecute(Bitmap result) { + if (mTarget.getTag() == this) { + mTarget.setImageBitmap(result); + mTarget.setTag(null); + } + } + } + + private static String formatTime(Context context, long when) { + // TODO: DateUtils should make this easier + Time then = new Time(); + then.set(when); + Time now = new Time(); + now.setToNow(); + + int flags = DateUtils.FORMAT_NO_NOON | DateUtils.FORMAT_NO_MIDNIGHT + | DateUtils.FORMAT_ABBREV_ALL; + + if (then.year != now.year) { + flags |= DateUtils.FORMAT_SHOW_YEAR | DateUtils.FORMAT_SHOW_DATE; + } else if (then.yearDay != now.yearDay) { + flags |= DateUtils.FORMAT_SHOW_DATE; + } else { + flags |= DateUtils.FORMAT_SHOW_TIME; + } + + return DateUtils.formatDateTime(context, when, flags); + } } diff --git a/packages/DocumentsUI/src/com/android/documentsui/ThumbnailCache.java b/packages/DocumentsUI/src/com/android/documentsui/ThumbnailCache.java new file mode 100644 index 0000000..bc7abeb --- /dev/null +++ b/packages/DocumentsUI/src/com/android/documentsui/ThumbnailCache.java @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2013 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.documentsui; + +import android.app.ActivityManager; +import android.content.Context; +import android.graphics.Bitmap; +import android.net.Uri; +import android.util.LruCache; + +public class ThumbnailCache extends LruCache<Uri, Bitmap> { + private static ThumbnailCache sCache; + + public static ThumbnailCache get(Context context) { + if (sCache == null) { + final ActivityManager am = (ActivityManager) context.getSystemService( + Context.ACTIVITY_SERVICE); + final int memoryClassBytes = am.getMemoryClass() * 1024 * 1024; + sCache = new ThumbnailCache(memoryClassBytes / 4); + } + return sCache; + } + + public ThumbnailCache(int maxSizeBytes) { + super(maxSizeBytes); + } + + @Override + protected int sizeOf(Uri key, Bitmap value) { + return value.getByteCount(); + } +} diff --git a/packages/ExternalStorageProvider/AndroidManifest.xml b/packages/ExternalStorageProvider/AndroidManifest.xml index afdb6bb..5272166 100644 --- a/packages/ExternalStorageProvider/AndroidManifest.xml +++ b/packages/ExternalStorageProvider/AndroidManifest.xml @@ -7,7 +7,7 @@ <application android:label="@string/app_label"> <provider android:name=".ExternalStorageProvider" - android:authorities="com.android.externalstorage" + android:authorities="com.android.externalstorage.documents" android:grantUriPermissions="true" android:exported="true" android:permission="android.permission.MANAGE_DOCUMENTS"> diff --git a/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java b/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java index 659139d..b4bf563 100644 --- a/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java +++ b/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java @@ -22,10 +22,10 @@ import android.content.ContentValues; import android.content.UriMatcher; import android.database.Cursor; import android.database.MatrixCursor; +import android.database.MatrixCursor.RowBuilder; import android.net.Uri; import android.os.Environment; import android.os.ParcelFileDescriptor; -import android.provider.BaseColumns; import android.provider.DocumentsContract; import android.provider.DocumentsContract.DocumentColumns; import android.provider.DocumentsContract.Documents; @@ -45,7 +45,7 @@ import java.util.LinkedList; public class ExternalStorageProvider extends ContentProvider { private static final String TAG = "ExternalStorage"; - private static final String AUTHORITY = "com.android.externalstorage"; + private static final String AUTHORITY = "com.android.externalstorage.documents"; // TODO: support multiple storage devices @@ -57,6 +57,14 @@ public class ExternalStorageProvider extends ContentProvider { private static final int URI_DOCS_ID_CONTENTS = 4; private static final int URI_DOCS_ID_SEARCH = 5; + static { + sMatcher.addURI(AUTHORITY, "roots", URI_ROOTS); + sMatcher.addURI(AUTHORITY, "roots/*", URI_ROOTS_ID); + sMatcher.addURI(AUTHORITY, "roots/*/docs/*", URI_DOCS_ID); + sMatcher.addURI(AUTHORITY, "roots/*/docs/*/contents", URI_DOCS_ID_CONTENTS); + sMatcher.addURI(AUTHORITY, "roots/*/docs/*/search", URI_DOCS_ID_SEARCH); + } + private HashMap<String, Root> mRoots = Maps.newHashMap(); private static class Root { @@ -68,13 +76,15 @@ public class ExternalStorageProvider extends ContentProvider { public File path; } - static { - sMatcher.addURI(AUTHORITY, "roots", URI_ROOTS); - sMatcher.addURI(AUTHORITY, "roots/*", URI_ROOTS_ID); - sMatcher.addURI(AUTHORITY, "roots/*/docs/*", URI_DOCS_ID); - sMatcher.addURI(AUTHORITY, "roots/*/docs/*/contents", URI_DOCS_ID_CONTENTS); - sMatcher.addURI(AUTHORITY, "roots/*/docs/*/search", URI_DOCS_ID_SEARCH); - } + private static final String[] ALL_ROOTS_COLUMNS = new String[] { + RootColumns.ROOT_ID, RootColumns.ROOT_TYPE, RootColumns.ICON, RootColumns.TITLE, + RootColumns.SUMMARY, RootColumns.AVAILABLE_BYTES + }; + + private static final String[] ALL_DOCUMENTS_COLUMNS = new String[] { + DocumentColumns.DOC_ID, DocumentColumns.DISPLAY_NAME, DocumentColumns.SIZE, + DocumentColumns.MIME_TYPE, DocumentColumns.LAST_MODIFIED, DocumentColumns.FLAGS + }; @Override public boolean onCreate() { @@ -93,64 +103,59 @@ public class ExternalStorageProvider extends ContentProvider { @Override public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) { - - // TODO: support custom projections - final String[] rootsProjection = new String[] { - BaseColumns._ID, RootColumns.ROOT_ID, RootColumns.ROOT_TYPE, RootColumns.ICON, - RootColumns.TITLE, RootColumns.SUMMARY, RootColumns.AVAILABLE_BYTES }; - final String[] docsProjection = new String[] { - BaseColumns._ID, DocumentColumns.DISPLAY_NAME, DocumentColumns.SIZE, - DocumentColumns.DOC_ID, DocumentColumns.MIME_TYPE, DocumentColumns.LAST_MODIFIED, - DocumentColumns.FLAGS }; - switch (sMatcher.match(uri)) { case URI_ROOTS: { - final MatrixCursor cursor = new MatrixCursor(rootsProjection); + final MatrixCursor result = new MatrixCursor( + projection != null ? projection : ALL_ROOTS_COLUMNS); for (Root root : mRoots.values()) { - includeRoot(cursor, root); + includeRoot(result, root); } - return cursor; + return result; } case URI_ROOTS_ID: { final Root root = mRoots.get(DocumentsContract.getRootId(uri)); - final MatrixCursor cursor = new MatrixCursor(rootsProjection); - includeRoot(cursor, root); - return cursor; + final MatrixCursor result = new MatrixCursor( + projection != null ? projection : ALL_ROOTS_COLUMNS); + includeRoot(result, root); + return result; } case URI_DOCS_ID: { final Root root = mRoots.get(DocumentsContract.getRootId(uri)); final String docId = DocumentsContract.getDocId(uri); - final MatrixCursor cursor = new MatrixCursor(docsProjection); + final MatrixCursor result = new MatrixCursor( + projection != null ? projection : ALL_DOCUMENTS_COLUMNS); final File file = docIdToFile(root, docId); - includeFile(cursor, root, file); - return cursor; + includeFile(result, root, file); + return result; } case URI_DOCS_ID_CONTENTS: { final Root root = mRoots.get(DocumentsContract.getRootId(uri)); final String docId = DocumentsContract.getDocId(uri); - final MatrixCursor cursor = new MatrixCursor(docsProjection); + final MatrixCursor result = new MatrixCursor( + projection != null ? projection : ALL_DOCUMENTS_COLUMNS); final File parent = docIdToFile(root, docId); for (File file : parent.listFiles()) { - includeFile(cursor, root, file); + includeFile(result, root, file); } - return cursor; + return result; } case URI_DOCS_ID_SEARCH: { final Root root = mRoots.get(DocumentsContract.getRootId(uri)); final String docId = DocumentsContract.getDocId(uri); final String query = DocumentsContract.getSearchQuery(uri).toLowerCase(); - final MatrixCursor cursor = new MatrixCursor(docsProjection); + final MatrixCursor result = new MatrixCursor( + projection != null ? projection : ALL_DOCUMENTS_COLUMNS); final File parent = docIdToFile(root, docId); final LinkedList<File> pending = new LinkedList<File>(); pending.add(parent); - while (!pending.isEmpty() && cursor.getCount() < 20) { + while (!pending.isEmpty() && result.getCount() < 20) { final File file = pending.removeFirst(); if (file.isDirectory()) { for (File child : file.listFiles()) { @@ -158,12 +163,12 @@ public class ExternalStorageProvider extends ContentProvider { } } else { if (file.getName().toLowerCase().contains(query)) { - includeFile(cursor, root, file); + includeFile(result, root, file); } } } - return cursor; + return result; } default: { throw new UnsupportedOperationException("Unsupported Uri " + uri); @@ -196,13 +201,17 @@ public class ExternalStorageProvider extends ContentProvider { } } - private void includeRoot(MatrixCursor cursor, Root root) { - cursor.addRow(new Object[] { - root.name.hashCode(), root.name, root.rootType, root.icon, root.title, root.summary, - root.path.getFreeSpace() }); + private void includeRoot(MatrixCursor result, Root root) { + final RowBuilder row = result.newRow(); + row.offer(RootColumns.ROOT_ID, root.name); + row.offer(RootColumns.ROOT_TYPE, root.rootType); + row.offer(RootColumns.ICON, root.icon); + row.offer(RootColumns.TITLE, root.title); + row.offer(RootColumns.SUMMARY, root.summary); + row.offer(RootColumns.AVAILABLE_BYTES, root.path.getFreeSpace()); } - private void includeFile(MatrixCursor cursor, Root root, File file) { + private void includeFile(MatrixCursor result, Root root, File file) { int flags = 0; if (file.isDirectory()) { @@ -223,8 +232,6 @@ public class ExternalStorageProvider extends ContentProvider { } final String docId = fileToDocId(root, file); - final long id = docId.hashCode(); - final String displayName; if (Documents.DOC_ID_ROOT.equals(docId)) { displayName = root.title; @@ -232,8 +239,13 @@ public class ExternalStorageProvider extends ContentProvider { displayName = file.getName(); } - cursor.addRow(new Object[] { - id, displayName, file.length(), docId, mimeType, file.lastModified(), flags }); + final RowBuilder row = result.newRow(); + row.offer(DocumentColumns.DOC_ID, docId); + row.offer(DocumentColumns.DISPLAY_NAME, displayName); + row.offer(DocumentColumns.SIZE, file.length()); + row.offer(DocumentColumns.MIME_TYPE, mimeType); + row.offer(DocumentColumns.LAST_MODIFIED, file.lastModified()); + row.offer(DocumentColumns.FLAGS, flags); } @Override |