1e934ce6f8430f50d1d22bccd3b341b982f5541eeSteve McKay/* 2e934ce6f8430f50d1d22bccd3b341b982f5541eeSteve McKay * Copyright (C) 2015 The Android Open Source Project 3e934ce6f8430f50d1d22bccd3b341b982f5541eeSteve McKay * 4e934ce6f8430f50d1d22bccd3b341b982f5541eeSteve McKay * Licensed under the Apache License, Version 2.0 (the "License"); 5e934ce6f8430f50d1d22bccd3b341b982f5541eeSteve McKay * you may not use this file except in compliance with the License. 6e934ce6f8430f50d1d22bccd3b341b982f5541eeSteve McKay * You may obtain a copy of the License at 7e934ce6f8430f50d1d22bccd3b341b982f5541eeSteve McKay * 8e934ce6f8430f50d1d22bccd3b341b982f5541eeSteve McKay * http://www.apache.org/licenses/LICENSE-2.0 9e934ce6f8430f50d1d22bccd3b341b982f5541eeSteve McKay * 10e934ce6f8430f50d1d22bccd3b341b982f5541eeSteve McKay * Unless required by applicable law or agreed to in writing, software 11e934ce6f8430f50d1d22bccd3b341b982f5541eeSteve McKay * distributed under the License is distributed on an "AS IS" BASIS, 12e934ce6f8430f50d1d22bccd3b341b982f5541eeSteve McKay * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13e934ce6f8430f50d1d22bccd3b341b982f5541eeSteve McKay * See the License for the specific language governing permissions and 14e934ce6f8430f50d1d22bccd3b341b982f5541eeSteve McKay * limitations under the License. 15e934ce6f8430f50d1d22bccd3b341b982f5541eeSteve McKay */ 16e934ce6f8430f50d1d22bccd3b341b982f5541eeSteve McKay 17e934ce6f8430f50d1d22bccd3b341b982f5541eeSteve McKaypackage com.android.documentsui; 18e934ce6f8430f50d1d22bccd3b341b982f5541eeSteve McKay 19a7e923c57c30b72671191c924b9b4ccc9e9fcc40Steve McKayimport static com.android.documentsui.OperationDialogFragment.DIALOG_TYPE_UNKNOWN; 2083df8c072ddd01a5adc11da0869103c4645e6d76Steve McKayimport static com.android.documentsui.Shared.DEBUG; 21d0d9afc5782fdadcdbb52e91da77188929dbedbdSteve McKay 22e934ce6f8430f50d1d22bccd3b341b982f5541eeSteve McKayimport android.app.Activity; 23e934ce6f8430f50d1d22bccd3b341b982f5541eeSteve McKayimport android.app.FragmentManager; 24e934ce6f8430f50d1d22bccd3b341b982f5541eeSteve McKayimport android.content.ActivityNotFoundException; 25e934ce6f8430f50d1d22bccd3b341b982f5541eeSteve McKayimport android.content.ClipData; 26e934ce6f8430f50d1d22bccd3b341b982f5541eeSteve McKayimport android.content.ContentResolver; 27e934ce6f8430f50d1d22bccd3b341b982f5541eeSteve McKayimport android.content.ContentValues; 28e934ce6f8430f50d1d22bccd3b341b982f5541eeSteve McKayimport android.content.Intent; 29e934ce6f8430f50d1d22bccd3b341b982f5541eeSteve McKayimport android.net.Uri; 30e934ce6f8430f50d1d22bccd3b341b982f5541eeSteve McKayimport android.os.Bundle; 31323ee3ec094b78b9f96a8ab55b5c3b291028eeafSteve McKayimport android.os.Parcelable; 32323ee3ec094b78b9f96a8ab55b5c3b291028eeafSteve McKayimport android.provider.DocumentsContract; 3394b486d32c10d5ffbd8627977ca4759c246ecf4bBen Kwaimport android.support.design.widget.Snackbar; 34e934ce6f8430f50d1d22bccd3b341b982f5541eeSteve McKayimport android.util.Log; 353da8afcf30337656601e9fc57f0823b4afd17afaSteve McKayimport android.view.KeyEvent; 36e934ce6f8430f50d1d22bccd3b341b982f5541eeSteve McKayimport android.view.Menu; 37e934ce6f8430f50d1d22bccd3b341b982f5541eeSteve McKayimport android.view.MenuItem; 38e934ce6f8430f50d1d22bccd3b341b982f5541eeSteve McKay 39a7e923c57c30b72671191c924b9b4ccc9e9fcc40Steve McKayimport com.android.documentsui.OperationDialogFragment.DialogType; 40e934ce6f8430f50d1d22bccd3b341b982f5541eeSteve McKayimport com.android.documentsui.RecentsProvider.ResumeColumns; 41ce71082254b6015ff6475374bc4d0001608b7636Steve McKayimport com.android.documentsui.dirlist.AnimationView; 42f862155e3476f8d9644d57072a6d92375bde628eSteve McKayimport com.android.documentsui.dirlist.DirectoryFragment; 433d988a969f39ca34ef89c449a0675164499c9a3aTomasz Mikolajewskiimport com.android.documentsui.dirlist.Model; 44e934ce6f8430f50d1d22bccd3b341b982f5541eeSteve McKayimport com.android.documentsui.model.DocumentInfo; 45e934ce6f8430f50d1d22bccd3b341b982f5541eeSteve McKayimport com.android.documentsui.model.DocumentStack; 46e934ce6f8430f50d1d22bccd3b341b982f5541eeSteve McKayimport com.android.documentsui.model.DurableUtils; 47e934ce6f8430f50d1d22bccd3b341b982f5541eeSteve McKayimport com.android.documentsui.model.RootInfo; 4814e827a958f713d9cdec550e0b1099622cda9479Steve McKayimport com.android.documentsui.services.FileOperationService; 49e934ce6f8430f50d1d22bccd3b341b982f5541eeSteve McKay 50a6120da1e37a4457bac58f8900bffa795dc8e7cbTomasz Mikolajewskiimport java.io.FileNotFoundException; 5161686593fd32babb6e86754ea5bfa6bc95cd3690Tomasz Mikolajewskiimport java.util.ArrayList; 52e934ce6f8430f50d1d22bccd3b341b982f5541eeSteve McKayimport java.util.Arrays; 53a6120da1e37a4457bac58f8900bffa795dc8e7cbTomasz Mikolajewskiimport java.util.Collection; 54e934ce6f8430f50d1d22bccd3b341b982f5541eeSteve McKayimport java.util.List; 55e934ce6f8430f50d1d22bccd3b341b982f5541eeSteve McKay 56ef3e2cf35fbede340d5ff830b410baea8e461a94Steve McKay/** 57273103b192d66375d560f98f3f099e8ff21d0607Steve McKay * Standalone file management activity. 58ef3e2cf35fbede340d5ff830b410baea8e461a94Steve McKay */ 5912055474a7f7119d3b44955e09358b9675167716Steve McKaypublic class FilesActivity extends BaseActivity { 60c78bcb8c7fa5db1726541c2c8bf8d4edfa0f1229Steve McKay 610f7078f0045f354ba6573f0094e097a9afd6534dBen Kwa public static final String TAG = "FilesActivity"; 62e934ce6f8430f50d1d22bccd3b341b982f5541eeSteve McKay 63c95d87c98360e4254c55272c79f0f9a05215aaf6Steve McKay // See comments where this const is referenced for details. 64c95d87c98360e4254c55272c79f0f9a05215aaf6Steve McKay private static final int DRAWER_NO_FIDDLE_DELAY = 1500; 65c95d87c98360e4254c55272c79f0f9a05215aaf6Steve McKay 66c95d87c98360e4254c55272c79f0f9a05215aaf6Steve McKay // Track the time we opened the drawer in response to back being pressed. 67c95d87c98360e4254c55272c79f0f9a05215aaf6Steve McKay // We use the time gap to figure out whether to close app or reopen the drawer. 68c95d87c98360e4254c55272c79f0f9a05215aaf6Steve McKay private long mDrawerLastFiddled; 69bdbd0ffdf2d5ee039c7a8ac58962276206467cb5Steve McKay private DocumentClipper mClipper; 70ef3e2cf35fbede340d5ff830b410baea8e461a94Steve McKay 7112055474a7f7119d3b44955e09358b9675167716Steve McKay public FilesActivity() { 7212055474a7f7119d3b44955e09358b9675167716Steve McKay super(R.layout.files_activity, TAG); 73ef3e2cf35fbede340d5ff830b410baea8e461a94Steve McKay } 74e934ce6f8430f50d1d22bccd3b341b982f5541eeSteve McKay 75e934ce6f8430f50d1d22bccd3b341b982f5541eeSteve McKay @Override 76e934ce6f8430f50d1d22bccd3b341b982f5541eeSteve McKay public void onCreate(Bundle icicle) { 77e934ce6f8430f50d1d22bccd3b341b982f5541eeSteve McKay super.onCreate(icicle); 78e934ce6f8430f50d1d22bccd3b341b982f5541eeSteve McKay 7912055474a7f7119d3b44955e09358b9675167716Steve McKay mClipper = new DocumentClipper(this); 80bdbd0ffdf2d5ee039c7a8ac58962276206467cb5Steve McKay 81e934ce6f8430f50d1d22bccd3b341b982f5541eeSteve McKay RootsFragment.show(getFragmentManager(), null); 8283df8c072ddd01a5adc11da0869103c4645e6d76Steve McKay 83aa684454f8e55fdba7829c7177799c0e8237d208Tomasz Mikolajewski final Intent intent = getIntent(); 84aa684454f8e55fdba7829c7177799c0e8237d208Tomasz Mikolajewski final Uri uri = intent.getData(); 85aa684454f8e55fdba7829c7177799c0e8237d208Tomasz Mikolajewski 86323ee3ec094b78b9f96a8ab55b5c3b291028eeafSteve McKay if (mState.restored) { 87aa684454f8e55fdba7829c7177799c0e8237d208Tomasz Mikolajewski if (DEBUG) Log.d(TAG, "Stack already resolved for uri: " + intent.getData()); 88aa684454f8e55fdba7829c7177799c0e8237d208Tomasz Mikolajewski } else if (!mState.stack.isEmpty()) { 893c6d499858d42cf3007ceaf029068cc7cdc05b8dSteve McKay // If a non-empty stack is present in our state, it was read (presumably) 90323ee3ec094b78b9f96a8ab55b5c3b291028eeafSteve McKay // from EXTRA_STACK intent extra. In this case, we'll skip other means of 913c6d499858d42cf3007ceaf029068cc7cdc05b8dSteve McKay // loading or restoring the stack (like URI). 92aa684454f8e55fdba7829c7177799c0e8237d208Tomasz Mikolajewski // 933c6d499858d42cf3007ceaf029068cc7cdc05b8dSteve McKay // When restoring from a stack, if a URI is present, it should only ever be: 943c6d499858d42cf3007ceaf029068cc7cdc05b8dSteve McKay // -- a launch URI: Launch URIs support sensible activity management, 953c6d499858d42cf3007ceaf029068cc7cdc05b8dSteve McKay // but don't specify a real content target) 963c6d499858d42cf3007ceaf029068cc7cdc05b8dSteve McKay // -- a fake Uri from notifications. These URIs have no authority (TODO: details). 973c6d499858d42cf3007ceaf029068cc7cdc05b8dSteve McKay // 983c6d499858d42cf3007ceaf029068cc7cdc05b8dSteve McKay // Any other URI is *sorta* unexpected...except when browsing an archive 993c6d499858d42cf3007ceaf029068cc7cdc05b8dSteve McKay // in downloads. 1003c6d499858d42cf3007ceaf029068cc7cdc05b8dSteve McKay if(uri != null 1013c6d499858d42cf3007ceaf029068cc7cdc05b8dSteve McKay && uri.getAuthority() != null 1023c6d499858d42cf3007ceaf029068cc7cdc05b8dSteve McKay && !uri.equals(mState.stack.peek()) 1033c6d499858d42cf3007ceaf029068cc7cdc05b8dSteve McKay && !LauncherActivity.isLaunchUri(uri)) { 1043c6d499858d42cf3007ceaf029068cc7cdc05b8dSteve McKay if (DEBUG) Log.w(TAG, 1053c6d499858d42cf3007ceaf029068cc7cdc05b8dSteve McKay "Launching with non-empty stack. Ignoring unexpected uri: " + uri); 1063c6d499858d42cf3007ceaf029068cc7cdc05b8dSteve McKay } else { 1073c6d499858d42cf3007ceaf029068cc7cdc05b8dSteve McKay if (DEBUG) Log.d(TAG, "Launching with non-empty stack."); 1083c6d499858d42cf3007ceaf029068cc7cdc05b8dSteve McKay } 109ce71082254b6015ff6475374bc4d0001608b7636Steve McKay refreshCurrentRootAndDirectory(AnimationView.ANIM_NONE); 1108fa99701491dee0ac18b8707e32252cb3c621af1Tomasz Mikolajewski } else if (Intent.ACTION_VIEW.equals(intent.getAction())) { 111a1f7680f535a30aa816d129c072870031c8a2eb6Steve McKay assert(uri != null); 11295cd85ad3859991c756c8ff9bb683c97b3546eb9Steve McKay new OpenUriForViewTask(this).executeOnExecutor( 113a6120da1e37a4457bac58f8900bffa795dc8e7cbTomasz Mikolajewski ProviderExecutor.forAuthority(uri.getAuthority()), uri); 114aa684454f8e55fdba7829c7177799c0e8237d208Tomasz Mikolajewski } else if (DocumentsContract.isRootUri(this, uri)) { 115aa684454f8e55fdba7829c7177799c0e8237d208Tomasz Mikolajewski if (DEBUG) Log.d(TAG, "Launching with root URI."); 116aa684454f8e55fdba7829c7177799c0e8237d208Tomasz Mikolajewski // If we've got a specific root to display, restore that root using a dedicated 117aa684454f8e55fdba7829c7177799c0e8237d208Tomasz Mikolajewski // authority. That way a misbehaving provider won't result in an ANR. 118c95d87c98360e4254c55272c79f0f9a05215aaf6Steve McKay loadRoot(uri); 119aa684454f8e55fdba7829c7177799c0e8237d208Tomasz Mikolajewski } else { 1206ce903d7b777ff5b668122a65d10da1d7d04373dSteve McKay if (DEBUG) Log.d(TAG, "All other means skipped. Launching into default directory."); 1214e627169041376b25fc5d9d62de0eccfa61b2913Aga Wronska loadRoot(getDefaultRoot()); 122aa684454f8e55fdba7829c7177799c0e8237d208Tomasz Mikolajewski } 123aa684454f8e55fdba7829c7177799c0e8237d208Tomasz Mikolajewski 124748ea8cc785b6f037518703308ffd3eb2a151c5aTomasz Mikolajewski final @DialogType int dialogType = intent.getIntExtra( 125748ea8cc785b6f037518703308ffd3eb2a151c5aTomasz Mikolajewski FileOperationService.EXTRA_DIALOG_TYPE, DIALOG_TYPE_UNKNOWN); 126aa684454f8e55fdba7829c7177799c0e8237d208Tomasz Mikolajewski // DialogFragment takes care of restoring the dialog on configuration change. 127aa684454f8e55fdba7829c7177799c0e8237d208Tomasz Mikolajewski // Only show it manually for the first time (icicle is null). 128748ea8cc785b6f037518703308ffd3eb2a151c5aTomasz Mikolajewski if (icicle == null && dialogType != DIALOG_TYPE_UNKNOWN) { 129748ea8cc785b6f037518703308ffd3eb2a151c5aTomasz Mikolajewski final int opType = intent.getIntExtra( 130748ea8cc785b6f037518703308ffd3eb2a151c5aTomasz Mikolajewski FileOperationService.EXTRA_OPERATION, 131748ea8cc785b6f037518703308ffd3eb2a151c5aTomasz Mikolajewski FileOperationService.OPERATION_COPY); 132748ea8cc785b6f037518703308ffd3eb2a151c5aTomasz Mikolajewski final ArrayList<DocumentInfo> srcList = 13314e827a958f713d9cdec550e0b1099622cda9479Steve McKay intent.getParcelableArrayListExtra(FileOperationService.EXTRA_SRC_LIST); 134748ea8cc785b6f037518703308ffd3eb2a151c5aTomasz Mikolajewski OperationDialogFragment.show( 135aa684454f8e55fdba7829c7177799c0e8237d208Tomasz Mikolajewski getFragmentManager(), 136748ea8cc785b6f037518703308ffd3eb2a151c5aTomasz Mikolajewski dialogType, 137748ea8cc785b6f037518703308ffd3eb2a151c5aTomasz Mikolajewski srcList, 138aa684454f8e55fdba7829c7177799c0e8237d208Tomasz Mikolajewski mState.stack, 13914e827a958f713d9cdec550e0b1099622cda9479Steve McKay opType); 140e934ce6f8430f50d1d22bccd3b341b982f5541eeSteve McKay } 141e934ce6f8430f50d1d22bccd3b341b982f5541eeSteve McKay } 142e934ce6f8430f50d1d22bccd3b341b982f5541eeSteve McKay 14312055474a7f7119d3b44955e09358b9675167716Steve McKay @Override 14495cd85ad3859991c756c8ff9bb683c97b3546eb9Steve McKay void includeState(State state) { 145e934ce6f8430f50d1d22bccd3b341b982f5541eeSteve McKay final Intent intent = getIntent(); 1460f7078f0045f354ba6573f0094e097a9afd6534dBen Kwa 14783df8c072ddd01a5adc11da0869103c4645e6d76Steve McKay state.action = State.ACTION_BROWSE; 1480f7078f0045f354ba6573f0094e097a9afd6534dBen Kwa state.allowMultiple = true; 149273103b192d66375d560f98f3f099e8ff21d0607Steve McKay 15083df8c072ddd01a5adc11da0869103c4645e6d76Steve McKay // Options specific to the DocumentsActivity. 151a1f7680f535a30aa816d129c072870031c8a2eb6Steve McKay assert(!intent.hasExtra(Intent.EXTRA_LOCAL_ONLY)); 152273103b192d66375d560f98f3f099e8ff21d0607Steve McKay 153323ee3ec094b78b9f96a8ab55b5c3b291028eeafSteve McKay final DocumentStack stack = intent.getParcelableExtra(Shared.EXTRA_STACK); 15483df8c072ddd01a5adc11da0869103c4645e6d76Steve McKay if (stack != null) { 155ef3e2cf35fbede340d5ff830b410baea8e461a94Steve McKay state.stack = stack; 15683df8c072ddd01a5adc11da0869103c4645e6d76Steve McKay } 157e934ce6f8430f50d1d22bccd3b341b982f5541eeSteve McKay } 158e934ce6f8430f50d1d22bccd3b341b982f5541eeSteve McKay 159e934ce6f8430f50d1d22bccd3b341b982f5541eeSteve McKay @Override 160e934ce6f8430f50d1d22bccd3b341b982f5541eeSteve McKay protected void onPostCreate(Bundle savedInstanceState) { 161e934ce6f8430f50d1d22bccd3b341b982f5541eeSteve McKay super.onPostCreate(savedInstanceState); 162b67bfbf975a453a67300f24fac6e4687a676a378Steve McKay // This check avoids a flicker from "Recents" to "Home". 163b67bfbf975a453a67300f24fac6e4687a676a378Steve McKay // Only update action bar at this point if there is an active 164b67bfbf975a453a67300f24fac6e4687a676a378Steve McKay // serach. Why? Because this avoid an early (undesired) load of 165b67bfbf975a453a67300f24fac6e4687a676a378Steve McKay // the recents root...which is the default root in other activities. 166b67bfbf975a453a67300f24fac6e4687a676a378Steve McKay // In Files app "Home" is the default, but it is loaded async. 1671f264a8a1a6c3e770e45c52fc08dc06de6b1aa55Steve McKay // update will be called once Home root is loaded. 168b67bfbf975a453a67300f24fac6e4687a676a378Steve McKay // Except while searching we need this call to ensure the 169b67bfbf975a453a67300f24fac6e4687a676a378Steve McKay // search bits get layed out correctly. 170b67bfbf975a453a67300f24fac6e4687a676a378Steve McKay if (mSearchManager.isSearching()) { 1711f264a8a1a6c3e770e45c52fc08dc06de6b1aa55Steve McKay mNavigator.update(); 172b67bfbf975a453a67300f24fac6e4687a676a378Steve McKay } 173e934ce6f8430f50d1d22bccd3b341b982f5541eeSteve McKay } 174e934ce6f8430f50d1d22bccd3b341b982f5541eeSteve McKay 175e934ce6f8430f50d1d22bccd3b341b982f5541eeSteve McKay @Override 17683df8c072ddd01a5adc11da0869103c4645e6d76Steve McKay public void onResume() { 17783df8c072ddd01a5adc11da0869103c4645e6d76Steve McKay super.onResume(); 17883df8c072ddd01a5adc11da0869103c4645e6d76Steve McKay 17983df8c072ddd01a5adc11da0869103c4645e6d76Steve McKay final RootInfo root = getCurrentRoot(); 18083df8c072ddd01a5adc11da0869103c4645e6d76Steve McKay 18183df8c072ddd01a5adc11da0869103c4645e6d76Steve McKay // If we're browsing a specific root, and that root went away, then we 18283df8c072ddd01a5adc11da0869103c4645e6d76Steve McKay // have no reason to hang around. 18383df8c072ddd01a5adc11da0869103c4645e6d76Steve McKay // TODO: Rather than just disappearing, maybe we should inform 18483df8c072ddd01a5adc11da0869103c4645e6d76Steve McKay // the user what has happened, let them close us. Less surprising. 18583df8c072ddd01a5adc11da0869103c4645e6d76Steve McKay if (mRoots.getRootBlocking(root.authority, root.rootId) == null) { 18683df8c072ddd01a5adc11da0869103c4645e6d76Steve McKay finish(); 18783df8c072ddd01a5adc11da0869103c4645e6d76Steve McKay } 18883df8c072ddd01a5adc11da0869103c4645e6d76Steve McKay } 18983df8c072ddd01a5adc11da0869103c4645e6d76Steve McKay 19083df8c072ddd01a5adc11da0869103c4645e6d76Steve McKay @Override 1911f264a8a1a6c3e770e45c52fc08dc06de6b1aa55Steve McKay public String getDrawerTitle() { 19253f109b39e2b62fa3730ce1c43344df2c733251cSteve McKay Intent intent = getIntent(); 19353f109b39e2b62fa3730ce1c43344df2c733251cSteve McKay return (intent != null && intent.hasExtra(Intent.EXTRA_TITLE)) 19453f109b39e2b62fa3730ce1c43344df2c733251cSteve McKay ? intent.getStringExtra(Intent.EXTRA_TITLE) 195ab58b5a3ddb7f0c477380e6bd91982e28a220d12Ben Lin : getString(R.string.downloads_label); 196e934ce6f8430f50d1d22bccd3b341b982f5541eeSteve McKay } 197e934ce6f8430f50d1d22bccd3b341b982f5541eeSteve McKay 198e934ce6f8430f50d1d22bccd3b341b982f5541eeSteve McKay @Override 199e934ce6f8430f50d1d22bccd3b341b982f5541eeSteve McKay public boolean onPrepareOptionsMenu(Menu menu) { 2005bbae10c4c603ec6597f8dc7e1c7d060877cefc9Steve McKay super.onPrepareOptionsMenu(menu); 2013ce95951bd173c422b8d369b4651c28e5bcc20f4Steve McKay 202efa1761776160376278fa467ea31d8e3f621a286Steve McKay final RootInfo root = getCurrentRoot(); 2039f9d5b432d6b87fe28a9f90f540b229d0f363538Steve McKay 204e934ce6f8430f50d1d22bccd3b341b982f5541eeSteve McKay final MenuItem createDir = menu.findItem(R.id.menu_create_dir); 2059f9d5b432d6b87fe28a9f90f540b229d0f363538Steve McKay final MenuItem pasteFromCb = menu.findItem(R.id.menu_paste_from_clipboard); 206efa1761776160376278fa467ea31d8e3f621a286Steve McKay final MenuItem settings = menu.findItem(R.id.menu_settings); 207f873769fba261fb26446b5082fddc4ca2724d931Steve McKay final MenuItem newWindow = menu.findItem(R.id.menu_new_window); 208e934ce6f8430f50d1d22bccd3b341b982f5541eeSteve McKay 2095bbae10c4c603ec6597f8dc7e1c7d060877cefc9Steve McKay createDir.setVisible(true); 2105bbae10c4c603ec6597f8dc7e1c7d060877cefc9Steve McKay createDir.setEnabled(canCreateDirectory()); 2115bbae10c4c603ec6597f8dc7e1c7d060877cefc9Steve McKay pasteFromCb.setEnabled(mClipper.hasItemsToPaste()); 212efa1761776160376278fa467ea31d8e3f621a286Steve McKay settings.setVisible(root.hasSettings()); 213f570c771f23792837fb63f708bfa5c948d5fcad7Steve McKay newWindow.setVisible(Shared.shouldShowFancyFeatures(this)); 2149f9d5b432d6b87fe28a9f90f540b229d0f363538Steve McKay 2155bbae10c4c603ec6597f8dc7e1c7d060877cefc9Steve McKay Menus.disableHiddenItems(menu, pasteFromCb); 216b09985639fd116a133cb0ec27abc6975b11b2eb6Aga Wronska // It hides icon if searching in progress 217b09985639fd116a133cb0ec27abc6975b11b2eb6Aga Wronska mSearchManager.updateMenu(); 2185bbae10c4c603ec6597f8dc7e1c7d060877cefc9Steve McKay return true; 219e934ce6f8430f50d1d22bccd3b341b982f5541eeSteve McKay } 220e934ce6f8430f50d1d22bccd3b341b982f5541eeSteve McKay 221e934ce6f8430f50d1d22bccd3b341b982f5541eeSteve McKay @Override 222bdbd0ffdf2d5ee039c7a8ac58962276206467cb5Steve McKay public boolean onOptionsItemSelected(MenuItem item) { 2239f9d5b432d6b87fe28a9f90f540b229d0f363538Steve McKay switch (item.getItemId()) { 2249f9d5b432d6b87fe28a9f90f540b229d0f363538Steve McKay case R.id.menu_create_dir: 225a1f7680f535a30aa816d129c072870031c8a2eb6Steve McKay assert(canCreateDirectory()); 2269f9d5b432d6b87fe28a9f90f540b229d0f363538Steve McKay showCreateDirectoryDialog(); 227cf966ae5b5647e1a24bfb0220ed0dea5edd87ae8Aga Wronska break; 2289f9d5b432d6b87fe28a9f90f540b229d0f363538Steve McKay case R.id.menu_new_window: 229323ee3ec094b78b9f96a8ab55b5c3b291028eeafSteve McKay createNewWindow(); 230cf966ae5b5647e1a24bfb0220ed0dea5edd87ae8Aga Wronska break; 2319f9d5b432d6b87fe28a9f90f540b229d0f363538Steve McKay case R.id.menu_paste_from_clipboard: 2323ce95951bd173c422b8d369b4651c28e5bcc20f4Steve McKay DirectoryFragment dir = getDirectoryFragment(); 2333ce95951bd173c422b8d369b4651c28e5bcc20f4Steve McKay if (dir != null) { 2343ce95951bd173c422b8d369b4651c28e5bcc20f4Steve McKay dir.pasteFromClipboard(); 2353ce95951bd173c422b8d369b4651c28e5bcc20f4Steve McKay } 236cf966ae5b5647e1a24bfb0220ed0dea5edd87ae8Aga Wronska break; 237cf966ae5b5647e1a24bfb0220ed0dea5edd87ae8Aga Wronska default: 238cf966ae5b5647e1a24bfb0220ed0dea5edd87ae8Aga Wronska return super.onOptionsItemSelected(item); 239bdbd0ffdf2d5ee039c7a8ac58962276206467cb5Steve McKay } 240cf966ae5b5647e1a24bfb0220ed0dea5edd87ae8Aga Wronska return true; 241bdbd0ffdf2d5ee039c7a8ac58962276206467cb5Steve McKay } 242bdbd0ffdf2d5ee039c7a8ac58962276206467cb5Steve McKay 243323ee3ec094b78b9f96a8ab55b5c3b291028eeafSteve McKay private void createNewWindow() { 24443df577ac46e36f21da3797d6f31a5ae6fa58c9fAga Wronska Metrics.logUserAction(this, Metrics.USER_ACTION_NEW_WINDOW); 24543df577ac46e36f21da3797d6f31a5ae6fa58c9fAga Wronska 246323ee3ec094b78b9f96a8ab55b5c3b291028eeafSteve McKay Intent intent = LauncherActivity.createLaunchIntent(this); 247323ee3ec094b78b9f96a8ab55b5c3b291028eeafSteve McKay intent.putExtra(Shared.EXTRA_STACK, (Parcelable) mState.stack); 248a7e923c57c30b72671191c924b9b4ccc9e9fcc40Steve McKay 249a7e923c57c30b72671191c924b9b4ccc9e9fcc40Steve McKay // With new multi-window mode we have to pick how we are launched. 250a7e923c57c30b72671191c924b9b4ccc9e9fcc40Steve McKay // By default we'd be launched in-place above the existing app. 251a7e923c57c30b72671191c924b9b4ccc9e9fcc40Steve McKay // By setting launch-to-side ActivityManager will open us to side. 252933076d80561751618f462b26309ce9e4c3ff3bfAndrii Kulian if (isInMultiWindowMode()) { 2532a25a62739bca2f93aa91fbba698a6de697032b2Wale Ogunwale intent.addFlags(Intent.FLAG_ACTIVITY_LAUNCH_ADJACENT); 254a7e923c57c30b72671191c924b9b4ccc9e9fcc40Steve McKay } 255a7e923c57c30b72671191c924b9b4ccc9e9fcc40Steve McKay 256323ee3ec094b78b9f96a8ab55b5c3b291028eeafSteve McKay startActivity(intent); 257323ee3ec094b78b9f96a8ab55b5c3b291028eeafSteve McKay } 258323ee3ec094b78b9f96a8ab55b5c3b291028eeafSteve McKay 259bdbd0ffdf2d5ee039c7a8ac58962276206467cb5Steve McKay @Override 260f6a31d319f3e08d26ca4c0fbfb5803056bafb243Aga Wronska void refreshDirectory(int anim) { 261e934ce6f8430f50d1d22bccd3b341b982f5541eeSteve McKay final FragmentManager fm = getFragmentManager(); 262e934ce6f8430f50d1d22bccd3b341b982f5541eeSteve McKay final RootInfo root = getCurrentRoot(); 263e934ce6f8430f50d1d22bccd3b341b982f5541eeSteve McKay final DocumentInfo cwd = getCurrentDirectory(); 264e934ce6f8430f50d1d22bccd3b341b982f5541eeSteve McKay 265a1f7680f535a30aa816d129c072870031c8a2eb6Steve McKay assert(!mSearchManager.isSearching()); 266893390bd580eca39ecd693cb0d76c7bc9b36a11dAga Wronska 267e934ce6f8430f50d1d22bccd3b341b982f5541eeSteve McKay if (cwd == null) { 268e934ce6f8430f50d1d22bccd3b341b982f5541eeSteve McKay DirectoryFragment.showRecentsOpen(fm, anim); 269e934ce6f8430f50d1d22bccd3b341b982f5541eeSteve McKay } else { 270893390bd580eca39ecd693cb0d76c7bc9b36a11dAga Wronska // Normal boring directory 271893390bd580eca39ecd693cb0d76c7bc9b36a11dAga Wronska DirectoryFragment.showDirectory(fm, root, cwd, anim); 272e934ce6f8430f50d1d22bccd3b341b982f5541eeSteve McKay } 273e934ce6f8430f50d1d22bccd3b341b982f5541eeSteve McKay } 274e934ce6f8430f50d1d22bccd3b341b982f5541eeSteve McKay 275e934ce6f8430f50d1d22bccd3b341b982f5541eeSteve McKay @Override 2764f1604088f11f6c5583d1148c34bc6a45e5c619fSteve McKay void onRootPicked(RootInfo root) { 2774f1604088f11f6c5583d1148c34bc6a45e5c619fSteve McKay super.onRootPicked(root); 2784f1604088f11f6c5583d1148c34bc6a45e5c619fSteve McKay mDrawer.setOpen(false); 2794f1604088f11f6c5583d1148c34bc6a45e5c619fSteve McKay } 2804f1604088f11f6c5583d1148c34bc6a45e5c619fSteve McKay 2814f1604088f11f6c5583d1148c34bc6a45e5c619fSteve McKay @Override 2826eaf3863c81779233c032b7f7fc5b90e94f5f70aSteve McKay public void onDocumentsPicked(List<DocumentInfo> docs) { 2836eaf3863c81779233c032b7f7fc5b90e94f5f70aSteve McKay throw new UnsupportedOperationException(); 2846eaf3863c81779233c032b7f7fc5b90e94f5f70aSteve McKay } 2856eaf3863c81779233c032b7f7fc5b90e94f5f70aSteve McKay 2866eaf3863c81779233c032b7f7fc5b90e94f5f70aSteve McKay @Override 2873d988a969f39ca34ef89c449a0675164499c9a3aTomasz Mikolajewski public void onDocumentPicked(DocumentInfo doc, Model model) { 2883e63e7de2378055857c329e80862a11d947852c4Steve McKay // Anything on downloads goes through the back through downloads manager 2893e63e7de2378055857c329e80862a11d947852c4Steve McKay // (that's the MANAGE_DOCUMENT bit). 2903e63e7de2378055857c329e80862a11d947852c4Steve McKay // This is done for two reasons: 2913e63e7de2378055857c329e80862a11d947852c4Steve McKay // 1) The file in question might be a failed/queued or otherwise have some 2923e63e7de2378055857c329e80862a11d947852c4Steve McKay // specialized download handling. 2933e63e7de2378055857c329e80862a11d947852c4Steve McKay // 2) For APKs, the download manager will add on some important security stuff 2943e63e7de2378055857c329e80862a11d947852c4Steve McKay // like origin URL. 2953e63e7de2378055857c329e80862a11d947852c4Steve McKay // All other files not on downloads, event APKs, would get no benefit from this 2963e63e7de2378055857c329e80862a11d947852c4Steve McKay // treatment, thusly the "isDownloads" check. 2978fa99701491dee0ac18b8707e32252cb3c621af1Tomasz Mikolajewski 2988fa99701491dee0ac18b8707e32252cb3c621af1Tomasz Mikolajewski // Launch MANAGE_DOCUMENTS only for the root level files, so it's not called for 2998fa99701491dee0ac18b8707e32252cb3c621af1Tomasz Mikolajewski // files in archives. Also, if the activity is already browsing a ZIP from downloads, 3008fa99701491dee0ac18b8707e32252cb3c621af1Tomasz Mikolajewski // then skip MANAGE_DOCUMENTS. 3018fa99701491dee0ac18b8707e32252cb3c621af1Tomasz Mikolajewski final boolean isViewing = Intent.ACTION_VIEW.equals(getIntent().getAction()); 3028fa99701491dee0ac18b8707e32252cb3c621af1Tomasz Mikolajewski final boolean isInArchive = mState.stack.size() > 1; 3038fa99701491dee0ac18b8707e32252cb3c621af1Tomasz Mikolajewski if (getCurrentRoot().isDownloads() && !isInArchive && !isViewing) { 3049bb98f3121e7efa2b232613f89bef99a80d07269Steve McKay // First try managing the document; we expect manager to filter 3059bb98f3121e7efa2b232613f89bef99a80d07269Steve McKay // based on authority, so we don't grant. 3069bb98f3121e7efa2b232613f89bef99a80d07269Steve McKay final Intent manage = new Intent(DocumentsContract.ACTION_MANAGE_DOCUMENT); 3079bb98f3121e7efa2b232613f89bef99a80d07269Steve McKay manage.setData(doc.derivedUri); 3089bb98f3121e7efa2b232613f89bef99a80d07269Steve McKay 3099bb98f3121e7efa2b232613f89bef99a80d07269Steve McKay try { 3109bb98f3121e7efa2b232613f89bef99a80d07269Steve McKay startActivity(manage); 3119bb98f3121e7efa2b232613f89bef99a80d07269Steve McKay return; 3129bb98f3121e7efa2b232613f89bef99a80d07269Steve McKay } catch (ActivityNotFoundException ex) { 3139bb98f3121e7efa2b232613f89bef99a80d07269Steve McKay // fall back to regular handling below. 3149bb98f3121e7efa2b232613f89bef99a80d07269Steve McKay } 3159bb98f3121e7efa2b232613f89bef99a80d07269Steve McKay } 3169bb98f3121e7efa2b232613f89bef99a80d07269Steve McKay 3178fa99701491dee0ac18b8707e32252cb3c621af1Tomasz Mikolajewski if (doc.isContainer()) { 3188fa99701491dee0ac18b8707e32252cb3c621af1Tomasz Mikolajewski openContainerDocument(doc); 3198fa99701491dee0ac18b8707e32252cb3c621af1Tomasz Mikolajewski } else { 3208fa99701491dee0ac18b8707e32252cb3c621af1Tomasz Mikolajewski openDocument(doc, model); 3218fa99701491dee0ac18b8707e32252cb3c621af1Tomasz Mikolajewski } 3228fa99701491dee0ac18b8707e32252cb3c621af1Tomasz Mikolajewski } 3238fa99701491dee0ac18b8707e32252cb3c621af1Tomasz Mikolajewski 3248fa99701491dee0ac18b8707e32252cb3c621af1Tomasz Mikolajewski /** 3258fa99701491dee0ac18b8707e32252cb3c621af1Tomasz Mikolajewski * Launches an intent to view the specified document. 3268fa99701491dee0ac18b8707e32252cb3c621af1Tomasz Mikolajewski */ 3278fa99701491dee0ac18b8707e32252cb3c621af1Tomasz Mikolajewski private void openDocument(DocumentInfo doc, Model model) { 3283d988a969f39ca34ef89c449a0675164499c9a3aTomasz Mikolajewski Intent intent = new QuickViewIntentBuilder( 3293d988a969f39ca34ef89c449a0675164499c9a3aTomasz Mikolajewski getPackageManager(), getResources(), doc, model).build(); 3306eaf3863c81779233c032b7f7fc5b90e94f5f70aSteve McKay 3313b2ad11fca93f07ab552ea41452e43168888833bSteve McKay if (intent != null) { 3323b2ad11fca93f07ab552ea41452e43168888833bSteve McKay // TODO: un-work around issue b/24963914. Should be fixed soon. 3333b2ad11fca93f07ab552ea41452e43168888833bSteve McKay try { 3343b2ad11fca93f07ab552ea41452e43168888833bSteve McKay startActivity(intent); 3353b2ad11fca93f07ab552ea41452e43168888833bSteve McKay return; 3363b2ad11fca93f07ab552ea41452e43168888833bSteve McKay } catch (SecurityException e) { 3371eafb666c24736be4454c199a62c256c55e86bc4Steve McKay // Carry on to regular view mode. 3383b2ad11fca93f07ab552ea41452e43168888833bSteve McKay Log.e(TAG, "Caught security error: " + e.getLocalizedMessage()); 3393b2ad11fca93f07ab552ea41452e43168888833bSteve McKay } 340e934ce6f8430f50d1d22bccd3b341b982f5541eeSteve McKay } 341c78bcb8c7fa5db1726541c2c8bf8d4edfa0f1229Steve McKay 3429bb98f3121e7efa2b232613f89bef99a80d07269Steve McKay // Fall back to traditional VIEW action... 3433b2ad11fca93f07ab552ea41452e43168888833bSteve McKay intent = new Intent(Intent.ACTION_VIEW); 3443f5885918b60824d98386f9c31b7dd189b7f426cSteve McKay intent.setDataAndType(doc.derivedUri, doc.mimeType); 3453f5885918b60824d98386f9c31b7dd189b7f426cSteve McKay 3463f5885918b60824d98386f9c31b7dd189b7f426cSteve McKay // Downloads has traditionally added the WRITE permission 3473f5885918b60824d98386f9c31b7dd189b7f426cSteve McKay // in the TrampolineActivity. Since this behavior is long 3483f5885918b60824d98386f9c31b7dd189b7f426cSteve McKay // established, we set the same permission for non-managed files 3493f5885918b60824d98386f9c31b7dd189b7f426cSteve McKay // This ensures consistent behavior between the Downloads root 3503f5885918b60824d98386f9c31b7dd189b7f426cSteve McKay // and other roots. 3513f5885918b60824d98386f9c31b7dd189b7f426cSteve McKay int flags = Intent.FLAG_GRANT_READ_URI_PERMISSION; 3523f5885918b60824d98386f9c31b7dd189b7f426cSteve McKay if (doc.isWriteSupported()) { 3533f5885918b60824d98386f9c31b7dd189b7f426cSteve McKay flags |= Intent.FLAG_GRANT_WRITE_URI_PERMISSION; 3543f5885918b60824d98386f9c31b7dd189b7f426cSteve McKay } 3553f5885918b60824d98386f9c31b7dd189b7f426cSteve McKay intent.setFlags(flags); 3563b2ad11fca93f07ab552ea41452e43168888833bSteve McKay 3576eaf3863c81779233c032b7f7fc5b90e94f5f70aSteve McKay if (DEBUG && intent.getClipData() != null) { 3586eaf3863c81779233c032b7f7fc5b90e94f5f70aSteve McKay Log.d(TAG, "Starting intent w/ clip data: " + intent.getClipData()); 3596eaf3863c81779233c032b7f7fc5b90e94f5f70aSteve McKay } 3606eaf3863c81779233c032b7f7fc5b90e94f5f70aSteve McKay 361c78bcb8c7fa5db1726541c2c8bf8d4edfa0f1229Steve McKay try { 362c78bcb8c7fa5db1726541c2c8bf8d4edfa0f1229Steve McKay startActivity(intent); 3633b2ad11fca93f07ab552ea41452e43168888833bSteve McKay } catch (ActivityNotFoundException e) { 3643b2ad11fca93f07ab552ea41452e43168888833bSteve McKay Snackbars.makeSnackbar( 3653b2ad11fca93f07ab552ea41452e43168888833bSteve McKay this, R.string.toast_no_application, Snackbar.LENGTH_SHORT).show(); 366c78bcb8c7fa5db1726541c2c8bf8d4edfa0f1229Steve McKay } 367c78bcb8c7fa5db1726541c2c8bf8d4edfa0f1229Steve McKay } 368c78bcb8c7fa5db1726541c2c8bf8d4edfa0f1229Steve McKay 369e934ce6f8430f50d1d22bccd3b341b982f5541eeSteve McKay @Override 3703da8afcf30337656601e9fc57f0823b4afd17afaSteve McKay public boolean onKeyShortcut(int keyCode, KeyEvent event) { 3713da8afcf30337656601e9fc57f0823b4afd17afaSteve McKay DirectoryFragment dir; 3723ce95951bd173c422b8d369b4651c28e5bcc20f4Steve McKay // TODO: All key events should be statically bound using alphabeticShortcut. 3733ce95951bd173c422b8d369b4651c28e5bcc20f4Steve McKay // But not working. 3743da8afcf30337656601e9fc57f0823b4afd17afaSteve McKay switch (keyCode) { 3753da8afcf30337656601e9fc57f0823b4afd17afaSteve McKay case KeyEvent.KEYCODE_A: 3763ce95951bd173c422b8d369b4651c28e5bcc20f4Steve McKay dir = getDirectoryFragment(); 3773ce95951bd173c422b8d369b4651c28e5bcc20f4Steve McKay if (dir != null) { 3783ce95951bd173c422b8d369b4651c28e5bcc20f4Steve McKay dir.selectAllFiles(); 3793ce95951bd173c422b8d369b4651c28e5bcc20f4Steve McKay } 3803da8afcf30337656601e9fc57f0823b4afd17afaSteve McKay return true; 381bdbd0ffdf2d5ee039c7a8ac58962276206467cb5Steve McKay case KeyEvent.KEYCODE_C: 3823ce95951bd173c422b8d369b4651c28e5bcc20f4Steve McKay dir = getDirectoryFragment(); 3833ce95951bd173c422b8d369b4651c28e5bcc20f4Steve McKay if (dir != null) { 3843ce95951bd173c422b8d369b4651c28e5bcc20f4Steve McKay dir.copySelectedToClipboard(); 3853ce95951bd173c422b8d369b4651c28e5bcc20f4Steve McKay } 3868fd086a18d9c71590a66a86d91b7f7471621a08fSteve McKay return true; 3878fd086a18d9c71590a66a86d91b7f7471621a08fSteve McKay case KeyEvent.KEYCODE_V: 3883ce95951bd173c422b8d369b4651c28e5bcc20f4Steve McKay dir = getDirectoryFragment(); 3893ce95951bd173c422b8d369b4651c28e5bcc20f4Steve McKay if (dir != null) { 3903ce95951bd173c422b8d369b4651c28e5bcc20f4Steve McKay dir.pasteFromClipboard(); 3913ce95951bd173c422b8d369b4651c28e5bcc20f4Steve McKay } 3928fd086a18d9c71590a66a86d91b7f7471621a08fSteve McKay return true; 3938fd086a18d9c71590a66a86d91b7f7471621a08fSteve McKay default: 3948fd086a18d9c71590a66a86d91b7f7471621a08fSteve McKay return super.onKeyShortcut(keyCode, event); 3953da8afcf30337656601e9fc57f0823b4afd17afaSteve McKay } 3963da8afcf30337656601e9fc57f0823b4afd17afaSteve McKay } 3973da8afcf30337656601e9fc57f0823b4afd17afaSteve McKay 398c95d87c98360e4254c55272c79f0f9a05215aaf6Steve McKay // Do some "do what a I want" drawer fiddling, but don't 399c95d87c98360e4254c55272c79f0f9a05215aaf6Steve McKay // do it if user already hit back recently and we recently 400c95d87c98360e4254c55272c79f0f9a05215aaf6Steve McKay // did some fiddling. 401c95d87c98360e4254c55272c79f0f9a05215aaf6Steve McKay @Override 402c95d87c98360e4254c55272c79f0f9a05215aaf6Steve McKay boolean onBeforePopDir() { 403c95d87c98360e4254c55272c79f0f9a05215aaf6Steve McKay int size = mState.stack.size(); 404c95d87c98360e4254c55272c79f0f9a05215aaf6Steve McKay 405c95d87c98360e4254c55272c79f0f9a05215aaf6Steve McKay if (mDrawer.isPresent() 406c95d87c98360e4254c55272c79f0f9a05215aaf6Steve McKay && (System.currentTimeMillis() - mDrawerLastFiddled) > DRAWER_NO_FIDDLE_DELAY) { 407c95d87c98360e4254c55272c79f0f9a05215aaf6Steve McKay // Close drawer if it is open. 408c95d87c98360e4254c55272c79f0f9a05215aaf6Steve McKay if (mDrawer.isOpen()) { 409c95d87c98360e4254c55272c79f0f9a05215aaf6Steve McKay mDrawer.setOpen(false); 410c95d87c98360e4254c55272c79f0f9a05215aaf6Steve McKay mDrawerLastFiddled = System.currentTimeMillis(); 411c95d87c98360e4254c55272c79f0f9a05215aaf6Steve McKay return true; 412c95d87c98360e4254c55272c79f0f9a05215aaf6Steve McKay } 413c95d87c98360e4254c55272c79f0f9a05215aaf6Steve McKay 414c95d87c98360e4254c55272c79f0f9a05215aaf6Steve McKay // Open the Close drawer if it is closed and we're at the top of a root. 41596e30eba1eaed0e35d6b8cfcd504aed5475556d8Aga Wronska if (size <= 1) { 416c95d87c98360e4254c55272c79f0f9a05215aaf6Steve McKay mDrawer.setOpen(true); 417c95d87c98360e4254c55272c79f0f9a05215aaf6Steve McKay // Remember so we don't just close it again if back is pressed again. 418c95d87c98360e4254c55272c79f0f9a05215aaf6Steve McKay mDrawerLastFiddled = System.currentTimeMillis(); 419c95d87c98360e4254c55272c79f0f9a05215aaf6Steve McKay return true; 420c95d87c98360e4254c55272c79f0f9a05215aaf6Steve McKay } 421c95d87c98360e4254c55272c79f0f9a05215aaf6Steve McKay } 422c95d87c98360e4254c55272c79f0f9a05215aaf6Steve McKay 423c95d87c98360e4254c55272c79f0f9a05215aaf6Steve McKay return false; 424c95d87c98360e4254c55272c79f0f9a05215aaf6Steve McKay } 425c95d87c98360e4254c55272c79f0f9a05215aaf6Steve McKay 42695cd85ad3859991c756c8ff9bb683c97b3546eb9Steve McKay // Turns out only DocumentsActivity was ever calling saveStackBlocking. 42795cd85ad3859991c756c8ff9bb683c97b3546eb9Steve McKay // There may be a case where we want to contribute entries from 42895cd85ad3859991c756c8ff9bb683c97b3546eb9Steve McKay // Behavior here in FilesActivity, but it isn't yet obvious. 42995cd85ad3859991c756c8ff9bb683c97b3546eb9Steve McKay // TODO: Contribute to recents, or remove this. 43095cd85ad3859991c756c8ff9bb683c97b3546eb9Steve McKay void writeStackToRecentsBlocking() { 431e934ce6f8430f50d1d22bccd3b341b982f5541eeSteve McKay final ContentResolver resolver = getContentResolver(); 432e934ce6f8430f50d1d22bccd3b341b982f5541eeSteve McKay final ContentValues values = new ContentValues(); 433e934ce6f8430f50d1d22bccd3b341b982f5541eeSteve McKay 43495cd85ad3859991c756c8ff9bb683c97b3546eb9Steve McKay final byte[] rawStack = DurableUtils.writeToArrayOrNull(mState.stack); 435e934ce6f8430f50d1d22bccd3b341b982f5541eeSteve McKay 436e934ce6f8430f50d1d22bccd3b341b982f5541eeSteve McKay // Remember location for next app launch 437e934ce6f8430f50d1d22bccd3b341b982f5541eeSteve McKay final String packageName = getCallingPackageMaybeExtra(); 438e934ce6f8430f50d1d22bccd3b341b982f5541eeSteve McKay values.clear(); 439e934ce6f8430f50d1d22bccd3b341b982f5541eeSteve McKay values.put(ResumeColumns.STACK, rawStack); 440e934ce6f8430f50d1d22bccd3b341b982f5541eeSteve McKay values.put(ResumeColumns.EXTERNAL, 0); 441e934ce6f8430f50d1d22bccd3b341b982f5541eeSteve McKay resolver.insert(RecentsProvider.buildResume(packageName), values); 442e934ce6f8430f50d1d22bccd3b341b982f5541eeSteve McKay } 443e934ce6f8430f50d1d22bccd3b341b982f5541eeSteve McKay 444ef3e2cf35fbede340d5ff830b410baea8e461a94Steve McKay @Override 445ef3e2cf35fbede340d5ff830b410baea8e461a94Steve McKay void onTaskFinished(Uri... uris) { 446ffa829f779d7513c64bba76cc884c62b702f52ddBen Kwa if (DEBUG) Log.d(TAG, "onFinished() " + Arrays.toString(uris)); 447e934ce6f8430f50d1d22bccd3b341b982f5541eeSteve McKay 448e934ce6f8430f50d1d22bccd3b341b982f5541eeSteve McKay final Intent intent = new Intent(); 449e934ce6f8430f50d1d22bccd3b341b982f5541eeSteve McKay if (uris.length == 1) { 450e934ce6f8430f50d1d22bccd3b341b982f5541eeSteve McKay intent.setData(uris[0]); 451e934ce6f8430f50d1d22bccd3b341b982f5541eeSteve McKay } else if (uris.length > 1) { 452e934ce6f8430f50d1d22bccd3b341b982f5541eeSteve McKay final ClipData clipData = new ClipData( 453e934ce6f8430f50d1d22bccd3b341b982f5541eeSteve McKay null, mState.acceptMimes, new ClipData.Item(uris[0])); 454e934ce6f8430f50d1d22bccd3b341b982f5541eeSteve McKay for (int i = 1; i < uris.length; i++) { 455e934ce6f8430f50d1d22bccd3b341b982f5541eeSteve McKay clipData.addItem(new ClipData.Item(uris[i])); 456e934ce6f8430f50d1d22bccd3b341b982f5541eeSteve McKay } 457e934ce6f8430f50d1d22bccd3b341b982f5541eeSteve McKay intent.setClipData(clipData); 458e934ce6f8430f50d1d22bccd3b341b982f5541eeSteve McKay } 459e934ce6f8430f50d1d22bccd3b341b982f5541eeSteve McKay 460e934ce6f8430f50d1d22bccd3b341b982f5541eeSteve McKay intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION 461e934ce6f8430f50d1d22bccd3b341b982f5541eeSteve McKay | Intent.FLAG_GRANT_WRITE_URI_PERMISSION 462e934ce6f8430f50d1d22bccd3b341b982f5541eeSteve McKay | Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION); 463e934ce6f8430f50d1d22bccd3b341b982f5541eeSteve McKay 464e934ce6f8430f50d1d22bccd3b341b982f5541eeSteve McKay setResult(Activity.RESULT_OK, intent); 465e934ce6f8430f50d1d22bccd3b341b982f5541eeSteve McKay finish(); 466e934ce6f8430f50d1d22bccd3b341b982f5541eeSteve McKay } 467a6120da1e37a4457bac58f8900bffa795dc8e7cbTomasz Mikolajewski 468a6120da1e37a4457bac58f8900bffa795dc8e7cbTomasz Mikolajewski /** 469a6120da1e37a4457bac58f8900bffa795dc8e7cbTomasz Mikolajewski * Builds a stack for the specific Uris. Multi roots are not supported, as it's impossible 470a6120da1e37a4457bac58f8900bffa795dc8e7cbTomasz Mikolajewski * to know which root to select. Also, the stack doesn't contain intermediate directories. 471a6120da1e37a4457bac58f8900bffa795dc8e7cbTomasz Mikolajewski * It's primarly used for opening ZIP archives from Downloads app. 472a6120da1e37a4457bac58f8900bffa795dc8e7cbTomasz Mikolajewski */ 47395cd85ad3859991c756c8ff9bb683c97b3546eb9Steve McKay private static final class OpenUriForViewTask extends PairedTask<FilesActivity, Uri, Void> { 47495cd85ad3859991c756c8ff9bb683c97b3546eb9Steve McKay 47595cd85ad3859991c756c8ff9bb683c97b3546eb9Steve McKay private final State mState; 47695cd85ad3859991c756c8ff9bb683c97b3546eb9Steve McKay public OpenUriForViewTask(FilesActivity activity) { 47795cd85ad3859991c756c8ff9bb683c97b3546eb9Steve McKay super(activity); 47895cd85ad3859991c756c8ff9bb683c97b3546eb9Steve McKay mState = activity.mState; 47995cd85ad3859991c756c8ff9bb683c97b3546eb9Steve McKay } 48095cd85ad3859991c756c8ff9bb683c97b3546eb9Steve McKay 481a6120da1e37a4457bac58f8900bffa795dc8e7cbTomasz Mikolajewski @Override 48295cd85ad3859991c756c8ff9bb683c97b3546eb9Steve McKay protected Void run(Uri... params) { 483a6120da1e37a4457bac58f8900bffa795dc8e7cbTomasz Mikolajewski final Uri uri = params[0]; 484a6120da1e37a4457bac58f8900bffa795dc8e7cbTomasz Mikolajewski 48595cd85ad3859991c756c8ff9bb683c97b3546eb9Steve McKay final RootsCache rootsCache = DocumentsApplication.getRootsCache(mOwner); 486a6120da1e37a4457bac58f8900bffa795dc8e7cbTomasz Mikolajewski final String authority = uri.getAuthority(); 487a6120da1e37a4457bac58f8900bffa795dc8e7cbTomasz Mikolajewski 488a6120da1e37a4457bac58f8900bffa795dc8e7cbTomasz Mikolajewski final Collection<RootInfo> roots = 489a6120da1e37a4457bac58f8900bffa795dc8e7cbTomasz Mikolajewski rootsCache.getRootsForAuthorityBlocking(authority); 490a6120da1e37a4457bac58f8900bffa795dc8e7cbTomasz Mikolajewski if (roots.isEmpty()) { 491a6120da1e37a4457bac58f8900bffa795dc8e7cbTomasz Mikolajewski Log.e(TAG, "Failed to find root for the requested Uri: " + uri); 492a6120da1e37a4457bac58f8900bffa795dc8e7cbTomasz Mikolajewski return null; 493a6120da1e37a4457bac58f8900bffa795dc8e7cbTomasz Mikolajewski } 494a6120da1e37a4457bac58f8900bffa795dc8e7cbTomasz Mikolajewski 495a6120da1e37a4457bac58f8900bffa795dc8e7cbTomasz Mikolajewski final RootInfo root = roots.iterator().next(); 496a6120da1e37a4457bac58f8900bffa795dc8e7cbTomasz Mikolajewski mState.stack.root = root; 497a6120da1e37a4457bac58f8900bffa795dc8e7cbTomasz Mikolajewski try { 49895cd85ad3859991c756c8ff9bb683c97b3546eb9Steve McKay mState.stack.add(DocumentInfo.fromUri(mOwner.getContentResolver(), uri)); 499a6120da1e37a4457bac58f8900bffa795dc8e7cbTomasz Mikolajewski } catch (FileNotFoundException e) { 500a6120da1e37a4457bac58f8900bffa795dc8e7cbTomasz Mikolajewski Log.e(TAG, "Failed to resolve DocumentInfo from Uri: " + uri); 501a6120da1e37a4457bac58f8900bffa795dc8e7cbTomasz Mikolajewski } 50295cd85ad3859991c756c8ff9bb683c97b3546eb9Steve McKay mState.stack.add(mOwner.getRootDocumentBlocking(root)); 503a6120da1e37a4457bac58f8900bffa795dc8e7cbTomasz Mikolajewski return null; 504a6120da1e37a4457bac58f8900bffa795dc8e7cbTomasz Mikolajewski } 505a6120da1e37a4457bac58f8900bffa795dc8e7cbTomasz Mikolajewski 506a6120da1e37a4457bac58f8900bffa795dc8e7cbTomasz Mikolajewski @Override 50795cd85ad3859991c756c8ff9bb683c97b3546eb9Steve McKay protected void finish(Void result) { 508ce71082254b6015ff6475374bc4d0001608b7636Steve McKay mOwner.refreshCurrentRootAndDirectory(AnimationView.ANIM_NONE); 509a6120da1e37a4457bac58f8900bffa795dc8e7cbTomasz Mikolajewski } 510a6120da1e37a4457bac58f8900bffa795dc8e7cbTomasz Mikolajewski } 511e934ce6f8430f50d1d22bccd3b341b982f5541eeSteve McKay} 512