summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Ben Lin <linben@google.com> 2017-03-13 18:25:29 -0700
committer Ben Lin <linben@google.com> 2017-03-15 16:55:42 -0700
commit0902f07dec9cfb0bd5d7c9c6222b433b91bf2051 (patch)
tree943fd8df9ea1380d267191b050c32453dc282f9c
parent390cd78b43643e42ebd177d0b55112ab66e9d963 (diff)
Moving back button behavior to SharedInputHandler, and now handling ESC keys.
Bug: 35674183 Change-Id: Ia6a5eb78f89ed1346aec81455dd6a721861bc6fa
-rw-r--r--src/com/android/documentsui/BaseActivity.java19
-rw-r--r--src/com/android/documentsui/SharedInputHandler.java101
-rw-r--r--src/com/android/documentsui/dirlist/DirectoryFragment.java9
-rw-r--r--src/com/android/documentsui/files/ActivityInputHandler.java19
-rw-r--r--src/com/android/documentsui/files/FilesActivity.java11
-rw-r--r--src/com/android/documentsui/picker/PickActivity.java11
-rw-r--r--tests/common/com/android/documentsui/dirlist/TestFocusHandler.java4
-rw-r--r--tests/unit/com/android/documentsui/SharedInputHandlerTest.java194
8 files changed, 315 insertions, 53 deletions
diff --git a/src/com/android/documentsui/BaseActivity.java b/src/com/android/documentsui/BaseActivity.java
index c4dc81089..145bf1aa8 100644
--- a/src/com/android/documentsui/BaseActivity.java
+++ b/src/com/android/documentsui/BaseActivity.java
@@ -545,25 +545,6 @@ public abstract class BaseActivity
return mState.stack.peek();
}
- @Override
- public void onBackPressed() {
- // While action bar is expanded, the state stack UI is hidden.
- if (mSearchManager.cancelSearch()) {
- return;
- }
-
- DirectoryFragment dir = getDirectoryFragment();
- if (dir != null && dir.onBackPressed()) {
- return;
- }
-
- if (popDir()) {
- return;
- }
-
- super.onBackPressed();
- }
-
@VisibleForTesting
public void addEventListener(EventListener listener) {
mEventListeners.add(listener);
diff --git a/src/com/android/documentsui/SharedInputHandler.java b/src/com/android/documentsui/SharedInputHandler.java
index 367805902..f3f26419d 100644
--- a/src/com/android/documentsui/SharedInputHandler.java
+++ b/src/com/android/documentsui/SharedInputHandler.java
@@ -15,43 +15,114 @@
*/
package com.android.documentsui;
+import static com.android.documentsui.base.Shared.DEBUG;
+
+import android.util.Log;
import android.view.KeyEvent;
import com.android.documentsui.base.Events;
import com.android.documentsui.base.Features;
import com.android.documentsui.base.Procedure;
+import com.android.documentsui.dirlist.FocusHandler;
+import com.android.documentsui.selection.SelectionManager;
public class SharedInputHandler {
- private final FocusManager mFocusManager;
+ private static final String TAG = "SharedInputHandler";
+
+ private final FocusHandler mFocusManager;
+ private final Procedure mSearchCanceler;
private final Procedure mDirPopper;
private final Features mFeatures;
+ private final SelectionManager mSelectionMgr;
- public SharedInputHandler(FocusManager focusManager, Procedure dirPopper, Features features) {
- mFocusManager = focusManager;
+ public SharedInputHandler(
+ FocusHandler focusHandler,
+ SelectionManager selectionMgr,
+ Procedure searchCanceler,
+ Procedure dirPopper,
+ Features features) {
+ mFocusManager = focusHandler;
+ mSearchCanceler = searchCanceler;
+ mSelectionMgr = selectionMgr;
mDirPopper = dirPopper;
mFeatures = features;
}
public boolean onKeyDown(int keyCode, KeyEvent event) {
- if (Events.isNavigationKeyCode(keyCode)) {
- // Forward all unclaimed navigation keystrokes to the directory list.
- // This causes any stray navigation keystrokes to focus the content pane,
- // which is probably what the user is trying to do.
- mFocusManager.focusDirectoryList();
- return true;
- } else if (keyCode == KeyEvent.KEYCODE_TAB
- && !mFeatures.isSystemKeyboardNavigationEnabled()) {
+ switch (keyCode) {
+ // Unhandled ESC keys end up being rethrown back at us as BACK keys. So by returning
+ // true, we make sure it always does no-op.
+ case KeyEvent.KEYCODE_ESCAPE:
+ return onEscape();
+
+ case KeyEvent.KEYCODE_DEL:
+ return onDelete();
+
+ // This is the Android back button, not backspace.
+ case KeyEvent.KEYCODE_BACK:
+ return onBack();
+
+ case KeyEvent.KEYCODE_TAB:
+ return onTab();
+
+ default:
+ // Instead of duplicating the switch-case in #isNavigationKeyCode, best just to
+ // leave it here.
+ if (Events.isNavigationKeyCode(keyCode)) {
+ // Forward all unclaimed navigation keystrokes to the directory list.
+ // This causes any stray navigation keystrokes to focus the content pane,
+ // which is probably what the user is trying to do.
+ mFocusManager.focusDirectoryList();
+ return true;
+ }
+ return false;
+ }
+ }
+
+ private boolean onTab() {
+ if (!mFeatures.isSystemKeyboardNavigationEnabled()) {
// Tab toggles focus on the navigation drawer.
- // This should only be called in pre-O devices, since O has built-in keyboard navigation
+ // This should only be called in pre-O devices, since O has built-in keyboard
+ // navigation
// support.
mFocusManager.advanceFocusArea();
return true;
- } else if (keyCode == KeyEvent.KEYCODE_DEL) {
- mDirPopper.run();
- return true;
}
return false;
}
+
+ private boolean onDelete() {
+ mDirPopper.run();
+ return true;
+ }
+
+ private boolean onBack() {
+ if (mSearchCanceler.run()) {
+ return true;
+ }
+
+ if (mSelectionMgr.hasSelection()) {
+ if (DEBUG) Log.d(TAG, "Back pressed. Clearing existing selection.");
+ mSelectionMgr.clearSelection();
+ return true;
+ }
+
+ return mDirPopper.run();
+ }
+
+ private boolean onEscape() {
+ if (mSearchCanceler.run()) {
+ return true;
+ }
+
+ if (mSelectionMgr.hasSelection()) {
+ if (DEBUG) Log.d(TAG, "ESC pressed. Clearing existing selection.");
+ mSelectionMgr.clearSelection();
+ return true;
+ }
+
+ return true;
+ }
}
diff --git a/src/com/android/documentsui/dirlist/DirectoryFragment.java b/src/com/android/documentsui/dirlist/DirectoryFragment.java
index 26e0c1d6e..d64fa93a5 100644
--- a/src/com/android/documentsui/dirlist/DirectoryFragment.java
+++ b/src/com/android/documentsui/dirlist/DirectoryFragment.java
@@ -692,15 +692,6 @@ public class DirectoryFragment extends Fragment
}
}
- public final boolean onBackPressed() {
- if (mSelectionMgr.hasSelection()) {
- if (DEBUG) Log.d(TAG, "Clearing selection on selection manager.");
- mSelectionMgr.clearSelection();
- return true;
- }
- return false;
- }
-
private boolean onAccessibilityClick(View child) {
DocumentDetails doc = getDocumentHolder(child);
mActions.openDocument(doc);
diff --git a/src/com/android/documentsui/files/ActivityInputHandler.java b/src/com/android/documentsui/files/ActivityInputHandler.java
index 35653d2d7..3f0eb65b1 100644
--- a/src/com/android/documentsui/files/ActivityInputHandler.java
+++ b/src/com/android/documentsui/files/ActivityInputHandler.java
@@ -30,11 +30,18 @@ final class ActivityInputHandler {
}
boolean onKeyDown(int keyCode, KeyEvent event) {
- if ((keyCode == KeyEvent.KEYCODE_DEL && event.isAltPressed())
- || keyCode == KeyEvent.KEYCODE_FORWARD_DEL) {
- mDeleteHandler.run();
- return true;
+ switch (keyCode) {
+ case KeyEvent.KEYCODE_FORWARD_DEL:
+ mDeleteHandler.run();
+ return true;
+ case KeyEvent.KEYCODE_DEL:
+ if (event.isAltPressed()) {
+ mDeleteHandler.run();
+ return true;
+ }
+ return false;
+ default:
+ return false;
}
- return false;
}
-} \ No newline at end of file
+}
diff --git a/src/com/android/documentsui/files/FilesActivity.java b/src/com/android/documentsui/files/FilesActivity.java
index 103c272a5..835e82146 100644
--- a/src/com/android/documentsui/files/FilesActivity.java
+++ b/src/com/android/documentsui/files/FilesActivity.java
@@ -132,7 +132,12 @@ public class FilesActivity extends BaseActivity implements ActionHandler.Addons
mActivityInputHandler =
new ActivityInputHandler(mInjector.actions::deleteSelectedDocuments);
mSharedInputHandler =
- new SharedInputHandler(mInjector.focusManager, this::popDir, mInjector.features);
+ new SharedInputHandler(
+ mInjector.focusManager,
+ mInjector.selectionMgr,
+ mInjector.searchManager::cancelSearch,
+ this::popDir,
+ mInjector.features);
RootsFragment.show(getFragmentManager(), null);
@@ -302,7 +307,9 @@ public class FilesActivity extends BaseActivity implements ActionHandler.Addons
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
return mActivityInputHandler.onKeyDown(keyCode, event)
- || mSharedInputHandler.onKeyDown(keyCode, event)
+ || mSharedInputHandler.onKeyDown(
+ keyCode,
+ event)
|| super.onKeyDown(keyCode, event);
}
diff --git a/src/com/android/documentsui/picker/PickActivity.java b/src/com/android/documentsui/picker/PickActivity.java
index a90510399..e3d245e53 100644
--- a/src/com/android/documentsui/picker/PickActivity.java
+++ b/src/com/android/documentsui/picker/PickActivity.java
@@ -124,7 +124,12 @@ public class PickActivity extends BaseActivity implements ActionHandler.Addons {
Intent intent = getIntent();
mSharedInputHandler =
- new SharedInputHandler(mInjector.focusManager, this::popDir, mInjector.features);
+ new SharedInputHandler(
+ mInjector.focusManager,
+ mInjector.selectionMgr,
+ mInjector.searchManager::cancelSearch,
+ this::popDir,
+ mInjector.features);
setupLayout(intent);
mInjector.actions.initLocation(intent);
}
@@ -339,7 +344,9 @@ public class PickActivity extends BaseActivity implements ActionHandler.Addons {
@CallSuper
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
- return mSharedInputHandler.onKeyDown(keyCode, event)
+ return mSharedInputHandler.onKeyDown(
+ keyCode,
+ event)
|| super.onKeyDown(keyCode, event);
}
diff --git a/tests/common/com/android/documentsui/dirlist/TestFocusHandler.java b/tests/common/com/android/documentsui/dirlist/TestFocusHandler.java
index d196c332d..73eb8e8db 100644
--- a/tests/common/com/android/documentsui/dirlist/TestFocusHandler.java
+++ b/tests/common/com/android/documentsui/dirlist/TestFocusHandler.java
@@ -27,6 +27,8 @@ public final class TestFocusHandler implements FocusHandler {
public boolean handleKey;
public int focusPos = 0;
public String focusModelId;
+ public boolean advanceFocusAreaCalled;
+ public boolean focusDirectoryCalled;
@Override
public boolean handleKey(DocumentHolder doc, int keyCode, KeyEvent event) {
@@ -39,11 +41,13 @@ public final class TestFocusHandler implements FocusHandler {
@Override
public boolean advanceFocusArea() {
+ advanceFocusAreaCalled = true;
return true;
}
@Override
public boolean focusDirectoryList() {
+ focusDirectoryCalled = true;
return true;
}
diff --git a/tests/unit/com/android/documentsui/SharedInputHandlerTest.java b/tests/unit/com/android/documentsui/SharedInputHandlerTest.java
new file mode 100644
index 000000000..0f5c28064
--- /dev/null
+++ b/tests/unit/com/android/documentsui/SharedInputHandlerTest.java
@@ -0,0 +1,194 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.documentsui;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.view.KeyEvent;
+import android.view.MotionEvent;
+
+import com.android.documentsui.base.Procedure;
+import com.android.documentsui.dirlist.TestFocusHandler;
+import com.android.documentsui.selection.SelectionManager;
+import com.android.documentsui.testing.SelectionManagers;
+import com.android.documentsui.testing.TestFeatures;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class SharedInputHandlerTest {
+
+ private SharedInputHandler mSharedInputHandler;
+ private SelectionManager mSelectionMgr = SelectionManagers.createTestInstance();
+ private TestFeatures mFeatures = new TestFeatures();
+ private TestFocusHandler mFocusHandler = new TestFocusHandler();
+ private boolean mDirPopHappened;
+ private boolean mCanceledSearch;
+ private Procedure mDirPopper = new Procedure() {
+ @Override
+ public boolean run() {
+ mDirPopHappened = true;
+ return true;
+ }
+ };
+
+ @Before
+ public void setUp() {
+ mDirPopHappened = false;
+ mSharedInputHandler = new SharedInputHandler(
+ mFocusHandler,
+ mSelectionMgr,
+ () -> {
+ return false;
+ },
+ mDirPopper,
+ mFeatures);
+ }
+
+ @Test
+ public void testUnrelatedButton_DoesNothing() {
+ KeyEvent event =
+ new KeyEvent(0, 0, MotionEvent.ACTION_DOWN, KeyEvent.KEYCODE_A, 0, 0);
+ assertFalse(mSharedInputHandler.onKeyDown(event.getKeyCode(), event));
+ }
+
+ @Test
+ public void testBackButton_CancelsSearch() {
+ mSelectionMgr.toggleSelection("1");
+ mSharedInputHandler = new SharedInputHandler(
+ new TestFocusHandler(),
+ SelectionManagers.createTestInstance(),
+ () -> {
+ mCanceledSearch = true;
+ return true;
+ },
+ mDirPopper,
+ new TestFeatures());
+ KeyEvent backEvent =
+ new KeyEvent(0, 0, MotionEvent.ACTION_DOWN, KeyEvent.KEYCODE_BACK, 0, 0);
+ assertTrue(mSharedInputHandler.onKeyDown(backEvent.getKeyCode(), backEvent));
+
+ assertTrue(mCanceledSearch);
+ assertEquals(mSelectionMgr.getSelection().size(), 1);
+ assertFalse(mDirPopHappened);
+ }
+
+ @Test
+ public void testBackButton_ClearsSelection() {
+ mSelectionMgr.toggleSelection("1");
+ assertEquals(mSelectionMgr.getSelection().size(), 1);
+ KeyEvent backEvent =
+ new KeyEvent(0, 0, MotionEvent.ACTION_DOWN, KeyEvent.KEYCODE_BACK, 0, 0);
+ assertTrue(mSharedInputHandler.onKeyDown(backEvent.getKeyCode(), backEvent));
+
+ assertFalse(mCanceledSearch);
+ assertEquals(mSelectionMgr.getSelection().size(), 0);
+ assertFalse(mDirPopHappened);
+ }
+
+ @Test
+ public void testBackButton_PopsDirectory() {
+ KeyEvent backEvent =
+ new KeyEvent(0, 0, MotionEvent.ACTION_DOWN, KeyEvent.KEYCODE_BACK, 0, 0);
+ assertTrue(mSharedInputHandler.onKeyDown(backEvent.getKeyCode(), backEvent));
+
+ assertFalse(mCanceledSearch);
+ assertEquals(mSelectionMgr.getSelection().size(), 0);
+ assertTrue(mDirPopHappened);
+ }
+
+ @Test
+ public void testEscButton_CancelsSearch() {
+ mSelectionMgr.toggleSelection("1");
+ mSharedInputHandler = new SharedInputHandler(
+ new TestFocusHandler(),
+ SelectionManagers.createTestInstance(),
+ () -> {
+ mCanceledSearch = true;
+ return true;
+ },
+ mDirPopper,
+ new TestFeatures());
+ KeyEvent escapeEvent =
+ new KeyEvent(0, 0, MotionEvent.ACTION_DOWN, KeyEvent.KEYCODE_ESCAPE, 0, 0);
+ assertTrue(mSharedInputHandler.onKeyDown(escapeEvent.getKeyCode(), escapeEvent));
+
+ assertTrue(mCanceledSearch);
+ assertEquals(mSelectionMgr.getSelection().size(), 1);
+ assertFalse(mDirPopHappened);
+ }
+
+ @Test
+ public void testEscButton_ClearsSelection() {
+ mSelectionMgr.toggleSelection("1");
+ assertEquals(mSelectionMgr.getSelection().size(), 1);
+ KeyEvent escapeEvent =
+ new KeyEvent(0, 0, MotionEvent.ACTION_DOWN, KeyEvent.KEYCODE_ESCAPE, 0, 0);
+ assertTrue(mSharedInputHandler.onKeyDown(escapeEvent.getKeyCode(), escapeEvent));
+
+ assertFalse(mCanceledSearch);
+ assertEquals(mSelectionMgr.getSelection().size(), 0);
+ assertFalse(mDirPopHappened);
+ }
+
+ @Test
+ public void testEscButton_DoesNotPopDirectory() {
+ KeyEvent escapeEvent =
+ new KeyEvent(0, 0, MotionEvent.ACTION_DOWN, KeyEvent.KEYCODE_ESCAPE, 0, 0);
+ assertTrue(mSharedInputHandler.onKeyDown(escapeEvent.getKeyCode(), escapeEvent));
+
+ assertFalse(mCanceledSearch);
+ assertEquals(mSelectionMgr.getSelection().size(), 0);
+ assertFalse(mDirPopHappened);
+ }
+
+ @Test
+ public void testDeleteButton_PopsDirectory() {
+ KeyEvent delEvent =
+ new KeyEvent(0, 0, MotionEvent.ACTION_DOWN, KeyEvent.KEYCODE_DEL, 0, 0);
+ assertTrue(mSharedInputHandler.onKeyDown(delEvent.getKeyCode(), delEvent));
+
+ assertTrue(mDirPopHappened);
+ }
+
+ @Test
+ public void testTab_AdvancesFocusArea() {
+ mFeatures.systemKeyboardNavigation = false;
+ KeyEvent tabEvent =
+ new KeyEvent(0, 0, MotionEvent.ACTION_DOWN, KeyEvent.KEYCODE_TAB, 0, 0);
+ assertTrue(mSharedInputHandler.onKeyDown(tabEvent.getKeyCode(), tabEvent));
+
+ assertTrue(mFocusHandler.advanceFocusAreaCalled);
+ }
+
+ @Test
+ public void testNavKey_FocusesDirectory() {
+ mFeatures.systemKeyboardNavigation = false;
+ KeyEvent navEvent =
+ new KeyEvent(0, 0, MotionEvent.ACTION_DOWN, KeyEvent.KEYCODE_DPAD_UP, 0, 0);
+ assertTrue(mSharedInputHandler.onKeyDown(navEvent.getKeyCode(), navEvent));
+
+ assertTrue(mFocusHandler.focusDirectoryCalled);
+ }
+}