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 package com.android.documentsui; 17 18 import static com.android.documentsui.base.SharedMinimal.DEBUG; 19 20 import android.util.Log; 21 import android.view.KeyEvent; 22 23 import androidx.recyclerview.selection.SelectionTracker; 24 25 import com.android.documentsui.base.Events; 26 import com.android.documentsui.base.Features; 27 import com.android.documentsui.base.Procedure; 28 import com.android.documentsui.dirlist.FocusHandler; 29 30 /** 31 * Handle common input events. 32 */ 33 public class SharedInputHandler { 34 35 private static final String TAG = "SharedInputHandler"; 36 37 private final FocusHandler mFocusManager; 38 private final Procedure mSearchCanceler; 39 private final Procedure mDirPopper; 40 private final Runnable mSearchExecutor; 41 private final Features mFeatures; 42 private final SelectionTracker<String> mSelectionMgr; 43 private final DrawerController mDrawer; 44 SharedInputHandler( FocusHandler focusHandler, SelectionTracker<String> selectionMgr, Procedure searchCanceler, Procedure dirPopper, Features features, DrawerController drawer, Runnable searchExcutor)45 public SharedInputHandler( 46 FocusHandler focusHandler, 47 SelectionTracker<String> selectionMgr, 48 Procedure searchCanceler, 49 Procedure dirPopper, 50 Features features, 51 DrawerController drawer, 52 Runnable searchExcutor) { 53 mFocusManager = focusHandler; 54 mSearchCanceler = searchCanceler; 55 mSelectionMgr = selectionMgr; 56 mDirPopper = dirPopper; 57 mFeatures = features; 58 mDrawer = drawer; 59 mSearchExecutor = searchExcutor; 60 } 61 onKeyDown(int keyCode, KeyEvent event)62 public boolean onKeyDown(int keyCode, KeyEvent event) { 63 switch (keyCode) { 64 // Unhandled ESC keys end up being rethrown back at us as BACK keys. So by returning 65 // true, we make sure it always does no-op. 66 case KeyEvent.KEYCODE_ESCAPE: 67 return onEscape(); 68 69 case KeyEvent.KEYCODE_DEL: 70 return onDelete(); 71 72 // This is the Android back button, not backspace. 73 case KeyEvent.KEYCODE_BACK: 74 return onBack(); 75 76 case KeyEvent.KEYCODE_TAB: 77 return onTab(); 78 79 case KeyEvent.KEYCODE_SEARCH: 80 mSearchExecutor.run(); 81 return true; 82 83 default: 84 // Instead of duplicating the switch-case in #isNavigationKeyCode, best just to 85 // leave it here. 86 if (Events.isNavigationKeyCode(keyCode)) { 87 // Forward all unclaimed navigation keystrokes to the directory list. 88 // This causes any stray navigation keystrokes to focus the content pane, 89 // which is probably what the user is trying to do. 90 mFocusManager.focusDirectoryList(); 91 return true; 92 } 93 return false; 94 } 95 } 96 onTab()97 private boolean onTab() { 98 if (!mFeatures.isSystemKeyboardNavigationEnabled()) { 99 // Tab toggles focus on the navigation drawer. 100 // This should only be called in pre-O devices, since O has built-in keyboard 101 // navigation 102 // support. 103 mFocusManager.advanceFocusArea(); 104 return true; 105 } 106 107 return false; 108 } 109 onDelete()110 private boolean onDelete() { 111 mDirPopper.run(); 112 return true; 113 } 114 onBack()115 private boolean onBack() { 116 if (mDrawer.isPresent() && mDrawer.isOpen()) { 117 mDrawer.setOpen(false); 118 return true; 119 } 120 121 if (mSearchCanceler.run()) { 122 return true; 123 } 124 125 if (mSelectionMgr.hasSelection()) { 126 if (DEBUG) { 127 Log.d(TAG, "Back pressed. Clearing existing selection."); 128 } 129 mSelectionMgr.clearSelection(); 130 return true; 131 } 132 133 return mDirPopper.run(); 134 } 135 onEscape()136 private boolean onEscape() { 137 if (mSearchCanceler.run()) { 138 return true; 139 } 140 141 if (mSelectionMgr.hasSelection()) { 142 if (DEBUG) { 143 Log.d(TAG, "ESC pressed. Clearing existing selection."); 144 } 145 mSelectionMgr.clearSelection(); 146 return true; 147 } 148 149 return true; 150 } 151 } 152