Merge "Refactor archives to support creating archives." into arc-apps
diff --git a/res/drawable-hdpi/ic_menu_extract_alpha.png b/res/drawable-hdpi/ic_menu_extract_alpha.png
new file mode 100644
index 0000000..c05764d
--- /dev/null
+++ b/res/drawable-hdpi/ic_menu_extract_alpha.png
Binary files differ
diff --git a/res/drawable-mdpi/ic_menu_extract_alpha.png b/res/drawable-mdpi/ic_menu_extract_alpha.png
new file mode 100644
index 0000000..ca7c3c9
--- /dev/null
+++ b/res/drawable-mdpi/ic_menu_extract_alpha.png
Binary files differ
diff --git a/res/drawable-xhdpi/ic_menu_extract_alpha.png b/res/drawable-xhdpi/ic_menu_extract_alpha.png
new file mode 100644
index 0000000..0567dee
--- /dev/null
+++ b/res/drawable-xhdpi/ic_menu_extract_alpha.png
Binary files differ
diff --git a/res/drawable-xxhdpi/ic_menu_extract_alpha.png b/res/drawable-xxhdpi/ic_menu_extract_alpha.png
new file mode 100644
index 0000000..7275663
--- /dev/null
+++ b/res/drawable-xxhdpi/ic_menu_extract_alpha.png
Binary files differ
diff --git a/res/drawable-xxxhdpi/ic_menu_extract_alpha.png b/res/drawable-xxxhdpi/ic_menu_extract_alpha.png
new file mode 100644
index 0000000..ca7c3c9
--- /dev/null
+++ b/res/drawable-xxxhdpi/ic_menu_extract_alpha.png
Binary files differ
diff --git a/res/drawable/ic_menu_extract.xml b/res/drawable/ic_menu_extract.xml
new file mode 100644
index 0000000..8458e15
--- /dev/null
+++ b/res/drawable/ic_menu_extract.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
+    android:src="@drawable/ic_menu_extract_alpha"
+    android:tint="?android:attr/colorControlNormal" />
diff --git a/res/menu/dir_context_menu.xml b/res/menu/dir_context_menu.xml
index 8c0772d..89e43f1 100644
--- a/res/menu/dir_context_menu.xml
+++ b/res/menu/dir_context_menu.xml
@@ -47,4 +47,4 @@
             android:id="@+id/menu_delete"
             android:title="@string/menu_delete" />
     </group>
-</menu>
\ No newline at end of file
+</menu>
diff --git a/res/menu/mode_directory.xml b/res/menu/mode_directory.xml
index e2125ad..7880aea 100644
--- a/res/menu/mode_directory.xml
+++ b/res/menu/mode_directory.xml
@@ -39,6 +39,12 @@
         android:showAsAction="never"
         android:visible="false" />
     <item
+        android:id="@+id/menu_extract_to"
+        android:icon="@drawable/ic_menu_extract"
+        android:title="@string/menu_extract"
+        android:showAsAction="always"
+        android:visible="false" />
+    <item
         android:id="@+id/menu_move_to"
         android:title="@string/menu_move"
         android:showAsAction="never"
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 6daab3d..0d9cadf 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -52,6 +52,8 @@
     <string name="menu_copy">Copy to\u2026</string>
     <!-- Menu item title that moves the selected documents [CHAR LIMIT=28] -->
     <string name="menu_move">Move to\u2026</string>
+    <!-- Menu item title that extracts the selected documents [CHAR LIMIT=28] -->
+    <string name="menu_extract">Extract to\u2026</string>
     <!-- Menu item that renames the selected document [CHAR LIMIT=28] -->
     <string name="menu_rename">Rename</string>
 
diff --git a/src/com/android/documentsui/MenuManager.java b/src/com/android/documentsui/MenuManager.java
index b12353d..1aa78c2 100644
--- a/src/com/android/documentsui/MenuManager.java
+++ b/src/com/android/documentsui/MenuManager.java
@@ -60,6 +60,7 @@
         updateSelectAll(menu.findItem(R.id.menu_select_all));
         updateMoveTo(menu.findItem(R.id.menu_move_to), selection);
         updateCopyTo(menu.findItem(R.id.menu_copy_to), selection);
+        updateExtractTo(menu.findItem(R.id.menu_extract_to), selection);
 
         Menus.disableHiddenItems(menu);
     }
