summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--packages/DocumentsUI/AndroidManifest.xml5
-rw-r--r--packages/DocumentsUI/res/layout/fragment_roots.xml3
-rw-r--r--packages/DocumentsUI/res/layout/item_doc_grid.xml69
-rw-r--r--packages/DocumentsUI/res/layout/item_doc_list.xml92
-rw-r--r--packages/DocumentsUI/res/menu/activity.xml10
-rw-r--r--packages/DocumentsUI/res/menu/directory.xml28
-rw-r--r--packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java145
-rw-r--r--packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java154
-rw-r--r--packages/DocumentsUI/src/com/android/documentsui/MimePredicate.java4
-rw-r--r--packages/DocumentsUI/src/com/android/documentsui/RecentsCreateFragment.java209
-rw-r--r--packages/DocumentsUI/src/com/android/documentsui/RecentsProvider.java4
-rw-r--r--packages/DocumentsUI/src/com/android/documentsui/RootsCache.java21
-rw-r--r--packages/DocumentsUI/src/com/android/documentsui/RootsFragment.java2
-rw-r--r--packages/DocumentsUI/src/com/android/documentsui/model/Document.java56
-rw-r--r--packages/DocumentsUI/src/com/android/documentsui/model/DocumentStack.java62
-rw-r--r--packages/DocumentsUI/src/com/android/documentsui/model/Root.java11
16 files changed, 627 insertions, 248 deletions
diff --git a/packages/DocumentsUI/AndroidManifest.xml b/packages/DocumentsUI/AndroidManifest.xml
index b88099ef64f0..1d97161fdccb 100644
--- a/packages/DocumentsUI/AndroidManifest.xml
+++ b/packages/DocumentsUI/AndroidManifest.xml
@@ -3,7 +3,10 @@
<uses-permission android:name="android.permission.MANAGE_DOCUMENTS" />
- <application android:label="@string/app_label">
+ <application
+ android:label="@string/app_label"
+ android:supportsRtl="true">
+
<activity
android:name=".DocumentsActivity"
android:finishOnCloseSystemDialogs="true"
diff --git a/packages/DocumentsUI/res/layout/fragment_roots.xml b/packages/DocumentsUI/res/layout/fragment_roots.xml
index d77289216097..09782d9349b7 100644
--- a/packages/DocumentsUI/res/layout/fragment_roots.xml
+++ b/packages/DocumentsUI/res/layout/fragment_roots.xml
@@ -17,4 +17,5 @@
<ListView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@android:id/list"
android:layout_width="match_parent"
- android:layout_height="match_parent" />
+ android:layout_height="match_parent"
+ android:divider="@null" />
diff --git a/packages/DocumentsUI/res/layout/item_doc_grid.xml b/packages/DocumentsUI/res/layout/item_doc_grid.xml
index caa9db664179..ad8f51cb1a07 100644
--- a/packages/DocumentsUI/res/layout/item_doc_grid.xml
+++ b/packages/DocumentsUI/res/layout/item_doc_grid.xml
@@ -16,7 +16,7 @@
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
- android:layout_height="140dip"
+ android:layout_height="160dip"
android:paddingBottom="?android:attr/listPreferredItemPaddingEnd"
android:paddingEnd="?android:attr/listPreferredItemPaddingEnd">
@@ -27,16 +27,16 @@
android:foreground="@drawable/item_background"
android:duplicateParentState="true">
- <GridLayout
+ <LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:columnCount="1">
+ android:orientation="vertical">
<ImageView
android:id="@android:id/icon"
android:layout_width="match_parent"
android:layout_height="0dip"
- android:layout_gravity="fill_vertical"
+ android:layout_weight="1"
android:background="#bbb"
android:scaleType="centerInside"
android:contentDescription="@null" />
@@ -44,16 +44,67 @@
<TextView
android:id="@android:id/title"
android:layout_width="match_parent"
- android:layout_marginStart="8dip"
- android:layout_marginEnd="8dip"
- android:layout_marginTop="8dip"
- android:layout_marginBottom="8dip"
+ android:layout_height="wrap_content"
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:textAlignment="viewStart" />
- </GridLayout>
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal"
+ android:paddingBottom="6dp"
+ 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:layout_marginEnd="8dp"
+ android:singleLine="true"
+ android:ellipsize="marquee"
+ android:textAlignment="viewStart"
+ android:textAppearance="?android:attr/textAppearanceSmall" />
+
+ <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>
+
+ </LinearLayout>
</FrameLayout>
diff --git a/packages/DocumentsUI/res/layout/item_doc_list.xml b/packages/DocumentsUI/res/layout/item_doc_list.xml
index 39e55beef5db..bb2717372370 100644
--- a/packages/DocumentsUI/res/layout/item_doc_list.xml
+++ b/packages/DocumentsUI/res/layout/item_doc_list.xml
@@ -14,7 +14,7 @@
limitations under the License.
-->
-<GridLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/item_background"
@@ -23,40 +23,82 @@
android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
android:paddingTop="8dip"
android:paddingBottom="8dip"
- android:columnCount="3">
+ android:orientation="horizontal">
<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_marginEnd="8dip"
+ android:layout_gravity="center_vertical"
android:scaleType="centerInside"
android:contentDescription="@null" />
- <TextView
- android:id="@android:id/title"
+ <LinearLayout
android:layout_width="0dip"
- android:layout_gravity="fill_horizontal"
- android:layout_marginTop="2dip"
- android:layout_columnSpan="2"
- android:singleLine="true"
- android:ellipsize="marquee"
- android:textAppearance="?android:attr/textAppearanceMedium"
- android:textAlignment="viewStart" />
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:layout_gravity="center_vertical"
+ android:orientation="vertical">
- <ImageView
- android:id="@android:id/icon1"
- android:layout_width="24dip"
- android:layout_height="24dip"
- android:layout_marginEnd="8dip"
- android:visibility="gone"
- android:scaleType="centerInside"
- android:contentDescription="@null" />
+ <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/line2"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal">
+
+ <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:layout_marginEnd="8dp"
+ android:singleLine="true"
+ android:ellipsize="marquee"
+ android:textAlignment="viewStart"
+ android:textAppearance="?android:attr/textAppearanceSmall" />
+
+ <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>
- <TextView
- android:id="@android:id/summary"
- android:layout_marginTop="2dip"
- android:textAppearance="?android:attr/textAppearanceSmall" />
+ </LinearLayout>
-</GridLayout>
+</LinearLayout>
diff --git a/packages/DocumentsUI/res/menu/activity.xml b/packages/DocumentsUI/res/menu/activity.xml
index a0d03b251699..d57f88ab247b 100644
--- a/packages/DocumentsUI/res/menu/activity.xml
+++ b/packages/DocumentsUI/res/menu/activity.xml
@@ -27,4 +27,14 @@
android:showAsAction="always|collapseActionView"
android:actionViewClass="android.widget.SearchView"
android:imeOptions="actionSearch" />
+ <item
+ android:id="@+id/menu_grid"
+ android:title="@string/menu_grid"
+ android:icon="@drawable/ic_menu_grid"
+ android:showAsAction="ifRoom" />
+ <item
+ android:id="@+id/menu_list"
+ android:title="@string/menu_list"
+ android:icon="@drawable/ic_menu_list"
+ android:showAsAction="ifRoom" />
</menu>
diff --git a/packages/DocumentsUI/res/menu/directory.xml b/packages/DocumentsUI/res/menu/directory.xml
deleted file mode 100644
index 12d0324fb26e..000000000000
--- a/packages/DocumentsUI/res/menu/directory.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?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.
--->
-
-<menu xmlns:android="http://schemas.android.com/apk/res/android">
- <item
- android:id="@+id/menu_grid"
- android:title="@string/menu_grid"
- android:icon="@drawable/ic_menu_grid"
- android:showAsAction="ifRoom" />
- <item
- android:id="@+id/menu_list"
- android:title="@string/menu_list"
- android:icon="@drawable/ic_menu_list"
- android:showAsAction="ifRoom" />
-</menu>
diff --git a/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java b/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java
index 1443f2679efb..d986a512e9da 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java
@@ -26,11 +26,12 @@ import android.net.Uri;
import android.os.Bundle;
import android.provider.DocumentsContract;
import android.text.format.DateUtils;
+import android.text.format.Formatter;
+import android.util.Log;
import android.util.SparseBooleanArray;
import android.view.ActionMode;
import android.view.LayoutInflater;
import android.view.Menu;
-import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
@@ -46,20 +47,21 @@ import android.widget.TextView;
import com.android.documentsui.DocumentsActivity.DisplayState;
import com.android.documentsui.model.Document;
+import com.android.documentsui.model.Root;
import com.android.internal.util.Predicate;
import com.google.android.collect.Lists;
+import java.text.DateFormat;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
+import java.util.concurrent.atomic.AtomicInteger;
/**
* Display the documents inside a single directory.
*/
public class DirectoryFragment extends Fragment {
- // TODO: show storage backend in item views when requested
-
private ListView mListView;
private GridView mGridView;
@@ -68,19 +70,35 @@ public class DirectoryFragment extends Fragment {
public static final int TYPE_NORMAL = 1;
public static final int TYPE_SEARCH = 2;
public static final int TYPE_RECENT_OPEN = 3;
- public static final int TYPE_RECENT_CREATE = 4;
private int mType = TYPE_NORMAL;
private DocumentsAdapter mAdapter;
private LoaderCallbacks<List<Document>> mCallbacks;
+ private static final String EXTRA_TYPE = "type";
private static final String EXTRA_URI = "uri";
- private static final int LOADER_DOCUMENTS = 2;
+ private static AtomicInteger sLoaderId = new AtomicInteger(4000);
+
+ private final int mLoaderId = sLoaderId.incrementAndGet();
+
+ public static void showNormal(FragmentManager fm, Uri uri) {
+ show(fm, TYPE_NORMAL, uri);
+ }
+
+ public static void showSearch(FragmentManager fm, Uri uri, String query) {
+ final Uri searchUri = DocumentsContract.buildSearchUri(uri, query);
+ show(fm, TYPE_SEARCH, searchUri);
+ }
+
+ public static void showRecentsOpen(FragmentManager fm) {
+ show(fm, TYPE_RECENT_OPEN, null);
+ }
- public static void show(FragmentManager fm, Uri uri) {
+ private static void show(FragmentManager fm, int type, Uri uri) {
final Bundle args = new Bundle();
+ args.putInt(EXTRA_TYPE, type);
args.putParcelable(EXTRA_URI, uri);
final DirectoryFragment fragment = new DirectoryFragment();
@@ -97,12 +115,6 @@ public class DirectoryFragment extends Fragment {
}
@Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setHasOptionsMenu(true);
- }
-
- @Override
public View onCreateView(
LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
final Context context = inflater.getContext();
@@ -118,19 +130,9 @@ public class DirectoryFragment extends Fragment {
mGridView.setMultiChoiceModeListener(mMultiListener);
mAdapter = new DocumentsAdapter();
- updateMode();
final Uri uri = getArguments().getParcelable(EXTRA_URI);
-
- if (uri.getQueryParameter(DocumentsContract.PARAM_QUERY) != null) {
- mType = TYPE_SEARCH;
- } else if (RecentsProvider.buildRecentOpen().equals(uri)) {
- mType = TYPE_RECENT_OPEN;
- } else if (RecentsProvider.buildRecentCreate().equals(uri)) {
- mType = TYPE_RECENT_CREATE;
- } else {
- mType = TYPE_NORMAL;
- }
+ mType = getArguments().getInt(EXTRA_TYPE);
mCallbacks = new LoaderCallbacks<List<Document>>() {
@Override
@@ -140,6 +142,8 @@ public class DirectoryFragment extends Fragment {
final Uri contentsUri;
if (mType == TYPE_NORMAL) {
contentsUri = DocumentsContract.buildContentsUri(uri);
+ } else if (mType == TYPE_RECENT_OPEN) {
+ contentsUri = RecentsProvider.buildRecentOpen();
} else {
contentsUri = uri;
}
@@ -147,8 +151,7 @@ public class DirectoryFragment extends Fragment {
final Predicate<Document> filter = new MimePredicate(state.acceptMimes);
final Comparator<Document> sortOrder;
- if (state.sortOrder == DisplayState.SORT_ORDER_DATE || mType == TYPE_RECENT_OPEN
- || mType == TYPE_RECENT_CREATE) {
+ if (state.sortOrder == DisplayState.SORT_ORDER_DATE || mType == TYPE_RECENT_OPEN) {
sortOrder = new Document.DateComparator();
} else if (state.sortOrder == DisplayState.SORT_ORDER_NAME) {
sortOrder = new Document.NameComparator();
@@ -170,56 +173,30 @@ public class DirectoryFragment extends Fragment {
}
};
+ updateDisplayState();
+
return view;
}
@Override
public void onStart() {
super.onStart();
- getLoaderManager().restartLoader(LOADER_DOCUMENTS, getArguments(), mCallbacks);
+ getLoaderManager().restartLoader(mLoaderId, getArguments(), mCallbacks);
}
@Override
public void onStop() {
super.onStop();
- getLoaderManager().destroyLoader(LOADER_DOCUMENTS);
- }
-
- @Override
- public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
- super.onCreateOptionsMenu(menu, inflater);
- inflater.inflate(R.menu.directory, menu);
+ getLoaderManager().destroyLoader(mLoaderId);
}
- @Override
- public void onPrepareOptionsMenu(Menu menu) {
- super.onPrepareOptionsMenu(menu);
+ public void updateDisplayState() {
final DisplayState state = getDisplayState(this);
- menu.findItem(R.id.menu_grid).setVisible(state.mode != DisplayState.MODE_GRID);
- menu.findItem(R.id.menu_list).setVisible(state.mode != DisplayState.MODE_LIST);
- }
- @Override
- public boolean onOptionsItemSelected(MenuItem item) {
- final DisplayState state = getDisplayState(this);
- final int id = item.getItemId();
- if (id == R.id.menu_grid) {
- state.mode = DisplayState.MODE_GRID;
- updateMode();
- getFragmentManager().invalidateOptionsMenu();
- return true;
- } else if (id == R.id.menu_list) {
- state.mode = DisplayState.MODE_LIST;
- updateMode();
- getFragmentManager().invalidateOptionsMenu();
- return true;
- } else {
- return super.onOptionsItemSelected(item);
- }
- }
-
- private void updateMode() {
- final DisplayState state = getDisplayState(this);
+ // TODO: avoid kicking loader when sort didn't change
+ getLoaderManager().restartLoader(mLoaderId, getArguments(), mCallbacks);
+ mListView.smoothScrollToPosition(0);
+ mGridView.smoothScrollToPosition(0);
mListView.setVisibility(state.mode == DisplayState.MODE_LIST ? View.VISIBLE : View.GONE);
mGridView.setVisibility(state.mode == DisplayState.MODE_GRID ? View.VISIBLE : View.GONE);
@@ -250,12 +227,6 @@ public class DirectoryFragment extends Fragment {
}
}
- public void updateSortOrder() {
- getLoaderManager().restartLoader(LOADER_DOCUMENTS, getArguments(), mCallbacks);
- mListView.smoothScrollToPosition(0);
- mGridView.smoothScrollToPosition(0);
- }
-
private OnItemClickListener mItemListener = new OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
@@ -309,7 +280,7 @@ public class DirectoryFragment extends Fragment {
if (checked) {
// Directories cannot be checked
final Document doc = mAdapter.getItem(position);
- if (DocumentsContract.MIME_TYPE_DIRECTORY.equals(doc.mimeType)) {
+ if (doc.isDirectory()) {
mCurrentView.setItemChecked(position, false);
}
}
@@ -337,10 +308,10 @@ public class DirectoryFragment extends Fragment {
@Override
public View getView(int position, View convertView, ViewGroup parent) {
final Context context = parent.getContext();
+ final DisplayState state = getDisplayState(DirectoryFragment.this);
if (convertView == null) {
final LayoutInflater inflater = LayoutInflater.from(context);
- final DisplayState state = getDisplayState(DirectoryFragment.this);
if (state.mode == DisplayState.MODE_LIST) {
convertView = inflater.inflate(R.layout.item_doc_list, parent, false);
} else if (state.mode == DisplayState.MODE_GRID) {
@@ -352,9 +323,12 @@ public class DirectoryFragment extends Fragment {
final Document doc = getItem(position);
+ final ImageView icon = (ImageView) convertView.findViewById(android.R.id.icon);
final TextView title = (TextView) convertView.findViewById(android.R.id.title);
+ final ImageView icon1 = (ImageView) convertView.findViewById(android.R.id.icon1);
final TextView summary = (TextView) convertView.findViewById(android.R.id.summary);
- final ImageView icon = (ImageView) convertView.findViewById(android.R.id.icon);
+ final TextView date = (TextView) convertView.findViewById(R.id.date);
+ final TextView size = (TextView) convertView.findViewById(R.id.size);
if (doc.isThumbnailSupported()) {
// TODO: load thumbnails async
@@ -365,8 +339,37 @@ public class DirectoryFragment extends Fragment {
}
title.setText(doc.displayName);
- if (summary != null) {
- summary.setText(DateUtils.getRelativeTimeSpanString(doc.lastModified));
+
+ if (mType == TYPE_NORMAL || mType == TYPE_SEARCH) {
+ icon1.setVisibility(View.GONE);
+ if (doc.summary != null) {
+ summary.setText(doc.summary);
+ summary.setVisibility(View.VISIBLE);
+ } else {
+ summary.setVisibility(View.INVISIBLE);
+ }
+ } else if (mType == TYPE_RECENT_OPEN) {
+ final Root root = RootsCache.findRoot(context, doc);
+ icon1.setVisibility(View.VISIBLE);
+ icon1.setImageDrawable(root.icon);
+ summary.setText(root.getDirectoryString());
+ summary.setVisibility(View.VISIBLE);
+ }
+
+ // TODO: omit year from format
+ date.setText(DateUtils.formatSameDayTime(
+ doc.lastModified, System.currentTimeMillis(), DateFormat.SHORT,
+ DateFormat.SHORT));
+
+ if (state.showSize) {
+ size.setVisibility(View.VISIBLE);
+ if (doc.isDirectory()) {
+ size.setText(null);
+ } else {
+ size.setText(Formatter.formatFileSize(context, doc.size));
+ }
+ } else {
+ size.setVisibility(View.GONE);
}
return convertView;
diff --git a/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java b/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java
index 6067581869d1..6784d709dbbb 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java
@@ -28,7 +28,6 @@ import android.database.Cursor;
import android.graphics.drawable.ColorDrawable;
import android.net.Uri;
import android.os.Bundle;
-import android.provider.DocumentsContract;
import android.provider.DocumentsContract.DocumentColumns;
import android.support.v4.app.ActionBarDrawerToggle;
import android.support.v4.view.GravityCompat;
@@ -42,27 +41,23 @@ import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
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.model.Document;
+import com.android.documentsui.model.DocumentStack;
import com.android.documentsui.model.Root;
-import org.json.JSONArray;
-import org.json.JSONException;
-
import java.util.Arrays;
-import java.util.LinkedList;
import java.util.List;
public class DocumentsActivity extends Activity {
public static final String TAG = "Documents";
- // TODO: share backend root cache with recents provider
-
- private static final int ACTION_OPEN = 1;
- private static final int ACTION_CREATE = 2;
+ public static final int ACTION_OPEN = 1;
+ public static final int ACTION_CREATE = 2;
private int mAction;
@@ -72,11 +67,12 @@ public class DocumentsActivity extends Activity {
private DrawerLayout mDrawerLayout;
private ActionBarDrawerToggle mDrawerToggle;
- private Root mCurrentRoot;
-
private final DisplayState mDisplayState = new DisplayState();
- private LinkedList<Document> mStack = new LinkedList<Document>();
+ /** Current user navigation stack; empty implies recents. */
+ private DocumentStack mStack;
+ /** Currently active search, overriding any stack. */
+ private String mCurrentSearch;
@Override
public void onCreate(Bundle icicle) {
@@ -135,19 +131,14 @@ public class DocumentsActivity extends Activity {
.query(RecentsProvider.buildResume(packageName), null, null, null, null);
try {
if (cursor.moveToFirst()) {
- final String rawStack = cursor.getString(
+ final String raw = cursor.getString(
cursor.getColumnIndex(RecentsProvider.COL_PATH));
- restoreStack(rawStack);
+ mStack = DocumentStack.deserialize(getContentResolver(), raw);
}
} finally {
cursor.close();
}
- // Start in recents if no restored stack
- if (mStack.isEmpty()) {
- onRootPicked(RootsCache.getRecentOpenRoot(this), false);
- }
-
updateDirectoryFragment();
}
@@ -201,7 +192,7 @@ public class DocumentsActivity extends Activity {
final Root root = getCurrentRoot();
actionBar.setIcon(root != null ? root.icon : null);
- if (getCurrentRoot().isRecents) {
+ if (root.isRecents) {
actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_STANDARD);
actionBar.setTitle(root.title);
} else {
@@ -229,10 +220,8 @@ public class DocumentsActivity extends Activity {
mSearchView.setOnQueryTextListener(new OnQueryTextListener() {
@Override
public boolean onQueryTextSubmit(String query) {
- // TODO: use second directory stack for searches?
- final Document cwd = getCurrentDirectory();
- final Document searchDoc = Document.fromSearch(cwd.uri, query);
- onDocumentPicked(searchDoc);
+ mCurrentSearch = query;
+ updateDirectoryFragment();
mSearchView.setIconified(true);
return true;
}
@@ -243,6 +232,15 @@ public class DocumentsActivity extends Activity {
}
});
+ mSearchView.setOnCloseListener(new OnCloseListener() {
+ @Override
+ public boolean onClose() {
+ mCurrentSearch = null;
+ updateDirectoryFragment();
+ return false;
+ }
+ });
+
return true;
}
@@ -265,6 +263,9 @@ public class DocumentsActivity extends Activity {
SaveFragment.get(fm).setSaveEnabled(cwd != null && cwd.isCreateSupported());
}
+ menu.findItem(R.id.menu_grid).setVisible(mDisplayState.mode != DisplayState.MODE_GRID);
+ menu.findItem(R.id.menu_list).setVisible(mDisplayState.mode != DisplayState.MODE_LIST);
+
return true;
}
@@ -283,8 +284,19 @@ public class DocumentsActivity extends Activity {
return true;
} else if (id == R.id.menu_search) {
return false;
+ } else if (id == R.id.menu_grid) {
+ mDisplayState.mode = DisplayState.MODE_GRID;
+ updateDisplayState();
+ invalidateOptionsMenu();
+ return true;
+ } else if (id == R.id.menu_list) {
+ mDisplayState.mode = DisplayState.MODE_LIST;
+ updateDisplayState();
+ invalidateOptionsMenu();
+ return true;
+ } else {
+ return super.onOptionsItemSelected(item);
}
- return super.onOptionsItemSelected(item);
}
@Override
@@ -339,7 +351,8 @@ public class DocumentsActivity extends Activity {
if (cwd != null) {
title.setText(cwd.displayName);
} else {
- title.setText(null);
+ // No directory means recents
+ title.setText(R.string.root_recent);
}
summary.setText((String) getItem(position));
@@ -365,13 +378,18 @@ public class DocumentsActivity extends Activity {
@Override
public boolean onNavigationItemSelected(int itemPosition, long itemId) {
mDisplayState.sortOrder = itemPosition;
- DirectoryFragment.get(getFragmentManager()).updateSortOrder();
+ updateDisplayState();
return true;
}
};
public Root getCurrentRoot() {
- return mCurrentRoot;
+ final Document cwd = getCurrentDirectory();
+ if (cwd != null) {
+ return RootsCache.findRoot(this, cwd);
+ } else {
+ return RootsCache.getRecentsRoot(this);
+ }
}
public Document getCurrentDirectory() {
@@ -385,19 +403,47 @@ public class DocumentsActivity extends Activity {
private void updateDirectoryFragment() {
final FragmentManager fm = getFragmentManager();
final Document cwd = getCurrentDirectory();
- if (cwd != null) {
- DirectoryFragment.show(fm, cwd.uri);
+ if (cwd == null) {
+ // No directory means recents
+ if (mAction == ACTION_CREATE) {
+ RecentsCreateFragment.show(fm);
+ } else {
+ DirectoryFragment.showRecentsOpen(fm);
+ }
+ } else {
+ if (mCurrentSearch != null) {
+ // Ongoing search
+ DirectoryFragment.showSearch(fm, cwd.uri, mCurrentSearch);
+ } else {
+ // Normal boring directory
+ DirectoryFragment.showNormal(fm, cwd.uri);
+ }
}
+
updateActionBar();
invalidateOptionsMenu();
dumpStack();
}
+ private void updateDisplayState() {
+ // TODO: handle multiple directory stacks on tablets
+ DirectoryFragment.get(getFragmentManager()).updateDisplayState();
+ }
+
+ public void onStackPicked(DocumentStack stack) {
+ mStack = stack;
+ updateDirectoryFragment();
+ }
+
public void onRootPicked(Root root, boolean closeDrawer) {
// Clear entire backstack and start in new root
mStack.clear();
- mCurrentRoot = root;
- onDocumentPicked(Document.fromRoot(getContentResolver(), root));
+
+ if (!root.isRecents) {
+ onDocumentPicked(Document.fromRoot(getContentResolver(), root));
+ } else {
+ updateDirectoryFragment();
+ }
if (closeDrawer) {
mDrawerLayout.closeDrawers();
@@ -406,7 +452,7 @@ public class DocumentsActivity extends Activity {
public void onDocumentPicked(Document doc) {
final FragmentManager fm = getFragmentManager();
- if (DocumentsContract.MIME_TYPE_DIRECTORY.equals(doc.mimeType)) {
+ if (doc.isDirectory()) {
mStack.push(doc);
updateDirectoryFragment();
} else if (mAction == ACTION_OPEN) {
@@ -443,52 +489,17 @@ public class DocumentsActivity extends Activity {
}
}
- private String saveStack() {
- if (mCurrentRoot.isRecents) return null;
-
- final JSONArray stack = new JSONArray();
- for (int i = 0; i < mStack.size(); i++) {
- stack.put(mStack.get(i).uri);
- }
- return stack.toString();
- }
-
- private void restoreStack(String rawStack) {
- Log.d(TAG, "restoreStack: " + rawStack);
- mStack.clear();
-
- if (rawStack == null) return;
- try {
- final JSONArray stack = new JSONArray(rawStack);
- for (int i = 0; i < stack.length(); i++) {
- final Uri uri = Uri.parse(stack.getString(i));
- final Document doc = Document.fromUri(getContentResolver(), uri);
- mStack.add(doc);
- }
- } catch (JSONException e) {
- Log.w(TAG, "Failed to decode stack", e);
- }
-
- // TODO: handle roots that have gone missing
- final Document cwd = getCurrentDirectory();
- if (cwd != null) {
- final String authority = cwd.uri.getAuthority();
- final String rootId = DocumentsContract.getRootId(cwd.uri);
- mCurrentRoot = RootsCache.findRoot(this, authority, rootId);
- }
- }
-
private void onFinished(Uri... uris) {
Log.d(TAG, "onFinished() " + Arrays.toString(uris));
final ContentResolver resolver = getContentResolver();
final ContentValues values = new ContentValues();
- final String stack = saveStack();
+ final String rawStack = DocumentStack.serialize(mStack);
if (mAction == ACTION_CREATE) {
// Remember stack for last create
values.clear();
- values.put(RecentsProvider.COL_PATH, stack);
+ values.put(RecentsProvider.COL_PATH, rawStack);
resolver.insert(RecentsProvider.buildRecentCreate(), values);
} else if (mAction == ACTION_OPEN) {
@@ -503,7 +514,7 @@ public class DocumentsActivity extends Activity {
// Remember location for next app launch
final String packageName = getCallingPackage();
values.clear();
- values.put(RecentsProvider.COL_PATH, stack);
+ values.put(RecentsProvider.COL_PATH, rawStack);
resolver.insert(RecentsProvider.buildResume(packageName), values);
final Intent intent = new Intent();
@@ -532,6 +543,7 @@ public class DocumentsActivity extends Activity {
public String[] acceptMimes;
public int sortOrder = SORT_ORDER_NAME;
public boolean allowMultiple = false;
+ public boolean showSize = false;
public static final int MODE_LIST = 0;
public static final int MODE_GRID = 1;
diff --git a/packages/DocumentsUI/src/com/android/documentsui/MimePredicate.java b/packages/DocumentsUI/src/com/android/documentsui/MimePredicate.java
index 0d2f381dd2bf..f945c6a0d98c 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/MimePredicate.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/MimePredicate.java
@@ -16,8 +16,6 @@
package com.android.documentsui;
-import android.provider.DocumentsContract;
-
import com.android.documentsui.model.Document;
import com.android.internal.util.Predicate;
@@ -30,7 +28,7 @@ public class MimePredicate implements Predicate<Document> {
@Override
public boolean apply(Document doc) {
- if (DocumentsContract.MIME_TYPE_DIRECTORY.equals(doc.mimeType)) {
+ if (doc.isDirectory()) {
return true;
}
for (String filter : mFilters) {
diff --git a/packages/DocumentsUI/src/com/android/documentsui/RecentsCreateFragment.java b/packages/DocumentsUI/src/com/android/documentsui/RecentsCreateFragment.java
new file mode 100644
index 000000000000..2651e4c358a3
--- /dev/null
+++ b/packages/DocumentsUI/src/com/android/documentsui/RecentsCreateFragment.java
@@ -0,0 +1,209 @@
+/*
+ * 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 android.app.Fragment;
+import android.app.FragmentManager;
+import android.app.FragmentTransaction;
+import android.app.LoaderManager.LoaderCallbacks;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.Loader;
+import android.database.Cursor;
+import android.net.Uri;
+import android.os.Bundle;
+import android.os.CancellationSignal;
+import android.text.TextUtils.TruncateAt;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.AdapterView;
+import android.widget.AdapterView.OnItemClickListener;
+import android.widget.BaseAdapter;
+import android.widget.ImageView;
+import android.widget.ListView;
+import android.widget.TextView;
+
+import com.android.documentsui.model.DocumentStack;
+import com.android.documentsui.model.Root;
+import com.google.android.collect.Lists;
+
+import libcore.io.IoUtils;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Display directories where recent creates took place.
+ */
+public class RecentsCreateFragment extends Fragment {
+
+ private ListView mListView;
+
+ private DocumentStackAdapter mAdapter;
+ private LoaderCallbacks<List<DocumentStack>> mCallbacks;
+
+ private static final int LOADER_RECENTS = 3;
+
+ public static void show(FragmentManager fm) {
+ final RecentsCreateFragment fragment = new RecentsCreateFragment();
+ final FragmentTransaction ft = fm.beginTransaction();
+ ft.replace(R.id.container_directory, fragment);
+ ft.commitAllowingStateLoss();
+ }
+
+ @Override
+ public View onCreateView(
+ LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
+ final Context context = inflater.getContext();
+
+ final View view = inflater.inflate(R.layout.fragment_directory, container, false);
+
+ mListView = (ListView) view.findViewById(R.id.list);
+ mListView.setOnItemClickListener(mItemListener);
+
+ mAdapter = new DocumentStackAdapter();
+ mListView.setAdapter(mAdapter);
+
+ mCallbacks = new LoaderCallbacks<List<DocumentStack>>() {
+ @Override
+ public Loader<List<DocumentStack>> onCreateLoader(int id, Bundle args) {
+ return new RecentsCreateLoader(context);
+ }
+
+ @Override
+ public void onLoadFinished(
+ Loader<List<DocumentStack>> loader, List<DocumentStack> data) {
+ mAdapter.swapStacks(data);
+ }
+
+ @Override
+ public void onLoaderReset(Loader<List<DocumentStack>> loader) {
+ mAdapter.swapStacks(null);
+ }
+ };
+
+ return view;
+ }
+
+ @Override
+ public void onStart() {
+ super.onStart();
+ getLoaderManager().restartLoader(LOADER_RECENTS, getArguments(), mCallbacks);
+ }
+
+ @Override
+ public void onStop() {
+ super.onStop();
+ getLoaderManager().destroyLoader(LOADER_RECENTS);
+ }
+
+ private OnItemClickListener mItemListener = new OnItemClickListener() {
+ @Override
+ public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
+ final DocumentStack stack = mAdapter.getItem(position);
+ ((DocumentsActivity) getActivity()).onStackPicked(stack);
+ }
+ };
+
+ public static class RecentsCreateLoader extends UriDerivativeLoader<List<DocumentStack>> {
+ public RecentsCreateLoader(Context context) {
+ super(context, RecentsProvider.buildRecentCreate());
+ }
+
+ @Override
+ public List<DocumentStack> loadInBackground(Uri uri, CancellationSignal signal) {
+ final ArrayList<DocumentStack> result = Lists.newArrayList();
+
+ final ContentResolver resolver = getContext().getContentResolver();
+ final Cursor cursor = resolver.query(
+ uri, null, null, null, RecentsProvider.COL_TIMESTAMP + " DESC", signal);
+ try {
+ while (cursor != null && cursor.moveToNext()) {
+ final String rawStack = cursor.getString(
+ cursor.getColumnIndex(RecentsProvider.COL_PATH));
+ final DocumentStack stack = DocumentStack.deserialize(resolver, rawStack);
+ result.add(stack);
+ }
+ } finally {
+ IoUtils.closeQuietly(cursor);
+ }
+
+ return result;
+ }
+ }
+
+ private class DocumentStackAdapter extends BaseAdapter {
+ private List<DocumentStack> mStacks;
+
+ public DocumentStackAdapter() {
+ }
+
+ public void swapStacks(List<DocumentStack> stacks) {
+ mStacks = stacks;
+ notifyDataSetChanged();
+ }
+
+ @Override
+ public View getView(int position, View convertView, ViewGroup parent) {
+ final Context context = parent.getContext();
+
+ if (convertView == null) {
+ final LayoutInflater inflater = LayoutInflater.from(context);
+ convertView = inflater.inflate(R.layout.item_doc_list, parent, false);
+ }
+
+ final ImageView icon = (ImageView) convertView.findViewById(android.R.id.icon);
+ final TextView title = (TextView) convertView.findViewById(android.R.id.title);
+ final View line2 = convertView.findViewById(R.id.line2);
+
+ final DocumentStack stack = getItem(position);
+ final Root root = RootsCache.findRoot(context, stack.peek());
+ icon.setImageDrawable(root != null ? root.icon : null);
+
+ final StringBuilder builder = new StringBuilder();
+ final int size = stack.size();
+ for (int i = 0; i < size; i++) {
+ builder.append(stack.get(i).displayName);
+ if (i < size - 1) {
+ builder.append(" \u232a ");
+ }
+ }
+ title.setText(builder.toString());
+ title.setEllipsize(TruncateAt.MIDDLE);
+
+ line2.setVisibility(View.GONE);
+
+ return convertView;
+ }
+
+ @Override
+ public int getCount() {
+ return mStacks != null ? mStacks.size() : 0;
+ }
+
+ @Override
+ public DocumentStack getItem(int position) {
+ return mStacks.get(position);
+ }
+
+ @Override
+ public long getItemId(int position) {
+ return getItem(position).hashCode();
+ }
+ }
+}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/RecentsProvider.java b/packages/DocumentsUI/src/com/android/documentsui/RecentsProvider.java
index dbcb0396fdc4..5268c1d25c3d 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/RecentsProvider.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/RecentsProvider.java
@@ -129,11 +129,11 @@ public class RecentsProvider extends ContentProvider {
switch (sMatcher.match(uri)) {
case URI_RECENT_OPEN: {
return db.query(TABLE_RECENT_OPEN, projection,
- buildWhereYounger(DateUtils.WEEK_IN_MILLIS), null, null, null, null);
+ buildWhereYounger(DateUtils.WEEK_IN_MILLIS), null, null, null, sortOrder);
}
case URI_RECENT_CREATE: {
return db.query(TABLE_RECENT_CREATE, projection,
- buildWhereYounger(DateUtils.WEEK_IN_MILLIS), null, null, null, null);
+ buildWhereYounger(DateUtils.WEEK_IN_MILLIS), null, null, null, sortOrder);
}
case URI_RESUME: {
final String packageName = uri.getPathSegments().get(1);
diff --git a/packages/DocumentsUI/src/com/android/documentsui/RootsCache.java b/packages/DocumentsUI/src/com/android/documentsui/RootsCache.java
index 1b56a2003157..b26db3ba4153 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/RootsCache.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/RootsCache.java
@@ -30,6 +30,7 @@ import android.provider.DocumentsContract;
import android.util.Log;
import android.util.Pair;
+import com.android.documentsui.model.Document;
import com.android.documentsui.model.DocumentsProviderInfo;
import com.android.documentsui.model.DocumentsProviderInfo.Icon;
import com.android.documentsui.model.Root;
@@ -58,7 +59,7 @@ public class RootsCache {
public static ArrayList<Root> sRootsList = Lists.newArrayList();
- private static Root sRecentOpenRoot;
+ private static Root sRecentsRoot;
/**
* Gather roots from all known storage providers.
@@ -73,9 +74,9 @@ public class RootsCache {
{
// Create special root for recents
- final Root root = Root.buildRecentOpen(context);
+ final Root root = Root.buildRecents(context);
sRootsList.add(root);
- sRecentOpenRoot = root;
+ sRecentsRoot = root;
}
// Query for other storage backends
@@ -125,13 +126,21 @@ public class RootsCache {
}
@GuardedBy("ActivityThread")
- public static Root getRecentOpenRoot(Context context) {
+ public static Root findRoot(Context context, Document doc) {
+ final String authority = doc.uri.getAuthority();
+ final String rootId = DocumentsContract.getRootId(doc.uri);
+ return findRoot(context, authority, rootId);
+ }
+
+ @GuardedBy("ActivityThread")
+ public static Root getRecentsRoot(Context context) {
ensureCache(context);
- return sRecentOpenRoot;
+ return sRecentsRoot;
}
@GuardedBy("ActivityThread")
- public static Collection<Root> getRoots() {
+ public static Collection<Root> getRoots(Context context) {
+ ensureCache(context);
return sRootsList;
}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/RootsFragment.java b/packages/DocumentsUI/src/com/android/documentsui/RootsFragment.java
index 3e645bcb6241..c4e9c15aa686 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/RootsFragment.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/RootsFragment.java
@@ -69,7 +69,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);
- mAdapter = new SectionedRootsAdapter(context, RootsCache.getRoots());
+ mAdapter = new SectionedRootsAdapter(context, RootsCache.getRoots(context));
mList.setAdapter(mAdapter);
mList.setOnItemClickListener(mItemListener);
diff --git a/packages/DocumentsUI/src/com/android/documentsui/model/Document.java b/packages/DocumentsUI/src/com/android/documentsui/model/Document.java
index ed69690010f3..3b82ba8c4b17 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/model/Document.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/model/Document.java
@@ -35,26 +35,22 @@ public class Document {
public final String displayName;
public final long lastModified;
public final int flags;
+ public final String summary;
+ public final long size;
- private Document(Uri uri, String mimeType, String displayName, long lastModified, int flags) {
+ private Document(Uri uri, String mimeType, String displayName, long lastModified, int flags,
+ String summary, long size) {
this.uri = uri;
this.mimeType = mimeType;
this.displayName = displayName;
this.lastModified = lastModified;
this.flags = flags;
+ this.summary = summary;
+ this.size = size;
}
public static Document fromRoot(ContentResolver resolver, Root root) {
- if (root.isRecents) {
- final Uri uri = root.uri;
- final String mimeType = DocumentsContract.MIME_TYPE_DIRECTORY;
- final String displayName = root.title;
- final long lastModified = -1;
- final int flags = 0;
- return new Document(uri, mimeType, displayName, lastModified, flags);
- } else {
- return fromUri(resolver, root.uri);
- }
+ return fromUri(resolver, root.uri);
}
public static Document fromDirectoryCursor(Uri parent, Cursor cursor) {
@@ -67,8 +63,10 @@ public class Document {
final String displayName = getCursorString(cursor, DocumentColumns.DISPLAY_NAME);
final long lastModified = getCursorLong(cursor, DocumentColumns.LAST_MODIFIED);
final int flags = getCursorInt(cursor, DocumentColumns.FLAGS);
+ final String summary = getCursorString(cursor, DocumentColumns.SUMMARY);
+ final long size = getCursorLong(cursor, DocumentColumns.SIZE);
- return new Document(uri, mimeType, displayName, lastModified, flags);
+ return new Document(uri, mimeType, displayName, lastModified, flags, summary, size);
}
public static Document fromRecentOpenCursor(ContentResolver resolver, Cursor cursor) {
@@ -84,8 +82,10 @@ public class Document {
final String displayName = getCursorString(itemCursor, DocumentColumns.DISPLAY_NAME);
final int flags = getCursorInt(itemCursor, DocumentColumns.FLAGS)
& DocumentsContract.FLAG_SUPPORTS_THUMBNAIL;
+ final String summary = getCursorString(cursor, DocumentColumns.SUMMARY);
+ final long size = getCursorLong(cursor, DocumentColumns.SIZE);
- return new Document(uri, mimeType, displayName, lastModified, flags);
+ return new Document(uri, mimeType, displayName, lastModified, flags, summary, size);
} finally {
itemCursor.close();
}
@@ -101,22 +101,15 @@ public class Document {
final String displayName = getCursorString(cursor, DocumentColumns.DISPLAY_NAME);
final long lastModified = getCursorLong(cursor, DocumentColumns.LAST_MODIFIED);
final int flags = getCursorInt(cursor, DocumentColumns.FLAGS);
+ final String summary = getCursorString(cursor, DocumentColumns.SUMMARY);
+ final long size = getCursorLong(cursor, DocumentColumns.SIZE);
- return new Document(uri, mimeType, displayName, lastModified, flags);
+ return new Document(uri, mimeType, displayName, lastModified, flags, summary, size);
} finally {
cursor.close();
}
}
- public static Document fromSearch(Uri relatedUri, String query) {
- final Uri uri = DocumentsContract.buildSearchUri(relatedUri, query);
- final String mimeType = DocumentsContract.MIME_TYPE_DIRECTORY;
- final String displayName = query;
- final long lastModified = System.currentTimeMillis();
- final int flags = 0;
- return new Document(uri, mimeType, displayName, lastModified, flags);
- }
-
@Override
public String toString() {
return "Document{name=" + displayName + ", uri=" + uri + "}";
@@ -134,23 +127,30 @@ public class Document {
return (flags & DocumentsContract.FLAG_SUPPORTS_THUMBNAIL) != 0;
}
+ public boolean isDirectory() {
+ return DocumentsContract.MIME_TYPE_DIRECTORY.equals(mimeType);
+ }
+
private static String getCursorString(Cursor cursor, String columnName) {
- return cursor.getString(cursor.getColumnIndexOrThrow(columnName));
+ final int index = cursor.getColumnIndex(columnName);
+ return (index != -1) ? cursor.getString(index) : null;
}
private static long getCursorLong(Cursor cursor, String columnName) {
- return cursor.getLong(cursor.getColumnIndexOrThrow(columnName));
+ final int index = cursor.getColumnIndex(columnName);
+ return (index != -1) ? cursor.getLong(index) : 0;
}
private static int getCursorInt(Cursor cursor, String columnName) {
- return cursor.getInt(cursor.getColumnIndexOrThrow(columnName));
+ final int index = cursor.getColumnIndex(columnName);
+ return (index != -1) ? cursor.getInt(index) : 0;
}
public static class NameComparator implements Comparator<Document> {
@Override
public int compare(Document lhs, Document rhs) {
- final boolean leftDir = DocumentsContract.MIME_TYPE_DIRECTORY.equals(lhs.mimeType);
- final boolean rightDir = DocumentsContract.MIME_TYPE_DIRECTORY.equals(rhs.mimeType);
+ final boolean leftDir = lhs.isDirectory();
+ final boolean rightDir = rhs.isDirectory();
if (leftDir != rightDir) {
return leftDir ? -1 : 1;
diff --git a/packages/DocumentsUI/src/com/android/documentsui/model/DocumentStack.java b/packages/DocumentsUI/src/com/android/documentsui/model/DocumentStack.java
new file mode 100644
index 000000000000..dade8a357b97
--- /dev/null
+++ b/packages/DocumentsUI/src/com/android/documentsui/model/DocumentStack.java
@@ -0,0 +1,62 @@
+/*
+ * 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.model;
+
+import static com.android.documentsui.DocumentsActivity.TAG;
+
+import android.content.ContentResolver;
+import android.net.Uri;
+import android.util.Log;
+
+import org.json.JSONArray;
+import org.json.JSONException;
+
+import java.util.LinkedList;
+
+/**
+ * Representation of a stack of {@link Document}, usually the result of a
+ * user-driven traversal.
+ */
+public class DocumentStack extends LinkedList<Document> {
+
+ public static String serialize(DocumentStack stack) {
+ final JSONArray json = new JSONArray();
+ for (int i = 0; i < stack.size(); i++) {
+ json.put(stack.get(i).uri);
+ }
+ return json.toString();
+ }
+
+ public static DocumentStack deserialize(ContentResolver resolver, String raw) {
+ Log.d(TAG, "restoreStack: " + raw);
+
+ final DocumentStack stack = new DocumentStack();
+ try {
+ final JSONArray json = new JSONArray(raw);
+ for (int i = 0; i < json.length(); i++) {
+ final Uri uri = Uri.parse(json.getString(i));
+ final Document doc = Document.fromUri(resolver, uri);
+ stack.add(doc);
+ }
+ } catch (JSONException e) {
+ Log.w(TAG, "Failed to decode stack", e);
+ }
+
+ // TODO: handle roots that have gone missing
+ return stack;
+ }
+}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/model/Root.java b/packages/DocumentsUI/src/com/android/documentsui/model/Root.java
index 9d816d7ace79..629dbc4d8b72 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/model/Root.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/model/Root.java
@@ -43,12 +43,12 @@ public class Root {
public String summary;
public boolean isRecents;
- public static Root buildRecentOpen(Context context) {
+ public static Root buildRecents(Context context) {
final PackageManager pm = context.getPackageManager();
final Root root = new Root();
root.rootId = null;
root.rootType = DocumentsContract.ROOT_TYPE_SHORTCUT;
- root.uri = RecentsProvider.buildRecentOpen();
+ root.uri = null;
root.icon = context.getResources().getDrawable(R.drawable.ic_dir);
root.title = context.getString(R.string.root_recent);
root.summary = null;
@@ -92,6 +92,13 @@ public class Root {
return root;
}
+ /**
+ * Return string most suited to showing in a directory listing.
+ */
+ public String getDirectoryString() {
+ return (summary != null) ? summary : title;
+ }
+
public static class RootComparator implements Comparator<Root> {
@Override
public int compare(Root lhs, Root rhs) {