blob: 914f71e157093fcb5ab99bcd053f2d572edc35cb [file] [log] [blame]
Steve McKayd3f6f142015-10-27 15:57:53 -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.dirlist;
18
Steve McKayaa15dae2016-02-09 16:17:24 -080019import static com.android.documentsui.Shared.DEBUG;
Steve McKayd3f6f142015-10-27 15:57:53 -070020import static com.android.documentsui.State.ACTION_BROWSE;
Steve McKayf69502c2015-11-09 17:38:35 +090021import static com.android.documentsui.State.ACTION_CREATE;
22import static com.android.documentsui.State.ACTION_GET_CONTENT;
Steve McKayd3f6f142015-10-27 15:57:53 -070023import static com.android.documentsui.State.ACTION_MANAGE;
Steve McKayf69502c2015-11-09 17:38:35 +090024import static com.android.documentsui.State.ACTION_OPEN;
25import static com.android.documentsui.State.ACTION_OPEN_TREE;
Steve McKayd3f6f142015-10-27 15:57:53 -070026import static com.android.internal.util.Preconditions.checkArgument;
27
Steve McKayaa15dae2016-02-09 16:17:24 -080028import android.content.Context;
29import android.os.SystemProperties;
30import android.provider.DocumentsContract.Document;
31import android.util.Log;
32import android.view.Menu;
33import android.view.MenuItem;
34
35import com.android.documentsui.DocumentsActivity;
36import com.android.documentsui.FilesActivity;
Steve McKayd3f6f142015-10-27 15:57:53 -070037import com.android.documentsui.Menus;
Steve McKayf69502c2015-11-09 17:38:35 +090038import com.android.documentsui.MimePredicate;
Steve McKayd3f6f142015-10-27 15:57:53 -070039import com.android.documentsui.R;
40import com.android.documentsui.State;
Steve McKayaa15dae2016-02-09 16:17:24 -080041import com.android.documentsui.dirlist.DirectoryFragment.ResultType;
Steve McKayf69502c2015-11-09 17:38:35 +090042
Steve McKayd3f6f142015-10-27 15:57:53 -070043/**
44 * Providers support for specializing the DirectoryFragment to the "host" Activity.
45 * Feel free to expand the role of this class to handle other specializations.
46 */
47public abstract class FragmentTuner {
Steve McKayf69502c2015-11-09 17:38:35 +090048
Steve McKayaa15dae2016-02-09 16:17:24 -080049 final Context mContext;
Steve McKayf69502c2015-11-09 17:38:35 +090050 final State mState;
51
Steve McKayaa15dae2016-02-09 16:17:24 -080052 public FragmentTuner(Context context, State state) {
53 mContext = context;
Steve McKayf69502c2015-11-09 17:38:35 +090054 mState = state;
55 }
56
Steve McKayaa15dae2016-02-09 16:17:24 -080057 public static FragmentTuner pick(Context context, State state) {
Steve McKayd3f6f142015-10-27 15:57:53 -070058 switch (state.action) {
59 case ACTION_BROWSE:
Steve McKayaa15dae2016-02-09 16:17:24 -080060 return new FilesTuner(context, state);
Steve McKayd3f6f142015-10-27 15:57:53 -070061 case ACTION_MANAGE:
Steve McKayaa15dae2016-02-09 16:17:24 -080062 return new DownloadsTuner(context, state);
Steve McKayd3f6f142015-10-27 15:57:53 -070063 default:
Steve McKayaa15dae2016-02-09 16:17:24 -080064 return new DocumentsTuner(context, state);
Steve McKayd3f6f142015-10-27 15:57:53 -070065 }
66 }
67
Steve McKayf69502c2015-11-09 17:38:35 +090068
Aga Wronska3b327ef2016-01-20 16:32:33 -080069 public abstract void updateActionMenu(Menu menu, int dirType, boolean canDelete,
70 boolean canRename);
Steve McKayd3f6f142015-10-27 15:57:53 -070071
Steve McKayf69502c2015-11-09 17:38:35 +090072 // Subtly different from isDocumentEnabled. The reason may be illuminated as follows.
73 // A folder is enabled such that it may be double clicked, even in settings
74 // when the folder itself cannot be selected. This may also be true of container types.
Tomasz Mikolajewskia8057a92015-11-16 11:41:28 +090075 public boolean canSelectType(String docMimeType, int docFlags) {
Steve McKayf69502c2015-11-09 17:38:35 +090076 return true;
77 }
78
79 public boolean isDocumentEnabled(String docMimeType, int docFlags) {
80 if (isDirectory(docMimeType)) {
81 return true;
82 }
83
84 return MimePredicate.mimeMatches(mState.acceptMimes, docMimeType);
85 }
86
Aga Wronska893390b2016-02-17 13:50:42 -080087 abstract void onModelLoaded(Model model, @ResultType int resultType, boolean isSearch);
Steve McKayaa15dae2016-02-09 16:17:24 -080088
Steve McKayd3f6f142015-10-27 15:57:53 -070089 /**
90 * Provides support for Platform specific specializations of DirectoryFragment.
91 */
92 private static final class DocumentsTuner extends FragmentTuner {
Steve McKayf69502c2015-11-09 17:38:35 +090093
Steve McKayaa15dae2016-02-09 16:17:24 -080094 public DocumentsTuner(Context context, State state) {
95 super(context, state);
Steve McKayf69502c2015-11-09 17:38:35 +090096 }
97
98 @Override
Tomasz Mikolajewskia8057a92015-11-16 11:41:28 +090099 public boolean canSelectType(String docMimeType, int docFlags) {
100 if (!isDocumentEnabled(docMimeType, docFlags)) {
101 return false;
Steve McKayf69502c2015-11-09 17:38:35 +0900102 }
Tomasz Mikolajewskia8057a92015-11-16 11:41:28 +0900103
104 if (isDirectory(docMimeType)) {
105 return false;
106 }
107
108 if (mState.action == ACTION_OPEN_TREE) {
109 // In this case nothing *ever* is selectable...the expected user behavior is
110 // they navigate *into* a folder, then click a confirmation button indicating
111 // that the current directory is the directory they are picking.
112 return false;
113 }
114
Steve McKayf69502c2015-11-09 17:38:35 +0900115 return true;
116 }
117
118 @Override
119 public boolean isDocumentEnabled(String docMimeType, int docFlags) {
Tomasz Mikolajewskia8057a92015-11-16 11:41:28 +0900120 // Directories are always enabled.
Steve McKayf69502c2015-11-09 17:38:35 +0900121 if (isDirectory(docMimeType)) {
122 return true;
123 }
124
Tomasz Mikolajewskia8057a92015-11-16 11:41:28 +0900125 switch (mState.action) {
126 case ACTION_CREATE:
127 // Read-only files are disabled when creating.
128 if ((docFlags & Document.FLAG_SUPPORTS_WRITE) == 0) {
129 return false;
130 }
131 case ACTION_OPEN:
132 case ACTION_GET_CONTENT:
133 final boolean isVirtual = (docFlags & Document.FLAG_VIRTUAL_DOCUMENT) != 0;
134 if (isVirtual && mState.openableOnly) {
135 return false;
136 }
Steve McKayf69502c2015-11-09 17:38:35 +0900137 }
138
139 return MimePredicate.mimeMatches(mState.acceptMimes, docMimeType);
140 }
141
Steve McKayd3f6f142015-10-27 15:57:53 -0700142 @Override
Aga Wronska3b327ef2016-01-20 16:32:33 -0800143 public void updateActionMenu(Menu menu, int dirType, boolean canDelete,
144 boolean canRename) {
Steve McKayd3f6f142015-10-27 15:57:53 -0700145
146 boolean copyEnabled = dirType != DirectoryFragment.TYPE_RECENT_OPEN;
147 boolean moveEnabled =
148 SystemProperties.getBoolean("debug.documentsui.enable_move", false);
149 menu.findItem(R.id.menu_copy_to_clipboard).setEnabled(copyEnabled);
150
151 final MenuItem open = menu.findItem(R.id.menu_open);
152 final MenuItem share = menu.findItem(R.id.menu_share);
153 final MenuItem delete = menu.findItem(R.id.menu_delete);
154 final MenuItem copyTo = menu.findItem(R.id.menu_copy_to);
155 final MenuItem moveTo = menu.findItem(R.id.menu_move_to);
Aga Wronska3b327ef2016-01-20 16:32:33 -0800156 final MenuItem rename = menu.findItem(R.id.menu_rename);
Steve McKayd3f6f142015-10-27 15:57:53 -0700157
158 open.setVisible(true);
159 share.setVisible(false);
160 delete.setVisible(false);
161 copyTo.setVisible(copyEnabled);
162 copyTo.setEnabled(copyEnabled);
163 moveTo.setVisible(moveEnabled);
164 moveTo.setEnabled(moveEnabled);
Aga Wronska3b327ef2016-01-20 16:32:33 -0800165 rename.setVisible(false);
Steve McKayd3f6f142015-10-27 15:57:53 -0700166 }
Steve McKayaa15dae2016-02-09 16:17:24 -0800167
168 @Override
Aga Wronska893390b2016-02-17 13:50:42 -0800169 void onModelLoaded(Model model, @ResultType int resultType, boolean isSearch) {
Steve McKayaa15dae2016-02-09 16:17:24 -0800170 // When launched into empty recents, show drawer
171 if (resultType == DirectoryFragment.TYPE_RECENT_OPEN
172 && model.isEmpty()
173 && !mState.hasLocationChanged()) {
174 ((DocumentsActivity) mContext).setRootsDrawerOpen(true);
175 }
176 }
Steve McKayd3f6f142015-10-27 15:57:53 -0700177 }
178
179 /**
180 * Provides support for Platform specific specializations of DirectoryFragment.
181 */
Steve McKayf69502c2015-11-09 17:38:35 +0900182 private static final class DownloadsTuner extends FragmentTuner {
183
Steve McKayaa15dae2016-02-09 16:17:24 -0800184 public DownloadsTuner(Context context, State state) {
185 super(context, state);
Steve McKayf69502c2015-11-09 17:38:35 +0900186 }
Steve McKayd3f6f142015-10-27 15:57:53 -0700187
188 @Override
Aga Wronska3b327ef2016-01-20 16:32:33 -0800189 public void updateActionMenu(Menu menu, int dirType, boolean canDelete,
190 boolean canRename) {
Steve McKayd3f6f142015-10-27 15:57:53 -0700191 checkArgument(dirType != DirectoryFragment.TYPE_RECENT_OPEN);
192
193 boolean moveEnabled =
194 SystemProperties.getBoolean("debug.documentsui.enable_move", false);
195 menu.findItem(R.id.menu_copy_to_clipboard).setEnabled(true);
196
197 final MenuItem open = menu.findItem(R.id.menu_open);
198 final MenuItem share = menu.findItem(R.id.menu_share);
199 final MenuItem delete = menu.findItem(R.id.menu_delete);
200 final MenuItem copyTo = menu.findItem(R.id.menu_copy_to);
201 final MenuItem moveTo = menu.findItem(R.id.menu_move_to);
Aga Wronska3b327ef2016-01-20 16:32:33 -0800202 final MenuItem rename = menu.findItem(R.id.menu_rename);
Steve McKayd3f6f142015-10-27 15:57:53 -0700203
204 open.setVisible(false);
Steve McKayd3f6f142015-10-27 15:57:53 -0700205 delete.setVisible(canDelete);
206 copyTo.setVisible(true);
207 copyTo.setEnabled(true);
208 moveTo.setVisible(moveEnabled);
209 moveTo.setEnabled(moveEnabled);
Aga Wronska3b327ef2016-01-20 16:32:33 -0800210 rename.setVisible(false);
Steve McKayd3f6f142015-10-27 15:57:53 -0700211 }
Steve McKayaa15dae2016-02-09 16:17:24 -0800212
213 @Override
Aga Wronska893390b2016-02-17 13:50:42 -0800214 void onModelLoaded(Model model, @ResultType int resultType, boolean isSearch) {}
Steve McKayd3f6f142015-10-27 15:57:53 -0700215 }
216
217 /**
218 * Provides support for Files activity specific specializations of DirectoryFragment.
219 */
220 private static final class FilesTuner extends FragmentTuner {
Steve McKayf69502c2015-11-09 17:38:35 +0900221
Steve McKayaa15dae2016-02-09 16:17:24 -0800222 private static final String TAG = "FilesTuner";
223
224 public FilesTuner(Context context, State state) {
225 super(context, state);
Steve McKayf69502c2015-11-09 17:38:35 +0900226 }
227
Steve McKayd3f6f142015-10-27 15:57:53 -0700228 @Override
Aga Wronska3b327ef2016-01-20 16:32:33 -0800229 public void updateActionMenu(Menu menu, int dirType, boolean canDelete,
230 boolean canRename) {
Steve McKayd3f6f142015-10-27 15:57:53 -0700231
232 MenuItem copy = menu.findItem(R.id.menu_copy_to_clipboard);
233 MenuItem paste = menu.findItem(R.id.menu_paste_from_clipboard);
234 copy.setEnabled(dirType != DirectoryFragment.TYPE_RECENT_OPEN);
235
Aga Wronska3b327ef2016-01-20 16:32:33 -0800236 MenuItem rename = menu.findItem(R.id.menu_rename);
237 rename.setVisible(true);
238 rename.setEnabled(canRename);
239
Steve McKayd3f6f142015-10-27 15:57:53 -0700240 menu.findItem(R.id.menu_share).setVisible(true);
241 menu.findItem(R.id.menu_delete).setVisible(canDelete);
242
243 menu.findItem(R.id.menu_open).setVisible(false);
244 menu.findItem(R.id.menu_copy_to).setVisible(true);
245 menu.findItem(R.id.menu_move_to).setVisible(true);
246
247 Menus.disableHiddenItems(menu, copy, paste);
248 }
Steve McKayaa15dae2016-02-09 16:17:24 -0800249
250 @Override
Aga Wronska893390b2016-02-17 13:50:42 -0800251 void onModelLoaded(Model model, @ResultType int resultType, boolean isSearch) {
Aga Wronskad4b17532016-02-12 09:15:32 -0800252 if (DEBUG) Log.d(TAG, "Handling model loaded. Has Location shcnage: " + mState.initialLocationHasChanged());
Steve McKayaa15dae2016-02-09 16:17:24 -0800253 // When launched into empty root, open drawer.
Aga Wronska893390b2016-02-17 13:50:42 -0800254 if (model.isEmpty() && !mState.initialLocationHasChanged() && !isSearch) {
Steve McKayaa15dae2016-02-09 16:17:24 -0800255 if (DEBUG) Log.d(TAG, "Showing roots drawer cuz stuffs empty.");
256
257 // This noops on layouts without drawer, so no need to guard.
258 ((FilesActivity) mContext).setRootsDrawerOpen(true);
259 }
260 if (DEBUG) Log.d(TAG, "Donezo.");
261 }
Steve McKayd3f6f142015-10-27 15:57:53 -0700262 }
Steve McKayf69502c2015-11-09 17:38:35 +0900263
264 private static boolean isDirectory(String mimeType) {
265 return Document.MIME_TYPE_DIR.equals(mimeType);
266 }
Steve McKayaa15dae2016-02-09 16:17:24 -0800267
Steve McKayd3f6f142015-10-27 15:57:53 -0700268}