summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSteve McKay <smckay@google.com>2015-11-18 14:56:50 -0800
committerSteve McKay <smckay@google.com>2015-11-19 15:56:05 -0800
commitc6a4cd8c0f35a7e9d126ab09924f8f1f8422182a (patch)
treea7850cc689a5945f99121122451f011402abbf89
parentc38a5d7da10102b0664749f5720b6c50631e133d (diff)
Add "Home" directory support.
Update FilesActivityUiTests to verify Home is present and that clicking a root sets the title accordingly. Guard addition of WRITABLE flag with a volume test. Bug: 25147243 Change-Id: Ic20372737cae08a82af0aade0c0dbbd8c22d5f34
-rw-r--r--packages/DocumentsUI/res/drawable/ic_root_home.xml15
-rw-r--r--packages/DocumentsUI/src/com/android/documentsui/RootsFragment.java2
-rw-r--r--packages/DocumentsUI/src/com/android/documentsui/model/RootInfo.java16
-rw-r--r--packages/DocumentsUI/tests/src/com/android/documentsui/FilesActivityUiTest.java8
-rw-r--r--packages/DocumentsUI/tests/src/com/android/documentsui/UiBot.java16
-rw-r--r--packages/ExternalStorageProvider/res/values/strings.xml4
-rw-r--r--packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java74
7 files changed, 112 insertions, 23 deletions
diff --git a/packages/DocumentsUI/res/drawable/ic_root_home.xml b/packages/DocumentsUI/res/drawable/ic_root_home.xml
new file mode 100644
index 000000000000..0a258ac65019
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable/ic_root_home.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="utf-8"?>
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24">
+
+ <path
+ android:fillColor="#000000"
+ android:pathData="M20 6h-8l-2-2H4c-1.1 0-1.99 .9 -1.99 2L2 18c0 1.1 .9 2 2 2h16c1.1 0 2-.9
+2-2V8c0-1.1-.9-2-2-2zm-5 3c1.1 0 2 .9 2 2s-.9 2-2 2-2-.9-2-2 .9-2 2-2zm4
+8h-8v-1c0-1.33 2.67-2 4-2s4 .67 4 2v1z" />
+ <path
+ android:pathData="M0 0h24v24H0z" />
+</vector>
diff --git a/packages/DocumentsUI/src/com/android/documentsui/RootsFragment.java b/packages/DocumentsUI/src/com/android/documentsui/RootsFragment.java
index beff196509b2..4c844c422ff5 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/RootsFragment.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/RootsFragment.java
@@ -297,7 +297,7 @@ public class RootsFragment extends Fragment {
for (final RootInfo root : roots) {
final RootItem item = new RootItem(root);
- if (root.isLibrary()) {
+ if (root.isLibrary() || root.isHome()) {
libraries.add(item);
} else {
others.add(item);
diff --git a/packages/DocumentsUI/src/com/android/documentsui/model/RootInfo.java b/packages/DocumentsUI/src/com/android/documentsui/model/RootInfo.java
index 723700ded6c6..ae5644d7fc3b 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/model/RootInfo.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/model/RootInfo.java
@@ -52,7 +52,7 @@ public class RootInfo implements Durable, Parcelable {
public static final int TYPE_DOWNLOADS = 5;
public static final int TYPE_LOCAL = 6;
public static final int TYPE_MTP = 7;
- public static final int TYPE_CLOUD = 8;
+ public static final int TYPE_OTHER = 8;
public String authority;
public String rootId;
@@ -168,7 +168,10 @@ public class RootInfo implements Durable, Parcelable {
derivedMimeTypes = (mimeTypes != null) ? mimeTypes.split("\n") : null;
// TODO: remove these special case icons
- if (isExternalStorage()) {
+ if (isHome()) {
+ derivedIcon = R.drawable.ic_root_home;
+ derivedType = TYPE_LOCAL;
+ } else if (isExternalStorage()) {
derivedIcon = R.drawable.ic_root_sdcard;
derivedType = TYPE_LOCAL;
} else if (isDownloads()) {
@@ -188,7 +191,7 @@ public class RootInfo implements Durable, Parcelable {
} else if (isMtp()) {
derivedType = TYPE_MTP;
} else {
- derivedType = TYPE_CLOUD;
+ derivedType = TYPE_OTHER;
}
}
@@ -196,6 +199,13 @@ public class RootInfo implements Durable, Parcelable {
return authority == null && rootId == null;
}
+ public boolean isHome() {
+ // Note that "home" is the expected root id for the auto-created
+ // user home directory on external storage. The "home" value should
+ // match ExternalStorageProvider.ROOT_ID_HOME.
+ return isExternalStorage() && "home".equals(rootId);
+ }
+
public boolean isExternalStorage() {
return "com.android.externalstorage.documents".equals(authority);
}
diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/FilesActivityUiTest.java b/packages/DocumentsUI/tests/src/com/android/documentsui/FilesActivityUiTest.java
index ba91c83b95e8..71d8b34f6773 100644
--- a/packages/DocumentsUI/tests/src/com/android/documentsui/FilesActivityUiTest.java
+++ b/packages/DocumentsUI/tests/src/com/android/documentsui/FilesActivityUiTest.java
@@ -125,6 +125,7 @@ public class FilesActivityUiTest extends InstrumentationTestCase {
"Videos",
"Audio",
"Downloads",
+ "Home",
ROOT_0_ID,
ROOT_1_ID);
}
@@ -136,6 +137,13 @@ public class FilesActivityUiTest extends InstrumentationTestCase {
mBot.assertHasDocuments("file0.log", "file1.png", "file2.csv");
}
+ public void testRootClickSetsWindowTitle() throws Exception {
+ initTestFiles();
+
+ mBot.openRoot("Home");
+ mBot.assertWindowTitle("Home");
+ }
+
public void testFilesList_LiveUpdate() throws Exception {
initTestFiles();
diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/UiBot.java b/packages/DocumentsUI/tests/src/com/android/documentsui/UiBot.java
index 5c09794a3e28..ecad0617c179 100644
--- a/packages/DocumentsUI/tests/src/com/android/documentsui/UiBot.java
+++ b/packages/DocumentsUI/tests/src/com/android/documentsui/UiBot.java
@@ -16,6 +16,8 @@
package com.android.documentsui;
+import static junit.framework.Assert.assertEquals;
+
import android.support.test.uiautomator.By;
import android.support.test.uiautomator.BySelector;
import android.support.test.uiautomator.UiDevice;
@@ -80,6 +82,20 @@ class UiBot {
mDevice.waitForIdle();
}
+ void assertWindowTitle(String expected) {
+ // Turns out the title field on a window does not have
+ // an id associated with it at runtime (which confuses the hell out of me)
+ // In code we address this via "android.R.id.title".
+ UiObject2 o = find(By.text(expected));
+ // It's a bit of a conceit that we then *assert* that the title
+ // is the value that we used to identify the UiObject2.
+ // If the preceeding lookup fails, this'll choke with an NPE.
+ // But given the issue described in the comment above, we're
+ // going to do it anyway. Because we shouldn't be looking up
+ // the uiobject by it's expected content :|
+ assertEquals(expected, o.getText());
+ }
+
void assertHasRoots(String... labels) throws UiObjectNotFoundException {
List<String> missing = new ArrayList<>();
for (String label : labels) {
diff --git a/packages/ExternalStorageProvider/res/values/strings.xml b/packages/ExternalStorageProvider/res/values/strings.xml
index f1c1adefc291..e48436ecb8ba 100644
--- a/packages/ExternalStorageProvider/res/values/strings.xml
+++ b/packages/ExternalStorageProvider/res/values/strings.xml
@@ -20,6 +20,6 @@
<!-- Title for documents backend that offers internal storage. [CHAR LIMIT=24] -->
<string name="root_internal_storage">Internal storage</string>
- <!-- Title for documents backend that offers documents. [CHAR LIMIT=24] -->
- <string name="root_documents">Documents</string>
+ <!-- Title for user home dir. [CHAR LIMIT=24] -->
+ <string name="root_home">Home</string>
</resources>
diff --git a/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java b/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java
index fcd45f223825..2cedc7238434 100644
--- a/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java
+++ b/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java
@@ -85,9 +85,11 @@ public class ExternalStorageProvider extends DocumentsProvider {
public String docId;
public File visiblePath;
public File path;
+ public boolean reportAvailableBytes = true;
}
private static final String ROOT_ID_PRIMARY_EMULATED = "primary";
+ private static final String ROOT_ID_HOME = "home";
private StorageManager mStorageManager;
private Handler mHandler;
@@ -118,6 +120,7 @@ public class ExternalStorageProvider extends DocumentsProvider {
private void updateVolumesLocked() {
mRoots.clear();
+ VolumeInfo primaryVolume = null;
final int userId = UserHandle.myUserId();
final List<VolumeInfo> volumes = mStorageManager.getVolumes();
for (VolumeInfo volume : volumes) {
@@ -126,6 +129,9 @@ public class ExternalStorageProvider extends DocumentsProvider {
final String rootId;
final String title;
if (volume.getType() == VolumeInfo.TYPE_EMULATED) {
+ // save off the primary volume for subsequent "Home" dir initialization.
+ primaryVolume = volume;
+
// We currently only support a single emulated volume mounted at
// a time, and it's always considered the primary
rootId = ROOT_ID_PRIMARY_EMULATED;
@@ -152,25 +158,58 @@ public class ExternalStorageProvider extends DocumentsProvider {
continue;
}
+ final RootInfo root = new RootInfo();
+ mRoots.put(rootId, root);
+
+ root.rootId = rootId;
+ root.flags = Root.FLAG_LOCAL_ONLY | Root.FLAG_ADVANCED
+ | Root.FLAG_SUPPORTS_SEARCH | Root.FLAG_SUPPORTS_IS_CHILD;
+
+ // Dunno when this would NOT be the case, but never hurts to be correct.
+ if (volume.isMountedWritable()) {
+ root.flags |= Root.FLAG_SUPPORTS_CREATE;
+ }
+ root.title = title;
+ if (volume.getType() == VolumeInfo.TYPE_PUBLIC) {
+ root.flags |= Root.FLAG_HAS_SETTINGS;
+ }
+ if (volume.isVisibleForRead(userId)) {
+ root.visiblePath = volume.getPathForUser(userId);
+ } else {
+ root.visiblePath = null;
+ }
+ root.path = volume.getInternalPathForUser(userId);
try {
- final RootInfo root = new RootInfo();
- mRoots.put(rootId, root);
-
- root.rootId = rootId;
- root.flags = Root.FLAG_SUPPORTS_CREATE | Root.FLAG_LOCAL_ONLY | Root.FLAG_ADVANCED
- | Root.FLAG_SUPPORTS_SEARCH | Root.FLAG_SUPPORTS_IS_CHILD;
- root.title = title;
- if (volume.getType() == VolumeInfo.TYPE_PUBLIC) {
- root.flags |= Root.FLAG_HAS_SETTINGS;
- }
- if (volume.isVisibleForRead(userId)) {
- root.visiblePath = volume.getPathForUser(userId);
- } else {
- root.visiblePath = null;
- }
- root.path = volume.getInternalPathForUser(userId);
root.docId = getDocIdForFile(root.path);
+ } catch (FileNotFoundException e) {
+ throw new IllegalStateException(e);
+ }
+ }
+
+ // Finally, if primary storage is available we add the "Home" directory,
+ // creating it as needed.
+ if (primaryVolume != null && primaryVolume.isVisible()) {
+ final RootInfo root = new RootInfo();
+ root.rootId = ROOT_ID_HOME;
+ mRoots.put(root.rootId, root);
+ root.title = getContext().getString(R.string.root_home);
+ // Only report bytes on *volumes*...as a matter of policy.
+ root.reportAvailableBytes = false;
+ root.flags = Root.FLAG_LOCAL_ONLY | Root.FLAG_SUPPORTS_SEARCH
+ | Root.FLAG_SUPPORTS_IS_CHILD;
+
+ // Dunno when this would NOT be the case, but never hurts to be correct.
+ if (primaryVolume.isMountedWritable()) {
+ root.flags |= Root.FLAG_SUPPORTS_CREATE;
+ }
+
+ root.visiblePath = new File(
+ primaryVolume.getPathForUser(userId), root.rootId);
+ root.path = new File(
+ primaryVolume.getInternalPathForUser(userId), root.rootId);
+ try {
+ root.docId = getDocIdForFile(root.path);
} catch (FileNotFoundException e) {
throw new IllegalStateException(e);
}
@@ -312,7 +351,8 @@ public class ExternalStorageProvider extends DocumentsProvider {
row.add(Root.COLUMN_FLAGS, root.flags);
row.add(Root.COLUMN_TITLE, root.title);
row.add(Root.COLUMN_DOCUMENT_ID, root.docId);
- row.add(Root.COLUMN_AVAILABLE_BYTES, root.path.getFreeSpace());
+ row.add(Root.COLUMN_AVAILABLE_BYTES,
+ root.reportAvailableBytes ? root.path.getFreeSpace() : -1);
}
}
return result;