@@ -269,6 +270,10 @@
         copyTo.setVisible(false);
     }
 
+    protected void updateExtractTo(MenuItem extractTo, SelectionDetails selectionDetails) {
+        extractTo.setVisible(false);
+    }
+
     protected void updatePasteInto(MenuItem pasteInto, SelectionDetails selectionDetails) {
         pasteInto.setVisible(false);
     }
@@ -301,6 +306,8 @@
         boolean canRename();
 
         boolean canPasteInto();
+
+        boolean canExtract();
     }
 
     public static class DirectoryDetails {
diff --git a/src/com/android/documentsui/dirlist/DirectoryFragment.java b/src/com/android/documentsui/dirlist/DirectoryFragment.java
index 0508e61..05b584b 100644
--- a/src/com/android/documentsui/dirlist/DirectoryFragment.java
+++ b/src/com/android/documentsui/dirlist/DirectoryFragment.java
@@ -611,6 +611,8 @@
                 return true;
 
             case R.id.menu_copy_to:
+            // TODO: Add a separate OPERATION_EXTRACT.
+            case R.id.menu_extract_to:
                 transferDocuments(selection, FileOperationService.OPERATION_COPY);
                 // TODO: Only finish selection mode if copy-to is not canceled.
                 // Need to plum down into handling the way we do with deleteDocuments.
diff --git a/src/com/android/documentsui/files/MenuManager.java b/src/com/android/documentsui/files/MenuManager.java
index 36542ca..75c02e6 100644
--- a/src/com/android/documentsui/files/MenuManager.java
+++ b/src/com/android/documentsui/files/MenuManager.java
@@ -169,7 +169,13 @@
     @Override
     protected void updateCopyTo(MenuItem copyTo, SelectionDetails selectionDetails) {
         copyTo.setVisible(true);
-        copyTo.setEnabled(!selectionDetails.containsPartialFiles());
+        copyTo.setEnabled(!selectionDetails.containsPartialFiles() &&
+                !selectionDetails.canExtract());
+    }
+
+    @Override
+    protected void updateExtractTo(MenuItem extractTo, SelectionDetails selectionDetails) {
+        extractTo.setVisible(selectionDetails.canExtract());
     }
 
     @Override
diff --git a/src/com/android/documentsui/selection/SelectionMetadata.java b/src/com/android/documentsui/selection/SelectionMetadata.java
index 1da5748..6b326b2 100644
--- a/src/com/android/documentsui/selection/SelectionMetadata.java
+++ b/src/com/android/documentsui/selection/SelectionMetadata.java
@@ -24,7 +24,9 @@
 import android.util.Log;
 
 import com.android.documentsui.MenuManager;
+import com.android.documentsui.archives.ArchivesProvider;
 import com.android.documentsui.base.MimeTypes;
+import com.android.documentsui.roots.RootCursorWrapper;
 
 import java.util.function.Function;
 
@@ -46,6 +48,7 @@
     private int mWritableDirectoryCount = 0;
     private int mNoDeleteCount = 0;
     private int mNoRenameCount = 0;
+    private int mInArchiveCount = 0;
 
     public SelectionMetadata(Function<String, Cursor> docFinder) {
         mDocFinder = docFinder;
@@ -82,6 +85,14 @@
         if ((docFlags & Document.FLAG_SUPPORTS_RENAME) == 0) {
             mNoRenameCount += delta;
         }
+        if ((docFlags & Document.FLAG_PARTIAL) != 0) {
+            mPartialCount += delta;
+        }
+
+        final String authority = getCursorString(cursor, RootCursorWrapper.COLUMN_AUTHORITY);
+        if (ArchivesProvider.AUTHORITY.equals(authority)) {
+            mInArchiveCount += delta;
+        }
     }
 
     @Override
@@ -110,6 +121,11 @@
     }
 
     @Override
+    public boolean canExtract() {
+        return size() > 0 && mInArchiveCount == size();
+    }
+
+    @Override
     public boolean canRename() {
         return mNoRenameCount == 0 && size() == 1;
     }
diff --git a/tests/common/com/android/documentsui/testing/TestMenu.java b/tests/common/com/android/documentsui/testing/TestMenu.java
index d61db11..75d8bd6 100644
--- a/tests/common/com/android/documentsui/testing/TestMenu.java
+++ b/tests/common/com/android/documentsui/testing/TestMenu.java
@@ -43,6 +43,7 @@
                 R.id.menu_rename,
                 R.id.menu_move_to,
                 R.id.menu_copy_to,
