Merge "Make the executor pool size as 1" into mainline-prod
diff --git a/res/drawable/launcher_screen.xml b/res/drawable/launcher_screen.xml
index 4851606..c0d8146 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 8a9ffd3..983c497 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 5768aff..5067af0 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 0000000..3f0c48b
--- /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 0ebd936..7f2a959 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 86bcbbc..1da85cd 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 e00984a..aa0c3a4 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/res/values/strings.xml b/res/values/strings.xml
index 088e672..66e16b2 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -540,4 +540,11 @@
<!-- Snackbar shown when users drag and drop files from another app
to DocumentsUI. [CHAR_LIMIT=100] -->
<string name="drag_from_another_app">You can\u2019t move files from another app.</string>
+
+ <!-- Accessibility announcement when switching to grid mode of files and directories shown. [CHAR_LIMIT=100] -->
+ <string name="grid_mode_showing">Showing in grid mode.</string>
+
+ <!-- Accessibility announcement when switching to list mode of files and directories shown. [CHAR_LIMIT=100] -->
+ <string name="list_mode_showing">Showing in list mode.</string>
+
</resources>
diff --git a/src/com/android/documentsui/DirectoryLoader.java b/src/com/android/documentsui/DirectoryLoader.java
index 458f861..2775ec4 100644
--- a/src/com/android/documentsui/DirectoryLoader.java
+++ b/src/com/android/documentsui/DirectoryLoader.java
@@ -56,7 +56,6 @@
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 @@
}
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)
@@ -281,10 +279,11 @@
@Override
protected void onStartLoading() {
- if (mResult != null) {
+ boolean isCursorStale = checkIfCursorStale(mResult);
+ if (mResult != null && !isCursorStale) {
deliverResult(mResult);
}
- if (takeContentChanged() || mResult == null) {
+ if (takeContentChanged() || mResult == null || isCursorStale) {
forceLoad();
}
}
@@ -313,4 +312,22 @@
FileUtils.closeQuietly(mResult);
mResult = null;
}
+
+ private boolean checkIfCursorStale(DirectoryResult result) {
+ if (mResult == null) {
+ return true;
+ }
+ Cursor cursor = result.cursor;
+ cursor.moveToPosition(-1);
+ for (int pos = 0; pos < cursor.getCount(); ++pos) {
+ try {
+ if (!cursor.moveToNext()) {
+ return true;
+ }
+ } catch (Exception e) {
+ return true;
+ }
+ }
+ return false;
+ }
}
diff --git a/src/com/android/documentsui/MultiRootDocumentsLoader.java b/src/com/android/documentsui/MultiRootDocumentsLoader.java
index 643f122..b25828d 100644
--- a/src/com/android/documentsui/MultiRootDocumentsLoader.java
+++ b/src/com/android/documentsui/MultiRootDocumentsLoader.java
@@ -104,8 +104,6 @@
* @param state current state
* @param executors the executors of authorities
* @param fileTypeMap the map of mime types and file types.
- * @param lock the selection lock
- * @param contentChangedCallback callback when content changed
*/
public MultiRootDocumentsLoader(Context context, ProvidersAccess providers, State state,
Lookup<String, Executor> executors, Lookup<String, String> fileTypeMap) {
@@ -181,17 +179,18 @@
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) {
@@ -303,10 +302,11 @@
@Override
protected void onStartLoading() {
- if (mResult != null) {
+ boolean isCursorStale = checkIfCursorStale(mResult);
+ if (mResult != null && !isCursorStale) {
deliverResult(mResult);
}
- if (takeContentChanged() || mResult == null) {
+ if (takeContentChanged() || mResult == null || isCursorStale) {
forceLoad();
}
}
@@ -456,4 +456,22 @@
mIsClosed = true;
}
}
+
+ private boolean checkIfCursorStale(DirectoryResult result) {
+ if (mResult == null) {
+ return true;
+ }
+ Cursor cursor = result.cursor;
+ cursor.moveToPosition(-1);
+ for (int pos = 0; pos < cursor.getCount(); ++pos) {
+ try {
+ if (!cursor.moveToNext()) {
+ return true;
+ }
+ } catch (Exception e) {
+ return true;
+ }
+ }
+ return false;
+ }
}
diff --git a/src/com/android/documentsui/archives/ArchiveEntryInputStream.java b/src/com/android/documentsui/archives/ArchiveEntryInputStream.java
index 0b1c0c2..2c34e5a 100644
--- a/src/com/android/documentsui/archives/ArchiveEntryInputStream.java
+++ b/src/com/android/documentsui/archives/ArchiveEntryInputStream.java
@@ -20,16 +20,16 @@
import androidx.annotation.NonNull;
-import java.io.Closeable;
-import java.io.IOException;
-import java.io.InputStream;
-
import org.apache.commons.compress.archivers.ArchiveEntry;
import org.apache.commons.compress.archivers.ArchiveInputStream;
import org.apache.commons.compress.archivers.sevenz.SevenZFile;
import org.apache.commons.compress.archivers.zip.ZipArchiveEntry;
import org.apache.commons.compress.archivers.zip.ZipFile;
+import java.io.Closeable;
+import java.io.IOException;
+import java.io.InputStream;
+
/**
* To simulate the input stream by using ZipFile, SevenZFile, or ArchiveInputStream.
*/
@@ -124,7 +124,7 @@
throw new IllegalArgumentException("ArchiveEntry is empty");
}
- if (archiveEntry.isDirectory() || archiveEntry.getSize() <= 0
+ if (archiveEntry.isDirectory() || archiveEntry.getSize() < 0
|| TextUtils.isEmpty(archiveEntry.getName())) {
throw new IllegalArgumentException("ArchiveEntry is an invalid file entry");
}
diff --git a/src/com/android/documentsui/base/FilteringCursorWrapper.java b/src/com/android/documentsui/base/FilteringCursorWrapper.java
index 67b7533..577e47c 100644
--- a/src/com/android/documentsui/base/FilteringCursorWrapper.java
+++ b/src/com/android/documentsui/base/FilteringCursorWrapper.java
@@ -29,68 +29,62 @@
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;
+ /** 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;
+ });
+ }
- final int count = cursor.getCount();
- mPosition = new int[count];
+ /** Filter hidden files based on preference. */
+ public void filterHiddenFiles(boolean showHiddenFiles) {
+ if (showHiddenFiles) {
+ return;
+ }
- cursor.moveToPosition(-1);
- while (cursor.moveToNext() && mCount < count) {
+ 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);
- if (!showHiddenFiles && documentId != null
- && (documentId.startsWith(".") || documentId.contains("/."))) {
- continue;
- }
- mPosition[mCount++] = cursor.getPosition();
- }
-
- if (DEBUG && mCount != cursor.getCount()) {
- Log.d(TAG, "Before filtering " + cursor.getCount() + ", after " + mCount);
- }
+ boolean documentIdHidden = documentId != null && documentId.contains("/.");
+ boolean fileNameHidden = name != null && name.startsWith(".");
+ return !(documentIdHidden || fileNameHidden);
+ });
}
@Override
@@ -106,7 +100,7 @@
@Override
public boolean onMove(int oldPosition, int newPosition) {
- return mCursor.moveToPosition(mPosition[newPosition]);
+ return mCursor.moveToPosition(mPositions[newPosition]);
}
@Override
@@ -168,4 +162,27 @@
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;
+ }
}
diff --git a/src/com/android/documentsui/dirlist/DirectoryFragment.java b/src/com/android/documentsui/dirlist/DirectoryFragment.java
index 8fa02ca..a079ab1 100644
--- a/src/com/android/documentsui/dirlist/DirectoryFragment.java
+++ b/src/com/android/documentsui/dirlist/DirectoryFragment.java
@@ -180,6 +180,7 @@
private SelectionMetadata mSelectionMetadata;
private KeyInputHandler mKeyListener;
private @Nullable DragHoverListener mDragHoverListener;
+ private View mRootView;
private IconHelper mIconHelper;
private SwipeRefreshLayout mRefreshLayout;
private RecyclerView mRecView;
@@ -348,12 +349,12 @@
mHandler = new Handler(Looper.getMainLooper());
mActivity = (BaseActivity) getActivity();
- final View view = inflater.inflate(R.layout.fragment_directory, container, false);
+ mRootView = inflater.inflate(R.layout.fragment_directory, container, false);
- mProgressBar = view.findViewById(R.id.progressbar);
+ mProgressBar = mRootView.findViewById(R.id.progressbar);
assert mProgressBar != null;
- mRecView = (RecyclerView) view.findViewById(R.id.dir_list);
+ mRecView = (RecyclerView) mRootView.findViewById(R.id.dir_list);
mRecView.setRecyclerListener(
new RecyclerListener() {
@Override
@@ -362,7 +363,7 @@
}
});
- mRefreshLayout = (SwipeRefreshLayout) view.findViewById(R.id.refresh_layout);
+ mRefreshLayout = (SwipeRefreshLayout) mRootView.findViewById(R.id.refresh_layout);
mRefreshLayout.setOnRefreshListener(this);
mRecView.setItemAnimator(new DirectoryItemAnimator());
@@ -398,7 +399,7 @@
setPreDrawListenerEnabled(true);
- return view;
+ return mRootView;
}
@Override
@@ -684,6 +685,9 @@
public void onViewModeChanged() {
// Mode change is just visual change; no need to kick loader.
+ mRootView.announceForAccessibility(getString(
+ mState.derivedMode == State.MODE_GRID ? R.string.grid_mode_showing
+ : R.string.list_mode_showing));
onDisplayStateChanged();
}
diff --git a/src/com/android/documentsui/queries/SearchChipViewManager.java b/src/com/android/documentsui/queries/SearchChipViewManager.java
index ebda22b..2305da4 100644
--- a/src/com/android/documentsui/queries/SearchChipViewManager.java
+++ b/src/com/android/documentsui/queries/SearchChipViewManager.java
@@ -24,6 +24,7 @@
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
+import android.view.accessibility.AccessibilityEvent;
import android.widget.HorizontalScrollView;
import androidx.annotation.NonNull;
@@ -35,6 +36,7 @@
import com.android.documentsui.R;
import com.android.documentsui.base.MimeTypes;
import com.android.documentsui.base.Shared;
+import com.android.documentsui.util.VersionUtils;
import com.google.android.material.chip.Chip;
import com.google.common.primitives.Ints;
@@ -96,9 +98,11 @@
static {
sMimeTypesChipItems.put(TYPE_IMAGES,
new SearchChipData(TYPE_IMAGES, R.string.chip_title_images, IMAGES_MIMETYPES));
- sMimeTypesChipItems.put(TYPE_DOCUMENTS,
- new SearchChipData(TYPE_DOCUMENTS, R.string.chip_title_documents,
- DOCUMENTS_MIMETYPES));
+ if (VersionUtils.isAtLeastR()) {
+ sMimeTypesChipItems.put(TYPE_DOCUMENTS,
+ new SearchChipData(TYPE_DOCUMENTS, R.string.chip_title_documents,
+ DOCUMENTS_MIMETYPES));
+ }
sMimeTypesChipItems.put(TYPE_AUDIO,
new SearchChipData(TYPE_AUDIO, R.string.chip_title_audio, AUDIO_MIMETYPES));
sMimeTypesChipItems.put(TYPE_VIDEOS,
@@ -465,6 +469,10 @@
if (parent instanceof HorizontalScrollView) {
final int scrollToX = isRtl ? parent.getWidth() : 0;
((HorizontalScrollView) parent).smoothScrollTo(scrollToX, 0);
+ if (mChipGroup.getChildCount() > 0) {
+ mChipGroup.getChildAt(0)
+ .sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_FOCUSED);
+ }
}
}
}
diff --git a/src/com/android/documentsui/services/CompressJob.java b/src/com/android/documentsui/services/CompressJob.java
index 1f2ea44..e9ba6e4 100644
--- a/src/com/android/documentsui/services/CompressJob.java
+++ b/src/com/android/documentsui/services/CompressJob.java
@@ -16,6 +16,8 @@
package com.android.documentsui.services;
+import static android.content.ContentResolver.wrap;
+
import static com.android.documentsui.services.FileOperationService.OPERATION_MOVE;
import android.app.Notification;
@@ -45,6 +47,8 @@
private static final String TAG = "CompressJob";
private static final String NEW_ARCHIVE_EXTENSION = ".zip";
+ private Uri mArchiveUri;
+
/**
* Moves files to a destination identified by {@code destination}.
* Performs most work by delegating to CopyJob, then deleting
@@ -99,17 +103,16 @@
displayName = service.getString(R.string.new_archive_file_name, NEW_ARCHIVE_EXTENSION);
}
- Uri archiveUri;
try {
- archiveUri = DocumentsContract.createDocument(
- resolver, mDstInfo.derivedUri, "application/zip", displayName);
+ mArchiveUri = DocumentsContract.createDocument(
+ resolver, mDstInfo.derivedUri, "application/zip", displayName);
} catch (Exception e) {
- archiveUri = null;
+ mArchiveUri = null;
}
try {
mDstInfo = DocumentInfo.fromUri(resolver, ArchivesProvider.buildUriForArchive(
- archiveUri, ParcelFileDescriptor.MODE_WRITE_ONLY), UserId.DEFAULT_USER);
+ mArchiveUri, ParcelFileDescriptor.MODE_WRITE_ONLY), UserId.DEFAULT_USER);
ArchivesProvider.acquireArchive(getClient(mDstInfo), mDstInfo.derivedUri);
} catch (FileNotFoundException e) {
Log.e(TAG, "Failed to create dstInfo.", e);
@@ -132,7 +135,14 @@
Log.e(TAG, "Failed to release the archive.");
}
- // TODO: Remove the archive file in case of an error.
+ // Remove the archive file in case of an error.
+ try {
+ if (!isFinished() || isCanceled()) {
+ DocumentsContract.deleteDocument(wrap(getClient(mArchiveUri)), mArchiveUri);
+ }
+ } catch (RemoteException | FileNotFoundException e) {
+ Log.w(TAG, "Failed to cleanup after compress error: " + mDstInfo.toString(), e);
+ }
super.finish();
}
diff --git a/tests/unit/com/android/documentsui/queries/SearchChipViewManagerTest.java b/tests/unit/com/android/documentsui/queries/SearchChipViewManagerTest.java
index 9dbef02..da83c38 100644
--- a/tests/unit/com/android/documentsui/queries/SearchChipViewManagerTest.java
+++ b/tests/unit/com/android/documentsui/queries/SearchChipViewManagerTest.java
@@ -34,6 +34,7 @@
import com.android.documentsui.R;
import com.android.documentsui.base.MimeTypes;
import com.android.documentsui.base.Shared;
+import com.android.documentsui.util.VersionUtils;
import org.junit.Before;
import org.junit.Test;
@@ -49,6 +50,8 @@
private static final String LARGE_FILES_CHIP_MIME_TYPE = "";
private static final String FROM_THIS_WEEK_CHIP_MIME_TYPE = "";
+ private static final String[] TEST_MIME_TYPES_INCLUDING_DOCUMENT =
+ new String[]{"image/*", "video/*", "text/*"};
private static final String[] TEST_MIME_TYPES =
new String[]{"image/*", "video/*"};
private static final String[] TEST_OTHER_TYPES =
@@ -88,6 +91,18 @@
}
@Test
+ public void testUpdateChips_documentsFilterOnlyAvailableAboveR() throws Exception {
+ mSearchChipViewManager.updateChips(TEST_MIME_TYPES_INCLUDING_DOCUMENT);
+
+ int totalChipLength = TEST_MIME_TYPES_INCLUDING_DOCUMENT.length + TEST_OTHER_TYPES.length;
+ if (VersionUtils.isAtLeastR()) {
+ assertThat(mChipGroup.getChildCount()).isEqualTo(totalChipLength);
+ } else {
+ assertThat(mChipGroup.getChildCount()).isEqualTo(totalChipLength - 1);
+ }
+ }
+
+ @Test
public void testUpdateChips_withSingleMimeType_hasCorrectChipCount() throws Exception {
mSearchChipViewManager.updateChips(new String[]{"image/*"});