blob: 8b8a217c122929bd2a3f9f959de87faabd4b772f [file] [log] [blame]
Steve McKayd0a2a2c2015-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 McKayd0a2a2c2015-03-25 14:35:33 -070019import static com.android.documentsui.DirectoryFragment.ANIM_DOWN;
20import static com.android.documentsui.DirectoryFragment.ANIM_NONE;
Steve McKayd0a2a2c2015-03-25 14:35:33 -070021import static com.android.documentsui.DirectoryFragment.ANIM_UP;
Ben Kwacb4461f2015-05-05 11:50:11 -070022
Steve McKayd0a2a2c2015-03-25 14:35:33 -070023import android.app.Activity;
Steve McKayd0a2a2c2015-03-25 14:35:33 -070024import android.app.FragmentManager;
25import android.content.ActivityNotFoundException;
26import android.content.ClipData;
Steve McKayd0a2a2c2015-03-25 14:35:33 -070027import android.content.ContentResolver;
28import android.content.ContentValues;
29import android.content.Context;
30import android.content.Intent;
Steve McKayd0a2a2c2015-03-25 14:35:33 -070031import android.net.Uri;
Steve McKayd0a2a2c2015-03-25 14:35:33 -070032import android.os.Bundle;
Steve McKayd0a2a2c2015-03-25 14:35:33 -070033import android.provider.DocumentsContract;
Steve McKayb68dd222015-04-20 17:18:15 -070034import android.provider.DocumentsContract.Root;
Steve McKayd0a2a2c2015-03-25 14:35:33 -070035import android.util.Log;
Steve McKayd0a2a2c2015-03-25 14:35:33 -070036import android.view.Menu;
37import android.view.MenuItem;
Steve McKayd0a2a2c2015-03-25 14:35:33 -070038import android.view.View;
Steve McKayd0a2a2c2015-03-25 14:35:33 -070039import android.widget.BaseAdapter;
Steve McKayd0a2a2c2015-03-25 14:35:33 -070040import android.widget.Spinner;
Steve McKayd0a2a2c2015-03-25 14:35:33 -070041import android.widget.Toast;
42import android.widget.Toolbar;
43
44import com.android.documentsui.RecentsProvider.ResumeColumns;
45import com.android.documentsui.model.DocumentInfo;
46import com.android.documentsui.model.DocumentStack;
47import com.android.documentsui.model.DurableUtils;
48import com.android.documentsui.model.RootInfo;
49
Tomasz Mikolajewski332d8192015-04-13 19:38:43 +090050import java.util.ArrayList;
Steve McKayd0a2a2c2015-03-25 14:35:33 -070051import java.util.Arrays;
Steve McKayd0a2a2c2015-03-25 14:35:33 -070052import java.util.List;
Steve McKayd0a2a2c2015-03-25 14:35:33 -070053
Steve McKayb68dd222015-04-20 17:18:15 -070054/**
55 * Activity providing a directly launchable file management activity.
56 */
Steve McKayd0a2a2c2015-03-25 14:35:33 -070057public class StandaloneActivity extends BaseActivity {
58 public static final String TAG = "StandaloneFileManagement";
59
Steve McKayd0a2a2c2015-03-25 14:35:33 -070060 private Toolbar mToolbar;
61 private Spinner mToolbarStack;
Steve McKayd0a2a2c2015-03-25 14:35:33 -070062 private Toolbar mRootsToolbar;
Steve McKayd0a2a2c2015-03-25 14:35:33 -070063 private DirectoryContainerView mDirectoryContainer;
Steve McKayd0a2a2c2015-03-25 14:35:33 -070064 private State mState;
Steve McKayb68dd222015-04-20 17:18:15 -070065 private ItemSelectedListener mStackListener;
66 private BaseAdapter mStackAdapter;
67
68 public StandaloneActivity() {
69 super(TAG);
70 }
Steve McKayd0a2a2c2015-03-25 14:35:33 -070071
72 @Override
73 public void onCreate(Bundle icicle) {
Steve McKayd0a2a2c2015-03-25 14:35:33 -070074 super.onCreate(icicle);
75
Steve McKayd0a2a2c2015-03-25 14:35:33 -070076 setResult(Activity.RESULT_CANCELED);
77 setContentView(R.layout.activity);
78
79 final Context context = this;
Steve McKayd0a2a2c2015-03-25 14:35:33 -070080
Steve McKayd0a2a2c2015-03-25 14:35:33 -070081 mDirectoryContainer = (DirectoryContainerView) findViewById(R.id.container_directory);
82
Steve McKayb68dd222015-04-20 17:18:15 -070083 mState = (icicle != null)
Ben Kwacb4461f2015-05-05 11:50:11 -070084 ? icicle.<State> getParcelable(EXTRA_STATE)
85 : buildDefaultState();
Steve McKayd0a2a2c2015-03-25 14:35:33 -070086
87 mToolbar = (Toolbar) findViewById(R.id.toolbar);
88 mToolbar.setTitleTextAppearance(context,
89 android.R.style.TextAppearance_DeviceDefault_Widget_ActionBar_Title);
90
Steve McKayb68dd222015-04-20 17:18:15 -070091 mStackAdapter = new StackAdapter();
92 mStackListener = new ItemSelectedListener();
Steve McKayd0a2a2c2015-03-25 14:35:33 -070093 mToolbarStack = (Spinner) findViewById(R.id.stack);
94 mToolbarStack.setOnItemSelectedListener(mStackListener);
95
96 mRootsToolbar = (Toolbar) findViewById(R.id.roots_toolbar);
97 if (mRootsToolbar != null) {
98 mRootsToolbar.setTitleTextAppearance(context,
99 android.R.style.TextAppearance_DeviceDefault_Widget_ActionBar_Title);
100 }
101
102 setActionBar(mToolbar);
103
104 RootsFragment.show(getFragmentManager(), null);
105 if (!mState.restored) {
106 new RestoreStackTask().execute();
Tomasz Mikolajewski9452c442015-04-14 16:32:41 +0900107
108 // Show a failure dialog if there was a failed operation.
Tomasz Mikolajewski332d8192015-04-13 19:38:43 +0900109 final Intent intent = getIntent();
Tomasz Mikolajewski9452c442015-04-14 16:32:41 +0900110 final DocumentStack dstStack = intent.getParcelableExtra(CopyService.EXTRA_STACK);
Tomasz Mikolajewski332d8192015-04-13 19:38:43 +0900111 final int failure = intent.getIntExtra(CopyService.EXTRA_FAILURE, 0);
Ben Kwacb4461f2015-05-05 11:50:11 -0700112 final int transferMode = intent.getIntExtra(CopyService.EXTRA_TRANSFER_MODE,
113 CopyService.TRANSFER_MODE_NONE);
Tomasz Mikolajewski332d8192015-04-13 19:38:43 +0900114 if (failure != 0) {
Tomasz Mikolajewski9452c442015-04-14 16:32:41 +0900115 final ArrayList<DocumentInfo> failedSrcList =
116 intent.getParcelableArrayListExtra(CopyService.EXTRA_SRC_LIST);
Ben Kwacb4461f2015-05-05 11:50:11 -0700117 FailureDialogFragment.show(getFragmentManager(), failure, failedSrcList, dstStack,
118 transferMode);
Tomasz Mikolajewski332d8192015-04-13 19:38:43 +0900119 }
Steve McKayd0a2a2c2015-03-25 14:35:33 -0700120 } else {
121 onCurrentDirectoryChanged(ANIM_NONE);
122 }
123 }
124
Steve McKayb68dd222015-04-20 17:18:15 -0700125 private State buildDefaultState() {
126 State state = new State();
Steve McKayd0a2a2c2015-03-25 14:35:33 -0700127
128 final Intent intent = getIntent();
Steve McKayb68dd222015-04-20 17:18:15 -0700129 state.action = State.ACTION_BROWSE_ALL;
130 state.acceptMimes = new String[] { "*/*" };
131 state.allowMultiple = true;
132 state.acceptMimes = new String[] { intent.getType() };
133 state.localOnly = intent.getBooleanExtra(Intent.EXTRA_LOCAL_ONLY, false);
134 state.forceAdvanced = intent.getBooleanExtra(DocumentsContract.EXTRA_SHOW_ADVANCED, false);
135 state.showAdvanced = state.forceAdvanced
Steve McKayd0a2a2c2015-03-25 14:35:33 -0700136 | LocalPreferences.getDisplayAdvancedDevices(this);
Steve McKayb68dd222015-04-20 17:18:15 -0700137 state.showSize = true;
Tomasz Mikolajewski2023fcf2015-04-10 10:30:33 +0900138 final DocumentStack stack = intent.getParcelableExtra(CopyService.EXTRA_STACK);
139 if (stack != null)
Steve McKayb68dd222015-04-20 17:18:15 -0700140 state.stack = stack;
Steve McKayd0a2a2c2015-03-25 14:35:33 -0700141
Steve McKayb68dd222015-04-20 17:18:15 -0700142 return state;
Steve McKayd0a2a2c2015-03-25 14:35:33 -0700143 }
144
145 @Override
146 protected void onPostCreate(Bundle savedInstanceState) {
147 super.onPostCreate(savedInstanceState);
Steve McKayd0a2a2c2015-03-25 14:35:33 -0700148 updateActionBar();
149 }
150
151 @Override
Steve McKayd0a2a2c2015-03-25 14:35:33 -0700152 public void updateActionBar() {
153 final RootInfo root = getCurrentRoot();
154 mToolbar.setNavigationIcon(
155 root != null ? root.loadToolbarIcon(mToolbar.getContext()) : null);
156 mToolbar.setNavigationContentDescription(R.string.drawer_open);
157 mToolbar.setNavigationOnClickListener(null);
158
Steve McKayb68dd222015-04-20 17:18:15 -0700159 if (mSearchManager.isExpanded()) {
Steve McKayd0a2a2c2015-03-25 14:35:33 -0700160 mToolbar.setTitle(null);
161 mToolbarStack.setVisibility(View.GONE);
162 mToolbarStack.setAdapter(null);
163 } else {
164 if (mState.stack.size() <= 1) {
165 mToolbar.setTitle(root.title);
166 mToolbarStack.setVisibility(View.GONE);
167 mToolbarStack.setAdapter(null);
168 } else {
169 mToolbar.setTitle(null);
170 mToolbarStack.setVisibility(View.VISIBLE);
171 mToolbarStack.setAdapter(mStackAdapter);
172
Steve McKayb68dd222015-04-20 17:18:15 -0700173 mStackListener.mIgnoreNextNavigation = true;
Steve McKayd0a2a2c2015-03-25 14:35:33 -0700174 mToolbarStack.setSelection(mStackAdapter.getCount() - 1);
175 }
176 }
177 }
178
179 @Override
180 public boolean onCreateOptionsMenu(Menu menu) {
Steve McKayb68dd222015-04-20 17:18:15 -0700181 boolean showMenu = super.onCreateOptionsMenu(menu);
Steve McKayd0a2a2c2015-03-25 14:35:33 -0700182
Steve McKayb68dd222015-04-20 17:18:15 -0700183 expandMenus(menu);
Steve McKayb68dd222015-04-20 17:18:15 -0700184 return showMenu;
Steve McKayd0a2a2c2015-03-25 14:35:33 -0700185 }
186
187 @Override
188 public boolean onPrepareOptionsMenu(Menu menu) {
Steve McKay7bd32e12015-04-30 16:12:59 -0700189 boolean shown = super.onPrepareOptionsMenu(menu);
Steve McKayd0a2a2c2015-03-25 14:35:33 -0700190
Steve McKayd0a2a2c2015-03-25 14:35:33 -0700191 final RootInfo root = getCurrentRoot();
192 final DocumentInfo cwd = getCurrentDirectory();
193
194 final MenuItem createDir = menu.findItem(R.id.menu_create_dir);
Steve McKayd0a2a2c2015-03-25 14:35:33 -0700195 final MenuItem advanced = menu.findItem(R.id.menu_advanced);
196 final MenuItem fileSize = menu.findItem(R.id.menu_file_size);
Steve McKayb68dd222015-04-20 17:18:15 -0700197 final MenuItem settings = menu.findItem(R.id.menu_settings);
Steve McKayd0a2a2c2015-03-25 14:35:33 -0700198
Steve McKayb68dd222015-04-20 17:18:15 -0700199 createDir.setVisible(cwd != null
200 && cwd.isCreateSupported()
201 && !mSearchManager.isSearching()
202 && !root.isDownloads());
203
204 fileSize.setVisible(cwd != null);
205 advanced.setVisible(cwd != null);
Steve McKayd0a2a2c2015-03-25 14:35:33 -0700206
Steve McKayb68dd222015-04-20 17:18:15 -0700207 settings.setVisible((root.flags & Root.FLAG_HAS_SETTINGS) != 0);
Steve McKayd0a2a2c2015-03-25 14:35:33 -0700208
Steve McKay7bd32e12015-04-30 16:12:59 -0700209 return shown;
Steve McKayd0a2a2c2015-03-25 14:35:33 -0700210 }
211
212 @Override
Steve McKayd0a2a2c2015-03-25 14:35:33 -0700213 public void onBackPressed() {
214 if (!mState.stackTouched) {
215 super.onBackPressed();
216 return;
217 }
218
219 final int size = mState.stack.size();
220 if (size > 1) {
221 mState.stack.pop();
222 onCurrentDirectoryChanged(ANIM_UP);
223 } else {
224 super.onBackPressed();
225 }
226 }
227
228 @Override
Steve McKayd0a2a2c2015-03-25 14:35:33 -0700229 public State getDisplayState() {
230 return mState;
231 }
232
Steve McKayb68dd222015-04-20 17:18:15 -0700233 @Override
234 void onDirectoryChanged(int anim) {
Steve McKayd0a2a2c2015-03-25 14:35:33 -0700235 final FragmentManager fm = getFragmentManager();
236 final RootInfo root = getCurrentRoot();
237 final DocumentInfo cwd = getCurrentDirectory();
238
239 mDirectoryContainer.setDrawDisappearingFirst(anim == ANIM_DOWN);
240
241 if (cwd == null) {
242 DirectoryFragment.showRecentsOpen(fm, anim);
243
244 // Start recents in grid when requesting visual things
245 final boolean visualMimes = MimePredicate.mimeMatches(
246 MimePredicate.VISUAL_MIMES, mState.acceptMimes);
247 mState.userMode = visualMimes ? State.MODE_GRID : State.MODE_LIST;
248 mState.derivedMode = mState.userMode;
249 } else {
250 if (mState.currentSearch != null) {
251 // Ongoing search
252 DirectoryFragment.showSearch(fm, root, mState.currentSearch, anim);
253 } else {
254 // Normal boring directory
255 DirectoryFragment.showNormal(fm, root, cwd, anim);
256 }
257 }
Steve McKayd0a2a2c2015-03-25 14:35:33 -0700258 }
259
260 @Override
261 public void onDocumentPicked(DocumentInfo doc) {
Steve McKayd0a2a2c2015-03-25 14:35:33 -0700262 if (doc.isDirectory()) {
263 mState.stack.push(doc);
264 mState.stackTouched = true;
265 onCurrentDirectoryChanged(ANIM_DOWN);
266 } else {
267 // Fall back to viewing
268 final Intent view = new Intent(Intent.ACTION_VIEW);
269 view.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
270 view.setData(doc.derivedUri);
271
272 try {
273 startActivity(view);
274 } catch (ActivityNotFoundException ex2) {
275 Toast.makeText(this, R.string.toast_no_application, Toast.LENGTH_SHORT).show();
276 }
277 }
278 }
279
Ben Kwacb4461f2015-05-05 11:50:11 -0700280 @Override
Steve McKayd0a2a2c2015-03-25 14:35:33 -0700281 public void onDocumentsPicked(List<DocumentInfo> docs) {
282 // TODO
283 }
284
285 @Override
Steve McKayb68dd222015-04-20 17:18:15 -0700286 void saveStackBlocking() {
Steve McKayd0a2a2c2015-03-25 14:35:33 -0700287 final ContentResolver resolver = getContentResolver();
288 final ContentValues values = new ContentValues();
289
Steve McKayb68dd222015-04-20 17:18:15 -0700290 final byte[] rawStack = DurableUtils.writeToArrayOrNull(
291 getDisplayState().stack);
Steve McKayd0a2a2c2015-03-25 14:35:33 -0700292
293 // Remember location for next app launch
294 final String packageName = getCallingPackageMaybeExtra();
295 values.clear();
296 values.put(ResumeColumns.STACK, rawStack);
297 values.put(ResumeColumns.EXTERNAL, 0);
298 resolver.insert(RecentsProvider.buildResume(packageName), values);
299 }
300
Steve McKayb68dd222015-04-20 17:18:15 -0700301 @Override
302 void onTaskFinished(Uri... uris) {
Steve McKayd0a2a2c2015-03-25 14:35:33 -0700303 Log.d(TAG, "onFinished() " + Arrays.toString(uris));
304
305 final Intent intent = new Intent();
306 if (uris.length == 1) {
307 intent.setData(uris[0]);
308 } else if (uris.length > 1) {
309 final ClipData clipData = new ClipData(
310 null, mState.acceptMimes, new ClipData.Item(uris[0]));
311 for (int i = 1; i < uris.length; i++) {
312 clipData.addItem(new ClipData.Item(uris[i]));
313 }
314 intent.setClipData(clipData);
315 }
316
317 intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION
318 | Intent.FLAG_GRANT_WRITE_URI_PERMISSION
319 | Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION);
320
321 setResult(Activity.RESULT_OK, intent);
322 finish();
323 }
Steve McKayd0a2a2c2015-03-25 14:35:33 -0700324}