diff options
-rw-r--r-- | res/drawable/launcher_screen.xml | 2 | ||||
-rw-r--r-- | res/drawable/launcher_screen_night.xml | 2 | ||||
-rw-r--r-- | res/drawable/list_divider.xml | 2 | ||||
-rw-r--r-- | res/drawable/splash_screen.xml | 64 | ||||
-rw-r--r-- | res/layout/dialog_file_name.xml | 1 | ||||
-rw-r--r-- | res/values-night/colors.xml | 2 | ||||
-rw-r--r-- | res/values/colors.xml | 2 | ||||
-rw-r--r-- | src/com/android/documentsui/DirectoryLoader.java | 12 | ||||
-rw-r--r-- | src/com/android/documentsui/MultiRootDocumentsLoader.java | 13 | ||||
-rw-r--r-- | src/com/android/documentsui/base/FilteringCursorWrapper.java | 111 |
10 files changed, 148 insertions, 63 deletions
diff --git a/res/drawable/launcher_screen.xml b/res/drawable/launcher_screen.xml index 485160615..c0d814632 100644 --- a/res/drawable/launcher_screen.xml +++ b/res/drawable/launcher_screen.xml @@ -3,7 +3,7 @@ <item android:drawable="@android:color/white"/> <item - android:drawable="@drawable/app_icon" + android:drawable="@drawable/splash_screen" android:height="150dp" android:width="150dp" android:gravity="center"/> diff --git a/res/drawable/launcher_screen_night.xml b/res/drawable/launcher_screen_night.xml index 8a9ffd3a6..983c4977d 100644 --- a/res/drawable/launcher_screen_night.xml +++ b/res/drawable/launcher_screen_night.xml @@ -3,7 +3,7 @@ <item android:drawable="@color/app_background_color"/> <item - android:drawable="@drawable/app_icon" + android:drawable="@drawable/splash_screen" android:height="150dp" android:width="150dp" android:gravity="center"/> diff --git a/res/drawable/list_divider.xml b/res/drawable/list_divider.xml index 5768aff8a..5067af08e 100644 --- a/res/drawable/list_divider.xml +++ b/res/drawable/list_divider.xml @@ -16,7 +16,7 @@ <shape xmlns:android="http://schemas.android.com/apk/res/android" android:tint="?android:attr/colorForeground"> - <solid android:color="#1f000000" /> + <solid android:color="@color/list_divider_color" /> <size android:height="1dp" android:width="1dp" /> diff --git a/res/drawable/splash_screen.xml b/res/drawable/splash_screen.xml new file mode 100644 index 000000000..3f0c48b6b --- /dev/null +++ b/res/drawable/splash_screen.xml @@ -0,0 +1,64 @@ +<vector xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:aapt="http://schemas.android.com/aapt" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24" + android:viewportHeight="24"> + <path + android:pathData="M12,12m-11,0a11,11 0,1 1,22 0a11,11 0,1 1,-22 0" + android:fillColor="#4285F4"/> + <path + android:pathData="M23,12c0,6.1 -4.9,11 -11,11S1,18.1 1,12c0,0 0,0 0,-0.1c0,6 4.9,10.9 11,10.9S23,18 23,12C23,12 23,12 23,12z" + android:strokeAlpha="0.2" + android:fillColor="#263238" + android:fillAlpha="0.2"/> + <path + android:pathData="M23,12C23,12 23,12 23,12c0,-6 -4.9,-10.9 -11,-10.9S1,6 1,12.1c0,0 0,0 0,-0.1C1,5.9 5.9,1 12,1S23,5.9 23,12z" + android:strokeAlpha="0.2" + android:fillColor="#FFFFFF" + android:fillAlpha="0.2"/> + <path + android:pathData="M22.8,14.2c-1,4.8 -5,8.4 -9.9,8.8l-6.4,-6.4L17.6,9C17.6,9 22.8,14.2 22.8,14.2z" + android:fillColor="#4285F4"/> + <path + android:pathData="M22.8,14.2c-1,4.8 -5,8.4 -9.9,8.8l-6.4,-6.4L17.6,9C17.6,9 22.8,14.2 22.8,14.2z"> + <aapt:attr name="android:fillColor"> + <gradient + android:startY="12.203438" + android:startX="11.452812" + android:endY="20.219812" + android:endX="19.469187" + android:type="linear"> + <item android:offset="0" android:color="#33263238"/> + <item android:offset="1" android:color="#05263238"/> + </gradient> + </aapt:attr> + </path> + <path + android:pathData="M16.5,8.5H12L10.8,7H7.5C6.7,7 6,7.7 6,8.5v7C6,16.3 6.7,17 7.5,17h9c0.8,0 1.5,-0.7 1.5,-1.5V10C18,9.2 17.3,8.5 16.5,8.5z" + android:fillColor="#F5F5F5"/> + <path + android:pathData="M18,10v0.1c0,-0.8 -0.7,-1.5 -1.5,-1.5H12l-1.2,-1.5H7.5C6.7,7.1 6,7.8 6,8.6V8.5C6,7.7 6.7,7 7.5,7h3.2L12,8.5h4.5C17.3,8.5 18,9.2 18,10z" + android:strokeAlpha="0.4" + android:fillColor="#FFFFFF" + android:fillAlpha="0.4"/> + <path + android:pathData="M18,15.5v0.1c0,0.8 -0.7,1.5 -1.5,1.5h-9c-0.8,0 -1.5,-0.7 -1.5,-1.5v-0.1C6,16.3 6.7,17 7.5,17h9C17.3,17 18,16.3 18,15.5z" + android:strokeAlpha="0.2" + android:fillColor="#263238" + android:fillAlpha="0.2"/> + <path + android:pathData="M12,12m-11,0a11,11 0,1 1,22 0a11,11 0,1 1,-22 0" + android:fillAlpha="0.1"> + <aapt:attr name="android:fillColor"> + <gradient + android:gradientRadius="22.333876" + android:centerX="3.238875" + android:centerY="5.0445" + android:type="radial"> + <item android:offset="0" android:color="#FFFFFFFF"/> + <item android:offset="1" android:color="#00FFFFFF"/> + </gradient> + </aapt:attr> + </path> +</vector> diff --git a/res/layout/dialog_file_name.xml b/res/layout/dialog_file_name.xml index 0ebd936d0..7f2a9592b 100644 --- a/res/layout/dialog_file_name.xml +++ b/res/layout/dialog_file_name.xml @@ -35,6 +35,7 @@ android:id="@android:id/text1" android:layout_width="match_parent" android:layout_height="wrap_content" + android:maxLength="255" android:inputType="textCapSentences"/> </com.google.android.material.textfield.TextInputLayout> diff --git a/res/values-night/colors.xml b/res/values-night/colors.xml index 86bcbbc48..1da85cde8 100644 --- a/res/values-night/colors.xml +++ b/res/values-night/colors.xml @@ -33,4 +33,6 @@ <!-- AppCompat.textColorSecondary --> <color name="doc_list_item_subtitle_enabled">#b3ffffff</color> <color name="doc_list_item_subtitle_disabled">#36ffffff</color> + + <color name="list_divider_color">#9aa0a6</color> </resources> diff --git a/res/values/colors.xml b/res/values/colors.xml index e00984ada..aa0c3a4ce 100644 --- a/res/values/colors.xml +++ b/res/values/colors.xml @@ -52,4 +52,6 @@ <color name="doc_list_item_subtitle_enabled">#5F6368</color> <!-- Gray 700 --> <color name="doc_list_item_subtitle_disabled">#613c4043</color> <!-- 38% Grey800 --> + + <color name="list_divider_color">#1f000000</color> </resources> diff --git a/src/com/android/documentsui/DirectoryLoader.java b/src/com/android/documentsui/DirectoryLoader.java index d90d51f74..2775ec4bb 100644 --- a/src/com/android/documentsui/DirectoryLoader.java +++ b/src/com/android/documentsui/DirectoryLoader.java @@ -56,7 +56,6 @@ import java.util.concurrent.Executor; public class DirectoryLoader extends AsyncTaskLoader<DirectoryResult> { private static final String TAG = "DirectoryLoader"; - private static final String[] SEARCH_REJECT_MIMES = new String[] { Document.MIME_TYPE_DIR }; private static final String[] PHOTO_PICKING_ACCEPT_MIMES = new String[] {Document.MIME_TYPE_DIR, MimeTypes.IMAGE_MIME}; @@ -178,17 +177,16 @@ public class DirectoryLoader extends AsyncTaskLoader<DirectoryResult> { } cursor.registerContentObserver(mObserver); - // Filter hidden files. - cursor = new FilteringCursorWrapper(cursor, mState.showHiddenFiles); - + FilteringCursorWrapper filteringCursor = new FilteringCursorWrapper(cursor); + filteringCursor.filterHiddenFiles(mState.showHiddenFiles); if (mSearchMode && !mFeatures.isFoldersInSearchResultsEnabled()) { // There is no findDocumentPath API. Enable filtering on folders in search mode. - cursor = new FilteringCursorWrapper(cursor, null, SEARCH_REJECT_MIMES); + filteringCursor.filterMimes(/* acceptMimes= */ null, SEARCH_REJECT_MIMES); } - if (mPhotoPicking) { - cursor = new FilteringCursorWrapper(cursor, PHOTO_PICKING_ACCEPT_MIMES, null); + filteringCursor.filterMimes(PHOTO_PICKING_ACCEPT_MIMES, /* rejectMimes= */ null); } + cursor = filteringCursor; // TODO: When API tweaks have landed, use ContentResolver.EXTRA_HONORED_ARGS // instead of checking directly for ContentResolver.QUERY_ARG_SORT_COLUMNS (won't work) diff --git a/src/com/android/documentsui/MultiRootDocumentsLoader.java b/src/com/android/documentsui/MultiRootDocumentsLoader.java index 065c99aaa..b25828dda 100644 --- a/src/com/android/documentsui/MultiRootDocumentsLoader.java +++ b/src/com/android/documentsui/MultiRootDocumentsLoader.java @@ -179,17 +179,18 @@ public abstract class MultiRootDocumentsLoader extends AsyncTaskLoader<Directory continue; } - // Filter hidden files. - cursor = new FilteringCursorWrapper(cursor, mState.showHiddenFiles); - - final FilteringCursorWrapper filtered = new FilteringCursorWrapper( - cursor, mState.acceptMimes, getRejectMimes(), rejectBefore) { + final FilteringCursorWrapper filteredCursor = + new FilteringCursorWrapper(cursor) { @Override public void close() { // Ignored, since we manage cursor lifecycle internally } }; - cursors.add(filtered); + filteredCursor.filterHiddenFiles(mState.showHiddenFiles); + filteredCursor.filterMimes(mState.acceptMimes, getRejectMimes()); + filteredCursor.filterLastModified(rejectBefore); + + cursors.add(filteredCursor); } } catch (InterruptedException e) { diff --git a/src/com/android/documentsui/base/FilteringCursorWrapper.java b/src/com/android/documentsui/base/FilteringCursorWrapper.java index 67b7533e5..577e47c33 100644 --- a/src/com/android/documentsui/base/FilteringCursorWrapper.java +++ b/src/com/android/documentsui/base/FilteringCursorWrapper.java @@ -29,68 +29,62 @@ import android.provider.DocumentsContract.Document; import android.util.Log; /** - * Cursor wrapper that filters MIME types not matching given list. + * Cursor wrapper that filters cursor results by given conditions. */ public class FilteringCursorWrapper extends AbstractCursor { private final Cursor mCursor; - private final int[] mPosition; + private int[] mPositions; private int mCount; - public FilteringCursorWrapper(Cursor cursor, String[] acceptMimes) { - this(cursor, acceptMimes, null, Long.MIN_VALUE); - } - - public FilteringCursorWrapper(Cursor cursor, String[] acceptMimes, String[] rejectMimes) { - this(cursor, acceptMimes, rejectMimes, Long.MIN_VALUE); - } - - public FilteringCursorWrapper( - Cursor cursor, String[] acceptMimes, String[] rejectMimes, long rejectBefore) { + public FilteringCursorWrapper(Cursor cursor) { mCursor = cursor; + mCount = cursor.getCount(); + mPositions = new int[mCount]; + for (int i = 0; i < mCount; i++) { + mPositions[i] = i; + } + } - final int count = cursor.getCount(); - mPosition = new int[count]; - - cursor.moveToPosition(-1); - while (cursor.moveToNext() && mCount < count) { + /** + * Filters cursor according to mimes. If both lists are empty, all mimes will be rejected. + * + * @param acceptMimes allowed list of mimes + * @param rejectMimes blocked list of mimes + */ + public void filterMimes(String[] acceptMimes, String[] rejectMimes) { + filterByCondition((cursor) -> { final String mimeType = getCursorString(cursor, Document.COLUMN_MIME_TYPE); - final long lastModified = getCursorLong(cursor, Document.COLUMN_LAST_MODIFIED); if (rejectMimes != null && MimeTypes.mimeMatches(rejectMimes, mimeType)) { - continue; + return false; } - if (lastModified < rejectBefore) { - continue; - } - if (MimeTypes.mimeMatches(acceptMimes, mimeType)) { - mPosition[mCount++] = cursor.getPosition(); - } - } - - if (DEBUG && mCount != cursor.getCount()) { - Log.d(TAG, "Before filtering " + cursor.getCount() + ", after " + mCount); - } + return MimeTypes.mimeMatches(acceptMimes, mimeType); + }); } - public FilteringCursorWrapper(Cursor cursor, boolean showHiddenFiles) { - mCursor = cursor; - - final int count = cursor.getCount(); - mPosition = new int[count]; + /** Filters cursor according to last modified time, and reject earlier than given timestamp. */ + public void filterLastModified(long rejectBeforeTimestamp) { + filterByCondition((cursor) -> { + final long lastModified = getCursorLong(cursor, Document.COLUMN_LAST_MODIFIED); + return lastModified >= rejectBeforeTimestamp; + }); + } - cursor.moveToPosition(-1); - while (cursor.moveToNext() && mCount < count) { - final String documentId = getCursorString(cursor, Document.COLUMN_DOCUMENT_ID); - if (!showHiddenFiles && documentId != null - && (documentId.startsWith(".") || documentId.contains("/."))) { - continue; - } - mPosition[mCount++] = cursor.getPosition(); + /** Filter hidden files based on preference. */ + public void filterHiddenFiles(boolean showHiddenFiles) { + if (showHiddenFiles) { + return; } - if (DEBUG && mCount != cursor.getCount()) { - Log.d(TAG, "Before filtering " + cursor.getCount() + ", after " + mCount); - } + filterByCondition((cursor) -> { + // Judge by name and documentId separately because for some providers + // e.g. DownloadProvider, documentId may not contain file name. + final String name = getCursorString(cursor, Document.COLUMN_DISPLAY_NAME); + final String documentId = getCursorString(cursor, Document.COLUMN_DOCUMENT_ID); + boolean documentIdHidden = documentId != null && documentId.contains("/."); + boolean fileNameHidden = name != null && name.startsWith("."); + return !(documentIdHidden || fileNameHidden); + }); } @Override @@ -106,7 +100,7 @@ public class FilteringCursorWrapper extends AbstractCursor { @Override public boolean onMove(int oldPosition, int newPosition) { - return mCursor.moveToPosition(mPosition[newPosition]); + return mCursor.moveToPosition(mPositions[newPosition]); } @Override @@ -168,4 +162,27 @@ public class FilteringCursorWrapper extends AbstractCursor { public void unregisterContentObserver(ContentObserver observer) { mCursor.unregisterContentObserver(observer); } + + private interface FilteringCondition { + boolean accept(Cursor cursor); + } + + private void filterByCondition(FilteringCondition condition) { + final int oldCount = this.getCount(); + int[] newPositions = new int[oldCount]; + int newCount = 0; + + this.moveToPosition(-1); + while (this.moveToNext() && newCount < oldCount) { + if (condition.accept(mCursor)) { + newPositions[newCount++] = mPositions[this.getPosition()]; + } + } + + if (DEBUG && newCount != this.getCount()) { + Log.d(TAG, "Before filtering " + oldCount + ", after " + newCount); + } + mCount = newCount; + mPositions = newPositions; + } } |