+                R.id.menu_extract_to,
                 R.id.menu_cut_to_clipboard,
                 R.id.menu_copy_to_clipboard,
                 R.id.menu_paste_from_clipboard,
diff --git a/tests/common/com/android/documentsui/testing/TestSelectionDetails.java b/tests/common/com/android/documentsui/testing/TestSelectionDetails.java
index e7f9b6c..f5d2a4c 100644
--- a/tests/common/com/android/documentsui/testing/TestSelectionDetails.java
+++ b/tests/common/com/android/documentsui/testing/TestSelectionDetails.java
@@ -30,31 +30,37 @@
     public boolean containDirectories;
     public boolean containFiles;
     public boolean canPasteInto;
+    public boolean canExtract;
 
-     @Override
-     public boolean containsPartialFiles() {
-         return containPartial;
-     }
+    @Override
+    public boolean containsPartialFiles() {
+        return containPartial;
+    }
 
-     @Override
-     public boolean containsFiles() {
-         return containFiles;
-     }
+    @Override
+    public boolean containsFiles() {
+        return containFiles;
+    }
 
-     @Override
-     public boolean containsDirectories() {
-         return containDirectories;
-     }
+    @Override
+    public boolean containsDirectories() {
+        return containDirectories;
+    }
 
-     @Override
-     public boolean canRename() {
-         return canRename;
-     }
+    @Override
+    public boolean canRename() {
+        return canRename;
+    }
 
-     @Override
-     public boolean canDelete() {
-         return canDelete;
-     }
+    @Override
+    public boolean canDelete() {
+        return canDelete;
+    }
+
+    @Override
+    public boolean canExtract() {
+        return canExtract;
+    }
 
     @Override
     public boolean canPasteInto() {
@@ -65,4 +71,4 @@
     public int size() {
         return size;
     }
- }
\ No newline at end of file
+ }
diff --git a/tests/unit/com/android/documentsui/files/MenuManagerTest.java b/tests/unit/com/android/documentsui/files/MenuManagerTest.java
index 473f3a8..968111f 100644
--- a/tests/unit/com/android/documentsui/files/MenuManagerTest.java
+++ b/tests/unit/com/android/documentsui/files/MenuManagerTest.java
@@ -49,6 +49,7 @@
     private TestMenuItem selectAll;
     private TestMenuItem moveTo;
     private TestMenuItem copyTo;
+    private TestMenuItem extractTo;
     private TestMenuItem share;
     private TestMenuItem delete;
     private TestMenuItem createDir;
@@ -80,6 +81,7 @@
         selectAll = testMenu.findItem(R.id.menu_select_all);
         moveTo = testMenu.findItem(R.id.menu_move_to);
         copyTo = testMenu.findItem(R.id.menu_copy_to);
+        extractTo = testMenu.findItem(R.id.menu_extract_to);
         share = testMenu.findItem(R.id.menu_share);
         delete = testMenu.findItem(R.id.menu_delete);
         createDir = testMenu.findItem(R.id.menu_create_dir);
@@ -119,6 +121,7 @@
         delete.assertVisible();
         share.assertVisible();
         copyTo.assertEnabled();
+        extractTo.assertInvisible();
         moveTo.assertEnabled();
     }
 
@@ -130,6 +133,7 @@
         rename.assertDisabled();
         share.assertInvisible();
         copyTo.assertDisabled();
+        extractTo.assertDisabled();
         moveTo.assertDisabled();
     }
 
@@ -161,6 +165,23 @@
     }
 
     @Test
+    public void testActionMenu_cantExtract() {
+        selectionDetails.canExtract = false;
+        mgr.updateActionMenu(testMenu, selectionDetails);
+
+        extractTo.assertInvisible();
+    }
+
+    @Test
+    public void testActionMenu_canExtract_hidesCopyTo() {
+        selectionDetails.canExtract = true;
+        mgr.updateActionMenu(testMenu, selectionDetails);
+
+        extractTo.assertEnabled();
+        copyTo.assertDisabled();
+    }
+
+    @Test
     public void testOptionMenu() {
         mgr.updateOptionMenu(testMenu);