Merge "Temporary workaround for long failure messages when running from AS" into ub-launcher3-master
diff --git a/go/src/com/android/launcher3/shortcuts/DeepShortcutManager.java b/go/src/com/android/launcher3/shortcuts/DeepShortcutManager.java
deleted file mode 100644
index 42b1194..0000000
--- a/go/src/com/android/launcher3/shortcuts/DeepShortcutManager.java
+++ /dev/null
@@ -1,119 +0,0 @@
-/*
- * Copyright (C) 2018 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.shortcuts;
-
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.pm.ShortcutInfo;
-import android.graphics.Rect;
-import android.graphics.drawable.Drawable;
-import android.os.Bundle;
-import android.os.UserHandle;
-
-import com.android.launcher3.ItemInfo;
-import com.android.launcher3.notification.NotificationKeyData;
-
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * Performs operations related to deep shortcuts, such as querying for them, pinning them, etc.
- */
-public class DeepShortcutManager {
-
- private static final DeepShortcutManager sInstance = new DeepShortcutManager();
-
- public static DeepShortcutManager getInstance(Context context) {
- return sInstance;
- }
-
- private final QueryResult mFailure = new QueryResult();
-
- private DeepShortcutManager() { }
-
- /**
- * Queries for the shortcuts with the package name and provided ids.
- *
- * This method is intended to get the full details for shortcuts when they are added or updated,
- * because we only get "key" fields in onShortcutsChanged().
- */
- public QueryResult queryForFullDetails(String packageName,
- List<String> shortcutIds, UserHandle user) {
- return mFailure;
- }
-
- /**
- * Gets all the manifest and dynamic shortcuts associated with the given package and user,
- * to be displayed in the shortcuts container on long press.
- */
- public QueryResult queryForShortcutsContainer(ComponentName activity,
- UserHandle user) {
- return mFailure;
- }
-
- /**
- * Removes the given shortcut from the current list of pinned shortcuts.
- * (Runs on background thread)
- */
- public void unpinShortcut(final ShortcutKey key) {
- }
-
- /**
- * Adds the given shortcut to the current list of pinned shortcuts.
- * (Runs on background thread)
- */
- public void pinShortcut(final ShortcutKey key) {
- }
-
- public void startShortcut(String packageName, String id, Rect sourceBounds,
- Bundle startActivityOptions, UserHandle user) {
- }
-
- public Drawable getShortcutIconDrawable(ShortcutInfo shortcutInfo, int density) {
- return null;
- }
-
- /**
- * Returns the id's of pinned shortcuts associated with the given package and user.
- *
- * If packageName is null, returns all pinned shortcuts regardless of package.
- */
- public QueryResult queryForPinnedShortcuts(String packageName, UserHandle user) {
- return mFailure;
- }
-
- public QueryResult queryForPinnedShortcuts(String packageName,
- List<String> shortcutIds, UserHandle user) {
- return mFailure;
- }
-
- public QueryResult queryForAllShortcuts(UserHandle user) {
- return mFailure;
- }
-
- public boolean hasHostPermission() {
- return false;
- }
-
-
- public static class QueryResult extends ArrayList<ShortcutInfo> {
-
- public boolean wasSuccess() {
- return true;
- }
- }
-}
diff --git a/protos/launcher_log.proto b/protos/launcher_log.proto
index 8f413dc..0560d68 100644
--- a/protos/launcher_log.proto
+++ b/protos/launcher_log.proto
@@ -93,7 +93,7 @@
TASKSWITCHER = 12; // Recents UI Container (QuickStep)
APP = 13; // Foreground activity is another app (QuickStep)
TIP = 14; // Onboarding texts (QuickStep)
- SIDELOADED_LAUNCHER = 15;
+ OTHER_LAUNCHER_APP = 15;
}
// Used to define what type of control a Target would represent.
diff --git a/quickstep/recents_ui_overrides/res/drawable/predicted_icon_background.xml b/quickstep/recents_ui_overrides/res/drawable/predicted_icon_background.xml
deleted file mode 100644
index cfc6d48..0000000
--- a/quickstep/recents_ui_overrides/res/drawable/predicted_icon_background.xml
+++ /dev/null
@@ -1,8 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<inset xmlns:android="http://schemas.android.com/apk/res/android"
- android:inset="@dimen/predicted_icon_background_inset">
- <shape>
- <solid android:color="?attr/folderFillColor" />
- <corners android:radius="@dimen/predicted_icon_background_corner_radius" />
- </shape>
-</inset>
diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/HotseatPredictionController.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/HotseatPredictionController.java
index f7e71f3..b94142a 100644
--- a/quickstep/recents_ui_overrides/src/com/android/launcher3/HotseatPredictionController.java
+++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/HotseatPredictionController.java
@@ -44,6 +44,7 @@
import com.android.launcher3.icons.IconCache;
import com.android.launcher3.popup.SystemShortcut;
import com.android.launcher3.shortcuts.ShortcutKey;
+import com.android.launcher3.touch.ItemLongClickListener;
import com.android.launcher3.uioverrides.PredictedAppIcon;
import com.android.launcher3.uioverrides.QuickstepLauncher;
import com.android.launcher3.userevent.nano.LauncherLogProto;
@@ -61,7 +62,7 @@
public class HotseatPredictionController implements DragController.DragListener,
View.OnAttachStateChangeListener, SystemShortcut.Factory<QuickstepLauncher>,
InvariantDeviceProfile.OnIDPChangeListener, AllAppsStore.OnUpdateListener,
- IconCache.ItemInfoUpdateReceiver {
+ IconCache.ItemInfoUpdateReceiver, DragSource {
private static final String TAG = "PredictiveHotseat";
private static final boolean DEBUG = false;
@@ -72,6 +73,9 @@
private static final String APP_LOCATION_HOTSEAT = "hotseat";
private static final String APP_LOCATION_WORKSPACE = "workspace";
+ private static final String BUNDLE_KEY_HOTSEAT = "hotseat_apps";
+ private static final String BUNDLE_KEY_WORKSPACE = "workspace_apps";
+
private static final String PREDICTION_CLIENT = "hotseat";
private DropTarget.DragObject mDragObject;
@@ -79,7 +83,7 @@
private int mPredictedSpotsCount = 0;
private Launcher mLauncher;
- private Hotseat mHotseat;
+ private final Hotseat mHotseat;
private List<ComponentKeyMapper> mComponentKeyMappers = new ArrayList<>();
@@ -87,10 +91,18 @@
private AppPredictor mAppPredictor;
private AllAppsStore mAllAppsStore;
+ private AnimatorSet mIconRemoveAnimators;
+
private List<PredictedAppIcon.PredictedIconOutlineDrawing> mOutlineDrawings = new ArrayList<>();
- private static HotseatPredictionController sInstance;
+ private final View.OnLongClickListener mPredictionLongClickListener = v -> {
+ if (!ItemLongClickListener.canStartDrag(mLauncher)) return false;
+ if (mLauncher.getWorkspace().isSwitchingState()) return false;
+ // Start the drag
+ mLauncher.getWorkspace().beginDragShared(v, this, new DragOptions());
+ return false;
+ };
public HotseatPredictionController(Launcher launcher) {
mLauncher = launcher;
@@ -101,7 +113,9 @@
mHotSeatItemsCount = mLauncher.getDeviceProfile().inv.numHotseatIcons;
launcher.getDeviceProfile().inv.addOnChangeListener(this);
mHotseat.addOnAttachStateChangeListener(this);
- sInstance = this;
+ if (mHotseat.isAttachedToWindow()) {
+ onViewAttachedToWindow(mHotseat);
+ }
}
@Override
@@ -125,6 +139,17 @@
List<WorkspaceItemInfo> predictedApps = mapToWorkspaceItemInfo(mComponentKeyMappers);
int predictionIndex = 0;
ArrayList<WorkspaceItemInfo> newItems = new ArrayList<>();
+ // make sure predicted icon removal and filling predictions don't step on each other
+ if (mIconRemoveAnimators != null && mIconRemoveAnimators.isRunning()) {
+ mIconRemoveAnimators.addListener(new AnimationSuccessListener() {
+ @Override
+ public void onAnimationSuccess(Animator animator) {
+ fillGapsWithPrediction(animate, callback);
+ mIconRemoveAnimators.removeListener(this);
+ }
+ });
+ return;
+ }
for (int rank = 0; rank < mHotSeatItemsCount; rank++) {
View child = mHotseat.getChildAt(
mHotseat.getCellXFromOrder(rank),
@@ -140,12 +165,11 @@
}
continue;
}
-
WorkspaceItemInfo predictedItem = predictedApps.get(predictionIndex++);
if (isPredictedIcon(child) && child.isEnabled()) {
PredictedAppIcon icon = (PredictedAppIcon) child;
icon.applyFromWorkspaceItem(predictedItem);
- icon.finishBinding();
+ icon.finishBinding(mPredictionLongClickListener);
} else {
newItems.add(predictedItem);
}
@@ -160,7 +184,7 @@
for (WorkspaceItemInfo item : itemsToAdd) {
PredictedAppIcon icon = PredictedAppIcon.createIcon(mHotseat, item);
mLauncher.getWorkspace().addInScreenFromBind(icon, item);
- icon.finishBinding();
+ icon.finishBinding(mPredictionLongClickListener);
if (animate) {
animationSet.play(ObjectAnimator.ofFloat(icon, SCALE_PROPERTY, 0.2f, 1));
}
@@ -215,9 +239,9 @@
private Bundle getAppPredictionContextExtra() {
Bundle bundle = new Bundle();
- bundle.putParcelableArrayList(APP_LOCATION_HOTSEAT,
+ bundle.putParcelableArrayList(BUNDLE_KEY_HOTSEAT,
getPinnedAppTargetsInViewGroup((mHotseat.getShortcutsAndWidgets())));
- bundle.putParcelableArrayList(APP_LOCATION_WORKSPACE, getPinnedAppTargetsInViewGroup(
+ bundle.putParcelableArrayList(BUNDLE_KEY_WORKSPACE, getPinnedAppTargetsInViewGroup(
mLauncher.getWorkspace().getScreenWithId(
Workspace.FIRST_SCREEN_ID).getShortcutsAndWidgets()));
return bundle;
@@ -285,9 +309,12 @@
ItemInfoWithIcon info = mapper.getApp(allAppsStore);
if (info instanceof AppInfo) {
WorkspaceItemInfo predictedApp = new WorkspaceItemInfo((AppInfo) info);
+ predictedApp.container = LauncherSettings.Favorites.CONTAINER_HOTSEAT_PREDICTION;
predictedApps.add(predictedApp);
} else if (info instanceof WorkspaceItemInfo) {
- predictedApps.add(new WorkspaceItemInfo((WorkspaceItemInfo) info));
+ WorkspaceItemInfo predictedApp = new WorkspaceItemInfo((WorkspaceItemInfo) info);
+ predictedApp.container = LauncherSettings.Favorites.CONTAINER_HOTSEAT_PREDICTION;
+ predictedApps.add(predictedApp);
} else {
if (DEBUG) {
Log.e(TAG, "Predicted app not found: " + mapper);
@@ -313,13 +340,27 @@
return icons;
}
- private void removePredictedApps(List<PredictedAppIcon.PredictedIconOutlineDrawing> outlines) {
+ private void removePredictedApps(List<PredictedAppIcon.PredictedIconOutlineDrawing> outlines,
+ ItemInfo draggedInfo) {
+ if (mIconRemoveAnimators != null) {
+ mIconRemoveAnimators.end();
+ }
+ mIconRemoveAnimators = new AnimatorSet();
+ removeOutlineDrawings();
for (PredictedAppIcon icon : getPredictedIcons()) {
+ if (!icon.isEnabled()) {
+ continue;
+ }
+ if (icon.getTag().equals(draggedInfo)) {
+ mHotseat.removeView(icon);
+ continue;
+ }
int rank = ((WorkspaceItemInfo) icon.getTag()).rank;
outlines.add(new PredictedAppIcon.PredictedIconOutlineDrawing(
mHotseat.getCellXFromOrder(rank), mHotseat.getCellYFromOrder(rank), icon));
icon.setEnabled(false);
- icon.animate().scaleY(0).scaleX(0).setListener(new AnimationSuccessListener() {
+ ObjectAnimator animator = ObjectAnimator.ofFloat(icon, SCALE_PROPERTY, 0);
+ animator.addListener(new AnimationSuccessListener() {
@Override
public void onAnimationSuccess(Animator animator) {
if (icon.getParent() != null) {
@@ -327,10 +368,11 @@
}
}
});
+ mIconRemoveAnimators.play(animator);
}
+ mIconRemoveAnimators.start();
}
-
private void notifyItemAction(AppTarget target, String location, int action) {
if (mAppPredictor != null) {
mAppPredictor.notifyAppTargetEvent(new AppTargetEvent.Builder(target,
@@ -340,7 +382,7 @@
@Override
public void onDragStart(DropTarget.DragObject dragObject, DragOptions options) {
- removePredictedApps(mOutlineDrawings);
+ removePredictedApps(mOutlineDrawings, dragObject.dragInfo);
mDragObject = dragObject;
if (mOutlineDrawings.isEmpty()) return;
for (PredictedAppIcon.PredictedIconOutlineDrawing outlineDrawing : mOutlineDrawings) {
@@ -354,14 +396,25 @@
if (mDragObject == null) {
return;
}
+
ItemInfo dragInfo = mDragObject.dragInfo;
- if (dragInfo instanceof WorkspaceItemInfo && dragInfo.getTargetComponent() != null) {
+ ViewGroup hotseatVG = mHotseat.getShortcutsAndWidgets();
+ ViewGroup firstScreenVG = mLauncher.getWorkspace().getScreenWithId(
+ Workspace.FIRST_SCREEN_ID).getShortcutsAndWidgets();
+
+ if (dragInfo instanceof WorkspaceItemInfo
+ && dragInfo.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION
+ && dragInfo.getTargetComponent() != null) {
AppTarget appTarget = getAppTargetFromItemInfo(dragInfo);
if (!isInHotseat(dragInfo) && isInHotseat(mDragObject.originalDragInfo)) {
- notifyItemAction(appTarget, APP_LOCATION_HOTSEAT, APPTARGET_ACTION_UNPIN);
+ if (!getPinnedAppTargetsInViewGroup(hotseatVG).contains(appTarget)) {
+ notifyItemAction(appTarget, APP_LOCATION_HOTSEAT, APPTARGET_ACTION_UNPIN);
+ }
}
if (!isInFirstPage(dragInfo) && isInFirstPage(mDragObject.originalDragInfo)) {
- notifyItemAction(appTarget, APP_LOCATION_WORKSPACE, APPTARGET_ACTION_UNPIN);
+ if (!getPinnedAppTargetsInViewGroup(firstScreenVG).contains(appTarget)) {
+ notifyItemAction(appTarget, APP_LOCATION_WORKSPACE, APPTARGET_ACTION_UNPIN);
+ }
}
if (isInHotseat(dragInfo) && !isInHotseat(mDragObject.originalDragInfo)) {
notifyItemAction(appTarget, APP_LOCATION_HOTSEAT, AppTargetEvent.ACTION_PIN);
@@ -371,14 +424,7 @@
}
}
mDragObject = null;
- fillGapsWithPrediction(true, () -> {
- if (mOutlineDrawings.isEmpty()) return;
- for (PredictedAppIcon.PredictedIconOutlineDrawing outlineDrawing : mOutlineDrawings) {
- mHotseat.removeDelegatedCellDrawing(outlineDrawing);
- }
- mHotseat.invalidate();
- mOutlineDrawings.clear();
- });
+ fillGapsWithPrediction(true, this::removeOutlineDrawings);
}
@Nullable
@@ -394,11 +440,20 @@
private void preparePredictionInfo(WorkspaceItemInfo itemInfo, int rank) {
itemInfo.container = LauncherSettings.Favorites.CONTAINER_HOTSEAT_PREDICTION;
itemInfo.rank = rank;
- itemInfo.cellX = rank;
- itemInfo.cellY = mHotSeatItemsCount - rank - 1;
+ itemInfo.cellX = mHotseat.getCellXFromOrder(rank);
+ itemInfo.cellY = mHotseat.getCellYFromOrder(rank);
itemInfo.screenId = rank;
}
+ private void removeOutlineDrawings() {
+ if (mOutlineDrawings.isEmpty()) return;
+ for (PredictedAppIcon.PredictedIconOutlineDrawing outlineDrawing : mOutlineDrawings) {
+ mHotseat.removeDelegatedCellDrawing(outlineDrawing);
+ }
+ mHotseat.invalidate();
+ mOutlineDrawings.clear();
+ }
+
@Override
public void onIdpChanged(int changeFlags, InvariantDeviceProfile profile) {
this.mHotSeatItemsCount = profile.numHotseatIcons;
@@ -415,6 +470,17 @@
}
+ @Override
+ public void onDropCompleted(View target, DropTarget.DragObject d, boolean success) {
+ //Does nothing
+ }
+
+ @Override
+ public void fillInLogContainerData(View v, ItemInfo info, LauncherLogProto.Target target,
+ LauncherLogProto.Target targetParent) {
+ mHotseat.fillInLogContainerData(v, info, target, targetParent);
+ }
+
private class PinPrediction extends SystemShortcut<QuickstepLauncher> {
private PinPrediction(QuickstepLauncher target, ItemInfo itemInfo) {
@@ -435,18 +501,22 @@
*/
public static void fillInHybridHotseatRank(
@NonNull ItemInfo itemInfo, @NonNull LauncherLogProto.Target target) {
- if (sInstance == null || itemInfo.getTargetComponent() == null
+ QuickstepLauncher launcher = QuickstepLauncher.ACTIVITY_TRACKER.getCreatedActivity();
+ if (launcher == null || launcher.getHotseatPredictionController() == null
+ || itemInfo.getTargetComponent() == null
|| itemInfo.container != LauncherSettings.Favorites.CONTAINER_HOTSEAT_PREDICTION) {
return;
}
+ HotseatPredictionController controller = launcher.getHotseatPredictionController();
+
final ComponentKey k = new ComponentKey(itemInfo.getTargetComponent(), itemInfo.user);
- final List<ComponentKeyMapper> predictedApps = sInstance.mComponentKeyMappers;
+ final List<ComponentKeyMapper> predictedApps = controller.mComponentKeyMappers;
IntStream.range(0, predictedApps.size())
.filter((i) -> k.equals(predictedApps.get(i).getComponentKey()))
.findFirst()
.ifPresent((rank) -> target.predictedRank =
- Integer.parseInt(sInstance.mPredictedSpotsCount + "0" + rank));
+ Integer.parseInt(controller.mPredictedSpotsCount + "0" + rank));
}
private static boolean isPredictedIcon(View view) {
@@ -461,8 +531,7 @@
}
ItemInfo info = (ItemInfo) view.getTag();
return info.container != LauncherSettings.Favorites.CONTAINER_HOTSEAT_PREDICTION && (
- info.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION
- || info.itemType == LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT);
+ info.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION);
}
private static boolean isInHotseat(ItemInfo itemInfo) {
diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/appprediction/DynamicItemCache.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/appprediction/DynamicItemCache.java
index 38bb180..76972af 100644
--- a/quickstep/recents_ui_overrides/src/com/android/launcher3/appprediction/DynamicItemCache.java
+++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/appprediction/DynamicItemCache.java
@@ -44,8 +44,8 @@
import com.android.launcher3.allapps.AllAppsStore;
import com.android.launcher3.icons.IconCache;
import com.android.launcher3.icons.LauncherIcons;
-import com.android.launcher3.shortcuts.DeepShortcutManager;
import com.android.launcher3.shortcuts.ShortcutKey;
+import com.android.launcher3.shortcuts.ShortcutRequest;
import com.android.launcher3.util.InstantAppResolver;
import java.util.ArrayList;
@@ -167,11 +167,7 @@
@WorkerThread
private WorkspaceItemInfo loadShortcutWorker(ShortcutKey shortcutKey) {
- DeepShortcutManager mgr = DeepShortcutManager.getInstance(mContext);
- List<ShortcutInfo> details = mgr.queryForFullDetails(
- shortcutKey.componentName.getPackageName(),
- Collections.<String>singletonList(shortcutKey.getId()),
- shortcutKey.user);
+ List<ShortcutInfo> details = shortcutKey.buildRequest(mContext).query(ShortcutRequest.ALL);
if (!details.isEmpty()) {
WorkspaceItemInfo si = new WorkspaceItemInfo(details.get(0), mContext);
try (LauncherIcons li = LauncherIcons.obtain(mContext)) {
diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/PredictedAppIcon.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/PredictedAppIcon.java
index 1dcbffb..27ac284 100644
--- a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/PredictedAppIcon.java
+++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/PredictedAppIcon.java
@@ -29,7 +29,6 @@
import androidx.core.graphics.ColorUtils;
-import com.android.launcher3.BubbleTextView;
import com.android.launcher3.CellLayout;
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.Launcher;
@@ -37,7 +36,6 @@
import com.android.launcher3.WorkspaceItemInfo;
import com.android.launcher3.graphics.IconPalette;
import com.android.launcher3.icons.IconNormalizer;
-import com.android.launcher3.popup.PopupContainerWithArrow;
import com.android.launcher3.touch.ItemClickHandler;
import com.android.launcher3.touch.ItemLongClickListener;
import com.android.launcher3.views.DoubleShadowBubbleTextView;
@@ -47,14 +45,13 @@
*/
public class PredictedAppIcon extends DoubleShadowBubbleTextView {
- private static final float RING_EFFECT_RATIO = 0.12f;
+ private static final float RING_EFFECT_RATIO = 0.11f;
private DeviceProfile mDeviceProfile;
private final Paint mIconRingPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
private boolean mIsPinned = false;
private int mNormalizedIconRadius;
-
public PredictedAppIcon(Context context) {
this(context, null, 0);
}
@@ -105,14 +102,8 @@
/**
* prepares prediction icon for usage after bind
*/
- public void finishBinding() {
- setOnLongClickListener((v) -> {
- PopupContainerWithArrow.showForIcon((BubbleTextView) v);
- if (getParent() != null) {
- getParent().requestDisallowInterceptTouchEvent(true);
- }
- return true;
- });
+ public void finishBinding(OnLongClickListener longClickListener) {
+ setOnLongClickListener(longClickListener);
((CellLayout.LayoutParams) getLayoutParams()).canReorder = false;
setTextVisibility(false);
verifyHighRes();
diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/QuickstepLauncher.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
index 37a3929..cae01ae 100644
--- a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
+++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
@@ -178,6 +178,13 @@
}
/**
+ * Returns Prediction controller for hybrid hotseat
+ */
+ public HotseatPredictionController getHotseatPredictionController() {
+ return mHotseatPredictionController;
+ }
+
+ /**
* Recents logic that triggers when launcher state changes or launcher activity stops/resumes.
*/
private void onStateOrResumeChanged() {
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/FallbackActivityInterface.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/FallbackActivityInterface.java
index f889bc1..6574d22 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/FallbackActivityInterface.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/FallbackActivityInterface.java
@@ -226,7 +226,7 @@
RecentsActivity activity = getCreatedActivity();
boolean visible = activity != null && activity.isStarted() && activity.hasWindowFocus();
return visible
- ? LauncherLogProto.ContainerType.SIDELOADED_LAUNCHER
+ ? LauncherLogProto.ContainerType.OTHER_LAUNCHER_APP
: LauncherLogProto.ContainerType.APP;
}
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java
index bafb2ef..29df5cc 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java
@@ -484,7 +484,9 @@
base = new AssistantInputConsumer(this, newGestureState, base, mInputMonitorCompat);
}
- if (mOverscrollPlugin != null) {
+ if (FeatureFlags.ENABLE_QUICK_CAPTURE_GESTURE.get()
+ && (mOverscrollPlugin != null)
+ && mOverscrollPlugin.isActive()) {
// Put the overscroll gesture as higher priority than the Assistant or base gestures
base = new OverscrollInputConsumer(this, newGestureState, base, mInputMonitorCompat,
mOverscrollPlugin);
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/OverscrollInputConsumer.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/OverscrollInputConsumer.java
index e3da98b..0a21413 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/OverscrollInputConsumer.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/OverscrollInputConsumer.java
@@ -26,14 +26,17 @@
import android.content.Context;
import android.graphics.PointF;
+import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.ViewConfiguration;
import androidx.annotation.Nullable;
import com.android.launcher3.BaseDraggingActivity;
+import com.android.launcher3.R;
import com.android.quickstep.GestureState;
import com.android.quickstep.InputConsumer;
+import com.android.quickstep.views.LauncherRecentsView;
import com.android.quickstep.views.RecentsView;
import com.android.systemui.plugins.OverscrollPlugin;
import com.android.systemui.shared.system.InputMonitorCompat;
@@ -47,12 +50,12 @@
private static final String TAG = "OverscrollInputConsumer";
- private static final int ANGLE_THRESHOLD = 35; // Degrees
-
private final PointF mDownPos = new PointF();
private final PointF mLastPos = new PointF();
private final PointF mStartDragPos = new PointF();
+ private final int mAngleThreshold;
+ private final float mFlingThresholdPx;
private int mActivePointerId = -1;
private boolean mPassedSlop = false;
@@ -60,19 +63,28 @@
private final Context mContext;
private final GestureState mGestureState;
- @Nullable private final OverscrollPlugin mPlugin;
+ @Nullable
+ private final OverscrollPlugin mPlugin;
+ private final GestureDetector mGestureDetector;
private RecentsView mRecentsView;
public OverscrollInputConsumer(Context context, GestureState gestureState,
InputConsumer delegate, InputMonitorCompat inputMonitor, OverscrollPlugin plugin) {
super(delegate, inputMonitor);
+
+ mAngleThreshold = context.getResources()
+ .getInteger(R.integer.assistant_gesture_corner_deg_threshold);
+ mFlingThresholdPx = context.getResources()
+ .getDimension(R.dimen.gestures_overscroll_fling_threshold);
mContext = context;
mGestureState = gestureState;
mPlugin = plugin;
float slop = ViewConfiguration.get(context).getScaledTouchSlop();
+
mSquaredSlop = slop * slop;
+ mGestureDetector = new GestureDetector(context, new FlingGestureListener());
gestureState.getActivityInterface().createActivityInitListener(this::onActivityInit)
.register();
@@ -139,21 +151,29 @@
mPassedSlop = true;
mStartDragPos.set(mLastPos.x, mLastPos.y);
-
if (isOverscrolled()) {
setActive(ev);
+
+ if (mPlugin != null) {
+ mPlugin.onTouchStart(getDeviceState(), getUnderlyingActivity());
+ }
} else {
mState = STATE_DELEGATE_ACTIVE;
}
}
}
+ if (mPassedSlop && mState != STATE_DELEGATE_ACTIVE && isOverscrolled()
+ && mPlugin != null) {
+ mPlugin.onTouchTraveled(getDistancePx());
+ }
+
break;
}
case ACTION_CANCEL:
case ACTION_UP:
if (mState != STATE_DELEGATE_ACTIVE && mPassedSlop && mPlugin != null) {
- mPlugin.onOverscroll(getDeviceState());
+ mPlugin.onTouchEnd(getDistancePx());
}
mPassedSlop = false;
@@ -161,6 +181,10 @@
break;
}
+ if (mState != STATE_DELEGATE_ACTIVE) {
+ mGestureDetector.onTouchEvent(ev);
+ }
+
if (mState != STATE_ACTIVE) {
mDelegate.onMotionEvent(ev);
}
@@ -168,12 +192,19 @@
private boolean isOverscrolled() {
// Make sure there isn't an app to quick switch to on our right
- boolean atRightMostApp = (mRecentsView == null || mRecentsView.getRunningTaskIndex() <= 0);
+ int maxIndex = 0;
+ if ((mRecentsView instanceof LauncherRecentsView)
+ && ((LauncherRecentsView) mRecentsView).hasRecentsExtraCard()) {
+ maxIndex = 1;
+ }
+
+ boolean atRightMostApp = (mRecentsView == null
+ || mRecentsView.getRunningTaskIndex() <= maxIndex);
// Check if the gesture is within our angle threshold of horizontal
float deltaY = Math.abs(mLastPos.y - mDownPos.y);
float deltaX = mDownPos.x - mLastPos.x; // Positive if this is a gesture to the left
- boolean angleInBounds = Math.toDegrees(Math.atan2(deltaY, deltaX)) < ANGLE_THRESHOLD;
+ boolean angleInBounds = Math.toDegrees(Math.atan2(deltaY, deltaX)) < mAngleThreshold;
return atRightMostApp && angleInBounds;
}
@@ -193,4 +224,36 @@
return deviceState;
}
+
+ private int getDistancePx() {
+ return (int) Math.hypot(mLastPos.x - mDownPos.x, mLastPos.y - mDownPos.y);
+ }
+
+ private String getUnderlyingActivity() {
+ return mGestureState.getRunningTask().topActivity.flattenToString();
+ }
+
+ private class FlingGestureListener extends GestureDetector.SimpleOnGestureListener {
+ @Override
+ public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
+ if (isValidAngle(velocityX, -velocityY)
+ && getDistancePx() >= mFlingThresholdPx
+ && mState != STATE_DELEGATE_ACTIVE) {
+
+ if (mPlugin != null) {
+ mPlugin.onFling(-velocityX);
+ }
+ }
+ return true;
+ }
+
+ private boolean isValidAngle(float deltaX, float deltaY) {
+ float angle = (float) Math.toDegrees(Math.atan2(deltaY, deltaX));
+ // normalize so that angle is measured clockwise from horizontal in the bottom right
+ // corner and counterclockwise from horizontal in the bottom left corner
+
+ angle = angle > 90 ? 180 - angle : angle;
+ return (angle < mAngleThreshold);
+ }
+ }
}
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/LauncherRecentsView.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/LauncherRecentsView.java
index 82fbbc6..1bbb3f5 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/LauncherRecentsView.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/LauncherRecentsView.java
@@ -378,6 +378,11 @@
}
@Override
+ public boolean hasRecentsExtraCard() {
+ return mRecentsExtraViewContainer != null;
+ }
+
+ @Override
public void setContentAlpha(float alpha) {
super.setContentAlpha(alpha);
if (mRecentsExtraViewContainer != null) {
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/RecentsView.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/RecentsView.java
index bcaa126..47bc31a 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/RecentsView.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/RecentsView.java
@@ -830,6 +830,11 @@
public abstract void startHome();
+ /** `true` if there is a +1 space available in overview. */
+ public boolean hasRecentsExtraCard() {
+ return false;
+ }
+
public void reset() {
setCurrentTask(-1);
mIgnoreResetTaskId = -1;
diff --git a/quickstep/res/drawable-v28/back_gesture_tutorial_action_button_background.xml b/quickstep/res/drawable-v28/back_gesture_tutorial_action_button_background.xml
new file mode 100644
index 0000000..cd30ef7
--- /dev/null
+++ b/quickstep/res/drawable-v28/back_gesture_tutorial_action_button_background.xml
@@ -0,0 +1,20 @@
+<!--
+ Copyright (C) 2020 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.
+-->
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+ android:shape="rectangle">
+ <corners android:radius="?android:attr/dialogCornerRadius"/>
+ <solid android:color="@color/back_gesture_tutorial_primary_color"/>
+</shape>
\ No newline at end of file
diff --git a/quickstep/res/drawable/back_gesture.xml b/quickstep/res/drawable/back_gesture.xml
new file mode 100644
index 0000000..a5c57b4
--- /dev/null
+++ b/quickstep/res/drawable/back_gesture.xml
@@ -0,0 +1,367 @@
+<!--
+ Copyright (C) 2020 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.
+-->
+<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:aapt="http://schemas.android.com/aapt">
+ <aapt:attr name="android:drawable">
+ <vector
+ android:width="206dp"
+ android:height="435dp"
+ android:viewportWidth="206"
+ android:viewportHeight="435">
+ <group android:name="edgeGroup"
+ android:translateX="197"
+ android:translateY="0">
+ <path
+ android:name="edge"
+ android:fillAlpha="0"
+ android:fillType="nonZero"
+ android:fillColor="#1a73eb"
+ android:pathData=" M0,0 h9 v435 h-9 z " />
+ </group>
+ <group
+ android:name="trailGroup"
+ android:translateX="226"
+ android:translateY="200">
+ <path
+ android:name="trail"
+ android:fillAlpha="1"
+ android:fillType="nonZero"
+ android:pathData=" M0,0 h55 v36 h-55 z ">
+ <aapt:attr name="android:fillColor">
+ <gradient
+ android:startX="0"
+ android:endX="55"
+ android:type="linear">
+ <item
+ android:color="#991a73eb"
+ android:offset="0" />
+ <item
+ android:color="#401a73eb"
+ android:offset="0.5" />
+ <item
+ android:color="#001a73eb"
+ android:offset="1" />
+ </gradient>
+ </aapt:attr>
+ </path>
+ </group>
+ <group android:name="_R_G">
+ <group
+ android:name="_R_G_L_0_G_T_1"
+ android:rotation="11"
+ android:scaleX="0.9"
+ android:scaleY="0.9"
+ android:translateX="309"
+ android:translateY="422.5">
+ <group
+ android:name="_R_G_L_0_G"
+ android:translateX="-145"
+ android:translateY="-208">
+ <path
+ android:name="_R_G_L_0_G_D_0_P_0"
+ android:fillAlpha="1"
+ android:fillColor="#d2e3fc"
+ android:fillType="nonZero"
+ android:pathData=" M12.5 -47 C-7.93,-41.24 -3,-20.5 -1.5,-7 C0,6.5 2.5,22 9,39.5 C13.52,51.67 17.06,63.52 19,113 C21,164 53.5,243.5 53.5,243.5 C53.5,243.5 59,275.5 123.5,326 C188,376.5 283.5,236 290.5,199 C297.5,162 194.5,80 149,73 C103.5,66 90.5,57.5 77,50 C63.5,42.5 57,27 54.5,13.5 C52,0 43.5,-15 40,-25 C36.5,-35 32,-52.5 12.5,-47c " />
+ <path
+ android:name="_R_G_L_0_G_D_1_P_0"
+ android:pathData=" M4.45 -34.66 C4.45,-34.66 10.5,-12.66 10.5,-12.66 C11.24,-9.98 13.98,-8.38 16.67,-9.04 C16.67,-9.04 29.72,-12.27 29.72,-12.27 C32.39,-12.93 34.05,-15.59 33.47,-18.28 C33.47,-18.28 32.11,-24.57 32.11,-24.57 "
+ android:strokeWidth="4"
+ android:strokeAlpha="1"
+ android:strokeColor="#a0c2f9" />
+ <path
+ android:name="_R_G_L_0_G_D_2_P_0"
+ android:pathData=" M18.35 21.81 C21.41,17.24 36.97,10.77 44.63,13.55 "
+ android:strokeWidth="4"
+ android:strokeAlpha="1"
+ android:strokeColor="#a0c2f9" />
+ </group>
+ </group>
+ </group>
+ <group android:name="time_group" />
+ </vector>
+ </aapt:attr>
+ <target android:name="edge">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="333"
+ android:propertyName="fillAlpha"
+ android:startOffset="0"
+ android:valueFrom="0"
+ android:valueTo="0.2"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="917"
+ android:propertyName="fillAlpha"
+ android:startOffset="333"
+ android:valueFrom="0.2"
+ android:valueTo="0.2"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="583"
+ android:propertyName="fillAlpha"
+ android:startOffset="1250"
+ android:valueFrom="0.2"
+ android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="trail">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="2000"
+ android:propertyName="fillAlpha"
+ android:startOffset="0"
+ android:valueFrom="1"
+ android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="850"
+ android:propertyName="fillAlpha"
+ android:startOffset="2000"
+ android:valueFrom="1"
+ android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="trailGroup">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="83"
+ android:propertyName="translateX"
+ android:startOffset="1250"
+ android:valueFrom="226"
+ android:valueTo="226"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.285,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="1000"
+ android:propertyName="translateX"
+ android:startOffset="1333"
+ android:valueFrom="226"
+ android:valueTo="151"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.285,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="517"
+ android:propertyName="translateX"
+ android:startOffset="2333"
+ android:valueFrom="151"
+ android:valueTo="151"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.285,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="50"
+ android:propertyName="translateX"
+ android:startOffset="2850"
+ android:valueFrom="226"
+ android:valueTo="226"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.285,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_D_0_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="1833"
+ android:propertyName="fillAlpha"
+ android:startOffset="1250"
+ android:valueFrom="1"
+ android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="167"
+ android:propertyName="fillAlpha"
+ android:startOffset="3083"
+ android:valueFrom="1"
+ android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_D_1_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="1833"
+ android:propertyName="strokeAlpha"
+ android:startOffset="1250"
+ android:valueFrom="1"
+ android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="100"
+ android:propertyName="strokeAlpha"
+ android:startOffset="3083"
+ android:valueFrom="1"
+ android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_D_2_P_0">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="1833"
+ android:propertyName="strokeAlpha"
+ android:startOffset="1250"
+ android:valueFrom="1"
+ android:valueTo="1"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="100"
+ android:propertyName="strokeAlpha"
+ android:startOffset="3083"
+ android:valueFrom="1"
+ android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.833,0.833 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_T_1">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="83"
+ android:propertyName="translateX"
+ android:startOffset="1250"
+ android:valueFrom="309"
+ android:valueTo="309"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.285,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="1417"
+ android:propertyName="translateX"
+ android:startOffset="1333"
+ android:valueFrom="309"
+ android:valueTo="251"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.285,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="_R_G_L_0_G_T_1">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="83"
+ android:propertyName="rotation"
+ android:startOffset="1250"
+ android:valueFrom="11"
+ android:valueTo="11"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.277,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ <objectAnimator
+ android:duration="1417"
+ android:propertyName="rotation"
+ android:startOffset="1333"
+ android:valueFrom="11"
+ android:valueTo="0"
+ android:valueType="floatType">
+ <aapt:attr name="android:interpolator">
+ <pathInterpolator android:pathData="M 0.0,0.0 c0.167,0.167 0.277,1 1.0,1.0" />
+ </aapt:attr>
+ </objectAnimator>
+ </set>
+ </aapt:attr>
+ </target>
+ <target android:name="time_group">
+ <aapt:attr name="android:animation">
+ <set android:ordering="together">
+ <objectAnimator
+ android:duration="2183"
+ android:propertyName="translateX"
+ android:startOffset="1250"
+ android:valueFrom="0"
+ android:valueTo="1"
+ android:valueType="floatType" />
+ </set>
+ </aapt:attr>
+ </target>
+</animated-vector>
\ No newline at end of file
diff --git a/quickstep/res/drawable/back_gesture_tutorial_action_button_background.xml b/quickstep/res/drawable/back_gesture_tutorial_action_button_background.xml
new file mode 100644
index 0000000..d7b9102
--- /dev/null
+++ b/quickstep/res/drawable/back_gesture_tutorial_action_button_background.xml
@@ -0,0 +1,20 @@
+<!--
+ Copyright (C) 2020 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.
+-->
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+ android:shape="rectangle">
+ <corners android:radius="@dimen/default_dialog_corner_radius"/>
+ <solid android:color="@color/back_gesture_tutorial_primary_color"/>
+</shape>
\ No newline at end of file
diff --git a/quickstep/res/drawable/back_gesture_tutorial_close_button.xml b/quickstep/res/drawable/back_gesture_tutorial_close_button.xml
new file mode 100644
index 0000000..0702042
--- /dev/null
+++ b/quickstep/res/drawable/back_gesture_tutorial_close_button.xml
@@ -0,0 +1,25 @@
+<!--
+ Copyright (C) 2020 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:height="13dp"
+ android:viewportHeight="14"
+ android:viewportWidth="14"
+ android:width="13dp">
+ <path
+ android:fillColor="#000000"
+ android:fillType="evenOdd"
+ android:pathData="M14,1.41L12.59,0L7,5.59L1.41,0L0,1.41L5.59,7L0,12.59L1.41,14L7,8.41L12.59,14L14,12.59L8.41,7L14,1.41Z"/>
+</vector>
\ No newline at end of file
diff --git a/quickstep/res/drawable/ic_bulb_outline.xml b/quickstep/res/drawable/ic_bulb_outline.xml
new file mode 100644
index 0000000..ef7bf9a
--- /dev/null
+++ b/quickstep/res/drawable/ic_bulb_outline.xml
@@ -0,0 +1,29 @@
+<!--
+ Copyright (C) 2020 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="192dp"
+ android:height="192dp"
+ android:viewportWidth="192"
+ android:viewportHeight="192">
+ <path
+ android:pathData="M96,90.01"
+ android:strokeWidth="2.4297"
+ android:fillColor="#00000000"
+ android:strokeColor="#FFC800"/>
+ <path
+ android:pathData="M153.24,48.09c-0.5,-1.51 -0.99,-2.86 -1.51,-4.12c-3.03,-7.1 -7.26,-13.45 -12.59,-18.88C127.68,13.42 112.4,7 96.1,7c-14,0 -27.66,4.93 -38.45,13.87C47,29.69 39.61,41.99 36.82,55.51c-0.76,3.9 -1.14,7.86 -1.14,11.78c0,16.39 6.36,31.77 17.9,43.3c2.65,2.65 5.59,5.08 8.74,7.23l0.09,24.14v22.03c0,5.33 4.82,10.01 10.32,10.01h0.41h3.85v0c0,6.23 4.53,10.93 10.53,10.93h16.94c6.01,0 10.54,-4.7 10.54,-10.93v0h4.31c5.56,0 10.26,-4.5 10.26,-9.83v-22.01c0.01,-0.06 0.01,-0.13 0.01,-0.2v-23.74c16.75,-11.15 26.73,-30.15 26.73,-50.94C156.31,60.76 155.28,54.3 153.24,48.09zM118.51,111.08l-0.46,0.29l-0.46,0.29v0.55v0.55v4.38v22.77l-14.12,0V95.9h14h2v-2v-8.5v-2h-2H74.53h-2v2v8.5v2h2h14v44.02l-14.13,0l-0.09,-23.21l-0.02,-4.3l0,-0.54l0,-0.54l-0.45,-0.29l-0.45,-0.29l-3.6,-2.36c-2.81,-1.84 -5.41,-3.95 -7.73,-6.28c-9.27,-9.26 -14.38,-21.63 -14.38,-34.82c0,-3.14 0.3,-6.31 0.9,-9.43C53.25,35.35 73.23,19 96.1,19c13.05,0 25.3,5.15 34.48,14.5c4.27,4.34 7.66,9.43 10.08,15.1c0.39,0.96 0.78,2.03 1.18,3.24c1.64,5 2.47,10.2 2.47,15.45c0,17.1 -8.27,32.58 -22.11,41.43L118.51,111.08z"
+ android:fillColor="#4285F4"/>
+</vector>
\ No newline at end of file
diff --git a/quickstep/res/layout/back_gesture_tutorial_activity.xml b/quickstep/res/layout/back_gesture_tutorial_activity.xml
new file mode 100644
index 0000000..e894e89
--- /dev/null
+++ b/quickstep/res/layout/back_gesture_tutorial_activity.xml
@@ -0,0 +1,19 @@
+<!--
+ Copyright (C) 2020 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.
+-->
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/back_gesture_tutorial_fragment_container"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"/>
\ No newline at end of file
diff --git a/quickstep/res/layout/back_gesture_tutorial_fragment.xml b/quickstep/res/layout/back_gesture_tutorial_fragment.xml
new file mode 100644
index 0000000..294e46e
--- /dev/null
+++ b/quickstep/res/layout/back_gesture_tutorial_fragment.xml
@@ -0,0 +1,121 @@
+<!--
+ Copyright (C) 2020 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.
+-->
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layerType="software"
+ android:background="@color/back_gesture_tutorial_background_color">
+ <!--The layout is rendered on the software layer to avoid b/136158117-->
+
+ <ImageView
+ android:id="@+id/back_gesture_tutorial_fragment_hand_coaching"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:scaleType="centerCrop"/>
+
+ <ImageButton
+ android:id="@+id/back_gesture_tutorial_fragment_close_button"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:padding="18dp"
+ android:layout_marginTop="30dp"
+ android:layout_marginStart="4dp"
+ android:layout_alignParentLeft="true"
+ android:layout_alignParentTop="true"
+ android:background="@android:color/transparent"
+ android:accessibilityTraversalAfter="@id/back_gesture_tutorial_fragment_titles_container"
+ android:contentDescription="@string/back_gesture_tutorial_close_button_content_description"
+ android:src="@drawable/back_gesture_tutorial_close_button"/>
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_marginTop="70dp"
+ android:orientation="vertical">
+
+ <LinearLayout
+ android:id="@+id/back_gesture_tutorial_fragment_titles_container"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical"
+ android:focusable="true">
+
+ <TextView
+ android:id="@+id/back_gesture_tutorial_fragment_title_view"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_horizontal"
+ android:layout_marginStart="@dimen/back_gesture_tutorial_title_margin_start_end"
+ android:layout_marginEnd="@dimen/back_gesture_tutorial_title_margin_start_end"
+ style="@style/TextAppearance.BackGestureTutorial.Title"/>
+
+ <TextView
+ android:id="@+id/back_gesture_tutorial_fragment_subtitle_view"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_horizontal"
+ android:layout_marginTop="10dp"
+ android:layout_marginStart="@dimen/back_gesture_tutorial_subtitle_margin_start_end"
+ android:layout_marginEnd="@dimen/back_gesture_tutorial_subtitle_margin_start_end"
+ style="@style/TextAppearance.BackGestureTutorial.Subtitle"/>
+
+ </LinearLayout>
+
+ <Space
+ android:layout_width="wrap_content"
+ android:layout_weight="1"
+ android:layout_height="0dp"
+ android:layout_marginTop="48dp"
+ android:layout_gravity="center_horizontal"
+ android:gravity="center_horizontal"
+ android:orientation="vertical"/>
+
+ <!-- android:stateListAnimator="@null" removes shadow and normal on click behavior (increase
+ of elevation and shadow) which is replaced by ripple effect in android:foreground -->
+ <RelativeLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="46dp"
+ android:layout_marginBottom="48dp"
+ android:layout_gravity="center_horizontal">
+
+ <Button
+ android:id="@+id/back_gesture_tutorial_fragment_action_button"
+ android:layout_width="142dp"
+ android:layout_height="49dp"
+ android:layout_marginEnd="@dimen/back_gesture_tutorial_button_margin_start_end"
+ android:layout_alignParentEnd="true"
+ android:stateListAnimator="@null"
+ android:background="@drawable/back_gesture_tutorial_action_button_background"
+ android:foreground="?android:attr/selectableItemBackgroundBorderless"
+ style="@style/TextAppearance.BackGestureTutorial.ButtonLabel"/>
+
+ <Button
+ android:id="@+id/back_gesture_tutorial_fragment_action_text_button"
+ android:layout_width="142dp"
+ android:layout_height="49dp"
+ android:layout_marginStart="@dimen/back_gesture_tutorial_button_margin_start_end"
+ android:layout_alignParentStart="true"
+ android:stateListAnimator="@null"
+ android:background="@null"
+ android:foreground="?android:attr/selectableItemBackgroundBorderless"
+ style="@style/TextAppearance.BackGestureTutorial.TextButtonLabel"/>
+
+ </RelativeLayout>
+
+ </LinearLayout>
+
+</RelativeLayout>
\ No newline at end of file
diff --git a/quickstep/res/values/dimens.xml b/quickstep/res/values/dimens.xml
index 9ff1350..988c78d 100644
--- a/quickstep/res/values/dimens.xml
+++ b/quickstep/res/values/dimens.xml
@@ -77,4 +77,12 @@
<!-- Distance to move elements when swiping up to go home from launcher -->
<dimen name="home_pullback_distance">28dp</dimen>
+
+ <!-- Overscroll Gesture -->
+ <dimen name="gestures_overscroll_fling_threshold">40dp</dimen>
+
+ <!-- Tips Gesture Tutorial -->
+ <dimen name="back_gesture_tutorial_title_margin_start_end">40dp</dimen>
+ <dimen name="back_gesture_tutorial_subtitle_margin_start_end">16dp</dimen>
+ <dimen name="back_gesture_tutorial_button_margin_start_end">18dp</dimen>
</resources>
diff --git a/quickstep/res/values/strings.xml b/quickstep/res/values/strings.xml
index 4319b5d..378858f 100644
--- a/quickstep/res/values/strings.xml
+++ b/quickstep/res/values/strings.xml
@@ -66,5 +66,33 @@
<!-- Text of the tip when user lands in all apps view for the first time, indicating where the tip toast points to is the predicted apps section. [CHAR_LIMIT=50] -->
<string name="all_apps_prediction_tip">Your predicted apps</string>
+ <!-- Content description for a close button. [CHAR LIMIT=NONE] -->
+ <string name="back_gesture_tutorial_close_button_content_description" translatable="false">Close</string>
+ <!-- Title shown on the notification of Back gesture tutorial. [CHAR LIMIT=30] -->
+ <string name="back_gesture_tutorial_notification_title" translatable="false">Try the new back gesture</string>
+ <!-- Subtitle shown on the notification of Back gesture tutorial. [CHAR LIMIT=60] -->
+ <string name="back_gesture_tutorial_notification_subtitle" translatable="false">Learn how to go back while using your apps</string>
+ <!-- Action text shown on the notification of Back gesture tutorial. [CHAR LIMIT=14] -->
+ <string name="back_gesture_tutorial_notification_action_label" translatable="false">Try it</string>
+
+ <!-- Title shown during interactive part of Back gesture tutorial for right edge. [CHAR LIMIT=30] -->
+ <string name="back_gesture_tutorial_playground_title_swipe_inward_right_edge" translatable="false">Try the back gesture</string>
+ <!-- Subtitle shown during interactive parts of Back gesture tutorial for right edge. [CHAR LIMIT=60] -->
+ <string name="back_gesture_tutorial_engaged_subtitle_swipe_inward_right_edge" translatable="false">Start at the right edge and swipe toward the middle</string>
+
+ <!-- Title shown during interactive part of Back gesture tutorial for left edge. [CHAR LIMIT=30] -->
+ <string name="back_gesture_tutorial_playground_title_swipe_inward_left_edge" translatable="false">Try the other side</string>
+ <!-- Subtitle shown during interactive parts of Back gesture tutorial for left edge. [CHAR LIMIT=60] -->
+ <string name="back_gesture_tutorial_engaged_subtitle_swipe_inward_left_edge" translatable="false">That\'s it! Now try swiping from the left edge.</string>
+
+ <!-- Title shown on the confirmation screen after successful gesture. [CHAR LIMIT=30] -->
+ <string name="back_gesture_tutorial_confirm_title" translatable="false">All set</string>
+ <!-- Subtitle shown on the confirmation screen after successful gesture. [CHAR LIMIT=60] -->
+ <string name="back_gesture_tutorial_confirm_subtitle" translatable="false">To change the sensitivity of the back gesture, go to Settings</string>
+
+ <!-- Button text shown on a button on the confirm screen. [CHAR LIMIT=14] -->
+ <string name="back_gesture_tutorial_action_button_label" translatable="false">Done</string>
+ <!-- Button text shown on a text button on the confirm screen. [CHAR LIMIT=14] -->
+ <string name="back_gesture_tutorial_action_text_button_label" translatable="false">Settings</string>
</resources>
\ No newline at end of file
diff --git a/quickstep/res/values/styles.xml b/quickstep/res/values/styles.xml
index bb364ff..c8d7777 100644
--- a/quickstep/res/values/styles.xml
+++ b/quickstep/res/values/styles.xml
@@ -25,4 +25,39 @@
<item name="android:layout_width">match_parent</item>
<item name="android:layout_height">wrap_content</item>
</style>
+
+ <style name="TextAppearance.BackGestureTutorial"
+ parent="android:TextAppearance.Material.Body1" />
+
+ <style name="TextAppearance.BackGestureTutorial.CallToAction"
+ parent="android:TextAppearance.Material.Body2" />
+
+ <style name="TextAppearance.BackGestureTutorial.Title"
+ parent="TextAppearance.BackGestureTutorial">
+ <item name="android:gravity">center</item>
+ <item name="android:textColor">@color/back_gesture_tutorial_title_color</item>
+ <item name="android:textSize">28sp</item>
+ </style>
+
+ <style name="TextAppearance.BackGestureTutorial.Subtitle"
+ parent="TextAppearance.BackGestureTutorial">
+ <item name="android:gravity">center</item>
+ <item name="android:textColor">@color/back_gesture_tutorial_subtitle_color</item>
+ <item name="android:letterSpacing">0.03</item>
+ <item name="android:textSize">21sp</item>
+ </style>
+
+ <style name="TextAppearance.BackGestureTutorial.ButtonLabel"
+ parent="TextAppearance.BackGestureTutorial.CallToAction">
+ <item name="android:gravity">center</item>
+ <item name="android:textColor">@color/back_gesture_tutorial_action_button_label_color</item>
+ <item name="android:letterSpacing">0.02</item>
+ <item name="android:textSize">16sp</item>
+ <item name="android:textAllCaps">false</item>
+ </style>
+
+ <style name="TextAppearance.BackGestureTutorial.TextButtonLabel"
+ parent="TextAppearance.BackGestureTutorial.ButtonLabel">
+ <item name="android:textColor">@color/back_gesture_tutorial_primary_color</item>
+ </style>
</resources>
\ No newline at end of file
diff --git a/quickstep/res/xml/notification_action.xml b/quickstep/res/xml/notification_action.xml
new file mode 100644
index 0000000..cc3612e
--- /dev/null
+++ b/quickstep/res/xml/notification_action.xml
@@ -0,0 +1,19 @@
+<!--
+ Copyright (C) 2020 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.
+-->
+<alias xmlns:android="http://schemas.android.com/apk/res/android">
+ <intent
+ android:action="com.android.quickstep.action.BACK_GESTURE_TUTORIAL" />
+</alias>
\ No newline at end of file
diff --git a/res/values/colors.xml b/res/values/colors.xml
index 3c8fe1e..815ae21 100644
--- a/res/values/colors.xml
+++ b/res/values/colors.xml
@@ -37,4 +37,10 @@
<color name="all_apps_bg_hand_fill">#E5E5E5</color>
<color name="all_apps_bg_hand_fill_dark">#9AA0A6</color>
+
+ <color name="back_gesture_tutorial_background_color">#FFFFFFFF</color>
+ <color name="back_gesture_tutorial_subtitle_color">#99000000</color> <!-- 60% black -->
+ <color name="back_gesture_tutorial_title_color">#FF000000</color>
+ <color name="back_gesture_tutorial_action_button_label_color">#FFFFFFFF</color>
+ <color name="back_gesture_tutorial_primary_color">#1A73E8</color> <!-- Blue -->
</resources>
diff --git a/src/com/android/launcher3/BaseActivity.java b/src/com/android/launcher3/BaseActivity.java
index f319ae1..ea63fa7 100644
--- a/src/com/android/launcher3/BaseActivity.java
+++ b/src/com/android/launcher3/BaseActivity.java
@@ -16,6 +16,7 @@
package com.android.launcher3;
+import static com.android.launcher3.model.WidgetsModel.GO_DISABLE_WIDGETS;
import static com.android.launcher3.util.SystemUiController.UI_STATE_OVERVIEW;
import static java.lang.annotation.RetentionPolicy.SOURCE;
@@ -24,7 +25,12 @@
import android.content.Context;
import android.content.ContextWrapper;
import android.content.Intent;
+import android.content.pm.LauncherApps;
import android.content.res.Configuration;
+import android.graphics.Rect;
+import android.os.Bundle;
+import android.os.UserHandle;
+import android.util.Log;
import android.view.ContextThemeWrapper;
import androidx.annotation.IntDef;
@@ -47,6 +53,8 @@
public abstract class BaseActivity extends Activity
implements UserEventDelegate, LogStateProvider, ActivityContext {
+ private static final String TAG = "BaseActivity";
+
public static final int INVISIBLE_BY_STATE_HANDLER = 1 << 0;
public static final int INVISIBLE_BY_APP_TRANSITIONS = 1 << 1;
public static final int INVISIBLE_BY_PENDING_FLAGS = 1 << 2;
@@ -312,6 +320,22 @@
writer.println(prefix + "mForceInvisible: " + mForceInvisible);
}
+ /**
+ * A wrapper around the platform method with Launcher specific checks
+ */
+ public void startShortcut(String packageName, String id, Rect sourceBounds,
+ Bundle startActivityOptions, UserHandle user) {
+ if (GO_DISABLE_WIDGETS) {
+ return;
+ }
+ try {
+ getSystemService(LauncherApps.class).startShortcut(packageName, id, sourceBounds,
+ startActivityOptions, user);
+ } catch (SecurityException | IllegalStateException e) {
+ Log.e(TAG, "Failed to start shortcut", e);
+ }
+ }
+
public static <T extends BaseActivity> T fromContext(Context context) {
if (context instanceof BaseActivity) {
return (T) context;
diff --git a/src/com/android/launcher3/BaseDraggingActivity.java b/src/com/android/launcher3/BaseDraggingActivity.java
index 21c819a..df15fc1 100644
--- a/src/com/android/launcher3/BaseDraggingActivity.java
+++ b/src/com/android/launcher3/BaseDraggingActivity.java
@@ -35,7 +35,6 @@
import com.android.launcher3.LauncherSettings.Favorites;
import com.android.launcher3.model.AppLaunchTracker;
-import com.android.launcher3.shortcuts.DeepShortcutManager;
import com.android.launcher3.uioverrides.DisplayRotationListener;
import com.android.launcher3.uioverrides.WallpaperColorInfo;
import com.android.launcher3.util.PackageManagerHelper;
@@ -198,8 +197,7 @@
if (info.itemType == LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT) {
String id = ((WorkspaceItemInfo) info).getDeepShortcutId();
String packageName = intent.getPackage();
- DeepShortcutManager.getInstance(this).startShortcut(
- packageName, id, intent.getSourceBounds(), optsBundle, info.user);
+ startShortcut(packageName, id, intent.getSourceBounds(), optsBundle, info.user);
AppLaunchTracker.INSTANCE.get(this).onStartShortcut(packageName, id, info.user,
sourceContainer);
} else {
diff --git a/src/com/android/launcher3/ExtendedEditText.java b/src/com/android/launcher3/ExtendedEditText.java
index 52a393f..8b6d209 100644
--- a/src/com/android/launcher3/ExtendedEditText.java
+++ b/src/com/android/launcher3/ExtendedEditText.java
@@ -108,6 +108,7 @@
@Override
public void onCommitCompletion(CompletionInfo text) {
setText(text.getText());
+ setSelection(text.getText().length());
}
/**
diff --git a/src/com/android/launcher3/InstallShortcutReceiver.java b/src/com/android/launcher3/InstallShortcutReceiver.java
index df03027..3eb02b3 100644
--- a/src/com/android/launcher3/InstallShortcutReceiver.java
+++ b/src/com/android/launcher3/InstallShortcutReceiver.java
@@ -49,8 +49,8 @@
import com.android.launcher3.icons.GraphicsUtils;
import com.android.launcher3.icons.LauncherIcons;
import com.android.launcher3.pm.UserCache;
-import com.android.launcher3.shortcuts.DeepShortcutManager;
import com.android.launcher3.shortcuts.ShortcutKey;
+import com.android.launcher3.shortcuts.ShortcutRequest;
import com.android.launcher3.util.PackageManagerHelper;
import com.android.launcher3.util.Preconditions;
import com.android.launcher3.util.Thunk;
@@ -538,12 +538,9 @@
return new PendingInstallShortcutInfo(info, context);
}
} else if (decoder.optBoolean(DEEPSHORTCUT_TYPE_KEY)) {
- DeepShortcutManager sm = DeepShortcutManager.getInstance(context);
- List<ShortcutInfo> si = sm.queryForFullDetails(
- decoder.launcherIntent.getPackage(),
- Arrays.asList(decoder.launcherIntent.getStringExtra(
- ShortcutKey.EXTRA_SHORTCUT_ID)),
- decoder.user);
+ List<ShortcutInfo> si = ShortcutKey.fromIntent(decoder.launcherIntent, decoder.user)
+ .buildRequest(context)
+ .query(ShortcutRequest.ALL);
if (si.isEmpty()) {
return null;
} else {
diff --git a/src/com/android/launcher3/LauncherModel.java b/src/com/android/launcher3/LauncherModel.java
index 67fd7db..0bdf8fd 100644
--- a/src/com/android/launcher3/LauncherModel.java
+++ b/src/com/android/launcher3/LauncherModel.java
@@ -20,6 +20,7 @@
import static com.android.launcher3.config.FeatureFlags.IS_DOGFOOD_BUILD;
import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
import static com.android.launcher3.util.Executors.MODEL_EXECUTOR;
+import static com.android.launcher3.util.PackageManagerHelper.hasShortcutsPermission;
import android.content.Context;
import android.content.Intent;
@@ -54,7 +55,7 @@
import com.android.launcher3.pm.InstallSessionTracker;
import com.android.launcher3.pm.PackageInstallInfo;
import com.android.launcher3.pm.UserCache;
-import com.android.launcher3.shortcuts.DeepShortcutManager;
+import com.android.launcher3.shortcuts.ShortcutRequest;
import com.android.launcher3.util.IntSparseArrayMap;
import com.android.launcher3.util.ItemInfoMatcher;
import com.android.launcher3.util.PackageUserKey;
@@ -113,12 +114,9 @@
private final Runnable mShortcutPermissionCheckRunnable = new Runnable() {
@Override
public void run() {
- if (mModelLoaded) {
- boolean hasShortcutHostPermission =
- DeepShortcutManager.getInstance(mApp.getContext()).hasHostPermission();
- if (hasShortcutHostPermission != sBgDataModel.hasShortcutHostPermission) {
- forceReload();
- }
+ if (mModelLoaded && hasShortcutsPermission(mApp.getContext())
+ != sBgDataModel.hasShortcutHostPermission) {
+ forceReload();
}
}
};
@@ -220,8 +218,8 @@
Context context = mApp.getContext();
onPackageChanged(packageName, user);
- List<ShortcutInfo> pinnedShortcuts = DeepShortcutManager.getInstance(context)
- .queryForPinnedShortcuts(packageName, user);
+ List<ShortcutInfo> pinnedShortcuts = new ShortcutRequest(context, user)
+ .forPackage(packageName).query(ShortcutRequest.PINNED);
if (!pinnedShortcuts.isEmpty()) {
enqueueModelUpdateTask(new ShortcutsChangedTask(packageName, pinnedShortcuts, user,
false));
diff --git a/src/com/android/launcher3/Utilities.java b/src/com/android/launcher3/Utilities.java
index 2bec0ba..af9a1b4 100644
--- a/src/com/android/launcher3/Utilities.java
+++ b/src/com/android/launcher3/Utilities.java
@@ -65,9 +65,10 @@
import com.android.launcher3.graphics.TintedDrawableSpan;
import com.android.launcher3.icons.IconProvider;
import com.android.launcher3.icons.LauncherIcons;
+import com.android.launcher3.icons.ShortcutCachingLogic;
import com.android.launcher3.pm.ShortcutConfigActivityInfo;
-import com.android.launcher3.shortcuts.DeepShortcutManager;
import com.android.launcher3.shortcuts.ShortcutKey;
+import com.android.launcher3.shortcuts.ShortcutRequest;
import com.android.launcher3.util.IntArray;
import com.android.launcher3.util.PackageManagerHelper;
import com.android.launcher3.views.Transposable;
@@ -540,15 +541,14 @@
outObj[0] = activityInfo;
return activityInfo.getFullResIcon(appState.getIconCache());
}
- ShortcutKey key = ShortcutKey.fromItemInfo(info);
- DeepShortcutManager sm = DeepShortcutManager.getInstance(launcher);
- List<ShortcutInfo> si = sm.queryForFullDetails(
- key.componentName.getPackageName(), Arrays.asList(key.getId()), key.user);
+ List<ShortcutInfo> si = ShortcutKey.fromItemInfo(info)
+ .buildRequest(launcher)
+ .query(ShortcutRequest.ALL);
if (si.isEmpty()) {
return null;
} else {
outObj[0] = si.get(0);
- return sm.getShortcutIconDrawable(si.get(0),
+ return ShortcutCachingLogic.getIcon(launcher, si.get(0),
appState.getInvariantDeviceProfile().fillResIconDpi);
}
} else if (info.itemType == LauncherSettings.Favorites.ITEM_TYPE_FOLDER) {
diff --git a/src/com/android/launcher3/allapps/AlphabeticalAppsList.java b/src/com/android/launcher3/allapps/AlphabeticalAppsList.java
index 0c4be62..10e2821 100644
--- a/src/com/android/launcher3/allapps/AlphabeticalAppsList.java
+++ b/src/com/android/launcher3/allapps/AlphabeticalAppsList.java
@@ -15,13 +15,14 @@
*/
package com.android.launcher3.allapps;
+import static com.android.launcher3.util.PackageManagerHelper.hasShortcutsPermission;
+
import android.content.Context;
import android.content.pm.PackageManager;
import com.android.launcher3.AppInfo;
import com.android.launcher3.Launcher;
import com.android.launcher3.Utilities;
-import com.android.launcher3.shortcuts.DeepShortcutManager;
import com.android.launcher3.util.ComponentKey;
import com.android.launcher3.util.ItemInfoMatcher;
import com.android.launcher3.util.LabelComparator;
@@ -398,7 +399,7 @@
private boolean shouldShowWorkFooter() {
return mIsWork && Utilities.ATLEAST_P &&
- (DeepShortcutManager.getInstance(mLauncher).hasHostPermission()
+ (hasShortcutsPermission(mLauncher)
|| mLauncher.checkSelfPermission("android.permission.MODIFY_QUIET_MODE")
== PackageManager.PERMISSION_GRANTED);
}
diff --git a/src/com/android/launcher3/config/FeatureFlags.java b/src/com/android/launcher3/config/FeatureFlags.java
index 7334964..003ca82 100644
--- a/src/com/android/launcher3/config/FeatureFlags.java
+++ b/src/com/android/launcher3/config/FeatureFlags.java
@@ -114,7 +114,7 @@
"ENABLE_PREDICTION_DISMISS", false, "Allow option to dimiss apps from predicted list");
public static final TogglableFlag ENABLE_QUICK_CAPTURE_GESTURE = new TogglableFlag(
- "ENABLE_QUICK_CAPTURE_GESTURE", false, "Swipe from right to left to quick capture");
+ "ENABLE_QUICK_CAPTURE_GESTURE", true, "Swipe from right to left to quick capture");
public static final TogglableFlag ASSISTANT_GIVES_LAUNCHER_FOCUS = new TogglableFlag(
"ASSISTANT_GIVES_LAUNCHER_FOCUS", false,
diff --git a/src/com/android/launcher3/dragndrop/DragController.java b/src/com/android/launcher3/dragndrop/DragController.java
index b72fd98..dcdf5d6 100644
--- a/src/com/android/launcher3/dragndrop/DragController.java
+++ b/src/com/android/launcher3/dragndrop/DragController.java
@@ -19,6 +19,7 @@
import static com.android.launcher3.AbstractFloatingView.TYPE_DISCOVERY_BOUNCE;
import static com.android.launcher3.LauncherAnimUtils.SPRING_LOADED_EXIT_DELAY;
import static com.android.launcher3.LauncherState.NORMAL;
+import static com.android.launcher3.Utilities.ATLEAST_Q;
import android.animation.ValueAnimator;
import android.content.ComponentName;
@@ -56,6 +57,12 @@
public class DragController implements DragDriver.EventListener, TouchController {
private static final boolean PROFILE_DRAWING_DURING_DRAG = false;
+ /**
+ * When a drag is started from a deep press, you need to drag this much farther than normal to
+ * end a pre-drag. See {@link DragOptions.PreDragCondition#shouldStartDrag(double)}.
+ */
+ private static final int DEEP_PRESS_DISTANCE_FACTOR = 3;
+
@Thunk Launcher mLauncher;
private FlingToDeleteHelper mFlingToDeleteHelper;
@@ -91,9 +98,10 @@
private DropTarget mLastDropTarget;
- @Thunk int mLastTouch[] = new int[2];
- @Thunk long mLastTouchUpTime = -1;
- @Thunk int mDistanceSinceScroll = 0;
+ private final int[] mLastTouch = new int[2];
+ private long mLastTouchUpTime = -1;
+ private int mLastTouchClassification;
+ private int mDistanceSinceScroll = 0;
private int mTmpPoint[] = new int[2];
private Rect mDragLayerRect = new Rect();
@@ -204,7 +212,7 @@
}
mLauncher.getDragLayer().performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
- dragView.show(mMotionDownX, mMotionDownY);
+ dragView.show(mLastTouch[0], mLastTouch[1]);
mDistanceSinceScroll = 0;
if (!mIsInPreDrag) {
@@ -213,9 +221,7 @@
mOptions.preDragCondition.onPreDragStart(mDragObject);
}
- mLastTouch[0] = mMotionDownX;
- mLastTouch[1] = mMotionDownY;
- handleMoveEvent(mMotionDownX, mMotionDownY);
+ handleMoveEvent(mLastTouch[0], mLastTouch[1]);
mLauncher.getUserEventDispatcher().resetActionDurationMillis();
return dragView;
}
@@ -430,6 +436,11 @@
final int[] dragLayerPos = getClampedDragLayerPos(ev.getX(), ev.getY());
final int dragLayerX = dragLayerPos[0];
final int dragLayerY = dragLayerPos[1];
+ mLastTouch[0] = dragLayerX;
+ mLastTouch[1] = dragLayerY;
+ if (ATLEAST_Q) {
+ mLastTouchClassification = ev.getClassification();
+ }
switch (action) {
case MotionEvent.ACTION_DOWN:
@@ -488,8 +499,12 @@
mLastTouch[0] = x;
mLastTouch[1] = y;
+ int distanceDragged = mDistanceSinceScroll;
+ if (ATLEAST_Q && mLastTouchClassification == MotionEvent.CLASSIFICATION_DEEP_PRESS) {
+ distanceDragged /= DEEP_PRESS_DISTANCE_FACTOR;
+ }
if (mIsInPreDrag && mOptions.preDragCondition != null
- && mOptions.preDragCondition.shouldStartDrag(mDistanceSinceScroll)) {
+ && mOptions.preDragCondition.shouldStartDrag(distanceDragged)) {
callOnDragStart();
}
}
diff --git a/src/com/android/launcher3/icons/LauncherIcons.java b/src/com/android/launcher3/icons/LauncherIcons.java
index 4d3599e..e67d244 100644
--- a/src/com/android/launcher3/icons/LauncherIcons.java
+++ b/src/com/android/launcher3/icons/LauncherIcons.java
@@ -35,7 +35,6 @@
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.graphics.IconShape;
import com.android.launcher3.model.PackageItemInfo;
-import com.android.launcher3.shortcuts.DeepShortcutManager;
import com.android.launcher3.util.Themes;
import java.util.function.Supplier;
@@ -133,8 +132,8 @@
public BitmapInfo createShortcutIconLegacy(ShortcutInfo shortcutInfo, boolean badged,
@Nullable Supplier<ItemInfoWithIcon> fallbackIconProvider) {
- Drawable unbadgedDrawable = DeepShortcutManager.getInstance(mContext)
- .getShortcutIconDrawable(shortcutInfo, mFillResIconDpi);
+ Drawable unbadgedDrawable = ShortcutCachingLogic.getIcon(
+ mContext, shortcutInfo, mFillResIconDpi);
IconCache cache = LauncherAppState.getInstance(mContext).getIconCache();
final Bitmap unbadgedBitmap;
if (unbadgedDrawable != null) {
diff --git a/src/com/android/launcher3/icons/ShortcutCachingLogic.java b/src/com/android/launcher3/icons/ShortcutCachingLogic.java
index 5c21470..b856dd1 100644
--- a/src/com/android/launcher3/icons/ShortcutCachingLogic.java
+++ b/src/com/android/launcher3/icons/ShortcutCachingLogic.java
@@ -16,19 +16,22 @@
package com.android.launcher3.icons;
+import static com.android.launcher3.model.WidgetsModel.GO_DISABLE_WIDGETS;
+
import android.content.ComponentName;
import android.content.Context;
+import android.content.pm.LauncherApps;
import android.content.pm.PackageInfo;
import android.content.pm.ShortcutInfo;
import android.graphics.drawable.Drawable;
import android.os.UserHandle;
+import android.util.Log;
import androidx.annotation.NonNull;
import com.android.launcher3.LauncherAppState;
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.icons.cache.CachingLogic;
-import com.android.launcher3.shortcuts.DeepShortcutManager;
import com.android.launcher3.shortcuts.ShortcutKey;
import com.android.launcher3.util.Themes;
@@ -37,6 +40,8 @@
*/
public class ShortcutCachingLogic implements CachingLogic<ShortcutInfo> {
+ private static final String TAG = "ShortcutCachingLogic";
+
@Override
public ComponentName getComponent(ShortcutInfo info) {
return ShortcutKey.fromInfo(info).componentName;
@@ -56,8 +61,8 @@
@Override
public BitmapInfo loadIcon(Context context, ShortcutInfo info) {
try (LauncherIcons li = LauncherIcons.obtain(context)) {
- Drawable unbadgedDrawable = DeepShortcutManager.getInstance(context)
- .getShortcutIconDrawable(info, LauncherAppState.getIDP(context).fillResIconDpi);
+ Drawable unbadgedDrawable = ShortcutCachingLogic.getIcon(
+ context, info, LauncherAppState.getIDP(context).fillResIconDpi);
if (unbadgedDrawable == null) return BitmapInfo.LOW_RES_INFO;
return new BitmapInfo(li.createScaledBitmapWithoutShadow(
unbadgedDrawable, 0), Themes.getColorAccent(context));
@@ -76,4 +81,21 @@
public boolean addToMemCache() {
return false;
}
+
+ /**
+ * Similar to {@link LauncherApps#getShortcutIconDrawable(ShortcutInfo, int)} with additional
+ * Launcher specific checks
+ */
+ public static Drawable getIcon(Context context, ShortcutInfo shortcutInfo, int density) {
+ if (GO_DISABLE_WIDGETS) {
+ return null;
+ }
+ try {
+ return context.getSystemService(LauncherApps.class)
+ .getShortcutIconDrawable(shortcutInfo, density);
+ } catch (SecurityException | IllegalStateException e) {
+ Log.e(TAG, "Failed to get shortcut icon", e);
+ return null;
+ }
+ }
}
diff --git a/src/com/android/launcher3/logging/FileLog.java b/src/com/android/launcher3/logging/FileLog.java
index 04cf20a..2c972a0 100644
--- a/src/com/android/launcher3/logging/FileLog.java
+++ b/src/com/android/launcher3/logging/FileLog.java
@@ -42,6 +42,8 @@
private static Handler sHandler = null;
private static File sLogsDirectory = null;
+ private static final int LOG_DAYS = 2;
+
public static void setDir(File logsDir) {
if (ENABLED) {
synchronized (DATE_FORMAT) {
@@ -147,7 +149,7 @@
case MSG_WRITE: {
Calendar cal = Calendar.getInstance();
// suffix with 0 or 1 based on the day of the year.
- String fileName = FILE_NAME_PREFIX + (cal.get(Calendar.DAY_OF_YEAR) & 1);
+ String fileName = FILE_NAME_PREFIX + (cal.get(Calendar.DAY_OF_YEAR) % LOG_DAYS);
if (!fileName.equals(mCurrentFileName)) {
closeWriter();
@@ -195,8 +197,9 @@
(Pair<PrintWriter, CountDownLatch>) msg.obj;
if (p.first != null) {
- dumpFile(p.first, FILE_NAME_PREFIX + 0);
- dumpFile(p.first, FILE_NAME_PREFIX + 1);
+ for (int i = 0; i < LOG_DAYS; i++) {
+ dumpFile(p.first, FILE_NAME_PREFIX + i);
+ }
}
p.second.countDown();
return true;
@@ -226,4 +229,15 @@
}
}
}
+
+ /**
+ * Gets files used for FileLog
+ */
+ public static File[] getLogFiles() {
+ File[] files = new File[LOG_DAYS];
+ for (int i = 0; i < LOG_DAYS; i++) {
+ files[i] = new File(sLogsDirectory, FILE_NAME_PREFIX + i);
+ }
+ return files;
+ }
}
diff --git a/src/com/android/launcher3/logging/UserEventDispatcher.java b/src/com/android/launcher3/logging/UserEventDispatcher.java
index 499cd2a..8289da9 100644
--- a/src/com/android/launcher3/logging/UserEventDispatcher.java
+++ b/src/com/android/launcher3/logging/UserEventDispatcher.java
@@ -147,6 +147,12 @@
}
fillIntentInfo(event.srcTarget[0], intent, userHandle);
}
+ ItemInfo info = (ItemInfo) v.getTag();
+ if (Utilities.IS_DEBUG_DEVICE && FeatureFlags.ENABLE_HYBRID_HOTSEAT.get()) {
+ FileLog.d(TAG, "appLaunch: packageName:" + info.getTargetComponent().getPackageName()
+ + ",isWorkApp:" + (info.user != null && !Process.myUserHandle().equals(
+ userHandle)) + ",launchLocation:" + info.container);
+ }
dispatchUserEvent(event, intent);
mAppOrTaskLaunch = true;
}
diff --git a/src/com/android/launcher3/model/BgDataModel.java b/src/com/android/launcher3/model/BgDataModel.java
index 0e20270..88f2a09 100644
--- a/src/com/android/launcher3/model/BgDataModel.java
+++ b/src/com/android/launcher3/model/BgDataModel.java
@@ -15,7 +15,11 @@
*/
package com.android.launcher3.model;
+import static com.android.launcher3.model.WidgetsModel.GO_DISABLE_WIDGETS;
+import static com.android.launcher3.shortcuts.ShortcutRequest.PINNED;
+
import android.content.Context;
+import android.content.pm.LauncherApps;
import android.content.pm.ShortcutInfo;
import android.os.UserHandle;
import android.text.TextUtils;
@@ -29,15 +33,15 @@
import com.android.launcher3.LauncherAppWidgetInfo;
import com.android.launcher3.LauncherSettings;
import com.android.launcher3.PromiseAppInfo;
-import com.android.launcher3.WorkspaceItemInfo;
import com.android.launcher3.Workspace;
+import com.android.launcher3.WorkspaceItemInfo;
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.logging.DumpTargetWrapper;
import com.android.launcher3.model.nano.LauncherDumpProto;
import com.android.launcher3.model.nano.LauncherDumpProto.ContainerType;
import com.android.launcher3.model.nano.LauncherDumpProto.DumpTarget;
-import com.android.launcher3.shortcuts.DeepShortcutManager;
import com.android.launcher3.shortcuts.ShortcutKey;
+import com.android.launcher3.shortcuts.ShortcutRequest;
import com.android.launcher3.util.ComponentKey;
import com.android.launcher3.util.IntArray;
import com.android.launcher3.util.IntSet;
@@ -59,6 +63,8 @@
import java.util.Iterator;
import java.util.List;
import java.util.Map;
+import java.util.function.BiConsumer;
+import java.util.stream.Collectors;
/**
* All the data stored in-memory and managed by the LauncherModel
@@ -287,7 +293,7 @@
if ((count == null || --count.value == 0)
&& !InstallShortcutReceiver.getPendingShortcuts(context)
.contains(pinnedShortcut)) {
- DeepShortcutManager.getInstance(context).unpinShortcut(pinnedShortcut);
+ unpinShortcut(context, pinnedShortcut);
}
// Fall through.
}
@@ -324,7 +330,7 @@
// Since this is a new item, pin the shortcut in the system server.
if (newItem && count.value == 1) {
- DeepShortcutManager.getInstance(context).pinShortcut(pinnedShortcut);
+ updatePinnedShortcuts(context, pinnedShortcut, List::add);
}
// Fall through
}
@@ -355,6 +361,36 @@
}
/**
+ * Removes the given shortcut from the current list of pinned shortcuts.
+ * (Runs on background thread)
+ */
+ public void unpinShortcut(Context context, ShortcutKey key) {
+ updatePinnedShortcuts(context, key, List::remove);
+ }
+
+ private void updatePinnedShortcuts(Context context, ShortcutKey key,
+ BiConsumer<List<String>, String> idOp) {
+ if (GO_DISABLE_WIDGETS) {
+ return;
+ }
+ String packageName = key.componentName.getPackageName();
+ String id = key.getId();
+ UserHandle user = key.user;
+ List<String> pinnedIds = new ShortcutRequest(context, user)
+ .forPackage(packageName)
+ .query(PINNED)
+ .stream()
+ .map(ShortcutInfo::getId)
+ .collect(Collectors.toCollection(ArrayList::new));
+ idOp.accept(pinnedIds, id);
+ try {
+ context.getSystemService(LauncherApps.class).pinShortcuts(packageName, pinnedIds, user);
+ } catch (SecurityException | IllegalStateException e) {
+ Log.w(TAG, "Failed to pin shortcut", e);
+ }
+ }
+
+ /**
* Return an existing FolderInfo object if we have encountered this ID previously,
* or make a new one.
*/
diff --git a/src/com/android/launcher3/model/LoaderTask.java b/src/com/android/launcher3/model/LoaderTask.java
index 605bb75..571d41a 100644
--- a/src/com/android/launcher3/model/LoaderTask.java
+++ b/src/com/android/launcher3/model/LoaderTask.java
@@ -21,6 +21,7 @@
import static com.android.launcher3.ItemInfoWithIcon.FLAG_DISABLED_SUSPENDED;
import static com.android.launcher3.model.ModelUtils.filterCurrentWorkspaceItems;
import static com.android.launcher3.util.Executors.MODEL_EXECUTOR;
+import static com.android.launcher3.util.PackageManagerHelper.hasShortcutsPermission;
import static com.android.launcher3.util.PackageManagerHelper.isSystemApp;
import android.appwidget.AppWidgetProviderInfo;
@@ -72,8 +73,9 @@
import com.android.launcher3.pm.UserCache;
import com.android.launcher3.provider.ImportDataTask;
import com.android.launcher3.qsb.QsbContainerView;
-import com.android.launcher3.shortcuts.DeepShortcutManager;
import com.android.launcher3.shortcuts.ShortcutKey;
+import com.android.launcher3.shortcuts.ShortcutRequest;
+import com.android.launcher3.shortcuts.ShortcutRequest.QueryResult;
import com.android.launcher3.util.ComponentKey;
import com.android.launcher3.util.IOUtils;
import com.android.launcher3.util.LooperIdleLock;
@@ -114,7 +116,6 @@
private final UserManager mUserManager;
private final UserCache mUserCache;
- private final DeepShortcutManager mShortcutManager;
private final InstallSessionHelper mSessionHelper;
private final IconCache mIconCache;
@@ -130,7 +131,6 @@
mLauncherApps = mApp.getContext().getSystemService(LauncherApps.class);
mUserManager = mApp.getContext().getSystemService(UserManager.class);
mUserCache = UserCache.INSTANCE.get(mApp.getContext());
- mShortcutManager = DeepShortcutManager.getInstance(mApp.getContext());
mSessionHelper = InstallSessionHelper.INSTANCE.get(mApp.getContext());
mIconCache = mApp.getIconCache();
}
@@ -349,8 +349,8 @@
// We can only query for shortcuts when the user is unlocked.
if (userUnlocked) {
- DeepShortcutManager.QueryResult pinnedShortcuts =
- mShortcutManager.queryForPinnedShortcuts(null, user);
+ QueryResult pinnedShortcuts = new ShortcutRequest(context, user)
+ .query(ShortcutRequest.PINNED);
if (pinnedShortcuts.wasSuccess()) {
for (ShortcutInfo shortcut : pinnedShortcuts) {
shortcutKeyToPinnedShortcuts.put(ShortcutKey.fromInfo(shortcut),
@@ -786,7 +786,7 @@
if ((numTimesPinned == null || numTimesPinned.value == 0)
&& !pendingShortcuts.contains(key)) {
// Shortcut is pinned but doesn't exist on the workspace; unpin it.
- mShortcutManager.unpinShortcut(key);
+ mBgDataModel.unpinShortcut(context, key);
}
}
@@ -884,12 +884,12 @@
private List<ShortcutInfo> loadDeepShortcuts() {
List<ShortcutInfo> allShortcuts = new ArrayList<>();
mBgDataModel.deepShortcutMap.clear();
- mBgDataModel.hasShortcutHostPermission = mShortcutManager.hasHostPermission();
+ mBgDataModel.hasShortcutHostPermission = hasShortcutsPermission(mApp.getContext());
if (mBgDataModel.hasShortcutHostPermission) {
for (UserHandle user : mUserCache.getUserProfiles()) {
if (mUserManager.isUserUnlocked(user)) {
- List<ShortcutInfo> shortcuts =
- mShortcutManager.queryForAllShortcuts(user);
+ List<ShortcutInfo> shortcuts = new ShortcutRequest(mApp.getContext(), user)
+ .query(ShortcutRequest.ALL);
allShortcuts.addAll(shortcuts);
mBgDataModel.updateDeepShortcutCounts(null, user, shortcuts);
}
diff --git a/src/com/android/launcher3/model/PackageUpdatedTask.java b/src/com/android/launcher3/model/PackageUpdatedTask.java
index 3361ff0..48c56e9 100644
--- a/src/com/android/launcher3/model/PackageUpdatedTask.java
+++ b/src/com/android/launcher3/model/PackageUpdatedTask.java
@@ -41,7 +41,7 @@
import com.android.launcher3.icons.IconCache;
import com.android.launcher3.icons.LauncherIcons;
import com.android.launcher3.logging.FileLog;
-import com.android.launcher3.shortcuts.DeepShortcutManager;
+import com.android.launcher3.shortcuts.ShortcutRequest;
import com.android.launcher3.testing.TestProtocol;
import com.android.launcher3.util.FlagOp;
import com.android.launcher3.util.IntSparseArrayMap;
@@ -208,10 +208,11 @@
if (si.isPromise() && isNewApkAvailable) {
boolean isTargetValid = true;
if (si.itemType == Favorites.ITEM_TYPE_DEEP_SHORTCUT) {
- List<ShortcutInfo> shortcut = DeepShortcutManager
- .getInstance(context).queryForPinnedShortcuts(
- cn.getPackageName(),
- Arrays.asList(si.getDeepShortcutId()), mUser);
+ List<ShortcutInfo> shortcut =
+ new ShortcutRequest(context, mUser)
+ .forPackage(cn.getPackageName(),
+ si.getDeepShortcutId())
+ .query(ShortcutRequest.PINNED);
if (shortcut.isEmpty()) {
isTargetValid = false;
} else {
diff --git a/src/com/android/launcher3/model/ShortcutsChangedTask.java b/src/com/android/launcher3/model/ShortcutsChangedTask.java
index 05225d4..b0e7a69 100644
--- a/src/com/android/launcher3/model/ShortcutsChangedTask.java
+++ b/src/com/android/launcher3/model/ShortcutsChangedTask.java
@@ -24,8 +24,8 @@
import com.android.launcher3.LauncherSettings;
import com.android.launcher3.WorkspaceItemInfo;
import com.android.launcher3.icons.LauncherIcons;
-import com.android.launcher3.shortcuts.DeepShortcutManager;
import com.android.launcher3.shortcuts.ShortcutKey;
+import com.android.launcher3.shortcuts.ShortcutRequest;
import com.android.launcher3.util.ItemInfoMatcher;
import com.android.launcher3.util.MultiHashMap;
@@ -54,8 +54,6 @@
@Override
public void execute(LauncherAppState app, BgDataModel dataModel, AllAppsList apps) {
final Context context = app.getContext();
- DeepShortcutManager deepShortcutManager = DeepShortcutManager.getInstance(context);
-
// Find WorkspaceItemInfo's that have changed on the workspace.
HashSet<ShortcutKey> removedKeys = new HashSet<>();
MultiHashMap<ShortcutKey, WorkspaceItemInfo> keyToShortcutInfo = new MultiHashMap<>();
@@ -74,8 +72,9 @@
final ArrayList<WorkspaceItemInfo> updatedWorkspaceItemInfos = new ArrayList<>();
if (!keyToShortcutInfo.isEmpty()) {
// Update the workspace to reflect the changes to updated shortcuts residing on it.
- List<ShortcutInfo> shortcuts = deepShortcutManager.queryForFullDetails(
- mPackageName, new ArrayList<>(allIds), mUser);
+ List<ShortcutInfo> shortcuts = new ShortcutRequest(context, mUser)
+ .forPackage(mPackageName, new ArrayList<>(allIds))
+ .query(ShortcutRequest.ALL);
for (ShortcutInfo fullDetails : shortcuts) {
ShortcutKey key = ShortcutKey.fromInfo(fullDetails);
List<WorkspaceItemInfo> workspaceItemInfos = keyToShortcutInfo.remove(key);
diff --git a/src/com/android/launcher3/model/UserLockStateChangedTask.java b/src/com/android/launcher3/model/UserLockStateChangedTask.java
index 694ae1a..d527423 100644
--- a/src/com/android/launcher3/model/UserLockStateChangedTask.java
+++ b/src/com/android/launcher3/model/UserLockStateChangedTask.java
@@ -27,8 +27,9 @@
import com.android.launcher3.LauncherSettings;
import com.android.launcher3.WorkspaceItemInfo;
import com.android.launcher3.icons.LauncherIcons;
-import com.android.launcher3.shortcuts.DeepShortcutManager;
import com.android.launcher3.shortcuts.ShortcutKey;
+import com.android.launcher3.shortcuts.ShortcutRequest;
+import com.android.launcher3.shortcuts.ShortcutRequest.QueryResult;
import com.android.launcher3.util.ComponentKey;
import com.android.launcher3.util.ItemInfoMatcher;
@@ -52,12 +53,11 @@
public void execute(LauncherAppState app, BgDataModel dataModel, AllAppsList apps) {
Context context = app.getContext();
boolean isUserUnlocked = context.getSystemService(UserManager.class).isUserUnlocked(mUser);
- DeepShortcutManager deepShortcutManager = DeepShortcutManager.getInstance(context);
HashMap<ShortcutKey, ShortcutInfo> pinnedShortcuts = new HashMap<>();
if (isUserUnlocked) {
- DeepShortcutManager.QueryResult shortcuts =
- deepShortcutManager.queryForPinnedShortcuts(null, mUser);
+ QueryResult shortcuts = new ShortcutRequest(context, mUser)
+ .query(ShortcutRequest.PINNED);
if (shortcuts.wasSuccess()) {
for (ShortcutInfo shortcut : shortcuts) {
pinnedShortcuts.put(ShortcutKey.fromInfo(shortcut), shortcut);
@@ -115,7 +115,8 @@
if (isUserUnlocked) {
dataModel.updateDeepShortcutCounts(
- null, mUser, deepShortcutManager.queryForAllShortcuts(mUser));
+ null, mUser,
+ new ShortcutRequest(context, mUser).query(ShortcutRequest.ALL));
}
bindDeepShortcuts(dataModel);
}
diff --git a/src/com/android/launcher3/popup/PopupPopulator.java b/src/com/android/launcher3/popup/PopupPopulator.java
index 80c6683..947f49d 100644
--- a/src/com/android/launcher3/popup/PopupPopulator.java
+++ b/src/com/android/launcher3/popup/PopupPopulator.java
@@ -31,8 +31,8 @@
import com.android.launcher3.notification.NotificationInfo;
import com.android.launcher3.notification.NotificationKeyData;
import com.android.launcher3.notification.NotificationListener;
-import com.android.launcher3.shortcuts.DeepShortcutManager;
import com.android.launcher3.shortcuts.DeepShortcutView;
+import com.android.launcher3.shortcuts.ShortcutRequest;
import com.android.launcher3.util.PackageUserKey;
import java.util.ArrayList;
@@ -144,8 +144,9 @@
uiHandler.post(() -> container.applyNotificationInfos(infos));
}
- List<ShortcutInfo> shortcuts = DeepShortcutManager.getInstance(launcher)
- .queryForShortcutsContainer(activity, user);
+ List<ShortcutInfo> shortcuts = new ShortcutRequest(launcher, user)
+ .withContainer(activity)
+ .query(ShortcutRequest.PUBLISHED);
String shortcutIdToDeDupe = notificationKeys.isEmpty() ? null
: notificationKeys.get(0).shortcutId;
shortcuts = PopupPopulator.sortAndFilterShortcuts(shortcuts, shortcutIdToDeDupe);
diff --git a/src/com/android/launcher3/provider/RestoreDbTask.java b/src/com/android/launcher3/provider/RestoreDbTask.java
index fb33551..36ff07e 100644
--- a/src/com/android/launcher3/provider/RestoreDbTask.java
+++ b/src/com/android/launcher3/provider/RestoreDbTask.java
@@ -34,8 +34,8 @@
import com.android.launcher3.LauncherAppWidgetInfo;
import com.android.launcher3.LauncherProvider.DatabaseHelper;
import com.android.launcher3.LauncherSettings.Favorites;
-import com.android.launcher3.WorkspaceItemInfo;
import com.android.launcher3.Utilities;
+import com.android.launcher3.WorkspaceItemInfo;
import com.android.launcher3.logging.FileLog;
import com.android.launcher3.provider.LauncherDbUtils.SQLiteTransaction;
import com.android.launcher3.util.IntArray;
@@ -112,9 +112,18 @@
whereClause.append(" AND profileId != ?");
profileIds[i] = Long.toString(profileMapping.keyAt(i));
}
- int itemsDeleted = db.delete(Favorites.TABLE_NAME, whereClause.toString(), profileIds);
- if (itemsDeleted > 0) {
- FileLog.d(TAG, itemsDeleted + " items from unrestored user(s) were deleted");
+ try {
+ int itemsDeleted = db.delete(Favorites.TABLE_NAME, whereClause.toString(), profileIds);
+ if (itemsDeleted > 0) {
+ FileLog.d(TAG, itemsDeleted + " items from unrestored user(s) were deleted");
+ }
+ } catch (IllegalArgumentException exception) {
+ // b/147114476
+ FileLog.e(TAG, new StringBuilder("Failed to execute delete, where clause: '")
+ .append(whereClause).append("', profile Id size:").append(profileIds.length)
+ .append("profileIds: ").append(String.join(", ", profileIds)).toString()
+ );
+ throw exception;
}
// Mark all items as restored.
diff --git a/src/com/android/launcher3/shortcuts/ShortcutKey.java b/src/com/android/launcher3/shortcuts/ShortcutKey.java
index 70665ca..fa1a85f 100644
--- a/src/com/android/launcher3/shortcuts/ShortcutKey.java
+++ b/src/com/android/launcher3/shortcuts/ShortcutKey.java
@@ -1,6 +1,7 @@
package com.android.launcher3.shortcuts;
import android.content.ComponentName;
+import android.content.Context;
import android.content.Intent;
import android.content.pm.ShortcutInfo;
import android.os.UserHandle;
@@ -29,6 +30,14 @@
return componentName.getClassName();
}
+ /**
+ * Creates a {@link ShortcutRequest} for this key
+ */
+ public ShortcutRequest buildRequest(Context context) {
+ return new ShortcutRequest(context, user)
+ .forPackage(componentName.getPackageName(), getId());
+ }
+
public static ShortcutKey fromInfo(ShortcutInfo shortcutInfo) {
return new ShortcutKey(shortcutInfo.getPackage(), shortcutInfo.getUserHandle(),
shortcutInfo.getId());
diff --git a/src/com/android/launcher3/shortcuts/ShortcutRequest.java b/src/com/android/launcher3/shortcuts/ShortcutRequest.java
new file mode 100644
index 0000000..e6203b4
--- /dev/null
+++ b/src/com/android/launcher3/shortcuts/ShortcutRequest.java
@@ -0,0 +1,119 @@
+/*
+ * Copyright (C) 2020 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.shortcuts;
+
+import static com.android.launcher3.model.WidgetsModel.GO_DISABLE_WIDGETS;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.pm.LauncherApps;
+import android.content.pm.LauncherApps.ShortcutQuery;
+import android.content.pm.ShortcutInfo;
+import android.os.UserHandle;
+import android.util.Log;
+
+import androidx.annotation.Nullable;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * Utility class to streamline Shortcut query
+ */
+public class ShortcutRequest {
+
+ private static final String TAG = "ShortcutRequest";
+
+ public static final int ALL = ShortcutQuery.FLAG_MATCH_DYNAMIC
+ | ShortcutQuery.FLAG_MATCH_MANIFEST | ShortcutQuery.FLAG_MATCH_PINNED;
+ public static final int PUBLISHED = ShortcutQuery.FLAG_MATCH_DYNAMIC
+ | ShortcutQuery.FLAG_MATCH_MANIFEST;
+ public static final int PINNED = ShortcutQuery.FLAG_MATCH_PINNED;
+
+ private final ShortcutQuery mQuery = GO_DISABLE_WIDGETS ? null : new ShortcutQuery();
+
+ private final Context mContext;
+ private final UserHandle mUserHandle;
+
+ boolean mFailed = false;
+
+ public ShortcutRequest(Context context, UserHandle userHandle) {
+ mContext = context;
+ mUserHandle = userHandle;
+ }
+
+ public ShortcutRequest forPackage(String packageName, String... shortcutIds) {
+ return forPackage(packageName, Arrays.asList(shortcutIds));
+ }
+
+ public ShortcutRequest forPackage(String packageName, @Nullable List<String> shortcutIds) {
+ if (!GO_DISABLE_WIDGETS && packageName != null) {
+ mQuery.setPackage(packageName);
+ mQuery.setShortcutIds(shortcutIds);
+ }
+ return this;
+ }
+
+ public ShortcutRequest withContainer(@Nullable ComponentName activity) {
+ if (!GO_DISABLE_WIDGETS) {
+ if (activity == null) {
+ mFailed = true;
+ } else {
+ mQuery.setActivity(activity);
+ }
+ }
+ return this;
+ }
+
+ public QueryResult query(int flags) {
+ if (GO_DISABLE_WIDGETS || mFailed) {
+ return QueryResult.DEFAULT;
+ }
+ mQuery.setQueryFlags(flags);
+
+ try {
+ return new QueryResult(mContext.getSystemService(LauncherApps.class)
+ .getShortcuts(mQuery, mUserHandle));
+ } catch (SecurityException | IllegalStateException e) {
+ Log.e(TAG, "Failed to query for shortcuts", e);
+ return QueryResult.DEFAULT;
+ }
+ }
+
+ public static class QueryResult extends ArrayList<ShortcutInfo> {
+
+ static final QueryResult DEFAULT = new QueryResult(GO_DISABLE_WIDGETS);
+
+ private final boolean mWasSuccess;
+
+ QueryResult(List<ShortcutInfo> result) {
+ super(result == null ? Collections.emptyList() : result);
+ mWasSuccess = true;
+ }
+
+ QueryResult(boolean wasSuccess) {
+ mWasSuccess = wasSuccess;
+ }
+
+
+ public boolean wasSuccess() {
+ return mWasSuccess;
+ }
+ }
+}
diff --git a/src/com/android/launcher3/util/PackageManagerHelper.java b/src/com/android/launcher3/util/PackageManagerHelper.java
index 2d56ce7..8b2ee36 100644
--- a/src/com/android/launcher3/util/PackageManagerHelper.java
+++ b/src/com/android/launcher3/util/PackageManagerHelper.java
@@ -332,4 +332,17 @@
}
return false;
}
+
+ /**
+ * Returns true if Launcher has the permission to access shortcuts.
+ * @see LauncherApps#hasShortcutHostPermission()
+ */
+ public static boolean hasShortcutsPermission(Context context) {
+ try {
+ return context.getSystemService(LauncherApps.class).hasShortcutHostPermission();
+ } catch (SecurityException | IllegalStateException e) {
+ Log.e(TAG, "Failed to make shortcut manager call", e);
+ }
+ return false;
+ }
}
diff --git a/src_plugins/com/android/systemui/plugins/OverscrollPlugin.java b/src_plugins/com/android/systemui/plugins/OverscrollPlugin.java
index 60eb304..28a9193 100644
--- a/src_plugins/com/android/systemui/plugins/OverscrollPlugin.java
+++ b/src_plugins/com/android/systemui/plugins/OverscrollPlugin.java
@@ -24,11 +24,11 @@
* the user to a more recent app).
*/
@ProvidesInterface(action = com.android.systemui.plugins.OverscrollPlugin.ACTION,
- version = com.android.systemui.plugins.OverlayPlugin.VERSION)
+ version = com.android.systemui.plugins.OverscrollPlugin.VERSION)
public interface OverscrollPlugin extends Plugin {
String ACTION = "com.android.systemui.action.PLUGIN_LAUNCHER_OVERSCROLL";
- int VERSION = 1;
+ int VERSION = 3;
String DEVICE_STATE_LOCKED = "Locked";
String DEVICE_STATE_LAUNCHER = "Launcher";
@@ -36,9 +36,38 @@
String DEVICE_STATE_UNKNOWN = "Unknown";
/**
- * Called when the user completed a right to left swipe in the gesture area.
- *
- * @param deviceState One of the DEVICE_STATE_* constants.
+ * @return true if the plugin is active and will accept overscroll gestures
*/
- void onOverscroll(String deviceState);
+ boolean isActive();
+
+ /**
+ * Called when a touch is down and has been recognized as an overscroll gesture.
+ * A call of this method will always result in `onTouchUp` being called, and possibly
+ * `onFling` as well.
+ *
+ * @param deviceState String representing the current device state
+ * @param underlyingActivity String representing the currently active Activity
+ */
+ void onTouchStart(String deviceState, String underlyingActivity);
+
+ /**
+ * Called when a touch that was previously recognized has moved.
+ *
+ * @param px distance between the position of touch on this update and the position of the
+ * touch when it was initially recognized.
+ */
+ void onTouchTraveled(int px);
+
+ /**
+ * Called when a touch that was previously recognized has ended.
+ *
+ * @param px distance between the position of touch on this update and the position of the
+ * touch when it was initially recognized.
+ */
+ void onTouchEnd(int px);
+
+ /**
+ * Called when the user starts Compose with a fling. `onTouchUp` will also be called.
+ */
+ void onFling(float velocity);
}
diff --git a/src_shortcuts_overrides/com/android/launcher3/shortcuts/DeepShortcutManager.java b/src_shortcuts_overrides/com/android/launcher3/shortcuts/DeepShortcutManager.java
deleted file mode 100644
index 57f4164..0000000
--- a/src_shortcuts_overrides/com/android/launcher3/shortcuts/DeepShortcutManager.java
+++ /dev/null
@@ -1,213 +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.shortcuts;
-
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.pm.LauncherApps;
-import android.content.pm.LauncherApps.ShortcutQuery;
-import android.content.pm.ShortcutInfo;
-import android.graphics.Rect;
-import android.graphics.drawable.Drawable;
-import android.os.Bundle;
-import android.os.UserHandle;
-import android.util.Log;
-
-import androidx.annotation.Nullable;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-
-/**
- * Performs operations related to deep shortcuts, such as querying for them, pinning them, etc.
- */
-public class DeepShortcutManager {
- private static final String TAG = "DeepShortcutManager";
-
- private static final int FLAG_GET_ALL = ShortcutQuery.FLAG_MATCH_DYNAMIC
- | ShortcutQuery.FLAG_MATCH_MANIFEST | ShortcutQuery.FLAG_MATCH_PINNED;
-
- private static DeepShortcutManager sInstance;
-
- public static DeepShortcutManager getInstance(Context context) {
- if (sInstance == null) {
- sInstance = new DeepShortcutManager(context.getApplicationContext());
- }
- return sInstance;
- }
-
- private final LauncherApps mLauncherApps;
-
- private DeepShortcutManager(Context context) {
- mLauncherApps = (LauncherApps) context.getSystemService(Context.LAUNCHER_APPS_SERVICE);
- }
-
- /**
- * Queries for the shortcuts with the package name and provided ids.
- *
- * This method is intended to get the full details for shortcuts when they are added or updated,
- * because we only get "key" fields in onShortcutsChanged().
- */
- public QueryResult queryForFullDetails(String packageName,
- List<String> shortcutIds, UserHandle user) {
- return query(FLAG_GET_ALL, packageName, null, shortcutIds, user);
- }
-
- /**
- * Gets all the manifest and dynamic shortcuts associated with the given package and user,
- * to be displayed in the shortcuts container on long press.
- */
- public QueryResult queryForShortcutsContainer(@Nullable ComponentName activity,
- UserHandle user) {
- if (activity == null) return QueryResult.FAILURE;
- return query(ShortcutQuery.FLAG_MATCH_MANIFEST | ShortcutQuery.FLAG_MATCH_DYNAMIC,
- activity.getPackageName(), activity, null, user);
- }
-
- /**
- * Removes the given shortcut from the current list of pinned shortcuts.
- * (Runs on background thread)
- */
- public void unpinShortcut(final ShortcutKey key) {
- String packageName = key.componentName.getPackageName();
- String id = key.getId();
- UserHandle user = key.user;
- List<String> pinnedIds = extractIds(queryForPinnedShortcuts(packageName, user));
- pinnedIds.remove(id);
- try {
- mLauncherApps.pinShortcuts(packageName, pinnedIds, user);
- } catch (SecurityException|IllegalStateException e) {
- Log.w(TAG, "Failed to unpin shortcut", e);
- }
- }
-
- /**
- * Adds the given shortcut to the current list of pinned shortcuts.
- * (Runs on background thread)
- */
- public void pinShortcut(final ShortcutKey key) {
- String packageName = key.componentName.getPackageName();
- String id = key.getId();
- UserHandle user = key.user;
- List<String> pinnedIds = extractIds(queryForPinnedShortcuts(packageName, user));
- pinnedIds.add(id);
- try {
- mLauncherApps.pinShortcuts(packageName, pinnedIds, user);
- } catch (SecurityException|IllegalStateException e) {
- Log.w(TAG, "Failed to pin shortcut", e);
- }
- }
-
- public void startShortcut(String packageName, String id, Rect sourceBounds,
- Bundle startActivityOptions, UserHandle user) {
- try {
- mLauncherApps.startShortcut(packageName, id, sourceBounds,
- startActivityOptions, user);
- } catch (SecurityException|IllegalStateException e) {
- Log.e(TAG, "Failed to start shortcut", e);
- }
- }
-
- public Drawable getShortcutIconDrawable(ShortcutInfo shortcutInfo, int density) {
- try {
- return mLauncherApps.getShortcutIconDrawable(shortcutInfo, density);
- } catch (SecurityException|IllegalStateException e) {
- Log.e(TAG, "Failed to get shortcut icon", e);
- return null;
- }
- }
-
- /**
- * Returns the id's of pinned shortcuts associated with the given package and user.
- *
- * If packageName is null, returns all pinned shortcuts regardless of package.
- */
- public QueryResult queryForPinnedShortcuts(String packageName, UserHandle user) {
- return queryForPinnedShortcuts(packageName, null, user);
- }
-
- public QueryResult queryForPinnedShortcuts(String packageName, List<String> shortcutIds,
- UserHandle user) {
- return query(ShortcutQuery.FLAG_MATCH_PINNED, packageName, null, shortcutIds, user);
- }
-
- public QueryResult queryForAllShortcuts(UserHandle user) {
- return query(FLAG_GET_ALL, null, null, null, user);
- }
-
- private static List<String> extractIds(List<ShortcutInfo> shortcuts) {
- List<String> shortcutIds = new ArrayList<>(shortcuts.size());
- for (ShortcutInfo shortcut : shortcuts) {
- shortcutIds.add(shortcut.getId());
- }
- return shortcutIds;
- }
-
- /**
- * Query the system server for all the shortcuts matching the given parameters.
- * If packageName == null, we query for all shortcuts with the passed flags, regardless of app.
- *
- * TODO: Use the cache to optimize this so we don't make an RPC every time.
- */
- private QueryResult query(int flags, String packageName, ComponentName activity,
- List<String> shortcutIds, UserHandle user) {
- ShortcutQuery q = new ShortcutQuery();
- q.setQueryFlags(flags);
- if (packageName != null) {
- q.setPackage(packageName);
- q.setActivity(activity);
- q.setShortcutIds(shortcutIds);
- }
- try {
- return new QueryResult(mLauncherApps.getShortcuts(q, user));
- } catch (SecurityException|IllegalStateException e) {
- Log.e(TAG, "Failed to query for shortcuts", e);
- return QueryResult.FAILURE;
- }
- }
-
- public boolean hasHostPermission() {
- try {
- return mLauncherApps.hasShortcutHostPermission();
- } catch (SecurityException|IllegalStateException e) {
- Log.e(TAG, "Failed to make shortcut manager call", e);
- }
- return false;
- }
-
- public static class QueryResult extends ArrayList<ShortcutInfo> {
-
- static QueryResult FAILURE = new QueryResult();
-
- private final boolean mWasSuccess;
-
- QueryResult(List<ShortcutInfo> result) {
- super(result == null ? Collections.emptyList() : result);
- mWasSuccess = true;
- }
-
- QueryResult() {
- mWasSuccess = false;
- }
-
-
- public boolean wasSuccess() {
- return mWasSuccess;
- }
- }
-}
diff --git a/tests/Android.mk b/tests/Android.mk
index 83fdddc..d1a6c06 100644
--- a/tests/Android.mk
+++ b/tests/Android.mk
@@ -57,7 +57,7 @@
LOCAL_PRIVATE_PLATFORM_APIS := true
LOCAL_STATIC_JAVA_LIBRARIES += launcher-aosp-tapl
else
- LOCAL_SDK_VERSION := 28
+ LOCAL_SDK_VERSION := system_28
LOCAL_MIN_SDK_VERSION := 21
LOCAL_STATIC_JAVA_LIBRARIES += ub-launcher-aosp-tapl
endif