DirectoryFragment.java revision dc2963aecaf38bf53d6de82957412a486049c207
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.CursorLoader;
259e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkeyimport android.content.Loader;
269e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkeyimport android.database.Cursor;
279e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkeyimport android.net.Uri;
289e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkeyimport android.os.Bundle;
299e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkeyimport android.provider.DocumentsContract;
309e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkeyimport android.provider.DocumentsContract.DocumentColumns;
3154e55b740fef1be654c3959aee41ef5ddfa61293Jeff Sharkeyimport android.text.format.DateUtils;
32be8b12e687bd10a526b1f54c2d8a52abdad15d85Jeff Sharkeyimport android.util.SparseBooleanArray;
33be8b12e687bd10a526b1f54c2d8a52abdad15d85Jeff Sharkeyimport android.view.ActionMode;
349e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkeyimport android.view.LayoutInflater;
3554e55b740fef1be654c3959aee41ef5ddfa61293Jeff Sharkeyimport android.view.Menu;
3654e55b740fef1be654c3959aee41ef5ddfa61293Jeff Sharkeyimport android.view.MenuInflater;
3754e55b740fef1be654c3959aee41ef5ddfa61293Jeff Sharkeyimport android.view.MenuItem;
389e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkeyimport android.view.View;
399e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkeyimport android.view.ViewGroup;
40be8b12e687bd10a526b1f54c2d8a52abdad15d85Jeff Sharkeyimport android.widget.AbsListView;
41be8b12e687bd10a526b1f54c2d8a52abdad15d85Jeff Sharkeyimport android.widget.AbsListView.MultiChoiceModeListener;
4254e55b740fef1be654c3959aee41ef5ddfa61293Jeff Sharkeyimport android.widget.AdapterView;
4354e55b740fef1be654c3959aee41ef5ddfa61293Jeff Sharkeyimport android.widget.AdapterView.OnItemClickListener;
449e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkeyimport android.widget.CursorAdapter;
4554e55b740fef1be654c3959aee41ef5ddfa61293Jeff Sharkeyimport android.widget.GridView;
469e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkeyimport android.widget.ImageView;
479e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkeyimport android.widget.ListView;
489e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkeyimport android.widget.TextView;
499e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkey
501482789374fb8da3abea8f6f4f272a67205b95dbJeff Sharkeyimport com.android.documentsui.DocumentsActivity.DisplayState;
5154e55b740fef1be654c3959aee41ef5ddfa61293Jeff Sharkeyimport com.android.documentsui.DocumentsActivity.Document;
52be8b12e687bd10a526b1f54c2d8a52abdad15d85Jeff Sharkeyimport com.google.android.collect.Lists;
53be8b12e687bd10a526b1f54c2d8a52abdad15d85Jeff Sharkey
54be8b12e687bd10a526b1f54c2d8a52abdad15d85Jeff Sharkeyimport java.util.ArrayList;
5554e55b740fef1be654c3959aee41ef5ddfa61293Jeff Sharkey
5654e55b740fef1be654c3959aee41ef5ddfa61293Jeff Sharkey/**
5754e55b740fef1be654c3959aee41ef5ddfa61293Jeff Sharkey * Display the documents inside a single directory.
5854e55b740fef1be654c3959aee41ef5ddfa61293Jeff Sharkey */
5954e55b740fef1be654c3959aee41ef5ddfa61293Jeff Sharkeypublic class DirectoryFragment extends Fragment {
6054e55b740fef1be654c3959aee41ef5ddfa61293Jeff Sharkey
6154e55b740fef1be654c3959aee41ef5ddfa61293Jeff Sharkey    // TODO: show storage backend in item views when requested
6292d7e697a864a3e18bef4ef256bb3eb339a66b4eJeff Sharkey    // TODO: apply sort order locally
6392d7e697a864a3e18bef4ef256bb3eb339a66b4eJeff Sharkey    // TODO: apply MIME filtering locally
641482789374fb8da3abea8f6f4f272a67205b95dbJeff Sharkey
6554e55b740fef1be654c3959aee41ef5ddfa61293Jeff Sharkey    private ListView mListView;
6654e55b740fef1be654c3959aee41ef5ddfa61293Jeff Sharkey    private GridView mGridView;
6754e55b740fef1be654c3959aee41ef5ddfa61293Jeff Sharkey
68be8b12e687bd10a526b1f54c2d8a52abdad15d85Jeff Sharkey    private AbsListView mCurrentView;
69be8b12e687bd10a526b1f54c2d8a52abdad15d85Jeff Sharkey
70dc2963aecaf38bf53d6de82957412a486049c207Jeff Sharkey    private static final int TYPE_NORMAL = 1;
71dc2963aecaf38bf53d6de82957412a486049c207Jeff Sharkey    private static final int TYPE_SEARCH = 2;
72dc2963aecaf38bf53d6de82957412a486049c207Jeff Sharkey    private static final int TYPE_RECENT_OPEN = 3;
73dc2963aecaf38bf53d6de82957412a486049c207Jeff Sharkey    private static final int TYPE_RECENT_CREATE = 4;
74dc2963aecaf38bf53d6de82957412a486049c207Jeff Sharkey
75dc2963aecaf38bf53d6de82957412a486049c207Jeff Sharkey    private int mType = TYPE_NORMAL;
76dc2963aecaf38bf53d6de82957412a486049c207Jeff Sharkey
779e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkey    private DocumentsAdapter mAdapter;
789e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkey    private LoaderCallbacks<Cursor> mCallbacks;
799e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkey
80dc2963aecaf38bf53d6de82957412a486049c207Jeff Sharkey    private static final String EXTRA_URI = "uri";
819e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkey
829e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkey    private static final int LOADER_DOCUMENTS = 2;
839e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkey
84dc2963aecaf38bf53d6de82957412a486049c207Jeff Sharkey    public static void show(FragmentManager fm, Uri uri) {
859e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkey        final Bundle args = new Bundle();
86dc2963aecaf38bf53d6de82957412a486049c207Jeff Sharkey        args.putParcelable(EXTRA_URI, uri);
879e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkey
889e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkey        final DirectoryFragment fragment = new DirectoryFragment();
899e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkey        fragment.setArguments(args);
909e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkey
919e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkey        final FragmentTransaction ft = fm.beginTransaction();
9254e55b740fef1be654c3959aee41ef5ddfa61293Jeff Sharkey        ft.replace(R.id.directory, fragment);
939e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkey        ft.commitAllowingStateLoss();
949e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkey    }
959e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkey
969e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkey    @Override
9754e55b740fef1be654c3959aee41ef5ddfa61293Jeff Sharkey    public void onCreate(Bundle savedInstanceState) {
9854e55b740fef1be654c3959aee41ef5ddfa61293Jeff Sharkey        super.onCreate(savedInstanceState);
9954e55b740fef1be654c3959aee41ef5ddfa61293Jeff Sharkey        setHasOptionsMenu(true);
10054e55b740fef1be654c3959aee41ef5ddfa61293Jeff Sharkey    }
10154e55b740fef1be654c3959aee41ef5ddfa61293Jeff Sharkey
10254e55b740fef1be654c3959aee41ef5ddfa61293Jeff Sharkey    @Override
1039e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkey    public View onCreateView(
1049e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkey            LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
1059e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkey        final Context context = inflater.getContext();
1069e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkey
10754e55b740fef1be654c3959aee41ef5ddfa61293Jeff Sharkey        final View view = inflater.inflate(R.layout.fragment_directory, container, false);
10854e55b740fef1be654c3959aee41ef5ddfa61293Jeff Sharkey
10954e55b740fef1be654c3959aee41ef5ddfa61293Jeff Sharkey        mListView = (ListView) view.findViewById(R.id.list);
11054e55b740fef1be654c3959aee41ef5ddfa61293Jeff Sharkey        mListView.setOnItemClickListener(mItemListener);
111be8b12e687bd10a526b1f54c2d8a52abdad15d85Jeff Sharkey        mListView.setMultiChoiceModeListener(mMultiListener);
11254e55b740fef1be654c3959aee41ef5ddfa61293Jeff Sharkey
11354e55b740fef1be654c3959aee41ef5ddfa61293Jeff Sharkey        mGridView = (GridView) view.findViewById(R.id.grid);
11454e55b740fef1be654c3959aee41ef5ddfa61293Jeff Sharkey        mGridView.setOnItemClickListener(mItemListener);
115be8b12e687bd10a526b1f54c2d8a52abdad15d85Jeff Sharkey        mGridView.setMultiChoiceModeListener(mMultiListener);
11654e55b740fef1be654c3959aee41ef5ddfa61293Jeff Sharkey
1179e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkey        mAdapter = new DocumentsAdapter(context);
11854e55b740fef1be654c3959aee41ef5ddfa61293Jeff Sharkey        updateMode();
11954e55b740fef1be654c3959aee41ef5ddfa61293Jeff Sharkey
120dc2963aecaf38bf53d6de82957412a486049c207Jeff Sharkey        final Uri uri = getArguments().getParcelable(EXTRA_URI);
121dc2963aecaf38bf53d6de82957412a486049c207Jeff Sharkey
122dc2963aecaf38bf53d6de82957412a486049c207Jeff Sharkey        if (uri.getQueryParameter(DocumentsContract.PARAM_QUERY) != null) {
123dc2963aecaf38bf53d6de82957412a486049c207Jeff Sharkey            mType = TYPE_SEARCH;
124dc2963aecaf38bf53d6de82957412a486049c207Jeff Sharkey        } else if (RecentsProvider.buildRecentOpen().equals(uri)) {
125dc2963aecaf38bf53d6de82957412a486049c207Jeff Sharkey            mType = TYPE_RECENT_OPEN;
126dc2963aecaf38bf53d6de82957412a486049c207Jeff Sharkey        } else if (RecentsProvider.buildRecentCreate().equals(uri)) {
127dc2963aecaf38bf53d6de82957412a486049c207Jeff Sharkey            mType = TYPE_RECENT_CREATE;
128dc2963aecaf38bf53d6de82957412a486049c207Jeff Sharkey        } else {
129dc2963aecaf38bf53d6de82957412a486049c207Jeff Sharkey            mType = TYPE_NORMAL;
130dc2963aecaf38bf53d6de82957412a486049c207Jeff Sharkey        }
1319e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkey
1329e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkey        mCallbacks = new LoaderCallbacks<Cursor>() {
1339e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkey            @Override
1349e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkey            public Loader<Cursor> onCreateLoader(int id, Bundle args) {
1351482789374fb8da3abea8f6f4f272a67205b95dbJeff Sharkey                final DisplayState state = getDisplayState(DirectoryFragment.this);
1361482789374fb8da3abea8f6f4f272a67205b95dbJeff Sharkey                final String sortOrder;
1371482789374fb8da3abea8f6f4f272a67205b95dbJeff Sharkey                if (state.sortBy == DisplayState.SORT_BY_NAME) {
1381482789374fb8da3abea8f6f4f272a67205b95dbJeff Sharkey                    sortOrder = DocumentColumns.DISPLAY_NAME + " ASC";
1391482789374fb8da3abea8f6f4f272a67205b95dbJeff Sharkey                } else if (state.sortBy == DisplayState.SORT_BY_DATE) {
1401482789374fb8da3abea8f6f4f272a67205b95dbJeff Sharkey                    sortOrder = DocumentColumns.LAST_MODIFIED + " DESC";
1411482789374fb8da3abea8f6f4f272a67205b95dbJeff Sharkey                } else {
1421482789374fb8da3abea8f6f4f272a67205b95dbJeff Sharkey                    sortOrder = null;
1431482789374fb8da3abea8f6f4f272a67205b95dbJeff Sharkey                }
1441482789374fb8da3abea8f6f4f272a67205b95dbJeff Sharkey
145bc2971d2499f5bf5534ced7296ece630ca902738Jeff Sharkey                final Uri contentsUri;
146dc2963aecaf38bf53d6de82957412a486049c207Jeff Sharkey                if (mType == TYPE_NORMAL) {
147dc2963aecaf38bf53d6de82957412a486049c207Jeff Sharkey                    contentsUri = DocumentsContract.buildContentsUri(uri);
148bc2971d2499f5bf5534ced7296ece630ca902738Jeff Sharkey                } else {
149dc2963aecaf38bf53d6de82957412a486049c207Jeff Sharkey                    contentsUri = uri;
150bc2971d2499f5bf5534ced7296ece630ca902738Jeff Sharkey                }
151bc2971d2499f5bf5534ced7296ece630ca902738Jeff Sharkey
1521482789374fb8da3abea8f6f4f272a67205b95dbJeff Sharkey                return new CursorLoader(context, contentsUri, null, null, null, sortOrder);
1539e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkey            }
1549e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkey
1559e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkey            @Override
1569e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkey            public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
1579e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkey                mAdapter.swapCursor(data);
1589e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkey            }
1599e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkey
1609e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkey            @Override
1619e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkey            public void onLoaderReset(Loader<Cursor> loader) {
1629e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkey                mAdapter.swapCursor(null);
1639e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkey            }
1649e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkey        };
1659e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkey
16654e55b740fef1be654c3959aee41ef5ddfa61293Jeff Sharkey        return view;
1679e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkey    }
1689e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkey
1699e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkey    @Override
1709e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkey    public void onStart() {
1719e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkey        super.onStart();
1729e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkey        getLoaderManager().restartLoader(LOADER_DOCUMENTS, getArguments(), mCallbacks);
1739e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkey    }
1749e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkey
1759e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkey    @Override
1769e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkey    public void onStop() {
1779e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkey        super.onStop();
1789e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkey        getLoaderManager().destroyLoader(LOADER_DOCUMENTS);
1799e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkey    }
1809e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkey
1819e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkey    @Override
18254e55b740fef1be654c3959aee41ef5ddfa61293Jeff Sharkey    public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
18354e55b740fef1be654c3959aee41ef5ddfa61293Jeff Sharkey        super.onCreateOptionsMenu(menu, inflater);
18454e55b740fef1be654c3959aee41ef5ddfa61293Jeff Sharkey        inflater.inflate(R.menu.directory, menu);
18554e55b740fef1be654c3959aee41ef5ddfa61293Jeff Sharkey    }
1869e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkey
18754e55b740fef1be654c3959aee41ef5ddfa61293Jeff Sharkey    @Override
18854e55b740fef1be654c3959aee41ef5ddfa61293Jeff Sharkey    public void onPrepareOptionsMenu(Menu menu) {
18954e55b740fef1be654c3959aee41ef5ddfa61293Jeff Sharkey        super.onPrepareOptionsMenu(menu);
1901482789374fb8da3abea8f6f4f272a67205b95dbJeff Sharkey        final DisplayState state = getDisplayState(this);
1911482789374fb8da3abea8f6f4f272a67205b95dbJeff Sharkey        menu.findItem(R.id.menu_grid).setVisible(state.mode != DisplayState.MODE_GRID);
1921482789374fb8da3abea8f6f4f272a67205b95dbJeff Sharkey        menu.findItem(R.id.menu_list).setVisible(state.mode != DisplayState.MODE_LIST);
19354e55b740fef1be654c3959aee41ef5ddfa61293Jeff Sharkey    }
19454e55b740fef1be654c3959aee41ef5ddfa61293Jeff Sharkey
19554e55b740fef1be654c3959aee41ef5ddfa61293Jeff Sharkey    @Override
19654e55b740fef1be654c3959aee41ef5ddfa61293Jeff Sharkey    public boolean onOptionsItemSelected(MenuItem item) {
1971482789374fb8da3abea8f6f4f272a67205b95dbJeff Sharkey        final DisplayState state = getDisplayState(this);
19854e55b740fef1be654c3959aee41ef5ddfa61293Jeff Sharkey        final int id = item.getItemId();
19954e55b740fef1be654c3959aee41ef5ddfa61293Jeff Sharkey        if (id == R.id.menu_grid) {
2001482789374fb8da3abea8f6f4f272a67205b95dbJeff Sharkey            state.mode = DisplayState.MODE_GRID;
20154e55b740fef1be654c3959aee41ef5ddfa61293Jeff Sharkey            updateMode();
2021482789374fb8da3abea8f6f4f272a67205b95dbJeff Sharkey            getFragmentManager().invalidateOptionsMenu();
20354e55b740fef1be654c3959aee41ef5ddfa61293Jeff Sharkey            return true;
20454e55b740fef1be654c3959aee41ef5ddfa61293Jeff Sharkey        } else if (id == R.id.menu_list) {
2051482789374fb8da3abea8f6f4f272a67205b95dbJeff Sharkey            state.mode = DisplayState.MODE_LIST;
20654e55b740fef1be654c3959aee41ef5ddfa61293Jeff Sharkey            updateMode();
2071482789374fb8da3abea8f6f4f272a67205b95dbJeff Sharkey            getFragmentManager().invalidateOptionsMenu();
2081482789374fb8da3abea8f6f4f272a67205b95dbJeff Sharkey            return true;
2099e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkey        } else {
21054e55b740fef1be654c3959aee41ef5ddfa61293Jeff Sharkey            return super.onOptionsItemSelected(item);
2119e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkey        }
2129e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkey    }
2139e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkey
21454e55b740fef1be654c3959aee41ef5ddfa61293Jeff Sharkey    private void updateMode() {
2151482789374fb8da3abea8f6f4f272a67205b95dbJeff Sharkey        final DisplayState state = getDisplayState(this);
21654e55b740fef1be654c3959aee41ef5ddfa61293Jeff Sharkey
2171482789374fb8da3abea8f6f4f272a67205b95dbJeff Sharkey        mListView.setVisibility(state.mode == DisplayState.MODE_LIST ? View.VISIBLE : View.GONE);
2181482789374fb8da3abea8f6f4f272a67205b95dbJeff Sharkey        mGridView.setVisibility(state.mode == DisplayState.MODE_GRID ? View.VISIBLE : View.GONE);
21954e55b740fef1be654c3959aee41ef5ddfa61293Jeff Sharkey
220be8b12e687bd10a526b1f54c2d8a52abdad15d85Jeff Sharkey        final int choiceMode;
2211482789374fb8da3abea8f6f4f272a67205b95dbJeff Sharkey        if (state.allowMultiple) {
222be8b12e687bd10a526b1f54c2d8a52abdad15d85Jeff Sharkey            choiceMode = ListView.CHOICE_MODE_MULTIPLE_MODAL;
223be8b12e687bd10a526b1f54c2d8a52abdad15d85Jeff Sharkey        } else {
224be8b12e687bd10a526b1f54c2d8a52abdad15d85Jeff Sharkey            choiceMode = ListView.CHOICE_MODE_NONE;
225be8b12e687bd10a526b1f54c2d8a52abdad15d85Jeff Sharkey        }
226be8b12e687bd10a526b1f54c2d8a52abdad15d85Jeff Sharkey
2271482789374fb8da3abea8f6f4f272a67205b95dbJeff Sharkey        if (state.mode == DisplayState.MODE_GRID) {
22854e55b740fef1be654c3959aee41ef5ddfa61293Jeff Sharkey            mListView.setAdapter(null);
229be8b12e687bd10a526b1f54c2d8a52abdad15d85Jeff Sharkey            mListView.setChoiceMode(ListView.CHOICE_MODE_NONE);
23054e55b740fef1be654c3959aee41ef5ddfa61293Jeff Sharkey            mGridView.setAdapter(mAdapter);
231be8b12e687bd10a526b1f54c2d8a52abdad15d85Jeff Sharkey            mGridView.setColumnWidth(getResources().getDimensionPixelSize(R.dimen.grid_width));
23254e55b740fef1be654c3959aee41ef5ddfa61293Jeff Sharkey            mGridView.setNumColumns(GridView.AUTO_FIT);
233be8b12e687bd10a526b1f54c2d8a52abdad15d85Jeff Sharkey            mGridView.setChoiceMode(choiceMode);
234be8b12e687bd10a526b1f54c2d8a52abdad15d85Jeff Sharkey            mCurrentView = mGridView;
2351482789374fb8da3abea8f6f4f272a67205b95dbJeff Sharkey        } else if (state.mode == DisplayState.MODE_LIST) {
23654e55b740fef1be654c3959aee41ef5ddfa61293Jeff Sharkey            mGridView.setAdapter(null);
237be8b12e687bd10a526b1f54c2d8a52abdad15d85Jeff Sharkey            mGridView.setChoiceMode(ListView.CHOICE_MODE_NONE);
23854e55b740fef1be654c3959aee41ef5ddfa61293Jeff Sharkey            mListView.setAdapter(mAdapter);
239be8b12e687bd10a526b1f54c2d8a52abdad15d85Jeff Sharkey            mListView.setChoiceMode(choiceMode);
240be8b12e687bd10a526b1f54c2d8a52abdad15d85Jeff Sharkey            mCurrentView = mListView;
2411482789374fb8da3abea8f6f4f272a67205b95dbJeff Sharkey        } else {
2421482789374fb8da3abea8f6f4f272a67205b95dbJeff Sharkey            throw new IllegalStateException();
24354e55b740fef1be654c3959aee41ef5ddfa61293Jeff Sharkey        }
24454e55b740fef1be654c3959aee41ef5ddfa61293Jeff Sharkey    }
24554e55b740fef1be654c3959aee41ef5ddfa61293Jeff Sharkey
246bc2971d2499f5bf5534ced7296ece630ca902738Jeff Sharkey    public void updateSortBy() {
2471482789374fb8da3abea8f6f4f272a67205b95dbJeff Sharkey        getLoaderManager().restartLoader(LOADER_DOCUMENTS, getArguments(), mCallbacks);
2481482789374fb8da3abea8f6f4f272a67205b95dbJeff Sharkey    }
2491482789374fb8da3abea8f6f4f272a67205b95dbJeff Sharkey
25054e55b740fef1be654c3959aee41ef5ddfa61293Jeff Sharkey    private OnItemClickListener mItemListener = new OnItemClickListener() {
25154e55b740fef1be654c3959aee41ef5ddfa61293Jeff Sharkey        @Override
25254e55b740fef1be654c3959aee41ef5ddfa61293Jeff Sharkey        public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
25354e55b740fef1be654c3959aee41ef5ddfa61293Jeff Sharkey            final Cursor cursor = (Cursor) mAdapter.getItem(position);
254dc2963aecaf38bf53d6de82957412a486049c207Jeff Sharkey            final Uri uri = getArguments().getParcelable(EXTRA_URI);
255dc2963aecaf38bf53d6de82957412a486049c207Jeff Sharkey            final Document doc = Document.fromCursor(uri, cursor);
25654e55b740fef1be654c3959aee41ef5ddfa61293Jeff Sharkey            ((DocumentsActivity) getActivity()).onDocumentPicked(doc);
25754e55b740fef1be654c3959aee41ef5ddfa61293Jeff Sharkey        }
25854e55b740fef1be654c3959aee41ef5ddfa61293Jeff Sharkey    };
25954e55b740fef1be654c3959aee41ef5ddfa61293Jeff Sharkey
260be8b12e687bd10a526b1f54c2d8a52abdad15d85Jeff Sharkey    private MultiChoiceModeListener mMultiListener = new MultiChoiceModeListener() {
261be8b12e687bd10a526b1f54c2d8a52abdad15d85Jeff Sharkey        @Override
262be8b12e687bd10a526b1f54c2d8a52abdad15d85Jeff Sharkey        public boolean onCreateActionMode(ActionMode mode, Menu menu) {
263be8b12e687bd10a526b1f54c2d8a52abdad15d85Jeff Sharkey            mode.getMenuInflater().inflate(R.menu.mode_directory, menu);
264be8b12e687bd10a526b1f54c2d8a52abdad15d85Jeff Sharkey            return true;
265be8b12e687bd10a526b1f54c2d8a52abdad15d85Jeff Sharkey        }
266be8b12e687bd10a526b1f54c2d8a52abdad15d85Jeff Sharkey
267be8b12e687bd10a526b1f54c2d8a52abdad15d85Jeff Sharkey        @Override
268be8b12e687bd10a526b1f54c2d8a52abdad15d85Jeff Sharkey        public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
269be8b12e687bd10a526b1f54c2d8a52abdad15d85Jeff Sharkey            return true;
270be8b12e687bd10a526b1f54c2d8a52abdad15d85Jeff Sharkey        }
271be8b12e687bd10a526b1f54c2d8a52abdad15d85Jeff Sharkey
272be8b12e687bd10a526b1f54c2d8a52abdad15d85Jeff Sharkey        @Override
273be8b12e687bd10a526b1f54c2d8a52abdad15d85Jeff Sharkey        public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
274be8b12e687bd10a526b1f54c2d8a52abdad15d85Jeff Sharkey            if (item.getItemId() == R.id.menu_open) {
275dc2963aecaf38bf53d6de82957412a486049c207Jeff Sharkey                final Uri uri = getArguments().getParcelable(EXTRA_URI);
276be8b12e687bd10a526b1f54c2d8a52abdad15d85Jeff Sharkey                final SparseBooleanArray checked = mCurrentView.getCheckedItemPositions();
277be8b12e687bd10a526b1f54c2d8a52abdad15d85Jeff Sharkey                final ArrayList<Document> docs = Lists.newArrayList();
278be8b12e687bd10a526b1f54c2d8a52abdad15d85Jeff Sharkey
279be8b12e687bd10a526b1f54c2d8a52abdad15d85Jeff Sharkey                final int size = checked.size();
280be8b12e687bd10a526b1f54c2d8a52abdad15d85Jeff Sharkey                for (int i = 0; i < size; i++) {
281be8b12e687bd10a526b1f54c2d8a52abdad15d85Jeff Sharkey                    if (checked.valueAt(i)) {
282be8b12e687bd10a526b1f54c2d8a52abdad15d85Jeff Sharkey                        final Cursor cursor = (Cursor) mAdapter.getItem(checked.keyAt(i));
283dc2963aecaf38bf53d6de82957412a486049c207Jeff Sharkey                        docs.add(Document.fromCursor(uri, cursor));
284be8b12e687bd10a526b1f54c2d8a52abdad15d85Jeff Sharkey                    }
285be8b12e687bd10a526b1f54c2d8a52abdad15d85Jeff Sharkey                }
286be8b12e687bd10a526b1f54c2d8a52abdad15d85Jeff Sharkey
287be8b12e687bd10a526b1f54c2d8a52abdad15d85Jeff Sharkey                ((DocumentsActivity) getActivity()).onDocumentsPicked(docs);
288be8b12e687bd10a526b1f54c2d8a52abdad15d85Jeff Sharkey                return true;
289be8b12e687bd10a526b1f54c2d8a52abdad15d85Jeff Sharkey            } else {
290be8b12e687bd10a526b1f54c2d8a52abdad15d85Jeff Sharkey                return false;
291be8b12e687bd10a526b1f54c2d8a52abdad15d85Jeff Sharkey            }
292be8b12e687bd10a526b1f54c2d8a52abdad15d85Jeff Sharkey        }
293be8b12e687bd10a526b1f54c2d8a52abdad15d85Jeff Sharkey
294be8b12e687bd10a526b1f54c2d8a52abdad15d85Jeff Sharkey        @Override
295be8b12e687bd10a526b1f54c2d8a52abdad15d85Jeff Sharkey        public void onDestroyActionMode(ActionMode mode) {
296be8b12e687bd10a526b1f54c2d8a52abdad15d85Jeff Sharkey            // ignored
297be8b12e687bd10a526b1f54c2d8a52abdad15d85Jeff Sharkey        }
298be8b12e687bd10a526b1f54c2d8a52abdad15d85Jeff Sharkey
299be8b12e687bd10a526b1f54c2d8a52abdad15d85Jeff Sharkey        @Override
300be8b12e687bd10a526b1f54c2d8a52abdad15d85Jeff Sharkey        public void onItemCheckedStateChanged(
301be8b12e687bd10a526b1f54c2d8a52abdad15d85Jeff Sharkey                ActionMode mode, int position, long id, boolean checked) {
302be8b12e687bd10a526b1f54c2d8a52abdad15d85Jeff Sharkey            if (checked) {
303be8b12e687bd10a526b1f54c2d8a52abdad15d85Jeff Sharkey                final Cursor cursor = (Cursor) mAdapter.getItem(position);
304be8b12e687bd10a526b1f54c2d8a52abdad15d85Jeff Sharkey                final String mimeType = getCursorString(cursor, DocumentColumns.MIME_TYPE);
305be8b12e687bd10a526b1f54c2d8a52abdad15d85Jeff Sharkey
306be8b12e687bd10a526b1f54c2d8a52abdad15d85Jeff Sharkey                // Directories cannot be checked
307be8b12e687bd10a526b1f54c2d8a52abdad15d85Jeff Sharkey                if (DocumentsContract.MIME_TYPE_DIRECTORY.equals(mimeType)) {
308be8b12e687bd10a526b1f54c2d8a52abdad15d85Jeff Sharkey                    mCurrentView.setItemChecked(position, false);
309be8b12e687bd10a526b1f54c2d8a52abdad15d85Jeff Sharkey                }
310be8b12e687bd10a526b1f54c2d8a52abdad15d85Jeff Sharkey            }
311be8b12e687bd10a526b1f54c2d8a52abdad15d85Jeff Sharkey
312be8b12e687bd10a526b1f54c2d8a52abdad15d85Jeff Sharkey            mode.setTitle(getResources()
313be8b12e687bd10a526b1f54c2d8a52abdad15d85Jeff Sharkey                    .getString(R.string.mode_selected_count, mCurrentView.getCheckedItemCount()));
314be8b12e687bd10a526b1f54c2d8a52abdad15d85Jeff Sharkey        }
315be8b12e687bd10a526b1f54c2d8a52abdad15d85Jeff Sharkey    };
316be8b12e687bd10a526b1f54c2d8a52abdad15d85Jeff Sharkey
3171482789374fb8da3abea8f6f4f272a67205b95dbJeff Sharkey    private static DisplayState getDisplayState(Fragment fragment) {
3181482789374fb8da3abea8f6f4f272a67205b95dbJeff Sharkey        return ((DocumentsActivity) fragment.getActivity()).getDisplayState();
31954e55b740fef1be654c3959aee41ef5ddfa61293Jeff Sharkey    }
32054e55b740fef1be654c3959aee41ef5ddfa61293Jeff Sharkey
3219e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkey    private class DocumentsAdapter extends CursorAdapter {
3229e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkey        public DocumentsAdapter(Context context) {
3239e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkey            super(context, null, false);
3249e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkey        }
3259e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkey
3269e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkey        @Override
3279e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkey        public View newView(Context context, Cursor cursor, ViewGroup parent) {
32854e55b740fef1be654c3959aee41ef5ddfa61293Jeff Sharkey            final LayoutInflater inflater = LayoutInflater.from(context);
3291482789374fb8da3abea8f6f4f272a67205b95dbJeff Sharkey            final DisplayState state = getDisplayState(DirectoryFragment.this);
3301482789374fb8da3abea8f6f4f272a67205b95dbJeff Sharkey            if (state.mode == DisplayState.MODE_LIST) {
33154e55b740fef1be654c3959aee41ef5ddfa61293Jeff Sharkey                return inflater.inflate(R.layout.item_doc_list, parent, false);
3321482789374fb8da3abea8f6f4f272a67205b95dbJeff Sharkey            } else if (state.mode == DisplayState.MODE_GRID) {
33354e55b740fef1be654c3959aee41ef5ddfa61293Jeff Sharkey                return inflater.inflate(R.layout.item_doc_grid, parent, false);
33454e55b740fef1be654c3959aee41ef5ddfa61293Jeff Sharkey            } else {
33554e55b740fef1be654c3959aee41ef5ddfa61293Jeff Sharkey                throw new IllegalStateException();
33654e55b740fef1be654c3959aee41ef5ddfa61293Jeff Sharkey            }
3379e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkey        }
3389e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkey
3399e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkey        @Override
3409e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkey        public void bindView(View view, Context context, Cursor cursor) {
3419e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkey            final TextView title = (TextView) view.findViewById(android.R.id.title);
3429e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkey            final TextView summary = (TextView) view.findViewById(android.R.id.summary);
3439e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkey            final ImageView icon = (ImageView) view.findViewById(android.R.id.icon);
3449e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkey
34592d7e697a864a3e18bef4ef256bb3eb339a66b4eJeff Sharkey            final String docId = getCursorString(cursor, DocumentColumns.DOC_ID);
3469e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkey            final String displayName = getCursorString(cursor, DocumentColumns.DISPLAY_NAME);
3479e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkey            final String mimeType = getCursorString(cursor, DocumentColumns.MIME_TYPE);
34854e55b740fef1be654c3959aee41ef5ddfa61293Jeff Sharkey            final long lastModified = getCursorLong(cursor, DocumentColumns.LAST_MODIFIED);
3499e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkey            final int flags = getCursorInt(cursor, DocumentColumns.FLAGS);
3509e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkey
351dc2963aecaf38bf53d6de82957412a486049c207Jeff Sharkey            final Uri uri = getArguments().getParcelable(EXTRA_URI);
3529e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkey            if ((flags & DocumentsContract.FLAG_SUPPORTS_THUMBNAIL) != 0) {
353dc2963aecaf38bf53d6de82957412a486049c207Jeff Sharkey                final Uri childUri = DocumentsContract.buildDocumentUri(uri, docId);
3549e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkey                icon.setImageURI(childUri);
3559e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkey            } else {
356dc2963aecaf38bf53d6de82957412a486049c207Jeff Sharkey                icon.setImageDrawable(DocumentsActivity.resolveDocumentIcon(
357dc2963aecaf38bf53d6de82957412a486049c207Jeff Sharkey                        context, uri.getAuthority(), mimeType));
3589e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkey            }
3599e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkey
3609e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkey            title.setText(displayName);
36154e55b740fef1be654c3959aee41ef5ddfa61293Jeff Sharkey            if (summary != null) {
36254e55b740fef1be654c3959aee41ef5ddfa61293Jeff Sharkey                summary.setText(DateUtils.getRelativeTimeSpanString(lastModified));
36354e55b740fef1be654c3959aee41ef5ddfa61293Jeff Sharkey            }
36454e55b740fef1be654c3959aee41ef5ddfa61293Jeff Sharkey        }
36554e55b740fef1be654c3959aee41ef5ddfa61293Jeff Sharkey    }
36654e55b740fef1be654c3959aee41ef5ddfa61293Jeff Sharkey
36754e55b740fef1be654c3959aee41ef5ddfa61293Jeff Sharkey    public static String getCursorString(Cursor cursor, String columnName) {
3689e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkey        return cursor.getString(cursor.getColumnIndex(columnName));
3699e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkey    }
3709e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkey
37154e55b740fef1be654c3959aee41ef5ddfa61293Jeff Sharkey    public static long getCursorLong(Cursor cursor, String columnName) {
37254e55b740fef1be654c3959aee41ef5ddfa61293Jeff Sharkey        return cursor.getLong(cursor.getColumnIndex(columnName));
37354e55b740fef1be654c3959aee41ef5ddfa61293Jeff Sharkey    }
37454e55b740fef1be654c3959aee41ef5ddfa61293Jeff Sharkey
37554e55b740fef1be654c3959aee41ef5ddfa61293Jeff Sharkey    public static int getCursorInt(Cursor cursor, String columnName) {
3769e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkey        return cursor.getInt(cursor.getColumnIndex(columnName));
3779e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkey    }
3789e0036ed7d3260d79cc5f9ffd8e3bbe760699924Jeff Sharkey}
379