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