Merge "Removing menu and dialog for custom actions hanlding. These do not work well with gesture-nav and can potentially block the Launcher UI." into sc-dev
This commit is contained in:
commit
3c5e748b36
|
@ -0,0 +1,57 @@
|
|||
/*
|
||||
* Copyright (C) 2021 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;
|
||||
|
||||
import android.view.KeyEvent;
|
||||
import android.view.View;
|
||||
|
||||
import com.android.launcher3.accessibility.LauncherAccessibilityDelegate;
|
||||
import com.android.launcher3.model.data.ItemInfo;
|
||||
import com.android.launcher3.uioverrides.PredictedAppIcon;
|
||||
import com.android.launcher3.uioverrides.QuickstepLauncher;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class QuickstepAccessibilityDelegate extends LauncherAccessibilityDelegate {
|
||||
|
||||
public QuickstepAccessibilityDelegate(QuickstepLauncher launcher) {
|
||||
super(launcher);
|
||||
mActions.put(PIN_PREDICTION, new LauncherAction(
|
||||
PIN_PREDICTION, R.string.pin_prediction, KeyEvent.KEYCODE_P));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void getSupportedActions(View host, ItemInfo item, List<LauncherAction> out) {
|
||||
if (host instanceof PredictedAppIcon && !((PredictedAppIcon) host).isPinned()) {
|
||||
out.add(new LauncherAction(PIN_PREDICTION, R.string.pin_prediction,
|
||||
KeyEvent.KEYCODE_P));
|
||||
}
|
||||
super.getSupportedActions(host, item, out);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean performAction(View host, ItemInfo item, int action, boolean fromKeyboard) {
|
||||
QuickstepLauncher launcher = (QuickstepLauncher) mLauncher;
|
||||
if (action == PIN_PREDICTION) {
|
||||
if (launcher.getHotseatPredictionController() == null) {
|
||||
return false;
|
||||
}
|
||||
launcher.getHotseatPredictionController().pinPrediction(item);
|
||||
return true;
|
||||
}
|
||||
return super.performAction(host, item, action, fromKeyboard);
|
||||
}
|
||||
}
|
|
@ -15,7 +15,6 @@
|
|||
*/
|
||||
package com.android.launcher3.uioverrides;
|
||||
|
||||
import static com.android.launcher3.accessibility.LauncherAccessibilityDelegate.PIN_PREDICTION;
|
||||
import static com.android.launcher3.graphics.IconShape.getShape;
|
||||
|
||||
import android.content.Context;
|
||||
|
@ -29,7 +28,6 @@ import android.os.Process;
|
|||
import android.util.AttributeSet;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.accessibility.AccessibilityNodeInfo;
|
||||
|
||||
import androidx.core.graphics.ColorUtils;
|
||||
|
||||
|
@ -37,9 +35,7 @@ import com.android.launcher3.CellLayout;
|
|||
import com.android.launcher3.DeviceProfile;
|
||||
import com.android.launcher3.Launcher;
|
||||
import com.android.launcher3.R;
|
||||
import com.android.launcher3.accessibility.LauncherAccessibilityDelegate;
|
||||
import com.android.launcher3.graphics.IconPalette;
|
||||
import com.android.launcher3.hybridhotseat.HotseatPredictionController;
|
||||
import com.android.launcher3.icons.IconNormalizer;
|
||||
import com.android.launcher3.icons.LauncherIcons;
|
||||
import com.android.launcher3.model.data.ItemInfo;
|
||||
|
@ -53,8 +49,7 @@ import com.android.launcher3.views.DoubleShadowBubbleTextView;
|
|||
/**
|
||||
* A BubbleTextView with a ring around it's drawable
|
||||
*/
|
||||
public class PredictedAppIcon extends DoubleShadowBubbleTextView implements
|
||||
LauncherAccessibilityDelegate.AccessibilityActionHandler {
|
||||
public class PredictedAppIcon extends DoubleShadowBubbleTextView {
|
||||
|
||||
private static final int RING_SHADOW_COLOR = 0x99000000;
|
||||
private static final float RING_EFFECT_RATIO = 0.095f;
|
||||
|
@ -147,29 +142,6 @@ public class PredictedAppIcon extends DoubleShadowBubbleTextView implements
|
|||
verifyHighRes();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addSupportedAccessibilityActions(AccessibilityNodeInfo accessibilityNodeInfo) {
|
||||
if (!mIsPinned) {
|
||||
accessibilityNodeInfo.addAction(
|
||||
new AccessibilityNodeInfo.AccessibilityAction(PIN_PREDICTION,
|
||||
getContext().getText(R.string.pin_prediction)));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean performAccessibilityAction(int action, ItemInfo info) {
|
||||
QuickstepLauncher launcher = Launcher.cast(Launcher.getLauncher(getContext()));
|
||||
if (action == PIN_PREDICTION) {
|
||||
if (launcher == null) {
|
||||
return false;
|
||||
}
|
||||
HotseatPredictionController controller = launcher.getHotseatPredictionController();
|
||||
controller.pinPrediction(info);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void getIconBounds(Rect outBounds) {
|
||||
super.getIconBounds(outBounds);
|
||||
|
@ -179,6 +151,10 @@ public class PredictedAppIcon extends DoubleShadowBubbleTextView implements
|
|||
}
|
||||
}
|
||||
|
||||
public boolean isPinned() {
|
||||
return mIsPinned;
|
||||
}
|
||||
|
||||
private int getOutlineOffsetX() {
|
||||
return (getMeasuredWidth() / 2) - mNormalizedIconRadius;
|
||||
}
|
||||
|
|
|
@ -43,7 +43,9 @@ import com.android.launcher3.DeviceProfile;
|
|||
import com.android.launcher3.Launcher;
|
||||
import com.android.launcher3.LauncherSettings.Favorites;
|
||||
import com.android.launcher3.LauncherState;
|
||||
import com.android.launcher3.QuickstepAccessibilityDelegate;
|
||||
import com.android.launcher3.Workspace;
|
||||
import com.android.launcher3.accessibility.LauncherAccessibilityDelegate;
|
||||
import com.android.launcher3.anim.AnimatorPlaybackController;
|
||||
import com.android.launcher3.appprediction.PredictionRowView;
|
||||
import com.android.launcher3.hybridhotseat.HotseatPredictionController;
|
||||
|
@ -134,6 +136,11 @@ public class QuickstepLauncher extends BaseQuickstepLauncher {
|
|||
mHotseatPredictionController.logLaunchedAppRankingInfo(info, instanceId);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected LauncherAccessibilityDelegate createAccessibilityDelegate() {
|
||||
return new QuickstepAccessibilityDelegate(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns Prediction controller for hybrid hotseat
|
||||
*/
|
||||
|
|
|
@ -0,0 +1,25 @@
|
|||
<!--
|
||||
Copyright (C) 2021 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.
|
||||
-->
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24"
|
||||
android:tint="?android:attr/textColorPrimary">
|
||||
<path
|
||||
android:fillColor="#FFFFFF"
|
||||
android:pathData="M8,19h3v3h2v-3h3l-4,-4 -4,4zM16,4h-3L13,1h-2v3L8,4l4,4 4,-4zM4,9v2h16L20,9L4,9zM4,12h16v2H4z"/>
|
||||
</vector>
|
|
@ -0,0 +1,25 @@
|
|||
<!--
|
||||
Copyright (C) 2021 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.
|
||||
-->
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24"
|
||||
android:tint="?android:attr/textColorPrimary">
|
||||
<path
|
||||
android:fillColor="#FFFFFF"
|
||||
android:pathData="M4,20h16v2L4,22zM4,2h16v2L4,4zM13,9h3l-4,-4 -4,4h3v6L8,15l4,4 4,-4h-3z"/>
|
||||
</vector>
|
|
@ -0,0 +1,22 @@
|
|||
<!--
|
||||
Copyright (C) 2021 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.
|
||||
-->
|
||||
<rotate
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:drawable="@drawable/ic_widget_height_decrease"
|
||||
android:pivotX="50%"
|
||||
android:pivotY="50%"
|
||||
android:fromDegrees="90"
|
||||
android:toDegrees="90" />
|
|
@ -0,0 +1,22 @@
|
|||
<!--
|
||||
Copyright (C) 2021 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.
|
||||
-->
|
||||
<rotate
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:drawable="@drawable/ic_widget_height_increase"
|
||||
android:pivotX="50%"
|
||||
android:pivotY="50%"
|
||||
android:fromDegrees="90"
|
||||
android:toDegrees="90" />
|
|
@ -37,8 +37,6 @@
|
|||
<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</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] -->
|
||||
|
|
|
@ -59,7 +59,7 @@ public abstract class AbstractFloatingView extends LinearLayout implements Touch
|
|||
TYPE_SNACKBAR,
|
||||
TYPE_LISTENER,
|
||||
TYPE_ALL_APPS_EDU,
|
||||
|
||||
TYPE_DRAG_DROP_POPUP,
|
||||
TYPE_TASK_MENU,
|
||||
TYPE_OPTIONS_POPUP,
|
||||
TYPE_ICON_SURFACE
|
||||
|
|
|
@ -309,6 +309,8 @@ public class CellLayout extends ViewGroup {
|
|||
setImportantForAccessibility(accessibilityFlag);
|
||||
getShortcutsAndWidgets().setImportantForAccessibility(accessibilityFlag);
|
||||
|
||||
// ExploreByTouchHelper sets focusability. Clear it when the delegate is cleared.
|
||||
setFocusable(delegate != null);
|
||||
// Invalidate the accessibility hierarchy
|
||||
if (getParent() != null) {
|
||||
getParent().notifySubtreeAccessibilityStateChanged(
|
||||
|
|
|
@ -37,6 +37,7 @@ import static com.android.launcher3.LauncherState.NO_SCALE;
|
|||
import static com.android.launcher3.LauncherState.OVERVIEW;
|
||||
import static com.android.launcher3.LauncherState.SPRING_LOADED;
|
||||
import static com.android.launcher3.Utilities.postAsyncCallback;
|
||||
import static com.android.launcher3.accessibility.LauncherAccessibilityDelegate.getSupportedActions;
|
||||
import static com.android.launcher3.dragndrop.DragLayer.ALPHA_INDEX_LAUNCHER_LOAD;
|
||||
import static com.android.launcher3.logging.StatsLogManager.LAUNCHER_STATE_BACKGROUND;
|
||||
import static com.android.launcher3.logging.StatsLogManager.LAUNCHER_STATE_HOME;
|
||||
|
@ -107,6 +108,7 @@ import androidx.annotation.VisibleForTesting;
|
|||
|
||||
import com.android.launcher3.DropTarget.DragObject;
|
||||
import com.android.launcher3.accessibility.LauncherAccessibilityDelegate;
|
||||
import com.android.launcher3.accessibility.LauncherAccessibilityDelegate.LauncherAction;
|
||||
import com.android.launcher3.allapps.AllAppsContainerView;
|
||||
import com.android.launcher3.allapps.AllAppsStore;
|
||||
import com.android.launcher3.allapps.AllAppsTransitionController;
|
||||
|
@ -123,7 +125,6 @@ import com.android.launcher3.folder.FolderGridOrganizer;
|
|||
import com.android.launcher3.folder.FolderIcon;
|
||||
import com.android.launcher3.icons.BitmapRenderer;
|
||||
import com.android.launcher3.icons.IconCache;
|
||||
import com.android.launcher3.keyboard.CustomActionsPopup;
|
||||
import com.android.launcher3.keyboard.ViewGroupFocusHelper;
|
||||
import com.android.launcher3.logger.LauncherAtom;
|
||||
import com.android.launcher3.logging.FileLog;
|
||||
|
@ -168,7 +169,6 @@ import com.android.launcher3.util.PackageManagerHelper;
|
|||
import com.android.launcher3.util.PackageUserKey;
|
||||
import com.android.launcher3.util.PendingRequestArgs;
|
||||
import com.android.launcher3.util.SafeCloseable;
|
||||
import com.android.launcher3.util.ShortcutUtil;
|
||||
import com.android.launcher3.util.SystemUiController;
|
||||
import com.android.launcher3.util.Themes;
|
||||
import com.android.launcher3.util.Thunk;
|
||||
|
@ -395,7 +395,7 @@ public class Launcher extends StatefulActivity<LauncherState> implements Launche
|
|||
idp.addOnChangeListener(this);
|
||||
mSharedPrefs = Utilities.getPrefs(this);
|
||||
mIconCache = app.getIconCache();
|
||||
mAccessibilityDelegate = new LauncherAccessibilityDelegate(this);
|
||||
mAccessibilityDelegate = createAccessibilityDelegate();
|
||||
|
||||
mDragController = new DragController(this);
|
||||
mAllAppsController = new AllAppsTransitionController(this);
|
||||
|
@ -2694,19 +2694,9 @@ public class Launcher extends StatefulActivity<LauncherState> implements Launche
|
|||
shortcutInfos.add(new KeyboardShortcutInfo(getString(R.string.widget_button_text),
|
||||
KeyEvent.KEYCODE_W, KeyEvent.META_CTRL_ON));
|
||||
}
|
||||
final View currentFocus = getCurrentFocus();
|
||||
if (currentFocus != null) {
|
||||
if (new CustomActionsPopup(this, currentFocus).canShow()) {
|
||||
shortcutInfos.add(new KeyboardShortcutInfo(getString(R.string.custom_actions),
|
||||
KeyEvent.KEYCODE_O, KeyEvent.META_CTRL_ON));
|
||||
}
|
||||
if (currentFocus.getTag() instanceof ItemInfo
|
||||
&& ShortcutUtil.supportsShortcuts((ItemInfo) currentFocus.getTag())) {
|
||||
getSupportedActions(this, getCurrentFocus()).forEach(la ->
|
||||
shortcutInfos.add(new KeyboardShortcutInfo(
|
||||
getString(R.string.shortcuts_menu_with_notifications_description),
|
||||
KeyEvent.KEYCODE_S, KeyEvent.META_CTRL_ON));
|
||||
}
|
||||
}
|
||||
la.accessibilityAction.getLabel(), la.keyCode, KeyEvent.META_CTRL_ON)));
|
||||
if (!shortcutInfos.isEmpty()) {
|
||||
data.add(new KeyboardShortcutGroup(getString(R.string.home_screen), shortcutInfos));
|
||||
}
|
||||
|
@ -2724,30 +2714,18 @@ public class Launcher extends StatefulActivity<LauncherState> implements Launche
|
|||
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,
|
||||
true)) {
|
||||
PopupContainerWithArrow.getOpen(this).requestFocus();
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case KeyEvent.KEYCODE_O:
|
||||
if (new CustomActionsPopup(this, getCurrentFocus()).show()) {
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
case KeyEvent.KEYCODE_W:
|
||||
if (isInState(NORMAL)) {
|
||||
OptionsPopupView.openWidgets(this);
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
for (LauncherAction la : getSupportedActions(this, getCurrentFocus())) {
|
||||
if (la.keyCode == keyCode) {
|
||||
return la.invokeFromKeyboard(getCurrentFocus());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return super.onKeyShortcut(keyCode, event);
|
||||
|
@ -2805,6 +2783,9 @@ public class Launcher extends StatefulActivity<LauncherState> implements Launche
|
|||
return Stream.of(APP_INFO, WIDGETS, INSTALL);
|
||||
}
|
||||
|
||||
protected LauncherAccessibilityDelegate createAccessibilityDelegate() {
|
||||
return new LauncherAccessibilityDelegate(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see LauncherState#getOverviewScaleAndOffset(Launcher)
|
||||
|
|
|
@ -37,6 +37,8 @@ import com.android.launcher3.Launcher.OnResumeCallback;
|
|||
import com.android.launcher3.config.FeatureFlags;
|
||||
import com.android.launcher3.dragndrop.DragOptions;
|
||||
import com.android.launcher3.logging.FileLog;
|
||||
import com.android.launcher3.logging.InstanceId;
|
||||
import com.android.launcher3.logging.InstanceIdSequence;
|
||||
import com.android.launcher3.logging.StatsLogManager;
|
||||
import com.android.launcher3.logging.StatsLogManager.StatsLogger;
|
||||
import com.android.launcher3.model.data.ItemInfo;
|
||||
|
@ -203,9 +205,13 @@ public class SecondaryDropTarget extends ButtonDropTarget implements OnAlarmList
|
|||
d.dragSource = new DeferredOnComplete(d.dragSource, getContext());
|
||||
|
||||
super.onDrop(d, options);
|
||||
StatsLogger logger = mStatsLogManager.logger().withInstanceId(d.logInstanceId);
|
||||
if (d.originalDragInfo != null) {
|
||||
logger.withItemInfo(d.originalDragInfo);
|
||||
doLog(d.logInstanceId, d.originalDragInfo);
|
||||
}
|
||||
|
||||
private void doLog(InstanceId logInstanceId, ItemInfo itemInfo) {
|
||||
StatsLogger logger = mStatsLogManager.logger().withInstanceId(logInstanceId);
|
||||
if (itemInfo != null) {
|
||||
logger.withItemInfo(itemInfo);
|
||||
}
|
||||
if (mCurrentAccessibilityAction == UNINSTALL) {
|
||||
logger.log(LAUNCHER_ITEM_DROPPED_ON_UNINSTALL);
|
||||
|
@ -296,6 +302,7 @@ public class SecondaryDropTarget extends ButtonDropTarget implements OnAlarmList
|
|||
|
||||
@Override
|
||||
public void onAccessibilityDrop(View view, ItemInfo item) {
|
||||
doLog(new InstanceIdSequence().newInstanceId(), item);
|
||||
performDropAction(view, item);
|
||||
}
|
||||
|
||||
|
|
|
@ -3,17 +3,18 @@ package com.android.launcher3.accessibility;
|
|||
import static android.view.accessibility.AccessibilityNodeInfo.ACTION_LONG_CLICK;
|
||||
|
||||
import static com.android.launcher3.LauncherState.NORMAL;
|
||||
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.IGNORE;
|
||||
|
||||
import android.app.AlertDialog;
|
||||
import android.appwidget.AppWidgetProviderInfo;
|
||||
import android.content.DialogInterface;
|
||||
import android.graphics.Point;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.RectF;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
import android.util.SparseArray;
|
||||
import android.view.KeyEvent;
|
||||
import android.view.View;
|
||||
import android.view.View.AccessibilityDelegate;
|
||||
import android.view.accessibility.AccessibilityNodeInfo;
|
||||
|
@ -25,7 +26,6 @@ import com.android.launcher3.ButtonDropTarget;
|
|||
import com.android.launcher3.CellLayout;
|
||||
import com.android.launcher3.DropTarget.DragObject;
|
||||
import com.android.launcher3.Launcher;
|
||||
import com.android.launcher3.LauncherSettings;
|
||||
import com.android.launcher3.LauncherSettings.Favorites;
|
||||
import com.android.launcher3.PendingAddItemInfo;
|
||||
import com.android.launcher3.R;
|
||||
|
@ -33,7 +33,6 @@ import com.android.launcher3.Workspace;
|
|||
import com.android.launcher3.dragndrop.DragController.DragListener;
|
||||
import com.android.launcher3.dragndrop.DragOptions;
|
||||
import com.android.launcher3.folder.Folder;
|
||||
import com.android.launcher3.keyboard.CustomActionsPopup;
|
||||
import com.android.launcher3.keyboard.KeyboardDragAndDropView;
|
||||
import com.android.launcher3.model.data.AppInfo;
|
||||
import com.android.launcher3.model.data.FolderInfo;
|
||||
|
@ -41,14 +40,19 @@ import com.android.launcher3.model.data.ItemInfo;
|
|||
import com.android.launcher3.model.data.LauncherAppWidgetInfo;
|
||||
import com.android.launcher3.model.data.WorkspaceItemInfo;
|
||||
import com.android.launcher3.notification.NotificationListener;
|
||||
import com.android.launcher3.popup.ArrowPopup;
|
||||
import com.android.launcher3.popup.PopupContainerWithArrow;
|
||||
import com.android.launcher3.touch.ItemLongClickListener;
|
||||
import com.android.launcher3.util.IntArray;
|
||||
import com.android.launcher3.util.ShortcutUtil;
|
||||
import com.android.launcher3.util.Thunk;
|
||||
import com.android.launcher3.views.OptionsPopupView;
|
||||
import com.android.launcher3.views.OptionsPopupView.OptionItem;
|
||||
import com.android.launcher3.widget.LauncherAppWidgetHostView;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
public class LauncherAccessibilityDelegate extends AccessibilityDelegate implements DragListener {
|
||||
|
||||
|
@ -78,89 +82,105 @@ public class LauncherAccessibilityDelegate extends AccessibilityDelegate impleme
|
|||
public View item;
|
||||
}
|
||||
|
||||
protected final SparseArray<AccessibilityAction> mActions = new SparseArray<>();
|
||||
@Thunk final Launcher mLauncher;
|
||||
protected final SparseArray<LauncherAction> mActions = new SparseArray<>();
|
||||
protected final Launcher mLauncher;
|
||||
|
||||
private DragInfo mDragInfo = null;
|
||||
|
||||
public LauncherAccessibilityDelegate(Launcher launcher) {
|
||||
mLauncher = launcher;
|
||||
|
||||
mActions.put(REMOVE, new AccessibilityAction(REMOVE,
|
||||
launcher.getText(R.string.remove_drop_target_label)));
|
||||
mActions.put(UNINSTALL, new AccessibilityAction(UNINSTALL,
|
||||
launcher.getText(R.string.uninstall_drop_target_label)));
|
||||
mActions.put(DISMISS_PREDICTION, new AccessibilityAction(DISMISS_PREDICTION,
|
||||
launcher.getText(R.string.dismiss_prediction_label)));
|
||||
mActions.put(RECONFIGURE, new AccessibilityAction(RECONFIGURE,
|
||||
launcher.getText(R.string.gadget_setup_text)));
|
||||
mActions.put(ADD_TO_WORKSPACE, new AccessibilityAction(ADD_TO_WORKSPACE,
|
||||
launcher.getText(R.string.action_add_to_workspace)));
|
||||
mActions.put(MOVE, new AccessibilityAction(MOVE,
|
||||
launcher.getText(R.string.action_move)));
|
||||
mActions.put(MOVE_TO_WORKSPACE, new AccessibilityAction(MOVE_TO_WORKSPACE,
|
||||
launcher.getText(R.string.action_move_to_workspace)));
|
||||
mActions.put(RESIZE, new AccessibilityAction(RESIZE,
|
||||
launcher.getText(R.string.action_resize)));
|
||||
mActions.put(DEEP_SHORTCUTS, new AccessibilityAction(DEEP_SHORTCUTS,
|
||||
launcher.getText(R.string.action_deep_shortcut)));
|
||||
mActions.put(SHORTCUTS_AND_NOTIFICATIONS, new AccessibilityAction(DEEP_SHORTCUTS,
|
||||
launcher.getText(R.string.shortcuts_menu_with_notifications_description)));
|
||||
mActions.put(REMOVE, new LauncherAction(
|
||||
REMOVE, R.string.remove_drop_target_label, KeyEvent.KEYCODE_X));
|
||||
mActions.put(UNINSTALL, new LauncherAction(
|
||||
UNINSTALL, R.string.uninstall_drop_target_label, KeyEvent.KEYCODE_U));
|
||||
mActions.put(DISMISS_PREDICTION, new LauncherAction(DISMISS_PREDICTION,
|
||||
R.string.dismiss_prediction_label, KeyEvent.KEYCODE_X));
|
||||
mActions.put(RECONFIGURE, new LauncherAction(
|
||||
RECONFIGURE, R.string.gadget_setup_text, KeyEvent.KEYCODE_E));
|
||||
mActions.put(ADD_TO_WORKSPACE, new LauncherAction(
|
||||
ADD_TO_WORKSPACE, R.string.action_add_to_workspace, KeyEvent.KEYCODE_P));
|
||||
mActions.put(MOVE, new LauncherAction(
|
||||
MOVE, R.string.action_move, KeyEvent.KEYCODE_M));
|
||||
mActions.put(MOVE_TO_WORKSPACE, new LauncherAction(MOVE_TO_WORKSPACE,
|
||||
R.string.action_move_to_workspace, KeyEvent.KEYCODE_P));
|
||||
mActions.put(RESIZE, new LauncherAction(
|
||||
RESIZE, R.string.action_resize, KeyEvent.KEYCODE_R));
|
||||
mActions.put(DEEP_SHORTCUTS, new LauncherAction(DEEP_SHORTCUTS,
|
||||
R.string.action_deep_shortcut, KeyEvent.KEYCODE_S));
|
||||
mActions.put(SHORTCUTS_AND_NOTIFICATIONS, new LauncherAction(DEEP_SHORTCUTS,
|
||||
R.string.shortcuts_menu_with_notifications_description, KeyEvent.KEYCODE_S));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfo info) {
|
||||
super.onInitializeAccessibilityNodeInfo(host, info);
|
||||
addSupportedActions(host, info, false);
|
||||
}
|
||||
|
||||
public void addSupportedActions(View host, AccessibilityNodeInfo info, boolean fromKeyboard) {
|
||||
if (!(host.getTag() instanceof ItemInfo)) return;
|
||||
if (host.getTag() instanceof ItemInfo) {
|
||||
ItemInfo item = (ItemInfo) host.getTag();
|
||||
|
||||
if (host instanceof AccessibilityActionHandler) {
|
||||
((AccessibilityActionHandler) host).addSupportedAccessibilityActions(info);
|
||||
List<LauncherAction> actions = new ArrayList<>();
|
||||
getSupportedActions(host, item, actions);
|
||||
actions.forEach(la -> info.addAction(la.accessibilityAction));
|
||||
|
||||
if (!itemSupportsLongClick(host, item)) {
|
||||
info.setLongClickable(false);
|
||||
info.removeAction(AccessibilityAction.ACTION_LONG_CLICK);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds all the accessibility actions that can be handled.
|
||||
*/
|
||||
protected void getSupportedActions(View host, ItemInfo item, List<LauncherAction> out) {
|
||||
// If the request came from keyboard, do not add custom shortcuts as that is already
|
||||
// exposed as a direct shortcut
|
||||
if (!fromKeyboard && ShortcutUtil.supportsShortcuts(item)) {
|
||||
info.addAction(mActions.get(NotificationListener.getInstanceIfConnected() != null
|
||||
if (ShortcutUtil.supportsShortcuts(item)) {
|
||||
out.add(mActions.get(NotificationListener.getInstanceIfConnected() != null
|
||||
? SHORTCUTS_AND_NOTIFICATIONS : DEEP_SHORTCUTS));
|
||||
}
|
||||
|
||||
for (ButtonDropTarget target : mLauncher.getDropTargetBar().getDropTargets()) {
|
||||
if (target.supportsAccessibilityDrop(item, host)) {
|
||||
info.addAction(mActions.get(target.getAccessibilityAction()));
|
||||
out.add(mActions.get(target.getAccessibilityAction()));
|
||||
}
|
||||
}
|
||||
|
||||
// Do not add move actions for keyboard request as this uses virtual nodes.
|
||||
if (itemSupportsAccessibleDrag(item)) {
|
||||
info.addAction(mActions.get(MOVE));
|
||||
out.add(mActions.get(MOVE));
|
||||
|
||||
if (item.container >= 0) {
|
||||
info.addAction(mActions.get(MOVE_TO_WORKSPACE));
|
||||
out.add(mActions.get(MOVE_TO_WORKSPACE));
|
||||
} else if (item instanceof LauncherAppWidgetInfo) {
|
||||
if (!getSupportedResizeActions(host, (LauncherAppWidgetInfo) item).isEmpty()) {
|
||||
info.addAction(mActions.get(RESIZE));
|
||||
out.add(mActions.get(RESIZE));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!fromKeyboard && !itemSupportsLongClick(host, item)) {
|
||||
info.setLongClickable(false);
|
||||
info.removeAction(AccessibilityAction.ACTION_LONG_CLICK);
|
||||
}
|
||||
|
||||
if ((item instanceof AppInfo) || (item instanceof PendingAddItemInfo)) {
|
||||
info.addAction(mActions.get(ADD_TO_WORKSPACE));
|
||||
out.add(mActions.get(ADD_TO_WORKSPACE));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all the accessibility actions that can be handled by the host.
|
||||
*/
|
||||
public static List<LauncherAction> getSupportedActions(Launcher launcher, View host) {
|
||||
if (host == null || !(host.getTag() instanceof ItemInfo)) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
PopupContainerWithArrow container = PopupContainerWithArrow.getOpen(launcher);
|
||||
LauncherAccessibilityDelegate delegate = container != null
|
||||
? container.getAccessibilityDelegate() : launcher.getAccessibilityDelegate();
|
||||
List<LauncherAction> result = new ArrayList<>();
|
||||
delegate.getSupportedActions(host, (ItemInfo) host.getTag(), result);
|
||||
return result;
|
||||
}
|
||||
|
||||
private boolean itemSupportsLongClick(View host, ItemInfo info) {
|
||||
return PopupContainerWithArrow.canShow(host, info)
|
||||
|| new CustomActionsPopup(mLauncher, host).canShow();
|
||||
return PopupContainerWithArrow.canShow(host, info);
|
||||
}
|
||||
|
||||
private boolean itemSupportsAccessibleDrag(ItemInfo item) {
|
||||
|
@ -184,7 +204,7 @@ public class LauncherAccessibilityDelegate extends AccessibilityDelegate impleme
|
|||
/**
|
||||
* Performs the provided action on the host
|
||||
*/
|
||||
public boolean performAction(final View host, final ItemInfo item, int action,
|
||||
protected boolean performAction(final View host, final ItemInfo item, int action,
|
||||
boolean fromKeyboard) {
|
||||
if (action == ACTION_LONG_CLICK) {
|
||||
if (PopupContainerWithArrow.canShow(host, item)) {
|
||||
|
@ -193,19 +213,8 @@ public class LauncherAccessibilityDelegate extends AccessibilityDelegate impleme
|
|||
// standard long press path does.
|
||||
PopupContainerWithArrow.showForIcon((BubbleTextView) host);
|
||||
return true;
|
||||
} else {
|
||||
CustomActionsPopup popup = new CustomActionsPopup(mLauncher, host);
|
||||
if (popup.canShow()) {
|
||||
popup.show();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (host instanceof AccessibilityActionHandler
|
||||
&& ((AccessibilityActionHandler) host).performAccessibilityAction(action, item)) {
|
||||
return true;
|
||||
}
|
||||
if (action == MOVE) {
|
||||
} else if (action == MOVE) {
|
||||
return beginAccessibleDrag(host, item, fromKeyboard);
|
||||
} else if (action == ADD_TO_WORKSPACE) {
|
||||
final int[] coordinates = new int[2];
|
||||
|
@ -220,9 +229,7 @@ public class LauncherAccessibilityDelegate extends AccessibilityDelegate impleme
|
|||
Favorites.CONTAINER_DESKTOP,
|
||||
screenId, coordinates[0], coordinates[1]);
|
||||
|
||||
ArrayList<ItemInfo> itemList = new ArrayList<>();
|
||||
itemList.add(info);
|
||||
mLauncher.bindItems(itemList, true);
|
||||
mLauncher.bindItems(Collections.singletonList(info), true);
|
||||
announceConfirmation(R.string.item_added_to_workspace);
|
||||
} else if (item instanceof PendingAddItemInfo) {
|
||||
PendingAddItemInfo info = (PendingAddItemInfo) item;
|
||||
|
@ -243,47 +250,31 @@ public class LauncherAccessibilityDelegate extends AccessibilityDelegate impleme
|
|||
final int[] coordinates = new int[2];
|
||||
final int screenId = findSpaceOnWorkspace(item, coordinates);
|
||||
mLauncher.getModelWriter().moveItemInDatabase(info,
|
||||
LauncherSettings.Favorites.CONTAINER_DESKTOP,
|
||||
Favorites.CONTAINER_DESKTOP,
|
||||
screenId, coordinates[0], coordinates[1]);
|
||||
|
||||
// Bind the item in next frame so that if a new workspace page was created,
|
||||
// it will get laid out.
|
||||
new Handler().post(new Runnable() {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
ArrayList<ItemInfo> itemList = new ArrayList<>();
|
||||
itemList.add(item);
|
||||
mLauncher.bindItems(itemList, true);
|
||||
new Handler().post(() -> {
|
||||
mLauncher.bindItems(Collections.singletonList(item), true);
|
||||
announceConfirmation(R.string.item_moved);
|
||||
}
|
||||
});
|
||||
return true;
|
||||
} else if (action == RESIZE) {
|
||||
final LauncherAppWidgetInfo info = (LauncherAppWidgetInfo) item;
|
||||
final IntArray actions = getSupportedResizeActions(host, info);
|
||||
CharSequence[] labels = new CharSequence[actions.size()];
|
||||
for (int i = 0; i < actions.size(); i++) {
|
||||
labels[i] = mLauncher.getText(actions.get(i));
|
||||
}
|
||||
|
||||
new AlertDialog.Builder(mLauncher)
|
||||
.setTitle(R.string.action_resize)
|
||||
.setItems(labels, new DialogInterface.OnClickListener() {
|
||||
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
performResizeAction(actions.get(which), host, info);
|
||||
dialog.dismiss();
|
||||
}
|
||||
})
|
||||
.show();
|
||||
List<OptionItem> actions = getSupportedResizeActions(host, info);
|
||||
Rect pos = new Rect();
|
||||
mLauncher.getDragLayer().getDescendantRectRelativeToSelf(host, pos);
|
||||
ArrowPopup popup = OptionsPopupView.show(mLauncher, new RectF(pos), actions);
|
||||
popup.requestFocus();
|
||||
popup.setOnCloseCallback(host::requestFocus);
|
||||
return true;
|
||||
} else if (action == DEEP_SHORTCUTS) {
|
||||
} else if (action == DEEP_SHORTCUTS || action == SHORTCUTS_AND_NOTIFICATIONS) {
|
||||
return PopupContainerWithArrow.showForIcon((BubbleTextView) host) != null;
|
||||
} else {
|
||||
for (ButtonDropTarget dropTarget : mLauncher.getDropTargetBar().getDropTargets()) {
|
||||
if (dropTarget.supportsAccessibilityDrop(item, host) &&
|
||||
action == dropTarget.getAccessibilityAction()) {
|
||||
if (dropTarget.supportsAccessibilityDrop(item, host)
|
||||
&& action == dropTarget.getAccessibilityAction()) {
|
||||
dropTarget.onAccessibilityDrop(host, item);
|
||||
return true;
|
||||
}
|
||||
|
@ -292,9 +283,8 @@ public class LauncherAccessibilityDelegate extends AccessibilityDelegate impleme
|
|||
return false;
|
||||
}
|
||||
|
||||
private IntArray getSupportedResizeActions(View host, LauncherAppWidgetInfo info) {
|
||||
IntArray actions = new IntArray();
|
||||
|
||||
private List<OptionItem> getSupportedResizeActions(View host, LauncherAppWidgetInfo info) {
|
||||
List<OptionItem> actions = new ArrayList<>();
|
||||
AppWidgetProviderInfo providerInfo = ((LauncherAppWidgetHostView) host).getAppWidgetInfo();
|
||||
if (providerInfo == null) {
|
||||
return actions;
|
||||
|
@ -304,28 +294,40 @@ public class LauncherAccessibilityDelegate extends AccessibilityDelegate impleme
|
|||
if ((providerInfo.resizeMode & AppWidgetProviderInfo.RESIZE_HORIZONTAL) != 0) {
|
||||
if (layout.isRegionVacant(info.cellX + info.spanX, info.cellY, 1, info.spanY) ||
|
||||
layout.isRegionVacant(info.cellX - 1, info.cellY, 1, info.spanY)) {
|
||||
actions.add(R.string.action_increase_width);
|
||||
actions.add(new OptionItem(
|
||||
R.string.action_increase_width, R.drawable.ic_widget_width_increase,
|
||||
IGNORE,
|
||||
v -> performResizeAction(R.string.action_increase_width, host, info)));
|
||||
}
|
||||
|
||||
if (info.spanX > info.minSpanX && info.spanX > 1) {
|
||||
actions.add(R.string.action_decrease_width);
|
||||
actions.add(new OptionItem(
|
||||
R.string.action_decrease_width, R.drawable.ic_widget_width_decrease,
|
||||
IGNORE,
|
||||
v -> performResizeAction(R.string.action_decrease_width, host, info)));
|
||||
}
|
||||
}
|
||||
|
||||
if ((providerInfo.resizeMode & AppWidgetProviderInfo.RESIZE_VERTICAL) != 0) {
|
||||
if (layout.isRegionVacant(info.cellX, info.cellY + info.spanY, info.spanX, 1) ||
|
||||
layout.isRegionVacant(info.cellX, info.cellY - 1, info.spanX, 1)) {
|
||||
actions.add(R.string.action_increase_height);
|
||||
actions.add(new OptionItem(
|
||||
R.string.action_increase_height, R.drawable.ic_widget_height_increase,
|
||||
IGNORE,
|
||||
v -> performResizeAction(R.string.action_increase_height, host, info)));
|
||||
}
|
||||
|
||||
if (info.spanY > info.minSpanY && info.spanY > 1) {
|
||||
actions.add(R.string.action_decrease_height);
|
||||
actions.add(new OptionItem(
|
||||
R.string.action_decrease_height, R.drawable.ic_widget_height_decrease,
|
||||
IGNORE,
|
||||
v -> performResizeAction(R.string.action_decrease_height, host, info)));
|
||||
}
|
||||
}
|
||||
return actions;
|
||||
}
|
||||
|
||||
@Thunk void performResizeAction(int action, View host, LauncherAppWidgetInfo info) {
|
||||
private boolean performResizeAction(int action, View host, LauncherAppWidgetInfo info) {
|
||||
CellLayout.LayoutParams lp = (CellLayout.LayoutParams) host.getLayoutParams();
|
||||
CellLayout layout = (CellLayout) host.getParent().getParent();
|
||||
layout.markCellsAsUnoccupiedForView(host);
|
||||
|
@ -362,6 +364,7 @@ public class LauncherAccessibilityDelegate extends AccessibilityDelegate impleme
|
|||
host.requestLayout();
|
||||
mLauncher.getModelWriter().updateItemInDatabase(info);
|
||||
announceConfirmation(mLauncher.getString(R.string.widget_resized, info.spanX, info.spanY));
|
||||
return true;
|
||||
}
|
||||
|
||||
@Thunk void announceConfirmation(int resId) {
|
||||
|
@ -489,19 +492,28 @@ public class LauncherAccessibilityDelegate extends AccessibilityDelegate impleme
|
|||
return screenId;
|
||||
}
|
||||
|
||||
/**
|
||||
* An interface allowing views to handle their own action.
|
||||
*/
|
||||
public interface AccessibilityActionHandler {
|
||||
public class LauncherAction {
|
||||
public final int keyCode;
|
||||
public final AccessibilityAction accessibilityAction;
|
||||
|
||||
private final LauncherAccessibilityDelegate mDelegate;
|
||||
|
||||
public LauncherAction(int id, int labelRes, int keyCode) {
|
||||
this.keyCode = keyCode;
|
||||
accessibilityAction = new AccessibilityAction(id, mLauncher.getString(labelRes));
|
||||
mDelegate = LauncherAccessibilityDelegate.this;
|
||||
}
|
||||
|
||||
/**
|
||||
* performs accessibility action and returns true on success
|
||||
* Invokes the action for the provided host
|
||||
*/
|
||||
boolean performAccessibilityAction(int action, ItemInfo itemInfo);
|
||||
|
||||
/**
|
||||
* adds all the accessibility actions that can be handled.
|
||||
*/
|
||||
void addSupportedAccessibilityActions(AccessibilityNodeInfo accessibilityNodeInfo);
|
||||
public boolean invokeFromKeyboard(View host) {
|
||||
if (host != null && host.getTag() instanceof ItemInfo) {
|
||||
return mDelegate.performAction(
|
||||
host, (ItemInfo) host.getTag(), accessibilityAction.getId(), true);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,9 +18,8 @@ package com.android.launcher3.accessibility;
|
|||
|
||||
import static com.android.launcher3.LauncherState.NORMAL;
|
||||
|
||||
import android.view.KeyEvent;
|
||||
import android.view.View;
|
||||
import android.view.accessibility.AccessibilityNodeInfo;
|
||||
import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction;
|
||||
|
||||
import com.android.launcher3.AbstractFloatingView;
|
||||
import com.android.launcher3.Launcher;
|
||||
|
@ -31,7 +30,8 @@ import com.android.launcher3.model.data.WorkspaceItemInfo;
|
|||
import com.android.launcher3.notification.NotificationMainView;
|
||||
import com.android.launcher3.shortcuts.DeepShortcutView;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Extension of {@link LauncherAccessibilityDelegate} with actions specific to shortcuts in
|
||||
|
@ -43,23 +43,23 @@ public class ShortcutMenuAccessibilityDelegate extends LauncherAccessibilityDele
|
|||
|
||||
public ShortcutMenuAccessibilityDelegate(Launcher launcher) {
|
||||
super(launcher);
|
||||
mActions.put(DISMISS_NOTIFICATION, new AccessibilityAction(DISMISS_NOTIFICATION,
|
||||
launcher.getText(R.string.action_dismiss_notification)));
|
||||
mActions.put(DISMISS_NOTIFICATION, new LauncherAction(DISMISS_NOTIFICATION,
|
||||
R.string.action_dismiss_notification, KeyEvent.KEYCODE_X));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addSupportedActions(View host, AccessibilityNodeInfo info, boolean fromKeyboard) {
|
||||
protected void getSupportedActions(View host, ItemInfo item, List<LauncherAction> out) {
|
||||
if ((host.getParent() instanceof DeepShortcutView)) {
|
||||
info.addAction(mActions.get(ADD_TO_WORKSPACE));
|
||||
out.add(mActions.get(ADD_TO_WORKSPACE));
|
||||
} else if (host instanceof NotificationMainView) {
|
||||
if (((NotificationMainView) host).canChildBeDismissed()) {
|
||||
info.addAction(mActions.get(DISMISS_NOTIFICATION));
|
||||
out.add(mActions.get(DISMISS_NOTIFICATION));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean performAction(View host, ItemInfo item, int action, boolean fromKeyboard) {
|
||||
protected boolean performAction(View host, ItemInfo item, int action, boolean fromKeyboard) {
|
||||
if (action == ADD_TO_WORKSPACE) {
|
||||
if (!(host.getParent() instanceof DeepShortcutView)) {
|
||||
return false;
|
||||
|
@ -73,9 +73,7 @@ public class ShortcutMenuAccessibilityDelegate extends LauncherAccessibilityDele
|
|||
mLauncher.getModelWriter().addItemToDatabase(info,
|
||||
LauncherSettings.Favorites.CONTAINER_DESKTOP,
|
||||
screenId, coordinates[0], coordinates[1]);
|
||||
ArrayList<ItemInfo> itemList = new ArrayList<>();
|
||||
itemList.add(info);
|
||||
mLauncher.bindItems(itemList, true);
|
||||
mLauncher.bindItems(Collections.singletonList(info), true);
|
||||
AbstractFloatingView.closeAllOpenViews(mLauncher);
|
||||
announceConfirmation(R.string.item_added_to_workspace);
|
||||
}
|
||||
|
|
|
@ -1,94 +0,0 @@
|
|||
/*
|
||||
* 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.Launcher;
|
||||
import com.android.launcher3.accessibility.LauncherAccessibilityDelegate;
|
||||
import com.android.launcher3.model.data.ItemInfo;
|
||||
import com.android.launcher3.popup.PopupContainerWithArrow;
|
||||
|
||||
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;
|
||||
PopupContainerWithArrow container = PopupContainerWithArrow.getOpen(launcher);
|
||||
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(),
|
||||
true);
|
||||
}
|
||||
}
|
|
@ -40,6 +40,8 @@ import android.view.ViewGroup;
|
|||
import android.view.ViewOutlineProvider;
|
||||
import android.widget.FrameLayout;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import com.android.launcher3.AbstractFloatingView;
|
||||
import com.android.launcher3.BaseDraggingActivity;
|
||||
import com.android.launcher3.InsettableFrameLayout;
|
||||
|
@ -82,6 +84,8 @@ public abstract class ArrowPopup<T extends BaseDraggingActivity> extends Abstrac
|
|||
private final Rect mStartRect = new Rect();
|
||||
private final Rect mEndRect = new Rect();
|
||||
|
||||
private Runnable mOnCloseCallback = () -> { };
|
||||
|
||||
public ArrowPopup(Context context, AttributeSet attrs, int defStyleAttr) {
|
||||
super(context, attrs, defStyleAttr);
|
||||
mInflater = LayoutInflater.from(context);
|
||||
|
@ -555,6 +559,14 @@ public abstract class ArrowPopup<T extends BaseDraggingActivity> extends Abstrac
|
|||
mDeferContainerRemoval = false;
|
||||
getPopupContainer().removeView(this);
|
||||
getPopupContainer().removeView(mArrow);
|
||||
mOnCloseCallback.run();
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback to be called when the popup is closed
|
||||
*/
|
||||
public void setOnCloseCallback(@NonNull Runnable callback) {
|
||||
mOnCloseCallback = callback;
|
||||
}
|
||||
|
||||
protected BaseDragLayer getPopupContainer() {
|
||||
|
|
|
@ -206,6 +206,7 @@ public class PopupContainerWithArrow<T extends BaseDraggingActivity> extends Arr
|
|||
.filter(Objects::nonNull)
|
||||
.collect(Collectors.toList()));
|
||||
launcher.refreshAndBindWidgetsForPackageUser(PackageUserKey.fromItemInfo(item));
|
||||
container.requestFocus();
|
||||
return container;
|
||||
}
|
||||
|
||||
|
|
|
@ -118,7 +118,8 @@ public class OptionsPopupView extends ArrowPopup
|
|||
mTargetRect.roundOut(outPos);
|
||||
}
|
||||
|
||||
public static void show(Launcher launcher, RectF targetRect, List<OptionItem> items) {
|
||||
public static OptionsPopupView show(
|
||||
Launcher launcher, RectF targetRect, List<OptionItem> items) {
|
||||
OptionsPopupView popup = (OptionsPopupView) launcher.getLayoutInflater()
|
||||
.inflate(R.layout.longpress_options_menu, launcher.getDragLayer(), false);
|
||||
popup.mTargetRect = targetRect;
|
||||
|
@ -134,6 +135,7 @@ public class OptionsPopupView extends ArrowPopup
|
|||
popup.mItemMap.put(view, item);
|
||||
}
|
||||
popup.show();
|
||||
return popup;
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
|
|
Loading…
Reference in New Issue