166516697a29cf00d93893a1011d3befc7c1ee37fJeff Sharkey/*
266516697a29cf00d93893a1011d3befc7c1ee37fJeff Sharkey * Copyright (C) 2013 The Android Open Source Project
366516697a29cf00d93893a1011d3befc7c1ee37fJeff Sharkey *
466516697a29cf00d93893a1011d3befc7c1ee37fJeff Sharkey * Licensed under the Apache License, Version 2.0 (the "License");
566516697a29cf00d93893a1011d3befc7c1ee37fJeff Sharkey * you may not use this file except in compliance with the License.
666516697a29cf00d93893a1011d3befc7c1ee37fJeff Sharkey * You may obtain a copy of the License at
766516697a29cf00d93893a1011d3befc7c1ee37fJeff Sharkey *
866516697a29cf00d93893a1011d3befc7c1ee37fJeff Sharkey *      http://www.apache.org/licenses/LICENSE-2.0
966516697a29cf00d93893a1011d3befc7c1ee37fJeff Sharkey *
1066516697a29cf00d93893a1011d3befc7c1ee37fJeff Sharkey * Unless required by applicable law or agreed to in writing, software
1166516697a29cf00d93893a1011d3befc7c1ee37fJeff Sharkey * distributed under the License is distributed on an "AS IS" BASIS,
1266516697a29cf00d93893a1011d3befc7c1ee37fJeff Sharkey * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1366516697a29cf00d93893a1011d3befc7c1ee37fJeff Sharkey * See the License for the specific language governing permissions and
1466516697a29cf00d93893a1011d3befc7c1ee37fJeff Sharkey * limitations under the License.
1566516697a29cf00d93893a1011d3befc7c1ee37fJeff Sharkey */
1666516697a29cf00d93893a1011d3befc7c1ee37fJeff Sharkey
1766516697a29cf00d93893a1011d3befc7c1ee37fJeff Sharkeypackage com.android.documentsui;
1866516697a29cf00d93893a1011d3befc7c1ee37fJeff Sharkey
1935820cfe963ce120a5876b8a123d5b1df13cbac5Steve McKayimport static com.android.documentsui.Shared.DEBUG;
2035820cfe963ce120a5876b8a123d5b1df13cbac5Steve McKay
2153f109b39e2b62fa3730ce1c43344df2c733251cSteve McKayimport android.app.Activity;
2266516697a29cf00d93893a1011d3befc7c1ee37fJeff Sharkeyimport android.app.Fragment;
2366516697a29cf00d93893a1011d3befc7c1ee37fJeff Sharkeyimport android.app.FragmentManager;
2466516697a29cf00d93893a1011d3befc7c1ee37fJeff Sharkeyimport android.app.FragmentTransaction;
25a9ce049db87259e302e2368d2a4a1c11a94fd831Jeff Sharkeyimport android.app.LoaderManager.LoaderCallbacks;
2666516697a29cf00d93893a1011d3befc7c1ee37fJeff Sharkeyimport android.content.Context;
2754ca29a5b94c2edf461c5433825d4ae17469fd7cJeff Sharkeyimport android.content.Intent;
28a9ce049db87259e302e2368d2a4a1c11a94fd831Jeff Sharkeyimport android.content.Loader;
2954ca29a5b94c2edf461c5433825d4ae17469fd7cJeff Sharkeyimport android.content.pm.PackageManager;
3054ca29a5b94c2edf461c5433825d4ae17469fd7cJeff Sharkeyimport android.content.pm.ResolveInfo;
31c24bbd4ce525d80e385de6e27b19dac239db1dfdJeff Sharkeyimport android.net.Uri;
3266516697a29cf00d93893a1011d3befc7c1ee37fJeff Sharkeyimport android.os.Bundle;
33c24bbd4ce525d80e385de6e27b19dac239db1dfdJeff Sharkeyimport android.provider.Settings;
344a1ca86f4757647b62995eede2a45d06273503bfSteve McKayimport android.support.annotation.Nullable;
354ec973925fc2cd18f9ec0d0ca5af588564fded27Jeff Sharkeyimport android.text.TextUtils;
369fb567b59112f99e64e0bff6f343188331bad28dJeff Sharkeyimport android.text.format.Formatter;
3735820cfe963ce120a5876b8a123d5b1df13cbac5Steve McKayimport android.util.Log;
3866516697a29cf00d93893a1011d3befc7c1ee37fJeff Sharkeyimport android.view.LayoutInflater;
3966516697a29cf00d93893a1011d3befc7c1ee37fJeff Sharkeyimport android.view.View;
4066516697a29cf00d93893a1011d3befc7c1ee37fJeff Sharkeyimport android.view.ViewGroup;
4166516697a29cf00d93893a1011d3befc7c1ee37fJeff Sharkeyimport android.widget.AdapterView;
4266516697a29cf00d93893a1011d3befc7c1ee37fJeff Sharkeyimport android.widget.AdapterView.OnItemClickListener;
43c24bbd4ce525d80e385de6e27b19dac239db1dfdJeff Sharkeyimport android.widget.AdapterView.OnItemLongClickListener;
4466516697a29cf00d93893a1011d3befc7c1ee37fJeff Sharkeyimport android.widget.ArrayAdapter;
4566516697a29cf00d93893a1011d3befc7c1ee37fJeff Sharkeyimport android.widget.ImageView;
4666516697a29cf00d93893a1011d3befc7c1ee37fJeff Sharkeyimport android.widget.ListView;
4766516697a29cf00d93893a1011d3befc7c1ee37fJeff Sharkeyimport android.widget.TextView;
4866516697a29cf00d93893a1011d3befc7c1ee37fJeff Sharkey
49ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkeyimport com.android.documentsui.model.RootInfo;
5066516697a29cf00d93893a1011d3befc7c1ee37fJeff Sharkey
5158efce36cd1b26006e08ddd696292bf06fc34c81Steve McKayimport java.util.ArrayList;
52a9ce049db87259e302e2368d2a4a1c11a94fd831Jeff Sharkeyimport java.util.Collection;
536efba22ce510352bb84910d6efc42fecafd31ed7Jeff Sharkeyimport java.util.Collections;
54aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkeyimport java.util.Comparator;
5554ca29a5b94c2edf461c5433825d4ae17469fd7cJeff Sharkeyimport java.util.List;
56e6585b32ea586743258a5457e2184ffc087f2d2fKenny Rootimport java.util.Objects;
5766516697a29cf00d93893a1011d3befc7c1ee37fJeff Sharkey
5866516697a29cf00d93893a1011d3befc7c1ee37fJeff Sharkey/**
5966516697a29cf00d93893a1011d3befc7c1ee37fJeff Sharkey * Display list of known storage backend roots.
6066516697a29cf00d93893a1011d3befc7c1ee37fJeff Sharkey */
6166516697a29cf00d93893a1011d3befc7c1ee37fJeff Sharkeypublic class RootsFragment extends Fragment {
6266516697a29cf00d93893a1011d3befc7c1ee37fJeff Sharkey
6335820cfe963ce120a5876b8a123d5b1df13cbac5Steve McKay    private static final String TAG = "RootsFragment";
6435820cfe963ce120a5876b8a123d5b1df13cbac5Steve McKay    private static final String EXTRA_INCLUDE_APPS = "includeApps";
6535820cfe963ce120a5876b8a123d5b1df13cbac5Steve McKay
6666516697a29cf00d93893a1011d3befc7c1ee37fJeff Sharkey    private ListView mList;
676efba22ce510352bb84910d6efc42fecafd31ed7Jeff Sharkey    private RootsAdapter mAdapter;
68a9ce049db87259e302e2368d2a4a1c11a94fd831Jeff Sharkey    private LoaderCallbacks<Collection<RootInfo>> mCallbacks;
69a9ce049db87259e302e2368d2a4a1c11a94fd831Jeff Sharkey
7054ca29a5b94c2edf461c5433825d4ae17469fd7cJeff Sharkey
7154ca29a5b94c2edf461c5433825d4ae17469fd7cJeff Sharkey    public static void show(FragmentManager fm, Intent includeApps) {
7254ca29a5b94c2edf461c5433825d4ae17469fd7cJeff Sharkey        final Bundle args = new Bundle();
7354ca29a5b94c2edf461c5433825d4ae17469fd7cJeff Sharkey        args.putParcelable(EXTRA_INCLUDE_APPS, includeApps);
7454ca29a5b94c2edf461c5433825d4ae17469fd7cJeff Sharkey
7566516697a29cf00d93893a1011d3befc7c1ee37fJeff Sharkey        final RootsFragment fragment = new RootsFragment();
7654ca29a5b94c2edf461c5433825d4ae17469fd7cJeff Sharkey        fragment.setArguments(args);
7766516697a29cf00d93893a1011d3befc7c1ee37fJeff Sharkey
7866516697a29cf00d93893a1011d3befc7c1ee37fJeff Sharkey        final FragmentTransaction ft = fm.beginTransaction();
7966516697a29cf00d93893a1011d3befc7c1ee37fJeff Sharkey        ft.replace(R.id.container_roots, fragment);
8066516697a29cf00d93893a1011d3befc7c1ee37fJeff Sharkey        ft.commitAllowingStateLoss();
8166516697a29cf00d93893a1011d3befc7c1ee37fJeff Sharkey    }
8266516697a29cf00d93893a1011d3befc7c1ee37fJeff Sharkey
8366516697a29cf00d93893a1011d3befc7c1ee37fJeff Sharkey    public static RootsFragment get(FragmentManager fm) {
8466516697a29cf00d93893a1011d3befc7c1ee37fJeff Sharkey        return (RootsFragment) fm.findFragmentById(R.id.container_roots);
8566516697a29cf00d93893a1011d3befc7c1ee37fJeff Sharkey    }
8666516697a29cf00d93893a1011d3befc7c1ee37fJeff Sharkey
8766516697a29cf00d93893a1011d3befc7c1ee37fJeff Sharkey    @Override
8866516697a29cf00d93893a1011d3befc7c1ee37fJeff Sharkey    public View onCreateView(
8966516697a29cf00d93893a1011d3befc7c1ee37fJeff Sharkey            LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
9066516697a29cf00d93893a1011d3befc7c1ee37fJeff Sharkey
9166516697a29cf00d93893a1011d3befc7c1ee37fJeff Sharkey        final View view = inflater.inflate(R.layout.fragment_roots, container, false);
922036dad877336bf4d81202c334b1f2c81462bd9fBen Kwa        mList = (ListView) view.findViewById(R.id.roots_list);
9366516697a29cf00d93893a1011d3befc7c1ee37fJeff Sharkey        mList.setOnItemClickListener(mItemListener);
9428c05ee8931cecf4c51c470e0043d30196010c49Jeff Sharkey        mList.setChoiceMode(ListView.CHOICE_MODE_SINGLE);
9566516697a29cf00d93893a1011d3befc7c1ee37fJeff Sharkey        return view;
9666516697a29cf00d93893a1011d3befc7c1ee37fJeff Sharkey    }
9766516697a29cf00d93893a1011d3befc7c1ee37fJeff Sharkey
989fb567b59112f99e64e0bff6f343188331bad28dJeff Sharkey    @Override
99a9ce049db87259e302e2368d2a4a1c11a94fd831Jeff Sharkey    public void onActivityCreated(Bundle savedInstanceState) {
100a9ce049db87259e302e2368d2a4a1c11a94fd831Jeff Sharkey        super.onActivityCreated(savedInstanceState);
101a9ce049db87259e302e2368d2a4a1c11a94fd831Jeff Sharkey
102a9ce049db87259e302e2368d2a4a1c11a94fd831Jeff Sharkey        final Context context = getActivity();
103a9ce049db87259e302e2368d2a4a1c11a94fd831Jeff Sharkey        final RootsCache roots = DocumentsApplication.getRootsCache(context);
104e934ce6f8430f50d1d22bccd3b341b982f5541eeSteve McKay        final State state = ((BaseActivity) context).getDisplayState();
105a9ce049db87259e302e2368d2a4a1c11a94fd831Jeff Sharkey
106a9ce049db87259e302e2368d2a4a1c11a94fd831Jeff Sharkey        mCallbacks = new LoaderCallbacks<Collection<RootInfo>>() {
107a9ce049db87259e302e2368d2a4a1c11a94fd831Jeff Sharkey            @Override
108a9ce049db87259e302e2368d2a4a1c11a94fd831Jeff Sharkey            public Loader<Collection<RootInfo>> onCreateLoader(int id, Bundle args) {
109a9ce049db87259e302e2368d2a4a1c11a94fd831Jeff Sharkey                return new RootsLoader(context, roots, state);
110a9ce049db87259e302e2368d2a4a1c11a94fd831Jeff Sharkey            }
111a9ce049db87259e302e2368d2a4a1c11a94fd831Jeff Sharkey
112a9ce049db87259e302e2368d2a4a1c11a94fd831Jeff Sharkey            @Override
113a9ce049db87259e302e2368d2a4a1c11a94fd831Jeff Sharkey            public void onLoadFinished(
114a9ce049db87259e302e2368d2a4a1c11a94fd831Jeff Sharkey                    Loader<Collection<RootInfo>> loader, Collection<RootInfo> result) {
1154a1ca86f4757647b62995eede2a45d06273503bfSteve McKay                if (!isAdded()) {
1164a1ca86f4757647b62995eede2a45d06273503bfSteve McKay                    return;
1174a1ca86f4757647b62995eede2a45d06273503bfSteve McKay                }
118a9ce049db87259e302e2368d2a4a1c11a94fd831Jeff Sharkey
1194a1ca86f4757647b62995eede2a45d06273503bfSteve McKay                Intent handlerAppIntent = getArguments().getParcelable(EXTRA_INCLUDE_APPS);
120a9ce049db87259e302e2368d2a4a1c11a94fd831Jeff Sharkey
121973168c142747fced7b3567019f4008b43920320Aga Wronska                mAdapter = new RootsAdapter(context, result, handlerAppIntent, state);
122a9ce049db87259e302e2368d2a4a1c11a94fd831Jeff Sharkey                mList.setAdapter(mAdapter);
123a9ce049db87259e302e2368d2a4a1c11a94fd831Jeff Sharkey
124a9ce049db87259e302e2368d2a4a1c11a94fd831Jeff Sharkey                onCurrentRootChanged();
125a9ce049db87259e302e2368d2a4a1c11a94fd831Jeff Sharkey            }
126a9ce049db87259e302e2368d2a4a1c11a94fd831Jeff Sharkey
127a9ce049db87259e302e2368d2a4a1c11a94fd831Jeff Sharkey            @Override
128a9ce049db87259e302e2368d2a4a1c11a94fd831Jeff Sharkey            public void onLoaderReset(Loader<Collection<RootInfo>> loader) {
129a9ce049db87259e302e2368d2a4a1c11a94fd831Jeff Sharkey                mAdapter = null;
130a9ce049db87259e302e2368d2a4a1c11a94fd831Jeff Sharkey                mList.setAdapter(null);
131a9ce049db87259e302e2368d2a4a1c11a94fd831Jeff Sharkey            }
132a9ce049db87259e302e2368d2a4a1c11a94fd831Jeff Sharkey        };
133a9ce049db87259e302e2368d2a4a1c11a94fd831Jeff Sharkey    }
134a9ce049db87259e302e2368d2a4a1c11a94fd831Jeff Sharkey
135a9ce049db87259e302e2368d2a4a1c11a94fd831Jeff Sharkey    @Override
13688f322c3115e85bb96fb46f9192b5daecd472c64Jeff Sharkey    public void onResume() {
13788f322c3115e85bb96fb46f9192b5daecd472c64Jeff Sharkey        super.onResume();
138669f8e7c70c595964a1c9ca154ac123da84d99a1Jeff Sharkey        onDisplayStateChanged();
139669f8e7c70c595964a1c9ca154ac123da84d99a1Jeff Sharkey    }
1409fb567b59112f99e64e0bff6f343188331bad28dJeff Sharkey
141669f8e7c70c595964a1c9ca154ac123da84d99a1Jeff Sharkey    public void onDisplayStateChanged() {
1429fb567b59112f99e64e0bff6f343188331bad28dJeff Sharkey        final Context context = getActivity();
143e934ce6f8430f50d1d22bccd3b341b982f5541eeSteve McKay        final State state = ((BaseActivity) context).getDisplayState();
144348ad6866b91afa4d59d45df533ef88094c74d13Jeff Sharkey
145e934ce6f8430f50d1d22bccd3b341b982f5541eeSteve McKay        if (state.action == State.ACTION_GET_CONTENT) {
146c24bbd4ce525d80e385de6e27b19dac239db1dfdJeff Sharkey            mList.setOnItemLongClickListener(mItemLongClickListener);
147c24bbd4ce525d80e385de6e27b19dac239db1dfdJeff Sharkey        } else {
148c24bbd4ce525d80e385de6e27b19dac239db1dfdJeff Sharkey            mList.setOnItemLongClickListener(null);
149c24bbd4ce525d80e385de6e27b19dac239db1dfdJeff Sharkey            mList.setLongClickable(false);
150c24bbd4ce525d80e385de6e27b19dac239db1dfdJeff Sharkey        }
151c24bbd4ce525d80e385de6e27b19dac239db1dfdJeff Sharkey
152a9ce049db87259e302e2368d2a4a1c11a94fd831Jeff Sharkey        getLoaderManager().restartLoader(2, null, mCallbacks);
15328c05ee8931cecf4c51c470e0043d30196010c49Jeff Sharkey    }
15428c05ee8931cecf4c51c470e0043d30196010c49Jeff Sharkey
15528c05ee8931cecf4c51c470e0043d30196010c49Jeff Sharkey    public void onCurrentRootChanged() {
1564a1ca86f4757647b62995eede2a45d06273503bfSteve McKay        if (mAdapter == null) {
1574a1ca86f4757647b62995eede2a45d06273503bfSteve McKay            return;
1584a1ca86f4757647b62995eede2a45d06273503bfSteve McKay        }
15928c05ee8931cecf4c51c470e0043d30196010c49Jeff Sharkey
160e934ce6f8430f50d1d22bccd3b341b982f5541eeSteve McKay        final RootInfo root = ((BaseActivity) getActivity()).getCurrentRoot();
16128c05ee8931cecf4c51c470e0043d30196010c49Jeff Sharkey        for (int i = 0; i < mAdapter.getCount(); i++) {
16228c05ee8931cecf4c51c470e0043d30196010c49Jeff Sharkey            final Object item = mAdapter.getItem(i);
163a82c2e24bc226c123075331cdaafb171b3b07b85Jeff Sharkey            if (item instanceof RootItem) {
164a82c2e24bc226c123075331cdaafb171b3b07b85Jeff Sharkey                final RootInfo testRoot = ((RootItem) item).root;
165e6585b32ea586743258a5457e2184ffc087f2d2fKenny Root                if (Objects.equals(testRoot, root)) {
166a82c2e24bc226c123075331cdaafb171b3b07b85Jeff Sharkey                    mList.setItemChecked(i, true);
1678e1c9637ec56fbfe313e964a5b60986c1bb092b9Aga Wronska                    mList.setSelection(i);
168a82c2e24bc226c123075331cdaafb171b3b07b85Jeff Sharkey                    return;
169a82c2e24bc226c123075331cdaafb171b3b07b85Jeff Sharkey                }
17028c05ee8931cecf4c51c470e0043d30196010c49Jeff Sharkey            }
17128c05ee8931cecf4c51c470e0043d30196010c49Jeff Sharkey        }
1729fb567b59112f99e64e0bff6f343188331bad28dJeff Sharkey    }
1739fb567b59112f99e64e0bff6f343188331bad28dJeff Sharkey
1742036dad877336bf4d81202c334b1f2c81462bd9fBen Kwa    /**
1752036dad877336bf4d81202c334b1f2c81462bd9fBen Kwa     * Attempts to shift focus back to the navigation drawer.
1762036dad877336bf4d81202c334b1f2c81462bd9fBen Kwa     */
1772036dad877336bf4d81202c334b1f2c81462bd9fBen Kwa    public void requestFocus() {
1782036dad877336bf4d81202c334b1f2c81462bd9fBen Kwa        mList.requestFocus();
1792036dad877336bf4d81202c334b1f2c81462bd9fBen Kwa    }
1802036dad877336bf4d81202c334b1f2c81462bd9fBen Kwa
181c24bbd4ce525d80e385de6e27b19dac239db1dfdJeff Sharkey    private void showAppDetails(ResolveInfo ri) {
182c24bbd4ce525d80e385de6e27b19dac239db1dfdJeff Sharkey        final Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
183c24bbd4ce525d80e385de6e27b19dac239db1dfdJeff Sharkey        intent.setData(Uri.fromParts("package", ri.activityInfo.packageName, null));
184c24bbd4ce525d80e385de6e27b19dac239db1dfdJeff Sharkey        intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET);
185c24bbd4ce525d80e385de6e27b19dac239db1dfdJeff Sharkey        startActivity(intent);
186c24bbd4ce525d80e385de6e27b19dac239db1dfdJeff Sharkey    }
187c24bbd4ce525d80e385de6e27b19dac239db1dfdJeff Sharkey
18866516697a29cf00d93893a1011d3befc7c1ee37fJeff Sharkey    private OnItemClickListener mItemListener = new OnItemClickListener() {
18966516697a29cf00d93893a1011d3befc7c1ee37fJeff Sharkey        @Override
19066516697a29cf00d93893a1011d3befc7c1ee37fJeff Sharkey        public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
191ef3e2cf35fbede340d5ff830b410baea8e461a94Steve McKay            Item item = mAdapter.getItem(position);
1926efba22ce510352bb84910d6efc42fecafd31ed7Jeff Sharkey            if (item instanceof RootItem) {
193ef3e2cf35fbede340d5ff830b410baea8e461a94Steve McKay                BaseActivity activity = BaseActivity.get(RootsFragment.this);
19445f75e2a81674d792077516f13088d476c0ba510Aga Wronska                RootInfo newRoot = ((RootItem) item).root;
19545f75e2a81674d792077516f13088d476c0ba510Aga Wronska                Metrics.logRootVisited(getActivity(), newRoot);
19645f75e2a81674d792077516f13088d476c0ba510Aga Wronska                activity.onRootPicked(newRoot);
1976efba22ce510352bb84910d6efc42fecafd31ed7Jeff Sharkey            } else if (item instanceof AppItem) {
198ef3e2cf35fbede340d5ff830b410baea8e461a94Steve McKay                DocumentsActivity activity = DocumentsActivity.get(RootsFragment.this);
199723799858a15fa316128716d9e131a681d1a51d2Ben Kwa                ResolveInfo info = ((AppItem) item).info;
200723799858a15fa316128716d9e131a681d1a51d2Ben Kwa                Metrics.logAppVisited(getActivity(), info);
201723799858a15fa316128716d9e131a681d1a51d2Ben Kwa                activity.onAppPicked(info);
20235820cfe963ce120a5876b8a123d5b1df13cbac5Steve McKay            } else if (item instanceof SpacerItem) {
20335820cfe963ce120a5876b8a123d5b1df13cbac5Steve McKay                if (DEBUG) Log.d(TAG, "Ignoring click on spacer item.");
20454ca29a5b94c2edf461c5433825d4ae17469fd7cJeff Sharkey            } else {
20554ca29a5b94c2edf461c5433825d4ae17469fd7cJeff Sharkey                throw new IllegalStateException("Unknown root: " + item);
20654ca29a5b94c2edf461c5433825d4ae17469fd7cJeff Sharkey            }
20766516697a29cf00d93893a1011d3befc7c1ee37fJeff Sharkey        }
20866516697a29cf00d93893a1011d3befc7c1ee37fJeff Sharkey    };
20966516697a29cf00d93893a1011d3befc7c1ee37fJeff Sharkey
210c24bbd4ce525d80e385de6e27b19dac239db1dfdJeff Sharkey    private OnItemLongClickListener mItemLongClickListener = new OnItemLongClickListener() {
211c24bbd4ce525d80e385de6e27b19dac239db1dfdJeff Sharkey        @Override
212c24bbd4ce525d80e385de6e27b19dac239db1dfdJeff Sharkey        public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) {
213c24bbd4ce525d80e385de6e27b19dac239db1dfdJeff Sharkey            final Item item = mAdapter.getItem(position);
214c24bbd4ce525d80e385de6e27b19dac239db1dfdJeff Sharkey            if (item instanceof AppItem) {
215c24bbd4ce525d80e385de6e27b19dac239db1dfdJeff Sharkey                showAppDetails(((AppItem) item).info);
216c24bbd4ce525d80e385de6e27b19dac239db1dfdJeff Sharkey                return true;
217c24bbd4ce525d80e385de6e27b19dac239db1dfdJeff Sharkey            } else {
218c24bbd4ce525d80e385de6e27b19dac239db1dfdJeff Sharkey                return false;
219c24bbd4ce525d80e385de6e27b19dac239db1dfdJeff Sharkey            }
220c24bbd4ce525d80e385de6e27b19dac239db1dfdJeff Sharkey        }
221c24bbd4ce525d80e385de6e27b19dac239db1dfdJeff Sharkey    };
222c24bbd4ce525d80e385de6e27b19dac239db1dfdJeff Sharkey
2236efba22ce510352bb84910d6efc42fecafd31ed7Jeff Sharkey    private static abstract class Item {
2246efba22ce510352bb84910d6efc42fecafd31ed7Jeff Sharkey        private final int mLayoutId;
2256efba22ce510352bb84910d6efc42fecafd31ed7Jeff Sharkey
2266efba22ce510352bb84910d6efc42fecafd31ed7Jeff Sharkey        public Item(int layoutId) {
2276efba22ce510352bb84910d6efc42fecafd31ed7Jeff Sharkey            mLayoutId = layoutId;
22866516697a29cf00d93893a1011d3befc7c1ee37fJeff Sharkey        }
22966516697a29cf00d93893a1011d3befc7c1ee37fJeff Sharkey
2306efba22ce510352bb84910d6efc42fecafd31ed7Jeff Sharkey        public View getView(View convertView, ViewGroup parent) {
2319eb88180592dfd65a0afc5d7373bb35403cf4657Garfield, Tan            // Disable recycling views because 1) it's very unlikely a view can be recycled here;
2329eb88180592dfd65a0afc5d7373bb35403cf4657Garfield, Tan            // 2) there is no easy way for us to know with which layout id the convertView was
2339eb88180592dfd65a0afc5d7373bb35403cf4657Garfield, Tan            // inflated; and 3) simplicity is much appreciated at this time.
2349eb88180592dfd65a0afc5d7373bb35403cf4657Garfield, Tan            convertView = LayoutInflater.from(parent.getContext())
2356efba22ce510352bb84910d6efc42fecafd31ed7Jeff Sharkey                        .inflate(mLayoutId, parent, false);
2366efba22ce510352bb84910d6efc42fecafd31ed7Jeff Sharkey            bindView(convertView);
2376efba22ce510352bb84910d6efc42fecafd31ed7Jeff Sharkey            return convertView;
2386efba22ce510352bb84910d6efc42fecafd31ed7Jeff Sharkey        }
2396efba22ce510352bb84910d6efc42fecafd31ed7Jeff Sharkey
2406efba22ce510352bb84910d6efc42fecafd31ed7Jeff Sharkey        public abstract void bindView(View convertView);
2416efba22ce510352bb84910d6efc42fecafd31ed7Jeff Sharkey    }
24266516697a29cf00d93893a1011d3befc7c1ee37fJeff Sharkey
2436efba22ce510352bb84910d6efc42fecafd31ed7Jeff Sharkey    private static class RootItem extends Item {
2446efba22ce510352bb84910d6efc42fecafd31ed7Jeff Sharkey        public final RootInfo root;
2456efba22ce510352bb84910d6efc42fecafd31ed7Jeff Sharkey
2466efba22ce510352bb84910d6efc42fecafd31ed7Jeff Sharkey        public RootItem(RootInfo root) {
2476efba22ce510352bb84910d6efc42fecafd31ed7Jeff Sharkey            super(R.layout.item_root);
2486efba22ce510352bb84910d6efc42fecafd31ed7Jeff Sharkey            this.root = root;
2496efba22ce510352bb84910d6efc42fecafd31ed7Jeff Sharkey        }
2506efba22ce510352bb84910d6efc42fecafd31ed7Jeff Sharkey
2516efba22ce510352bb84910d6efc42fecafd31ed7Jeff Sharkey        @Override
2526efba22ce510352bb84910d6efc42fecafd31ed7Jeff Sharkey        public void bindView(View convertView) {
25366516697a29cf00d93893a1011d3befc7c1ee37fJeff Sharkey            final ImageView icon = (ImageView) convertView.findViewById(android.R.id.icon);
25466516697a29cf00d93893a1011d3befc7c1ee37fJeff Sharkey            final TextView title = (TextView) convertView.findViewById(android.R.id.title);
25566516697a29cf00d93893a1011d3befc7c1ee37fJeff Sharkey            final TextView summary = (TextView) convertView.findViewById(android.R.id.summary);
25666516697a29cf00d93893a1011d3befc7c1ee37fJeff Sharkey
2576efba22ce510352bb84910d6efc42fecafd31ed7Jeff Sharkey            final Context context = convertView.getContext();
258cbce47001e15be85b084c36a64c20039a0c4a667Jeff Sharkey            icon.setImageDrawable(root.loadDrawerIcon(context));
25966516697a29cf00d93893a1011d3befc7c1ee37fJeff Sharkey            title.setText(root.title);
26066516697a29cf00d93893a1011d3befc7c1ee37fJeff Sharkey
2616efba22ce510352bb84910d6efc42fecafd31ed7Jeff Sharkey            // Show available space if no summary
2626efba22ce510352bb84910d6efc42fecafd31ed7Jeff Sharkey            String summaryText = root.summary;
2636efba22ce510352bb84910d6efc42fecafd31ed7Jeff Sharkey            if (TextUtils.isEmpty(summaryText) && root.availableBytes >= 0) {
2649fb567b59112f99e64e0bff6f343188331bad28dJeff Sharkey                summaryText = context.getString(R.string.root_available_bytes,
2659fb567b59112f99e64e0bff6f343188331bad28dJeff Sharkey                        Formatter.formatFileSize(context, root.availableBytes));
2669fb567b59112f99e64e0bff6f343188331bad28dJeff Sharkey            }
2679fb567b59112f99e64e0bff6f343188331bad28dJeff Sharkey
2689fb567b59112f99e64e0bff6f343188331bad28dJeff Sharkey            summary.setText(summaryText);
2694ec973925fc2cd18f9ec0d0ca5af588564fded27Jeff Sharkey            summary.setVisibility(TextUtils.isEmpty(summaryText) ? View.GONE : View.VISIBLE);
2706efba22ce510352bb84910d6efc42fecafd31ed7Jeff Sharkey        }
2716efba22ce510352bb84910d6efc42fecafd31ed7Jeff Sharkey    }
27266516697a29cf00d93893a1011d3befc7c1ee37fJeff Sharkey
2736efba22ce510352bb84910d6efc42fecafd31ed7Jeff Sharkey    private static class SpacerItem extends Item {
2746efba22ce510352bb84910d6efc42fecafd31ed7Jeff Sharkey        public SpacerItem() {
2756efba22ce510352bb84910d6efc42fecafd31ed7Jeff Sharkey            super(R.layout.item_root_spacer);
27666516697a29cf00d93893a1011d3befc7c1ee37fJeff Sharkey        }
27766516697a29cf00d93893a1011d3befc7c1ee37fJeff Sharkey
27866516697a29cf00d93893a1011d3befc7c1ee37fJeff Sharkey        @Override
2796efba22ce510352bb84910d6efc42fecafd31ed7Jeff Sharkey        public void bindView(View convertView) {
2806efba22ce510352bb84910d6efc42fecafd31ed7Jeff Sharkey            // Nothing to bind
28166516697a29cf00d93893a1011d3befc7c1ee37fJeff Sharkey        }
28266516697a29cf00d93893a1011d3befc7c1ee37fJeff Sharkey    }
28366516697a29cf00d93893a1011d3befc7c1ee37fJeff Sharkey
2846efba22ce510352bb84910d6efc42fecafd31ed7Jeff Sharkey    private static class AppItem extends Item {
2856efba22ce510352bb84910d6efc42fecafd31ed7Jeff Sharkey        public final ResolveInfo info;
2866efba22ce510352bb84910d6efc42fecafd31ed7Jeff Sharkey
2876efba22ce510352bb84910d6efc42fecafd31ed7Jeff Sharkey        public AppItem(ResolveInfo info) {
2886efba22ce510352bb84910d6efc42fecafd31ed7Jeff Sharkey            super(R.layout.item_root);
2896efba22ce510352bb84910d6efc42fecafd31ed7Jeff Sharkey            this.info = info;
29054ca29a5b94c2edf461c5433825d4ae17469fd7cJeff Sharkey        }
29154ca29a5b94c2edf461c5433825d4ae17469fd7cJeff Sharkey
29254ca29a5b94c2edf461c5433825d4ae17469fd7cJeff Sharkey        @Override
2936efba22ce510352bb84910d6efc42fecafd31ed7Jeff Sharkey        public void bindView(View convertView) {
29454ca29a5b94c2edf461c5433825d4ae17469fd7cJeff Sharkey            final ImageView icon = (ImageView) convertView.findViewById(android.R.id.icon);
29554ca29a5b94c2edf461c5433825d4ae17469fd7cJeff Sharkey            final TextView title = (TextView) convertView.findViewById(android.R.id.title);
29654ca29a5b94c2edf461c5433825d4ae17469fd7cJeff Sharkey            final TextView summary = (TextView) convertView.findViewById(android.R.id.summary);
29754ca29a5b94c2edf461c5433825d4ae17469fd7cJeff Sharkey
2986efba22ce510352bb84910d6efc42fecafd31ed7Jeff Sharkey            final PackageManager pm = convertView.getContext().getPackageManager();
29954ca29a5b94c2edf461c5433825d4ae17469fd7cJeff Sharkey            icon.setImageDrawable(info.loadIcon(pm));
30054ca29a5b94c2edf461c5433825d4ae17469fd7cJeff Sharkey            title.setText(info.loadLabel(pm));
30154ca29a5b94c2edf461c5433825d4ae17469fd7cJeff Sharkey
30254ca29a5b94c2edf461c5433825d4ae17469fd7cJeff Sharkey            // TODO: match existing summary behavior from disambig dialog
30354ca29a5b94c2edf461c5433825d4ae17469fd7cJeff Sharkey            summary.setVisibility(View.GONE);
30454ca29a5b94c2edf461c5433825d4ae17469fd7cJeff Sharkey        }
3056efba22ce510352bb84910d6efc42fecafd31ed7Jeff Sharkey    }
30654ca29a5b94c2edf461c5433825d4ae17469fd7cJeff Sharkey
3076efba22ce510352bb84910d6efc42fecafd31ed7Jeff Sharkey    private static class RootsAdapter extends ArrayAdapter<Item> {
3084a1ca86f4757647b62995eede2a45d06273503bfSteve McKay
3094a1ca86f4757647b62995eede2a45d06273503bfSteve McKay        /**
3104a1ca86f4757647b62995eede2a45d06273503bfSteve McKay         * @param handlerAppIntent When not null, apps capable of handling the original
3114a1ca86f4757647b62995eede2a45d06273503bfSteve McKay         *     intent will be included in list of roots (in special section at bottom).
3124a1ca86f4757647b62995eede2a45d06273503bfSteve McKay         */
313973168c142747fced7b3567019f4008b43920320Aga Wronska        public RootsAdapter(Context context, Collection<RootInfo> roots,
314973168c142747fced7b3567019f4008b43920320Aga Wronska                @Nullable Intent handlerAppIntent, State state) {
3156efba22ce510352bb84910d6efc42fecafd31ed7Jeff Sharkey            super(context, 0);
31654ca29a5b94c2edf461c5433825d4ae17469fd7cJeff Sharkey
3170c64308240a7e9d3a78d4dedba2a419da63b5afdBen Kwa            final List<RootItem> libraries = new ArrayList<>();
318abf397458dca89fd3df4234d547a94bf0487033dDaichi Hirono            final List<RootItem> others = new ArrayList<>();
319abf397458dca89fd3df4234d547a94bf0487033dDaichi Hirono
320abf397458dca89fd3df4234d547a94bf0487033dDaichi Hirono            for (final RootInfo root : roots) {
321abf397458dca89fd3df4234d547a94bf0487033dDaichi Hirono                final RootItem item = new RootItem(root);
322b4129d785c1a14d0499fa45291b14ea356d59ee7Aga Wronska
32353f109b39e2b62fa3730ce1c43344df2c733251cSteve McKay                if (root.isHome() &&
32453f109b39e2b62fa3730ce1c43344df2c733251cSteve McKay                        !Shared.shouldShowDocumentsRoot(context, ((Activity) context).getIntent())) {
325b4129d785c1a14d0499fa45291b14ea356d59ee7Aga Wronska                    continue;
326b4129d785c1a14d0499fa45291b14ea356d59ee7Aga Wronska                } else if (root.isLibrary()) {
3273ce95951bd173c422b8d369b4651c28e5bcc20f4Steve McKay                    if (DEBUG) Log.d(TAG, "Adding " + root + " as library.");
328abf397458dca89fd3df4234d547a94bf0487033dDaichi Hirono                    libraries.add(item);
329abf397458dca89fd3df4234d547a94bf0487033dDaichi Hirono                } else {
3303ce95951bd173c422b8d369b4651c28e5bcc20f4Steve McKay                    if (DEBUG) Log.d(TAG, "Adding " + root + " as non-library.");
331abf397458dca89fd3df4234d547a94bf0487033dDaichi Hirono                    others.add(item);
3325545f56f7561810187545a1817b6001dd1f9931bJeff Sharkey                }
3336efba22ce510352bb84910d6efc42fecafd31ed7Jeff Sharkey            }
3345545f56f7561810187545a1817b6001dd1f9931bJeff Sharkey
3356efba22ce510352bb84910d6efc42fecafd31ed7Jeff Sharkey            final RootComparator comp = new RootComparator();
3360c64308240a7e9d3a78d4dedba2a419da63b5afdBen Kwa            Collections.sort(libraries, comp);
337abf397458dca89fd3df4234d547a94bf0487033dDaichi Hirono            Collections.sort(others, comp);
3386efba22ce510352bb84910d6efc42fecafd31ed7Jeff Sharkey
3390c64308240a7e9d3a78d4dedba2a419da63b5afdBen Kwa            addAll(libraries);
3404a1ca86f4757647b62995eede2a45d06273503bfSteve McKay            // Only add the spacer if it is actually separating something.
3414a1ca86f4757647b62995eede2a45d06273503bfSteve McKay            if (!libraries.isEmpty() && !others.isEmpty()) {
3424a1ca86f4757647b62995eede2a45d06273503bfSteve McKay                add(new SpacerItem());
3434a1ca86f4757647b62995eede2a45d06273503bfSteve McKay            }
344abf397458dca89fd3df4234d547a94bf0487033dDaichi Hirono            addAll(others);
34566516697a29cf00d93893a1011d3befc7c1ee37fJeff Sharkey
3464a1ca86f4757647b62995eede2a45d06273503bfSteve McKay            // Include apps that can handle this intent too.
3474a1ca86f4757647b62995eede2a45d06273503bfSteve McKay            if (handlerAppIntent != null) {
3484a1ca86f4757647b62995eede2a45d06273503bfSteve McKay                includeHandlerApps(context, handlerAppIntent);
3494a1ca86f4757647b62995eede2a45d06273503bfSteve McKay            }
3504a1ca86f4757647b62995eede2a45d06273503bfSteve McKay        }
3516efba22ce510352bb84910d6efc42fecafd31ed7Jeff Sharkey
3524a1ca86f4757647b62995eede2a45d06273503bfSteve McKay        /**
3534a1ca86f4757647b62995eede2a45d06273503bfSteve McKay         * Adds apps capable of handling the original intent will be included
3544a1ca86f4757647b62995eede2a45d06273503bfSteve McKay         * in list of roots (in special section at bottom).
3554a1ca86f4757647b62995eede2a45d06273503bfSteve McKay         */
3564a1ca86f4757647b62995eede2a45d06273503bfSteve McKay        private void includeHandlerApps(Context context, Intent handlerAppIntent) {
3574a1ca86f4757647b62995eede2a45d06273503bfSteve McKay            final PackageManager pm = context.getPackageManager();
3584a1ca86f4757647b62995eede2a45d06273503bfSteve McKay            final List<ResolveInfo> infos = pm.queryIntentActivities(
3594a1ca86f4757647b62995eede2a45d06273503bfSteve McKay                    handlerAppIntent, PackageManager.MATCH_DEFAULT_ONLY);
3604a1ca86f4757647b62995eede2a45d06273503bfSteve McKay
3614a1ca86f4757647b62995eede2a45d06273503bfSteve McKay            final List<AppItem> apps = new ArrayList<>();
3624a1ca86f4757647b62995eede2a45d06273503bfSteve McKay
3634a1ca86f4757647b62995eede2a45d06273503bfSteve McKay            // Omit ourselves from the list
3644a1ca86f4757647b62995eede2a45d06273503bfSteve McKay            for (ResolveInfo info : infos) {
3654a1ca86f4757647b62995eede2a45d06273503bfSteve McKay                if (!context.getPackageName().equals(info.activityInfo.packageName)) {
3664a1ca86f4757647b62995eede2a45d06273503bfSteve McKay                    apps.add(new AppItem(info));
3676efba22ce510352bb84910d6efc42fecafd31ed7Jeff Sharkey                }
3684a1ca86f4757647b62995eede2a45d06273503bfSteve McKay            }
3696efba22ce510352bb84910d6efc42fecafd31ed7Jeff Sharkey
3704a1ca86f4757647b62995eede2a45d06273503bfSteve McKay            if (apps.size() > 0) {
3714a1ca86f4757647b62995eede2a45d06273503bfSteve McKay                add(new SpacerItem());
3724a1ca86f4757647b62995eede2a45d06273503bfSteve McKay                addAll(apps);
37354ca29a5b94c2edf461c5433825d4ae17469fd7cJeff Sharkey            }
3746efba22ce510352bb84910d6efc42fecafd31ed7Jeff Sharkey        }
37554ca29a5b94c2edf461c5433825d4ae17469fd7cJeff Sharkey
3766efba22ce510352bb84910d6efc42fecafd31ed7Jeff Sharkey        @Override
3776efba22ce510352bb84910d6efc42fecafd31ed7Jeff Sharkey        public View getView(int position, View convertView, ViewGroup parent) {
3786efba22ce510352bb84910d6efc42fecafd31ed7Jeff Sharkey            final Item item = getItem(position);
3796efba22ce510352bb84910d6efc42fecafd31ed7Jeff Sharkey            return item.getView(convertView, parent);
3806efba22ce510352bb84910d6efc42fecafd31ed7Jeff Sharkey        }
38166516697a29cf00d93893a1011d3befc7c1ee37fJeff Sharkey
3826efba22ce510352bb84910d6efc42fecafd31ed7Jeff Sharkey        @Override
3836efba22ce510352bb84910d6efc42fecafd31ed7Jeff Sharkey        public boolean areAllItemsEnabled() {
3846efba22ce510352bb84910d6efc42fecafd31ed7Jeff Sharkey            return false;
3856efba22ce510352bb84910d6efc42fecafd31ed7Jeff Sharkey        }
3866efba22ce510352bb84910d6efc42fecafd31ed7Jeff Sharkey
3876efba22ce510352bb84910d6efc42fecafd31ed7Jeff Sharkey        @Override
3886efba22ce510352bb84910d6efc42fecafd31ed7Jeff Sharkey        public boolean isEnabled(int position) {
3896efba22ce510352bb84910d6efc42fecafd31ed7Jeff Sharkey            return getItemViewType(position) != 1;
3906efba22ce510352bb84910d6efc42fecafd31ed7Jeff Sharkey        }
3916efba22ce510352bb84910d6efc42fecafd31ed7Jeff Sharkey
3926efba22ce510352bb84910d6efc42fecafd31ed7Jeff Sharkey        @Override
3936efba22ce510352bb84910d6efc42fecafd31ed7Jeff Sharkey        public int getItemViewType(int position) {
3946efba22ce510352bb84910d6efc42fecafd31ed7Jeff Sharkey            final Item item = getItem(position);
3956efba22ce510352bb84910d6efc42fecafd31ed7Jeff Sharkey            if (item instanceof RootItem || item instanceof AppItem) {
3966efba22ce510352bb84910d6efc42fecafd31ed7Jeff Sharkey                return 0;
3976efba22ce510352bb84910d6efc42fecafd31ed7Jeff Sharkey            } else {
3986efba22ce510352bb84910d6efc42fecafd31ed7Jeff Sharkey                return 1;
39954ca29a5b94c2edf461c5433825d4ae17469fd7cJeff Sharkey            }
40066516697a29cf00d93893a1011d3befc7c1ee37fJeff Sharkey        }
4016efba22ce510352bb84910d6efc42fecafd31ed7Jeff Sharkey
4026efba22ce510352bb84910d6efc42fecafd31ed7Jeff Sharkey        @Override
4036efba22ce510352bb84910d6efc42fecafd31ed7Jeff Sharkey        public int getViewTypeCount() {
4046efba22ce510352bb84910d6efc42fecafd31ed7Jeff Sharkey            return 2;
4056efba22ce510352bb84910d6efc42fecafd31ed7Jeff Sharkey        }
40666516697a29cf00d93893a1011d3befc7c1ee37fJeff Sharkey    }
407aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey
4080c64308240a7e9d3a78d4dedba2a419da63b5afdBen Kwa    public static class RootComparator implements Comparator<RootItem> {
409aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey        @Override
4100c64308240a7e9d3a78d4dedba2a419da63b5afdBen Kwa        public int compare(RootItem lhs, RootItem rhs) {
411008e948c3eac913ae3321bd690e3913e468e7fb1Steve McKay            return lhs.root.compareTo(rhs.root);
412aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey        }
413aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey    }
41466516697a29cf00d93893a1011d3befc7c1ee37fJeff Sharkey}
415