summaryrefslogtreecommitdiffstats
path: root/packages
diff options
context:
space:
mode:
Diffstat (limited to 'packages')
-rw-r--r--packages/DocumentsUI/res/drawable/item_doc_grid.xml19
-rw-r--r--packages/DocumentsUI/res/drawable/item_root.xml22
-rw-r--r--packages/DocumentsUI/res/layout/fragment_directory.xml2
-rw-r--r--packages/DocumentsUI/res/layout/item_doc_grid.xml163
-rw-r--r--packages/DocumentsUI/res/layout/item_doc_list.xml63
-rw-r--r--packages/DocumentsUI/res/layout/item_root.xml10
-rw-r--r--packages/DocumentsUI/res/layout/item_root_header.xml12
-rw-r--r--packages/DocumentsUI/res/layout/item_title.xml14
-rw-r--r--packages/DocumentsUI/res/values/colors.xml1
-rw-r--r--packages/DocumentsUI/res/values/dimens.xml3
-rw-r--r--packages/DocumentsUI/src/com/android/documentsui/CreateDirectoryFragment.java2
-rw-r--r--packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java127
-rw-r--r--packages/DocumentsUI/src/com/android/documentsui/DirectoryLoader.java84
-rw-r--r--packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java162
-rw-r--r--packages/DocumentsUI/src/com/android/documentsui/FilteringCursorWrapper.java119
-rw-r--r--packages/DocumentsUI/src/com/android/documentsui/MimePredicate.java12
-rw-r--r--packages/DocumentsUI/src/com/android/documentsui/RecentLoader.java30
-rw-r--r--packages/DocumentsUI/src/com/android/documentsui/RecentsCreateFragment.java18
-rw-r--r--packages/DocumentsUI/src/com/android/documentsui/RecentsProvider.java172
-rw-r--r--packages/DocumentsUI/src/com/android/documentsui/RootsCache.java5
-rw-r--r--packages/DocumentsUI/src/com/android/documentsui/RootsFragment.java17
-rw-r--r--packages/DocumentsUI/src/com/android/documentsui/model/DocumentInfo.java117
-rw-r--r--packages/DocumentsUI/src/com/android/documentsui/model/DocumentStack.java28
-rw-r--r--packages/DocumentsUI/src/com/android/documentsui/model/RootInfo.java128
-rw-r--r--packages/SystemUI/res/drawable-nodpi/lightning.pngbin2896 -> 0 bytes
-rw-r--r--packages/SystemUI/res/values/arrays.xml11
-rwxr-xr-xpackages/SystemUI/src/com/android/systemui/BatteryMeterView.java113
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java30
28 files changed, 1010 insertions, 474 deletions
diff --git a/packages/DocumentsUI/res/drawable/item_doc_grid.xml b/packages/DocumentsUI/res/drawable/item_doc_grid.xml
new file mode 100644
index 0000000..3f036f7
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable/item_doc_grid.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:drawable="@drawable/ic_grid_card_background" />
+</selector>
diff --git a/packages/DocumentsUI/res/drawable/item_root.xml b/packages/DocumentsUI/res/drawable/item_root.xml
new file mode 100644
index 0000000..183d273
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable/item_root.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:state_pressed="true" android:drawable="@color/item_root_activated" />
+ <item android:state_activated="true" android:drawable="@color/item_root_activated" />
+ <item android:state_focused="true" android:drawable="@color/item_root_activated" />
+ <item android:drawable="@android:color/white" />
+</selector>
diff --git a/packages/DocumentsUI/res/layout/fragment_directory.xml b/packages/DocumentsUI/res/layout/fragment_directory.xml
index 67c5954..881349b 100644
--- a/packages/DocumentsUI/res/layout/fragment_directory.xml
+++ b/packages/DocumentsUI/res/layout/fragment_directory.xml
@@ -38,8 +38,6 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
android:listSelector="@android:color/transparent"
- android:paddingTop="?android:attr/listPreferredItemPaddingStart"
- android:paddingStart="?android:attr/listPreferredItemPaddingStart"
android:visibility="gone" />
<Button
diff --git a/packages/DocumentsUI/res/layout/item_doc_grid.xml b/packages/DocumentsUI/res/layout/item_doc_grid.xml
index 244214b..8d1fc9a 100644
--- a/packages/DocumentsUI/res/layout/item_doc_grid.xml
+++ b/packages/DocumentsUI/res/layout/item_doc_grid.xml
@@ -16,110 +16,111 @@
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
- android:layout_height="180dip"
- android:paddingBottom="?android:attr/listPreferredItemPaddingEnd"
- android:paddingEnd="?android:attr/listPreferredItemPaddingEnd">
+ android:layout_height="@dimen/grid_height"
+ android:background="@drawable/item_doc_grid"
+ android:foreground="@drawable/item_background">
- <FrameLayout
+ <LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:background="@color/chip"
- android:foreground="@drawable/item_background"
- android:duplicateParentState="true">
+ android:paddingBottom="6dp"
+ android:orientation="vertical">
- <LinearLayout
+ <FrameLayout
android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:paddingBottom="6dp"
- android:orientation="vertical">
+ android:layout_height="0dip"
+ android:layout_weight="1"
+ android:background="#fff">
<ImageView
android:id="@android:id/icon"
android:layout_width="match_parent"
- android:layout_height="0dip"
- android:layout_weight="1"
- android:background="#bbb"
+ android:layout_height="match_parent"
android:scaleType="centerInside"
android:contentDescription="@null" />
+ <ImageView
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:scaleType="fitXY"
+ android:src="@drawable/ic_grid_gradient_bg"
+ android:contentDescription="@null" />
+
+ </FrameLayout>
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal"
+ android:paddingTop="6dp"
+ android:paddingStart="?android:attr/listPreferredItemPaddingStart"
+ android:paddingEnd="?android:attr/listPreferredItemPaddingEnd">
+
<TextView
android:id="@android:id/title"
- android:layout_width="match_parent"
+ android:layout_width="0dp"
android:layout_height="wrap_content"
+ android:layout_weight="1"
android:singleLine="true"
android:ellipsize="marquee"
- android:paddingTop="6dp"
- android:paddingStart="?android:attr/listPreferredItemPaddingStart"
- android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
- android:textAppearance="?android:attr/textAppearanceSmall"
+ android:textAppearance="?android:attr/textAppearanceMedium"
android:textAlignment="viewStart" />
- <LinearLayout
- android:id="@+id/summary_grid"
- android:layout_width="match_parent"
+ <ImageView
+ android:id="@android:id/icon1"
+ android:layout_width="@dimen/root_icon_size"
+ android:layout_height="@dimen/root_icon_size"
+ android:layout_marginStart="8dip"
+ android:scaleType="centerInside"
+ android:contentDescription="@null" />
+
+ </LinearLayout>
+
+ <LinearLayout
+ android:id="@+id/line2"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal"
+ android:paddingStart="?android:attr/listPreferredItemPaddingStart"
+ android:paddingEnd="?android:attr/listPreferredItemPaddingEnd">
+
+ <TextView
+ android:id="@+id/date"
+ android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:orientation="horizontal"
- android:paddingStart="?android:attr/listPreferredItemPaddingStart"
- android:paddingEnd="?android:attr/listPreferredItemPaddingEnd">
-
- <ImageView
- android:id="@android:id/icon1"
- android:layout_width="24dip"
- android:layout_height="24dip"
- android:layout_marginEnd="6dip"
- android:scaleType="centerInside"
- android:contentDescription="@null" />
-
- <TextView
- android:id="@android:id/summary"
- android:layout_width="0dp"
- android:layout_height="wrap_content"
- android:layout_weight="1"
- android:layout_gravity="center_vertical"
- android:singleLine="true"
- android:ellipsize="marquee"
- android:textAlignment="viewStart"
- android:textAppearance="?android:attr/textAppearanceSmall" />
-
- </LinearLayout>
-
- <LinearLayout
- android:layout_width="match_parent"
+ android:layout_gravity="center_vertical"
+ android:minWidth="80dp"
+ android:singleLine="true"
+ android:ellipsize="marquee"
+ android:textAlignment="viewStart"
+ android:textAppearance="?android:attr/textAppearanceSmall" />
+
+ <TextView
+ android:id="@+id/size"
+ android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:orientation="horizontal"
- android:paddingStart="?android:attr/listPreferredItemPaddingStart"
- android:paddingEnd="?android:attr/listPreferredItemPaddingEnd">
-
- <View
- android:layout_width="0dip"
- android:layout_height="0dip"
- android:layout_weight="1" />
-
- <TextView
- android:id="@+id/size"
- android:layout_width="70dp"
- android:layout_height="wrap_content"
- android:layout_gravity="center_vertical"
- android:layout_marginEnd="8dp"
- android:singleLine="true"
- android:ellipsize="marquee"
- android:textAlignment="viewEnd"
- android:textAppearance="?android:attr/textAppearanceSmall" />
-
- <TextView
- android:id="@+id/date"
- android:layout_width="70dp"
- android:layout_height="wrap_content"
- android:layout_gravity="center_vertical"
- android:singleLine="true"
- android:ellipsize="marquee"
- android:textAlignment="viewEnd"
- android:textAppearance="?android:attr/textAppearanceSmall" />
-
- </LinearLayout>
+ android:layout_gravity="center_vertical"
+ android:layout_marginStart="8dp"
+ android:minWidth="80dp"
+ android:singleLine="true"
+ android:ellipsize="marquee"
+ android:textAlignment="viewStart"
+ android:textAppearance="?android:attr/textAppearanceSmall" />
+
+ <TextView
+ android:id="@android:id/summary"
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:layout_gravity="center_vertical"
+ android:layout_marginStart="8dp"
+ android:singleLine="true"
+ android:ellipsize="marquee"
+ android:textAlignment="viewStart"
+ android:textAppearance="?android:attr/textAppearanceSmall" />
</LinearLayout>
- </FrameLayout>
+ </LinearLayout>
</FrameLayout>
diff --git a/packages/DocumentsUI/res/layout/item_doc_list.xml b/packages/DocumentsUI/res/layout/item_doc_list.xml
index 37c5881..8372eed 100644
--- a/packages/DocumentsUI/res/layout/item_doc_list.xml
+++ b/packages/DocumentsUI/res/layout/item_doc_list.xml
@@ -27,9 +27,10 @@
<ImageView
android:id="@android:id/icon"
- android:layout_width="@android:dimen/app_icon_size"
- android:layout_height="@android:dimen/app_icon_size"
- android:layout_marginEnd="8dip"
+ android:layout_width="@dimen/icon_size"
+ android:layout_height="@dimen/icon_size"
+ android:layout_marginStart="12dp"
+ android:layout_marginEnd="20dp"
android:layout_gravity="center_vertical"
android:scaleType="centerInside"
android:contentDescription="@null" />
@@ -41,36 +42,43 @@
android:layout_gravity="center_vertical"
android:orientation="vertical">
- <TextView
- android:id="@android:id/title"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:singleLine="true"
- android:ellipsize="marquee"
- android:textAppearance="?android:attr/textAppearanceMedium"
- android:textAlignment="viewStart" />
-
<LinearLayout
- android:id="@+id/summary_list"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
+ <TextView
+ android:id="@android:id/title"
+ android:layout_width="0dip"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:singleLine="true"
+ android:ellipsize="marquee"
+ android:textAppearance="?android:attr/textAppearanceMedium"
+ android:textAlignment="viewStart" />
+
<ImageView
android:id="@android:id/icon1"
- android:layout_width="24dip"
- android:layout_height="24dip"
- android:layout_marginEnd="6dip"
+ android:layout_width="@dimen/root_icon_size"
+ android:layout_height="@dimen/root_icon_size"
+ android:layout_marginStart="8dip"
android:scaleType="centerInside"
android:contentDescription="@null" />
+ </LinearLayout>
+
+ <LinearLayout
+ android:id="@+id/line2"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal">
+
<TextView
- android:id="@android:id/summary"
- android:layout_width="0dp"
+ android:id="@+id/date"
+ android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_weight="1"
android:layout_gravity="center_vertical"
- android:layout_marginEnd="8dp"
+ android:minWidth="70dp"
android:singleLine="true"
android:ellipsize="marquee"
android:textAlignment="viewStart"
@@ -78,23 +86,26 @@
<TextView
android:id="@+id/size"
- android:layout_width="70dp"
+ android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
- android:layout_marginEnd="8dp"
+ android:minWidth="70dp"
+ android:layout_marginStart="8dp"
android:singleLine="true"
android:ellipsize="marquee"
- android:textAlignment="viewEnd"
+ android:textAlignment="viewStart"
android:textAppearance="?android:attr/textAppearanceSmall" />
<TextView
- android:id="@+id/date"
- android:layout_width="70dp"
+ android:id="@android:id/summary"
+ android:layout_width="0dp"
android:layout_height="wrap_content"
+ android:layout_weight="1"
android:layout_gravity="center_vertical"
+ android:layout_marginStart="8dp"
android:singleLine="true"
android:ellipsize="marquee"
- android:textAlignment="viewEnd"
+ android:textAlignment="viewStart"
android:textAppearance="?android:attr/textAppearanceSmall" />
</LinearLayout>
diff --git a/packages/DocumentsUI/res/layout/item_root.xml b/packages/DocumentsUI/res/layout/item_root.xml
index e9cf3aa..ce97b57 100644
--- a/packages/DocumentsUI/res/layout/item_root.xml
+++ b/packages/DocumentsUI/res/layout/item_root.xml
@@ -17,17 +17,17 @@
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:minHeight="?android:attr/listPreferredItemHeight"
+ android:minHeight="?android:attr/listPreferredItemHeightSmall"
android:paddingStart="?android:attr/listPreferredItemPaddingStart"
android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
android:gravity="center_vertical"
- android:orientation="horizontal">
+ android:orientation="horizontal"
+ android:background="@drawable/item_root">
<ImageView
android:id="@android:id/icon"
- android:layout_width="@android:dimen/app_icon_size"
- android:layout_height="@android:dimen/app_icon_size"
- android:layout_rowSpan="2"
+ android:layout_width="@dimen/icon_size"
+ android:layout_height="@dimen/icon_size"
android:layout_marginEnd="8dip"
android:scaleType="centerInside"
android:contentDescription="@null" />
diff --git a/packages/DocumentsUI/res/layout/item_root_header.xml b/packages/DocumentsUI/res/layout/item_root_header.xml
index 2b9a46f..127b254 100644
--- a/packages/DocumentsUI/res/layout/item_root_header.xml
+++ b/packages/DocumentsUI/res/layout/item_root_header.xml
@@ -16,14 +16,4 @@
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@android:id/title"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:paddingStart="?android:attr/listPreferredItemPaddingStart"
- android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
- android:paddingTop="8dp"
- android:paddingBottom="8dp"
- android:singleLine="true"
- android:ellipsize="marquee"
- android:textAllCaps="true"
- android:textAppearance="?android:attr/textAppearanceSmall"
- android:textAlignment="viewStart" />
+ style="?android:attr/listSeparatorTextViewStyle" />
diff --git a/packages/DocumentsUI/res/layout/item_title.xml b/packages/DocumentsUI/res/layout/item_title.xml
index eab3839..9594e4e 100644
--- a/packages/DocumentsUI/res/layout/item_title.xml
+++ b/packages/DocumentsUI/res/layout/item_title.xml
@@ -17,8 +17,20 @@
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
+ android:minHeight="?android:attr/listPreferredItemHeightSmall"
+ android:paddingStart="?android:attr/listPreferredItemPaddingStart"
+ android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
android:gravity="center_vertical"
- android:orientation="vertical">
+ android:orientation="horizontal">
+
+ <ImageView
+ android:id="@+id/subdir"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:scaleType="centerInside"
+ android:visibility="gone"
+ android:src="@drawable/ic_subdirectory_arrow"
+ android:contentDescription="@null" />
<TextView
android:id="@android:id/title"
diff --git a/packages/DocumentsUI/res/values/colors.xml b/packages/DocumentsUI/res/values/colors.xml
index ff3e999..6d62759 100644
--- a/packages/DocumentsUI/res/values/colors.xml
+++ b/packages/DocumentsUI/res/values/colors.xml
@@ -16,4 +16,5 @@
<resources>
<color name="chip">#ddd</color>
+ <color name="item_root_activated">#cccccc</color>
</resources>
diff --git a/packages/DocumentsUI/res/values/dimens.xml b/packages/DocumentsUI/res/values/dimens.xml
index e5c4138..e5b5b4e 100644
--- a/packages/DocumentsUI/res/values/dimens.xml
+++ b/packages/DocumentsUI/res/values/dimens.xml
@@ -15,5 +15,8 @@
-->
<resources>
+ <dimen name="icon_size">32dp</dimen>
+ <dimen name="root_icon_size">24dp</dimen>
<dimen name="grid_width">180dp</dimen>
+ <dimen name="grid_height">180dp</dimen>
</resources>
diff --git a/packages/DocumentsUI/src/com/android/documentsui/CreateDirectoryFragment.java b/packages/DocumentsUI/src/com/android/documentsui/CreateDirectoryFragment.java
index e0b8d19..d8e60aa 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/CreateDirectoryFragment.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/CreateDirectoryFragment.java
@@ -70,7 +70,7 @@ public class CreateDirectoryFragment extends DialogFragment {
try {
final Uri childUri = DocumentsContract.createDocument(
- resolver, cwd.uri, Document.MIME_TYPE_DIR, displayName);
+ resolver, cwd.derivedUri, Document.MIME_TYPE_DIR, displayName);
// Navigate into newly created child
final DocumentInfo childDoc = DocumentInfo.fromUri(resolver, childUri);
diff --git a/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java b/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java
index ba464f7..a13beba 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java
@@ -20,6 +20,8 @@ import static com.android.documentsui.DocumentsActivity.TAG;
import static com.android.documentsui.DocumentsActivity.State.ACTION_MANAGE;
import static com.android.documentsui.DocumentsActivity.State.MODE_GRID;
import static com.android.documentsui.DocumentsActivity.State.MODE_LIST;
+import static com.android.documentsui.DocumentsActivity.State.MODE_UNKNOWN;
+import static com.android.documentsui.DocumentsActivity.State.SORT_ORDER_UNKNOWN;
import static com.android.documentsui.model.DocumentInfo.getCursorInt;
import static com.android.documentsui.model.DocumentInfo.getCursorLong;
import static com.android.documentsui.model.DocumentInfo.getCursorString;
@@ -91,43 +93,42 @@ public class DirectoryFragment extends Fragment {
private int mType = TYPE_NORMAL;
+ private int mLastMode = MODE_UNKNOWN;
+ private int mLastSortOrder = SORT_ORDER_UNKNOWN;
+
private Point mThumbSize;
private DocumentsAdapter mAdapter;
private LoaderCallbacks<DirectoryResult> mCallbacks;
private static final String EXTRA_TYPE = "type";
- private static final String EXTRA_AUTHORITY = "authority";
- private static final String EXTRA_ROOT_ID = "rootId";
- private static final String EXTRA_DOC_ID = "docId";
+ private static final String EXTRA_ROOT = "root";
+ private static final String EXTRA_DOC = "doc";
private static final String EXTRA_QUERY = "query";
private static AtomicInteger sLoaderId = new AtomicInteger(4000);
- private int mLastSortOrder = -1;
-
private final int mLoaderId = sLoaderId.incrementAndGet();
- public static void showNormal(FragmentManager fm, Uri uri) {
- show(fm, TYPE_NORMAL, uri.getAuthority(), null, DocumentsContract.getDocumentId(uri), null);
+ public static void showNormal(FragmentManager fm, RootInfo root, DocumentInfo doc) {
+ show(fm, TYPE_NORMAL, root, doc, null);
}
- public static void showSearch(FragmentManager fm, Uri uri, String query) {
- show(fm, TYPE_SEARCH, uri.getAuthority(), null, DocumentsContract.getDocumentId(uri),
- query);
+ public static void showSearch(
+ FragmentManager fm, RootInfo root, DocumentInfo doc, String query) {
+ show(fm, TYPE_SEARCH, root, doc, query);
}
public static void showRecentsOpen(FragmentManager fm) {
- show(fm, TYPE_RECENT_OPEN, null, null, null, null);
+ show(fm, TYPE_RECENT_OPEN, null, null, null);
}
- private static void show(FragmentManager fm, int type, String authority, String rootId,
- String docId, String query) {
+ private static void show(
+ FragmentManager fm, int type, RootInfo root, DocumentInfo doc, String query) {
final Bundle args = new Bundle();
args.putInt(EXTRA_TYPE, type);
- args.putString(EXTRA_AUTHORITY, authority);
- args.putString(EXTRA_ROOT_ID, rootId);
- args.putString(EXTRA_DOC_ID, docId);
+ args.putParcelable(EXTRA_ROOT, root);
+ args.putParcelable(EXTRA_DOC, doc);
args.putString(EXTRA_QUERY, query);
final DirectoryFragment fragment = new DirectoryFragment();
@@ -167,6 +168,7 @@ public class DirectoryFragment extends Fragment {
super.onActivityCreated(savedInstanceState);
final Context context = getActivity();
+ final State state = getDisplayState(DirectoryFragment.this);
mAdapter = new DocumentsAdapter();
mType = getArguments().getInt(EXTRA_TYPE);
@@ -174,35 +176,48 @@ public class DirectoryFragment extends Fragment {
mCallbacks = new LoaderCallbacks<DirectoryResult>() {
@Override
public Loader<DirectoryResult> onCreateLoader(int id, Bundle args) {
- final State state = getDisplayState(DirectoryFragment.this);
-
- final String authority = getArguments().getString(EXTRA_AUTHORITY);
- final String rootId = getArguments().getString(EXTRA_ROOT_ID);
- final String docId = getArguments().getString(EXTRA_DOC_ID);
+ final RootInfo root = getArguments().getParcelable(EXTRA_ROOT);
+ final DocumentInfo doc = getArguments().getParcelable(EXTRA_DOC);
final String query = getArguments().getString(EXTRA_QUERY);
Uri contentsUri;
switch (mType) {
case TYPE_NORMAL:
- contentsUri = DocumentsContract.buildChildDocumentsUri(authority, docId);
- return new DirectoryLoader(context, rootId, contentsUri, state.sortOrder);
+ contentsUri = DocumentsContract.buildChildDocumentsUri(
+ doc.authority, doc.documentId);
+ return new DirectoryLoader(context, root, doc, contentsUri);
case TYPE_SEARCH:
contentsUri = DocumentsContract.buildSearchDocumentsUri(
- authority, docId, query);
- return new DirectoryLoader(context, rootId, contentsUri, state.sortOrder);
+ doc.authority, doc.documentId, query);
+ return new DirectoryLoader(context, root, doc, contentsUri);
case TYPE_RECENT_OPEN:
final RootsCache roots = DocumentsApplication.getRootsCache(context);
final List<RootInfo> matchingRoots = roots.getMatchingRoots(state);
- return new RecentLoader(context, matchingRoots);
+ return new RecentLoader(context, matchingRoots, state.acceptMimes);
default:
throw new IllegalStateException("Unknown type " + mType);
-
}
}
@Override
public void onLoadFinished(Loader<DirectoryResult> loader, DirectoryResult result) {
+ if (!isAdded()) return;
+
mAdapter.swapCursor(result.cursor);
+
+ // Push latest state up to UI
+ // TODO: if mode change was racing with us, don't overwrite it
+ state.mode = result.mode;
+ state.sortOrder = result.sortOrder;
+ ((DocumentsActivity) context).onStateChanged();
+
+ updateDisplayState();
+
+ if (mLastSortOrder != result.sortOrder) {
+ mLastSortOrder = result.sortOrder;
+ mListView.smoothScrollToPosition(0);
+ mGridView.smoothScrollToPosition(0);
+ }
}
@Override
@@ -211,25 +226,39 @@ public class DirectoryFragment extends Fragment {
}
};
+ // Kick off loader at least once
+ getLoaderManager().restartLoader(mLoaderId, null, mCallbacks);
+
+ updateDisplayState();
+ }
+
+ @Override
+ public void onStart() {
+ super.onStart();
updateDisplayState();
}
- public void updateDisplayState() {
+ public void onUserSortOrderChanged() {
+ // User change always triggers reload
+ getLoaderManager().restartLoader(mLoaderId, null, mCallbacks);
+ }
+
+ public void onUserModeChanged() {
+ // Mode change is just display; no need to reload
+ updateDisplayState();
+ }
+
+ private void updateDisplayState() {
final State state = getDisplayState(this);
- if (mLastSortOrder != state.sortOrder) {
- getLoaderManager().restartLoader(mLoaderId, null, mCallbacks);
- mLastSortOrder = state.sortOrder;
- }
+ mFilter = new MimePredicate(state.acceptMimes);
- mListView.smoothScrollToPosition(0);
- mGridView.smoothScrollToPosition(0);
+ if (mLastMode == state.mode) return;
+ mLastMode = state.mode;
mListView.setVisibility(state.mode == MODE_LIST ? View.VISIBLE : View.GONE);
mGridView.setVisibility(state.mode == MODE_GRID ? View.VISIBLE : View.GONE);
- mFilter = new MimePredicate(state.acceptMimes);
-
final int choiceMode;
if (state.allowMultiple) {
choiceMode = ListView.CHOICE_MODE_MULTIPLE_MODAL;
@@ -248,14 +277,14 @@ public class DirectoryFragment extends Fragment {
mGridView.setChoiceMode(choiceMode);
mCurrentView = mGridView;
} else if (state.mode == MODE_LIST) {
- thumbSize = getResources().getDimensionPixelSize(android.R.dimen.app_icon_size);
+ thumbSize = getResources().getDimensionPixelSize(R.dimen.icon_size);
mGridView.setAdapter(null);
mGridView.setChoiceMode(ListView.CHOICE_MODE_NONE);
mListView.setAdapter(mAdapter);
mListView.setChoiceMode(choiceMode);
mCurrentView = mListView;
} else {
- throw new IllegalStateException();
+ throw new IllegalStateException("Unknown state " + state.mode);
}
mThumbSize = new Point(thumbSize, thumbSize);
@@ -360,7 +389,7 @@ public class DirectoryFragment extends Fragment {
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
intent.addCategory(Intent.CATEGORY_DEFAULT);
intent.setType(doc.mimeType);
- intent.putExtra(Intent.EXTRA_STREAM, doc.uri);
+ intent.putExtra(Intent.EXTRA_STREAM, doc.derivedUri);
} else if (docs.size() > 1) {
intent = new Intent(Intent.ACTION_SEND_MULTIPLE);
@@ -371,7 +400,7 @@ public class DirectoryFragment extends Fragment {
final ArrayList<Uri> uris = Lists.newArrayList();
for (DocumentInfo doc : docs) {
mimeTypes.add(doc.mimeType);
- uris.add(doc.uri);
+ uris.add(doc.derivedUri);
}
intent.setType(findCommonMimeType(mimeTypes));
@@ -397,7 +426,7 @@ public class DirectoryFragment extends Fragment {
continue;
}
- if (!DocumentsContract.deleteDocument(resolver, doc.uri)) {
+ if (!DocumentsContract.deleteDocument(resolver, doc.derivedUri)) {
Log.w(TAG, "Failed to delete " + doc);
hadTrouble = true;
}
@@ -541,7 +570,7 @@ public class DirectoryFragment extends Fragment {
final ImageView icon = (ImageView) convertView.findViewById(android.R.id.icon);
final TextView title = (TextView) convertView.findViewById(android.R.id.title);
- final View summaryGrid = convertView.findViewById(R.id.summary_grid);
+ final View line2 = convertView.findViewById(R.id.line2);
final ImageView icon1 = (ImageView) convertView.findViewById(android.R.id.icon1);
final TextView summary = (TextView) convertView.findViewById(android.R.id.summary);
final TextView date = (TextView) convertView.findViewById(R.id.date);
@@ -571,31 +600,32 @@ public class DirectoryFragment extends Fragment {
title.setText(docDisplayName);
+ boolean hasLine2 = false;
+
if (mType == TYPE_RECENT_OPEN) {
final RootInfo root = roots.getRoot(docAuthority, docRootId);
icon1.setVisibility(View.VISIBLE);
icon1.setImageDrawable(root.loadIcon(context));
summary.setText(root.getDirectoryString());
summary.setVisibility(View.VISIBLE);
+ summary.setTextAlignment(TextView.TEXT_ALIGNMENT_TEXT_END);
+ hasLine2 = true;
} else {
icon1.setVisibility(View.GONE);
if (docSummary != null) {
summary.setText(docSummary);
summary.setVisibility(View.VISIBLE);
+ hasLine2 = true;
} else {
summary.setVisibility(View.INVISIBLE);
}
}
- if (summaryGrid != null) {
- summaryGrid.setVisibility(
- (summary.getVisibility() == View.VISIBLE) ? View.VISIBLE : View.GONE);
- }
-
if (docLastModified == -1) {
date.setText(null);
} else {
date.setText(formatTime(context, docLastModified));
+ hasLine2 = true;
}
if (state.showSize) {
@@ -604,11 +634,14 @@ public class DirectoryFragment extends Fragment {
size.setText(null);
} else {
size.setText(Formatter.formatFileSize(context, docSize));
+ hasLine2 = true;
}
} else {
size.setVisibility(View.GONE);
}
+ line2.setVisibility(hasLine2 ? View.VISIBLE : View.GONE);
+
return convertView;
}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/DirectoryLoader.java b/packages/DocumentsUI/src/com/android/documentsui/DirectoryLoader.java
index 6ea57d7..72dfa30 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/DirectoryLoader.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/DirectoryLoader.java
@@ -16,18 +16,29 @@
package com.android.documentsui;
+import static com.android.documentsui.DocumentsActivity.TAG;
+import static com.android.documentsui.DocumentsActivity.State.MODE_UNKNOWN;
import static com.android.documentsui.DocumentsActivity.State.SORT_ORDER_DISPLAY_NAME;
import static com.android.documentsui.DocumentsActivity.State.SORT_ORDER_LAST_MODIFIED;
import static com.android.documentsui.DocumentsActivity.State.SORT_ORDER_SIZE;
+import static com.android.documentsui.DocumentsActivity.State.SORT_ORDER_UNKNOWN;
+import static com.android.documentsui.model.DocumentInfo.getCursorInt;
import android.content.AsyncTaskLoader;
import android.content.ContentProviderClient;
+import android.content.ContentResolver;
import android.content.Context;
import android.database.Cursor;
import android.net.Uri;
import android.os.CancellationSignal;
import android.os.OperationCanceledException;
import android.provider.DocumentsContract.Document;
+import android.util.Log;
+
+import com.android.documentsui.DocumentsActivity.State;
+import com.android.documentsui.RecentsProvider.StateColumns;
+import com.android.documentsui.model.DocumentInfo;
+import com.android.documentsui.model.RootInfo;
import libcore.io.IoUtils;
@@ -36,6 +47,9 @@ class DirectoryResult implements AutoCloseable {
Cursor cursor;
Exception exception;
+ int mode = MODE_UNKNOWN;
+ int sortOrder = SORT_ORDER_UNKNOWN;
+
@Override
public void close() {
IoUtils.closeQuietly(cursor);
@@ -48,18 +62,18 @@ class DirectoryResult implements AutoCloseable {
public class DirectoryLoader extends AsyncTaskLoader<DirectoryResult> {
private final ForceLoadContentObserver mObserver = new ForceLoadContentObserver();
- private final String mRootId;
+ private final RootInfo mRoot;
+ private final DocumentInfo mDoc;
private final Uri mUri;
- private final int mSortOrder;
private CancellationSignal mSignal;
private DirectoryResult mResult;
- public DirectoryLoader(Context context, String rootId, Uri uri, int sortOrder) {
+ public DirectoryLoader(Context context, RootInfo root, DocumentInfo doc, Uri uri) {
super(context);
- mRootId = rootId;
+ mRoot = root;
+ mDoc = doc;
mUri = uri;
- mSortOrder = sortOrder;
}
@Override
@@ -70,20 +84,65 @@ public class DirectoryLoader extends AsyncTaskLoader<DirectoryResult> {
}
mSignal = new CancellationSignal();
}
- final DirectoryResult result = new DirectoryResult();
+
+ final ContentResolver resolver = getContext().getContentResolver();
final String authority = mUri.getAuthority();
+
+ final DirectoryResult result = new DirectoryResult();
+
+ int userMode = State.MODE_UNKNOWN;
+ int userSortOrder = State.SORT_ORDER_UNKNOWN;
+
+ // Pick up any custom modes requested by user
+ Cursor cursor = null;
try {
- result.client = getContext()
- .getContentResolver().acquireUnstableContentProviderClient(authority);
- final Cursor cursor = result.client.query(
- mUri, null, null, null, getQuerySortOrder(mSortOrder), mSignal);
+ final Uri stateUri = RecentsProvider.buildState(
+ mRoot.authority, mRoot.rootId, mDoc.documentId);
+ cursor = resolver.query(stateUri, null, null, null, null);
+ if (cursor.moveToFirst()) {
+ userMode = getCursorInt(cursor, StateColumns.MODE);
+ userSortOrder = getCursorInt(cursor, StateColumns.SORT_ORDER);
+ }
+ } finally {
+ IoUtils.closeQuietly(cursor);
+ }
+
+ if (userMode != State.MODE_UNKNOWN) {
+ result.mode = userMode;
+ } else {
+ if ((mDoc.flags & Document.FLAG_DIR_PREFERS_GRID) != 0) {
+ result.mode = State.MODE_GRID;
+ } else {
+ result.mode = State.MODE_LIST;
+ }
+ }
+
+ if (userSortOrder != State.SORT_ORDER_UNKNOWN) {
+ result.sortOrder = userSortOrder;
+ } else {
+ if ((mDoc.flags & Document.FLAG_DIR_PREFERS_LAST_MODIFIED) != 0) {
+ result.sortOrder = State.SORT_ORDER_LAST_MODIFIED;
+ } else {
+ result.sortOrder = State.SORT_ORDER_DISPLAY_NAME;
+ }
+ }
+
+ Log.d(TAG, "userMode=" + userMode + ", userSortOrder=" + userSortOrder + " --> mode="
+ + result.mode + ", sortOrder=" + result.sortOrder);
+
+ try {
+ result.client = resolver.acquireUnstableContentProviderClient(authority);
+ cursor = result.client.query(
+ mUri, null, null, null, getQuerySortOrder(result.sortOrder), mSignal);
cursor.registerContentObserver(mObserver);
- final Cursor withRoot = new RootCursorWrapper(mUri.getAuthority(), mRootId, cursor, -1);
- final Cursor sorted = new SortingCursorWrapper(withRoot, mSortOrder);
+ final Cursor withRoot = new RootCursorWrapper(
+ mUri.getAuthority(), mRoot.rootId, cursor, -1);
+ final Cursor sorted = new SortingCursorWrapper(withRoot, result.sortOrder);
result.cursor = sorted;
} catch (Exception e) {
+ Log.d(TAG, "Failed to query", e);
result.exception = e;
ContentProviderClient.closeQuietly(result.client);
} finally {
@@ -91,6 +150,7 @@ public class DirectoryLoader extends AsyncTaskLoader<DirectoryResult> {
mSignal = null;
}
}
+
return result;
}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java b/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java
index e1f2606..fe39800 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java
@@ -53,12 +53,16 @@ import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
+import android.widget.ImageView;
import android.widget.SearchView;
import android.widget.SearchView.OnCloseListener;
import android.widget.SearchView.OnQueryTextListener;
import android.widget.TextView;
import android.widget.Toast;
+import com.android.documentsui.RecentsProvider.RecentColumns;
+import com.android.documentsui.RecentsProvider.ResumeColumns;
+import com.android.documentsui.RecentsProvider.StateColumns;
import com.android.documentsui.model.DocumentInfo;
import com.android.documentsui.model.DocumentStack;
import com.android.documentsui.model.DurableUtils;
@@ -190,7 +194,7 @@ public class DocumentsActivity extends Activity {
try {
if (cursor.moveToFirst()) {
final byte[] rawStack = cursor.getBlob(
- cursor.getColumnIndex(RecentsProvider.COL_PATH));
+ cursor.getColumnIndex(ResumeColumns.STACK));
DurableUtils.readFromArray(rawStack, mState.stack);
}
} catch (IOException e) {
@@ -203,7 +207,7 @@ public class DocumentsActivity extends Activity {
final RootInfo root = getCurrentRoot();
final List<RootInfo> matchingRoots = mRoots.getMatchingRoots(mState);
if (!matchingRoots.contains(root)) {
- mState.stack.clear();
+ mState.stack.reset();
}
// Only open drawer when showing recents
@@ -342,11 +346,16 @@ public class DocumentsActivity extends Activity {
final MenuItem list = menu.findItem(R.id.menu_list);
final MenuItem settings = menu.findItem(R.id.menu_settings);
- grid.setVisible(mState.mode != MODE_GRID);
- list.setVisible(mState.mode != MODE_LIST);
+ if (cwd != null) {
+ sort.setVisible(true);
+ grid.setVisible(mState.mode != MODE_GRID);
+ list.setVisible(mState.mode != MODE_LIST);
+ } else {
+ sort.setVisible(false);
+ grid.setVisible(false);
+ list.setVisible(false);
+ }
- // No sorting in recents
- sort.setVisible(cwd != null);
// Only sort by size when visible
sortSize.setVisible(mState.showSize);
@@ -391,28 +400,19 @@ public class DocumentsActivity extends Activity {
} else if (id == R.id.menu_search) {
return false;
} else if (id == R.id.menu_sort_name) {
- mState.sortOrder = State.SORT_ORDER_DISPLAY_NAME;
- updateDisplayState();
+ setUserSortOrder(State.SORT_ORDER_DISPLAY_NAME);
return true;
} else if (id == R.id.menu_sort_date) {
- mState.sortOrder = State.SORT_ORDER_LAST_MODIFIED;
- updateDisplayState();
+ setUserSortOrder(State.SORT_ORDER_LAST_MODIFIED);
return true;
} else if (id == R.id.menu_sort_size) {
- mState.sortOrder = State.SORT_ORDER_SIZE;
- updateDisplayState();
+ setUserSortOrder(State.SORT_ORDER_SIZE);
return true;
} else if (id == R.id.menu_grid) {
- // TODO: persist explicit user mode for cwd
- mState.mode = MODE_GRID;
- updateDisplayState();
- invalidateOptionsMenu();
+ setUserMode(State.MODE_GRID);
return true;
} else if (id == R.id.menu_list) {
- // TODO: persist explicit user mode for cwd
- mState.mode = MODE_LIST;
- updateDisplayState();
- invalidateOptionsMenu();
+ setUserMode(State.MODE_LIST);
return true;
} else if (id == R.id.menu_settings) {
startActivity(new Intent(this, SettingsActivity.class));
@@ -422,6 +422,51 @@ public class DocumentsActivity extends Activity {
}
}
+ /**
+ * Update UI to reflect internal state changes not from user.
+ */
+ public void onStateChanged() {
+ invalidateOptionsMenu();
+ }
+
+ /**
+ * Set state sort order based on explicit user action.
+ */
+ private void setUserSortOrder(int sortOrder) {
+ final RootInfo root = getCurrentRoot();
+ final DocumentInfo cwd = getCurrentDirectory();
+
+ // TODO: persist async, then trigger rebind
+ final Uri stateUri = RecentsProvider.buildState(
+ root.authority, root.rootId, cwd.documentId);
+ final ContentValues values = new ContentValues();
+ values.put(StateColumns.SORT_ORDER, sortOrder);
+ getContentResolver().insert(stateUri, values);
+
+ DirectoryFragment.get(getFragmentManager()).onUserSortOrderChanged();
+ onStateChanged();
+ }
+
+ /**
+ * Set state mode based on explicit user action.
+ */
+ private void setUserMode(int mode) {
+ final RootInfo root = getCurrentRoot();
+ final DocumentInfo cwd = getCurrentDirectory();
+
+ // TODO: persist async, then trigger rebind
+ final Uri stateUri = RecentsProvider.buildState(
+ root.authority, root.rootId, cwd.documentId);
+ final ContentValues values = new ContentValues();
+ values.put(StateColumns.MODE, mode);
+ getContentResolver().insert(stateUri, values);
+
+ mState.mode = mode;
+
+ DirectoryFragment.get(getFragmentManager()).onUserModeChanged();
+ onStateChanged();
+ }
+
@Override
public void onBackPressed() {
final int size = mState.stack.size();
@@ -481,6 +526,8 @@ public class DocumentsActivity extends Activity {
title.setText(doc.displayName);
}
+ // No padding when shown in actionbar
+ convertView.setPadding(0, 0, 0, 0);
return convertView;
}
@@ -488,17 +535,20 @@ public class DocumentsActivity extends Activity {
public View getDropDownView(int position, View convertView, ViewGroup parent) {
if (convertView == null) {
convertView = LayoutInflater.from(parent.getContext())
- .inflate(android.R.layout.simple_dropdown_item_1line, parent, false);
+ .inflate(R.layout.item_title, parent, false);
}
- final TextView text1 = (TextView) convertView.findViewById(android.R.id.text1);
+ final ImageView subdir = (ImageView) convertView.findViewById(R.id.subdir);
+ final TextView title = (TextView) convertView.findViewById(android.R.id.title);
final DocumentInfo doc = getItem(position);
if (position == 0) {
final RootInfo root = getCurrentRoot();
- text1.setText(root.title);
+ title.setText(root.title);
+ subdir.setVisibility(View.GONE);
} else {
- text1.setText(doc.displayName);
+ title.setText(doc.displayName);
+ subdir.setVisibility(View.VISIBLE);
}
return convertView;
@@ -522,8 +572,8 @@ public class DocumentsActivity extends Activity {
};
public RootInfo getCurrentRoot() {
- if (mState.stack.size() > 0) {
- return mState.stack.getRoot(mRoots);
+ if (mState.stack.root != null) {
+ return mState.stack.root;
} else {
return mRoots.getRecentsRoot();
}
@@ -539,6 +589,7 @@ public class DocumentsActivity extends Activity {
private void onCurrentDirectoryChanged() {
final FragmentManager fm = getFragmentManager();
+ final RootInfo root = getCurrentRoot();
final DocumentInfo cwd = getCurrentDirectory();
if (cwd == null) {
@@ -551,10 +602,10 @@ public class DocumentsActivity extends Activity {
} else {
if (mState.currentSearch != null) {
// Ongoing search
- DirectoryFragment.showSearch(fm, cwd.uri, mState.currentSearch);
+ DirectoryFragment.showSearch(fm, root, cwd, mState.currentSearch);
} else {
// Normal boring directory
- DirectoryFragment.showNormal(fm, cwd.uri);
+ DirectoryFragment.showNormal(fm, root, cwd);
}
}
@@ -566,16 +617,16 @@ public class DocumentsActivity extends Activity {
}
}
+ final RootsFragment roots = RootsFragment.get(fm);
+ if (roots != null) {
+ roots.onCurrentRootChanged();
+ }
+
updateActionBar();
invalidateOptionsMenu();
dumpStack();
}
- private void updateDisplayState() {
- // TODO: handle multiple directory stacks on tablets
- DirectoryFragment.get(getFragmentManager()).updateDisplayState();
- }
-
public void onStackPicked(DocumentStack stack) {
mState.stack = stack;
onCurrentDirectoryChanged();
@@ -583,6 +634,7 @@ public class DocumentsActivity extends Activity {
public void onRootPicked(RootInfo root, boolean closeDrawer) {
// Clear entire backstack and start in new root
+ mState.stack.root = root;
mState.stack.clear();
if (!mRoots.isRecentsRoot(root)) {
@@ -622,7 +674,7 @@ public class DocumentsActivity extends Activity {
onCurrentDirectoryChanged();
} else if (mState.action == ACTION_OPEN || mState.action == ACTION_GET_CONTENT) {
// Explicit file picked, return
- onFinished(doc.uri);
+ onFinished(doc.derivedUri);
} else if (mState.action == ACTION_CREATE) {
// Replace selected file
SaveFragment.get(fm).setReplaceTarget(doc);
@@ -630,7 +682,7 @@ public class DocumentsActivity extends Activity {
// First try managing the document; we expect manager to filter
// based on authority, so we don't grant.
final Intent manage = new Intent(DocumentsContract.ACTION_MANAGE_DOCUMENT);
- manage.setData(doc.uri);
+ manage.setData(doc.derivedUri);
try {
startActivity(manage);
@@ -638,7 +690,7 @@ public class DocumentsActivity extends Activity {
// Fall back to viewing
final Intent view = new Intent(Intent.ACTION_VIEW);
view.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
- view.setData(doc.uri);
+ view.setData(doc.derivedUri);
try {
startActivity(view);
@@ -654,22 +706,21 @@ public class DocumentsActivity extends Activity {
final int size = docs.size();
final Uri[] uris = new Uri[size];
for (int i = 0; i < size; i++) {
- uris[i] = docs.get(i).uri;
+ uris[i] = docs.get(i).derivedUri;
}
onFinished(uris);
}
}
public void onSaveRequested(DocumentInfo replaceTarget) {
- onFinished(replaceTarget.uri);
+ onFinished(replaceTarget.derivedUri);
}
public void onSaveRequested(String mimeType, String displayName) {
final DocumentInfo cwd = getCurrentDirectory();
- final String authority = cwd.uri.getAuthority();
final Uri childUri = DocumentsContract.createDocument(
- getContentResolver(), cwd.uri, mimeType, displayName);
+ getContentResolver(), cwd.derivedUri, mimeType, displayName);
if (childUri != null) {
onFinished(childUri);
} else {
@@ -687,22 +738,14 @@ public class DocumentsActivity extends Activity {
if (mState.action == ACTION_CREATE) {
// Remember stack for last create
values.clear();
- values.put(RecentsProvider.COL_PATH, rawStack);
- resolver.insert(RecentsProvider.buildRecentCreate(), values);
-
- } else if (mState.action == ACTION_OPEN || mState.action == ACTION_GET_CONTENT) {
- // Remember opened items
- for (Uri uri : uris) {
- values.clear();
- values.put(RecentsProvider.COL_URI, uri.toString());
- resolver.insert(RecentsProvider.buildRecentOpen(), values);
- }
+ values.put(RecentColumns.STACK, rawStack);
+ resolver.insert(RecentsProvider.buildRecent(), values);
}
// Remember location for next app launch
final String packageName = getCallingPackage();
values.clear();
- values.put(RecentsProvider.COL_PATH, rawStack);
+ values.put(ResumeColumns.STACK, rawStack);
resolver.insert(RecentsProvider.buildResume(packageName), values);
final Intent intent = new Intent();
@@ -749,12 +792,14 @@ public class DocumentsActivity extends Activity {
public static final int ACTION_GET_CONTENT = 3;
public static final int ACTION_MANAGE = 4;
- public static final int MODE_LIST = 0;
- public static final int MODE_GRID = 1;
+ public static final int MODE_UNKNOWN = 0;
+ public static final int MODE_LIST = 1;
+ public static final int MODE_GRID = 2;
- public static final int SORT_ORDER_DISPLAY_NAME = 0;
- public static final int SORT_ORDER_LAST_MODIFIED = 1;
- public static final int SORT_ORDER_SIZE = 2;
+ public static final int SORT_ORDER_UNKNOWN = 0;
+ public static final int SORT_ORDER_DISPLAY_NAME = 1;
+ public static final int SORT_ORDER_LAST_MODIFIED = 2;
+ public static final int SORT_ORDER_SIZE = 3;
@Override
public int describeContents() {
@@ -800,9 +845,10 @@ public class DocumentsActivity extends Activity {
}
private void dumpStack() {
- Log.d(TAG, "Current stack:");
+ Log.d(TAG, "Current stack: ");
+ Log.d(TAG, " * " + mState.stack.root);
for (DocumentInfo doc : mState.stack) {
- Log.d(TAG, "--> " + doc);
+ Log.d(TAG, " +-- " + doc);
}
}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/FilteringCursorWrapper.java b/packages/DocumentsUI/src/com/android/documentsui/FilteringCursorWrapper.java
new file mode 100644
index 0000000..60f0103
--- /dev/null
+++ b/packages/DocumentsUI/src/com/android/documentsui/FilteringCursorWrapper.java
@@ -0,0 +1,119 @@
+/*
+ * 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 static com.android.documentsui.DocumentsActivity.TAG;
+
+import android.database.AbstractCursor;
+import android.database.Cursor;
+import android.os.Bundle;
+import android.provider.DocumentsContract.Document;
+import android.util.Log;
+
+/**
+ * Cursor wrapper that filters MIME types not matching given list.
+ */
+public class FilteringCursorWrapper extends AbstractCursor {
+ private final Cursor mCursor;
+
+ private final int[] mPosition;
+ private int mCount;
+
+ public FilteringCursorWrapper(Cursor cursor, String[] acceptMimes) {
+ mCursor = cursor;
+
+ final int count = cursor.getCount();
+ mPosition = new int[count];
+
+ cursor.moveToPosition(-1);
+ while (cursor.moveToNext()) {
+ final String mimeType = cursor.getString(
+ cursor.getColumnIndex(Document.COLUMN_MIME_TYPE));
+ if (MimePredicate.mimeMatches(acceptMimes, mimeType)) {
+ mPosition[mCount++] = cursor.getPosition();
+ }
+ }
+
+ Log.d(TAG, "Before filtering " + cursor.getCount() + ", after " + mCount);
+ }
+
+ @Override
+ public Bundle getExtras() {
+ return mCursor.getExtras();
+ }
+
+ @Override
+ public void close() {
+ super.close();
+ mCursor.close();
+ }
+
+ @Override
+ public boolean onMove(int oldPosition, int newPosition) {
+ return mCursor.moveToPosition(mPosition[newPosition]);
+ }
+
+ @Override
+ public String[] getColumnNames() {
+ return mCursor.getColumnNames();
+ }
+
+ @Override
+ public int getCount() {
+ return mCount;
+ }
+
+ @Override
+ public double getDouble(int column) {
+ return mCursor.getDouble(column);
+ }
+
+ @Override
+ public float getFloat(int column) {
+ return mCursor.getFloat(column);
+ }
+
+ @Override
+ public int getInt(int column) {
+ return mCursor.getInt(column);
+ }
+
+ @Override
+ public long getLong(int column) {
+ return mCursor.getLong(column);
+ }
+
+ @Override
+ public short getShort(int column) {
+ return mCursor.getShort(column);
+ }
+
+ @Override
+ public String getString(int column) {
+ return mCursor.getString(column);
+ }
+
+ @Override
+ public int getType(int column) {
+ return mCursor.getType(column);
+ }
+
+ @Override
+ public boolean isNull(int column) {
+ return mCursor.isNull(column);
+ }
+}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/MimePredicate.java b/packages/DocumentsUI/src/com/android/documentsui/MimePredicate.java
index 85d0988..b55ce82 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/MimePredicate.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/MimePredicate.java
@@ -49,6 +49,18 @@ public class MimePredicate implements Predicate<DocumentInfo> {
return false;
}
+ public static boolean mimeMatches(String filter, String[] tests) {
+ if (tests == null) {
+ return true;
+ }
+ for (String test : tests) {
+ if (mimeMatches(filter, test)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
public static boolean mimeMatches(String[] filters, String test) {
if (filters == null) {
return true;
diff --git a/packages/DocumentsUI/src/com/android/documentsui/RecentLoader.java b/packages/DocumentsUI/src/com/android/documentsui/RecentLoader.java
index 756a297..57442a0 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/RecentLoader.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/RecentLoader.java
@@ -17,6 +17,9 @@
package com.android.documentsui;
import static com.android.documentsui.DocumentsActivity.TAG;
+import static com.android.documentsui.DocumentsActivity.State.MODE_GRID;
+import static com.android.documentsui.DocumentsActivity.State.MODE_LIST;
+import static com.android.documentsui.DocumentsActivity.State.SORT_ORDER_LAST_MODIFIED;
import android.content.AsyncTaskLoader;
import android.content.ContentProviderClient;
@@ -79,6 +82,7 @@ public class RecentLoader extends AsyncTaskLoader<DirectoryResult> {
}
private final List<RootInfo> mRoots;
+ private final String[] mAcceptMimes;
private final HashMap<RootInfo, RecentTask> mTasks = Maps.newHashMap();
@@ -135,9 +139,10 @@ public class RecentLoader extends AsyncTaskLoader<DirectoryResult> {
}
}
- public RecentLoader(Context context, List<RootInfo> roots) {
+ public RecentLoader(Context context, List<RootInfo> roots, String[] acceptMimes) {
super(context);
mRoots = roots;
+ mAcceptMimes = acceptMimes;
}
@Override
@@ -171,7 +176,15 @@ public class RecentLoader extends AsyncTaskLoader<DirectoryResult> {
for (RecentTask task : mTasks.values()) {
if (task.isDone()) {
try {
- cursors.add(task.get());
+ final Cursor cursor = task.get();
+ final FilteringCursorWrapper filtered = new FilteringCursorWrapper(
+ cursor, mAcceptMimes) {
+ @Override
+ public void close() {
+ // Ignored, since we manage cursor lifecycle internally
+ }
+ };
+ cursors.add(filtered);
} catch (InterruptedException e) {
throw new RuntimeException(e);
} catch (ExecutionException e) {
@@ -181,15 +194,14 @@ public class RecentLoader extends AsyncTaskLoader<DirectoryResult> {
}
final DirectoryResult result = new DirectoryResult();
+
+ final boolean acceptImages = MimePredicate.mimeMatches("image/*", mAcceptMimes);
+ result.mode = acceptImages ? MODE_GRID : MODE_LIST;
+ result.sortOrder = SORT_ORDER_LAST_MODIFIED;
+
if (cursors.size() > 0) {
final MergeCursor merged = new MergeCursor(cursors.toArray(new Cursor[cursors.size()]));
- final SortingCursorWrapper sorted = new SortingCursorWrapper(
- merged, State.SORT_ORDER_LAST_MODIFIED) {
- @Override
- public void close() {
- // Ignored, since we manage cursor lifecycle internally
- }
- };
+ final SortingCursorWrapper sorted = new SortingCursorWrapper(merged, result.sortOrder);
result.cursor = sorted;
}
return result;
diff --git a/packages/DocumentsUI/src/com/android/documentsui/RecentsCreateFragment.java b/packages/DocumentsUI/src/com/android/documentsui/RecentsCreateFragment.java
index fd7293d..9391ca9 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/RecentsCreateFragment.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/RecentsCreateFragment.java
@@ -41,8 +41,8 @@ import android.widget.ImageView;
import android.widget.ListView;
import android.widget.TextView;
+import com.android.documentsui.RecentsProvider.RecentColumns;
import com.android.documentsui.model.DocumentStack;
-import com.android.documentsui.model.RootInfo;
import com.google.android.collect.Lists;
import libcore.io.IoUtils;
@@ -128,7 +128,7 @@ public class RecentsCreateFragment extends Fragment {
public static class RecentsCreateLoader extends UriDerivativeLoader<Uri, List<DocumentStack>> {
public RecentsCreateLoader(Context context) {
- super(context, RecentsProvider.buildRecentCreate());
+ super(context, RecentsProvider.buildRecent());
}
@Override
@@ -137,14 +137,14 @@ public class RecentsCreateFragment extends Fragment {
final ContentResolver resolver = getContext().getContentResolver();
final Cursor cursor = resolver.query(
- uri, null, null, null, RecentsProvider.COL_TIMESTAMP + " DESC", signal);
+ uri, null, null, null, RecentColumns.TIMESTAMP + " DESC", signal);
try {
while (cursor != null && cursor.moveToNext()) {
- final byte[] raw = cursor.getBlob(
- cursor.getColumnIndex(RecentsProvider.COL_PATH));
+ final byte[] rawStack = cursor.getBlob(
+ cursor.getColumnIndex(RecentColumns.STACK));
try {
final DocumentStack stack = new DocumentStack();
- stack.read(new DataInputStream(new ByteArrayInputStream(raw)));
+ stack.read(new DataInputStream(new ByteArrayInputStream(rawStack)));
result.add(stack);
} catch (IOException e) {
Log.w(TAG, "Failed to resolve stack: " + e);
@@ -181,11 +181,9 @@ public class RecentsCreateFragment extends Fragment {
final ImageView icon = (ImageView) convertView.findViewById(android.R.id.icon);
final TextView title = (TextView) convertView.findViewById(android.R.id.title);
- final View summaryList = convertView.findViewById(R.id.summary_list);
final DocumentStack stack = getItem(position);
- final RootInfo root = stack.getRoot(roots);
- icon.setImageDrawable(root.loadIcon(context));
+ icon.setImageDrawable(stack.root.loadIcon(context));
final StringBuilder builder = new StringBuilder();
for (int i = stack.size() - 1; i >= 0; i--) {
@@ -197,8 +195,6 @@ public class RecentsCreateFragment extends Fragment {
title.setText(builder.toString());
title.setEllipsize(TruncateAt.MIDDLE);
- summaryList.setVisibility(View.GONE);
-
return convertView;
}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/RecentsProvider.java b/packages/DocumentsUI/src/com/android/documentsui/RecentsProvider.java
index 0c87783..df7ed4a 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/RecentsProvider.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/RecentsProvider.java
@@ -25,51 +25,64 @@ import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.net.Uri;
+import android.provider.DocumentsContract.Document;
+import android.provider.DocumentsContract.Root;
import android.text.format.DateUtils;
import android.util.Log;
public class RecentsProvider extends ContentProvider {
private static final String TAG = "RecentsProvider";
- // TODO: offer view of recents that handles backend root resolution before
- // returning cursor, include extra columns
+ public static final long MAX_HISTORY_IN_MILLIS = DateUtils.DAY_IN_MILLIS * 45;
- public static final String AUTHORITY = "com.android.documentsui.recents";
+ private static final String AUTHORITY = "com.android.documentsui.recents";
private static final UriMatcher sMatcher = new UriMatcher(UriMatcher.NO_MATCH);
- private static final int URI_RECENT_OPEN = 1;
- private static final int URI_RECENT_CREATE = 2;
+ private static final int URI_RECENT = 1;
+ private static final int URI_STATE = 2;
private static final int URI_RESUME = 3;
static {
- sMatcher.addURI(AUTHORITY, "recent_open", URI_RECENT_OPEN);
- sMatcher.addURI(AUTHORITY, "recent_create", URI_RECENT_CREATE);
+ sMatcher.addURI(AUTHORITY, "recent", URI_RECENT);
+ // state/authority/rootId/docId
+ sMatcher.addURI(AUTHORITY, "state/*/*/*", URI_STATE);
+ // resume/packageName
sMatcher.addURI(AUTHORITY, "resume/*", URI_RESUME);
}
- private static final String TABLE_RECENT_OPEN = "recent_open";
- private static final String TABLE_RECENT_CREATE = "recent_create";
- private static final String TABLE_RESUME = "resume";
-
- /**
- * String of URIs pointing at a storage backend, stored as a JSON array,
- * starting with root.
- */
- public static final String COL_PATH = "path";
- public static final String COL_URI = "uri";
- public static final String COL_PACKAGE_NAME = "package_name";
- public static final String COL_TIMESTAMP = "timestamp";
-
- @Deprecated
- public static Uri buildRecentOpen() {
- return new Uri.Builder().scheme(ContentResolver.SCHEME_CONTENT)
- .authority(AUTHORITY).appendPath("recent_open").build();
+ public static final String TABLE_RECENT = "recent";
+ public static final String TABLE_STATE = "state";
+ public static final String TABLE_RESUME = "resume";
+
+ public static class RecentColumns {
+ public static final String STACK = "stack";
+ public static final String TIMESTAMP = "timestamp";
+ }
+
+ public static class StateColumns {
+ public static final String AUTHORITY = "authority";
+ public static final String ROOT_ID = Root.COLUMN_ROOT_ID;
+ public static final String DOCUMENT_ID = Document.COLUMN_DOCUMENT_ID;
+ public static final String MODE = "mode";
+ public static final String SORT_ORDER = "sortOrder";
}
- public static Uri buildRecentCreate() {
+ public static class ResumeColumns {
+ public static final String PACKAGE_NAME = "package_name";
+ public static final String STACK = "stack";
+ public static final String TIMESTAMP = "timestamp";
+ }
+
+ public static Uri buildRecent() {
return new Uri.Builder().scheme(ContentResolver.SCHEME_CONTENT)
- .authority(AUTHORITY).appendPath("recent_create").build();
+ .authority(AUTHORITY).appendPath("recent").build();
+ }
+
+ public static Uri buildState(String authority, String rootId, String documentId) {
+ return new Uri.Builder().scheme(ContentResolver.SCHEME_CONTENT).authority(AUTHORITY)
+ .appendPath("state").appendPath(authority).appendPath(rootId).appendPath(documentId)
+ .build();
}
public static Uri buildResume(String packageName) {
@@ -83,35 +96,42 @@ public class RecentsProvider extends ContentProvider {
private static final String DB_NAME = "recents.db";
private static final int VERSION_INIT = 1;
+ private static final int VERSION_AS_BLOB = 3;
public DatabaseHelper(Context context) {
- super(context, DB_NAME, null, VERSION_INIT);
+ super(context, DB_NAME, null, VERSION_AS_BLOB);
}
@Override
public void onCreate(SQLiteDatabase db) {
- db.execSQL("CREATE TABLE " + TABLE_RECENT_OPEN + " (" +
- COL_URI + " TEXT PRIMARY KEY ON CONFLICT REPLACE," +
- COL_TIMESTAMP + " INTEGER" +
+
+ db.execSQL("CREATE TABLE " + TABLE_RECENT + " (" +
+ RecentColumns.STACK + " BLOB PRIMARY KEY ON CONFLICT REPLACE," +
+ RecentColumns.TIMESTAMP + " INTEGER" +
")");
- db.execSQL("CREATE TABLE " + TABLE_RECENT_CREATE + " (" +
- COL_PATH + " TEXT PRIMARY KEY ON CONFLICT REPLACE," +
- COL_TIMESTAMP + " INTEGER" +
+ db.execSQL("CREATE TABLE " + TABLE_STATE + " (" +
+ StateColumns.AUTHORITY + " TEXT," +
+ StateColumns.ROOT_ID + " TEXT," +
+ StateColumns.DOCUMENT_ID + " TEXT," +
+ StateColumns.MODE + " INTEGER," +
+ StateColumns.SORT_ORDER + " INTEGER," +
+ "PRIMARY KEY (" + StateColumns.AUTHORITY + ", " + StateColumns.ROOT_ID + ", "
+ + StateColumns.DOCUMENT_ID + ")" +
")");
db.execSQL("CREATE TABLE " + TABLE_RESUME + " (" +
- COL_PACKAGE_NAME + " TEXT PRIMARY KEY ON CONFLICT REPLACE," +
- COL_PATH + " TEXT," +
- COL_TIMESTAMP + " INTEGER" +
+ ResumeColumns.PACKAGE_NAME + " TEXT PRIMARY KEY ON CONFLICT REPLACE," +
+ ResumeColumns.STACK + " BLOB," +
+ ResumeColumns.TIMESTAMP + " INTEGER" +
")");
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
Log.w(TAG, "Upgrading database; wiping app data");
- db.execSQL("DROP TABLE IF EXISTS " + TABLE_RECENT_OPEN);
- db.execSQL("DROP TABLE IF EXISTS " + TABLE_RECENT_CREATE);
+ db.execSQL("DROP TABLE IF EXISTS " + TABLE_RECENT);
+ db.execSQL("DROP TABLE IF EXISTS " + TABLE_STATE);
db.execSQL("DROP TABLE IF EXISTS " + TABLE_RESUME);
onCreate(db);
}
@@ -128,22 +148,23 @@ public class RecentsProvider extends ContentProvider {
String sortOrder) {
final SQLiteDatabase db = mHelper.getReadableDatabase();
switch (sMatcher.match(uri)) {
- case URI_RECENT_OPEN: {
- return db.query(TABLE_RECENT_OPEN, projection,
- buildWhereYounger(DateUtils.WEEK_IN_MILLIS), null, null, null, null);
- }
- case URI_RECENT_CREATE: {
- return db.query(TABLE_RECENT_CREATE, projection,
- buildWhereYounger(DateUtils.WEEK_IN_MILLIS), null, null, null, null);
- }
- case URI_RESUME: {
+ case URI_RECENT:
+ return db.query(TABLE_RECENT, projection,
+ RecentColumns.TIMESTAMP + "<" + MAX_HISTORY_IN_MILLIS, null, null, null,
+ null);
+ case URI_STATE:
+ final String authority = uri.getPathSegments().get(1);
+ final String rootId = uri.getPathSegments().get(2);
+ final String documentId = uri.getPathSegments().get(3);
+ return db.query(TABLE_STATE, projection, StateColumns.AUTHORITY + "=? AND "
+ + StateColumns.ROOT_ID + "=? AND " + StateColumns.DOCUMENT_ID + "=?",
+ new String[] { authority, rootId, documentId }, null, null, null);
+ case URI_RESUME:
final String packageName = uri.getPathSegments().get(1);
- return db.query(TABLE_RESUME, projection, COL_PACKAGE_NAME + "=?",
+ return db.query(TABLE_RESUME, projection, ResumeColumns.PACKAGE_NAME + "=?",
new String[] { packageName }, null, null, null);
- }
- default: {
+ default:
throw new UnsupportedOperationException("Unsupported Uri " + uri);
- }
}
}
@@ -156,28 +177,37 @@ public class RecentsProvider extends ContentProvider {
public Uri insert(Uri uri, ContentValues values) {
final SQLiteDatabase db = mHelper.getWritableDatabase();
switch (sMatcher.match(uri)) {
- case URI_RECENT_OPEN: {
- values.put(COL_TIMESTAMP, System.currentTimeMillis());
- db.insert(TABLE_RECENT_OPEN, null, values);
- db.delete(TABLE_RECENT_OPEN, buildWhereOlder(DateUtils.WEEK_IN_MILLIS), null);
+ case URI_RECENT:
+ values.put(RecentColumns.TIMESTAMP, System.currentTimeMillis());
+ db.insert(TABLE_RECENT, null, values);
+ db.delete(
+ TABLE_RECENT, RecentColumns.TIMESTAMP + ">" + MAX_HISTORY_IN_MILLIS, null);
return uri;
- }
- case URI_RECENT_CREATE: {
- values.put(COL_TIMESTAMP, System.currentTimeMillis());
- db.insert(TABLE_RECENT_CREATE, null, values);
- db.delete(TABLE_RECENT_CREATE, buildWhereOlder(DateUtils.WEEK_IN_MILLIS), null);
+ case URI_STATE:
+ final String authority = uri.getPathSegments().get(1);
+ final String rootId = uri.getPathSegments().get(2);
+ final String documentId = uri.getPathSegments().get(3);
+
+ final ContentValues key = new ContentValues();
+ key.put(StateColumns.AUTHORITY, authority);
+ key.put(StateColumns.ROOT_ID, rootId);
+ key.put(StateColumns.DOCUMENT_ID, documentId);
+
+ // Ensure that row exists, then update with changed values
+ db.insertWithOnConflict(TABLE_STATE, null, key, SQLiteDatabase.CONFLICT_IGNORE);
+ db.update(TABLE_STATE, values, StateColumns.AUTHORITY + "=? AND "
+ + StateColumns.ROOT_ID + "=? AND " + StateColumns.DOCUMENT_ID + "=?",
+ new String[] { authority, rootId, documentId });
+
return uri;
- }
- case URI_RESUME: {
+ case URI_RESUME:
final String packageName = uri.getPathSegments().get(1);
- values.put(COL_PACKAGE_NAME, packageName);
- values.put(COL_TIMESTAMP, System.currentTimeMillis());
+ values.put(ResumeColumns.PACKAGE_NAME, packageName);
+ values.put(ResumeColumns.TIMESTAMP, System.currentTimeMillis());
db.insert(TABLE_RESUME, null, values);
return uri;
- }
- default: {
+ default:
throw new UnsupportedOperationException("Unsupported Uri " + uri);
- }
}
}
@@ -190,12 +220,4 @@ public class RecentsProvider extends ContentProvider {
public int delete(Uri uri, String selection, String[] selectionArgs) {
throw new UnsupportedOperationException("Unsupported Uri " + uri);
}
-
- private static String buildWhereOlder(long deltaMillis) {
- return COL_TIMESTAMP + "<" + (System.currentTimeMillis() - deltaMillis);
- }
-
- private static String buildWhereYounger(long deltaMillis) {
- return COL_TIMESTAMP + ">" + (System.currentTimeMillis() - deltaMillis);
- }
}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/RootsCache.java b/packages/DocumentsUI/src/com/android/documentsui/RootsCache.java
index d4f1b39..8530a9f 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/RootsCache.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/RootsCache.java
@@ -169,8 +169,9 @@ public class RootsCache {
if (state.localOnly && !localOnly) continue;
// Only include roots that serve requested content
- final boolean overlap = MimePredicate.mimeMatches(root.mimeTypes, state.acceptMimes)
- || MimePredicate.mimeMatches(state.acceptMimes, root.mimeTypes);
+ final boolean overlap =
+ MimePredicate.mimeMatches(root.derivedMimeTypes, state.acceptMimes) ||
+ MimePredicate.mimeMatches(state.acceptMimes, root.derivedMimeTypes);
if (!overlap) {
continue;
}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/RootsFragment.java b/packages/DocumentsUI/src/com/android/documentsui/RootsFragment.java
index ef3a31d..efb972d 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/RootsFragment.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/RootsFragment.java
@@ -40,6 +40,7 @@ import com.android.documentsui.DocumentsActivity.State;
import com.android.documentsui.SectionedListAdapter.SectionAdapter;
import com.android.documentsui.model.DocumentInfo;
import com.android.documentsui.model.RootInfo;
+import com.android.internal.util.Objects;
import java.util.Comparator;
import java.util.List;
@@ -78,6 +79,7 @@ public class RootsFragment extends Fragment {
final View view = inflater.inflate(R.layout.fragment_roots, container, false);
mList = (ListView) view.findViewById(android.R.id.list);
mList.setOnItemClickListener(mItemListener);
+ mList.setChoiceMode(ListView.CHOICE_MODE_SINGLE);
return view;
}
@@ -100,6 +102,21 @@ public class RootsFragment extends Fragment {
mAdapter = new SectionedRootsAdapter(context, matchingRoots, includeApps);
mList.setAdapter(mAdapter);
+
+ onCurrentRootChanged();
+ }
+
+ public void onCurrentRootChanged() {
+ if (mAdapter == null) return;
+
+ final RootInfo root = ((DocumentsActivity) getActivity()).getCurrentRoot();
+ for (int i = 0; i < mAdapter.getCount(); i++) {
+ final Object item = mAdapter.getItem(i);
+ if (Objects.equal(item, root)) {
+ mList.setItemChecked(i, true);
+ return;
+ }
+ }
}
private OnItemClickListener mItemListener = new OnItemClickListener() {
diff --git a/packages/DocumentsUI/src/com/android/documentsui/model/DocumentInfo.java b/packages/DocumentsUI/src/com/android/documentsui/model/DocumentInfo.java
index a1489a5..c69103e 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/model/DocumentInfo.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/model/DocumentInfo.java
@@ -20,6 +20,8 @@ import android.content.ContentProviderClient;
import android.content.ContentResolver;
import android.database.Cursor;
import android.net.Uri;
+import android.os.Parcel;
+import android.os.Parcelable;
import android.provider.DocumentsContract;
import android.provider.DocumentsContract.Document;
@@ -32,15 +34,16 @@ import java.io.DataOutputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.net.ProtocolException;
-import java.util.Comparator;
/**
* Representation of a {@link Document}.
*/
-public class DocumentInfo implements Durable {
+public class DocumentInfo implements Durable, Parcelable {
private static final int VERSION_INIT = 1;
+ private static final int VERSION_SPLIT_URI = 2;
- public Uri uri;
+ public String authority;
+ public String documentId;
public String mimeType;
public String displayName;
public long lastModified;
@@ -49,13 +52,17 @@ public class DocumentInfo implements Durable {
public long size;
public int icon;
+ /** Derived fields that aren't persisted */
+ public Uri derivedUri;
+
public DocumentInfo() {
reset();
}
@Override
public void reset() {
- uri = null;
+ authority = null;
+ documentId = null;
mimeType = null;
displayName = null;
lastModified = -1;
@@ -63,6 +70,8 @@ public class DocumentInfo implements Durable {
summary = null;
size = -1;
icon = 0;
+
+ derivedUri = null;
}
@Override
@@ -70,8 +79,10 @@ public class DocumentInfo implements Durable {
final int version = in.readInt();
switch (version) {
case VERSION_INIT:
- final String rawUri = DurableUtils.readNullableString(in);
- uri = rawUri != null ? Uri.parse(rawUri) : null;
+ throw new ProtocolException("Ignored upgrade");
+ case VERSION_SPLIT_URI:
+ authority = DurableUtils.readNullableString(in);
+ documentId = DurableUtils.readNullableString(in);
mimeType = DurableUtils.readNullableString(in);
displayName = DurableUtils.readNullableString(in);
lastModified = in.readLong();
@@ -79,6 +90,7 @@ public class DocumentInfo implements Durable {
summary = DurableUtils.readNullableString(in);
size = in.readLong();
icon = in.readInt();
+ deriveFields();
break;
default:
throw new ProtocolException("Unknown version " + version);
@@ -87,8 +99,9 @@ public class DocumentInfo implements Durable {
@Override
public void write(DataOutputStream out) throws IOException {
- out.writeInt(VERSION_INIT);
- DurableUtils.writeNullableString(out, uri.toString());
+ out.writeInt(VERSION_SPLIT_URI);
+ DurableUtils.writeNullableString(out, authority);
+ DurableUtils.writeNullableString(out, documentId);
DurableUtils.writeNullableString(out, mimeType);
DurableUtils.writeNullableString(out, displayName);
out.writeLong(lastModified);
@@ -98,11 +111,41 @@ public class DocumentInfo implements Durable {
out.writeInt(icon);
}
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ DurableUtils.writeToParcel(dest, this);
+ }
+
+ public static final Creator<DocumentInfo> CREATOR = new Creator<DocumentInfo>() {
+ @Override
+ public DocumentInfo createFromParcel(Parcel in) {
+ final DocumentInfo doc = new DocumentInfo();
+ DurableUtils.readFromParcel(in, doc);
+ return doc;
+ }
+
+ @Override
+ public DocumentInfo[] newArray(int size) {
+ return new DocumentInfo[size];
+ }
+ };
+
public static DocumentInfo fromDirectoryCursor(Cursor cursor) {
- final DocumentInfo doc = new DocumentInfo();
final String authority = getCursorString(cursor, RootCursorWrapper.COLUMN_AUTHORITY);
- final String docId = getCursorString(cursor, Document.COLUMN_DOCUMENT_ID);
- doc.uri = DocumentsContract.buildDocumentUri(authority, docId);
+ return fromCursor(cursor, authority);
+ }
+
+ public static DocumentInfo fromCursor(Cursor cursor, String authority) {
+ final DocumentInfo doc = new DocumentInfo();
+ doc.authority = authority;
+ doc.documentId = getCursorString(cursor, Document.COLUMN_DOCUMENT_ID);
+ doc.mimeType = getCursorString(cursor, Document.COLUMN_MIME_TYPE);
+ doc.documentId = getCursorString(cursor, Document.COLUMN_DOCUMENT_ID);
doc.mimeType = getCursorString(cursor, Document.COLUMN_MIME_TYPE);
doc.displayName = getCursorString(cursor, Document.COLUMN_DISPLAY_NAME);
doc.lastModified = getCursorLong(cursor, Document.COLUMN_LAST_MODIFIED);
@@ -110,6 +153,7 @@ public class DocumentInfo implements Durable {
doc.summary = getCursorString(cursor, Document.COLUMN_SUMMARY);
doc.size = getCursorLong(cursor, Document.COLUMN_SIZE);
doc.icon = getCursorInt(cursor, Document.COLUMN_ICON);
+ doc.deriveFields();
return doc;
}
@@ -122,16 +166,7 @@ public class DocumentInfo implements Durable {
if (!cursor.moveToFirst()) {
throw new FileNotFoundException("Missing details for " + uri);
}
- final DocumentInfo doc = new DocumentInfo();
- doc.uri = uri;
- doc.mimeType = getCursorString(cursor, Document.COLUMN_MIME_TYPE);
- doc.displayName = getCursorString(cursor, Document.COLUMN_DISPLAY_NAME);
- doc.lastModified = getCursorLong(cursor, Document.COLUMN_LAST_MODIFIED);
- doc.flags = getCursorInt(cursor, Document.COLUMN_FLAGS);
- doc.summary = getCursorString(cursor, Document.COLUMN_SUMMARY);
- doc.size = getCursorLong(cursor, Document.COLUMN_SIZE);
- doc.icon = getCursorInt(cursor, Document.COLUMN_ICON);
- return doc;
+ return fromCursor(cursor, uri.getAuthority());
} catch (Throwable t) {
throw asFileNotFoundException(t);
} finally {
@@ -140,9 +175,13 @@ public class DocumentInfo implements Durable {
}
}
+ private void deriveFields() {
+ derivedUri = DocumentsContract.buildDocumentUri(authority, documentId);
+ }
+
@Override
public String toString() {
- return "Document{name=" + displayName + ", uri=" + uri + "}";
+ return "Document{name=" + displayName + ", docId=" + documentId + "}";
}
public boolean isCreateSupported() {
@@ -189,42 +228,14 @@ public class DocumentInfo implements Durable {
}
}
+ /**
+ * Missing or null values are returned as 0.
+ */
public static int getCursorInt(Cursor cursor, String columnName) {
final int index = cursor.getColumnIndex(columnName);
return (index != -1) ? cursor.getInt(index) : 0;
}
- @Deprecated
- public static class DisplayNameComparator implements Comparator<DocumentInfo> {
- @Override
- public int compare(DocumentInfo lhs, DocumentInfo rhs) {
- final boolean leftDir = lhs.isDirectory();
- final boolean rightDir = rhs.isDirectory();
-
- if (leftDir != rightDir) {
- return leftDir ? -1 : 1;
- } else {
- return compareToIgnoreCaseNullable(lhs.displayName, rhs.displayName);
- }
- }
- }
-
- @Deprecated
- public static class LastModifiedComparator implements Comparator<DocumentInfo> {
- @Override
- public int compare(DocumentInfo lhs, DocumentInfo rhs) {
- return Long.compare(rhs.lastModified, lhs.lastModified);
- }
- }
-
- @Deprecated
- public static class SizeComparator implements Comparator<DocumentInfo> {
- @Override
- public int compare(DocumentInfo lhs, DocumentInfo rhs) {
- return Long.compare(rhs.size, lhs.size);
- }
- }
-
public static FileNotFoundException asFileNotFoundException(Throwable t)
throws FileNotFoundException {
if (t instanceof FileNotFoundException) {
diff --git a/packages/DocumentsUI/src/com/android/documentsui/model/DocumentStack.java b/packages/DocumentsUI/src/com/android/documentsui/model/DocumentStack.java
index 33a1376..2541440 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/model/DocumentStack.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/model/DocumentStack.java
@@ -16,8 +16,6 @@
package com.android.documentsui.model;
-import com.android.documentsui.RootsCache;
-
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
@@ -30,14 +28,13 @@ import java.util.LinkedList;
*/
public class DocumentStack extends LinkedList<DocumentInfo> implements Durable {
private static final int VERSION_INIT = 1;
+ private static final int VERSION_ADD_ROOT = 2;
- public RootInfo getRoot(RootsCache roots) {
- return roots.findRoot(getLast().uri);
- }
+ public RootInfo root;
- public String getTitle(RootsCache roots) {
- if (size() == 1) {
- return getRoot(roots).title;
+ public String getTitle() {
+ if (size() == 1 && root != null) {
+ return root.title;
} else if (size() > 1) {
return peek().displayName;
} else {
@@ -52,6 +49,7 @@ public class DocumentStack extends LinkedList<DocumentInfo> implements Durable {
@Override
public void reset() {
clear();
+ root = null;
}
@Override
@@ -59,6 +57,12 @@ public class DocumentStack extends LinkedList<DocumentInfo> implements Durable {
final int version = in.readInt();
switch (version) {
case VERSION_INIT:
+ throw new ProtocolException("Ignored upgrade");
+ case VERSION_ADD_ROOT:
+ if (in.readBoolean()) {
+ root = new RootInfo();
+ root.read(in);
+ }
final int size = in.readInt();
for (int i = 0; i < size; i++) {
final DocumentInfo doc = new DocumentInfo();
@@ -73,7 +77,13 @@ public class DocumentStack extends LinkedList<DocumentInfo> implements Durable {
@Override
public void write(DataOutputStream out) throws IOException {
- out.writeInt(VERSION_INIT);
+ out.writeInt(VERSION_ADD_ROOT);
+ if (root != null) {
+ out.writeBoolean(true);
+ root.write(out);
+ } else {
+ out.writeBoolean(false);
+ }
final int size = size();
out.writeInt(size);
for (int i = 0; i < size; i++) {
diff --git a/packages/DocumentsUI/src/com/android/documentsui/model/RootInfo.java b/packages/DocumentsUI/src/com/android/documentsui/model/RootInfo.java
index a6ddf70..e0e8acf 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/model/RootInfo.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/model/RootInfo.java
@@ -23,28 +23,121 @@ import static com.android.documentsui.model.DocumentInfo.getCursorString;
import android.content.Context;
import android.database.Cursor;
import android.graphics.drawable.Drawable;
+import android.os.Parcel;
+import android.os.Parcelable;
import android.provider.DocumentsContract.Root;
import com.android.documentsui.IconUtils;
import com.android.documentsui.R;
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.net.ProtocolException;
import java.util.Objects;
/**
* Representation of a {@link Root}.
*/
-public class RootInfo {
+public class RootInfo implements Durable, Parcelable {
+ private static final int VERSION_INIT = 1;
+
public String authority;
public String rootId;
public int rootType;
public int flags;
public int icon;
- public int localIcon;
public String title;
public String summary;
public String documentId;
public long availableBytes;
- public String[] mimeTypes;
+ public String mimeTypes;
+
+ /** Derived fields that aren't persisted */
+ public String[] derivedMimeTypes;
+ public int derivedIcon;
+
+ public RootInfo() {
+ reset();
+ }
+
+ @Override
+ public void reset() {
+ authority = null;
+ rootId = null;
+ rootType = 0;
+ flags = 0;
+ icon = 0;
+ title = null;
+ summary = null;
+ documentId = null;
+ availableBytes = -1;
+ mimeTypes = null;
+
+ derivedMimeTypes = null;
+ derivedIcon = 0;
+ }
+
+ @Override
+ public void read(DataInputStream in) throws IOException {
+ final int version = in.readInt();
+ switch (version) {
+ case VERSION_INIT:
+ authority = DurableUtils.readNullableString(in);
+ rootId = DurableUtils.readNullableString(in);
+ rootType = in.readInt();
+ flags = in.readInt();
+ icon = in.readInt();
+ title = DurableUtils.readNullableString(in);
+ summary = DurableUtils.readNullableString(in);
+ documentId = DurableUtils.readNullableString(in);
+ availableBytes = in.readLong();
+ mimeTypes = DurableUtils.readNullableString(in);
+ deriveFields();
+ break;
+ default:
+ throw new ProtocolException("Unknown version " + version);
+ }
+ }
+
+ @Override
+ public void write(DataOutputStream out) throws IOException {
+ out.writeInt(VERSION_INIT);
+ DurableUtils.writeNullableString(out, authority);
+ DurableUtils.writeNullableString(out, rootId);
+ out.writeInt(rootType);
+ out.writeInt(flags);
+ out.writeInt(icon);
+ DurableUtils.writeNullableString(out, title);
+ DurableUtils.writeNullableString(out, summary);
+ DurableUtils.writeNullableString(out, documentId);
+ out.writeLong(availableBytes);
+ DurableUtils.writeNullableString(out, mimeTypes);
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ DurableUtils.writeToParcel(dest, this);
+ }
+
+ public static final Creator<RootInfo> CREATOR = new Creator<RootInfo>() {
+ @Override
+ public RootInfo createFromParcel(Parcel in) {
+ final RootInfo root = new RootInfo();
+ DurableUtils.readFromParcel(in, root);
+ return root;
+ }
+
+ @Override
+ public RootInfo[] newArray(int size) {
+ return new RootInfo[size];
+ }
+ };
public static RootInfo fromRootsCursor(String authority, Cursor cursor) {
final RootInfo root = new RootInfo();
@@ -57,31 +150,38 @@ public class RootInfo {
root.summary = getCursorString(cursor, Root.COLUMN_SUMMARY);
root.documentId = getCursorString(cursor, Root.COLUMN_DOCUMENT_ID);
root.availableBytes = getCursorLong(cursor, Root.COLUMN_AVAILABLE_BYTES);
+ root.mimeTypes = getCursorString(cursor, Root.COLUMN_MIME_TYPES);
+ root.deriveFields();
+ return root;
+ }
- final String raw = getCursorString(cursor, Root.COLUMN_MIME_TYPES);
- root.mimeTypes = (raw != null) ? raw.split("\n") : null;
+ private void deriveFields() {
+ derivedMimeTypes = (mimeTypes != null) ? mimeTypes.split("\n") : null;
// TODO: remove these special case icons
if ("com.android.externalstorage.documents".equals(authority)) {
- root.localIcon = R.drawable.ic_root_sdcard;
+ derivedIcon = R.drawable.ic_root_sdcard;
}
if ("com.android.providers.downloads.documents".equals(authority)) {
- root.localIcon = R.drawable.ic_root_download;
+ derivedIcon = R.drawable.ic_root_download;
}
if ("com.android.providers.media.documents".equals(authority)) {
- if ("image".equals(root.rootId)) {
- root.localIcon = R.drawable.ic_doc_image;
- } else if ("audio".equals(root.rootId)) {
- root.localIcon = R.drawable.ic_doc_audio;
+ if ("image".equals(rootId)) {
+ derivedIcon = R.drawable.ic_doc_image;
+ } else if ("audio".equals(rootId)) {
+ derivedIcon = R.drawable.ic_doc_audio;
}
}
+ }
- return root;
+ @Override
+ public String toString() {
+ return "Root{title=" + title + ", rootId=" + rootId + "}";
}
public Drawable loadIcon(Context context) {
- if (localIcon != 0) {
- return context.getResources().getDrawable(localIcon);
+ if (derivedIcon != 0) {
+ return context.getResources().getDrawable(derivedIcon);
} else {
return IconUtils.loadPackageIcon(context, authority, icon);
}
diff --git a/packages/SystemUI/res/drawable-nodpi/lightning.png b/packages/SystemUI/res/drawable-nodpi/lightning.png
deleted file mode 100644
index 29de308..0000000
--- a/packages/SystemUI/res/drawable-nodpi/lightning.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/values/arrays.xml b/packages/SystemUI/res/values/arrays.xml
index 0812e80..b2c8aee 100644
--- a/packages/SystemUI/res/values/arrays.xml
+++ b/packages/SystemUI/res/values/arrays.xml
@@ -51,5 +51,14 @@
<item>#FFFF3300</item>
<item>#FFFFFFFF</item>
</array>
-
+ <array name="batterymeter_bolt_points">
+ <item>88</item> <item>0</item>
+ <item>459</item><item>1</item>
+ <item>238</item><item>333</item>
+ <item>525</item><item>310</item>
+ <item>120</item><item>840</item>
+ <item>82</item> <item>818</item>
+ <item>246</item><item>373</item>
+ <item>0</item> <item>408</item>
+ </array>
</resources>
diff --git a/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java b/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java
index be5c326..2257617 100755
--- a/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java
+++ b/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java
@@ -23,12 +23,13 @@ import android.content.IntentFilter;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.graphics.Canvas;
-import android.graphics.LightingColorFilter;
import android.graphics.Paint;
+import android.graphics.Path;
+import android.graphics.PorterDuff;
+import android.graphics.PorterDuffXfermode;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.Typeface;
-import android.graphics.drawable.Drawable;
import android.os.BatteryManager;
import android.os.Bundle;
import android.provider.Settings;
@@ -43,26 +44,27 @@ public class BatteryMeterView extends View implements DemoMode {
public static final boolean SINGLE_DIGIT_PERCENT = false;
public static final boolean SHOW_100_PERCENT = false;
- private static final LightingColorFilter LIGHTNING_FILTER_OPAQUE =
- new LightingColorFilter(0x00000000, 0x00000000);
- private static final LightingColorFilter LIGHTNING_FILTER_TRANS =
- new LightingColorFilter(0x00999999, 0x00000000);
-
public static final int FULL = 96;
public static final int EMPTY = 4;
int[] mColors;
boolean mShowPercent = true;
- Paint mFramePaint, mBatteryPaint, mWarningTextPaint, mTextPaint;
+ Paint mFramePaint, mBatteryPaint, mWarningTextPaint, mTextPaint, mBoltPaint;
int mButtonHeight;
private float mTextHeight, mWarningTextHeight;
- Drawable mLightning;
private int mHeight;
private int mWidth;
private String mWarningString;
private final int mChargeColor;
+ private final float[] mBoltPoints;
+ private final Path mBoltPath = new Path();
+
+ private final RectF mFrame = new RectF();
+ private final RectF mButtonFrame = new RectF();
+ private final RectF mClipFrame = new RectF();
+ private final Rect mBoltFrame = new Rect();
private class BatteryTracker extends BroadcastReceiver {
// current battery status
@@ -175,7 +177,8 @@ public class BatteryMeterView extends View implements DemoMode {
mColors[2*i] = levels.getInt(i, 0);
mColors[2*i+1] = colors.getColor(i, 0);
}
-
+ levels.recycle();
+ colors.recycle();
mShowPercent = ENABLE_PERCENT && 0 != Settings.System.getInt(
context.getContentResolver(), "status_bar_show_battery_percent", 0);
@@ -198,8 +201,28 @@ public class BatteryMeterView extends View implements DemoMode {
mWarningTextPaint.setTypeface(font);
mWarningTextPaint.setTextAlign(Paint.Align.CENTER);
- mLightning = getResources().getDrawable(R.drawable.lightning);
mChargeColor = getResources().getColor(R.color.batterymeter_charge_color);
+
+ mBoltPaint = new Paint();
+ mBoltPaint.setAntiAlias(true);
+ mBoltPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR)); // punch hole
+ setLayerType(LAYER_TYPE_HARDWARE, null);
+ mBoltPoints = loadBoltPoints(res);
+ }
+
+ private static float[] loadBoltPoints(Resources res) {
+ final int[] pts = res.getIntArray(R.array.batterymeter_bolt_points);
+ int maxX = 0, maxY = 0;
+ for (int i = 0; i < pts.length; i += 2) {
+ maxX = Math.max(maxX, pts[i]);
+ maxY = Math.max(maxY, pts[i + 1]);
+ }
+ final float[] ptsF = new float[pts.length];
+ for (int i = 0; i < pts.length; i += 2) {
+ ptsF[i] = (float)pts[i] / maxX;
+ ptsF[i + 1] = (float)pts[i + 1] / maxY;
+ }
+ return ptsF;
}
@Override
@@ -220,15 +243,6 @@ public class BatteryMeterView extends View implements DemoMode {
return color;
}
- // TODO jspurlock - remove once we draw hollow bolt in code
- public void setBarTransparent(boolean isTransparent) {
- mLightning.setColorFilter(isTransparent ? LIGHTNING_FILTER_TRANS : LIGHTNING_FILTER_OPAQUE);
- BatteryTracker tracker = mDemoMode ? mDemoTracker : mTracker;
- if (tracker.plugged) {
- postInvalidate();
- }
- }
-
@Override
public void draw(Canvas c) {
BatteryTracker tracker = mDemoMode ? mDemoTracker : mTracker;
@@ -243,22 +257,19 @@ public class BatteryMeterView extends View implements DemoMode {
mButtonHeight = (int) (height * 0.12f);
- final RectF frame = new RectF(0, 0, width, height);
- frame.offset(pl, pt);
-
- // Log.v("BatteryGauge", String.format("canvas: %dx%d frame: %s",
- // c.getWidth(), c.getHeight(), frame.toString()));
+ mFrame.set(0, 0, width, height);
+ mFrame.offset(pl, pt);
- final RectF buttonframe = new RectF(
- frame.left + width * 0.25f,
- frame.top,
- frame.right - width * 0.25f,
- frame.top + mButtonHeight);
+ mButtonFrame.set(
+ mFrame.left + width * 0.25f,
+ mFrame.top,
+ mFrame.right - width * 0.25f,
+ mFrame.top + mButtonHeight);
- frame.top += mButtonHeight;
+ mFrame.top += mButtonHeight;
// first, draw the battery shape
- c.drawRect(frame, mFramePaint);
+ c.drawRect(mFrame, mFramePaint);
// fill 'er up
final int pct = tracker.level;
@@ -271,15 +282,14 @@ public class BatteryMeterView extends View implements DemoMode {
drawFrac = 0f;
}
- c.drawRect(buttonframe,
- drawFrac == 1f ? mBatteryPaint : mFramePaint);
+ c.drawRect(mButtonFrame, drawFrac == 1f ? mBatteryPaint : mFramePaint);
- RectF clip = new RectF(frame);
- clip.top += (frame.height() * (1f - drawFrac));
+ mClipFrame.set(mFrame);
+ mClipFrame.top += (mFrame.height() * (1f - drawFrac));
c.save(Canvas.CLIP_SAVE_FLAG);
- c.clipRect(clip);
- c.drawRect(frame, mBatteryPaint);
+ c.clipRect(mClipFrame);
+ c.drawRect(mFrame, mBatteryPaint);
c.restore();
if (level <= EMPTY) {
@@ -287,11 +297,28 @@ public class BatteryMeterView extends View implements DemoMode {
final float y = (mHeight + mWarningTextHeight) * 0.48f;
c.drawText(mWarningString, x, y, mWarningTextPaint);
} else if (tracker.plugged) {
- final Rect r = new Rect(
- (int)frame.left + width / 4, (int)frame.top + height / 5,
- (int)frame.right - width / 4, (int)frame.bottom - height / 6);
- mLightning.setBounds(r);
- mLightning.draw(c);
+ // draw the bolt
+ final int bl = (int)(mFrame.left + width / 4f);
+ final int bt = (int)(mFrame.top + height / 6f);
+ final int br = (int)(mFrame.right - width / 5f);
+ final int bb = (int)(mFrame.bottom - height / 6f);
+ if (mBoltFrame.left != bl || mBoltFrame.top != bt
+ || mBoltFrame.right != br || mBoltFrame.bottom != bb) {
+ mBoltFrame.set(bl, bt, br, bb);
+ mBoltPath.reset();
+ mBoltPath.moveTo(
+ mBoltFrame.left + mBoltPoints[0] * mBoltFrame.width(),
+ mBoltFrame.top + mBoltPoints[1] * mBoltFrame.height());
+ for (int i = 2; i < mBoltPoints.length; i += 2) {
+ mBoltPath.lineTo(
+ mBoltFrame.left + mBoltPoints[i] * mBoltFrame.width(),
+ mBoltFrame.top + mBoltPoints[i + 1] * mBoltFrame.height());
+ }
+ mBoltPath.lineTo(
+ mBoltFrame.left + mBoltPoints[0] * mBoltFrame.width(),
+ mBoltFrame.top + mBoltPoints[1] * mBoltFrame.height());
+ }
+ c.drawPath(mBoltPath, mBoltPaint);
} else if (mShowPercent && !(tracker.level == 100 && !SHOW_100_PERCENT)) {
mTextPaint.setTextSize(height *
(SINGLE_DIGIT_PERCENT ? 0.75f
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
index f8b6ca6..b263a6e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
@@ -16,6 +16,7 @@
package com.android.systemui.statusbar.phone;
+import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.app.ActivityManager;
import android.content.Context;
@@ -28,7 +29,6 @@ import android.view.MotionEvent;
import android.view.View;
import android.view.accessibility.AccessibilityEvent;
-import com.android.systemui.BatteryMeterView;
import com.android.systemui.EventLogTags;
import com.android.systemui.R;
@@ -53,9 +53,7 @@ public class PhoneStatusBarView extends PanelBar {
private final int mTransparent;
private final float mAlphaWhenOpaque;
private final float mAlphaWhenTransparent = 1;
- private View mLeftSide;
- private View mRightSide;
- private BatteryMeterView mBattery;
+ private View mLeftSide, mStatusIcons, mSignalCluster, mClock;
public StatusBarTransitions(Context context) {
super(context, PhoneStatusBarView.this);
@@ -66,8 +64,9 @@ public class PhoneStatusBarView extends PanelBar {
public void init() {
mLeftSide = findViewById(R.id.notification_icon_area);
- mRightSide = findViewById(R.id.system_icon_area);
- mBattery = (BatteryMeterView) findViewById(R.id.battery);
+ mStatusIcons = findViewById(R.id.statusIcons);
+ mSignalCluster = findViewById(R.id.signal_battery_cluster);
+ mClock = findViewById(R.id.clock);
applyMode(getMode(), false /*animate*/);
}
@@ -96,17 +95,22 @@ public class PhoneStatusBarView extends PanelBar {
}
private void applyMode(int mode, boolean animate) {
- if (mLeftSide == null || mRightSide == null) return;
- mBattery.setBarTransparent(isTransparent(mode));
+ if (mLeftSide == null) return; // pre-init
float newAlpha = getAlphaFor(mode);
if (animate) {
- ObjectAnimator lhs = animateTransitionTo(mLeftSide, newAlpha);
- lhs.start();
- // TODO jspurlock - fix conflicting rhs animations on tablets
- mRightSide.setAlpha(newAlpha);
+ AnimatorSet anims = new AnimatorSet();
+ anims.playTogether(
+ animateTransitionTo(mLeftSide, newAlpha),
+ animateTransitionTo(mStatusIcons, newAlpha),
+ animateTransitionTo(mSignalCluster, newAlpha),
+ animateTransitionTo(mClock, newAlpha)
+ );
+ anims.start();
} else {
mLeftSide.setAlpha(newAlpha);
- mRightSide.setAlpha(newAlpha);
+ mStatusIcons.setAlpha(newAlpha);
+ mSignalCluster.setAlpha(newAlpha);
+ mClock.setAlpha(newAlpha);
}
}
}