1/*
2 * Copyright (C) 2016 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.files;
18
19import android.app.Fragment;
20import android.content.Context;
21import android.content.res.Resources;
22import android.net.Uri;
23import android.view.KeyEvent;
24import android.view.KeyboardShortcutGroup;
25import android.view.KeyboardShortcutInfo;
26import android.view.Menu;
27import android.view.MenuInflater;
28import android.view.MenuItem;
29import android.view.View;
30
31import com.android.documentsui.R;
32import com.android.documentsui.base.DocumentInfo;
33import com.android.documentsui.base.Features;
34import com.android.documentsui.base.Lookup;
35import com.android.documentsui.base.RootInfo;
36import com.android.documentsui.base.State;
37import com.android.documentsui.queries.SearchViewManager;
38import com.android.documentsui.selection.SelectionManager;
39
40import java.util.List;
41import java.util.function.Function;
42import java.util.function.IntFunction;
43
44public final class MenuManager extends com.android.documentsui.MenuManager {
45
46    private final Features mFeatures;
47    private final Context mContext;
48    private final SelectionManager mSelectionManager;
49    private final Lookup<String, Uri> mUriLookup;
50    private final Lookup<String, String> mAppNameLookup;
51
52    public MenuManager(
53            Features features,
54            SearchViewManager searchManager,
55            State displayState,
56            DirectoryDetails dirDetails,
57            Context context,
58            SelectionManager selectionManager,
59            Lookup<String, String> appNameLookup,
60            Lookup<String, Uri> uriLookup) {
61        super(searchManager, displayState, dirDetails);
62        mFeatures = features;
63        mContext = context;
64        mSelectionManager = selectionManager;
65        mAppNameLookup = appNameLookup;
66        mUriLookup = uriLookup;
67    }
68
69    @Override
70    public void updateOptionMenu(Menu menu) {
71        super.updateOptionMenu(menu);
72
73        // It hides icon if searching in progress
74        mSearchManager.updateMenu();
75    }
76
77    @Override
78    public void updateKeyboardShortcutsMenu(
79            List<KeyboardShortcutGroup> data, IntFunction<String> stringSupplier) {
80        KeyboardShortcutGroup group = new KeyboardShortcutGroup(
81                stringSupplier.apply(R.string.app_label));
82        group.addItem(new KeyboardShortcutInfo(
83                stringSupplier.apply(R.string.menu_cut_to_clipboard), KeyEvent.KEYCODE_X,
84                KeyEvent.META_CTRL_ON));
85        group.addItem(new KeyboardShortcutInfo(
86                stringSupplier.apply(R.string.menu_copy_to_clipboard), KeyEvent.KEYCODE_C,
87                KeyEvent.META_CTRL_ON));
88        group.addItem(new KeyboardShortcutInfo(
89                stringSupplier.apply(R.string.menu_paste_from_clipboard), KeyEvent.KEYCODE_V,
90                KeyEvent.META_CTRL_ON));
91        group.addItem(new KeyboardShortcutInfo(
92                stringSupplier.apply(R.string.menu_create_dir), KeyEvent.KEYCODE_E,
93                KeyEvent.META_CTRL_ON));
94        group.addItem(new KeyboardShortcutInfo(
95                stringSupplier.apply(R.string.menu_select_all), KeyEvent.KEYCODE_A,
96                KeyEvent.META_CTRL_ON));
97        group.addItem(new KeyboardShortcutInfo(
98                stringSupplier.apply(R.string.menu_new_window), KeyEvent.KEYCODE_N,
99                KeyEvent.META_CTRL_ON));
100        data.add(group);
101    }
102
103    @Override
104    public void showContextMenu(Fragment f, View v, float x, float y) {
105        // Register context menu here so long-press doesn't trigger this context floating menu.
106        f.registerForContextMenu(v);
107        v.showContextMenu(x, y);
108        f.unregisterForContextMenu(v);
109    }
110
111    @Override
112    public void inflateContextMenuForContainer(Menu menu, MenuInflater inflater) {
113        inflater.inflate(R.menu.container_context_menu, menu);
114        updateContextMenuForContainer(menu);
115    }
116
117    @Override
118    public void inflateContextMenuForDocs(
119            Menu menu, MenuInflater inflater, SelectionDetails selectionDetails) {
120        final boolean hasDir = selectionDetails.containsDirectories();
121        final boolean hasFile = selectionDetails.containsFiles();
122
123        assert(hasDir || hasFile);
124        if (!hasDir) {
125            inflater.inflate(R.menu.file_context_menu, menu);
126            updateContextMenuForFiles(menu, selectionDetails);
127            return;
128        }
129
130        if (!hasFile) {
131            inflater.inflate(R.menu.dir_context_menu, menu);
132            updateContextMenuForDirs(menu, selectionDetails);
133            return;
134        }
135
136        inflater.inflate(R.menu.mixed_context_menu, menu);
137        updateContextMenu(menu, selectionDetails);
138    }
139
140    @Override
141    protected void updateSettings(MenuItem settings, RootInfo root) {
142        settings.setVisible(true);
143        settings.setEnabled(root.hasSettings());
144    }
145
146    @Override
147    protected void updateEject(MenuItem eject, RootInfo root) {
148        eject.setVisible(root.supportsEject());
149        eject.setEnabled(!root.ejecting);
150    }
151
152    @Override
153    protected void updateSettings(MenuItem settings) {
154        boolean enabled = mDirDetails.hasRootSettings();
155        settings.setVisible(enabled);
156        settings.setEnabled(enabled);
157    }
158
159    @Override
160    protected void updateNewWindow(MenuItem newWindow) {
161        newWindow.setVisible(true);
162    }
163
164    @Override
165    protected void updateOpenInContextMenu(MenuItem open, SelectionDetails selectionDetails) {
166        open.setVisible(true);
167        open.setEnabled(selectionDetails.size() == 1
168                && !selectionDetails.containsPartialFiles());
169    }
170
171    @Override
172    protected void updateOpenWith(MenuItem openWith, SelectionDetails selectionDetails) {
173        openWith.setVisible(true);
174        openWith.setEnabled(selectionDetails.canOpenWith());
175    }
176
177    @Override
178    protected void updateOpenInNewWindow(
179            MenuItem openInNewWindow, SelectionDetails selectionDetails) {
180        openInNewWindow.setVisible(true);
181        openInNewWindow.setEnabled(selectionDetails.size() == 1
182            && !selectionDetails.containsPartialFiles());
183    }
184
185    @Override
186    protected void updateOpenInNewWindow(MenuItem openInNewWindow, RootInfo root) {
187        assert(openInNewWindow.isVisible() && openInNewWindow.isEnabled());
188    }
189
190    @Override
191    protected void updateMoveTo(MenuItem moveTo, SelectionDetails selectionDetails) {
192        moveTo.setVisible(true);
193        moveTo.setEnabled(!selectionDetails.containsPartialFiles() && selectionDetails.canDelete());
194    }
195
196    @Override
197    protected void updateCopyTo(MenuItem copyTo, SelectionDetails selectionDetails) {
198        copyTo.setVisible(true);
199        copyTo.setEnabled(!selectionDetails.containsPartialFiles() &&
200                !selectionDetails.canExtract());
201    }
202
203    @Override
204    protected void updateCompress(MenuItem compress, SelectionDetails selectionDetails) {
205        final boolean readOnly = !mDirDetails.canCreateDoc();
206        compress.setVisible(mFeatures.isArchiveCreationEnabled());
207        compress.setEnabled(!readOnly && !selectionDetails.containsPartialFiles() &&
208                !selectionDetails.canExtract());
209    }
210
211    @Override
212    protected void updateExtractTo(MenuItem extractTo, SelectionDetails selectionDetails) {
213        boolean enabled = selectionDetails.canExtract();
214        extractTo.setVisible(enabled);
215        extractTo.setEnabled(enabled);
216    }
217
218    @Override
219    protected void updatePasteInto(MenuItem pasteInto, SelectionDetails selectionDetails) {
220        pasteInto.setVisible(true);
221        pasteInto.setEnabled(selectionDetails.canPasteInto() && mDirDetails.hasItemsToPaste());
222    }
223
224    @Override
225    protected void updatePasteInto(MenuItem pasteInto, RootInfo root, DocumentInfo docInfo) {
226        pasteInto.setVisible(true);
227        pasteInto.setEnabled(root.supportsCreate()
228                && docInfo != null
229                && docInfo.isCreateSupported()
230                && mDirDetails.hasItemsToPaste());
231    }
232
233    @Override
234    protected void updateSelectAll(MenuItem selectAll) {
235        selectAll.setVisible(true);
236        selectAll.setEnabled(true);
237    }
238
239    @Override
240    protected void updateCreateDir(MenuItem createDir) {
241        createDir.setVisible(true);
242        createDir.setEnabled(mDirDetails.canCreateDirectory());
243    }
244
245    @Override
246    protected void updateShare(MenuItem share, SelectionDetails selectionDetails) {
247        boolean enabled = !selectionDetails.containsDirectories()
248                && !selectionDetails.containsPartialFiles()
249                && !selectionDetails.canExtract();
250        share.setVisible(enabled);
251        share.setEnabled(enabled);
252    }
253
254    @Override
255    protected void updateDelete(MenuItem delete, SelectionDetails selectionDetails) {
256        boolean enabled = selectionDetails.canDelete();
257        delete.setVisible(enabled);
258        delete.setEnabled(enabled);
259    }
260
261    @Override
262    protected void updateRename(MenuItem rename, SelectionDetails selectionDetails) {
263        rename.setVisible(true);
264        rename.setEnabled(!selectionDetails.containsPartialFiles() && selectionDetails.canRename());
265    }
266
267    @Override
268    protected void updateInspector(MenuItem properties, SelectionDetails selectionDetails) {
269        boolean visible = mFeatures.isInspectorEnabled();
270        properties.setVisible(visible);
271        properties.setEnabled(visible && selectionDetails.size() == 1);
272    }
273
274    @Override
275    protected void updateViewInOwner(MenuItem view, SelectionDetails selectionDetails) {
276        if (selectionDetails.canViewInOwner()) {
277            view.setVisible(true);
278            view.setEnabled(true);
279            Resources res = mContext.getResources();
280            String selectedModelId = mSelectionManager.getSelection().iterator().next();
281            Uri selectedUri = mUriLookup.lookup(selectedModelId);
282            String appName = mAppNameLookup.lookup(selectedUri.getAuthority());
283            String title = res.getString(R.string.menu_view_in_owner, appName);
284            view.setTitle(title);
285        }
286        else {
287            view.setVisible(false);
288        }
289    }
290}
291