summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSunny Goyal <sunnygoyal@google.com>2016-10-03 21:12:20 +0000
committerAndroid (Google) Code Review <android-gerrit@google.com>2016-10-03 21:12:20 +0000
commit7a372033ac2c9b8def4fb7870d3b3ee3b9db425f (patch)
tree8dd5818eb592dd8e751421cb4fd2877829bfdb37
parent61e917078a68631cba651c51284980bcd0075161 (diff)
parent66b24572e41a13ba5b85b37cf7be64804299c8f6 (diff)
downloadandroid_packages_apps_Trebuchet-7a372033ac2c9b8def4fb7870d3b3ee3b9db425f.tar.gz
android_packages_apps_Trebuchet-7a372033ac2c9b8def4fb7870d3b3ee3b9db425f.tar.bz2
android_packages_apps_Trebuchet-7a372033ac2c9b8def4fb7870d3b3ee3b9db425f.zip
Merge "Exposing custom actions using keyboard shortcut" into ub-launcher3-master
-rw-r--r--res/values/strings.xml4
-rw-r--r--src/com/android/launcher3/FocusHelper.java34
-rw-r--r--src/com/android/launcher3/Launcher.java63
-rw-r--r--src/com/android/launcher3/accessibility/LauncherAccessibilityDelegate.java16
-rw-r--r--src/com/android/launcher3/accessibility/ShortcutMenuAccessibilityDelegate.java6
-rw-r--r--src/com/android/launcher3/keyboard/CustomActionsPopup.java93
-rw-r--r--src/com/android/launcher3/keyboard/FocusIndicatorHelper.java2
-rw-r--r--src/com/android/launcher3/shortcuts/DeepShortcutsContainer.java4
-rw-r--r--src/com/android/launcher3/util/FocusLogic.java3
-rw-r--r--tests/src/com/android/launcher3/util/FocusLogicTest.java2
10 files changed, 180 insertions, 47 deletions
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 60a37e5ef..a9c970d6d 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -37,6 +37,10 @@
<string name="safemode_widget_error">Widgets disabled in Safe mode</string>
<!-- Message shown when a shortcut is not available. It could have been temporarily disabled and may start working again after some time. -->
<string name="shortcut_not_available">Shortcut isn\'t available</string>
+ <!-- User visible name for the launcher/home screen. [CHAR_LIMIT=30] -->
+ <string name="home_screen">Home screen</string>
+ <!-- Label for showing custom action list of a shortcut or widget. [CHAR_LIMIT=30] -->
+ <string name="custom_actions">Custom actions</string>
<!-- Widgets -->
<!-- Message to tell the user to press and hold on a widget to add it [CHAR_LIMIT=50] -->
diff --git a/src/com/android/launcher3/FocusHelper.java b/src/com/android/launcher3/FocusHelper.java
index c73ceea14..de079feda 100644
--- a/src/com/android/launcher3/FocusHelper.java
+++ b/src/com/android/launcher3/FocusHelper.java
@@ -250,14 +250,6 @@ public class FocusHelper {
} else if (keyCode == KeyEvent.KEYCODE_DPAD_RIGHT &&
profile.isVerticalBarLayout()) {
keyCode = KeyEvent.KEYCODE_PAGE_DOWN;
- } else if (isUninstallKeyChord(e)) {
- matrix = FocusLogic.createSparseMatrix(iconLayout);
- if (UninstallDropTarget.supportsDrop(launcher, itemInfo)) {
- UninstallDropTarget.startUninstallActivity(launcher, itemInfo);
- }
- } else if (isDeleteKeyChord(e)) {
- matrix = FocusLogic.createSparseMatrix(iconLayout);
- launcher.removeItem(v, itemInfo, true /* deleteFromDb */);
} else {
// For other KEYCODE_DPAD_LEFT and KEYCODE_DPAD_RIGHT navigation, do not use the
// matrix extended with hotseat.
@@ -374,14 +366,6 @@ public class FocusHelper {
} else if (keyCode == KeyEvent.KEYCODE_DPAD_RIGHT &&
profile.isVerticalBarLayout()) {
matrix = FocusLogic.createSparseMatrixWithHotseat(iconLayout, hotseatLayout, profile);
- } else if (isUninstallKeyChord(e)) {
- matrix = FocusLogic.createSparseMatrix(iconLayout);
- if (UninstallDropTarget.supportsDrop(launcher, itemInfo)) {
- UninstallDropTarget.startUninstallActivity(launcher, itemInfo);
- }
- } else if (isDeleteKeyChord(e)) {
- matrix = FocusLogic.createSparseMatrix(iconLayout);
- launcher.removeItem(v, itemInfo, true /* deleteFromDb */);
} else {
matrix = FocusLogic.createSparseMatrix(iconLayout);
}
@@ -532,24 +516,6 @@ public class FocusHelper {
}
}
- /**
- * Returns whether the key event represents a valid uninstall key chord.
- */
- private static boolean isUninstallKeyChord(KeyEvent event) {
- int keyCode = event.getKeyCode();
- return (keyCode == KeyEvent.KEYCODE_DEL || keyCode == KeyEvent.KEYCODE_FORWARD_DEL) &&
- event.hasModifiers(KeyEvent.META_CTRL_ON | KeyEvent.META_SHIFT_ON);
- }
-
- /**
- * Returns whether the key event represents a valid delete key chord.
- */
- private static boolean isDeleteKeyChord(KeyEvent event) {
- int keyCode = event.getKeyCode();
- return (keyCode == KeyEvent.KEYCODE_DEL || keyCode == KeyEvent.KEYCODE_FORWARD_DEL) &&
- event.hasModifiers(KeyEvent.META_CTRL_ON);
- }
-
private static View handlePreviousPageLastItem(Workspace workspace, CellLayout hotseatLayout,
int pageIndex, boolean isRtl) {
if (pageIndex - 1 < 0) {
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index 0a14c421d..f825e212c 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -69,6 +69,8 @@ import android.util.Log;
import android.view.Display;
import android.view.HapticFeedbackConstants;
import android.view.KeyEvent;
+import android.view.KeyboardShortcutGroup;
+import android.view.KeyboardShortcutInfo;
import android.view.Menu;
import android.view.MotionEvent;
import android.view.Surface;
@@ -79,6 +81,7 @@ import android.view.ViewGroup;
import android.view.ViewTreeObserver;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityManager;
+import android.view.accessibility.AccessibilityNodeInfo;
import android.view.animation.OvershootInterpolator;
import android.view.inputmethod.InputMethodManager;
import android.widget.Advanceable;
@@ -106,6 +109,7 @@ import com.android.launcher3.dragndrop.DragView;
import com.android.launcher3.dynamicui.ExtractedColors;
import com.android.launcher3.folder.Folder;
import com.android.launcher3.folder.FolderIcon;
+import com.android.launcher3.keyboard.CustomActionsPopup;
import com.android.launcher3.keyboard.ViewGroupFocusHelper;
import com.android.launcher3.logging.FileLog;
import com.android.launcher3.logging.UserEventDispatcher;
@@ -4456,6 +4460,65 @@ public class Launcher extends Activity
}
}
+ @Override
+ @TargetApi(Build.VERSION_CODES.N)
+ public void onProvideKeyboardShortcuts(
+ List<KeyboardShortcutGroup> data, Menu menu, int deviceId) {
+
+ ArrayList<KeyboardShortcutInfo> shortcutInfos = new ArrayList<>();
+ if (mState == State.WORKSPACE) {
+ shortcutInfos.add(new KeyboardShortcutInfo(getString(R.string.all_apps_button_label),
+ KeyEvent.KEYCODE_A, KeyEvent.META_CTRL_ON));
+ }
+ View currentFocus = getCurrentFocus();
+ if (new CustomActionsPopup(this, currentFocus).canShow()) {
+ shortcutInfos.add(new KeyboardShortcutInfo(getString(R.string.custom_actions),
+ KeyEvent.KEYCODE_O, KeyEvent.META_CTRL_ON));
+ }
+ if (currentFocus instanceof BubbleTextView &&
+ ((BubbleTextView) currentFocus).hasDeepShortcuts()) {
+ shortcutInfos.add(new KeyboardShortcutInfo(getString(R.string.action_deep_shortcut),
+ KeyEvent.KEYCODE_S, KeyEvent.META_CTRL_ON));
+ }
+ if (!shortcutInfos.isEmpty()) {
+ data.add(new KeyboardShortcutGroup(getString(R.string.home_screen), shortcutInfos));
+ }
+
+ super.onProvideKeyboardShortcuts(data, menu, deviceId);
+ }
+
+ @Override
+ public boolean onKeyShortcut(int keyCode, KeyEvent event) {
+ if (event.hasModifiers(KeyEvent.META_CTRL_ON)) {
+ switch (keyCode) {
+ case KeyEvent.KEYCODE_A:
+ if (mState == State.WORKSPACE) {
+ showAppsView(true, true, false);
+ return true;
+ }
+ break;
+ case KeyEvent.KEYCODE_S: {
+ View focusedView = getCurrentFocus();
+ if (focusedView instanceof BubbleTextView
+ && focusedView.getTag() instanceof ItemInfo
+ && mAccessibilityDelegate.performAction(focusedView,
+ (ItemInfo) focusedView.getTag(),
+ LauncherAccessibilityDelegate.DEEP_SHORTCUTS)) {
+ getOpenShortcutsContainer().requestFocus();
+ return true;
+ }
+ break;
+ }
+ case KeyEvent.KEYCODE_O:
+ if (new CustomActionsPopup(this, getCurrentFocus()).show()) {
+ return true;
+ }
+ break;
+ }
+ }
+ return super.onKeyShortcut(keyCode, event);
+ }
+
public static CustomAppWidget getCustomAppWidget(String name) {
return sCustomAppWidgets.get(name);
}
diff --git a/src/com/android/launcher3/accessibility/LauncherAccessibilityDelegate.java b/src/com/android/launcher3/accessibility/LauncherAccessibilityDelegate.java
index 173aad044..439e3145e 100644
--- a/src/com/android/launcher3/accessibility/LauncherAccessibilityDelegate.java
+++ b/src/com/android/launcher3/accessibility/LauncherAccessibilityDelegate.java
@@ -57,7 +57,7 @@ public class LauncherAccessibilityDelegate extends AccessibilityDelegate impleme
protected static final int MOVE = R.id.action_move;
protected static final int MOVE_TO_WORKSPACE = R.id.action_move_to_workspace;
protected static final int RESIZE = R.id.action_resize;
- protected static final int DEEP_SHORTCUTS = R.id.action_deep_shortcuts;
+ public static final int DEEP_SHORTCUTS = R.id.action_deep_shortcuts;
public enum DragType {
ICON,
@@ -100,14 +100,17 @@ public class LauncherAccessibilityDelegate extends AccessibilityDelegate impleme
@Override
public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfo info) {
super.onInitializeAccessibilityNodeInfo(host, info);
- addActions(host, info);
+ addSupportedActions(host, info, false);
}
- protected void addActions(View host, AccessibilityNodeInfo info) {
+ public void addSupportedActions(View host, AccessibilityNodeInfo info, boolean fromKeyboard) {
if (!(host.getTag() instanceof ItemInfo)) return;
ItemInfo item = (ItemInfo) host.getTag();
- if (host instanceof BubbleTextView && ((BubbleTextView) host).hasDeepShortcuts()) {
+ // If the request came from keyboard, do not add custom shortcuts as that is already
+ // exposed as a direct shortcut
+ if (!fromKeyboard && host instanceof BubbleTextView
+ && ((BubbleTextView) host).hasDeepShortcuts()) {
info.addAction(mActions.get(DEEP_SHORTCUTS));
}
@@ -121,9 +124,10 @@ public class LauncherAccessibilityDelegate extends AccessibilityDelegate impleme
info.addAction(mActions.get(INFO));
}
- if ((item instanceof ShortcutInfo)
+ // Do not add move actions for keyboard request as this uses virtual nodes.
+ if (!fromKeyboard && ((item instanceof ShortcutInfo)
|| (item instanceof LauncherAppWidgetInfo)
- || (item instanceof FolderInfo)) {
+ || (item instanceof FolderInfo))) {
info.addAction(mActions.get(MOVE));
if (item.container >= 0) {
diff --git a/src/com/android/launcher3/accessibility/ShortcutMenuAccessibilityDelegate.java b/src/com/android/launcher3/accessibility/ShortcutMenuAccessibilityDelegate.java
index 0baa8f3db..5baa7b59e 100644
--- a/src/com/android/launcher3/accessibility/ShortcutMenuAccessibilityDelegate.java
+++ b/src/com/android/launcher3/accessibility/ShortcutMenuAccessibilityDelegate.java
@@ -40,8 +40,10 @@ public class ShortcutMenuAccessibilityDelegate extends LauncherAccessibilityDele
}
@Override
- protected void addActions(View host, AccessibilityNodeInfo info) {
- info.addAction(mActions.get(ADD_TO_WORKSPACE));
+ public void addSupportedActions(View host, AccessibilityNodeInfo info, boolean fromKeyboard) {
+ if ((host.getParent() instanceof DeepShortcutView)) {
+ info.addAction(mActions.get(ADD_TO_WORKSPACE));
+ }
}
@Override
diff --git a/src/com/android/launcher3/keyboard/CustomActionsPopup.java b/src/com/android/launcher3/keyboard/CustomActionsPopup.java
new file mode 100644
index 000000000..6056f4c10
--- /dev/null
+++ b/src/com/android/launcher3/keyboard/CustomActionsPopup.java
@@ -0,0 +1,93 @@
+/*
+ * 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.launcher3.keyboard;
+
+import android.view.Menu;
+import android.view.MenuItem;
+import android.view.View;
+import android.view.accessibility.AccessibilityNodeInfo;
+import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction;
+import android.widget.PopupMenu;
+import android.widget.PopupMenu.OnMenuItemClickListener;
+
+import com.android.launcher3.ItemInfo;
+import com.android.launcher3.Launcher;
+import com.android.launcher3.accessibility.LauncherAccessibilityDelegate;
+import com.android.launcher3.shortcuts.DeepShortcutsContainer;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * Handles showing a popup menu with available custom actions for a launcher icon.
+ * This allows exposing various custom actions using keyboard shortcuts.
+ */
+public class CustomActionsPopup implements OnMenuItemClickListener {
+
+ private final Launcher mLauncher;
+ private final LauncherAccessibilityDelegate mDelegate;
+ private final View mIcon;
+
+ public CustomActionsPopup(Launcher launcher, View icon) {
+ mLauncher = launcher;
+ mIcon = icon;
+ DeepShortcutsContainer container = launcher.getOpenShortcutsContainer();
+ if (container != null) {
+ mDelegate = container.getAccessibilityDelegate();
+ } else {
+ mDelegate = launcher.getAccessibilityDelegate();
+ }
+ }
+
+ private List<AccessibilityAction> getActionList() {
+ if (mIcon == null || !(mIcon.getTag() instanceof ItemInfo)) {
+ return Collections.EMPTY_LIST;
+ }
+
+ AccessibilityNodeInfo info = AccessibilityNodeInfo.obtain();
+ mDelegate.addSupportedActions(mIcon, info, true);
+ List<AccessibilityAction> result = new ArrayList<>(info.getActionList());
+ info.recycle();
+ return result;
+ }
+
+ public boolean canShow() {
+ return !getActionList().isEmpty();
+ }
+
+ public boolean show() {
+ List<AccessibilityAction> actions = getActionList();
+ if (actions.isEmpty()) {
+ return false;
+ }
+
+ PopupMenu popup = new PopupMenu(mLauncher, mIcon);
+ popup.setOnMenuItemClickListener(this);
+ Menu menu = popup.getMenu();
+ for (AccessibilityAction action : actions) {
+ menu.add(Menu.NONE, action.getId(), Menu.NONE, action.getLabel());
+ }
+ popup.show();
+ return true;
+ }
+
+ @Override
+ public boolean onMenuItemClick(MenuItem menuItem) {
+ return mDelegate.performAction(mIcon, (ItemInfo) mIcon.getTag(), menuItem.getItemId());
+ }
+}
diff --git a/src/com/android/launcher3/keyboard/FocusIndicatorHelper.java b/src/com/android/launcher3/keyboard/FocusIndicatorHelper.java
index 7672f5a79..b0d6b2dbf 100644
--- a/src/com/android/launcher3/keyboard/FocusIndicatorHelper.java
+++ b/src/com/android/launcher3/keyboard/FocusIndicatorHelper.java
@@ -143,7 +143,7 @@ public abstract class FocusIndicatorHelper implements
}
private Rect getDrawRect() {
- if (mCurrentView != null) {
+ if (mCurrentView != null && mCurrentView.isAttachedToWindow()) {
viewToRect(mCurrentView, sTempRect1);
if (mShift > 0 && mTargetView != null) {
diff --git a/src/com/android/launcher3/shortcuts/DeepShortcutsContainer.java b/src/com/android/launcher3/shortcuts/DeepShortcutsContainer.java
index 1aa1b9e9e..9ff4721e0 100644
--- a/src/com/android/launcher3/shortcuts/DeepShortcutsContainer.java
+++ b/src/com/android/launcher3/shortcuts/DeepShortcutsContainer.java
@@ -610,6 +610,10 @@ public class DeepShortcutsContainer extends LinearLayout implements View.OnLongC
shortcutAnims.start();
}
+ public ShortcutMenuAccessibilityDelegate getAccessibilityDelegate() {
+ return mAccessibilityDelegate;
+ }
+
/**
* Closes the folder without animation.
*/
diff --git a/src/com/android/launcher3/util/FocusLogic.java b/src/com/android/launcher3/util/FocusLogic.java
index 163c953bb..afc45fe35 100644
--- a/src/com/android/launcher3/util/FocusLogic.java
+++ b/src/com/android/launcher3/util/FocusLogic.java
@@ -79,8 +79,7 @@ public class FocusLogic {
return (keyCode == KeyEvent.KEYCODE_DPAD_LEFT || keyCode == KeyEvent.KEYCODE_DPAD_RIGHT ||
keyCode == KeyEvent.KEYCODE_DPAD_UP || keyCode == KeyEvent.KEYCODE_DPAD_DOWN ||
keyCode == KeyEvent.KEYCODE_MOVE_HOME || keyCode == KeyEvent.KEYCODE_MOVE_END ||
- keyCode == KeyEvent.KEYCODE_PAGE_UP || keyCode == KeyEvent.KEYCODE_PAGE_DOWN ||
- keyCode == KeyEvent.KEYCODE_DEL || keyCode == KeyEvent.KEYCODE_FORWARD_DEL);
+ keyCode == KeyEvent.KEYCODE_PAGE_UP || keyCode == KeyEvent.KEYCODE_PAGE_DOWN);
}
public static int handleKeyEvent(int keyCode, int [][] map, int iconIdx, int pageIndex,
diff --git a/tests/src/com/android/launcher3/util/FocusLogicTest.java b/tests/src/com/android/launcher3/util/FocusLogicTest.java
index eee567fb8..79aed806c 100644
--- a/tests/src/com/android/launcher3/util/FocusLogicTest.java
+++ b/tests/src/com/android/launcher3/util/FocusLogicTest.java
@@ -49,8 +49,6 @@ public final class FocusLogicTest extends AndroidTestCase {
assertTrue(FocusLogic.shouldConsume(KeyEvent.KEYCODE_MOVE_END));
assertTrue(FocusLogic.shouldConsume(KeyEvent.KEYCODE_PAGE_UP));
assertTrue(FocusLogic.shouldConsume(KeyEvent.KEYCODE_PAGE_DOWN));
- assertTrue(FocusLogic.shouldConsume(KeyEvent.KEYCODE_DEL));
- assertTrue(FocusLogic.shouldConsume(KeyEvent.KEYCODE_FORWARD_DEL));
}
public void testCreateSparseMatrix() {