Home | History | Annotate | Download | only in documentsui
      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 
     17 package com.android.documentsui;
     18 
     19 import android.app.Fragment;
     20 import android.view.KeyboardShortcutGroup;
     21 import android.view.Menu;
     22 import android.view.MenuInflater;
     23 import android.view.MenuItem;
     24 import android.view.View;
     25 
     26 import com.android.documentsui.base.DocumentInfo;
     27 import com.android.documentsui.base.Menus;
     28 import com.android.documentsui.base.RootInfo;
     29 import com.android.documentsui.base.State;
     30 import com.android.documentsui.dirlist.DirectoryFragment;
     31 import com.android.documentsui.queries.SearchViewManager;
     32 import com.android.documentsui.sidebar.RootsFragment;
     33 import com.android.internal.annotations.VisibleForTesting;
     34 
     35 import java.util.List;
     36 import java.util.function.IntFunction;
     37 
     38 public abstract class MenuManager {
     39 
     40     final protected SearchViewManager mSearchManager;
     41     final protected State mState;
     42     final protected DirectoryDetails mDirDetails;
     43 
     44     public MenuManager(
     45             SearchViewManager searchManager,
     46             State displayState,
     47             DirectoryDetails dirDetails) {
     48         mSearchManager = searchManager;
     49         mState = displayState;
     50         mDirDetails = dirDetails;
     51     }
     52 
     53     /** @see ActionModeController */
     54     public void updateActionMenu(Menu menu, SelectionDetails selection) {
     55         updateOpenInActionMode(menu.findItem(R.id.action_menu_open), selection);
     56         updateOpenWith(menu.findItem(R.id.action_menu_open_with), selection);
     57         updateDelete(menu.findItem(R.id.action_menu_delete), selection);
     58         updateShare(menu.findItem(R.id.action_menu_share), selection);
     59         updateRename(menu.findItem(R.id.action_menu_rename), selection);
     60         updateSelectAll(menu.findItem(R.id.action_menu_select_all));
     61         updateMoveTo(menu.findItem(R.id.action_menu_move_to), selection);
     62         updateCopyTo(menu.findItem(R.id.action_menu_copy_to), selection);
     63         updateCompress(menu.findItem(R.id.action_menu_compress), selection);
     64         updateExtractTo(menu.findItem(R.id.action_menu_extract_to), selection);
     65         updateInspect(menu.findItem(R.id.action_menu_inspect), selection);
     66         updateViewInOwner(menu.findItem(R.id.action_menu_view_in_owner), selection);
     67 
     68         Menus.disableHiddenItems(menu);
     69     }
     70 
     71     /** @see BaseActivity#onPrepareOptionsMenu */
     72     public void updateOptionMenu(Menu menu) {
     73         updateCreateDir(menu.findItem(R.id.option_menu_create_dir));
     74         updateSettings(menu.findItem(R.id.option_menu_settings));
     75         updateSelectAll(menu.findItem(R.id.option_menu_select_all));
     76         updateNewWindow(menu.findItem(R.id.option_menu_new_window));
     77         updateModePicker(menu.findItem(R.id.option_menu_grid),
     78                 menu.findItem(R.id.option_menu_list));
     79         updateAdvanced(menu.findItem(R.id.option_menu_advanced));
     80         updateDebug(menu.findItem(R.id.option_menu_debug));
     81         updateInspect(menu.findItem(R.id.option_menu_inspect));
     82         Menus.disableHiddenItems(menu);
     83     }
     84 
     85     /**
     86      * Called when we needs {@link MenuManager} to ask Android to show context menu for us.
     87      * {@link MenuManager} can choose to defeat this request.
     88      *
     89      * {@link #inflateContextMenuForDocs} and {@link #inflateContextMenuForContainer} are called
     90      * afterwards when Android asks us to provide the content of context menus, so they're not
     91      * correct locations to suppress context menus.
     92      */
     93     public void showContextMenu(Fragment f, View v, float x, float y) {
     94         // Pickers don't have any context menu at this moment.
     95     }
     96 
     97     public void inflateContextMenuForContainer(Menu menu, MenuInflater inflater) {
     98         throw new UnsupportedOperationException("Pickers don't allow context menu.");
     99     }
    100 
    101     public void inflateContextMenuForDocs(
    102             Menu menu, MenuInflater inflater, SelectionDetails selectionDetails) {
    103         throw new UnsupportedOperationException("Pickers don't allow context menu.");
    104     }
    105 
    106     /**
    107      * @see DirectoryFragment#onCreateContextMenu
    108      *
    109      * Called when user tries to generate a context menu anchored to a file when the selection
    110      * doesn't contain any folder.
    111      *
    112      * @param selectionDetails
    113      *      containsFiles may return false because this may be called when user right clicks on an
    114      *      unselectable item in pickers
    115      */
    116     @VisibleForTesting
    117     public void updateContextMenuForFiles(Menu menu, SelectionDetails selectionDetails) {
    118         assert selectionDetails != null;
    119 
    120         MenuItem share = menu.findItem(R.id.dir_menu_share);
    121         MenuItem open = menu.findItem(R.id.dir_menu_open);
    122         MenuItem openWith = menu.findItem(R.id.dir_menu_open_with);
    123         MenuItem rename = menu.findItem(R.id.dir_menu_rename);
    124         MenuItem viewInOwner = menu.findItem(R.id.dir_menu_view_in_owner);
    125 
    126         updateShare(share, selectionDetails);
    127         updateOpenInContextMenu(open, selectionDetails);
    128         updateOpenWith(openWith, selectionDetails);
    129         updateRename(rename, selectionDetails);
    130         updateViewInOwner(viewInOwner, selectionDetails);
    131 
    132         updateContextMenu(menu, selectionDetails);
    133     }
    134 
    135     /**
    136      * @see DirectoryFragment#onCreateContextMenu
    137      *
    138      * Called when user tries to generate a context menu anchored to a folder when the selection
    139      * doesn't contain any file.
    140      *
    141      * @param selectionDetails
    142      *      containDirectories may return false because this may be called when user right clicks on
    143      *      an unselectable item in pickers
    144      */
    145     @VisibleForTesting
    146     public void updateContextMenuForDirs(Menu menu, SelectionDetails selectionDetails) {
    147         assert selectionDetails != null;
    148 
    149         MenuItem openInNewWindow = menu.findItem(R.id.dir_menu_open_in_new_window);
    150         MenuItem rename = menu.findItem(R.id.dir_menu_rename);
    151         MenuItem pasteInto = menu.findItem(R.id.dir_menu_paste_into_folder);
    152 
    153         updateOpenInNewWindow(openInNewWindow, selectionDetails);
    154         updateRename(rename, selectionDetails);
    155         updatePasteInto(pasteInto, selectionDetails);
    156 
    157         updateContextMenu(menu, selectionDetails);
    158     }
    159 
    160     /**
    161      * @see DirectoryFragment#onCreateContextMenu
    162      *
    163      * Update shared context menu items of both files and folders context menus.
    164      */
    165     @VisibleForTesting
    166     public void updateContextMenu(Menu menu, SelectionDetails selectionDetails) {
    167         assert selectionDetails != null;
    168 
    169         MenuItem cut = menu.findItem(R.id.dir_menu_cut_to_clipboard);
    170         MenuItem copy = menu.findItem(R.id.dir_menu_copy_to_clipboard);
    171         MenuItem delete = menu.findItem(R.id.dir_menu_delete);
    172         MenuItem inspect = menu.findItem(R.id.dir_menu_inspect);
    173 
    174         final boolean canCopy =
    175                 selectionDetails.size() > 0 && !selectionDetails.containsPartialFiles();
    176         final boolean canDelete = selectionDetails.canDelete();
    177         cut.setEnabled(canCopy && canDelete);
    178         copy.setEnabled(canCopy);
    179         delete.setEnabled(canDelete);
    180 
    181         inspect.setEnabled(selectionDetails.size() == 1);
    182     }
    183 
    184     /**
    185      * @see DirectoryFragment#onCreateContextMenu
    186      *
    187      * Called when user tries to generate a context menu anchored to an empty pane.
    188      */
    189     @VisibleForTesting
    190     public void updateContextMenuForContainer(Menu menu) {
    191         MenuItem paste = menu.findItem(R.id.dir_menu_paste_from_clipboard);
    192         MenuItem selectAll = menu.findItem(R.id.dir_menu_select_all);
    193         MenuItem createDir = menu.findItem(R.id.dir_menu_create_dir);
    194         MenuItem inspect = menu.findItem(R.id.dir_menu_inspect);
    195 
    196         paste.setEnabled(mDirDetails.hasItemsToPaste() && mDirDetails.canCreateDoc());
    197         updateSelectAll(selectAll);
    198         updateCreateDir(createDir);
    199         updateInspect(inspect);
    200     }
    201 
    202     /**
    203      * @see RootsFragment#onCreateContextMenu
    204      */
    205     public void updateRootContextMenu(Menu menu, RootInfo root, DocumentInfo docInfo) {
    206         MenuItem eject = menu.findItem(R.id.root_menu_eject_root);
    207         MenuItem pasteInto = menu.findItem(R.id.root_menu_paste_into_folder);
    208         MenuItem openInNewWindow = menu.findItem(R.id.root_menu_open_in_new_window);
    209         MenuItem settings = menu.findItem(R.id.root_menu_settings);
    210 
    211         updateEject(eject, root);
    212         updatePasteInto(pasteInto, root, docInfo);
    213         updateOpenInNewWindow(openInNewWindow, root);
    214         updateSettings(settings, root);
    215     }
    216 
    217     public abstract void updateKeyboardShortcutsMenu(
    218             List<KeyboardShortcutGroup> data, IntFunction<String> stringSupplier);
    219 
    220     protected void updateModePicker(MenuItem grid, MenuItem list) {
    221         grid.setVisible(mState.derivedMode != State.MODE_GRID);
    222         list.setVisible(mState.derivedMode != State.MODE_LIST);
    223     }
    224 
    225     protected void updateAdvanced(MenuItem advanced) {
    226         advanced.setVisible(mState.showDeviceStorageOption);
    227         advanced.setTitle(mState.showDeviceStorageOption && mState.showAdvanced
    228                 ? R.string.menu_advanced_hide : R.string.menu_advanced_show);
    229     }
    230 
    231     protected void updateDebug(MenuItem debug) {
    232         debug.setVisible(mState.debugMode);
    233     }
    234 
    235     protected void updateSettings(MenuItem settings) {
    236         settings.setVisible(false);
    237     }
    238 
    239     protected void updateSettings(MenuItem settings, RootInfo root) {
    240         settings.setVisible(false);
    241     }
    242 
    243     protected void updateEject(MenuItem eject, RootInfo root) {
    244         eject.setVisible(false);
    245     }
    246 
    247     protected void updateNewWindow(MenuItem newWindow) {
    248         newWindow.setVisible(false);
    249     }
    250 
    251     protected void updateOpenInActionMode(MenuItem open, SelectionDetails selectionDetails) {
    252         open.setVisible(false);
    253     }
    254 
    255     protected void updateOpenWith(MenuItem openWith, SelectionDetails selectionDetails) {
    256         openWith.setVisible(false);
    257     }
    258 
    259     protected void updateOpenInNewWindow(
    260             MenuItem openInNewWindow, SelectionDetails selectionDetails) {
    261         openInNewWindow.setVisible(false);
    262     }
    263 
    264     protected void updateOpenInNewWindow(
    265             MenuItem openInNewWindow, RootInfo root) {
    266         openInNewWindow.setVisible(false);
    267     }
    268 
    269     protected void updateShare(MenuItem share, SelectionDetails selectionDetails) {
    270         share.setVisible(false);
    271     }
    272 
    273     protected void updateDelete(MenuItem delete, SelectionDetails selectionDetails) {
    274         delete.setVisible(false);
    275     }
    276 
    277     protected void updateRename(MenuItem rename, SelectionDetails selectionDetails) {
    278         rename.setVisible(false);
    279     }
    280 
    281     /**
    282      * This method is called for standard activity option menu as opposed
    283      * to when there is a selection.
    284      */
    285     protected void updateInspect(MenuItem inspector) {
    286         inspector.setVisible(false);
    287     }
    288 
    289     /**
    290      * This method is called for action mode, when a selection exists.
    291      */
    292     protected void updateInspect(MenuItem inspect, SelectionDetails selectionDetails) {
    293         inspect.setVisible(false);
    294     }
    295 
    296     protected void updateViewInOwner(MenuItem view, SelectionDetails selectionDetails) {
    297         view.setVisible(false);
    298     }
    299 
    300     protected void updateMoveTo(MenuItem moveTo, SelectionDetails selectionDetails) {
    301         moveTo.setVisible(false);
    302     }
    303 
    304     protected void updateCopyTo(MenuItem copyTo, SelectionDetails selectionDetails) {
    305         copyTo.setVisible(false);
    306     }
    307 
    308     protected void updateCompress(MenuItem compress, SelectionDetails selectionDetails) {
    309         compress.setVisible(false);
    310     }
    311 
    312     protected void updateExtractTo(MenuItem extractTo, SelectionDetails selectionDetails) {
    313         extractTo.setVisible(false);
    314     }
    315 
    316     protected void updatePasteInto(MenuItem pasteInto, SelectionDetails selectionDetails) {
    317         pasteInto.setVisible(false);
    318     }
    319 
    320     protected void updatePasteInto(MenuItem pasteInto, RootInfo root, DocumentInfo docInfo) {
    321         pasteInto.setVisible(false);
    322     }
    323 
    324     protected abstract void updateOpenInContextMenu(
    325             MenuItem open, SelectionDetails selectionDetails);
    326     protected abstract void updateSelectAll(MenuItem selectAll);
    327     protected abstract void updateCreateDir(MenuItem createDir);
    328 
    329     /**
    330      * Access to meta data about the selection.
    331      */
    332     public interface SelectionDetails {
    333         boolean containsDirectories();
    334 
    335         boolean containsFiles();
    336 
    337         int size();
    338 
    339         boolean containsPartialFiles();
    340 
    341         boolean containsFilesInArchive();
    342 
    343         // TODO: Update these to express characteristics instead of answering concrete questions,
    344         // since the answer to those questions is (or can be) activity specific.
    345         boolean canDelete();
    346 
    347         boolean canRename();
    348 
    349         boolean canPasteInto();
    350 
    351         boolean canExtract();
    352 
    353         boolean canOpenWith();
    354 
    355         boolean canViewInOwner();
    356     }
    357 
    358     public static class DirectoryDetails {
    359         private final BaseActivity mActivity;
    360 
    361         public DirectoryDetails(BaseActivity activity) {
    362             mActivity = activity;
    363         }
    364 
    365         public boolean hasRootSettings() {
    366             return mActivity.getCurrentRoot().hasSettings();
    367         }
    368 
    369         public boolean hasItemsToPaste() {
    370             return false;
    371         }
    372 
    373         public boolean canCreateDoc() {
    374             return isInRecents() ? false : mActivity.getCurrentDirectory().isCreateSupported();
    375         }
    376 
    377         public boolean isInRecents() {
    378             return mActivity.getCurrentDirectory() == null;
    379         }
    380 
    381         public boolean canCreateDirectory() {
    382             return mActivity.canCreateDirectory();
    383         }
    384     }
    385 }
    386