blob: 8b42ac5811b5a6ea7ea7be23c453cd0e3a923aa6 [file] [log] [blame]
Steve McKaye934ce62015-03-25 14:35:33 -07001/*
2 * Copyright (C) 2015 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.documentsui;
18
Steve McKaya7e923c2016-01-28 12:02:57 -080019import static com.android.documentsui.OperationDialogFragment.DIALOG_TYPE_UNKNOWN;
Steve McKay83df8c02015-09-16 15:07:31 -070020import static com.android.documentsui.Shared.DEBUG;
Steve McKayf8621552015-11-03 15:23:16 -080021import static com.android.documentsui.dirlist.DirectoryFragment.ANIM_NONE;
Steve McKay83df8c02015-09-16 15:07:31 -070022import static com.android.internal.util.Preconditions.checkArgument;
Steve McKay9f9d5b42015-09-23 15:44:24 -070023import static com.android.internal.util.Preconditions.checkState;
Steve McKayd0d9afc2015-05-06 12:16:40 -070024
Steve McKaye934ce62015-03-25 14:35:33 -070025import android.app.Activity;
Steve McKaye934ce62015-03-25 14:35:33 -070026import android.app.FragmentManager;
27import android.content.ActivityNotFoundException;
28import android.content.ClipData;
Steve McKaye934ce62015-03-25 14:35:33 -070029import android.content.ContentResolver;
30import android.content.ContentValues;
Steve McKaye934ce62015-03-25 14:35:33 -070031import android.content.Intent;
Steve McKaye934ce62015-03-25 14:35:33 -070032import android.net.Uri;
Steve McKaye934ce62015-03-25 14:35:33 -070033import android.os.Bundle;
Steve McKay323ee3e2015-09-25 16:02:56 -070034import android.os.Parcelable;
35import android.provider.DocumentsContract;
Ben Kwa94b486d2015-09-30 10:00:10 -070036import android.support.design.widget.Snackbar;
Steve McKaye934ce62015-03-25 14:35:33 -070037import android.util.Log;
Steve McKay3da8afc2015-05-05 14:50:00 -070038import android.view.KeyEvent;
Steve McKaye934ce62015-03-25 14:35:33 -070039import android.view.Menu;
40import android.view.MenuItem;
Steve McKaye934ce62015-03-25 14:35:33 -070041
Steve McKaya7e923c2016-01-28 12:02:57 -080042import com.android.documentsui.OperationDialogFragment.DialogType;
Steve McKaye934ce62015-03-25 14:35:33 -070043import com.android.documentsui.RecentsProvider.ResumeColumns;
Steve McKayf8621552015-11-03 15:23:16 -080044import com.android.documentsui.dirlist.DirectoryFragment;
Tomasz Mikolajewski3d988a92016-02-16 12:28:43 +090045import com.android.documentsui.dirlist.Model;
Steve McKaye934ce62015-03-25 14:35:33 -070046import com.android.documentsui.model.DocumentInfo;
47import com.android.documentsui.model.DocumentStack;
48import com.android.documentsui.model.DurableUtils;
49import com.android.documentsui.model.RootInfo;
Steve McKay14e827a2016-01-06 18:32:13 -080050import com.android.documentsui.services.FileOperationService;
Steve McKaye934ce62015-03-25 14:35:33 -070051
Tomasz Mikolajewskia6120da2016-01-27 17:36:51 +090052import java.io.FileNotFoundException;
Tomasz Mikolajewski61686592015-04-13 19:38:43 +090053import java.util.ArrayList;
Steve McKaye934ce62015-03-25 14:35:33 -070054import java.util.Arrays;
Tomasz Mikolajewskia6120da2016-01-27 17:36:51 +090055import java.util.Collection;
Steve McKaye934ce62015-03-25 14:35:33 -070056import java.util.List;
Steve McKaye934ce62015-03-25 14:35:33 -070057
Steve McKayef3e2cf2015-04-20 17:18:15 -070058/**
Steve McKay273103b2015-05-12 12:49:58 -070059 * Standalone file management activity.
Steve McKayef3e2cf2015-04-20 17:18:15 -070060 */
Steve McKay12055472015-08-20 16:48:49 -070061public class FilesActivity extends BaseActivity {
Steve McKayc78bcb82015-07-31 14:35:22 -070062
Ben Kwa0f7078f02015-09-08 07:31:19 -070063 public static final String TAG = "FilesActivity";
Steve McKaye934ce62015-03-25 14:35:33 -070064
Steve McKaybdbd0ff2015-05-20 15:58:42 -070065 private DocumentClipper mClipper;
Steve McKayef3e2cf2015-04-20 17:18:15 -070066
Steve McKay12055472015-08-20 16:48:49 -070067 public FilesActivity() {
68 super(R.layout.files_activity, TAG);
Steve McKayef3e2cf2015-04-20 17:18:15 -070069 }
Steve McKaye934ce62015-03-25 14:35:33 -070070
71 @Override
72 public void onCreate(Bundle icicle) {
Steve McKaye934ce62015-03-25 14:35:33 -070073 super.onCreate(icicle);
74
Steve McKay12055472015-08-20 16:48:49 -070075 mClipper = new DocumentClipper(this);
Steve McKaybdbd0ff2015-05-20 15:58:42 -070076
Steve McKaye934ce62015-03-25 14:35:33 -070077 RootsFragment.show(getFragmentManager(), null);
Steve McKay83df8c02015-09-16 15:07:31 -070078
Tomasz Mikolajewskiaa684452015-12-25 17:06:52 +090079 final Intent intent = getIntent();
80 final Uri uri = intent.getData();
Steve McKay323ee3e2015-09-25 16:02:56 -070081
Tomasz Mikolajewskiaa684452015-12-25 17:06:52 +090082 if (mState.restored) {
83 if (DEBUG) Log.d(TAG, "Stack already resolved for uri: " + intent.getData());
Tomasz Mikolajewskiaa684452015-12-25 17:06:52 +090084 } else if (!mState.stack.isEmpty()) {
Steve McKay323ee3e2015-09-25 16:02:56 -070085 // If a non-empty stack is present in our state it was read (presumably)
86 // from EXTRA_STACK intent extra. In this case, we'll skip other means of
87 // loading or restoring the stack.
Tomasz Mikolajewskiaa684452015-12-25 17:06:52 +090088 //
89 // When restoring from a stack, if a URI is present, it should only ever
Tomasz Mikolajewskicd270152016-02-01 12:01:14 +090090 // be a launch URI, or a fake Uri from notifications.
91 // Launch URIs support sensible activity management, but don't specify a real
92 // content target.
Tomasz Mikolajewskiaa684452015-12-25 17:06:52 +090093 if (DEBUG) Log.d(TAG, "Launching with non-empty stack.");
Tomasz Mikolajewskicd270152016-02-01 12:01:14 +090094 checkState(uri == null || uri.getAuthority() == null ||
95 LauncherActivity.isLaunchUri(uri));
Aga Wronskaf6a31d32016-01-15 17:30:15 -080096 refreshCurrentRootAndDirectory(ANIM_NONE);
Tomasz Mikolajewskia6120da2016-01-27 17:36:51 +090097 } else if (intent.getAction() == Intent.ACTION_VIEW) {
98 checkArgument(uri != null);
Steve McKay95cd85a2016-02-04 12:15:22 -080099 new OpenUriForViewTask(this).executeOnExecutor(
Tomasz Mikolajewskia6120da2016-01-27 17:36:51 +0900100 ProviderExecutor.forAuthority(uri.getAuthority()), uri);
Tomasz Mikolajewskiaa684452015-12-25 17:06:52 +0900101 } else if (DocumentsContract.isRootUri(this, uri)) {
102 if (DEBUG) Log.d(TAG, "Launching with root URI.");
103 // If we've got a specific root to display, restore that root using a dedicated
104 // authority. That way a misbehaving provider won't result in an ANR.
Steve McKay95cd85a2016-02-04 12:15:22 -0800105 new RestoreRootTask(this, uri).executeOnExecutor(
Tomasz Mikolajewskiaa684452015-12-25 17:06:52 +0900106 ProviderExecutor.forAuthority(uri.getAuthority()));
107 } else {
108 if (DEBUG) Log.d(TAG, "Launching into Home directory.");
109 // If all else fails, try to load "Home" directory.
110 final Uri homeUri = DocumentsContract.buildHomeUri();
Steve McKay95cd85a2016-02-04 12:15:22 -0800111 new RestoreRootTask(this, homeUri).executeOnExecutor(
Tomasz Mikolajewskiaa684452015-12-25 17:06:52 +0900112 ProviderExecutor.forAuthority(homeUri.getAuthority()));
113 }
Tomasz Mikolajewskif8c3f322015-04-14 16:32:41 +0900114
Tomasz Mikolajewski748ea8c2016-01-22 16:22:51 +0900115 final @DialogType int dialogType = intent.getIntExtra(
116 FileOperationService.EXTRA_DIALOG_TYPE, DIALOG_TYPE_UNKNOWN);
Tomasz Mikolajewskiaa684452015-12-25 17:06:52 +0900117 // DialogFragment takes care of restoring the dialog on configuration change.
118 // Only show it manually for the first time (icicle is null).
Tomasz Mikolajewski748ea8c2016-01-22 16:22:51 +0900119 if (icicle == null && dialogType != DIALOG_TYPE_UNKNOWN) {
120 final int opType = intent.getIntExtra(
121 FileOperationService.EXTRA_OPERATION,
122 FileOperationService.OPERATION_COPY);
123 final ArrayList<DocumentInfo> srcList =
Steve McKay14e827a2016-01-06 18:32:13 -0800124 intent.getParcelableArrayListExtra(FileOperationService.EXTRA_SRC_LIST);
Tomasz Mikolajewski748ea8c2016-01-22 16:22:51 +0900125 OperationDialogFragment.show(
Tomasz Mikolajewskiaa684452015-12-25 17:06:52 +0900126 getFragmentManager(),
Tomasz Mikolajewski748ea8c2016-01-22 16:22:51 +0900127 dialogType,
128 srcList,
Tomasz Mikolajewskiaa684452015-12-25 17:06:52 +0900129 mState.stack,
Steve McKay14e827a2016-01-06 18:32:13 -0800130 opType);
Steve McKaye934ce62015-03-25 14:35:33 -0700131 }
132 }
133
Steve McKay12055472015-08-20 16:48:49 -0700134 @Override
Steve McKay95cd85a2016-02-04 12:15:22 -0800135 void includeState(State state) {
Steve McKaye934ce62015-03-25 14:35:33 -0700136 final Intent intent = getIntent();
Ben Kwa0f7078f02015-09-08 07:31:19 -0700137
Steve McKay83df8c02015-09-16 15:07:31 -0700138 state.action = State.ACTION_BROWSE;
Ben Kwa0f7078f02015-09-08 07:31:19 -0700139 state.allowMultiple = true;
Steve McKay273103b2015-05-12 12:49:58 -0700140
Steve McKay83df8c02015-09-16 15:07:31 -0700141 // Options specific to the DocumentsActivity.
142 checkArgument(!intent.hasExtra(Intent.EXTRA_LOCAL_ONLY));
Steve McKay273103b2015-05-12 12:49:58 -0700143
Steve McKay323ee3e2015-09-25 16:02:56 -0700144 final DocumentStack stack = intent.getParcelableExtra(Shared.EXTRA_STACK);
Steve McKay83df8c02015-09-16 15:07:31 -0700145 if (stack != null) {
Steve McKayef3e2cf2015-04-20 17:18:15 -0700146 state.stack = stack;
Steve McKay83df8c02015-09-16 15:07:31 -0700147 }
Steve McKaye934ce62015-03-25 14:35:33 -0700148 }
149
150 @Override
151 protected void onPostCreate(Bundle savedInstanceState) {
152 super.onPostCreate(savedInstanceState);
Steve McKayb67bfbf2015-12-08 17:02:03 -0800153 // This check avoids a flicker from "Recents" to "Home".
154 // Only update action bar at this point if there is an active
155 // serach. Why? Because this avoid an early (undesired) load of
156 // the recents root...which is the default root in other activities.
157 // In Files app "Home" is the default, but it is loaded async.
Steve McKay1f264a82016-02-03 11:15:57 -0800158 // update will be called once Home root is loaded.
Steve McKayb67bfbf2015-12-08 17:02:03 -0800159 // Except while searching we need this call to ensure the
160 // search bits get layed out correctly.
161 if (mSearchManager.isSearching()) {
Steve McKay1f264a82016-02-03 11:15:57 -0800162 mNavigator.update();
Steve McKayb67bfbf2015-12-08 17:02:03 -0800163 }
Steve McKaye934ce62015-03-25 14:35:33 -0700164 }
165
166 @Override
Steve McKay83df8c02015-09-16 15:07:31 -0700167 public void onResume() {
168 super.onResume();
169
170 final RootInfo root = getCurrentRoot();
171
172 // If we're browsing a specific root, and that root went away, then we
173 // have no reason to hang around.
174 // TODO: Rather than just disappearing, maybe we should inform
175 // the user what has happened, let them close us. Less surprising.
176 if (mRoots.getRootBlocking(root.authority, root.rootId) == null) {
177 finish();
178 }
179 }
180
181 @Override
Steve McKay1f264a82016-02-03 11:15:57 -0800182 public String getDrawerTitle() {
183 return getResources().getString(R.string.files_label);
Steve McKaye934ce62015-03-25 14:35:33 -0700184 }
185
186 @Override
Steve McKaye934ce62015-03-25 14:35:33 -0700187 public boolean onPrepareOptionsMenu(Menu menu) {
Steve McKay5bbae102015-10-01 11:39:24 -0700188 super.onPrepareOptionsMenu(menu);
Steve McKay3ce95952016-02-02 11:41:03 -0800189
Steve McKayefa17612016-01-29 18:15:39 -0800190 final RootInfo root = getCurrentRoot();
Steve McKay9f9d5b42015-09-23 15:44:24 -0700191
Steve McKaye934ce62015-03-25 14:35:33 -0700192 final MenuItem createDir = menu.findItem(R.id.menu_create_dir);
Steve McKay9f9d5b42015-09-23 15:44:24 -0700193 final MenuItem pasteFromCb = menu.findItem(R.id.menu_paste_from_clipboard);
Steve McKayefa17612016-01-29 18:15:39 -0800194 final MenuItem settings = menu.findItem(R.id.menu_settings);
Steve McKayf8737692016-02-04 19:40:45 -0800195 final MenuItem newWindow = menu.findItem(R.id.menu_new_window);
Steve McKaye934ce62015-03-25 14:35:33 -0700196
Steve McKay5bbae102015-10-01 11:39:24 -0700197 createDir.setVisible(true);
198 createDir.setEnabled(canCreateDirectory());
Steve McKay5bbae102015-10-01 11:39:24 -0700199 pasteFromCb.setEnabled(mClipper.hasItemsToPaste());
Steve McKayefa17612016-01-29 18:15:39 -0800200 settings.setVisible(root.hasSettings());
Steve McKayf8737692016-02-04 19:40:45 -0800201 newWindow.setVisible(true);
Steve McKaya521d0d2015-05-19 16:10:25 -0700202
Steve McKay5bbae102015-10-01 11:39:24 -0700203 Menus.disableHiddenItems(menu, pasteFromCb);
204 return true;
Steve McKaye934ce62015-03-25 14:35:33 -0700205 }
206
207 @Override
Steve McKaybdbd0ff2015-05-20 15:58:42 -0700208 public boolean onOptionsItemSelected(MenuItem item) {
Steve McKay9f9d5b42015-09-23 15:44:24 -0700209 switch (item.getItemId()) {
210 case R.id.menu_create_dir:
211 checkState(canCreateDirectory());
212 showCreateDirectoryDialog();
213 return true;
214 case R.id.menu_new_window:
Steve McKay323ee3e2015-09-25 16:02:56 -0700215 createNewWindow();
Steve McKay9f9d5b42015-09-23 15:44:24 -0700216 return true;
217 case R.id.menu_paste_from_clipboard:
Steve McKay3ce95952016-02-02 11:41:03 -0800218 DirectoryFragment dir = getDirectoryFragment();
219 if (dir != null) {
220 dir.pasteFromClipboard();
221 }
Steve McKay9f9d5b42015-09-23 15:44:24 -0700222 return true;
Steve McKaybdbd0ff2015-05-20 15:58:42 -0700223 }
224
225 return super.onOptionsItemSelected(item);
226 }
227
Steve McKay323ee3e2015-09-25 16:02:56 -0700228 private void createNewWindow() {
Ben Kwa72379982016-01-26 11:50:03 -0800229 Metrics.logMultiWindow(this);
Steve McKay323ee3e2015-09-25 16:02:56 -0700230 Intent intent = LauncherActivity.createLaunchIntent(this);
231 intent.putExtra(Shared.EXTRA_STACK, (Parcelable) mState.stack);
Steve McKaya7e923c2016-01-28 12:02:57 -0800232
233 // With new multi-window mode we have to pick how we are launched.
234 // By default we'd be launched in-place above the existing app.
235 // By setting launch-to-side ActivityManager will open us to side.
Wale Ogunwale3b93a4d2016-01-29 17:46:53 -0800236 if (inMultiWindow()) {
Wale Ogunwale2a25a622016-01-30 11:27:21 -0800237 intent.addFlags(Intent.FLAG_ACTIVITY_LAUNCH_ADJACENT);
Steve McKaya7e923c2016-01-28 12:02:57 -0800238 }
239
Steve McKay323ee3e2015-09-25 16:02:56 -0700240 startActivity(intent);
241 }
242
Steve McKaybdbd0ff2015-05-20 15:58:42 -0700243 @Override
Aga Wronskaf6a31d32016-01-15 17:30:15 -0800244 void refreshDirectory(int anim) {
Steve McKaye934ce62015-03-25 14:35:33 -0700245 final FragmentManager fm = getFragmentManager();
246 final RootInfo root = getCurrentRoot();
247 final DocumentInfo cwd = getCurrentDirectory();
248
Aga Wronska893390b2016-02-17 13:50:42 -0800249 if (DEBUG) checkState(!mSearchManager.isSearching());
250
Steve McKaye934ce62015-03-25 14:35:33 -0700251 if (cwd == null) {
252 DirectoryFragment.showRecentsOpen(fm, anim);
Steve McKaye934ce62015-03-25 14:35:33 -0700253 } else {
Aga Wronska893390b2016-02-17 13:50:42 -0800254 // Normal boring directory
255 DirectoryFragment.showDirectory(fm, root, cwd, anim);
Steve McKaye934ce62015-03-25 14:35:33 -0700256 }
Steve McKaye934ce62015-03-25 14:35:33 -0700257 }
258
259 @Override
Steve McKay4f160402015-08-17 13:18:05 -0700260 void onRootPicked(RootInfo root) {
261 super.onRootPicked(root);
262 mDrawer.setOpen(false);
263 }
264
265 @Override
Steve McKay6eaf38632015-08-04 10:11:01 -0700266 public void onDocumentsPicked(List<DocumentInfo> docs) {
267 throw new UnsupportedOperationException();
Steve McKaye934ce62015-03-25 14:35:33 -0700268 }
269
Steve McKay6eaf38632015-08-04 10:11:01 -0700270 @Override
Tomasz Mikolajewski3d988a92016-02-16 12:28:43 +0900271 public void onDocumentPicked(DocumentInfo doc, Model model) {
Tomasz Mikolajewski39acff52015-11-25 13:01:18 +0900272 if (doc.isContainer()) {
273 openContainerDocument(doc);
Steve McKay6eaf38632015-08-04 10:11:01 -0700274 } else {
Tomasz Mikolajewski3d988a92016-02-16 12:28:43 +0900275 openDocument(doc, model);
Steve McKay6eaf38632015-08-04 10:11:01 -0700276 }
Steve McKayc78bcb82015-07-31 14:35:22 -0700277 }
278
279 /**
280 * Launches an intent to view the specified document.
281 */
Tomasz Mikolajewski3d988a92016-02-16 12:28:43 +0900282 private void openDocument(DocumentInfo doc, Model model) {
283 Intent intent = new QuickViewIntentBuilder(
284 getPackageManager(), getResources(), doc, model).build();
Steve McKay6eaf38632015-08-04 10:11:01 -0700285
Steve McKay3b2ad112015-10-15 15:27:30 -0700286 if (intent != null) {
287 // TODO: un-work around issue b/24963914. Should be fixed soon.
288 try {
289 startActivity(intent);
290 return;
291 } catch (SecurityException e) {
Steve McKay1eafb662015-10-23 09:04:09 -0700292 // Carry on to regular view mode.
Steve McKay3b2ad112015-10-15 15:27:30 -0700293 Log.e(TAG, "Caught security error: " + e.getLocalizedMessage());
294 }
Steve McKayc78bcb82015-07-31 14:35:22 -0700295 }
296
Steve McKay1eafb662015-10-23 09:04:09 -0700297 // Fallback to traditional VIEW action...
Steve McKay3b2ad112015-10-15 15:27:30 -0700298 intent = new Intent(Intent.ACTION_VIEW);
299 intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
300 intent.setData(doc.derivedUri);
301
Steve McKay6eaf38632015-08-04 10:11:01 -0700302 if (DEBUG && intent.getClipData() != null) {
303 Log.d(TAG, "Starting intent w/ clip data: " + intent.getClipData());
304 }
305
Steve McKayc78bcb82015-07-31 14:35:22 -0700306 try {
307 startActivity(intent);
Steve McKay3b2ad112015-10-15 15:27:30 -0700308 } catch (ActivityNotFoundException e) {
309 Snackbars.makeSnackbar(
310 this, R.string.toast_no_application, Snackbar.LENGTH_SHORT).show();
Steve McKayc78bcb82015-07-31 14:35:22 -0700311 }
312 }
313
Steve McKaye934ce62015-03-25 14:35:33 -0700314 @Override
Steve McKay3da8afc2015-05-05 14:50:00 -0700315 public boolean onKeyShortcut(int keyCode, KeyEvent event) {
316 DirectoryFragment dir;
Steve McKay3ce95952016-02-02 11:41:03 -0800317 // TODO: All key events should be statically bound using alphabeticShortcut.
318 // But not working.
Steve McKay3da8afc2015-05-05 14:50:00 -0700319 switch (keyCode) {
320 case KeyEvent.KEYCODE_A:
Steve McKay3ce95952016-02-02 11:41:03 -0800321 dir = getDirectoryFragment();
322 if (dir != null) {
323 dir.selectAllFiles();
324 }
Steve McKay3da8afc2015-05-05 14:50:00 -0700325 return true;
Steve McKaybdbd0ff2015-05-20 15:58:42 -0700326 case KeyEvent.KEYCODE_C:
Steve McKay3ce95952016-02-02 11:41:03 -0800327 dir = getDirectoryFragment();
328 if (dir != null) {
329 dir.copySelectedToClipboard();
330 }
Steve McKay8fd086a2015-12-04 11:19:09 -0800331 return true;
332 case KeyEvent.KEYCODE_V:
Steve McKay3ce95952016-02-02 11:41:03 -0800333 dir = getDirectoryFragment();
334 if (dir != null) {
335 dir.pasteFromClipboard();
336 }
Steve McKay8fd086a2015-12-04 11:19:09 -0800337 return true;
338 default:
339 return super.onKeyShortcut(keyCode, event);
Steve McKay3da8afc2015-05-05 14:50:00 -0700340 }
341 }
342
Steve McKay95cd85a2016-02-04 12:15:22 -0800343 // Turns out only DocumentsActivity was ever calling saveStackBlocking.
344 // There may be a case where we want to contribute entries from
345 // Behavior here in FilesActivity, but it isn't yet obvious.
346 // TODO: Contribute to recents, or remove this.
347 void writeStackToRecentsBlocking() {
Steve McKaye934ce62015-03-25 14:35:33 -0700348 final ContentResolver resolver = getContentResolver();
349 final ContentValues values = new ContentValues();
350
Steve McKay95cd85a2016-02-04 12:15:22 -0800351 final byte[] rawStack = DurableUtils.writeToArrayOrNull(mState.stack);
Steve McKaye934ce62015-03-25 14:35:33 -0700352
353 // Remember location for next app launch
354 final String packageName = getCallingPackageMaybeExtra();
355 values.clear();
356 values.put(ResumeColumns.STACK, rawStack);
357 values.put(ResumeColumns.EXTERNAL, 0);
358 resolver.insert(RecentsProvider.buildResume(packageName), values);
359 }
360
Steve McKayef3e2cf2015-04-20 17:18:15 -0700361 @Override
362 void onTaskFinished(Uri... uris) {
Steve McKaye934ce62015-03-25 14:35:33 -0700363 Log.d(TAG, "onFinished() " + Arrays.toString(uris));
364
365 final Intent intent = new Intent();
366 if (uris.length == 1) {
367 intent.setData(uris[0]);
368 } else if (uris.length > 1) {
369 final ClipData clipData = new ClipData(
370 null, mState.acceptMimes, new ClipData.Item(uris[0]));
371 for (int i = 1; i < uris.length; i++) {
372 clipData.addItem(new ClipData.Item(uris[i]));
373 }
374 intent.setClipData(clipData);
375 }
376
377 intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION
378 | Intent.FLAG_GRANT_WRITE_URI_PERMISSION
379 | Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION);
380
381 setResult(Activity.RESULT_OK, intent);
382 finish();
383 }
Tomasz Mikolajewskia6120da2016-01-27 17:36:51 +0900384
385 /**
386 * Builds a stack for the specific Uris. Multi roots are not supported, as it's impossible
387 * to know which root to select. Also, the stack doesn't contain intermediate directories.
388 * It's primarly used for opening ZIP archives from Downloads app.
389 */
Steve McKay95cd85a2016-02-04 12:15:22 -0800390 private static final class OpenUriForViewTask extends PairedTask<FilesActivity, Uri, Void> {
391
392 private final State mState;
393 public OpenUriForViewTask(FilesActivity activity) {
394 super(activity);
395 mState = activity.mState;
396 }
397
Tomasz Mikolajewskia6120da2016-01-27 17:36:51 +0900398 @Override
Steve McKay95cd85a2016-02-04 12:15:22 -0800399 protected Void run(Uri... params) {
Tomasz Mikolajewskia6120da2016-01-27 17:36:51 +0900400 final Uri uri = params[0];
401
Steve McKay95cd85a2016-02-04 12:15:22 -0800402 final RootsCache rootsCache = DocumentsApplication.getRootsCache(mOwner);
Tomasz Mikolajewskia6120da2016-01-27 17:36:51 +0900403 final String authority = uri.getAuthority();
404
405 final Collection<RootInfo> roots =
406 rootsCache.getRootsForAuthorityBlocking(authority);
407 if (roots.isEmpty()) {
408 Log.e(TAG, "Failed to find root for the requested Uri: " + uri);
409 return null;
410 }
411
412 final RootInfo root = roots.iterator().next();
413 mState.stack.root = root;
414 try {
Steve McKay95cd85a2016-02-04 12:15:22 -0800415 mState.stack.add(DocumentInfo.fromUri(mOwner.getContentResolver(), uri));
Tomasz Mikolajewskia6120da2016-01-27 17:36:51 +0900416 } catch (FileNotFoundException e) {
417 Log.e(TAG, "Failed to resolve DocumentInfo from Uri: " + uri);
418 }
Steve McKay95cd85a2016-02-04 12:15:22 -0800419 mState.stack.add(mOwner.getRootDocumentBlocking(root));
Tomasz Mikolajewskia6120da2016-01-27 17:36:51 +0900420 return null;
421 }
422
423 @Override
Steve McKay95cd85a2016-02-04 12:15:22 -0800424 protected void finish(Void result) {
425 mOwner.refreshCurrentRootAndDirectory(ANIM_NONE);
Tomasz Mikolajewskia6120da2016-01-27 17:36:51 +0900426 }
427 }
Steve McKaye934ce62015-03-25 14:35:33 -0700428}