blob: f99ec85c358b1a304babcb1914705a24470eaccb [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
19import static com.android.documentsui.State.ACTION_BROWSE;
Steve McKayf69502c2015-11-09 17:38:35 +090020import static com.android.documentsui.State.ACTION_CREATE;
21import static com.android.documentsui.State.ACTION_GET_CONTENT;
Steve McKayd3f6f142015-10-27 15:57:53 -070022import static com.android.documentsui.State.ACTION_MANAGE;
Steve McKayf69502c2015-11-09 17:38:35 +090023import static com.android.documentsui.State.ACTION_OPEN;
24import static com.android.documentsui.State.ACTION_OPEN_TREE;
Steve McKayd3f6f142015-10-27 15:57:53 -070025
Steve McKayaa15dae2016-02-09 16:17:24 -080026import android.content.Context;
Steve McKayaa15dae2016-02-09 16:17:24 -080027import android.provider.DocumentsContract.Document;
Steve McKayaa15dae2016-02-09 16:17:24 -080028import android.view.Menu;
29import android.view.MenuItem;
30
Steve McKayc95d87c2016-02-23 14:34:50 -080031import com.android.documentsui.BaseActivity;
Steve McKayd3f6f142015-10-27 15:57:53 -070032import com.android.documentsui.Menus;
Steve McKayf69502c2015-11-09 17:38:35 +090033import com.android.documentsui.MimePredicate;
Steve McKayd3f6f142015-10-27 15:57:53 -070034import com.android.documentsui.R;
35import com.android.documentsui.State;
Steve McKayaa15dae2016-02-09 16:17:24 -080036import com.android.documentsui.dirlist.DirectoryFragment.ResultType;
Steve McKayf69502c2015-11-09 17:38:35 +090037
Steve McKayd3f6f142015-10-27 15:57:53 -070038/**
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.
41 */
42public abstract class FragmentTuner {
Steve McKayf69502c2015-11-09 17:38:35 +090043
Steve McKayaa15dae2016-02-09 16:17:24 -080044 final Context mContext;
Steve McKayf69502c2015-11-09 17:38:35 +090045 final State mState;
46
Steve McKayaa15dae2016-02-09 16:17:24 -080047 public FragmentTuner(Context context, State state) {
48 mContext = context;
Steve McKayf69502c2015-11-09 17:38:35 +090049 mState = state;
50 }
51
Steve McKayaa15dae2016-02-09 16:17:24 -080052 public static FragmentTuner pick(Context context, State state) {
Steve McKayd3f6f142015-10-27 15:57:53 -070053 switch (state.action) {
54 case ACTION_BROWSE:
Steve McKayaa15dae2016-02-09 16:17:24 -080055 return new FilesTuner(context, state);
Steve McKayd3f6f142015-10-27 15:57:53 -070056 case ACTION_MANAGE:
Steve McKayaa15dae2016-02-09 16:17:24 -080057 return new DownloadsTuner(context, state);
Steve McKayd3f6f142015-10-27 15:57:53 -070058 default:
Steve McKayaa15dae2016-02-09 16:17:24 -080059 return new DocumentsTuner(context, state);
Steve McKayd3f6f142015-10-27 15:57:53 -070060 }
61 }
62
Steve McKayf69502c2015-11-09 17:38:35 +090063
Steve McKay27d20a32016-02-22 18:38:09 -080064 public abstract void updateActionMenu(
65 Menu menu, @ResultType int dirType, boolean canDelete, boolean canRename);
Steve McKayd3f6f142015-10-27 15:57:53 -070066
Steve McKayf69502c2015-11-09 17:38:35 +090067 // Subtly different from isDocumentEnabled. The reason may be illuminated as follows.
68 // A folder is enabled such that it may be double clicked, even in settings
69 // when the folder itself cannot be selected. This may also be true of container types.
Tomasz Mikolajewskia8057a92015-11-16 11:41:28 +090070 public boolean canSelectType(String docMimeType, int docFlags) {
Steve McKayf69502c2015-11-09 17:38:35 +090071 return true;
72 }
73
74 public boolean isDocumentEnabled(String docMimeType, int docFlags) {
75 if (isDirectory(docMimeType)) {
76 return true;
77 }
78
79 return MimePredicate.mimeMatches(mState.acceptMimes, docMimeType);
80 }
81
Aga Wronska893390b2016-02-17 13:50:42 -080082 abstract void onModelLoaded(Model model, @ResultType int resultType, boolean isSearch);
Steve McKayaa15dae2016-02-09 16:17:24 -080083
Steve McKayd3f6f142015-10-27 15:57:53 -070084 /**
85 * Provides support for Platform specific specializations of DirectoryFragment.
86 */
87 private static final class DocumentsTuner extends FragmentTuner {
Steve McKayf69502c2015-11-09 17:38:35 +090088
Steve McKayaa15dae2016-02-09 16:17:24 -080089 public DocumentsTuner(Context context, State state) {
90 super(context, state);
Steve McKayf69502c2015-11-09 17:38:35 +090091 }
92
93 @Override
Tomasz Mikolajewskia8057a92015-11-16 11:41:28 +090094 public boolean canSelectType(String docMimeType, int docFlags) {
95 if (!isDocumentEnabled(docMimeType, docFlags)) {
96 return false;
Steve McKayf69502c2015-11-09 17:38:35 +090097 }
Tomasz Mikolajewskia8057a92015-11-16 11:41:28 +090098
99 if (isDirectory(docMimeType)) {
100 return false;
101 }
102
103 if (mState.action == ACTION_OPEN_TREE) {
104 // In this case nothing *ever* is selectable...the expected user behavior is
105 // they navigate *into* a folder, then click a confirmation button indicating
106 // that the current directory is the directory they are picking.
107 return false;
108 }
109
Steve McKayf69502c2015-11-09 17:38:35 +0900110 return true;
111 }
112
113 @Override
114 public boolean isDocumentEnabled(String docMimeType, int docFlags) {
Tomasz Mikolajewskia8057a92015-11-16 11:41:28 +0900115 // Directories are always enabled.
Steve McKayf69502c2015-11-09 17:38:35 +0900116 if (isDirectory(docMimeType)) {
117 return true;
118 }
119
Tomasz Mikolajewskia8057a92015-11-16 11:41:28 +0900120 switch (mState.action) {
121 case ACTION_CREATE:
122 // Read-only files are disabled when creating.
123 if ((docFlags & Document.FLAG_SUPPORTS_WRITE) == 0) {
124 return false;
125 }
126 case ACTION_OPEN:
127 case ACTION_GET_CONTENT:
128 final boolean isVirtual = (docFlags & Document.FLAG_VIRTUAL_DOCUMENT) != 0;
129 if (isVirtual && mState.openableOnly) {
130 return false;
131 }
Steve McKayf69502c2015-11-09 17:38:35 +0900132 }
133
134 return MimePredicate.mimeMatches(mState.acceptMimes, docMimeType);
135 }
136
Steve McKayd3f6f142015-10-27 15:57:53 -0700137 @Override
Steve McKay27d20a32016-02-22 18:38:09 -0800138 public void updateActionMenu(
139 Menu menu, @ResultType int dirType, boolean canDelete, boolean canRename) {
Steve McKayd3f6f142015-10-27 15:57:53 -0700140
Steve McKay27d20a32016-02-22 18:38:09 -0800141 MenuItem open = menu.findItem(R.id.menu_open);
142 MenuItem share = menu.findItem(R.id.menu_share);
143 MenuItem delete = menu.findItem(R.id.menu_delete);
144 MenuItem rename = menu.findItem(R.id.menu_rename);
Steve McKayd3f6f142015-10-27 15:57:53 -0700145
146 open.setVisible(true);
147 share.setVisible(false);
148 delete.setVisible(false);
Aga Wronska3b327ef2016-01-20 16:32:33 -0800149 rename.setVisible(false);
Steve McKayd3f6f142015-10-27 15:57:53 -0700150 }
Steve McKayaa15dae2016-02-09 16:17:24 -0800151
152 @Override
Aga Wronska893390b2016-02-17 13:50:42 -0800153 void onModelLoaded(Model model, @ResultType int resultType, boolean isSearch) {
Steve McKayc95d87c2016-02-23 14:34:50 -0800154 // When launched into empty root, open drawer.
155 if (model.isEmpty() && !mState.hasInitialLocationChanged() && !isSearch) {
156 // This noops on layouts without drawer, so no need to guard.
157 ((BaseActivity) mContext).setRootsDrawerOpen(true);
Steve McKayaa15dae2016-02-09 16:17:24 -0800158 }
159 }
Steve McKayd3f6f142015-10-27 15:57:53 -0700160 }
161
162 /**
163 * Provides support for Platform specific specializations of DirectoryFragment.
164 */
Steve McKayf69502c2015-11-09 17:38:35 +0900165 private static final class DownloadsTuner extends FragmentTuner {
166
Steve McKayaa15dae2016-02-09 16:17:24 -0800167 public DownloadsTuner(Context context, State state) {
168 super(context, state);
Steve McKayf69502c2015-11-09 17:38:35 +0900169 }
Steve McKayd3f6f142015-10-27 15:57:53 -0700170
171 @Override
Steve McKay27d20a32016-02-22 18:38:09 -0800172 public void updateActionMenu(
173 Menu menu, @ResultType int resultType, boolean canDelete, boolean canRename) {
Steve McKaya1f76802016-02-25 13:34:03 -0800174 assert(resultType != DirectoryFragment.TYPE_RECENT_OPEN);
Steve McKayd3f6f142015-10-27 15:57:53 -0700175
Steve McKay27d20a32016-02-22 18:38:09 -0800176 MenuItem open = menu.findItem(R.id.menu_open);
177 MenuItem delete = menu.findItem(R.id.menu_delete);
178 MenuItem copyTo = menu.findItem(R.id.menu_copy_to);
179 MenuItem moveTo = menu.findItem(R.id.menu_move_to);
180 MenuItem rename = menu.findItem(R.id.menu_rename);
181 MenuItem copy = menu.findItem(R.id.menu_copy_to_clipboard);
Steve McKayd3f6f142015-10-27 15:57:53 -0700182
183 open.setVisible(false);
Steve McKayd3f6f142015-10-27 15:57:53 -0700184 delete.setVisible(canDelete);
Steve McKay27d20a32016-02-22 18:38:09 -0800185 copy.setEnabled(true); // to clipboard
Steve McKayd3f6f142015-10-27 15:57:53 -0700186 copyTo.setVisible(true);
187 copyTo.setEnabled(true);
Steve McKay27d20a32016-02-22 18:38:09 -0800188 moveTo.setVisible(true);
189 moveTo.setEnabled(true);
Aga Wronska3b327ef2016-01-20 16:32:33 -0800190 rename.setVisible(false);
Steve McKayd3f6f142015-10-27 15:57:53 -0700191 }
Steve McKayaa15dae2016-02-09 16:17:24 -0800192
193 @Override
Aga Wronska893390b2016-02-17 13:50:42 -0800194 void onModelLoaded(Model model, @ResultType int resultType, boolean isSearch) {}
Steve McKayd3f6f142015-10-27 15:57:53 -0700195 }
196
197 /**
198 * Provides support for Files activity specific specializations of DirectoryFragment.
199 */
200 private static final class FilesTuner extends FragmentTuner {
Steve McKayf69502c2015-11-09 17:38:35 +0900201
Steve McKayaa15dae2016-02-09 16:17:24 -0800202 public FilesTuner(Context context, State state) {
203 super(context, state);
Steve McKayf69502c2015-11-09 17:38:35 +0900204 }
205
Steve McKayd3f6f142015-10-27 15:57:53 -0700206 @Override
Steve McKay27d20a32016-02-22 18:38:09 -0800207 public void updateActionMenu(
208 Menu menu, @ResultType int dirType, boolean canDelete, boolean canRename) {
Steve McKayd3f6f142015-10-27 15:57:53 -0700209
210 MenuItem copy = menu.findItem(R.id.menu_copy_to_clipboard);
211 MenuItem paste = menu.findItem(R.id.menu_paste_from_clipboard);
212 copy.setEnabled(dirType != DirectoryFragment.TYPE_RECENT_OPEN);
213
Aga Wronska3b327ef2016-01-20 16:32:33 -0800214 MenuItem rename = menu.findItem(R.id.menu_rename);
215 rename.setVisible(true);
216 rename.setEnabled(canRename);
217
Steve McKayd3f6f142015-10-27 15:57:53 -0700218 menu.findItem(R.id.menu_share).setVisible(true);
219 menu.findItem(R.id.menu_delete).setVisible(canDelete);
Steve McKayd3f6f142015-10-27 15:57:53 -0700220 menu.findItem(R.id.menu_open).setVisible(false);
221 menu.findItem(R.id.menu_copy_to).setVisible(true);
222 menu.findItem(R.id.menu_move_to).setVisible(true);
Steve McKay27d20a32016-02-22 18:38:09 -0800223 menu.findItem(R.id.menu_move_to).setEnabled(canDelete);
Steve McKayd3f6f142015-10-27 15:57:53 -0700224
225 Menus.disableHiddenItems(menu, copy, paste);
226 }
Steve McKayaa15dae2016-02-09 16:17:24 -0800227
228 @Override
Aga Wronska893390b2016-02-17 13:50:42 -0800229 void onModelLoaded(Model model, @ResultType int resultType, boolean isSearch) {
Steve McKayaa15dae2016-02-09 16:17:24 -0800230 // When launched into empty root, open drawer.
Steve McKayc95d87c2016-02-23 14:34:50 -0800231 if (model.isEmpty() && !mState.hasInitialLocationChanged() && !isSearch) {
Steve McKayaa15dae2016-02-09 16:17:24 -0800232 // This noops on layouts without drawer, so no need to guard.
Steve McKayc95d87c2016-02-23 14:34:50 -0800233 ((BaseActivity) mContext).setRootsDrawerOpen(true);
Steve McKayaa15dae2016-02-09 16:17:24 -0800234 }
Steve McKayaa15dae2016-02-09 16:17:24 -0800235 }
Steve McKayd3f6f142015-10-27 15:57:53 -0700236 }
Steve McKayf69502c2015-11-09 17:38:35 +0900237
238 private static boolean isDirectory(String mimeType) {
239 return Document.MIME_TYPE_DIR.equals(mimeType);
240 }
Steve McKayd3f6f142015-10-27 15:57:53 -0700241}