DirectoryFragment.java revision b156f4bf8cdfe475a7116b627d84a281e1a281b7
19e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkey/*
29e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkey * Copyright (C) 2013 The Android Open Source Project
39e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkey *
49e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkey * Licensed under the Apache License, Version 2.0 (the "License");
59e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkey * you may not use this file except in compliance with the License.
69e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkey * You may obtain a copy of the License at
79e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkey *
89e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkey *      http://www.apache.org/licenses/LICENSE-2.0
99e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkey *
109e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkey * Unless required by applicable law or agreed to in writing, software
119e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkey * distributed under the License is distributed on an "AS IS" BASIS,
129e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkey * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
139e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkey * See the License for the specific language governing permissions and
149e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkey * limitations under the License.
159e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkey */
169e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkey
179e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkeypackage com.android.documentsui;
189e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkey
1954e55b740fef1be654c3959aee41ef5ddfa61293Jeff Sharkeyimport android.app.Fragment;
209e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkeyimport android.app.FragmentManager;
219e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkeyimport android.app.FragmentTransaction;
229e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkeyimport android.app.LoaderManager.LoaderCallbacks;
239e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkeyimport android.content.Context;
249e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkeyimport android.content.Loader;
259e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkeyimport android.net.Uri;
269e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkeyimport android.os.Bundle;
279e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkeyimport android.provider.DocumentsContract;
2854e55b740fef1be654c3959aee41ef5ddfa61293Jeff Sharkeyimport android.text.format.DateUtils;
29b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkeyimport android.text.format.Formatter;
30b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkeyimport android.util.Log;
31be8b12e687bd10a526b1f54c2d8a52abdad15d85Jeff Sharkeyimport android.util.SparseBooleanArray;
32be8b12e687bd10a526b1f54c2d8a52abdad15d85Jeff Sharkeyimport android.view.ActionMode;
339e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkeyimport android.view.LayoutInflater;
3454e55b740fef1be654c3959aee41ef5ddfa61293Jeff Sharkeyimport android.view.Menu;
3554e55b740fef1be654c3959aee41ef5ddfa61293Jeff Sharkeyimport android.view.MenuItem;
369e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkeyimport android.view.View;
379e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkeyimport android.view.ViewGroup;
38be8b12e687bd10a526b1f54c2d8a52abdad15d85Jeff Sharkeyimport android.widget.AbsListView;
39be8b12e687bd10a526b1f54c2d8a52abdad15d85Jeff Sharkeyimport android.widget.AbsListView.MultiChoiceModeListener;
4054e55b740fef1be654c3959aee41ef5ddfa61293Jeff Sharkeyimport android.widget.AdapterView;
4154e55b740fef1be654c3959aee41ef5ddfa61293Jeff Sharkeyimport android.widget.AdapterView.OnItemClickListener;
42ef7184a1aa0be5d496a5cb495a0f9e11f342af44Jeff Sharkeyimport android.widget.BaseAdapter;
4354e55b740fef1be654c3959aee41ef5ddfa61293Jeff Sharkeyimport android.widget.GridView;
449e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkeyimport android.widget.ImageView;
459e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkeyimport android.widget.ListView;
469e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkeyimport android.widget.TextView;
479e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkey
481482789374fb8da3abea8f6f4f272a67205b95dbJeff Sharkeyimport com.android.documentsui.DocumentsActivity.DisplayState;
49ef7184a1aa0be5d496a5cb495a0f9e11f342af44Jeff Sharkeyimport com.android.documentsui.model.Document;
50b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkeyimport com.android.documentsui.model.Root;
51ef7184a1aa0be5d496a5cb495a0f9e11f342af44Jeff Sharkeyimport com.android.internal.util.Predicate;
52be8b12e687bd10a526b1f54c2d8a52abdad15d85Jeff Sharkeyimport com.google.android.collect.Lists;
53be8b12e687bd10a526b1f54c2d8a52abdad15d85Jeff Sharkey
54b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkeyimport java.text.DateFormat;
55be8b12e687bd10a526b1f54c2d8a52abdad15d85Jeff Sharkeyimport java.util.ArrayList;
56ef7184a1aa0be5d496a5cb495a0f9e11f342af44Jeff Sharkeyimport java.util.Comparator;
57ef7184a1aa0be5d496a5cb495a0f9e11f342af44Jeff Sharkeyimport java.util.List;
58b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkeyimport java.util.concurrent.atomic.AtomicInteger;
5954e55b740fef1be654c3959aee41ef5ddfa61293Jeff Sharkey
6054e55b740fef1be654c3959aee41ef5ddfa61293Jeff Sharkey/**
6154e55b740fef1be654c3959aee41ef5ddfa61293Jeff Sharkey * Display the documents inside a single directory.
6254e55b740fef1be654c3959aee41ef5ddfa61293Jeff Sharkey */
6354e55b740fef1be654c3959aee41ef5ddfa61293Jeff Sharkeypublic class DirectoryFragment extends Fragment {
6454e55b740fef1be654c3959aee41ef5ddfa61293Jeff Sharkey
6554e55b740fef1be654c3959aee41ef5ddfa61293Jeff Sharkey    private ListView mListView;
6654e55b740fef1be654c3959aee41ef5ddfa61293Jeff Sharkey    private GridView mGridView;
6754e55b740fef1be654c3959aee41ef5ddfa61293Jeff Sharkey
68be8b12e687bd10a526b1f54c2d8a52abdad15d85Jeff Sharkey    private AbsListView mCurrentView;
69be8b12e687bd10a526b1f54c2d8a52abdad15d85Jeff Sharkey
70ef7184a1aa0be5d496a5cb495a0f9e11f342af44Jeff Sharkey    public static final int TYPE_NORMAL = 1;
71ef7184a1aa0be5d496a5cb495a0f9e11f342af44Jeff Sharkey    public static final int TYPE_SEARCH = 2;
72ef7184a1aa0be5d496a5cb495a0f9e11f342af44Jeff Sharkey    public static final int TYPE_RECENT_OPEN = 3;
73dc2963aecaf38bf53d6de82957412a486049c207Jeff Sharkey
74dc2963aecaf38bf53d6de82957412a486049c207Jeff Sharkey    private int mType = TYPE_NORMAL;
75dc2963aecaf38bf53d6de82957412a486049c207Jeff Sharkey
769e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkey    private DocumentsAdapter mAdapter;
77ef7184a1aa0be5d496a5cb495a0f9e11f342af44Jeff Sharkey    private LoaderCallbacks<List<Document>> mCallbacks;
789e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkey
79b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey    private static final String EXTRA_TYPE = "type";
80dc2963aecaf38bf53d6de82957412a486049c207Jeff Sharkey    private static final String EXTRA_URI = "uri";
819e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkey
82b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey    private static AtomicInteger sLoaderId = new AtomicInteger(4000);
83b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey
84b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey    private final int mLoaderId = sLoaderId.incrementAndGet();
85b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey
86b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey    public static void showNormal(FragmentManager fm, Uri uri) {
87b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey        show(fm, TYPE_NORMAL, uri);
88b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey    }
89b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey
90b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey    public static void showSearch(FragmentManager fm, Uri uri, String query) {
91b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey        final Uri searchUri = DocumentsContract.buildSearchUri(uri, query);
92b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey        show(fm, TYPE_SEARCH, searchUri);
93b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey    }
94b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey
95b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey    public static void showRecentsOpen(FragmentManager fm) {
96b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey        show(fm, TYPE_RECENT_OPEN, null);
97b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey    }
989e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkey
99b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey    private static void show(FragmentManager fm, int type, Uri uri) {
1009e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkey        final Bundle args = new Bundle();
101b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey        args.putInt(EXTRA_TYPE, type);
102dc2963aecaf38bf53d6de82957412a486049c207Jeff Sharkey        args.putParcelable(EXTRA_URI, uri);
1039e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkey
1049e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkey        final DirectoryFragment fragment = new DirectoryFragment();
1059e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkey        fragment.setArguments(args);
1069e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkey
1079e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkey        final FragmentTransaction ft = fm.beginTransaction();
10866516697a29cf00d93893a1011d3befc7c1ee37fJeff Sharkey        ft.replace(R.id.container_directory, fragment);
1099e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkey        ft.commitAllowingStateLoss();
1109e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkey    }
1119e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkey
112ef7184a1aa0be5d496a5cb495a0f9e11f342af44Jeff Sharkey    public static DirectoryFragment get(FragmentManager fm) {
113ef7184a1aa0be5d496a5cb495a0f9e11f342af44Jeff Sharkey        // TODO: deal with multiple directories shown at once
11466516697a29cf00d93893a1011d3befc7c1ee37fJeff Sharkey        return (DirectoryFragment) fm.findFragmentById(R.id.container_directory);
115ef7184a1aa0be5d496a5cb495a0f9e11f342af44Jeff Sharkey    }
116ef7184a1aa0be5d496a5cb495a0f9e11f342af44Jeff Sharkey
1179e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkey    @Override
1189e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkey    public View onCreateView(
1199e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkey            LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
1209e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkey        final Context context = inflater.getContext();
1219e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkey
12254e55b740fef1be654c3959aee41ef5ddfa61293Jeff Sharkey        final View view = inflater.inflate(R.layout.fragment_directory, container, false);
12354e55b740fef1be654c3959aee41ef5ddfa61293Jeff Sharkey
12454e55b740fef1be654c3959aee41ef5ddfa61293Jeff Sharkey        mListView = (ListView) view.findViewById(R.id.list);
12554e55b740fef1be654c3959aee41ef5ddfa61293Jeff Sharkey        mListView.setOnItemClickListener(mItemListener);
126be8b12e687bd10a526b1f54c2d8a52abdad15d85Jeff Sharkey        mListView.setMultiChoiceModeListener(mMultiListener);
12754e55b740fef1be654c3959aee41ef5ddfa61293Jeff Sharkey
12854e55b740fef1be654c3959aee41ef5ddfa61293Jeff Sharkey        mGridView = (GridView) view.findViewById(R.id.grid);
12954e55b740fef1be654c3959aee41ef5ddfa61293Jeff Sharkey        mGridView.setOnItemClickListener(mItemListener);
130be8b12e687bd10a526b1f54c2d8a52abdad15d85Jeff Sharkey        mGridView.setMultiChoiceModeListener(mMultiListener);
13154e55b740fef1be654c3959aee41ef5ddfa61293Jeff Sharkey
132ef7184a1aa0be5d496a5cb495a0f9e11f342af44Jeff Sharkey        mAdapter = new DocumentsAdapter();
13354e55b740fef1be654c3959aee41ef5ddfa61293Jeff Sharkey
134dc2963aecaf38bf53d6de82957412a486049c207Jeff Sharkey        final Uri uri = getArguments().getParcelable(EXTRA_URI);
135b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey        mType = getArguments().getInt(EXTRA_TYPE);
1369e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkey
137ef7184a1aa0be5d496a5cb495a0f9e11f342af44Jeff Sharkey        mCallbacks = new LoaderCallbacks<List<Document>>() {
1389e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkey            @Override
139ef7184a1aa0be5d496a5cb495a0f9e11f342af44Jeff Sharkey            public Loader<List<Document>> onCreateLoader(int id, Bundle args) {
1401482789374fb8da3abea8f6f4f272a67205b95dbJeff Sharkey                final DisplayState state = getDisplayState(DirectoryFragment.this);
1411482789374fb8da3abea8f6f4f272a67205b95dbJeff Sharkey
142bc2971d2499f5bf5534ced7296ece630ca902738Jeff Sharkey                final Uri contentsUri;
143dc2963aecaf38bf53d6de82957412a486049c207Jeff Sharkey                if (mType == TYPE_NORMAL) {
144dc2963aecaf38bf53d6de82957412a486049c207Jeff Sharkey                    contentsUri = DocumentsContract.buildContentsUri(uri);
145b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey                } else if (mType == TYPE_RECENT_OPEN) {
146b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey                    contentsUri = RecentsProvider.buildRecentOpen();
147bc2971d2499f5bf5534ced7296ece630ca902738Jeff Sharkey                } else {
148dc2963aecaf38bf53d6de82957412a486049c207Jeff Sharkey                    contentsUri = uri;
149bc2971d2499f5bf5534ced7296ece630ca902738Jeff Sharkey                }
150bc2971d2499f5bf5534ced7296ece630ca902738Jeff Sharkey
151ef7184a1aa0be5d496a5cb495a0f9e11f342af44Jeff Sharkey                final Predicate<Document> filter = new MimePredicate(state.acceptMimes);
152ef7184a1aa0be5d496a5cb495a0f9e11f342af44Jeff Sharkey
153ef7184a1aa0be5d496a5cb495a0f9e11f342af44Jeff Sharkey                final Comparator<Document> sortOrder;
154b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey                if (state.sortOrder == DisplayState.SORT_ORDER_DATE || mType == TYPE_RECENT_OPEN) {
155ef7184a1aa0be5d496a5cb495a0f9e11f342af44Jeff Sharkey                    sortOrder = new Document.DateComparator();
156ef7184a1aa0be5d496a5cb495a0f9e11f342af44Jeff Sharkey                } else if (state.sortOrder == DisplayState.SORT_ORDER_NAME) {
157ef7184a1aa0be5d496a5cb495a0f9e11f342af44Jeff Sharkey                    sortOrder = new Document.NameComparator();
158ef7184a1aa0be5d496a5cb495a0f9e11f342af44Jeff Sharkey                } else {
159ef7184a1aa0be5d496a5cb495a0f9e11f342af44Jeff Sharkey                    throw new IllegalArgumentException("Unknown sort order " + state.sortOrder);
160ef7184a1aa0be5d496a5cb495a0f9e11f342af44Jeff Sharkey                }
161ef7184a1aa0be5d496a5cb495a0f9e11f342af44Jeff Sharkey
162ef7184a1aa0be5d496a5cb495a0f9e11f342af44Jeff Sharkey                return new DirectoryLoader(context, contentsUri, mType, filter, sortOrder);
1639e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkey            }
1649e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkey
1659e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkey            @Override
166ef7184a1aa0be5d496a5cb495a0f9e11f342af44Jeff Sharkey            public void onLoadFinished(Loader<List<Document>> loader, List<Document> data) {
167ef7184a1aa0be5d496a5cb495a0f9e11f342af44Jeff Sharkey                mAdapter.swapDocuments(data);
1689e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkey            }
1699e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkey
1709e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkey            @Override
171ef7184a1aa0be5d496a5cb495a0f9e11f342af44Jeff Sharkey            public void onLoaderReset(Loader<List<Document>> loader) {
172ef7184a1aa0be5d496a5cb495a0f9e11f342af44Jeff Sharkey                mAdapter.swapDocuments(null);
1739e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkey            }
1749e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkey        };
1759e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkey
176b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey        updateDisplayState();
177b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey
17854e55b740fef1be654c3959aee41ef5ddfa61293Jeff Sharkey        return view;
1799e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkey    }
1809e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkey
1819e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkey    @Override
1829e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkey    public void onStart() {
1839e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkey        super.onStart();
184b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey        getLoaderManager().restartLoader(mLoaderId, getArguments(), mCallbacks);
1859e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkey    }
1869e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkey
1879e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkey    @Override
1889e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkey    public void onStop() {
1899e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkey        super.onStop();
190b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey        getLoaderManager().destroyLoader(mLoaderId);
19154e55b740fef1be654c3959aee41ef5ddfa61293Jeff Sharkey    }
1929e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkey
193b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey    public void updateDisplayState() {
1941482789374fb8da3abea8f6f4f272a67205b95dbJeff Sharkey        final DisplayState state = getDisplayState(this);
19554e55b740fef1be654c3959aee41ef5ddfa61293Jeff Sharkey
196b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey        // TODO: avoid kicking loader when sort didn't change
197b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey        getLoaderManager().restartLoader(mLoaderId, getArguments(), mCallbacks);
198b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey        mListView.smoothScrollToPosition(0);
199b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey        mGridView.smoothScrollToPosition(0);
20054e55b740fef1be654c3959aee41ef5ddfa61293Jeff Sharkey
2011482789374fb8da3abea8f6f4f272a67205b95dbJeff Sharkey        mListView.setVisibility(state.mode == DisplayState.MODE_LIST ? View.VISIBLE : View.GONE);
2021482789374fb8da3abea8f6f4f272a67205b95dbJeff Sharkey        mGridView.setVisibility(state.mode == DisplayState.MODE_GRID ? View.VISIBLE : View.GONE);
20354e55b740fef1be654c3959aee41ef5ddfa61293Jeff Sharkey
204be8b12e687bd10a526b1f54c2d8a52abdad15d85Jeff Sharkey        final int choiceMode;
2051482789374fb8da3abea8f6f4f272a67205b95dbJeff Sharkey        if (state.allowMultiple) {
206be8b12e687bd10a526b1f54c2d8a52abdad15d85Jeff Sharkey            choiceMode = ListView.CHOICE_MODE_MULTIPLE_MODAL;
207be8b12e687bd10a526b1f54c2d8a52abdad15d85Jeff Sharkey        } else {
208be8b12e687bd10a526b1f54c2d8a52abdad15d85Jeff Sharkey            choiceMode = ListView.CHOICE_MODE_NONE;
209be8b12e687bd10a526b1f54c2d8a52abdad15d85Jeff Sharkey        }
210be8b12e687bd10a526b1f54c2d8a52abdad15d85Jeff Sharkey
2111482789374fb8da3abea8f6f4f272a67205b95dbJeff Sharkey        if (state.mode == DisplayState.MODE_GRID) {
21254e55b740fef1be654c3959aee41ef5ddfa61293Jeff Sharkey            mListView.setAdapter(null);
213be8b12e687bd10a526b1f54c2d8a52abdad15d85Jeff Sharkey            mListView.setChoiceMode(ListView.CHOICE_MODE_NONE);
21454e55b740fef1be654c3959aee41ef5ddfa61293Jeff Sharkey            mGridView.setAdapter(mAdapter);
215be8b12e687bd10a526b1f54c2d8a52abdad15d85Jeff Sharkey            mGridView.setColumnWidth(getResources().getDimensionPixelSize(R.dimen.grid_width));
21654e55b740fef1be654c3959aee41ef5ddfa61293Jeff Sharkey            mGridView.setNumColumns(GridView.AUTO_FIT);
217be8b12e687bd10a526b1f54c2d8a52abdad15d85Jeff Sharkey            mGridView.setChoiceMode(choiceMode);
218be8b12e687bd10a526b1f54c2d8a52abdad15d85Jeff Sharkey            mCurrentView = mGridView;
2191482789374fb8da3abea8f6f4f272a67205b95dbJeff Sharkey        } else if (state.mode == DisplayState.MODE_LIST) {
22054e55b740fef1be654c3959aee41ef5ddfa61293Jeff Sharkey            mGridView.setAdapter(null);
221be8b12e687bd10a526b1f54c2d8a52abdad15d85Jeff Sharkey            mGridView.setChoiceMode(ListView.CHOICE_MODE_NONE);
22254e55b740fef1be654c3959aee41ef5ddfa61293Jeff Sharkey            mListView.setAdapter(mAdapter);
223be8b12e687bd10a526b1f54c2d8a52abdad15d85Jeff Sharkey            mListView.setChoiceMode(choiceMode);
224be8b12e687bd10a526b1f54c2d8a52abdad15d85Jeff Sharkey            mCurrentView = mListView;
2251482789374fb8da3abea8f6f4f272a67205b95dbJeff Sharkey        } else {
2261482789374fb8da3abea8f6f4f272a67205b95dbJeff Sharkey            throw new IllegalStateException();
22754e55b740fef1be654c3959aee41ef5ddfa61293Jeff Sharkey        }
22854e55b740fef1be654c3959aee41ef5ddfa61293Jeff Sharkey    }
22954e55b740fef1be654c3959aee41ef5ddfa61293Jeff Sharkey
23054e55b740fef1be654c3959aee41ef5ddfa61293Jeff Sharkey    private OnItemClickListener mItemListener = new OnItemClickListener() {
23154e55b740fef1be654c3959aee41ef5ddfa61293Jeff Sharkey        @Override
23254e55b740fef1be654c3959aee41ef5ddfa61293Jeff Sharkey        public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
233ef7184a1aa0be5d496a5cb495a0f9e11f342af44Jeff Sharkey            final Document doc = mAdapter.getItem(position);
23454e55b740fef1be654c3959aee41ef5ddfa61293Jeff Sharkey            ((DocumentsActivity) getActivity()).onDocumentPicked(doc);
23554e55b740fef1be654c3959aee41ef5ddfa61293Jeff Sharkey        }
23654e55b740fef1be654c3959aee41ef5ddfa61293Jeff Sharkey    };
23754e55b740fef1be654c3959aee41ef5ddfa61293Jeff Sharkey
238be8b12e687bd10a526b1f54c2d8a52abdad15d85Jeff Sharkey    private MultiChoiceModeListener mMultiListener = new MultiChoiceModeListener() {
239be8b12e687bd10a526b1f54c2d8a52abdad15d85Jeff Sharkey        @Override
240be8b12e687bd10a526b1f54c2d8a52abdad15d85Jeff Sharkey        public boolean onCreateActionMode(ActionMode mode, Menu menu) {
241be8b12e687bd10a526b1f54c2d8a52abdad15d85Jeff Sharkey            mode.getMenuInflater().inflate(R.menu.mode_directory, menu);
242be8b12e687bd10a526b1f54c2d8a52abdad15d85Jeff Sharkey            return true;
243be8b12e687bd10a526b1f54c2d8a52abdad15d85Jeff Sharkey        }
244be8b12e687bd10a526b1f54c2d8a52abdad15d85Jeff Sharkey
245be8b12e687bd10a526b1f54c2d8a52abdad15d85Jeff Sharkey        @Override
246be8b12e687bd10a526b1f54c2d8a52abdad15d85Jeff Sharkey        public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
247be8b12e687bd10a526b1f54c2d8a52abdad15d85Jeff Sharkey            return true;
248be8b12e687bd10a526b1f54c2d8a52abdad15d85Jeff Sharkey        }
249be8b12e687bd10a526b1f54c2d8a52abdad15d85Jeff Sharkey
250be8b12e687bd10a526b1f54c2d8a52abdad15d85Jeff Sharkey        @Override
251be8b12e687bd10a526b1f54c2d8a52abdad15d85Jeff Sharkey        public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
252be8b12e687bd10a526b1f54c2d8a52abdad15d85Jeff Sharkey            if (item.getItemId() == R.id.menu_open) {
253dc2963aecaf38bf53d6de82957412a486049c207Jeff Sharkey                final Uri uri = getArguments().getParcelable(EXTRA_URI);
254be8b12e687bd10a526b1f54c2d8a52abdad15d85Jeff Sharkey                final SparseBooleanArray checked = mCurrentView.getCheckedItemPositions();
255be8b12e687bd10a526b1f54c2d8a52abdad15d85Jeff Sharkey                final ArrayList<Document> docs = Lists.newArrayList();
256be8b12e687bd10a526b1f54c2d8a52abdad15d85Jeff Sharkey
257be8b12e687bd10a526b1f54c2d8a52abdad15d85Jeff Sharkey                final int size = checked.size();
258be8b12e687bd10a526b1f54c2d8a52abdad15d85Jeff Sharkey                for (int i = 0; i < size; i++) {
259be8b12e687bd10a526b1f54c2d8a52abdad15d85Jeff Sharkey                    if (checked.valueAt(i)) {
260ef7184a1aa0be5d496a5cb495a0f9e11f342af44Jeff Sharkey                        final Document doc = mAdapter.getItem(checked.keyAt(i));
261ef7184a1aa0be5d496a5cb495a0f9e11f342af44Jeff Sharkey                        docs.add(doc);
262be8b12e687bd10a526b1f54c2d8a52abdad15d85Jeff Sharkey                    }
263be8b12e687bd10a526b1f54c2d8a52abdad15d85Jeff Sharkey                }
264be8b12e687bd10a526b1f54c2d8a52abdad15d85Jeff Sharkey
265be8b12e687bd10a526b1f54c2d8a52abdad15d85Jeff Sharkey                ((DocumentsActivity) getActivity()).onDocumentsPicked(docs);
266be8b12e687bd10a526b1f54c2d8a52abdad15d85Jeff Sharkey                return true;
267be8b12e687bd10a526b1f54c2d8a52abdad15d85Jeff Sharkey            } else {
268be8b12e687bd10a526b1f54c2d8a52abdad15d85Jeff Sharkey                return false;
269be8b12e687bd10a526b1f54c2d8a52abdad15d85Jeff Sharkey            }
270be8b12e687bd10a526b1f54c2d8a52abdad15d85Jeff Sharkey        }
271be8b12e687bd10a526b1f54c2d8a52abdad15d85Jeff Sharkey
272be8b12e687bd10a526b1f54c2d8a52abdad15d85Jeff Sharkey        @Override
273be8b12e687bd10a526b1f54c2d8a52abdad15d85Jeff Sharkey        public void onDestroyActionMode(ActionMode mode) {
274be8b12e687bd10a526b1f54c2d8a52abdad15d85Jeff Sharkey            // ignored
275be8b12e687bd10a526b1f54c2d8a52abdad15d85Jeff Sharkey        }
276be8b12e687bd10a526b1f54c2d8a52abdad15d85Jeff Sharkey
277be8b12e687bd10a526b1f54c2d8a52abdad15d85Jeff Sharkey        @Override
278be8b12e687bd10a526b1f54c2d8a52abdad15d85Jeff Sharkey        public void onItemCheckedStateChanged(
279be8b12e687bd10a526b1f54c2d8a52abdad15d85Jeff Sharkey                ActionMode mode, int position, long id, boolean checked) {
280be8b12e687bd10a526b1f54c2d8a52abdad15d85Jeff Sharkey            if (checked) {
281be8b12e687bd10a526b1f54c2d8a52abdad15d85Jeff Sharkey                // Directories cannot be checked
282ef7184a1aa0be5d496a5cb495a0f9e11f342af44Jeff Sharkey                final Document doc = mAdapter.getItem(position);
283b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey                if (doc.isDirectory()) {
284be8b12e687bd10a526b1f54c2d8a52abdad15d85Jeff Sharkey                    mCurrentView.setItemChecked(position, false);
285be8b12e687bd10a526b1f54c2d8a52abdad15d85Jeff Sharkey                }
286be8b12e687bd10a526b1f54c2d8a52abdad15d85Jeff Sharkey            }
287be8b12e687bd10a526b1f54c2d8a52abdad15d85Jeff Sharkey
288be8b12e687bd10a526b1f54c2d8a52abdad15d85Jeff Sharkey            mode.setTitle(getResources()
289be8b12e687bd10a526b1f54c2d8a52abdad15d85Jeff Sharkey                    .getString(R.string.mode_selected_count, mCurrentView.getCheckedItemCount()));
290be8b12e687bd10a526b1f54c2d8a52abdad15d85Jeff Sharkey        }
291be8b12e687bd10a526b1f54c2d8a52abdad15d85Jeff Sharkey    };
292be8b12e687bd10a526b1f54c2d8a52abdad15d85Jeff Sharkey
2931482789374fb8da3abea8f6f4f272a67205b95dbJeff Sharkey    private static DisplayState getDisplayState(Fragment fragment) {
2941482789374fb8da3abea8f6f4f272a67205b95dbJeff Sharkey        return ((DocumentsActivity) fragment.getActivity()).getDisplayState();
29554e55b740fef1be654c3959aee41ef5ddfa61293Jeff Sharkey    }
29654e55b740fef1be654c3959aee41ef5ddfa61293Jeff Sharkey
297ef7184a1aa0be5d496a5cb495a0f9e11f342af44Jeff Sharkey    private class DocumentsAdapter extends BaseAdapter {
298ef7184a1aa0be5d496a5cb495a0f9e11f342af44Jeff Sharkey        private List<Document> mDocuments;
299ef7184a1aa0be5d496a5cb495a0f9e11f342af44Jeff Sharkey
300ef7184a1aa0be5d496a5cb495a0f9e11f342af44Jeff Sharkey        public DocumentsAdapter() {
3019e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkey        }
3029e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkey
303ef7184a1aa0be5d496a5cb495a0f9e11f342af44Jeff Sharkey        public void swapDocuments(List<Document> documents) {
304ef7184a1aa0be5d496a5cb495a0f9e11f342af44Jeff Sharkey            mDocuments = documents;
305ef7184a1aa0be5d496a5cb495a0f9e11f342af44Jeff Sharkey            notifyDataSetChanged();
3069e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkey        }
3079e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkey
3089e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkey        @Override
309ef7184a1aa0be5d496a5cb495a0f9e11f342af44Jeff Sharkey        public View getView(int position, View convertView, ViewGroup parent) {
310ef7184a1aa0be5d496a5cb495a0f9e11f342af44Jeff Sharkey            final Context context = parent.getContext();
311b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey            final DisplayState state = getDisplayState(DirectoryFragment.this);
312ef7184a1aa0be5d496a5cb495a0f9e11f342af44Jeff Sharkey
313ef7184a1aa0be5d496a5cb495a0f9e11f342af44Jeff Sharkey            if (convertView == null) {
314ef7184a1aa0be5d496a5cb495a0f9e11f342af44Jeff Sharkey                final LayoutInflater inflater = LayoutInflater.from(context);
315ef7184a1aa0be5d496a5cb495a0f9e11f342af44Jeff Sharkey                if (state.mode == DisplayState.MODE_LIST) {
316ef7184a1aa0be5d496a5cb495a0f9e11f342af44Jeff Sharkey                    convertView = inflater.inflate(R.layout.item_doc_list, parent, false);
317ef7184a1aa0be5d496a5cb495a0f9e11f342af44Jeff Sharkey                } else if (state.mode == DisplayState.MODE_GRID) {
318ef7184a1aa0be5d496a5cb495a0f9e11f342af44Jeff Sharkey                    convertView = inflater.inflate(R.layout.item_doc_grid, parent, false);
319ef7184a1aa0be5d496a5cb495a0f9e11f342af44Jeff Sharkey                } else {
320ef7184a1aa0be5d496a5cb495a0f9e11f342af44Jeff Sharkey                    throw new IllegalStateException();
321ef7184a1aa0be5d496a5cb495a0f9e11f342af44Jeff Sharkey                }
322ef7184a1aa0be5d496a5cb495a0f9e11f342af44Jeff Sharkey            }
323ef7184a1aa0be5d496a5cb495a0f9e11f342af44Jeff Sharkey
324ef7184a1aa0be5d496a5cb495a0f9e11f342af44Jeff Sharkey            final Document doc = getItem(position);
325ef7184a1aa0be5d496a5cb495a0f9e11f342af44Jeff Sharkey
326b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey            final ImageView icon = (ImageView) convertView.findViewById(android.R.id.icon);
327ef7184a1aa0be5d496a5cb495a0f9e11f342af44Jeff Sharkey            final TextView title = (TextView) convertView.findViewById(android.R.id.title);
328b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey            final ImageView icon1 = (ImageView) convertView.findViewById(android.R.id.icon1);
329ef7184a1aa0be5d496a5cb495a0f9e11f342af44Jeff Sharkey            final TextView summary = (TextView) convertView.findViewById(android.R.id.summary);
330b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey            final TextView date = (TextView) convertView.findViewById(R.id.date);
331b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey            final TextView size = (TextView) convertView.findViewById(R.id.size);
332ef7184a1aa0be5d496a5cb495a0f9e11f342af44Jeff Sharkey
333ef7184a1aa0be5d496a5cb495a0f9e11f342af44Jeff Sharkey            if (doc.isThumbnailSupported()) {
334ef7184a1aa0be5d496a5cb495a0f9e11f342af44Jeff Sharkey                // TODO: load thumbnails async
335ef7184a1aa0be5d496a5cb495a0f9e11f342af44Jeff Sharkey                icon.setImageURI(doc.uri);
3369e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkey            } else {
33766516697a29cf00d93893a1011d3befc7c1ee37fJeff Sharkey                icon.setImageDrawable(RootsCache.resolveDocumentIcon(
338ef7184a1aa0be5d496a5cb495a0f9e11f342af44Jeff Sharkey                        context, doc.uri.getAuthority(), doc.mimeType));
3399e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkey            }
3409e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkey
341ef7184a1aa0be5d496a5cb495a0f9e11f342af44Jeff Sharkey            title.setText(doc.displayName);
342b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey
343b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey            if (mType == TYPE_NORMAL || mType == TYPE_SEARCH) {
344b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey                icon1.setVisibility(View.GONE);
345b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey                if (doc.summary != null) {
346b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey                    summary.setText(doc.summary);
347b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey                    summary.setVisibility(View.VISIBLE);
348b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey                } else {
349b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey                    summary.setVisibility(View.INVISIBLE);
350b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey                }
351b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey            } else if (mType == TYPE_RECENT_OPEN) {
352b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey                final Root root = RootsCache.findRoot(context, doc);
353b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey                icon1.setVisibility(View.VISIBLE);
354b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey                icon1.setImageDrawable(root.icon);
355b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey                summary.setText(root.getDirectoryString());
356b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey                summary.setVisibility(View.VISIBLE);
357b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey            }
358b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey
359b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey            // TODO: omit year from format
360b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey            date.setText(DateUtils.formatSameDayTime(
361b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey                    doc.lastModified, System.currentTimeMillis(), DateFormat.SHORT,
362b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey                    DateFormat.SHORT));
363b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey
364b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey            if (state.showSize) {
365b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey                size.setVisibility(View.VISIBLE);
366b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey                if (doc.isDirectory()) {
367b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey                    size.setText(null);
368b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey                } else {
369b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey                    size.setText(Formatter.formatFileSize(context, doc.size));
370b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey                }
371b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey            } else {
372b156f4bf8cdfe475a7116b627d84a281e1a281b7Jeff Sharkey                size.setVisibility(View.GONE);
37354e55b740fef1be654c3959aee41ef5ddfa61293Jeff Sharkey            }
374ef7184a1aa0be5d496a5cb495a0f9e11f342af44Jeff Sharkey
375ef7184a1aa0be5d496a5cb495a0f9e11f342af44Jeff Sharkey            return convertView;
37654e55b740fef1be654c3959aee41ef5ddfa61293Jeff Sharkey        }
37754e55b740fef1be654c3959aee41ef5ddfa61293Jeff Sharkey
378ef7184a1aa0be5d496a5cb495a0f9e11f342af44Jeff Sharkey        @Override
379ef7184a1aa0be5d496a5cb495a0f9e11f342af44Jeff Sharkey        public int getCount() {
380ef7184a1aa0be5d496a5cb495a0f9e11f342af44Jeff Sharkey            return mDocuments != null ? mDocuments.size() : 0;
381ef7184a1aa0be5d496a5cb495a0f9e11f342af44Jeff Sharkey        }
3829e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkey
383ef7184a1aa0be5d496a5cb495a0f9e11f342af44Jeff Sharkey        @Override
384ef7184a1aa0be5d496a5cb495a0f9e11f342af44Jeff Sharkey        public Document getItem(int position) {
385ef7184a1aa0be5d496a5cb495a0f9e11f342af44Jeff Sharkey            return mDocuments.get(position);
386ef7184a1aa0be5d496a5cb495a0f9e11f342af44Jeff Sharkey        }
38754e55b740fef1be654c3959aee41ef5ddfa61293Jeff Sharkey
388ef7184a1aa0be5d496a5cb495a0f9e11f342af44Jeff Sharkey        @Override
389ef7184a1aa0be5d496a5cb495a0f9e11f342af44Jeff Sharkey        public long getItemId(int position) {
390ef7184a1aa0be5d496a5cb495a0f9e11f342af44Jeff Sharkey            return getItem(position).uri.hashCode();
391ef7184a1aa0be5d496a5cb495a0f9e11f342af44Jeff Sharkey        }
3929e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkey    }
3939e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkey}
394