blob: 313d303e785d09376ab9c10e913f164f33535ed7 [file] [log] [blame]
Jeff Sharkeye22d02e2013-04-26 16:54:55 -07001/*
2 * Copyright (C) 2013 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 McKayf8a5e082015-09-23 17:21:40 -070019import static com.android.documentsui.State.ACTION_CREATE;
20import static com.android.documentsui.State.ACTION_GET_CONTENT;
21import static com.android.documentsui.State.ACTION_OPEN;
Steve McKayf8a5e082015-09-23 17:21:40 -070022import static com.android.documentsui.State.ACTION_OPEN_TREE;
Ben Kwab8a5e082015-12-07 13:25:27 -080023import static com.android.documentsui.State.ACTION_PICK_COPY_DESTINATION;
Steve McKayf68210e2015-11-03 15:23:16 -080024import static com.android.documentsui.dirlist.DirectoryFragment.ANIM_NONE;
Jeff Sharkey311a7d82015-04-11 21:27:21 -070025
Jeff Sharkeye22d02e2013-04-26 16:54:55 -070026import android.app.Activity;
Steve McKayb68dd222015-04-20 17:18:15 -070027import android.app.Fragment;
Jeff Sharkeye22d02e2013-04-26 16:54:55 -070028import android.app.FragmentManager;
Jeff Sharkeyc317af82013-07-01 16:56:54 -070029import android.content.ClipData;
Jeff Sharkey1d890e02013-08-15 11:24:03 -070030import android.content.ComponentName;
Jeff Sharkey3fd11772013-09-30 14:26:27 -070031import android.content.ContentProviderClient;
Jeff Sharkeyc317af82013-07-01 16:56:54 -070032import android.content.ContentResolver;
Jeff Sharkeyf7adc932013-07-30 17:08:39 -070033import android.content.ContentValues;
Jeff Sharkeye22d02e2013-04-26 16:54:55 -070034import android.content.Intent;
Jeff Sharkey1d890e02013-08-15 11:24:03 -070035import android.content.pm.ResolveInfo;
Jeff Sharkey7d58fc62013-09-12 16:25:02 -070036import android.content.res.Resources;
Jeff Sharkey7d58fc62013-09-12 16:25:02 -070037import android.graphics.Point;
Jeff Sharkeye22d02e2013-04-26 16:54:55 -070038import android.net.Uri;
Jeff Sharkey8b997042013-09-19 15:25:56 -070039import android.os.AsyncTask;
Jeff Sharkeye22d02e2013-04-26 16:54:55 -070040import android.os.Bundle;
Tomasz Mikolajewski2023fcf2015-04-10 10:30:33 +090041import android.os.Parcelable;
Jeff Sharkeyf339f252013-08-15 16:17:41 -070042import android.provider.DocumentsContract;
Ben Kwac4693342015-09-30 10:00:10 -070043import android.support.design.widget.Snackbar;
Jeff Sharkeye22d02e2013-04-26 16:54:55 -070044import android.util.Log;
Jeff Sharkey09c10bf2013-06-30 20:02:59 -070045import android.view.Menu;
46import android.view.MenuItem;
Jeff Sharkeye22d02e2013-04-26 16:54:55 -070047import android.view.View;
Jeff Sharkey7d58fc62013-09-12 16:25:02 -070048import android.view.WindowManager;
Jeff Sharkey09c10bf2013-06-30 20:02:59 -070049import android.widget.BaseAdapter;
Jeff Sharkeye6fcceb2014-07-28 16:38:52 -070050import android.widget.Spinner;
Jeff Sharkeye6fcceb2014-07-28 16:38:52 -070051import android.widget.Toolbar;
Jeff Sharkeye22d02e2013-04-26 16:54:55 -070052
Jeff Sharkeya4d1f222013-09-07 14:45:03 -070053import com.android.documentsui.RecentsProvider.RecentColumns;
54import com.android.documentsui.RecentsProvider.ResumeColumns;
Steve McKayf68210e2015-11-03 15:23:16 -080055import com.android.documentsui.dirlist.DirectoryFragment;
Jeff Sharkey724deeb2013-08-31 15:02:20 -070056import com.android.documentsui.model.DocumentInfo;
Jeff Sharkeyb3620442013-09-01 18:41:04 -070057import com.android.documentsui.model.DurableUtils;
Jeff Sharkey724deeb2013-08-31 15:02:20 -070058import com.android.documentsui.model.RootInfo;
Jeff Sharkeyf7adc932013-07-30 17:08:39 -070059
Ben Kwa0e66b9b2015-05-18 13:18:05 -070060import java.util.Arrays;
61import java.util.List;
62
Steve McKayd0a2a2c2015-03-25 14:35:33 -070063public class DocumentsActivity extends BaseActivity {
Steve McKayb68dd222015-04-20 17:18:15 -070064 private static final int CODE_FORWARD = 42;
Ben Kwa0574b182015-09-08 07:31:19 -070065 private static final String TAG = "DocumentsActivity";
Jeff Sharkeye22d02e2013-04-26 16:54:55 -070066
Jeff Sharkey7d58fc62013-09-12 16:25:02 -070067 private boolean mShowAsDialog;
68
Jeff Sharkeye6fcceb2014-07-28 16:38:52 -070069 private Toolbar mToolbar;
70 private Spinner mToolbarStack;
71
72 private Toolbar mRootsToolbar;
73
Steve McKayb68dd222015-04-20 17:18:15 -070074 private ItemSelectedListener mStackListener;
75 private BaseAdapter mStackAdapter;
76
77 public DocumentsActivity() {
Steve McKay7f395012015-08-24 10:34:49 -070078 super(R.layout.docs_activity, TAG);
Steve McKayb68dd222015-04-20 17:18:15 -070079 }
80
Jeff Sharkeye22d02e2013-04-26 16:54:55 -070081 @Override
82 public void onCreate(Bundle icicle) {
Steve McKay0fbfc652015-08-20 16:48:49 -070083 super.onCreate(icicle);
Oren Blasbergb243af72015-06-25 19:00:43 -070084
85 final Resources res = getResources();
Steve McKay459bc2b2015-09-16 15:07:31 -070086 mShowAsDialog = res.getBoolean(R.bool.show_as_dialog);
Steve McKay6bbed4d2015-08-17 13:18:05 -070087
Oren Blasbergb243af72015-06-25 19:00:43 -070088 if (!mShowAsDialog) {
Ben Kwa565a9422015-10-29 15:43:23 -070089 setTheme(R.style.DocumentsFullScreenTheme);
Oren Blasbergb243af72015-06-25 19:00:43 -070090 }
91
Jeff Sharkey7d58fc62013-09-12 16:25:02 -070092 if (mShowAsDialog) {
Steve McKay6bbed4d2015-08-17 13:18:05 -070093 mDrawer = DrawerController.createDummy();
94
Jeff Sharkeye6fcceb2014-07-28 16:38:52 -070095 // Strongly define our horizontal dimension; we leave vertical as
96 // WRAP_CONTENT so that system resizes us when IME is showing.
Jeff Sharkey7d58fc62013-09-12 16:25:02 -070097 final WindowManager.LayoutParams a = getWindow().getAttributes();
Jeff Sharkey46165b52013-07-31 20:53:22 -070098
Jeff Sharkey7d58fc62013-09-12 16:25:02 -070099 final Point size = new Point();
100 getWindowManager().getDefaultDisplay().getSize(size);
Jeff Sharkeye6fcceb2014-07-28 16:38:52 -0700101 a.width = (int) res.getFraction(R.dimen.dialog_width, size.x, size.x);
Jeff Sharkey7d58fc62013-09-12 16:25:02 -0700102
Jeff Sharkeye6fcceb2014-07-28 16:38:52 -0700103 getWindow().setAttributes(a);
Jeff Sharkey7d58fc62013-09-12 16:25:02 -0700104
105 } else {
Steve McKay6bbed4d2015-08-17 13:18:05 -0700106 mDrawer = DrawerController.create(this);
Jeff Sharkey7d58fc62013-09-12 16:25:02 -0700107 }
Jeff Sharkey46165b52013-07-31 20:53:22 -0700108
Jeff Sharkeye6fcceb2014-07-28 16:38:52 -0700109 mToolbar = (Toolbar) findViewById(R.id.toolbar);
Jeff Sharkeye6fcceb2014-07-28 16:38:52 -0700110
Steve McKayb68dd222015-04-20 17:18:15 -0700111 mStackAdapter = new StackAdapter();
112 mStackListener = new ItemSelectedListener();
Jeff Sharkeye6fcceb2014-07-28 16:38:52 -0700113 mToolbarStack = (Spinner) findViewById(R.id.stack);
114 mToolbarStack.setOnItemSelectedListener(mStackListener);
115
116 mRootsToolbar = (Toolbar) findViewById(R.id.roots_toolbar);
Jeff Sharkeye6fcceb2014-07-28 16:38:52 -0700117
Jeff Sharkeyeff65d32014-07-29 16:32:36 -0700118 setActionBar(mToolbar);
119
Jeff Sharkeyb3620442013-09-01 18:41:04 -0700120 if (mState.action == ACTION_CREATE) {
121 final String mimeType = getIntent().getType();
122 final String title = getIntent().getStringExtra(Intent.EXTRA_TITLE);
123 SaveFragment.show(getFragmentManager(), mimeType, title);
Daichi Hironocaadd412015-04-10 15:50:38 +0900124 } else if (mState.action == ACTION_OPEN_TREE ||
Ben Kwaae967802015-09-25 14:48:29 -0700125 mState.action == ACTION_PICK_COPY_DESTINATION) {
Jeff Sharkey6e565ff2014-04-05 19:05:24 -0700126 PickFragment.show(getFragmentManager());
Jeff Sharkeyb3620442013-09-01 18:41:04 -0700127 }
128
129 if (mState.action == ACTION_GET_CONTENT) {
130 final Intent moreApps = new Intent(getIntent());
131 moreApps.setComponent(null);
132 moreApps.setPackage(null);
133 RootsFragment.show(getFragmentManager(), moreApps);
Daichi Hironocaadd412015-04-10 15:50:38 +0900134 } else if (mState.action == ACTION_OPEN ||
135 mState.action == ACTION_CREATE ||
136 mState.action == ACTION_OPEN_TREE ||
Ben Kwaae967802015-09-25 14:48:29 -0700137 mState.action == ACTION_PICK_COPY_DESTINATION) {
Jeff Sharkeyb3620442013-09-01 18:41:04 -0700138 RootsFragment.show(getFragmentManager(), null);
139 }
140
Jeff Sharkey8b997042013-09-19 15:25:56 -0700141 if (!mState.restored) {
Makoto Onuki4f996222015-06-23 14:29:25 -0700142 // In this case, we set the activity title in AsyncTask.onPostExecute(). To prevent
143 // talkback from reading aloud the default title, we clear it here.
144 setTitle("");
Steve McKay459bc2b2015-09-16 15:07:31 -0700145 new RestoreStackTask().execute();
Jeff Sharkey8b997042013-09-19 15:25:56 -0700146 } else {
147 onCurrentDirectoryChanged(ANIM_NONE);
148 }
Jeff Sharkeyb3620442013-09-01 18:41:04 -0700149 }
150
Steve McKay0fbfc652015-08-20 16:48:49 -0700151 @Override
Ben Kwa0574b182015-09-08 07:31:19 -0700152 State buildState() {
153 State state = buildDefaultState();
Jeff Sharkeyb3620442013-09-01 18:41:04 -0700154
155 final Intent intent = getIntent();
156 final String action = intent.getAction();
157 if (Intent.ACTION_OPEN_DOCUMENT.equals(action)) {
Steve McKayb68dd222015-04-20 17:18:15 -0700158 state.action = ACTION_OPEN;
Jeff Sharkeyb3620442013-09-01 18:41:04 -0700159 } else if (Intent.ACTION_CREATE_DOCUMENT.equals(action)) {
Steve McKayb68dd222015-04-20 17:18:15 -0700160 state.action = ACTION_CREATE;
Jeff Sharkeyb3620442013-09-01 18:41:04 -0700161 } else if (Intent.ACTION_GET_CONTENT.equals(action)) {
Steve McKayb68dd222015-04-20 17:18:15 -0700162 state.action = ACTION_GET_CONTENT;
Jeff Sharkeyf4943e12014-06-04 16:42:47 -0700163 } else if (Intent.ACTION_OPEN_DOCUMENT_TREE.equals(action)) {
Steve McKayb68dd222015-04-20 17:18:15 -0700164 state.action = ACTION_OPEN_TREE;
Ben Kwaae967802015-09-25 14:48:29 -0700165 } else if (Shared.ACTION_PICK_COPY_DESTINATION.equals(action)) {
166 state.action = ACTION_PICK_COPY_DESTINATION;
Jeff Sharkeyb3620442013-09-01 18:41:04 -0700167 }
168
Steve McKayb68dd222015-04-20 17:18:15 -0700169 if (state.action == ACTION_OPEN || state.action == ACTION_GET_CONTENT) {
170 state.allowMultiple = intent.getBooleanExtra(
Jeff Sharkeyb3620442013-09-01 18:41:04 -0700171 Intent.EXTRA_ALLOW_MULTIPLE, false);
172 }
173
Tomasz Mikolajewski95d9c252015-11-16 11:41:28 +0900174 if (state.action == ACTION_OPEN || state.action == ACTION_GET_CONTENT
175 || state.action == ACTION_CREATE) {
176 state.openableOnly = intent.hasCategory(Intent.CATEGORY_OPENABLE);
177 }
178
Ben Kwaae967802015-09-25 14:48:29 -0700179 if (state.action == ACTION_PICK_COPY_DESTINATION) {
Steve McKayb68dd222015-04-20 17:18:15 -0700180 state.directoryCopy = intent.getBooleanExtra(
Ben Kwaae967802015-09-25 14:48:29 -0700181 Shared.EXTRA_DIRECTORY_COPY, false);
Ben Kwacb4461f2015-05-05 11:50:11 -0700182 state.transferMode = intent.getIntExtra(CopyService.EXTRA_TRANSFER_MODE,
Tomasz Mikolajewski85578962015-11-04 15:33:20 +0900183 CopyService.TRANSFER_MODE_COPY);
Daichi Hironof2a822d2015-04-14 17:12:54 +0900184 }
Steve McKayb68dd222015-04-20 17:18:15 -0700185
186 return state;
Jeff Sharkey8b997042013-09-19 15:25:56 -0700187 }
Jeff Sharkeyb3620442013-09-01 18:41:04 -0700188
Steve McKayb68dd222015-04-20 17:18:15 -0700189 @Override
190 void onStackRestored(boolean restored, boolean external) {
191 // Show drawer when no stack restored, but only when requesting
192 // non-visual content. However, if we last used an external app,
193 // drawer is always shown.
Jeff Sharkey8b997042013-09-19 15:25:56 -0700194
Steve McKayb68dd222015-04-20 17:18:15 -0700195 boolean showDrawer = false;
196 if (!restored) {
197 showDrawer = true;
198 }
199 if (MimePredicate.mimeMatches(MimePredicate.VISUAL_MIMES, mState.acceptMimes)) {
200 showDrawer = false;
201 }
202 if (external && mState.action == ACTION_GET_CONTENT) {
203 showDrawer = true;
Jeff Sharkey8b997042013-09-19 15:25:56 -0700204 }
205
Steve McKayb68dd222015-04-20 17:18:15 -0700206 if (showDrawer) {
207 setRootsDrawerOpen(true);
208 }
209 }
Jeff Sharkey8b997042013-09-19 15:25:56 -0700210
Steve McKayb68dd222015-04-20 17:18:15 -0700211 public void onAppPicked(ResolveInfo info) {
212 final Intent intent = new Intent(getIntent());
213 intent.setFlags(intent.getFlags() & ~Intent.FLAG_ACTIVITY_FORWARD_RESULT);
214 intent.setComponent(new ComponentName(
215 info.activityInfo.applicationInfo.packageName, info.activityInfo.name));
216 startActivityForResult(intent, CODE_FORWARD);
217 }
Jeff Sharkey38ec2522013-09-24 12:07:12 -0700218
Steve McKayb68dd222015-04-20 17:18:15 -0700219 @Override
220 protected void onActivityResult(int requestCode, int resultCode, Intent data) {
221 Log.d(TAG, "onActivityResult() code=" + resultCode);
Jeff Sharkey38ec2522013-09-24 12:07:12 -0700222
Steve McKayb68dd222015-04-20 17:18:15 -0700223 // Only relay back results when not canceled; otherwise stick around to
224 // let the user pick another app/backend.
225 if (requestCode == CODE_FORWARD && resultCode != RESULT_CANCELED) {
Jeff Sharkey8b997042013-09-19 15:25:56 -0700226
Steve McKayb68dd222015-04-20 17:18:15 -0700227 // Remember that we last picked via external app
228 final String packageName = getCallingPackageMaybeExtra();
229 final ContentValues values = new ContentValues();
230 values.put(ResumeColumns.EXTERNAL, 1);
231 getContentResolver().insert(RecentsProvider.buildResume(packageName), values);
232
233 // Pass back result to original caller
234 setResult(resultCode, data);
235 finish();
236 } else {
237 super.onActivityResult(requestCode, resultCode, data);
Jeff Sharkeyf339f252013-08-15 16:17:41 -0700238 }
239 }
240
Jeff Sharkey46165b52013-07-31 20:53:22 -0700241 @Override
242 protected void onPostCreate(Bundle savedInstanceState) {
243 super.onPostCreate(savedInstanceState);
Steve McKay6bbed4d2015-08-17 13:18:05 -0700244 mDrawer.syncState();
Jeff Sharkeyb58b3d32014-11-24 10:00:00 -0800245 updateActionBar();
Jeff Sharkey7d58fc62013-09-12 16:25:02 -0700246 }
247
248 public void setRootsDrawerOpen(boolean open) {
Steve McKay6bbed4d2015-08-17 13:18:05 -0700249 mDrawer.setOpen(open);
Jeff Sharkeye22d02e2013-04-26 16:54:55 -0700250 }
251
Steve McKayb68dd222015-04-20 17:18:15 -0700252 @Override
Jeff Sharkey09c10bf2013-06-30 20:02:59 -0700253 public void updateActionBar() {
Jeff Sharkeye6fcceb2014-07-28 16:38:52 -0700254 if (mRootsToolbar != null) {
Tomasz Mikolajewski77fd4022015-06-12 16:22:17 -0700255 final String prompt = getIntent().getStringExtra(DocumentsContract.EXTRA_PROMPT);
256 if (prompt != null) {
257 mRootsToolbar.setTitle(prompt);
258 } else {
259 if (mState.action == ACTION_OPEN ||
260 mState.action == ACTION_GET_CONTENT ||
261 mState.action == ACTION_OPEN_TREE) {
262 mRootsToolbar.setTitle(R.string.title_open);
263 } else if (mState.action == ACTION_CREATE ||
Ben Kwaae967802015-09-25 14:48:29 -0700264 mState.action == ACTION_PICK_COPY_DESTINATION) {
Tomasz Mikolajewski77fd4022015-06-12 16:22:17 -0700265 mRootsToolbar.setTitle(R.string.title_save);
266 }
Jeff Sharkey09c10bf2013-06-30 20:02:59 -0700267 }
Jeff Sharkeye6fcceb2014-07-28 16:38:52 -0700268 }
Jeff Sharkeya5defe32013-08-05 17:56:48 -0700269
Steve McKay6bbed4d2015-08-17 13:18:05 -0700270 if (!mShowAsDialog && mDrawer.isUnlocked()) {
Jeff Sharkeye6fcceb2014-07-28 16:38:52 -0700271 mToolbar.setNavigationIcon(R.drawable.ic_hamburger);
Jeff Sharkey738d8a52014-10-13 12:53:13 -0700272 mToolbar.setNavigationContentDescription(R.string.drawer_open);
Jeff Sharkeye6fcceb2014-07-28 16:38:52 -0700273 mToolbar.setNavigationOnClickListener(new View.OnClickListener() {
274 @Override
275 public void onClick(View v) {
276 setRootsDrawerOpen(true);
277 }
278 });
Tomasz Mikolajewski2cadb1d2015-06-12 15:32:30 -0700279 } else {
280 mToolbar.setNavigationIcon(null);
281 mToolbar.setNavigationContentDescription(R.string.drawer_open);
282 mToolbar.setNavigationOnClickListener(null);
Jeff Sharkeye6fcceb2014-07-28 16:38:52 -0700283 }
284
Steve McKayb68dd222015-04-20 17:18:15 -0700285 if (mSearchManager.isExpanded()) {
Jeff Sharkeye6fcceb2014-07-28 16:38:52 -0700286 mToolbar.setTitle(null);
287 mToolbarStack.setVisibility(View.GONE);
288 mToolbarStack.setAdapter(null);
289 } else {
Jeff Sharkey4c5fe522013-09-03 14:17:06 -0700290 if (mState.stack.size() <= 1) {
Tomasz Mikolajewski2cadb1d2015-06-12 15:32:30 -0700291 mToolbar.setTitle(getCurrentRoot().title);
Jeff Sharkeye6fcceb2014-07-28 16:38:52 -0700292 mToolbarStack.setVisibility(View.GONE);
293 mToolbarStack.setAdapter(null);
Jeff Sharkeya5defe32013-08-05 17:56:48 -0700294 } else {
Jeff Sharkeye6fcceb2014-07-28 16:38:52 -0700295 mToolbar.setTitle(null);
296 mToolbarStack.setVisibility(View.VISIBLE);
297 mToolbarStack.setAdapter(mStackAdapter);
298
Steve McKayb68dd222015-04-20 17:18:15 -0700299 mStackListener.mIgnoreNextNavigation = true;
Jeff Sharkeye6fcceb2014-07-28 16:38:52 -0700300 mToolbarStack.setSelection(mStackAdapter.getCount() - 1);
Jeff Sharkey46165b52013-07-31 20:53:22 -0700301 }
Jeff Sharkey09c10bf2013-06-30 20:02:59 -0700302 }
303 }
304
305 @Override
306 public boolean onCreateOptionsMenu(Menu menu) {
Steve McKayb68dd222015-04-20 17:18:15 -0700307 boolean showMenu = super.onCreateOptionsMenu(menu);
308
Jeff Sharkeye8d13ea2014-08-08 15:10:03 -0700309 // Most actions are visible when showing as dialog
Jeff Sharkey7d58fc62013-09-12 16:25:02 -0700310 if (mShowAsDialog) {
Steve McKayb68dd222015-04-20 17:18:15 -0700311 expandMenus(menu);
Jeff Sharkey7d58fc62013-09-12 16:25:02 -0700312 }
Steve McKayb68dd222015-04-20 17:18:15 -0700313 return showMenu;
Jeff Sharkey09c10bf2013-06-30 20:02:59 -0700314 }
315
316 @Override
317 public boolean onPrepareOptionsMenu(Menu menu) {
318 super.onPrepareOptionsMenu(menu);
319
Jeff Sharkey724deeb2013-08-31 15:02:20 -0700320 final DocumentInfo cwd = getCurrentDirectory();
Jeff Sharkey5b535922013-08-02 15:55:26 -0700321
Jeff Sharkey09c10bf2013-06-30 20:02:59 -0700322 final MenuItem createDir = menu.findItem(R.id.menu_create_dir);
Jeff Sharkey4c5fe522013-09-03 14:17:06 -0700323 final MenuItem grid = menu.findItem(R.id.menu_grid);
Jeff Sharkeyc6cbdf12013-08-07 16:22:02 -0700324 final MenuItem list = menu.findItem(R.id.menu_list);
Jeff Sharkeye8d13ea2014-08-08 15:10:03 -0700325 final MenuItem fileSize = menu.findItem(R.id.menu_file_size);
Jeff Sharkey938528d2015-04-12 21:52:24 -0700326 final MenuItem settings = menu.findItem(R.id.menu_settings);
Jeff Sharkey5b535922013-08-02 15:55:26 -0700327
Steve McKaye9809272015-10-01 11:39:24 -0700328 boolean recents = cwd == null;
329 boolean picking = mState.action == ACTION_CREATE
Steve McKay0873f8a2015-05-20 14:07:22 -0700330 || mState.action == ACTION_OPEN_TREE
Ben Kwaae967802015-09-25 14:48:29 -0700331 || mState.action == ACTION_PICK_COPY_DESTINATION;
Jeff Sharkeyc6cbdf12013-08-07 16:22:02 -0700332
Steve McKaye9809272015-10-01 11:39:24 -0700333 createDir.setVisible(picking && !recents && cwd.isCreateSupported());
334 mSearchManager.showMenu(!picking);
Jeff Sharkeyc6cbdf12013-08-07 16:22:02 -0700335
Steve McKaye9809272015-10-01 11:39:24 -0700336 // No display options in recent directories
337 grid.setVisible(!(picking && recents));
338 list.setVisible(!(picking && recents));
339
340 fileSize.setVisible(fileSize.isVisible() && !picking);
341 settings.setVisible(false);
342
343 if (mState.action == ACTION_CREATE) {
344 final FragmentManager fm = getFragmentManager();
Steve McKay0fe95042015-10-14 17:41:13 -0700345 SaveFragment.get(fm).prepareForDirectory(cwd);
Jeff Sharkey5b535922013-08-02 15:55:26 -0700346 }
Jeff Sharkey46165b52013-07-31 20:53:22 -0700347
Steve McKaye9809272015-10-01 11:39:24 -0700348 Menus.disableHiddenItems(menu);
Jeff Sharkey938528d2015-04-12 21:52:24 -0700349
Jeff Sharkey09c10bf2013-06-30 20:02:59 -0700350 return true;
351 }
352
353 @Override
354 public boolean onOptionsItemSelected(MenuItem item) {
Steve McKay6bbed4d2015-08-17 13:18:05 -0700355 return mDrawer.onOptionsItemSelected(item) || super.onOptionsItemSelected(item);
Jeff Sharkey4be51f12013-10-23 15:46:38 -0700356 }
357
Jeff Sharkey5b535922013-08-02 15:55:26 -0700358 @Override
Steve McKayb68dd222015-04-20 17:18:15 -0700359 void onDirectoryChanged(int anim) {
Jeff Sharkey5b535922013-08-02 15:55:26 -0700360 final FragmentManager fm = getFragmentManager();
Jeff Sharkeya4d1f222013-09-07 14:45:03 -0700361 final RootInfo root = getCurrentRoot();
Jeff Sharkey724deeb2013-08-31 15:02:20 -0700362 final DocumentInfo cwd = getCurrentDirectory();
Jeff Sharkeyc6cbdf12013-08-07 16:22:02 -0700363
Jeff Sharkey2e694f82013-08-06 16:26:14 -0700364 if (cwd == null) {
365 // No directory means recents
Daichi Hironocaadd412015-04-10 15:50:38 +0900366 if (mState.action == ACTION_CREATE ||
367 mState.action == ACTION_OPEN_TREE ||
Ben Kwaae967802015-09-25 14:48:29 -0700368 mState.action == ACTION_PICK_COPY_DESTINATION) {
Jeff Sharkey2e694f82013-08-06 16:26:14 -0700369 RecentsCreateFragment.show(fm);
370 } else {
Jeff Sharkeyc8ae7a52013-09-18 16:26:49 -0700371 DirectoryFragment.showRecentsOpen(fm, anim);
Jeff Sharkey7d58fc62013-09-12 16:25:02 -0700372
Jeff Sharkey38ec2522013-09-24 12:07:12 -0700373 // Start recents in grid when requesting visual things
374 final boolean visualMimes = MimePredicate.mimeMatches(
375 MimePredicate.VISUAL_MIMES, mState.acceptMimes);
Steve McKayb68dd222015-04-20 17:18:15 -0700376 mState.userMode = visualMimes ? State.MODE_GRID : State.MODE_LIST;
Jeff Sharkey7d58fc62013-09-12 16:25:02 -0700377 mState.derivedMode = mState.userMode;
Jeff Sharkey2e694f82013-08-06 16:26:14 -0700378 }
379 } else {
Jeff Sharkeyb3620442013-09-01 18:41:04 -0700380 if (mState.currentSearch != null) {
Jeff Sharkey2e694f82013-08-06 16:26:14 -0700381 // Ongoing search
Jeff Sharkeyc8ae7a52013-09-18 16:26:49 -0700382 DirectoryFragment.showSearch(fm, root, mState.currentSearch, anim);
Jeff Sharkey2e694f82013-08-06 16:26:14 -0700383 } else {
384 // Normal boring directory
Jeff Sharkeyc8ae7a52013-09-18 16:26:49 -0700385 DirectoryFragment.showNormal(fm, root, cwd, anim);
Jeff Sharkey2e694f82013-08-06 16:26:14 -0700386 }
Jeff Sharkey09c10bf2013-06-30 20:02:59 -0700387 }
Jeff Sharkey2e694f82013-08-06 16:26:14 -0700388
Jeff Sharkeyc6cbdf12013-08-07 16:22:02 -0700389 // Forget any replacement target
Jeff Sharkeyb3620442013-09-01 18:41:04 -0700390 if (mState.action == ACTION_CREATE) {
Jeff Sharkeyc6cbdf12013-08-07 16:22:02 -0700391 final SaveFragment save = SaveFragment.get(fm);
392 if (save != null) {
393 save.setReplaceTarget(null);
394 }
395 }
396
Daichi Hironocaadd412015-04-10 15:50:38 +0900397 if (mState.action == ACTION_OPEN_TREE ||
Ben Kwaae967802015-09-25 14:48:29 -0700398 mState.action == ACTION_PICK_COPY_DESTINATION) {
Jeff Sharkey6e565ff2014-04-05 19:05:24 -0700399 final PickFragment pick = PickFragment.get(fm);
400 if (pick != null) {
Daichi Hirono4e2bb182015-05-27 15:20:10 -0700401 pick.setPickTarget(mState.action, mState.transferMode, cwd);
Jeff Sharkey6e565ff2014-04-05 19:05:24 -0700402 }
403 }
Steve McKayb68dd222015-04-20 17:18:15 -0700404 }
Jeff Sharkey6e565ff2014-04-05 19:05:24 -0700405
Steve McKayb68dd222015-04-20 17:18:15 -0700406 void onSaveRequested(DocumentInfo replaceTarget) {
Steve McKay459bc2b2015-09-16 15:07:31 -0700407 new ExistingFinishTask(replaceTarget.derivedUri).executeOnExecutor(getExecutorForCurrentDirectory());
Steve McKayb68dd222015-04-20 17:18:15 -0700408 }
Jeff Sharkey42d26792013-09-06 13:22:09 -0700409
Steve McKayb68dd222015-04-20 17:18:15 -0700410 void onSaveRequested(String mimeType, String displayName) {
Steve McKay459bc2b2015-09-16 15:07:31 -0700411 new CreateFinishTask(mimeType, displayName).executeOnExecutor(getExecutorForCurrentDirectory());
Jeff Sharkey09c10bf2013-06-30 20:02:59 -0700412 }
413
Steve McKayd0a2a2c2015-03-25 14:35:33 -0700414 @Override
Steve McKayb68dd222015-04-20 17:18:15 -0700415 void onRootPicked(RootInfo root) {
416 super.onRootPicked(root);
417 setRootsDrawerOpen(false);
Jeff Sharkey1d890e02013-08-15 11:24:03 -0700418 }
419
Steve McKayd0a2a2c2015-03-25 14:35:33 -0700420 @Override
Ben Kwab8a5e082015-12-07 13:25:27 -0800421 public void onDocumentPicked(DocumentInfo doc, SiblingProvider siblings) {
Jeff Sharkey09c10bf2013-06-30 20:02:59 -0700422 final FragmentManager fm = getFragmentManager();
Tomasz Mikolajewski734936a2015-11-25 13:01:18 +0900423 if (doc.isContainer()) {
424 openContainerDocument(doc);
Jeff Sharkeyb3620442013-09-01 18:41:04 -0700425 } else if (mState.action == ACTION_OPEN || mState.action == ACTION_GET_CONTENT) {
Jeff Sharkey09c10bf2013-06-30 20:02:59 -0700426 // Explicit file picked, return
Steve McKay459bc2b2015-09-16 15:07:31 -0700427 new ExistingFinishTask(doc.derivedUri).executeOnExecutor(getExecutorForCurrentDirectory());
Jeff Sharkeyb3620442013-09-01 18:41:04 -0700428 } else if (mState.action == ACTION_CREATE) {
Jeff Sharkeyc6cbdf12013-08-07 16:22:02 -0700429 // Replace selected file
430 SaveFragment.get(fm).setReplaceTarget(doc);
Jeff Sharkey09c10bf2013-06-30 20:02:59 -0700431 }
432 }
433
Steve McKayd0a2a2c2015-03-25 14:35:33 -0700434 @Override
Jeff Sharkey724deeb2013-08-31 15:02:20 -0700435 public void onDocumentsPicked(List<DocumentInfo> docs) {
Jeff Sharkeyb3620442013-09-01 18:41:04 -0700436 if (mState.action == ACTION_OPEN || mState.action == ACTION_GET_CONTENT) {
Jeff Sharkey873daa32013-08-18 17:38:20 -0700437 final int size = docs.size();
438 final Uri[] uris = new Uri[size];
439 for (int i = 0; i < size; i++) {
Jeff Sharkeya4d1f222013-09-07 14:45:03 -0700440 uris[i] = docs.get(i).derivedUri;
Jeff Sharkey873daa32013-08-18 17:38:20 -0700441 }
Steve McKay459bc2b2015-09-16 15:07:31 -0700442 new ExistingFinishTask(uris).executeOnExecutor(getExecutorForCurrentDirectory());
Jeff Sharkeyc317af82013-07-01 16:56:54 -0700443 }
Jeff Sharkey09c10bf2013-06-30 20:02:59 -0700444 }
445
Jeff Sharkey6e565ff2014-04-05 19:05:24 -0700446 public void onPickRequested(DocumentInfo pickTarget) {
Daichi Hironocaadd412015-04-10 15:50:38 +0900447 Uri result;
448 if (mState.action == ACTION_OPEN_TREE) {
449 result = DocumentsContract.buildTreeDocumentUri(
450 pickTarget.authority, pickTarget.documentId);
Ben Kwaae967802015-09-25 14:48:29 -0700451 } else if (mState.action == ACTION_PICK_COPY_DESTINATION) {
Daichi Hironocaadd412015-04-10 15:50:38 +0900452 result = pickTarget.derivedUri;
453 } else {
454 // Should not be reached.
455 throw new IllegalStateException("Invalid mState.action.");
456 }
Steve McKay459bc2b2015-09-16 15:07:31 -0700457 new PickFinishTask(result).executeOnExecutor(getExecutorForCurrentDirectory());
Jeff Sharkey6e565ff2014-04-05 19:05:24 -0700458 }
459
Steve McKayb68dd222015-04-20 17:18:15 -0700460 @Override
461 void saveStackBlocking() {
Jeff Sharkey5b535922013-08-02 15:55:26 -0700462 final ContentResolver resolver = getContentResolver();
463 final ContentValues values = new ContentValues();
464
Jeff Sharkeyb3620442013-09-01 18:41:04 -0700465 final byte[] rawStack = DurableUtils.writeToArrayOrNull(mState.stack);
Daichi Hironocaadd412015-04-10 15:50:38 +0900466 if (mState.action == ACTION_CREATE ||
467 mState.action == ACTION_OPEN_TREE ||
Ben Kwaae967802015-09-25 14:48:29 -0700468 mState.action == ACTION_PICK_COPY_DESTINATION) {
Jeff Sharkey5b535922013-08-02 15:55:26 -0700469 // Remember stack for last create
470 values.clear();
Jeff Sharkey9dd02622013-09-27 16:44:11 -0700471 values.put(RecentColumns.KEY, mState.stack.buildKey());
Jeff Sharkeya4d1f222013-09-07 14:45:03 -0700472 values.put(RecentColumns.STACK, rawStack);
473 resolver.insert(RecentsProvider.buildRecent(), values);
Jeff Sharkey5b535922013-08-02 15:55:26 -0700474 }
475
476 // Remember location for next app launch
Jeff Sharkey0b744d82013-10-09 13:52:17 -0700477 final String packageName = getCallingPackageMaybeExtra();
Jeff Sharkey5b535922013-08-02 15:55:26 -0700478 values.clear();
Jeff Sharkeya4d1f222013-09-07 14:45:03 -0700479 values.put(ResumeColumns.STACK, rawStack);
Jeff Sharkey38ec2522013-09-24 12:07:12 -0700480 values.put(ResumeColumns.EXTERNAL, 0);
Jeff Sharkey5b535922013-08-02 15:55:26 -0700481 resolver.insert(RecentsProvider.buildResume(packageName), values);
Jeff Sharkey9dd02622013-09-27 16:44:11 -0700482 }
483
Steve McKayb68dd222015-04-20 17:18:15 -0700484 @Override
485 void onTaskFinished(Uri... uris) {
Jeff Sharkey9dd02622013-09-27 16:44:11 -0700486 Log.d(TAG, "onFinished() " + Arrays.toString(uris));
Jeff Sharkey5b535922013-08-02 15:55:26 -0700487
Jeff Sharkeye22d02e2013-04-26 16:54:55 -0700488 final Intent intent = new Intent();
Jeff Sharkeyc317af82013-07-01 16:56:54 -0700489 if (uris.length == 1) {
490 intent.setData(uris[0]);
491 } else if (uris.length > 1) {
Jeff Sharkeya5defe32013-08-05 17:56:48 -0700492 final ClipData clipData = new ClipData(
Jeff Sharkeyb3620442013-09-01 18:41:04 -0700493 null, mState.acceptMimes, new ClipData.Item(uris[0]));
Jeff Sharkeyc317af82013-07-01 16:56:54 -0700494 for (int i = 1; i < uris.length; i++) {
495 clipData.addItem(new ClipData.Item(uris[i]));
496 }
497 intent.setClipData(clipData);
498 }
Jeff Sharkeye22d02e2013-04-26 16:54:55 -0700499
Jeff Sharkeyb3620442013-09-01 18:41:04 -0700500 if (mState.action == ACTION_GET_CONTENT) {
Jeff Sharkey1d890e02013-08-15 11:24:03 -0700501 intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
Jeff Sharkey6c3164d2015-07-15 09:13:14 -0700502 } else if (mState.action == ACTION_OPEN_TREE) {
Jeff Sharkey6e565ff2014-04-05 19:05:24 -0700503 intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION
504 | Intent.FLAG_GRANT_WRITE_URI_PERMISSION
505 | Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION
506 | Intent.FLAG_GRANT_PREFIX_URI_PERMISSION);
Ben Kwaae967802015-09-25 14:48:29 -0700507 } else if (mState.action == ACTION_PICK_COPY_DESTINATION) {
Jeff Sharkey6c3164d2015-07-15 09:13:14 -0700508 // Picking a copy destination is only used internally by us, so we
509 // don't need to extend permissions to the caller.
Steve McKay4d0255f2015-09-25 16:02:56 -0700510 intent.putExtra(Shared.EXTRA_STACK, (Parcelable) mState.stack);
Ben Kwacb4461f2015-05-05 11:50:11 -0700511 intent.putExtra(CopyService.EXTRA_TRANSFER_MODE, mState.transferMode);
Jeff Sharkey1d890e02013-08-15 11:24:03 -0700512 } else {
513 intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION
514 | Intent.FLAG_GRANT_WRITE_URI_PERMISSION
Jeff Sharkey13d369f2013-09-20 14:30:59 -0700515 | Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION);
Jeff Sharkey1d890e02013-08-15 11:24:03 -0700516 }
Jeff Sharkeye22d02e2013-04-26 16:54:55 -0700517
518 setResult(Activity.RESULT_OK, intent);
519 finish();
520 }
521
Steve McKayb68dd222015-04-20 17:18:15 -0700522 public static DocumentsActivity get(Fragment fragment) {
523 return (DocumentsActivity) fragment.getActivity();
524 }
525
526 private final class PickFinishTask extends AsyncTask<Void, Void, Void> {
527 private final Uri mUri;
528
529 public PickFinishTask(Uri uri) {
530 mUri = uri;
531 }
532
533 @Override
534 protected Void doInBackground(Void... params) {
535 saveStackBlocking();
536 return null;
537 }
538
539 @Override
540 protected void onPostExecute(Void result) {
541 onTaskFinished(mUri);
542 }
543 }
544
545 final class ExistingFinishTask extends AsyncTask<Void, Void, Void> {
546 private final Uri[] mUris;
547
548 public ExistingFinishTask(Uri... uris) {
549 mUris = uris;
550 }
551
552 @Override
553 protected Void doInBackground(Void... params) {
554 saveStackBlocking();
555 return null;
556 }
557
558 @Override
559 protected void onPostExecute(Void result) {
560 onTaskFinished(mUris);
561 }
562 }
563
564 /**
565 * Task that creates a new document in the background.
566 */
567 final class CreateFinishTask extends AsyncTask<Void, Void, Uri> {
Jeff Sharkey9dd02622013-09-27 16:44:11 -0700568 private final String mMimeType;
569 private final String mDisplayName;
570
571 public CreateFinishTask(String mimeType, String displayName) {
572 mMimeType = mimeType;
573 mDisplayName = displayName;
574 }
575
576 @Override
Jeff Sharkey4be51f12013-10-23 15:46:38 -0700577 protected void onPreExecute() {
578 setPending(true);
579 }
580
581 @Override
Jeff Sharkey9dd02622013-09-27 16:44:11 -0700582 protected Uri doInBackground(Void... params) {
Jeff Sharkey3fd11772013-09-30 14:26:27 -0700583 final ContentResolver resolver = getContentResolver();
Jeff Sharkey9dd02622013-09-27 16:44:11 -0700584 final DocumentInfo cwd = getCurrentDirectory();
Jeff Sharkey3fd11772013-09-30 14:26:27 -0700585
586 ContentProviderClient client = null;
587 Uri childUri = null;
588 try {
589 client = DocumentsApplication.acquireUnstableProviderOrThrow(
590 resolver, cwd.derivedUri.getAuthority());
591 childUri = DocumentsContract.createDocument(
592 client, cwd.derivedUri, mMimeType, mDisplayName);
593 } catch (Exception e) {
594 Log.w(TAG, "Failed to create document", e);
595 } finally {
596 ContentProviderClient.releaseQuietly(client);
597 }
598
Jeff Sharkey9dd02622013-09-27 16:44:11 -0700599 if (childUri != null) {
600 saveStackBlocking();
601 }
Jeff Sharkey3fd11772013-09-30 14:26:27 -0700602
Jeff Sharkey9dd02622013-09-27 16:44:11 -0700603 return childUri;
604 }
605
606 @Override
607 protected void onPostExecute(Uri result) {
608 if (result != null) {
Steve McKayb68dd222015-04-20 17:18:15 -0700609 onTaskFinished(result);
Jeff Sharkey9dd02622013-09-27 16:44:11 -0700610 } else {
Steve McKaye9809272015-10-01 11:39:24 -0700611 Snackbars.makeSnackbar(
Ben Kwac4693342015-09-30 10:00:10 -0700612 DocumentsActivity.this, R.string.save_error, Snackbar.LENGTH_SHORT).show();
Jeff Sharkey9dd02622013-09-27 16:44:11 -0700613 }
Jeff Sharkey4be51f12013-10-23 15:46:38 -0700614
615 setPending(false);
Jeff Sharkey9dd02622013-09-27 16:44:11 -0700616 }
617 }
Jeff Sharkeye22d02e2013-04-26 16:54:55 -0700618}