Move to Android N-MR1 SDK.
[android_tools.git] / sdk / sources / android-25 / com / android / documentsui / dirlist / FragmentTuner.java
blob7b0510be644e01aab33bfdb41a8fee936638d3b4
1 /*
2 * Copyright (C) 2015 The Android Open Source Project
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 package com.android.documentsui.dirlist;
19 import static com.android.documentsui.State.ACTION_BROWSE;
20 import static com.android.documentsui.State.ACTION_CREATE;
21 import static com.android.documentsui.State.ACTION_GET_CONTENT;
22 import static com.android.documentsui.State.ACTION_OPEN;
23 import static com.android.documentsui.State.ACTION_OPEN_TREE;
24 import static com.android.documentsui.State.ACTION_PICK_COPY_DESTINATION;
26 import android.content.Context;
27 import android.provider.DocumentsContract.Document;
28 import android.view.Menu;
29 import android.view.MenuItem;
31 import com.android.documentsui.BaseActivity;
32 import com.android.documentsui.Menus;
33 import com.android.documentsui.MimePredicate;
34 import com.android.documentsui.R;
35 import com.android.documentsui.State;
36 import com.android.documentsui.dirlist.DirectoryFragment.ResultType;
38 /**
39 * Providers support for specializing the DirectoryFragment to the "host" Activity.
40 * Feel free to expand the role of this class to handle other specializations.
42 public abstract class FragmentTuner {
44 final Context mContext;
45 final State mState;
47 public FragmentTuner(Context context, State state) {
48 mContext = context;
49 mState = state;
52 public static FragmentTuner pick(Context context, State state) {
53 switch (state.action) {
54 case ACTION_BROWSE:
55 return new FilesTuner(context, state);
56 default:
57 return new DocumentsTuner(context, state);
62 // Subtly different from isDocumentEnabled. The reason may be illuminated as follows.
63 // A folder is enabled such that it may be double clicked, even in settings
64 // when the folder itself cannot be selected. This may also be true of container types.
65 public boolean canSelectType(String docMimeType, int docFlags) {
66 return true;
69 public boolean isDocumentEnabled(String docMimeType, int docFlags) {
70 return true;
73 /**
74 * When managed mode is enabled, active downloads will be visible in the UI.
75 * Presumably this should only be true when in the downloads directory.
77 boolean managedModeEnabled() {
78 return false;
81 /**
82 * Whether drag n' drop is allowed in this context
84 boolean dragAndDropEnabled() {
85 return false;
88 abstract void updateActionMenu(Menu menu, SelectionDetails selection);
89 abstract void onModelLoaded(Model model, @ResultType int resultType, boolean isSearch);
91 /**
92 * Provides support for Platform specific specializations of DirectoryFragment.
94 private static final class DocumentsTuner extends FragmentTuner {
96 // We use this to keep track of whether a model has been previously loaded or not so we can
97 // open the drawer on empty directories on first launch
98 private boolean mModelPreviousLoaded;
100 public DocumentsTuner(Context context, State state) {
101 super(context, state);
104 @Override
105 public boolean canSelectType(String docMimeType, int docFlags) {
106 if (!isDocumentEnabled(docMimeType, docFlags)) {
107 return false;
110 if (MimePredicate.isDirectoryType(docMimeType)) {
111 return false;
114 if (mState.action == ACTION_OPEN_TREE
115 || mState.action == ACTION_PICK_COPY_DESTINATION) {
116 // In this case nothing *ever* is selectable...the expected user behavior is
117 // they navigate *into* a folder, then click a confirmation button indicating
118 // that the current directory is the directory they are picking.
119 return false;
122 return true;
125 @Override
126 public boolean isDocumentEnabled(String mimeType, int docFlags) {
127 // Directories are always enabled.
128 if (MimePredicate.isDirectoryType(mimeType)) {
129 return true;
132 switch (mState.action) {
133 case ACTION_CREATE:
134 // Read-only files are disabled when creating.
135 if ((docFlags & Document.FLAG_SUPPORTS_WRITE) == 0) {
136 return false;
138 case ACTION_OPEN:
139 case ACTION_GET_CONTENT:
140 final boolean isVirtual = (docFlags & Document.FLAG_VIRTUAL_DOCUMENT) != 0;
141 if (isVirtual && mState.openableOnly) {
142 return false;
146 return MimePredicate.mimeMatches(mState.acceptMimes, mimeType);
149 @Override
150 public void updateActionMenu(Menu menu, SelectionDetails selection) {
152 MenuItem open = menu.findItem(R.id.menu_open);
153 MenuItem share = menu.findItem(R.id.menu_share);
154 MenuItem delete = menu.findItem(R.id.menu_delete);
155 MenuItem rename = menu.findItem(R.id.menu_rename);
156 MenuItem selectAll = menu.findItem(R.id.menu_select_all);
158 open.setVisible(mState.action == ACTION_GET_CONTENT
159 || mState.action == ACTION_OPEN);
160 share.setVisible(false);
161 delete.setVisible(false);
162 rename.setVisible(false);
163 selectAll.setVisible(mState.allowMultiple);
165 Menus.disableHiddenItems(menu);
168 @Override
169 void onModelLoaded(Model model, @ResultType int resultType, boolean isSearch) {
170 boolean showDrawer = false;
172 if (MimePredicate.mimeMatches(MimePredicate.VISUAL_MIMES, mState.acceptMimes)) {
173 showDrawer = false;
175 if (mState.external && mState.action == ACTION_GET_CONTENT) {
176 showDrawer = true;
178 if (mState.action == ACTION_PICK_COPY_DESTINATION) {
179 showDrawer = true;
182 // When launched into empty root, open drawer.
183 if (model.isEmpty()) {
184 showDrawer = true;
187 if (showDrawer && !mState.hasInitialLocationChanged() && !isSearch
188 && !mModelPreviousLoaded) {
189 // This noops on layouts without drawer, so no need to guard.
190 ((BaseActivity) mContext).setRootsDrawerOpen(true);
192 mModelPreviousLoaded = true;
197 * Provides support for Files activity specific specializations of DirectoryFragment.
199 private static final class FilesTuner extends FragmentTuner {
201 // We use this to keep track of whether a model has been previously loaded or not so we can
202 // open the drawer on empty directories on first launch
203 private boolean mModelPreviousLoaded;
205 public FilesTuner(Context context, State state) {
206 super(context, state);
209 @Override
210 public void updateActionMenu(Menu menu, SelectionDetails selection) {
212 menu.findItem(R.id.menu_open).setVisible(false); // "open" is never used in Files.
214 // Commands accessible only via keyboard...
215 MenuItem copy = menu.findItem(R.id.menu_copy_to_clipboard);
216 MenuItem paste = menu.findItem(R.id.menu_paste_from_clipboard);
218 // Commands visible in the UI...
219 MenuItem rename = menu.findItem(R.id.menu_rename);
220 MenuItem moveTo = menu.findItem(R.id.menu_move_to);
221 MenuItem copyTo = menu.findItem(R.id.menu_copy_to);
222 MenuItem share = menu.findItem(R.id.menu_share);
223 MenuItem delete = menu.findItem(R.id.menu_delete);
225 // copy is not visible, keyboard only
226 copy.setEnabled(!selection.containsPartialFiles());
228 // Commands usually on action-bar, so we always manage visibility.
229 share.setVisible(!selection.containsDirectories() && !selection.containsPartialFiles());
230 delete.setVisible(selection.canDelete());
232 share.setEnabled(!selection.containsDirectories() && !selection.containsPartialFiles());
233 delete.setEnabled(selection.canDelete());
235 // Commands always in overflow, so we don't bother showing/hiding...
236 copyTo.setVisible(true);
237 moveTo.setVisible(true);
238 rename.setVisible(true);
240 copyTo.setEnabled(!selection.containsPartialFiles());
241 moveTo.setEnabled(!selection.containsPartialFiles() && selection.canDelete());
242 rename.setEnabled(!selection.containsPartialFiles() && selection.canRename());
244 Menus.disableHiddenItems(menu, copy, paste);
247 @Override
248 void onModelLoaded(Model model, @ResultType int resultType, boolean isSearch) {
249 // When launched into empty root, open drawer.
250 if (model.isEmpty() && !mState.hasInitialLocationChanged() && !isSearch
251 && !mModelPreviousLoaded) {
252 // This noops on layouts without drawer, so no need to guard.
253 ((BaseActivity) mContext).setRootsDrawerOpen(true);
255 mModelPreviousLoaded = true;
258 @Override
259 public boolean managedModeEnabled() {
260 // When in downloads top level directory, we also show active downloads.
261 // And while we don't allow folders in Downloads, we do allow Zip files in
262 // downloads that themselves can be opened and viewed like directories.
263 // This method helps us understand when to kick in on those special behaviors.
264 return mState.stack.root != null
265 && mState.stack.root.isDownloads()
266 && mState.stack.size() == 1;
269 @Override
270 public boolean dragAndDropEnabled() {
271 return true;
276 * Access to meta data about the selection.
278 interface SelectionDetails {
279 boolean containsDirectories();
280 boolean containsPartialFiles();
282 // TODO: Update these to express characteristics instead of answering concrete questions,
283 // since the answer to those questions is (or can be) activity specific.
284 boolean canDelete();
285 boolean canRename();