1761122118b2437aee3a44e9263b73766986c12b8Jeff Sharkey/* 2761122118b2437aee3a44e9263b73766986c12b8Jeff Sharkey * Copyright (C) 2013 The Android Open Source Project 3761122118b2437aee3a44e9263b73766986c12b8Jeff Sharkey * 4761122118b2437aee3a44e9263b73766986c12b8Jeff Sharkey * Licensed under the Apache License, Version 2.0 (the "License"); 5761122118b2437aee3a44e9263b73766986c12b8Jeff Sharkey * you may not use this file except in compliance with the License. 6761122118b2437aee3a44e9263b73766986c12b8Jeff Sharkey * You may obtain a copy of the License at 7761122118b2437aee3a44e9263b73766986c12b8Jeff Sharkey * 8761122118b2437aee3a44e9263b73766986c12b8Jeff Sharkey * http://www.apache.org/licenses/LICENSE-2.0 9761122118b2437aee3a44e9263b73766986c12b8Jeff Sharkey * 10761122118b2437aee3a44e9263b73766986c12b8Jeff Sharkey * Unless required by applicable law or agreed to in writing, software 11761122118b2437aee3a44e9263b73766986c12b8Jeff Sharkey * distributed under the License is distributed on an "AS IS" BASIS, 12761122118b2437aee3a44e9263b73766986c12b8Jeff Sharkey * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13761122118b2437aee3a44e9263b73766986c12b8Jeff Sharkey * See the License for the specific language governing permissions and 14761122118b2437aee3a44e9263b73766986c12b8Jeff Sharkey * limitations under the License. 15761122118b2437aee3a44e9263b73766986c12b8Jeff Sharkey */ 16761122118b2437aee3a44e9263b73766986c12b8Jeff Sharkey 17d080506e3aa8547605cd4783eb660775d7d2b8eeSteve McKaypackage com.android.documentsui.sidebar; 18761122118b2437aee3a44e9263b73766986c12b8Jeff Sharkey 19d9caa6ab53aa784acaf241c0ded3c4ae2d342bf8Steve McKayimport static com.android.documentsui.base.Shared.DEBUG; 2030535bce902104c97bbf70783d684ee673cb7637Steve McKayimport static com.android.documentsui.base.Shared.VERBOSE; 21cc460af3f57dd9ffe58edb5f0e6c45cc80e06e75Steve McKay 227d75f7bbd1693a33abb8de6b472ec1950e33eb8bGarfield Tanimport android.annotation.Nullable; 2317f7e5891cbe86fc6cacae045a4edd3e41f8d5eeSteve McKayimport android.app.Activity; 24761122118b2437aee3a44e9263b73766986c12b8Jeff Sharkeyimport android.app.Fragment; 25761122118b2437aee3a44e9263b73766986c12b8Jeff Sharkeyimport android.app.FragmentManager; 26761122118b2437aee3a44e9263b73766986c12b8Jeff Sharkeyimport android.app.FragmentTransaction; 278b9970489d03ee0bda3d8d4773bf672c182922c6Jeff Sharkeyimport android.app.LoaderManager.LoaderCallbacks; 28761122118b2437aee3a44e9263b73766986c12b8Jeff Sharkeyimport android.content.Context; 291d890e0daf2f46dc83580280cfa22031dfebc216Jeff Sharkeyimport android.content.Intent; 308b9970489d03ee0bda3d8d4773bf672c182922c6Jeff Sharkeyimport android.content.Loader; 311d890e0daf2f46dc83580280cfa22031dfebc216Jeff Sharkeyimport android.content.pm.PackageManager; 321d890e0daf2f46dc83580280cfa22031dfebc216Jeff Sharkeyimport android.content.pm.ResolveInfo; 33761122118b2437aee3a44e9263b73766986c12b8Jeff Sharkeyimport android.os.Bundle; 34cc460af3f57dd9ffe58edb5f0e6c45cc80e06e75Steve McKayimport android.util.Log; 355668b866d52a4f8907474922dc9b1ba1b4db85a3Ben Linimport android.view.ContextMenu; 36a5588b65d55bc1b8b5ba943f8b660db26a7eac5cGarfield, Tanimport android.view.DragEvent; 37761122118b2437aee3a44e9263b73766986c12b8Jeff Sharkeyimport android.view.LayoutInflater; 385668b866d52a4f8907474922dc9b1ba1b4db85a3Ben Linimport android.view.MenuItem; 395668b866d52a4f8907474922dc9b1ba1b4db85a3Ben Linimport android.view.MotionEvent; 40761122118b2437aee3a44e9263b73766986c12b8Jeff Sharkeyimport android.view.View; 41804133e4ca98ffa168cd547793054b594cf6d9ccGarfield, Tanimport android.view.View.OnDragListener; 425668b866d52a4f8907474922dc9b1ba1b4db85a3Ben Linimport android.view.View.OnGenericMotionListener; 43761122118b2437aee3a44e9263b73766986c12b8Jeff Sharkeyimport android.view.ViewGroup; 44761122118b2437aee3a44e9263b73766986c12b8Jeff Sharkeyimport android.widget.AdapterView; 455668b866d52a4f8907474922dc9b1ba1b4db85a3Ben Linimport android.widget.AdapterView.AdapterContextMenuInfo; 46761122118b2437aee3a44e9263b73766986c12b8Jeff Sharkeyimport android.widget.AdapterView.OnItemClickListener; 478f1edfe6c6a39b8fec7521694328fe8f31d6496eJeff Sharkeyimport android.widget.AdapterView.OnItemLongClickListener; 48761122118b2437aee3a44e9263b73766986c12b8Jeff Sharkeyimport android.widget.ListView; 49761122118b2437aee3a44e9263b73766986c12b8Jeff Sharkey 506d20d190bc576bea1da48f79d868a5f383d3458bSteve McKayimport com.android.documentsui.ActionHandler; 51d080506e3aa8547605cd4783eb660775d7d2b8eeSteve McKayimport com.android.documentsui.BaseActivity; 52d080506e3aa8547605cd4783eb660775d7d2b8eeSteve McKayimport com.android.documentsui.DocumentsApplication; 53d020212fdad3be1537dfa47ff5b67e3bc4272d5eBen Linimport com.android.documentsui.DragAndDropHelper; 54b0761d3b04ed16800bc96a32a759fd6374d1e20fBen Linimport com.android.documentsui.DragShadowBuilder; 5592ae43d5d22331aad83e1a4302a7e1975f66354eSteve McKayimport com.android.documentsui.Injector; 5692ae43d5d22331aad83e1a4302a7e1975f66354eSteve McKayimport com.android.documentsui.Injector.Injected; 57d080506e3aa8547605cd4783eb660775d7d2b8eeSteve McKayimport com.android.documentsui.ItemDragListener; 58d080506e3aa8547605cd4783eb660775d7d2b8eeSteve McKayimport com.android.documentsui.R; 59739f94ba0dc9be264d9596dac551fd63082d2fddSteve McKayimport com.android.documentsui.base.BooleanConsumer; 608e9125847b29bbb436108c3bfda50a0018c48796Ben Linimport com.android.documentsui.base.DocumentInfo; 61739f94ba0dc9be264d9596dac551fd63082d2fddSteve McKayimport com.android.documentsui.base.DocumentStack; 62d9caa6ab53aa784acaf241c0ded3c4ae2d342bf8Steve McKayimport com.android.documentsui.base.Events; 63d080506e3aa8547605cd4783eb660775d7d2b8eeSteve McKayimport com.android.documentsui.base.RootInfo; 64d9caa6ab53aa784acaf241c0ded3c4ae2d342bf8Steve McKayimport com.android.documentsui.base.Shared; 65d9caa6ab53aa784acaf241c0ded3c4ae2d342bf8Steve McKayimport com.android.documentsui.base.State; 669bd4099ee27f8302a06fc66980079f29127318f8Jon Mannimport com.android.documentsui.roots.ProvidersCache; 67d9caa6ab53aa784acaf241c0ded3c4ae2d342bf8Steve McKayimport com.android.documentsui.roots.RootsLoader; 68761122118b2437aee3a44e9263b73766986c12b8Jeff Sharkey 69fefcd700d6b4cf1c4402af74c50fb0e762472901Steve McKayimport java.util.ArrayList; 708b9970489d03ee0bda3d8d4773bf672c182922c6Jeff Sharkeyimport java.util.Collection; 719dd02629d12d05c2e77780dc6b9fcc7639192de6Jeff Sharkeyimport java.util.Collections; 72b6a7f2cd05f8c507dfac684aa4c693088e8c01c7Jeff Sharkeyimport java.util.Comparator; 731d890e0daf2f46dc83580280cfa22031dfebc216Jeff Sharkeyimport java.util.List; 7416d8598bdec0015382519ecece459d8da653dcbcKenny Rootimport java.util.Objects; 75761122118b2437aee3a44e9263b73766986c12b8Jeff Sharkey 76761122118b2437aee3a44e9263b73766986c12b8Jeff Sharkey/** 77761122118b2437aee3a44e9263b73766986c12b8Jeff Sharkey * Display list of known storage backend roots. 78761122118b2437aee3a44e9263b73766986c12b8Jeff Sharkey */ 79804133e4ca98ffa168cd547793054b594cf6d9ccGarfield, Tanpublic class RootsFragment extends Fragment implements ItemDragListener.DragHost { 80761122118b2437aee3a44e9263b73766986c12b8Jeff Sharkey 81cc460af3f57dd9ffe58edb5f0e6c45cc80e06e75Steve McKay private static final String TAG = "RootsFragment"; 82cc460af3f57dd9ffe58edb5f0e6c45cc80e06e75Steve McKay private static final String EXTRA_INCLUDE_APPS = "includeApps"; 838e9125847b29bbb436108c3bfda50a0018c48796Ben Lin private static final int CONTEXT_MENU_ITEM_TIMEOUT = 500; 84cc460af3f57dd9ffe58edb5f0e6c45cc80e06e75Steve McKay 857d75f7bbd1693a33abb8de6b472ec1950e33eb8bGarfield Tan private final OnItemClickListener mItemListener = new OnItemClickListener() { 867d75f7bbd1693a33abb8de6b472ec1950e33eb8bGarfield Tan @Override 877d75f7bbd1693a33abb8de6b472ec1950e33eb8bGarfield Tan public void onItemClick(AdapterView<?> parent, View view, int position, long id) { 887d75f7bbd1693a33abb8de6b472ec1950e33eb8bGarfield Tan final Item item = mAdapter.getItem(position); 897d75f7bbd1693a33abb8de6b472ec1950e33eb8bGarfield Tan item.open(); 907d75f7bbd1693a33abb8de6b472ec1950e33eb8bGarfield Tan 917d75f7bbd1693a33abb8de6b472ec1950e33eb8bGarfield Tan getBaseActivity().setRootsDrawerOpen(false); 927d75f7bbd1693a33abb8de6b472ec1950e33eb8bGarfield Tan } 937d75f7bbd1693a33abb8de6b472ec1950e33eb8bGarfield Tan }; 947d75f7bbd1693a33abb8de6b472ec1950e33eb8bGarfield Tan 957d75f7bbd1693a33abb8de6b472ec1950e33eb8bGarfield Tan private final OnItemLongClickListener mItemLongClickListener = new OnItemLongClickListener() { 967d75f7bbd1693a33abb8de6b472ec1950e33eb8bGarfield Tan @Override 977d75f7bbd1693a33abb8de6b472ec1950e33eb8bGarfield Tan public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) { 987d75f7bbd1693a33abb8de6b472ec1950e33eb8bGarfield Tan final Item item = mAdapter.getItem(position); 99b285b40dedbde396aea8080c3d09577677bc71bcGarfield Tan return item.showAppDetails(); 100a5588b65d55bc1b8b5ba943f8b660db26a7eac5cGarfield, Tan } 101a5588b65d55bc1b8b5ba943f8b660db26a7eac5cGarfield, Tan }; 102a5588b65d55bc1b8b5ba943f8b660db26a7eac5cGarfield, Tan 103761122118b2437aee3a44e9263b73766986c12b8Jeff Sharkey private ListView mList; 1049dd02629d12d05c2e77780dc6b9fcc7639192de6Jeff Sharkey private RootsAdapter mAdapter; 1058b9970489d03ee0bda3d8d4773bf672c182922c6Jeff Sharkey private LoaderCallbacks<Collection<RootInfo>> mCallbacks; 106208945c4e262868d3ebe0f55f1b895cd5a201cbbGarfield Tan private @Nullable OnDragListener mDragListener; 107208945c4e262868d3ebe0f55f1b895cd5a201cbbGarfield Tan 10892ae43d5d22331aad83e1a4302a7e1975f66354eSteve McKay @Injected 10992ae43d5d22331aad83e1a4302a7e1975f66354eSteve McKay private Injector<?> mInjector; 1108b9970489d03ee0bda3d8d4773bf672c182922c6Jeff Sharkey 11192ae43d5d22331aad83e1a4302a7e1975f66354eSteve McKay @Injected 11292ae43d5d22331aad83e1a4302a7e1975f66354eSteve McKay private ActionHandler mActionHandler; 113208945c4e262868d3ebe0f55f1b895cd5a201cbbGarfield Tan 114821727a0fd0fa608a3046db8dad6ea588e16828fBen Lin public static RootsFragment show(FragmentManager fm, Intent includeApps) { 1151d890e0daf2f46dc83580280cfa22031dfebc216Jeff Sharkey final Bundle args = new Bundle(); 1161d890e0daf2f46dc83580280cfa22031dfebc216Jeff Sharkey args.putParcelable(EXTRA_INCLUDE_APPS, includeApps); 1171d890e0daf2f46dc83580280cfa22031dfebc216Jeff Sharkey 118761122118b2437aee3a44e9263b73766986c12b8Jeff Sharkey final RootsFragment fragment = new RootsFragment(); 1191d890e0daf2f46dc83580280cfa22031dfebc216Jeff Sharkey fragment.setArguments(args); 120761122118b2437aee3a44e9263b73766986c12b8Jeff Sharkey 121761122118b2437aee3a44e9263b73766986c12b8Jeff Sharkey final FragmentTransaction ft = fm.beginTransaction(); 122761122118b2437aee3a44e9263b73766986c12b8Jeff Sharkey ft.replace(R.id.container_roots, fragment); 123761122118b2437aee3a44e9263b73766986c12b8Jeff Sharkey ft.commitAllowingStateLoss(); 124821727a0fd0fa608a3046db8dad6ea588e16828fBen Lin 125821727a0fd0fa608a3046db8dad6ea588e16828fBen Lin return fragment; 126761122118b2437aee3a44e9263b73766986c12b8Jeff Sharkey } 127761122118b2437aee3a44e9263b73766986c12b8Jeff Sharkey 128761122118b2437aee3a44e9263b73766986c12b8Jeff Sharkey public static RootsFragment get(FragmentManager fm) { 129761122118b2437aee3a44e9263b73766986c12b8Jeff Sharkey return (RootsFragment) fm.findFragmentById(R.id.container_roots); 130761122118b2437aee3a44e9263b73766986c12b8Jeff Sharkey } 131761122118b2437aee3a44e9263b73766986c12b8Jeff Sharkey 132761122118b2437aee3a44e9263b73766986c12b8Jeff Sharkey @Override 133761122118b2437aee3a44e9263b73766986c12b8Jeff Sharkey public View onCreateView( 134761122118b2437aee3a44e9263b73766986c12b8Jeff Sharkey LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { 135761122118b2437aee3a44e9263b73766986c12b8Jeff Sharkey 13692ae43d5d22331aad83e1a4302a7e1975f66354eSteve McKay mInjector = getBaseActivity().getInjector(); 13792ae43d5d22331aad83e1a4302a7e1975f66354eSteve McKay 138761122118b2437aee3a44e9263b73766986c12b8Jeff Sharkey final View view = inflater.inflate(R.layout.fragment_roots, container, false); 13974e5d4173a1cd060b16c663108a1eeabeae25540Ben Kwa mList = (ListView) view.findViewById(R.id.roots_list); 140761122118b2437aee3a44e9263b73766986c12b8Jeff Sharkey mList.setOnItemClickListener(mItemListener); 141821727a0fd0fa608a3046db8dad6ea588e16828fBen Lin // ListView does not have right-click specific listeners, so we will have a 142821727a0fd0fa608a3046db8dad6ea588e16828fBen Lin // GenericMotionListener to listen for it. 143821727a0fd0fa608a3046db8dad6ea588e16828fBen Lin // Currently, right click is viewed the same as long press, so we will have to quickly 144821727a0fd0fa608a3046db8dad6ea588e16828fBen Lin // register for context menu when we receive a right click event, and quickly unregister 145821727a0fd0fa608a3046db8dad6ea588e16828fBen Lin // it afterwards to prevent context menus popping up upon long presses. 146821727a0fd0fa608a3046db8dad6ea588e16828fBen Lin // All other motion events will then get passed to OnItemClickListener. 1475668b866d52a4f8907474922dc9b1ba1b4db85a3Ben Lin mList.setOnGenericMotionListener( 1485668b866d52a4f8907474922dc9b1ba1b4db85a3Ben Lin new OnGenericMotionListener() { 1498e9125847b29bbb436108c3bfda50a0018c48796Ben Lin @Override 1508e9125847b29bbb436108c3bfda50a0018c48796Ben Lin public boolean onGenericMotion(View v, MotionEvent event) { 1518e9125847b29bbb436108c3bfda50a0018c48796Ben Lin if (Events.isMouseEvent(event) 1528e9125847b29bbb436108c3bfda50a0018c48796Ben Lin && event.getButtonState() == MotionEvent.BUTTON_SECONDARY) { 1538e9125847b29bbb436108c3bfda50a0018c48796Ben Lin int x = (int) event.getX(); 1548e9125847b29bbb436108c3bfda50a0018c48796Ben Lin int y = (int) event.getY(); 1558e9125847b29bbb436108c3bfda50a0018c48796Ben Lin return onRightClick(v, x, y, () -> { 15692ae43d5d22331aad83e1a4302a7e1975f66354eSteve McKay mInjector.menuManager.showContextMenu( 15792ae43d5d22331aad83e1a4302a7e1975f66354eSteve McKay RootsFragment.this, v, x, y); 1588e9125847b29bbb436108c3bfda50a0018c48796Ben Lin }); 1598e9125847b29bbb436108c3bfda50a0018c48796Ben Lin } 1608e9125847b29bbb436108c3bfda50a0018c48796Ben Lin return false; 1615668b866d52a4f8907474922dc9b1ba1b4db85a3Ben Lin } 1625668b866d52a4f8907474922dc9b1ba1b4db85a3Ben Lin }); 16342d267920811d75bda7fad2d2064b5ae48240f83Jeff Sharkey mList.setChoiceMode(ListView.CHOICE_MODE_SINGLE); 164761122118b2437aee3a44e9263b73766986c12b8Jeff Sharkey return view; 165761122118b2437aee3a44e9263b73766986c12b8Jeff Sharkey } 166761122118b2437aee3a44e9263b73766986c12b8Jeff Sharkey 1678e9125847b29bbb436108c3bfda50a0018c48796Ben Lin private boolean onRightClick(View v, int x, int y, Runnable callback) { 168d020212fdad3be1537dfa47ff5b67e3bc4272d5eBen Lin final int pos = mList.pointToPosition(x, y); 1698e9125847b29bbb436108c3bfda50a0018c48796Ben Lin final Item item = mAdapter.getItem(pos); 170d020212fdad3be1537dfa47ff5b67e3bc4272d5eBen Lin 171d020212fdad3be1537dfa47ff5b67e3bc4272d5eBen Lin // If a read-only root, no need to see if top level is writable (it's not) 172d020212fdad3be1537dfa47ff5b67e3bc4272d5eBen Lin if (!(item instanceof RootItem) || !((RootItem) item).root.supportsCreate()) { 1738e9125847b29bbb436108c3bfda50a0018c48796Ben Lin return false; 1748e9125847b29bbb436108c3bfda50a0018c48796Ben Lin } 1758e9125847b29bbb436108c3bfda50a0018c48796Ben Lin 176d020212fdad3be1537dfa47ff5b67e3bc4272d5eBen Lin final RootItem rootItem = (RootItem) item; 177d020212fdad3be1537dfa47ff5b67e3bc4272d5eBen Lin getRootDocument(rootItem, (DocumentInfo doc) -> { 178d020212fdad3be1537dfa47ff5b67e3bc4272d5eBen Lin rootItem.docInfo = doc; 1798e9125847b29bbb436108c3bfda50a0018c48796Ben Lin callback.run(); 180d020212fdad3be1537dfa47ff5b67e3bc4272d5eBen Lin }); 1818e9125847b29bbb436108c3bfda50a0018c48796Ben Lin return true; 1828e9125847b29bbb436108c3bfda50a0018c48796Ben Lin } 1838e9125847b29bbb436108c3bfda50a0018c48796Ben Lin 184c6cbdf11d976ff5845d12c46fb2d601ca7fb0ab2Jeff Sharkey @Override 1858b9970489d03ee0bda3d8d4773bf672c182922c6Jeff Sharkey public void onActivityCreated(Bundle savedInstanceState) { 1868b9970489d03ee0bda3d8d4773bf672c182922c6Jeff Sharkey super.onActivityCreated(savedInstanceState); 1878b9970489d03ee0bda3d8d4773bf672c182922c6Jeff Sharkey 1887d75f7bbd1693a33abb8de6b472ec1950e33eb8bGarfield Tan final BaseActivity activity = getBaseActivity(); 1899bd4099ee27f8302a06fc66980079f29127318f8Jon Mann final ProvidersCache providers = DocumentsApplication.getProvidersCache(activity); 1907d75f7bbd1693a33abb8de6b472ec1950e33eb8bGarfield Tan final State state = activity.getDisplayState(); 1917d75f7bbd1693a33abb8de6b472ec1950e33eb8bGarfield Tan 19292ae43d5d22331aad83e1a4302a7e1975f66354eSteve McKay mActionHandler = mInjector.actions; 193208945c4e262868d3ebe0f55f1b895cd5a201cbbGarfield Tan 19492ae43d5d22331aad83e1a4302a7e1975f66354eSteve McKay if (mInjector.config.dragAndDropEnabled()) { 195208945c4e262868d3ebe0f55f1b895cd5a201cbbGarfield Tan mDragListener = new ItemDragListener<RootsFragment>(this) { 196208945c4e262868d3ebe0f55f1b895cd5a201cbbGarfield Tan @Override 197208945c4e262868d3ebe0f55f1b895cd5a201cbbGarfield Tan public boolean handleDropEventChecked(View v, DragEvent event) { 198208945c4e262868d3ebe0f55f1b895cd5a201cbbGarfield Tan final int position = (Integer) v.getTag(R.id.item_position_tag); 199208945c4e262868d3ebe0f55f1b895cd5a201cbbGarfield Tan final Item item = mAdapter.getItem(position); 200208945c4e262868d3ebe0f55f1b895cd5a201cbbGarfield Tan 201208945c4e262868d3ebe0f55f1b895cd5a201cbbGarfield Tan assert (item.isDropTarget()); 202208945c4e262868d3ebe0f55f1b895cd5a201cbbGarfield Tan 203174fc2e99583c863287eb1f3bcaefd66565f4392Ben Lin return item.dropOn(event); 204208945c4e262868d3ebe0f55f1b895cd5a201cbbGarfield Tan } 205208945c4e262868d3ebe0f55f1b895cd5a201cbbGarfield Tan }; 206208945c4e262868d3ebe0f55f1b895cd5a201cbbGarfield Tan } 207208945c4e262868d3ebe0f55f1b895cd5a201cbbGarfield Tan 2088b9970489d03ee0bda3d8d4773bf672c182922c6Jeff Sharkey mCallbacks = new LoaderCallbacks<Collection<RootInfo>>() { 2098b9970489d03ee0bda3d8d4773bf672c182922c6Jeff Sharkey @Override 2108b9970489d03ee0bda3d8d4773bf672c182922c6Jeff Sharkey public Loader<Collection<RootInfo>> onCreateLoader(int id, Bundle args) { 2119bd4099ee27f8302a06fc66980079f29127318f8Jon Mann return new RootsLoader(activity, providers, state); 2128b9970489d03ee0bda3d8d4773bf672c182922c6Jeff Sharkey } 2138b9970489d03ee0bda3d8d4773bf672c182922c6Jeff Sharkey 2148b9970489d03ee0bda3d8d4773bf672c182922c6Jeff Sharkey @Override 2158b9970489d03ee0bda3d8d4773bf672c182922c6Jeff Sharkey public void onLoadFinished( 2168b9970489d03ee0bda3d8d4773bf672c182922c6Jeff Sharkey Loader<Collection<RootInfo>> loader, Collection<RootInfo> result) { 217323dffb4cffde781d325ddd3a36da9ed7b5bfec6Steve McKay if (!isAdded()) { 218323dffb4cffde781d325ddd3a36da9ed7b5bfec6Steve McKay return; 219323dffb4cffde781d325ddd3a36da9ed7b5bfec6Steve McKay } 2208b9970489d03ee0bda3d8d4773bf672c182922c6Jeff Sharkey 221323dffb4cffde781d325ddd3a36da9ed7b5bfec6Steve McKay Intent handlerAppIntent = getArguments().getParcelable(EXTRA_INCLUDE_APPS); 2228b9970489d03ee0bda3d8d4773bf672c182922c6Jeff Sharkey 2237d75f7bbd1693a33abb8de6b472ec1950e33eb8bGarfield Tan List<Item> sortedItems = sortLoadResult(result, handlerAppIntent); 2247d75f7bbd1693a33abb8de6b472ec1950e33eb8bGarfield Tan mAdapter = new RootsAdapter(activity, sortedItems, mDragListener); 2258b9970489d03ee0bda3d8d4773bf672c182922c6Jeff Sharkey mList.setAdapter(mAdapter); 2268b9970489d03ee0bda3d8d4773bf672c182922c6Jeff Sharkey 2278b9970489d03ee0bda3d8d4773bf672c182922c6Jeff Sharkey onCurrentRootChanged(); 2288b9970489d03ee0bda3d8d4773bf672c182922c6Jeff Sharkey } 2298b9970489d03ee0bda3d8d4773bf672c182922c6Jeff Sharkey 2308b9970489d03ee0bda3d8d4773bf672c182922c6Jeff Sharkey @Override 2318b9970489d03ee0bda3d8d4773bf672c182922c6Jeff Sharkey public void onLoaderReset(Loader<Collection<RootInfo>> loader) { 2328b9970489d03ee0bda3d8d4773bf672c182922c6Jeff Sharkey mAdapter = null; 2338b9970489d03ee0bda3d8d4773bf672c182922c6Jeff Sharkey mList.setAdapter(null); 2348b9970489d03ee0bda3d8d4773bf672c182922c6Jeff Sharkey } 2358b9970489d03ee0bda3d8d4773bf672c182922c6Jeff Sharkey }; 2368b9970489d03ee0bda3d8d4773bf672c182922c6Jeff Sharkey } 2378b9970489d03ee0bda3d8d4773bf672c182922c6Jeff Sharkey 2387d75f7bbd1693a33abb8de6b472ec1950e33eb8bGarfield Tan /** 2397d75f7bbd1693a33abb8de6b472ec1950e33eb8bGarfield Tan * @param handlerAppIntent When not null, apps capable of handling the original intent will 2407d75f7bbd1693a33abb8de6b472ec1950e33eb8bGarfield Tan * be included in list of roots (in special section at bottom). 2417d75f7bbd1693a33abb8de6b472ec1950e33eb8bGarfield Tan */ 2427d75f7bbd1693a33abb8de6b472ec1950e33eb8bGarfield Tan private List<Item> sortLoadResult( 2437d75f7bbd1693a33abb8de6b472ec1950e33eb8bGarfield Tan Collection<RootInfo> roots, @Nullable Intent handlerAppIntent) { 2447d75f7bbd1693a33abb8de6b472ec1950e33eb8bGarfield Tan final List<Item> result = new ArrayList<>(); 2457d75f7bbd1693a33abb8de6b472ec1950e33eb8bGarfield Tan 2467d75f7bbd1693a33abb8de6b472ec1950e33eb8bGarfield Tan final List<RootItem> libraries = new ArrayList<>(); 2477d75f7bbd1693a33abb8de6b472ec1950e33eb8bGarfield Tan final List<RootItem> others = new ArrayList<>(); 2487d75f7bbd1693a33abb8de6b472ec1950e33eb8bGarfield Tan 2497d75f7bbd1693a33abb8de6b472ec1950e33eb8bGarfield Tan for (final RootInfo root : roots) { 2507d75f7bbd1693a33abb8de6b472ec1950e33eb8bGarfield Tan final RootItem item = new RootItem(root, mActionHandler); 2517d75f7bbd1693a33abb8de6b472ec1950e33eb8bGarfield Tan 2527d75f7bbd1693a33abb8de6b472ec1950e33eb8bGarfield Tan Activity activity = getActivity(); 253a0b52655668ccbe3f12ca13ced4b34118a483783Steve McKay if (root.isHome() && !Shared.shouldShowDocumentsRoot(activity)) { 2547d75f7bbd1693a33abb8de6b472ec1950e33eb8bGarfield Tan continue; 2557d75f7bbd1693a33abb8de6b472ec1950e33eb8bGarfield Tan } else if (root.isLibrary()) { 2567d75f7bbd1693a33abb8de6b472ec1950e33eb8bGarfield Tan libraries.add(item); 2577d75f7bbd1693a33abb8de6b472ec1950e33eb8bGarfield Tan } else { 2587d75f7bbd1693a33abb8de6b472ec1950e33eb8bGarfield Tan others.add(item); 2597d75f7bbd1693a33abb8de6b472ec1950e33eb8bGarfield Tan } 2607d75f7bbd1693a33abb8de6b472ec1950e33eb8bGarfield Tan } 2617d75f7bbd1693a33abb8de6b472ec1950e33eb8bGarfield Tan 2627d75f7bbd1693a33abb8de6b472ec1950e33eb8bGarfield Tan final RootComparator comp = new RootComparator(); 2637d75f7bbd1693a33abb8de6b472ec1950e33eb8bGarfield Tan Collections.sort(libraries, comp); 2647d75f7bbd1693a33abb8de6b472ec1950e33eb8bGarfield Tan Collections.sort(others, comp); 2657d75f7bbd1693a33abb8de6b472ec1950e33eb8bGarfield Tan 26630535bce902104c97bbf70783d684ee673cb7637Steve McKay if (VERBOSE) Log.v(TAG, "Adding library roots: " + libraries); 2677d75f7bbd1693a33abb8de6b472ec1950e33eb8bGarfield Tan result.addAll(libraries); 2687d75f7bbd1693a33abb8de6b472ec1950e33eb8bGarfield Tan // Only add the spacer if it is actually separating something. 2697d75f7bbd1693a33abb8de6b472ec1950e33eb8bGarfield Tan if (!libraries.isEmpty() && !others.isEmpty()) { 2707d75f7bbd1693a33abb8de6b472ec1950e33eb8bGarfield Tan result.add(new SpacerItem()); 2717d75f7bbd1693a33abb8de6b472ec1950e33eb8bGarfield Tan } 2727d75f7bbd1693a33abb8de6b472ec1950e33eb8bGarfield Tan 27330535bce902104c97bbf70783d684ee673cb7637Steve McKay if (VERBOSE) Log.v(TAG, "Adding plain roots: " + libraries); 2747d75f7bbd1693a33abb8de6b472ec1950e33eb8bGarfield Tan result.addAll(others); 2757d75f7bbd1693a33abb8de6b472ec1950e33eb8bGarfield Tan 2767d75f7bbd1693a33abb8de6b472ec1950e33eb8bGarfield Tan // Include apps that can handle this intent too. 2777d75f7bbd1693a33abb8de6b472ec1950e33eb8bGarfield Tan if (handlerAppIntent != null) { 2787d75f7bbd1693a33abb8de6b472ec1950e33eb8bGarfield Tan includeHandlerApps(handlerAppIntent, result); 2797d75f7bbd1693a33abb8de6b472ec1950e33eb8bGarfield Tan } 2807d75f7bbd1693a33abb8de6b472ec1950e33eb8bGarfield Tan 2817d75f7bbd1693a33abb8de6b472ec1950e33eb8bGarfield Tan return result; 2827d75f7bbd1693a33abb8de6b472ec1950e33eb8bGarfield Tan } 2837d75f7bbd1693a33abb8de6b472ec1950e33eb8bGarfield Tan 2847d75f7bbd1693a33abb8de6b472ec1950e33eb8bGarfield Tan /** 2857d75f7bbd1693a33abb8de6b472ec1950e33eb8bGarfield Tan * Adds apps capable of handling the original intent will be included in list of roots (in 2867d75f7bbd1693a33abb8de6b472ec1950e33eb8bGarfield Tan * special section at bottom). 2877d75f7bbd1693a33abb8de6b472ec1950e33eb8bGarfield Tan */ 2887d75f7bbd1693a33abb8de6b472ec1950e33eb8bGarfield Tan private void includeHandlerApps(Intent handlerAppIntent, List<Item> result) { 28930535bce902104c97bbf70783d684ee673cb7637Steve McKay if (VERBOSE) Log.v(TAG, "Adding handler apps for intent: " + handlerAppIntent); 2907d75f7bbd1693a33abb8de6b472ec1950e33eb8bGarfield Tan Context context = getContext(); 2917d75f7bbd1693a33abb8de6b472ec1950e33eb8bGarfield Tan final PackageManager pm = context.getPackageManager(); 2927d75f7bbd1693a33abb8de6b472ec1950e33eb8bGarfield Tan final List<ResolveInfo> infos = pm.queryIntentActivities( 2937d75f7bbd1693a33abb8de6b472ec1950e33eb8bGarfield Tan handlerAppIntent, PackageManager.MATCH_DEFAULT_ONLY); 2947d75f7bbd1693a33abb8de6b472ec1950e33eb8bGarfield Tan 2957d75f7bbd1693a33abb8de6b472ec1950e33eb8bGarfield Tan final List<AppItem> apps = new ArrayList<>(); 2967d75f7bbd1693a33abb8de6b472ec1950e33eb8bGarfield Tan 2977d75f7bbd1693a33abb8de6b472ec1950e33eb8bGarfield Tan // Omit ourselves from the list 2987d75f7bbd1693a33abb8de6b472ec1950e33eb8bGarfield Tan for (ResolveInfo info : infos) { 2997d75f7bbd1693a33abb8de6b472ec1950e33eb8bGarfield Tan if (!context.getPackageName().equals(info.activityInfo.packageName)) { 3007d75f7bbd1693a33abb8de6b472ec1950e33eb8bGarfield Tan apps.add(new AppItem(info, mActionHandler)); 3017d75f7bbd1693a33abb8de6b472ec1950e33eb8bGarfield Tan } 3027d75f7bbd1693a33abb8de6b472ec1950e33eb8bGarfield Tan } 3037d75f7bbd1693a33abb8de6b472ec1950e33eb8bGarfield Tan 3047d75f7bbd1693a33abb8de6b472ec1950e33eb8bGarfield Tan if (apps.size() > 0) { 3057d75f7bbd1693a33abb8de6b472ec1950e33eb8bGarfield Tan result.add(new SpacerItem()); 3067d75f7bbd1693a33abb8de6b472ec1950e33eb8bGarfield Tan result.addAll(apps); 3077d75f7bbd1693a33abb8de6b472ec1950e33eb8bGarfield Tan } 3087d75f7bbd1693a33abb8de6b472ec1950e33eb8bGarfield Tan } 3097d75f7bbd1693a33abb8de6b472ec1950e33eb8bGarfield Tan 3108b9970489d03ee0bda3d8d4773bf672c182922c6Jeff Sharkey @Override 3117d58fc6e8875ccc3dbbb34bcd379a0f9c9ee481eJeff Sharkey public void onResume() { 3127d58fc6e8875ccc3dbbb34bcd379a0f9c9ee481eJeff Sharkey super.onResume(); 313e8d13ea5fbd07e9a9c0d2867a0eb3e6d761815cfJeff Sharkey onDisplayStateChanged(); 314e8d13ea5fbd07e9a9c0d2867a0eb3e6d761815cfJeff Sharkey } 315c6cbdf11d976ff5845d12c46fb2d601ca7fb0ab2Jeff Sharkey 316e8d13ea5fbd07e9a9c0d2867a0eb3e6d761815cfJeff Sharkey public void onDisplayStateChanged() { 317c6cbdf11d976ff5845d12c46fb2d601ca7fb0ab2Jeff Sharkey final Context context = getActivity(); 318d0a2a2c4e061da0de1b0008b841cacd9fc4416edSteve McKay final State state = ((BaseActivity) context).getDisplayState(); 3191c903ccb39bc3f96452b41cad91fb6efc053b664Jeff Sharkey 320d0a2a2c4e061da0de1b0008b841cacd9fc4416edSteve McKay if (state.action == State.ACTION_GET_CONTENT) { 3218f1edfe6c6a39b8fec7521694328fe8f31d6496eJeff Sharkey mList.setOnItemLongClickListener(mItemLongClickListener); 3228f1edfe6c6a39b8fec7521694328fe8f31d6496eJeff Sharkey } else { 3238f1edfe6c6a39b8fec7521694328fe8f31d6496eJeff Sharkey mList.setOnItemLongClickListener(null); 3248f1edfe6c6a39b8fec7521694328fe8f31d6496eJeff Sharkey mList.setLongClickable(false); 3258f1edfe6c6a39b8fec7521694328fe8f31d6496eJeff Sharkey } 3268f1edfe6c6a39b8fec7521694328fe8f31d6496eJeff Sharkey 3278b9970489d03ee0bda3d8d4773bf672c182922c6Jeff Sharkey getLoaderManager().restartLoader(2, null, mCallbacks); 32842d267920811d75bda7fad2d2064b5ae48240f83Jeff Sharkey } 32942d267920811d75bda7fad2d2064b5ae48240f83Jeff Sharkey 33042d267920811d75bda7fad2d2064b5ae48240f83Jeff Sharkey public void onCurrentRootChanged() { 331323dffb4cffde781d325ddd3a36da9ed7b5bfec6Steve McKay if (mAdapter == null) { 332323dffb4cffde781d325ddd3a36da9ed7b5bfec6Steve McKay return; 333323dffb4cffde781d325ddd3a36da9ed7b5bfec6Steve McKay } 33442d267920811d75bda7fad2d2064b5ae48240f83Jeff Sharkey 335d0a2a2c4e061da0de1b0008b841cacd9fc4416edSteve McKay final RootInfo root = ((BaseActivity) getActivity()).getCurrentRoot(); 33642d267920811d75bda7fad2d2064b5ae48240f83Jeff Sharkey for (int i = 0; i < mAdapter.getCount(); i++) { 33742d267920811d75bda7fad2d2064b5ae48240f83Jeff Sharkey final Object item = mAdapter.getItem(i); 33825f10b31243ed6f8de5f32ba2cb2dd0d6de911f5Jeff Sharkey if (item instanceof RootItem) { 33925f10b31243ed6f8de5f32ba2cb2dd0d6de911f5Jeff Sharkey final RootInfo testRoot = ((RootItem) item).root; 34016d8598bdec0015382519ecece459d8da653dcbcKenny Root if (Objects.equals(testRoot, root)) { 34125f10b31243ed6f8de5f32ba2cb2dd0d6de911f5Jeff Sharkey mList.setItemChecked(i, true); 34225f10b31243ed6f8de5f32ba2cb2dd0d6de911f5Jeff Sharkey return; 34325f10b31243ed6f8de5f32ba2cb2dd0d6de911f5Jeff Sharkey } 34442d267920811d75bda7fad2d2064b5ae48240f83Jeff Sharkey } 34542d267920811d75bda7fad2d2064b5ae48240f83Jeff Sharkey } 346c6cbdf11d976ff5845d12c46fb2d601ca7fb0ab2Jeff Sharkey } 347c6cbdf11d976ff5845d12c46fb2d601ca7fb0ab2Jeff Sharkey 34874e5d4173a1cd060b16c663108a1eeabeae25540Ben Kwa /** 34974e5d4173a1cd060b16c663108a1eeabeae25540Ben Kwa * Attempts to shift focus back to the navigation drawer. 35074e5d4173a1cd060b16c663108a1eeabeae25540Ben Kwa */ 351d947f0192142c7db40d7dfaa8d0c6caaa1cf7c36Ben Lin public boolean requestFocus() { 352d947f0192142c7db40d7dfaa8d0c6caaa1cf7c36Ben Lin return mList.requestFocus(); 35374e5d4173a1cd060b16c663108a1eeabeae25540Ben Kwa } 35474e5d4173a1cd060b16c663108a1eeabeae25540Ben Kwa 35592ae43d5d22331aad83e1a4302a7e1975f66354eSteve McKay private BaseActivity getBaseActivity() { 35692ae43d5d22331aad83e1a4302a7e1975f66354eSteve McKay return (BaseActivity) getActivity(); 3575668b866d52a4f8907474922dc9b1ba1b4db85a3Ben Lin } 3585668b866d52a4f8907474922dc9b1ba1b4db85a3Ben Lin 359804133e4ca98ffa168cd547793054b594cf6d9ccGarfield, Tan @Override 360804133e4ca98ffa168cd547793054b594cf6d9ccGarfield, Tan public void runOnUiThread(Runnable runnable) { 361804133e4ca98ffa168cd547793054b594cf6d9ccGarfield, Tan getActivity().runOnUiThread(runnable); 362804133e4ca98ffa168cd547793054b594cf6d9ccGarfield, Tan } 363804133e4ca98ffa168cd547793054b594cf6d9ccGarfield, Tan 364d020212fdad3be1537dfa47ff5b67e3bc4272d5eBen Lin // In RootsFragment, we check whether the item corresponds to a RootItem, and whether 365d020212fdad3be1537dfa47ff5b67e3bc4272d5eBen Lin // the currently dragged objects can be droppable or not, and change the drop-shadow 366d020212fdad3be1537dfa47ff5b67e3bc4272d5eBen Lin // accordingly 3677f72a3c30ea89e2655ea6c453f8964bfedf4474bBen Lin @Override 3681c45629929c31cf7903cf955a48f170a8cdee255Ben Lin public void onDragEntered(View v, Object localState) { 369d020212fdad3be1537dfa47ff5b67e3bc4272d5eBen Lin final int pos = (Integer) v.getTag(R.id.item_position_tag); 370d020212fdad3be1537dfa47ff5b67e3bc4272d5eBen Lin final Item item = mAdapter.getItem(pos); 371d020212fdad3be1537dfa47ff5b67e3bc4272d5eBen Lin 372d020212fdad3be1537dfa47ff5b67e3bc4272d5eBen Lin // If a read-only root, no need to see if top level is writable (it's not) 373d020212fdad3be1537dfa47ff5b67e3bc4272d5eBen Lin if (!(item instanceof RootItem) || !((RootItem) item).root.supportsCreate()) { 374d020212fdad3be1537dfa47ff5b67e3bc4272d5eBen Lin getBaseActivity().getShadowBuilder().setAppearDroppable(false); 375d020212fdad3be1537dfa47ff5b67e3bc4272d5eBen Lin v.updateDragShadow(getBaseActivity().getShadowBuilder()); 376d020212fdad3be1537dfa47ff5b67e3bc4272d5eBen Lin return; 377d020212fdad3be1537dfa47ff5b67e3bc4272d5eBen Lin } 378d020212fdad3be1537dfa47ff5b67e3bc4272d5eBen Lin 379d020212fdad3be1537dfa47ff5b67e3bc4272d5eBen Lin final RootItem rootItem = (RootItem) item; 380d020212fdad3be1537dfa47ff5b67e3bc4272d5eBen Lin getRootDocument(rootItem, (DocumentInfo doc) -> { 381b0761d3b04ed16800bc96a32a759fd6374d1e20fBen Lin updateDropShadow(v, localState, rootItem, doc); 382d020212fdad3be1537dfa47ff5b67e3bc4272d5eBen Lin }); 3837f72a3c30ea89e2655ea6c453f8964bfedf4474bBen Lin } 3847f72a3c30ea89e2655ea6c453f8964bfedf4474bBen Lin 385b0761d3b04ed16800bc96a32a759fd6374d1e20fBen Lin private void updateDropShadow( 386b0761d3b04ed16800bc96a32a759fd6374d1e20fBen Lin View v, Object localState, RootItem rootItem, DocumentInfo rootDoc) { 387b0761d3b04ed16800bc96a32a759fd6374d1e20fBen Lin final DragShadowBuilder shadowBuilder = getBaseActivity().getShadowBuilder(); 388b0761d3b04ed16800bc96a32a759fd6374d1e20fBen Lin if (rootDoc == null) { 389b0761d3b04ed16800bc96a32a759fd6374d1e20fBen Lin Log.e(TAG, "Root DocumentInfo is null. Defaulting to appear not droppable."); 390b0761d3b04ed16800bc96a32a759fd6374d1e20fBen Lin shadowBuilder.setAppearDroppable(false); 391b0761d3b04ed16800bc96a32a759fd6374d1e20fBen Lin } else { 392b0761d3b04ed16800bc96a32a759fd6374d1e20fBen Lin rootItem.docInfo = rootDoc; 393b0761d3b04ed16800bc96a32a759fd6374d1e20fBen Lin shadowBuilder.setAppearDroppable(rootDoc.isCreateSupported() 394b0761d3b04ed16800bc96a32a759fd6374d1e20fBen Lin && DragAndDropHelper.canCopyTo(localState, rootDoc)); 395b0761d3b04ed16800bc96a32a759fd6374d1e20fBen Lin } 396b0761d3b04ed16800bc96a32a759fd6374d1e20fBen Lin v.updateDragShadow(shadowBuilder); 397b0761d3b04ed16800bc96a32a759fd6374d1e20fBen Lin } 398b0761d3b04ed16800bc96a32a759fd6374d1e20fBen Lin 399d020212fdad3be1537dfa47ff5b67e3bc4272d5eBen Lin // In RootsFragment we always reset the drag shadow as it exits a RootItemView. 400d020212fdad3be1537dfa47ff5b67e3bc4272d5eBen Lin @Override 401d020212fdad3be1537dfa47ff5b67e3bc4272d5eBen Lin public void onDragExited(View v, Object localState) { 402d020212fdad3be1537dfa47ff5b67e3bc4272d5eBen Lin getBaseActivity().getShadowBuilder().resetBackground(); 403d020212fdad3be1537dfa47ff5b67e3bc4272d5eBen Lin v.updateDragShadow(getBaseActivity().getShadowBuilder()); 404d020212fdad3be1537dfa47ff5b67e3bc4272d5eBen Lin } 405d020212fdad3be1537dfa47ff5b67e3bc4272d5eBen Lin 406d020212fdad3be1537dfa47ff5b67e3bc4272d5eBen Lin // In RootsFragment we open the hovered root. 407804133e4ca98ffa168cd547793054b594cf6d9ccGarfield, Tan @Override 408a5588b65d55bc1b8b5ba943f8b660db26a7eac5cGarfield, Tan public void onViewHovered(View v) { 40957facaf76bc8d23b539518a342e1a126b51b64ceGarfield, Tan // SpacerView doesn't have DragListener so this view is guaranteed to be a RootItemView. 410a5588b65d55bc1b8b5ba943f8b660db26a7eac5cGarfield, Tan RootItemView itemView = (RootItemView) v; 41157facaf76bc8d23b539518a342e1a126b51b64ceGarfield, Tan itemView.drawRipple(); 41257facaf76bc8d23b539518a342e1a126b51b64ceGarfield, Tan 413a5588b65d55bc1b8b5ba943f8b660db26a7eac5cGarfield, Tan final int position = (Integer) v.getTag(R.id.item_position_tag); 4147d66a862d5f4c96e339f8f6dbfc0406ed16ee9b6Garfield, Tan final Item item = mAdapter.getItem(position); 4157d75f7bbd1693a33abb8de6b472ec1950e33eb8bGarfield Tan item.open(); 416804133e4ca98ffa168cd547793054b594cf6d9ccGarfield, Tan } 417804133e4ca98ffa168cd547793054b594cf6d9ccGarfield, Tan 418804133e4ca98ffa168cd547793054b594cf6d9ccGarfield, Tan @Override 419166c5c6fc17461cb52f2b83eaec86cfc15b53004Ben Lin public void setDropTargetHighlight(View v, Object localState, boolean highlight) { 42057facaf76bc8d23b539518a342e1a126b51b64ceGarfield, Tan // SpacerView doesn't have DragListener so this view is guaranteed to be a RootItemView. 42157facaf76bc8d23b539518a342e1a126b51b64ceGarfield, Tan RootItemView itemView = (RootItemView) v; 42257facaf76bc8d23b539518a342e1a126b51b64ceGarfield, Tan itemView.setHighlight(highlight); 423804133e4ca98ffa168cd547793054b594cf6d9ccGarfield, Tan } 424804133e4ca98ffa168cd547793054b594cf6d9ccGarfield, Tan 4255668b866d52a4f8907474922dc9b1ba1b4db85a3Ben Lin @Override 4265668b866d52a4f8907474922dc9b1ba1b4db85a3Ben Lin public void onCreateContextMenu( 4275668b866d52a4f8907474922dc9b1ba1b4db85a3Ben Lin ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) { 4285668b866d52a4f8907474922dc9b1ba1b4db85a3Ben Lin super.onCreateContextMenu(menu, v, menuInfo); 4295668b866d52a4f8907474922dc9b1ba1b4db85a3Ben Lin AdapterContextMenuInfo adapterMenuInfo = (AdapterContextMenuInfo) menuInfo; 4305668b866d52a4f8907474922dc9b1ba1b4db85a3Ben Lin final Item item = mAdapter.getItem(adapterMenuInfo.position); 4317d75f7bbd1693a33abb8de6b472ec1950e33eb8bGarfield Tan 43292ae43d5d22331aad83e1a4302a7e1975f66354eSteve McKay BaseActivity activity = getBaseActivity(); 43392ae43d5d22331aad83e1a4302a7e1975f66354eSteve McKay item.createContextMenu(menu, activity.getMenuInflater(), mInjector.menuManager); 4345668b866d52a4f8907474922dc9b1ba1b4db85a3Ben Lin } 4355668b866d52a4f8907474922dc9b1ba1b4db85a3Ben Lin 4365668b866d52a4f8907474922dc9b1ba1b4db85a3Ben Lin @Override 4375668b866d52a4f8907474922dc9b1ba1b4db85a3Ben Lin public boolean onContextItemSelected(MenuItem item) { 4385668b866d52a4f8907474922dc9b1ba1b4db85a3Ben Lin AdapterContextMenuInfo adapterMenuInfo = (AdapterContextMenuInfo) item.getMenuInfo(); 439035f0c8a6f8f2f5515ee30272b5343ec4095f8c0Ben Lin // There is a possibility that this is called from DirectoryFragment since 440035f0c8a6f8f2f5515ee30272b5343ec4095f8c0Ben Lin // all fragments' onContextItemSelected gets called when any menu item is selected 441035f0c8a6f8f2f5515ee30272b5343ec4095f8c0Ben Lin // This is to guard against it since DirectoryFragment's RecylerView does not have a 442035f0c8a6f8f2f5515ee30272b5343ec4095f8c0Ben Lin // menuInfo 443035f0c8a6f8f2f5515ee30272b5343ec4095f8c0Ben Lin if (adapterMenuInfo == null) { 444035f0c8a6f8f2f5515ee30272b5343ec4095f8c0Ben Lin return false; 445035f0c8a6f8f2f5515ee30272b5343ec4095f8c0Ben Lin } 4465668b866d52a4f8907474922dc9b1ba1b4db85a3Ben Lin final RootItem rootItem = (RootItem) mAdapter.getItem(adapterMenuInfo.position); 447035f0c8a6f8f2f5515ee30272b5343ec4095f8c0Ben Lin switch (item.getItemId()) { 4485668b866d52a4f8907474922dc9b1ba1b4db85a3Ben Lin case R.id.menu_eject_root: 449821727a0fd0fa608a3046db8dad6ea588e16828fBen Lin final View ejectIcon = adapterMenuInfo.targetView.findViewById(R.id.eject_icon); 4507d75f7bbd1693a33abb8de6b472ec1950e33eb8bGarfield Tan ejectClicked(ejectIcon, rootItem.root, mActionHandler); 4515668b866d52a4f8907474922dc9b1ba1b4db85a3Ben Lin return true; 452b285b40dedbde396aea8080c3d09577677bc71bcGarfield Tan case R.id.menu_open_in_new_window: 453739f94ba0dc9be264d9596dac551fd63082d2fddSteve McKay mActionHandler.openInNewWindow(new DocumentStack(rootItem.root)); 454b285b40dedbde396aea8080c3d09577677bc71bcGarfield Tan return true; 455b285b40dedbde396aea8080c3d09577677bc71bcGarfield Tan case R.id.menu_paste_into_folder: 456b285b40dedbde396aea8080c3d09577677bc71bcGarfield Tan mActionHandler.pasteIntoFolder(rootItem.root); 457b285b40dedbde396aea8080c3d09577677bc71bcGarfield Tan return true; 4585668b866d52a4f8907474922dc9b1ba1b4db85a3Ben Lin case R.id.menu_settings: 4597d75f7bbd1693a33abb8de6b472ec1950e33eb8bGarfield Tan mActionHandler.openSettings(rootItem.root); 4605668b866d52a4f8907474922dc9b1ba1b4db85a3Ben Lin return true; 4615668b866d52a4f8907474922dc9b1ba1b4db85a3Ben Lin default: 4625668b866d52a4f8907474922dc9b1ba1b4db85a3Ben Lin if (DEBUG) Log.d(TAG, "Unhandled menu item selected: " + item); 4635668b866d52a4f8907474922dc9b1ba1b4db85a3Ben Lin return false; 4645668b866d52a4f8907474922dc9b1ba1b4db85a3Ben Lin } 4655668b866d52a4f8907474922dc9b1ba1b4db85a3Ben Lin } 4665668b866d52a4f8907474922dc9b1ba1b4db85a3Ben Lin 467d020212fdad3be1537dfa47ff5b67e3bc4272d5eBen Lin @FunctionalInterface 468d020212fdad3be1537dfa47ff5b67e3bc4272d5eBen Lin interface RootUpdater { 469d020212fdad3be1537dfa47ff5b67e3bc4272d5eBen Lin void updateDocInfoForRoot(DocumentInfo doc); 470d020212fdad3be1537dfa47ff5b67e3bc4272d5eBen Lin } 471d020212fdad3be1537dfa47ff5b67e3bc4272d5eBen Lin 472d020212fdad3be1537dfa47ff5b67e3bc4272d5eBen Lin private void getRootDocument(RootItem rootItem, RootUpdater updater) { 473d020212fdad3be1537dfa47ff5b67e3bc4272d5eBen Lin // We need to start a GetRootDocumentTask so we can know whether items can be directly 474d020212fdad3be1537dfa47ff5b67e3bc4272d5eBen Lin // pasted into root 47530b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin mActionHandler.getRootDocument( 476d020212fdad3be1537dfa47ff5b67e3bc4272d5eBen Lin rootItem.root, 47730b0dc1896abc67a970b61ebfd420275a31c1e18Ben Lin CONTEXT_MENU_ITEM_TIMEOUT, 478d020212fdad3be1537dfa47ff5b67e3bc4272d5eBen Lin (DocumentInfo doc) -> { 479d020212fdad3be1537dfa47ff5b67e3bc4272d5eBen Lin updater.updateDocInfoForRoot(doc); 480d020212fdad3be1537dfa47ff5b67e3bc4272d5eBen Lin }); 481d020212fdad3be1537dfa47ff5b67e3bc4272d5eBen Lin } 482d020212fdad3be1537dfa47ff5b67e3bc4272d5eBen Lin 483739f94ba0dc9be264d9596dac551fd63082d2fddSteve McKay static void ejectClicked(View ejectIcon, RootInfo root, ActionHandler actionHandler) { 4845668b866d52a4f8907474922dc9b1ba1b4db85a3Ben Lin assert(ejectIcon != null); 4857d75f7bbd1693a33abb8de6b472ec1950e33eb8bGarfield Tan assert(!root.ejecting); 4865668b866d52a4f8907474922dc9b1ba1b4db85a3Ben Lin ejectIcon.setEnabled(false); 4875668b866d52a4f8907474922dc9b1ba1b4db85a3Ben Lin root.ejecting = true; 4887d75f7bbd1693a33abb8de6b472ec1950e33eb8bGarfield Tan actionHandler.ejectRoot( 4897d75f7bbd1693a33abb8de6b472ec1950e33eb8bGarfield Tan root, 490739f94ba0dc9be264d9596dac551fd63082d2fddSteve McKay new BooleanConsumer() { 4915668b866d52a4f8907474922dc9b1ba1b4db85a3Ben Lin @Override 492739f94ba0dc9be264d9596dac551fd63082d2fddSteve McKay public void accept(boolean ejected) { 493739f94ba0dc9be264d9596dac551fd63082d2fddSteve McKay // Event if ejected is false, we should reset, since the op failed. 494739f94ba0dc9be264d9596dac551fd63082d2fddSteve McKay // Either way, we are no longer attempting to eject the device. 4955668b866d52a4f8907474922dc9b1ba1b4db85a3Ben Lin root.ejecting = false; 496739f94ba0dc9be264d9596dac551fd63082d2fddSteve McKay 497739f94ba0dc9be264d9596dac551fd63082d2fddSteve McKay // If the view is still visible, we update its state. 498739f94ba0dc9be264d9596dac551fd63082d2fddSteve McKay if (ejectIcon.getVisibility() == View.VISIBLE) { 499739f94ba0dc9be264d9596dac551fd63082d2fddSteve McKay ejectIcon.setEnabled(!ejected); 500739f94ba0dc9be264d9596dac551fd63082d2fddSteve McKay } 5015668b866d52a4f8907474922dc9b1ba1b4db85a3Ben Lin } 5025668b866d52a4f8907474922dc9b1ba1b4db85a3Ben Lin }); 5035668b866d52a4f8907474922dc9b1ba1b4db85a3Ben Lin } 5045668b866d52a4f8907474922dc9b1ba1b4db85a3Ben Lin 5057d75f7bbd1693a33abb8de6b472ec1950e33eb8bGarfield Tan private static class RootComparator implements Comparator<RootItem> { 506b6a7f2cd05f8c507dfac684aa4c693088e8c01c7Jeff Sharkey @Override 50785c8cdd2e79e96f719932db64b61d3c51d4aeefcBen Kwa public int compare(RootItem lhs, RootItem rhs) { 50855c00e7356d9f76e7378cf7c701b9a41cb7be6daSteve McKay return lhs.root.compareTo(rhs.root); 509b6a7f2cd05f8c507dfac684aa4c693088e8c01c7Jeff Sharkey } 510b6a7f2cd05f8c507dfac684aa4c693088e8c01c7Jeff Sharkey } 511761122118b2437aee3a44e9263b73766986c12b8Jeff Sharkey} 512