RootsFragment.java revision 008e948c3eac913ae3321bd690e3913e468e7fb1
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
2166516697a29cf00d93893a1011d3befc7c1ee37fJeff Sharkeyimport android.app.Fragment;
2266516697a29cf00d93893a1011d3befc7c1ee37fJeff Sharkeyimport android.app.FragmentManager;
2366516697a29cf00d93893a1011d3befc7c1ee37fJeff Sharkeyimport android.app.FragmentTransaction;
24a9ce049db87259e302e2368d2a4a1c11a94fd831Jeff Sharkeyimport android.app.LoaderManager.LoaderCallbacks;
2566516697a29cf00d93893a1011d3befc7c1ee37fJeff Sharkeyimport android.content.Context;
2654ca29a5b94c2edf461c5433825d4ae17469fd7cJeff Sharkeyimport android.content.Intent;
27a9ce049db87259e302e2368d2a4a1c11a94fd831Jeff Sharkeyimport android.content.Loader;
2854ca29a5b94c2edf461c5433825d4ae17469fd7cJeff Sharkeyimport android.content.pm.PackageManager;
2954ca29a5b94c2edf461c5433825d4ae17469fd7cJeff Sharkeyimport android.content.pm.ResolveInfo;
30c24bbd4ce525d80e385de6e27b19dac239db1dfdJeff Sharkeyimport android.net.Uri;
3166516697a29cf00d93893a1011d3befc7c1ee37fJeff Sharkeyimport android.os.Bundle;
32c24bbd4ce525d80e385de6e27b19dac239db1dfdJeff Sharkeyimport android.provider.Settings;
334a1ca86f4757647b62995eede2a45d06273503bfSteve McKayimport android.support.annotation.Nullable;
344ec973925fc2cd18f9ec0d0ca5af588564fded27Jeff Sharkeyimport android.text.TextUtils;
359fb567b59112f99e64e0bff6f343188331bad28dJeff Sharkeyimport android.text.format.Formatter;
3635820cfe963ce120a5876b8a123d5b1df13cbac5Steve McKayimport android.util.Log;
3766516697a29cf00d93893a1011d3befc7c1ee37fJeff Sharkeyimport android.view.LayoutInflater;
3866516697a29cf00d93893a1011d3befc7c1ee37fJeff Sharkeyimport android.view.View;
3966516697a29cf00d93893a1011d3befc7c1ee37fJeff Sharkeyimport android.view.ViewGroup;
4066516697a29cf00d93893a1011d3befc7c1ee37fJeff Sharkeyimport android.widget.AdapterView;
4166516697a29cf00d93893a1011d3befc7c1ee37fJeff Sharkeyimport android.widget.AdapterView.OnItemClickListener;
42c24bbd4ce525d80e385de6e27b19dac239db1dfdJeff Sharkeyimport android.widget.AdapterView.OnItemLongClickListener;
4366516697a29cf00d93893a1011d3befc7c1ee37fJeff Sharkeyimport android.widget.ArrayAdapter;
4466516697a29cf00d93893a1011d3befc7c1ee37fJeff Sharkeyimport android.widget.ImageView;
4566516697a29cf00d93893a1011d3befc7c1ee37fJeff Sharkeyimport android.widget.ListView;
4666516697a29cf00d93893a1011d3befc7c1ee37fJeff Sharkeyimport android.widget.TextView;
4766516697a29cf00d93893a1011d3befc7c1ee37fJeff Sharkey
48ae9b51bfa313c51a31af30875a71255d7b6d2e61Jeff Sharkeyimport com.android.documentsui.model.RootInfo;
4966516697a29cf00d93893a1011d3befc7c1ee37fJeff Sharkey
5058efce36cd1b26006e08ddd696292bf06fc34c81Steve McKayimport java.util.ArrayList;
51a9ce049db87259e302e2368d2a4a1c11a94fd831Jeff Sharkeyimport java.util.Collection;
526efba22ce510352bb84910d6efc42fecafd31ed7Jeff Sharkeyimport java.util.Collections;
53aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkeyimport java.util.Comparator;
5454ca29a5b94c2edf461c5433825d4ae17469fd7cJeff Sharkeyimport java.util.List;
55e6585b32ea586743258a5457e2184ffc087f2d2fKenny Rootimport java.util.Objects;
5666516697a29cf00d93893a1011d3befc7c1ee37fJeff Sharkey
5766516697a29cf00d93893a1011d3befc7c1ee37fJeff Sharkey/**
5866516697a29cf00d93893a1011d3befc7c1ee37fJeff Sharkey * Display list of known storage backend roots.
5966516697a29cf00d93893a1011d3befc7c1ee37fJeff Sharkey */
6066516697a29cf00d93893a1011d3befc7c1ee37fJeff Sharkeypublic class RootsFragment extends Fragment {
6166516697a29cf00d93893a1011d3befc7c1ee37fJeff Sharkey
6235820cfe963ce120a5876b8a123d5b1df13cbac5Steve McKay    private static final String TAG = "RootsFragment";
6335820cfe963ce120a5876b8a123d5b1df13cbac5Steve McKay    private static final String EXTRA_INCLUDE_APPS = "includeApps";
6435820cfe963ce120a5876b8a123d5b1df13cbac5Steve McKay
6566516697a29cf00d93893a1011d3befc7c1ee37fJeff Sharkey    private ListView mList;
666efba22ce510352bb84910d6efc42fecafd31ed7Jeff Sharkey    private RootsAdapter mAdapter;
67a9ce049db87259e302e2368d2a4a1c11a94fd831Jeff Sharkey    private LoaderCallbacks<Collection<RootInfo>> mCallbacks;
68a9ce049db87259e302e2368d2a4a1c11a94fd831Jeff Sharkey
6954ca29a5b94c2edf461c5433825d4ae17469fd7cJeff Sharkey
7054ca29a5b94c2edf461c5433825d4ae17469fd7cJeff Sharkey    public static void show(FragmentManager fm, Intent includeApps) {
7154ca29a5b94c2edf461c5433825d4ae17469fd7cJeff Sharkey        final Bundle args = new Bundle();
7254ca29a5b94c2edf461c5433825d4ae17469fd7cJeff Sharkey        args.putParcelable(EXTRA_INCLUDE_APPS, includeApps);
7354ca29a5b94c2edf461c5433825d4ae17469fd7cJeff Sharkey
7466516697a29cf00d93893a1011d3befc7c1ee37fJeff Sharkey        final RootsFragment fragment = new RootsFragment();
7554ca29a5b94c2edf461c5433825d4ae17469fd7cJeff Sharkey        fragment.setArguments(args);
7666516697a29cf00d93893a1011d3befc7c1ee37fJeff Sharkey
7766516697a29cf00d93893a1011d3befc7c1ee37fJeff Sharkey        final FragmentTransaction ft = fm.beginTransaction();
7866516697a29cf00d93893a1011d3befc7c1ee37fJeff Sharkey        ft.replace(R.id.container_roots, fragment);
7966516697a29cf00d93893a1011d3befc7c1ee37fJeff Sharkey        ft.commitAllowingStateLoss();
8066516697a29cf00d93893a1011d3befc7c1ee37fJeff Sharkey    }
8166516697a29cf00d93893a1011d3befc7c1ee37fJeff Sharkey
8266516697a29cf00d93893a1011d3befc7c1ee37fJeff Sharkey    public static RootsFragment get(FragmentManager fm) {
8366516697a29cf00d93893a1011d3befc7c1ee37fJeff Sharkey        return (RootsFragment) fm.findFragmentById(R.id.container_roots);
8466516697a29cf00d93893a1011d3befc7c1ee37fJeff Sharkey    }
8566516697a29cf00d93893a1011d3befc7c1ee37fJeff Sharkey
8666516697a29cf00d93893a1011d3befc7c1ee37fJeff Sharkey    @Override
8766516697a29cf00d93893a1011d3befc7c1ee37fJeff Sharkey    public View onCreateView(
8866516697a29cf00d93893a1011d3befc7c1ee37fJeff Sharkey            LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
8966516697a29cf00d93893a1011d3befc7c1ee37fJeff Sharkey
9066516697a29cf00d93893a1011d3befc7c1ee37fJeff Sharkey        final View view = inflater.inflate(R.layout.fragment_roots, container, false);
912036dad877336bf4d81202c334b1f2c81462bd9fBen Kwa        mList = (ListView) view.findViewById(R.id.roots_list);
9266516697a29cf00d93893a1011d3befc7c1ee37fJeff Sharkey        mList.setOnItemClickListener(mItemListener);
9328c05ee8931cecf4c51c470e0043d30196010c49Jeff Sharkey        mList.setChoiceMode(ListView.CHOICE_MODE_SINGLE);
9466516697a29cf00d93893a1011d3befc7c1ee37fJeff Sharkey        return view;
9566516697a29cf00d93893a1011d3befc7c1ee37fJeff Sharkey    }
9666516697a29cf00d93893a1011d3befc7c1ee37fJeff Sharkey
979fb567b59112f99e64e0bff6f343188331bad28dJeff Sharkey    @Override
98a9ce049db87259e302e2368d2a4a1c11a94fd831Jeff Sharkey    public void onActivityCreated(Bundle savedInstanceState) {
99a9ce049db87259e302e2368d2a4a1c11a94fd831Jeff Sharkey        super.onActivityCreated(savedInstanceState);
100a9ce049db87259e302e2368d2a4a1c11a94fd831Jeff Sharkey
101a9ce049db87259e302e2368d2a4a1c11a94fd831Jeff Sharkey        final Context context = getActivity();
102a9ce049db87259e302e2368d2a4a1c11a94fd831Jeff Sharkey        final RootsCache roots = DocumentsApplication.getRootsCache(context);
103e934ce6f8430f50d1d22bccd3b341b982f5541eeSteve McKay        final State state = ((BaseActivity) context).getDisplayState();
104a9ce049db87259e302e2368d2a4a1c11a94fd831Jeff Sharkey
105a9ce049db87259e302e2368d2a4a1c11a94fd831Jeff Sharkey        mCallbacks = new LoaderCallbacks<Collection<RootInfo>>() {
106a9ce049db87259e302e2368d2a4a1c11a94fd831Jeff Sharkey            @Override
107a9ce049db87259e302e2368d2a4a1c11a94fd831Jeff Sharkey            public Loader<Collection<RootInfo>> onCreateLoader(int id, Bundle args) {
108a9ce049db87259e302e2368d2a4a1c11a94fd831Jeff Sharkey                return new RootsLoader(context, roots, state);
109a9ce049db87259e302e2368d2a4a1c11a94fd831Jeff Sharkey            }
110a9ce049db87259e302e2368d2a4a1c11a94fd831Jeff Sharkey
111a9ce049db87259e302e2368d2a4a1c11a94fd831Jeff Sharkey            @Override
112a9ce049db87259e302e2368d2a4a1c11a94fd831Jeff Sharkey            public void onLoadFinished(
113a9ce049db87259e302e2368d2a4a1c11a94fd831Jeff Sharkey                    Loader<Collection<RootInfo>> loader, Collection<RootInfo> result) {
1144a1ca86f4757647b62995eede2a45d06273503bfSteve McKay                if (!isAdded()) {
1154a1ca86f4757647b62995eede2a45d06273503bfSteve McKay                    return;
1164a1ca86f4757647b62995eede2a45d06273503bfSteve McKay                }
117a9ce049db87259e302e2368d2a4a1c11a94fd831Jeff Sharkey
1184a1ca86f4757647b62995eede2a45d06273503bfSteve McKay                Intent handlerAppIntent = getArguments().getParcelable(EXTRA_INCLUDE_APPS);
119a9ce049db87259e302e2368d2a4a1c11a94fd831Jeff Sharkey
1204a1ca86f4757647b62995eede2a45d06273503bfSteve McKay                mAdapter = new RootsAdapter(context, result, handlerAppIntent);
121a9ce049db87259e302e2368d2a4a1c11a94fd831Jeff Sharkey                mList.setAdapter(mAdapter);
122a9ce049db87259e302e2368d2a4a1c11a94fd831Jeff Sharkey
123a9ce049db87259e302e2368d2a4a1c11a94fd831Jeff Sharkey                onCurrentRootChanged();
124a9ce049db87259e302e2368d2a4a1c11a94fd831Jeff Sharkey            }
125a9ce049db87259e302e2368d2a4a1c11a94fd831Jeff Sharkey
126a9ce049db87259e302e2368d2a4a1c11a94fd831Jeff Sharkey            @Override
127a9ce049db87259e302e2368d2a4a1c11a94fd831Jeff Sharkey            public void onLoaderReset(Loader<Collection<RootInfo>> loader) {
128a9ce049db87259e302e2368d2a4a1c11a94fd831Jeff Sharkey                mAdapter = null;
129a9ce049db87259e302e2368d2a4a1c11a94fd831Jeff Sharkey                mList.setAdapter(null);
130a9ce049db87259e302e2368d2a4a1c11a94fd831Jeff Sharkey            }
131a9ce049db87259e302e2368d2a4a1c11a94fd831Jeff Sharkey        };
132a9ce049db87259e302e2368d2a4a1c11a94fd831Jeff Sharkey    }
133a9ce049db87259e302e2368d2a4a1c11a94fd831Jeff Sharkey
134a9ce049db87259e302e2368d2a4a1c11a94fd831Jeff Sharkey    @Override
13588f322c3115e85bb96fb46f9192b5daecd472c64Jeff Sharkey    public void onResume() {
13688f322c3115e85bb96fb46f9192b5daecd472c64Jeff Sharkey        super.onResume();
137669f8e7c70c595964a1c9ca154ac123da84d99a1Jeff Sharkey        onDisplayStateChanged();
138669f8e7c70c595964a1c9ca154ac123da84d99a1Jeff Sharkey    }
1399fb567b59112f99e64e0bff6f343188331bad28dJeff Sharkey
140669f8e7c70c595964a1c9ca154ac123da84d99a1Jeff Sharkey    public void onDisplayStateChanged() {
1419fb567b59112f99e64e0bff6f343188331bad28dJeff Sharkey        final Context context = getActivity();
142e934ce6f8430f50d1d22bccd3b341b982f5541eeSteve McKay        final State state = ((BaseActivity) context).getDisplayState();
143348ad6866b91afa4d59d45df533ef88094c74d13Jeff Sharkey
144e934ce6f8430f50d1d22bccd3b341b982f5541eeSteve McKay        if (state.action == State.ACTION_GET_CONTENT) {
145c24bbd4ce525d80e385de6e27b19dac239db1dfdJeff Sharkey            mList.setOnItemLongClickListener(mItemLongClickListener);
146c24bbd4ce525d80e385de6e27b19dac239db1dfdJeff Sharkey        } else {
147c24bbd4ce525d80e385de6e27b19dac239db1dfdJeff Sharkey            mList.setOnItemLongClickListener(null);
148c24bbd4ce525d80e385de6e27b19dac239db1dfdJeff Sharkey            mList.setLongClickable(false);
149c24bbd4ce525d80e385de6e27b19dac239db1dfdJeff Sharkey        }
150c24bbd4ce525d80e385de6e27b19dac239db1dfdJeff Sharkey
151a9ce049db87259e302e2368d2a4a1c11a94fd831Jeff Sharkey        getLoaderManager().restartLoader(2, null, mCallbacks);
15228c05ee8931cecf4c51c470e0043d30196010c49Jeff Sharkey    }
15328c05ee8931cecf4c51c470e0043d30196010c49Jeff Sharkey
15428c05ee8931cecf4c51c470e0043d30196010c49Jeff Sharkey    public void onCurrentRootChanged() {
1554a1ca86f4757647b62995eede2a45d06273503bfSteve McKay        if (mAdapter == null) {
1564a1ca86f4757647b62995eede2a45d06273503bfSteve McKay            return;
1574a1ca86f4757647b62995eede2a45d06273503bfSteve McKay        }
15828c05ee8931cecf4c51c470e0043d30196010c49Jeff Sharkey
159e934ce6f8430f50d1d22bccd3b341b982f5541eeSteve McKay        final RootInfo root = ((BaseActivity) getActivity()).getCurrentRoot();
16028c05ee8931cecf4c51c470e0043d30196010c49Jeff Sharkey        for (int i = 0; i < mAdapter.getCount(); i++) {
16128c05ee8931cecf4c51c470e0043d30196010c49Jeff Sharkey            final Object item = mAdapter.getItem(i);
162a82c2e24bc226c123075331cdaafb171b3b07b85Jeff Sharkey            if (item instanceof RootItem) {
163a82c2e24bc226c123075331cdaafb171b3b07b85Jeff Sharkey                final RootInfo testRoot = ((RootItem) item).root;
164e6585b32ea586743258a5457e2184ffc087f2d2fKenny Root                if (Objects.equals(testRoot, root)) {
165a82c2e24bc226c123075331cdaafb171b3b07b85Jeff Sharkey                    mList.setItemChecked(i, true);
1668e1c9637ec56fbfe313e964a5b60986c1bb092b9Aga Wronska                    mList.setSelection(i);
167a82c2e24bc226c123075331cdaafb171b3b07b85Jeff Sharkey                    return;
168a82c2e24bc226c123075331cdaafb171b3b07b85Jeff Sharkey                }
16928c05ee8931cecf4c51c470e0043d30196010c49Jeff Sharkey            }
17028c05ee8931cecf4c51c470e0043d30196010c49Jeff Sharkey        }
1719fb567b59112f99e64e0bff6f343188331bad28dJeff Sharkey    }
1729fb567b59112f99e64e0bff6f343188331bad28dJeff Sharkey
1732036dad877336bf4d81202c334b1f2c81462bd9fBen Kwa    /**
1742036dad877336bf4d81202c334b1f2c81462bd9fBen Kwa     * Attempts to shift focus back to the navigation drawer.
1752036dad877336bf4d81202c334b1f2c81462bd9fBen Kwa     */
1762036dad877336bf4d81202c334b1f2c81462bd9fBen Kwa    public void requestFocus() {
1772036dad877336bf4d81202c334b1f2c81462bd9fBen Kwa        mList.requestFocus();
1782036dad877336bf4d81202c334b1f2c81462bd9fBen Kwa    }
1792036dad877336bf4d81202c334b1f2c81462bd9fBen Kwa
180c24bbd4ce525d80e385de6e27b19dac239db1dfdJeff Sharkey    private void showAppDetails(ResolveInfo ri) {
181c24bbd4ce525d80e385de6e27b19dac239db1dfdJeff Sharkey        final Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
182c24bbd4ce525d80e385de6e27b19dac239db1dfdJeff Sharkey        intent.setData(Uri.fromParts("package", ri.activityInfo.packageName, null));
183c24bbd4ce525d80e385de6e27b19dac239db1dfdJeff Sharkey        intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET);
184c24bbd4ce525d80e385de6e27b19dac239db1dfdJeff Sharkey        startActivity(intent);
185c24bbd4ce525d80e385de6e27b19dac239db1dfdJeff Sharkey    }
186c24bbd4ce525d80e385de6e27b19dac239db1dfdJeff Sharkey
18766516697a29cf00d93893a1011d3befc7c1ee37fJeff Sharkey    private OnItemClickListener mItemListener = new OnItemClickListener() {
18866516697a29cf00d93893a1011d3befc7c1ee37fJeff Sharkey        @Override
18966516697a29cf00d93893a1011d3befc7c1ee37fJeff Sharkey        public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
190ef3e2cf35fbede340d5ff830b410baea8e461a94Steve McKay            Item item = mAdapter.getItem(position);
1916efba22ce510352bb84910d6efc42fecafd31ed7Jeff Sharkey            if (item instanceof RootItem) {
192ef3e2cf35fbede340d5ff830b410baea8e461a94Steve McKay                BaseActivity activity = BaseActivity.get(RootsFragment.this);
19345f75e2a81674d792077516f13088d476c0ba510Aga Wronska                RootInfo newRoot = ((RootItem) item).root;
19445f75e2a81674d792077516f13088d476c0ba510Aga Wronska                Metrics.logRootVisited(getActivity(), newRoot);
19545f75e2a81674d792077516f13088d476c0ba510Aga Wronska                activity.onRootPicked(newRoot);
1966efba22ce510352bb84910d6efc42fecafd31ed7Jeff Sharkey            } else if (item instanceof AppItem) {
197ef3e2cf35fbede340d5ff830b410baea8e461a94Steve McKay                DocumentsActivity activity = DocumentsActivity.get(RootsFragment.this);
198723799858a15fa316128716d9e131a681d1a51d2Ben Kwa                ResolveInfo info = ((AppItem) item).info;
199723799858a15fa316128716d9e131a681d1a51d2Ben Kwa                Metrics.logAppVisited(getActivity(), info);
200723799858a15fa316128716d9e131a681d1a51d2Ben Kwa                activity.onAppPicked(info);
20135820cfe963ce120a5876b8a123d5b1df13cbac5Steve McKay            } else if (item instanceof SpacerItem) {
20235820cfe963ce120a5876b8a123d5b1df13cbac5Steve McKay                if (DEBUG) Log.d(TAG, "Ignoring click on spacer item.");
20354ca29a5b94c2edf461c5433825d4ae17469fd7cJeff Sharkey            } else {
20454ca29a5b94c2edf461c5433825d4ae17469fd7cJeff Sharkey                throw new IllegalStateException("Unknown root: " + item);
20554ca29a5b94c2edf461c5433825d4ae17469fd7cJeff Sharkey            }
20666516697a29cf00d93893a1011d3befc7c1ee37fJeff Sharkey        }
20766516697a29cf00d93893a1011d3befc7c1ee37fJeff Sharkey    };
20866516697a29cf00d93893a1011d3befc7c1ee37fJeff Sharkey
209c24bbd4ce525d80e385de6e27b19dac239db1dfdJeff Sharkey    private OnItemLongClickListener mItemLongClickListener = new OnItemLongClickListener() {
210c24bbd4ce525d80e385de6e27b19dac239db1dfdJeff Sharkey        @Override
211c24bbd4ce525d80e385de6e27b19dac239db1dfdJeff Sharkey        public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) {
212c24bbd4ce525d80e385de6e27b19dac239db1dfdJeff Sharkey            final Item item = mAdapter.getItem(position);
213c24bbd4ce525d80e385de6e27b19dac239db1dfdJeff Sharkey            if (item instanceof AppItem) {
214c24bbd4ce525d80e385de6e27b19dac239db1dfdJeff Sharkey                showAppDetails(((AppItem) item).info);
215c24bbd4ce525d80e385de6e27b19dac239db1dfdJeff Sharkey                return true;
216c24bbd4ce525d80e385de6e27b19dac239db1dfdJeff Sharkey            } else {
217c24bbd4ce525d80e385de6e27b19dac239db1dfdJeff Sharkey                return false;
218c24bbd4ce525d80e385de6e27b19dac239db1dfdJeff Sharkey            }
219c24bbd4ce525d80e385de6e27b19dac239db1dfdJeff Sharkey        }
220c24bbd4ce525d80e385de6e27b19dac239db1dfdJeff Sharkey    };
221c24bbd4ce525d80e385de6e27b19dac239db1dfdJeff Sharkey
2226efba22ce510352bb84910d6efc42fecafd31ed7Jeff Sharkey    private static abstract class Item {
2236efba22ce510352bb84910d6efc42fecafd31ed7Jeff Sharkey        private final int mLayoutId;
2246efba22ce510352bb84910d6efc42fecafd31ed7Jeff Sharkey
2256efba22ce510352bb84910d6efc42fecafd31ed7Jeff Sharkey        public Item(int layoutId) {
2266efba22ce510352bb84910d6efc42fecafd31ed7Jeff Sharkey            mLayoutId = layoutId;
22766516697a29cf00d93893a1011d3befc7c1ee37fJeff Sharkey        }
22866516697a29cf00d93893a1011d3befc7c1ee37fJeff Sharkey
2296efba22ce510352bb84910d6efc42fecafd31ed7Jeff Sharkey        public View getView(View convertView, ViewGroup parent) {
23066516697a29cf00d93893a1011d3befc7c1ee37fJeff Sharkey            if (convertView == null) {
2316efba22ce510352bb84910d6efc42fecafd31ed7Jeff Sharkey                convertView = LayoutInflater.from(parent.getContext())
2326efba22ce510352bb84910d6efc42fecafd31ed7Jeff Sharkey                        .inflate(mLayoutId, parent, false);
23366516697a29cf00d93893a1011d3befc7c1ee37fJeff Sharkey            }
2346efba22ce510352bb84910d6efc42fecafd31ed7Jeff Sharkey            bindView(convertView);
2356efba22ce510352bb84910d6efc42fecafd31ed7Jeff Sharkey            return convertView;
2366efba22ce510352bb84910d6efc42fecafd31ed7Jeff Sharkey        }
2376efba22ce510352bb84910d6efc42fecafd31ed7Jeff Sharkey
2386efba22ce510352bb84910d6efc42fecafd31ed7Jeff Sharkey        public abstract void bindView(View convertView);
2396efba22ce510352bb84910d6efc42fecafd31ed7Jeff Sharkey    }
24066516697a29cf00d93893a1011d3befc7c1ee37fJeff Sharkey
2416efba22ce510352bb84910d6efc42fecafd31ed7Jeff Sharkey    private static class RootItem extends Item {
2426efba22ce510352bb84910d6efc42fecafd31ed7Jeff Sharkey        public final RootInfo root;
2436efba22ce510352bb84910d6efc42fecafd31ed7Jeff Sharkey
2446efba22ce510352bb84910d6efc42fecafd31ed7Jeff Sharkey        public RootItem(RootInfo root) {
2456efba22ce510352bb84910d6efc42fecafd31ed7Jeff Sharkey            super(R.layout.item_root);
2466efba22ce510352bb84910d6efc42fecafd31ed7Jeff Sharkey            this.root = root;
2476efba22ce510352bb84910d6efc42fecafd31ed7Jeff Sharkey        }
2486efba22ce510352bb84910d6efc42fecafd31ed7Jeff Sharkey
2496efba22ce510352bb84910d6efc42fecafd31ed7Jeff Sharkey        @Override
2506efba22ce510352bb84910d6efc42fecafd31ed7Jeff Sharkey        public void bindView(View convertView) {
25166516697a29cf00d93893a1011d3befc7c1ee37fJeff Sharkey            final ImageView icon = (ImageView) convertView.findViewById(android.R.id.icon);
25266516697a29cf00d93893a1011d3befc7c1ee37fJeff Sharkey            final TextView title = (TextView) convertView.findViewById(android.R.id.title);
25366516697a29cf00d93893a1011d3befc7c1ee37fJeff Sharkey            final TextView summary = (TextView) convertView.findViewById(android.R.id.summary);
25466516697a29cf00d93893a1011d3befc7c1ee37fJeff Sharkey
2556efba22ce510352bb84910d6efc42fecafd31ed7Jeff Sharkey            final Context context = convertView.getContext();
256cbce47001e15be85b084c36a64c20039a0c4a667Jeff Sharkey            icon.setImageDrawable(root.loadDrawerIcon(context));
25766516697a29cf00d93893a1011d3befc7c1ee37fJeff Sharkey            title.setText(root.title);
25866516697a29cf00d93893a1011d3befc7c1ee37fJeff Sharkey
2596efba22ce510352bb84910d6efc42fecafd31ed7Jeff Sharkey            // Show available space if no summary
2606efba22ce510352bb84910d6efc42fecafd31ed7Jeff Sharkey            String summaryText = root.summary;
2616efba22ce510352bb84910d6efc42fecafd31ed7Jeff Sharkey            if (TextUtils.isEmpty(summaryText) && root.availableBytes >= 0) {
2629fb567b59112f99e64e0bff6f343188331bad28dJeff Sharkey                summaryText = context.getString(R.string.root_available_bytes,
2639fb567b59112f99e64e0bff6f343188331bad28dJeff Sharkey                        Formatter.formatFileSize(context, root.availableBytes));
2649fb567b59112f99e64e0bff6f343188331bad28dJeff Sharkey            }
2659fb567b59112f99e64e0bff6f343188331bad28dJeff Sharkey
2669fb567b59112f99e64e0bff6f343188331bad28dJeff Sharkey            summary.setText(summaryText);
2674ec973925fc2cd18f9ec0d0ca5af588564fded27Jeff Sharkey            summary.setVisibility(TextUtils.isEmpty(summaryText) ? View.GONE : View.VISIBLE);
2686efba22ce510352bb84910d6efc42fecafd31ed7Jeff Sharkey        }
2696efba22ce510352bb84910d6efc42fecafd31ed7Jeff Sharkey    }
27066516697a29cf00d93893a1011d3befc7c1ee37fJeff Sharkey
2716efba22ce510352bb84910d6efc42fecafd31ed7Jeff Sharkey    private static class SpacerItem extends Item {
2726efba22ce510352bb84910d6efc42fecafd31ed7Jeff Sharkey        public SpacerItem() {
2736efba22ce510352bb84910d6efc42fecafd31ed7Jeff Sharkey            super(R.layout.item_root_spacer);
27466516697a29cf00d93893a1011d3befc7c1ee37fJeff Sharkey        }
27566516697a29cf00d93893a1011d3befc7c1ee37fJeff Sharkey
27666516697a29cf00d93893a1011d3befc7c1ee37fJeff Sharkey        @Override
2776efba22ce510352bb84910d6efc42fecafd31ed7Jeff Sharkey        public void bindView(View convertView) {
2786efba22ce510352bb84910d6efc42fecafd31ed7Jeff Sharkey            // Nothing to bind
27966516697a29cf00d93893a1011d3befc7c1ee37fJeff Sharkey        }
28066516697a29cf00d93893a1011d3befc7c1ee37fJeff Sharkey    }
28166516697a29cf00d93893a1011d3befc7c1ee37fJeff Sharkey
2826efba22ce510352bb84910d6efc42fecafd31ed7Jeff Sharkey    private static class AppItem extends Item {
2836efba22ce510352bb84910d6efc42fecafd31ed7Jeff Sharkey        public final ResolveInfo info;
2846efba22ce510352bb84910d6efc42fecafd31ed7Jeff Sharkey
2856efba22ce510352bb84910d6efc42fecafd31ed7Jeff Sharkey        public AppItem(ResolveInfo info) {
2866efba22ce510352bb84910d6efc42fecafd31ed7Jeff Sharkey            super(R.layout.item_root);
2876efba22ce510352bb84910d6efc42fecafd31ed7Jeff Sharkey            this.info = info;
28854ca29a5b94c2edf461c5433825d4ae17469fd7cJeff Sharkey        }
28954ca29a5b94c2edf461c5433825d4ae17469fd7cJeff Sharkey
29054ca29a5b94c2edf461c5433825d4ae17469fd7cJeff Sharkey        @Override
2916efba22ce510352bb84910d6efc42fecafd31ed7Jeff Sharkey        public void bindView(View convertView) {
29254ca29a5b94c2edf461c5433825d4ae17469fd7cJeff Sharkey            final ImageView icon = (ImageView) convertView.findViewById(android.R.id.icon);
29354ca29a5b94c2edf461c5433825d4ae17469fd7cJeff Sharkey            final TextView title = (TextView) convertView.findViewById(android.R.id.title);
29454ca29a5b94c2edf461c5433825d4ae17469fd7cJeff Sharkey            final TextView summary = (TextView) convertView.findViewById(android.R.id.summary);
29554ca29a5b94c2edf461c5433825d4ae17469fd7cJeff Sharkey
2966efba22ce510352bb84910d6efc42fecafd31ed7Jeff Sharkey            final PackageManager pm = convertView.getContext().getPackageManager();
29754ca29a5b94c2edf461c5433825d4ae17469fd7cJeff Sharkey            icon.setImageDrawable(info.loadIcon(pm));
29854ca29a5b94c2edf461c5433825d4ae17469fd7cJeff Sharkey            title.setText(info.loadLabel(pm));
29954ca29a5b94c2edf461c5433825d4ae17469fd7cJeff Sharkey
30054ca29a5b94c2edf461c5433825d4ae17469fd7cJeff Sharkey            // TODO: match existing summary behavior from disambig dialog
30154ca29a5b94c2edf461c5433825d4ae17469fd7cJeff Sharkey            summary.setVisibility(View.GONE);
30254ca29a5b94c2edf461c5433825d4ae17469fd7cJeff Sharkey        }
3036efba22ce510352bb84910d6efc42fecafd31ed7Jeff Sharkey    }
30454ca29a5b94c2edf461c5433825d4ae17469fd7cJeff Sharkey
3056efba22ce510352bb84910d6efc42fecafd31ed7Jeff Sharkey    private static class RootsAdapter extends ArrayAdapter<Item> {
3064a1ca86f4757647b62995eede2a45d06273503bfSteve McKay
3074a1ca86f4757647b62995eede2a45d06273503bfSteve McKay        /**
3084a1ca86f4757647b62995eede2a45d06273503bfSteve McKay         * @param handlerAppIntent When not null, apps capable of handling the original
3094a1ca86f4757647b62995eede2a45d06273503bfSteve McKay         *     intent will be included in list of roots (in special section at bottom).
3104a1ca86f4757647b62995eede2a45d06273503bfSteve McKay         */
3114a1ca86f4757647b62995eede2a45d06273503bfSteve McKay        public RootsAdapter(
3124a1ca86f4757647b62995eede2a45d06273503bfSteve McKay                Context context, Collection<RootInfo> roots, @Nullable Intent handlerAppIntent) {
3136efba22ce510352bb84910d6efc42fecafd31ed7Jeff Sharkey            super(context, 0);
31454ca29a5b94c2edf461c5433825d4ae17469fd7cJeff Sharkey
3150c64308240a7e9d3a78d4dedba2a419da63b5afdBen Kwa            final List<RootItem> libraries = new ArrayList<>();
316abf397458dca89fd3df4234d547a94bf0487033dDaichi Hirono            final List<RootItem> others = new ArrayList<>();
317abf397458dca89fd3df4234d547a94bf0487033dDaichi Hirono
318abf397458dca89fd3df4234d547a94bf0487033dDaichi Hirono            for (final RootInfo root : roots) {
319abf397458dca89fd3df4234d547a94bf0487033dDaichi Hirono                final RootItem item = new RootItem(root);
320e95c321fd991773e895e71bc415afff46236c77bBen Kwa                if (root.isLibrary()) {
3213ce95951bd173c422b8d369b4651c28e5bcc20f4Steve McKay                    if (DEBUG) Log.d(TAG, "Adding " + root + " as library.");
322abf397458dca89fd3df4234d547a94bf0487033dDaichi Hirono                    libraries.add(item);
323abf397458dca89fd3df4234d547a94bf0487033dDaichi Hirono                } else {
3243ce95951bd173c422b8d369b4651c28e5bcc20f4Steve McKay                    if (DEBUG) Log.d(TAG, "Adding " + root + " as non-library.");
325abf397458dca89fd3df4234d547a94bf0487033dDaichi Hirono                    others.add(item);
3265545f56f7561810187545a1817b6001dd1f9931bJeff Sharkey                }
3276efba22ce510352bb84910d6efc42fecafd31ed7Jeff Sharkey            }
3285545f56f7561810187545a1817b6001dd1f9931bJeff Sharkey
3296efba22ce510352bb84910d6efc42fecafd31ed7Jeff Sharkey            final RootComparator comp = new RootComparator();
3300c64308240a7e9d3a78d4dedba2a419da63b5afdBen Kwa            Collections.sort(libraries, comp);
331abf397458dca89fd3df4234d547a94bf0487033dDaichi Hirono            Collections.sort(others, comp);
3326efba22ce510352bb84910d6efc42fecafd31ed7Jeff Sharkey
3330c64308240a7e9d3a78d4dedba2a419da63b5afdBen Kwa            addAll(libraries);
3344a1ca86f4757647b62995eede2a45d06273503bfSteve McKay            // Only add the spacer if it is actually separating something.
3354a1ca86f4757647b62995eede2a45d06273503bfSteve McKay            if (!libraries.isEmpty() && !others.isEmpty()) {
3364a1ca86f4757647b62995eede2a45d06273503bfSteve McKay                add(new SpacerItem());
3374a1ca86f4757647b62995eede2a45d06273503bfSteve McKay            }
338abf397458dca89fd3df4234d547a94bf0487033dDaichi Hirono            addAll(others);
33966516697a29cf00d93893a1011d3befc7c1ee37fJeff Sharkey
3404a1ca86f4757647b62995eede2a45d06273503bfSteve McKay            // Include apps that can handle this intent too.
3414a1ca86f4757647b62995eede2a45d06273503bfSteve McKay            if (handlerAppIntent != null) {
3424a1ca86f4757647b62995eede2a45d06273503bfSteve McKay                includeHandlerApps(context, handlerAppIntent);
3434a1ca86f4757647b62995eede2a45d06273503bfSteve McKay            }
3444a1ca86f4757647b62995eede2a45d06273503bfSteve McKay        }
3456efba22ce510352bb84910d6efc42fecafd31ed7Jeff Sharkey
3464a1ca86f4757647b62995eede2a45d06273503bfSteve McKay        /**
3474a1ca86f4757647b62995eede2a45d06273503bfSteve McKay         * Adds apps capable of handling the original intent will be included
3484a1ca86f4757647b62995eede2a45d06273503bfSteve McKay         * in list of roots (in special section at bottom).
3494a1ca86f4757647b62995eede2a45d06273503bfSteve McKay         */
3504a1ca86f4757647b62995eede2a45d06273503bfSteve McKay        private void includeHandlerApps(Context context, Intent handlerAppIntent) {
3514a1ca86f4757647b62995eede2a45d06273503bfSteve McKay            final PackageManager pm = context.getPackageManager();
3524a1ca86f4757647b62995eede2a45d06273503bfSteve McKay            final List<ResolveInfo> infos = pm.queryIntentActivities(
3534a1ca86f4757647b62995eede2a45d06273503bfSteve McKay                    handlerAppIntent, PackageManager.MATCH_DEFAULT_ONLY);
3544a1ca86f4757647b62995eede2a45d06273503bfSteve McKay
3554a1ca86f4757647b62995eede2a45d06273503bfSteve McKay            final List<AppItem> apps = new ArrayList<>();
3564a1ca86f4757647b62995eede2a45d06273503bfSteve McKay
3574a1ca86f4757647b62995eede2a45d06273503bfSteve McKay            // Omit ourselves from the list
3584a1ca86f4757647b62995eede2a45d06273503bfSteve McKay            for (ResolveInfo info : infos) {
3594a1ca86f4757647b62995eede2a45d06273503bfSteve McKay                if (!context.getPackageName().equals(info.activityInfo.packageName)) {
3604a1ca86f4757647b62995eede2a45d06273503bfSteve McKay                    apps.add(new AppItem(info));
3616efba22ce510352bb84910d6efc42fecafd31ed7Jeff Sharkey                }
3624a1ca86f4757647b62995eede2a45d06273503bfSteve McKay            }
3636efba22ce510352bb84910d6efc42fecafd31ed7Jeff Sharkey
3644a1ca86f4757647b62995eede2a45d06273503bfSteve McKay            if (apps.size() > 0) {
3654a1ca86f4757647b62995eede2a45d06273503bfSteve McKay                add(new SpacerItem());
3664a1ca86f4757647b62995eede2a45d06273503bfSteve McKay                addAll(apps);
36754ca29a5b94c2edf461c5433825d4ae17469fd7cJeff Sharkey            }
3686efba22ce510352bb84910d6efc42fecafd31ed7Jeff Sharkey        }
36954ca29a5b94c2edf461c5433825d4ae17469fd7cJeff Sharkey
3706efba22ce510352bb84910d6efc42fecafd31ed7Jeff Sharkey        @Override
3716efba22ce510352bb84910d6efc42fecafd31ed7Jeff Sharkey        public View getView(int position, View convertView, ViewGroup parent) {
3726efba22ce510352bb84910d6efc42fecafd31ed7Jeff Sharkey            final Item item = getItem(position);
3736efba22ce510352bb84910d6efc42fecafd31ed7Jeff Sharkey            return item.getView(convertView, parent);
3746efba22ce510352bb84910d6efc42fecafd31ed7Jeff Sharkey        }
37566516697a29cf00d93893a1011d3befc7c1ee37fJeff Sharkey
3766efba22ce510352bb84910d6efc42fecafd31ed7Jeff Sharkey        @Override
3776efba22ce510352bb84910d6efc42fecafd31ed7Jeff Sharkey        public boolean areAllItemsEnabled() {
3786efba22ce510352bb84910d6efc42fecafd31ed7Jeff Sharkey            return false;
3796efba22ce510352bb84910d6efc42fecafd31ed7Jeff Sharkey        }
3806efba22ce510352bb84910d6efc42fecafd31ed7Jeff Sharkey
3816efba22ce510352bb84910d6efc42fecafd31ed7Jeff Sharkey        @Override
3826efba22ce510352bb84910d6efc42fecafd31ed7Jeff Sharkey        public boolean isEnabled(int position) {
3836efba22ce510352bb84910d6efc42fecafd31ed7Jeff Sharkey            return getItemViewType(position) != 1;
3846efba22ce510352bb84910d6efc42fecafd31ed7Jeff Sharkey        }
3856efba22ce510352bb84910d6efc42fecafd31ed7Jeff Sharkey
3866efba22ce510352bb84910d6efc42fecafd31ed7Jeff Sharkey        @Override
3876efba22ce510352bb84910d6efc42fecafd31ed7Jeff Sharkey        public int getItemViewType(int position) {
3886efba22ce510352bb84910d6efc42fecafd31ed7Jeff Sharkey            final Item item = getItem(position);
3896efba22ce510352bb84910d6efc42fecafd31ed7Jeff Sharkey            if (item instanceof RootItem || item instanceof AppItem) {
3906efba22ce510352bb84910d6efc42fecafd31ed7Jeff Sharkey                return 0;
3916efba22ce510352bb84910d6efc42fecafd31ed7Jeff Sharkey            } else {
3926efba22ce510352bb84910d6efc42fecafd31ed7Jeff Sharkey                return 1;
39354ca29a5b94c2edf461c5433825d4ae17469fd7cJeff Sharkey            }
39466516697a29cf00d93893a1011d3befc7c1ee37fJeff Sharkey        }
3956efba22ce510352bb84910d6efc42fecafd31ed7Jeff Sharkey
3966efba22ce510352bb84910d6efc42fecafd31ed7Jeff Sharkey        @Override
3976efba22ce510352bb84910d6efc42fecafd31ed7Jeff Sharkey        public int getViewTypeCount() {
3986efba22ce510352bb84910d6efc42fecafd31ed7Jeff Sharkey            return 2;
3996efba22ce510352bb84910d6efc42fecafd31ed7Jeff Sharkey        }
40066516697a29cf00d93893a1011d3befc7c1ee37fJeff Sharkey    }
401aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey
4020c64308240a7e9d3a78d4dedba2a419da63b5afdBen Kwa    public static class RootComparator implements Comparator<RootItem> {
403aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey        @Override
4040c64308240a7e9d3a78d4dedba2a419da63b5afdBen Kwa        public int compare(RootItem lhs, RootItem rhs) {
405008e948c3eac913ae3321bd690e3913e468e7fb1Steve McKay            return lhs.root.compareTo(rhs.root);
406aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey        }
407aeb16e2435f9975b9fa1fc4b747796647a21292eJeff Sharkey    }
40866516697a29cf00d93893a1011d3befc7c1ee37fJeff Sharkey}
409