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         updateViewInOwner(menu.findItem(R.id.action_menu_view_in_owner), selection);
     66         updateInspector(menu.findItem(R.id.action_menu_inspector), 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 
     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 
    173         final boolean canCopy =
    174                 selectionDetails.size() > 0 && !selectionDetails.containsPartialFiles();
    175         final boolean canDelete = selectionDetails.canDelete();
    176         cut.setEnabled(canCopy && canDelete);
    177         copy.setEnabled(canCopy);
    178         delete.setEnabled(canDelete);
    179     }
    180 
    181     /**
    182      * @see DirectoryFragment#onCreateContextMenu
    183      *
    184      * Called when user tries to generate a context menu anchored to an empty pane.
    185      */
    186     @VisibleForTesting
    187     public void updateContextMenuForContainer(Menu menu) {
    188         MenuItem paste = menu.findItem(R.id.dir_menu_paste_from_clipboard);
    189         MenuItem selectAll = menu.findItem(R.id.dir_menu_select_all);
    190         MenuItem createDir = menu.findItem(R.id.dir_menu_create_dir);
    191 
    192         paste.setEnabled(mDirDetails.hasItemsToPaste() && mDirDetails.canCreateDoc());
    193         updateSelectAll(selectAll);
    194         updateCreateDir(createDir);
    195     }
    196 
    197     /**
    198      * @see RootsFragment#onCreateContextMenu
    199      */
    200     public void updateRootContextMenu(Menu menu, RootInfo root, DocumentInfo docInfo) {
    201         MenuItem eject = menu.findItem(R.id.root_menu_eject_root);
    202         MenuItem pasteInto = menu.findItem(R.id.root_menu_paste_into_folder);
    203         MenuItem openInNewWindow = menu.findItem(R.id.root_menu_open_in_new_window);
    204         MenuItem settings = menu.findItem(R.id.root_menu_settings);
    205 
    206         updateEject(eject, root);
    207         updatePasteInto(pasteInto, root, docInfo);
    208         updateOpenInNewWindow(openInNewWindow, root);
    209         updateSettings(settings, root);
    210     }
    211 
    212     public abstract void updateKeyboardShortcutsMenu(
    213             List<KeyboardShortcutGroup> data, IntFunction<String> stringSupplier);
    214 
    215     protected void updateModePicker(MenuItem grid, MenuItem list) {
    216         grid.setVisible(mState.derivedMode != State.MODE_GRID);
    217         list.setVisible(mState.derivedMode != State.MODE_LIST);
    218     }
    219 
    220     protected void updateAdvanced(MenuItem advanced) {
    221         advanced.setVisible(mState.showDeviceStorageOption);
    222         advanced.setTitle(mState.showDeviceStorageOption && mState.showAdvanced
    223                 ? R.string.menu_advanced_hide : R.string.menu_advanced_show);
    224     }
    225 
    226     protected void updateDebug(MenuItem debug) {
    227         debug.setVisible(mState.debugMode);
    228     }
    229 
    230     protected void updateSettings(MenuItem settings) {
    231         settings.setVisible(false);
    232     }
    233 
    234     protected void updateSettings(MenuItem settings, RootInfo root) {
    235         settings.setVisible(false);
    236     }
    237 
    238     protected void updateEject(MenuItem eject, RootInfo root) {
    239         eject.setVisible(false);
    240     }
    241 
    242     protected void updateNewWindow(MenuItem newWindow) {
    243         newWindow.setVisible(false);
    244     }
    245 
    246     protected void updateOpenInActionMode(MenuItem open, SelectionDetails selectionDetails) {
    247         open.setVisible(false);
    248     }
    249 
    250     protected void updateOpenWith(MenuItem openWith, SelectionDetails selectionDetails) {
    251         openWith.setVisible(false);
    252     }
    253 
    254     protected void updateOpenInNewWindow(
    255             MenuItem openInNewWindow, SelectionDetails selectionDetails) {
    256         openInNewWindow.setVisible(false);
    257     }
    258 
    259     protected void updateOpenInNewWindow(
    260             MenuItem openInNewWindow, RootInfo root) {
    261         openInNewWindow.setVisible(false);
    262     }
    263 
    264     protected void updateShare(MenuItem share, SelectionDetails selectionDetails) {
    265         share.setVisible(false);
    266     }
    267 
    268     protected void updateDelete(MenuItem delete, SelectionDetails selectionDetails) {
    269         delete.setVisible(false);
    270     }
    271 
    272     protected void updateRename(MenuItem rename, SelectionDetails selectionDetails) {
    273         rename.setVisible(false);
    274     }
    275 
    276     protected void updateInspector(MenuItem properties, SelectionDetails selectionDetails) {
    277         properties.setVisible(false);
    278     }
    279 
    280     protected void updateViewInOwner(MenuItem view, SelectionDetails selectionDetails) {
    281         view.setVisible(false);
    282     }
    283 
    284     protected void updateMoveTo(MenuItem moveTo, SelectionDetails selectionDetails) {
    285         moveTo.setVisible(false);
    286     }
    287 
    288     protected void updateCopyTo(MenuItem copyTo, SelectionDetails selectionDetails) {
    289         copyTo.setVisible(false);
    290     }
    291 
    292     protected void updateCompress(MenuItem compress, SelectionDetails selectionDetails) {
    293         compress.setVisible(false);
    294     }
    295 
    296     protected void updateExtractTo(MenuItem extractTo, SelectionDetails selectionDetails) {
    297         extractTo.setVisible(false);
    298     }
    299 
    300     protected void updatePasteInto(MenuItem pasteInto, SelectionDetails selectionDetails) {
    301         pasteInto.setVisible(false);
    302     }
    303 
    304     protected void updatePasteInto(MenuItem pasteInto, RootInfo root, DocumentInfo docInfo) {
    305         pasteInto.setVisible(false);
    306     }
    307 
    308     protected abstract void updateOpenInContextMenu(
    309             MenuItem open, SelectionDetails selectionDetails);
    310     protected abstract void updateSelectAll(MenuItem selectAll);
    311     protected abstract void updateCreateDir(MenuItem createDir);
    312 
    313     /**
    314      * Access to meta data about the selection.
    315      */
    316     public interface SelectionDetails {
    317         boolean containsDirectories();
    318 
    319         boolean containsFiles();
    320 
    321         int size();
    322 
    323         boolean containsPartialFiles();
    324 
    325         boolean containsFilesInArchive();
    326 
    327         // TODO: Update these to express characteristics instead of answering concrete questions,
    328         // since the answer to those questions is (or can be) activity specific.
    329         boolean canDelete();
    330 
    331         boolean canRename();
    332 
    333         boolean canPasteInto();
    334 
    335         boolean canExtract();
    336 
    337         boolean canOpenWith();
    338 
    339         boolean canViewInOwner();
    340     }
    341 
    342     public static class DirectoryDetails {
    343         private final BaseActivity mActivity;
    344 
    345         public DirectoryDetails(BaseActivity activity) {
    346             mActivity = activity;
    347         }
    348 
    349         public boolean hasRootSettings() {
    350             return mActivity.getCurrentRoot().hasSettings();
    351         }
    352 
    353         public boolean hasItemsToPaste() {
    354             return false;
    355         }
    356 
    357         public boolean canCreateDoc() {
    358             return isInRecents() ? false : mActivity.getCurrentDirectory().isCreateSupported();
    359         }
    360 
    361         public boolean isInRecents() {
    362             return mActivity.getCurrentDirectory() == null;
    363         }
    364 
    365         public boolean canCreateDirectory() {
    366             return mActivity.canCreateDirectory();
    367         }
    368     }
    369 }
    370