Merge "Refactoring DigitalWellbeing Banner to not use footers." into ub-launcher3-master
diff --git a/quickstep/robolectric_tests/src/com/android/quickstep/util/RecentsOrientedStateTest.java b/quickstep/robolectric_tests/src/com/android/quickstep/util/RecentsOrientedStateTest.java
new file mode 100644
index 0000000..656379f
--- /dev/null
+++ b/quickstep/robolectric_tests/src/com/android/quickstep/util/RecentsOrientedStateTest.java
@@ -0,0 +1,89 @@
+/*
+ * 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.quickstep.util;
+
+import static android.view.Surface.ROTATION_0;
+import static android.view.Surface.ROTATION_180;
+import static android.view.Surface.ROTATION_90;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
+
+import android.content.Context;
+
+import com.android.quickstep.FallbackActivityInterface;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.RuntimeEnvironment;
+import org.robolectric.annotation.LooperMode;
+import org.robolectric.annotation.LooperMode.Mode;
+
+/**
+ * Tests for {@link RecentsOrientedState}
+ */
+@RunWith(RobolectricTestRunner.class)
+@LooperMode(Mode.PAUSED)
+public class RecentsOrientedStateTest {
+
+ private RecentsOrientedState mR1, mR2;
+
+ @Before
+ public void setup() {
+ Context context = RuntimeEnvironment.application;
+ mR1 = new RecentsOrientedState(context, FallbackActivityInterface.INSTANCE, i -> { });
+ mR2 = new RecentsOrientedState(context, FallbackActivityInterface.INSTANCE, i -> { });
+ assertEquals(mR1.getStateId(), mR2.getStateId());
+ }
+
+ @Test
+ public void stateId_changesWithFlags() {
+ mR1.setGestureActive(true);
+ mR2.setGestureActive(false);
+ assertNotEquals(mR1.getStateId(), mR2.getStateId());
+
+ mR2.setGestureActive(true);
+ assertEquals(mR1.getStateId(), mR2.getStateId());
+ }
+
+ @Test
+ public void stateId_changesWithRecentsRotation() {
+ mR1.setRecentsRotation(ROTATION_90);
+ mR2.setRecentsRotation(ROTATION_180);
+ assertNotEquals(mR1.getStateId(), mR2.getStateId());
+
+ mR2.setRecentsRotation(ROTATION_90);
+ assertEquals(mR1.getStateId(), mR2.getStateId());
+ }
+
+ @Test
+ public void stateId_changesWithDisplayRotation() {
+ mR1.update(ROTATION_0, ROTATION_90);
+ mR2.update(ROTATION_0, ROTATION_180);
+ assertNotEquals(mR1.getStateId(), mR2.getStateId());
+
+ mR2.update(ROTATION_90, ROTATION_90);
+ assertNotEquals(mR1.getStateId(), mR2.getStateId());
+
+ mR2.update(ROTATION_90, ROTATION_0);
+ assertNotEquals(mR1.getStateId(), mR2.getStateId());
+
+ mR2.update(ROTATION_0, ROTATION_90);
+ assertEquals(mR1.getStateId(), mR2.getStateId());
+ }
+}
diff --git a/quickstep/robolectric_tests/src/com/android/quickstep/util/TaskViewSimulatorTest.java b/quickstep/robolectric_tests/src/com/android/quickstep/util/TaskViewSimulatorTest.java
index 6c88e55..688f323 100644
--- a/quickstep/robolectric_tests/src/com/android/quickstep/util/TaskViewSimulatorTest.java
+++ b/quickstep/robolectric_tests/src/com/android/quickstep/util/TaskViewSimulatorTest.java
@@ -148,7 +148,7 @@
if (mAppRotation < 0) {
mAppRotation = launcherRotation;
}
- tvs.setLayoutRotation(launcherRotation, mAppRotation);
+ tvs.getOrientationState().update(launcherRotation, mAppRotation);
if (mAppInsets == null) {
mAppInsets = new Rect(mLauncherInsets);
}
diff --git a/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java b/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java
index 44d43c6..456727c 100644
--- a/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java
+++ b/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java
@@ -19,11 +19,10 @@
import static com.android.launcher3.AbstractFloatingView.TYPE_HIDE_BACK_BUTTON;
import static com.android.launcher3.LauncherState.FLAG_HIDE_BACK_BUTTON;
import static com.android.launcher3.LauncherState.NORMAL;
+import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
import static com.android.quickstep.SysUINavigationMode.removeShelfFromOverview;
import static com.android.systemui.shared.system.ActivityManagerWrapper.CLOSE_SYSTEM_WINDOWS_REASON_HOME_KEY;
-import com.android.systemui.shared.system.InteractionJankMonitorWrapper;
-
import android.animation.AnimatorSet;
import android.animation.ValueAnimator;
import android.app.ActivityOptions;
@@ -48,12 +47,14 @@
import com.android.quickstep.SysUINavigationMode.Mode;
import com.android.quickstep.SysUINavigationMode.NavigationModeChangeListener;
import com.android.quickstep.SystemUiProxy;
+import com.android.quickstep.TaskUtils;
import com.android.quickstep.util.RemoteAnimationProvider;
import com.android.quickstep.util.RemoteFadeOutAnimationListener;
import com.android.quickstep.views.OverviewActionsView;
import com.android.quickstep.views.RecentsView;
import com.android.systemui.shared.system.ActivityManagerWrapper;
import com.android.systemui.shared.system.ActivityOptionsCompat;
+import com.android.systemui.shared.system.InteractionJankMonitorWrapper;
import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
import java.util.stream.Stream;
@@ -123,7 +124,8 @@
@Override
protected void onUiChangedWhileSleeping() {
// Remove the snapshot because the content view may have obvious changes.
- ActivityManagerWrapper.getInstance().invalidateHomeTaskSnapshot(this);
+ UI_HELPER_EXECUTOR.execute(
+ () -> ActivityManagerWrapper.getInstance().invalidateHomeTaskSnapshot(this));
}
@Override
@@ -203,8 +205,7 @@
@Override
protected void closeOpenViews(boolean animate) {
super.closeOpenViews(animate);
- ActivityManagerWrapper.getInstance()
- .closeSystemWindows(CLOSE_SYSTEM_WINDOWS_REASON_HOME_KEY);
+ TaskUtils.closeSystemWindowsAsync(CLOSE_SYSTEM_WINDOWS_REASON_HOME_KEY);
}
@Override
diff --git a/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java b/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
index e808f8c..e02c0c3 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
@@ -74,10 +74,10 @@
import com.android.quickstep.SysUINavigationMode;
import com.android.quickstep.SysUINavigationMode.Mode;
import com.android.quickstep.SystemUiProxy;
+import com.android.quickstep.TaskUtils;
import com.android.quickstep.util.QuickstepOnboardingPrefs;
import com.android.quickstep.views.RecentsView;
import com.android.quickstep.views.TaskView;
-import com.android.systemui.shared.system.ActivityManagerWrapper;
import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -175,8 +175,7 @@
@Override
protected void showAllAppsFromIntent(boolean alreadyOnHome) {
- ActivityManagerWrapper.getInstance().closeSystemWindows(
- CLOSE_SYSTEM_WINDOWS_REASON_HOME_KEY);
+ TaskUtils.closeSystemWindowsAsync(CLOSE_SYSTEM_WINDOWS_REASON_HOME_KEY);
super.showAllAppsFromIntent(alreadyOnHome);
}
diff --git a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NavBarToHomeTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NavBarToHomeTouchController.java
index d210bc6..f73e2f2 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NavBarToHomeTouchController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NavBarToHomeTouchController.java
@@ -17,6 +17,8 @@
import static com.android.launcher3.AbstractFloatingView.TYPE_ALL;
import static com.android.launcher3.AbstractFloatingView.TYPE_ALL_APPS_EDU;
+import static com.android.launcher3.LauncherAnimUtils.SUCCESS_TRANSITION_PROGRESS;
+import static com.android.launcher3.LauncherAnimUtils.newCancelListener;
import static com.android.launcher3.LauncherState.ALL_APPS;
import static com.android.launcher3.LauncherState.NORMAL;
import static com.android.launcher3.allapps.AllAppsTransitionController.ALL_APPS_PROGRESS;
@@ -24,7 +26,6 @@
import static com.android.launcher3.config.FeatureFlags.ENABLE_ALL_APPS_EDU;
import static com.android.launcher3.config.FeatureFlags.ENABLE_QUICKSTEP_LIVE_TILE;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_HOME_GESTURE;
-import static com.android.launcher3.touch.AbstractStateChangeTouchController.SUCCESS_TRANSITION_PROGRESS;
import static com.android.systemui.shared.system.ActivityManagerWrapper.CLOSE_SYSTEM_WINDOWS_REASON_RECENTS;
import android.animation.ValueAnimator;
@@ -49,11 +50,11 @@
import com.android.launcher3.testing.TestProtocol;
import com.android.launcher3.touch.SingleAxisSwipeDetector;
import com.android.launcher3.util.TouchController;
+import com.android.quickstep.TaskUtils;
import com.android.quickstep.util.AnimatorControllerWithResistance;
import com.android.quickstep.util.AssistantUtilities;
import com.android.quickstep.util.OverviewToHomeAnim;
import com.android.quickstep.views.RecentsView;
-import com.android.systemui.shared.system.ActivityManagerWrapper;
/**
* Handles swiping up on the nav bar to go home from launcher, e.g. overview or all apps.
@@ -186,8 +187,8 @@
if (topView != null) {
topView.addHintCloseAnim(mPullbackDistance, PULLBACK_INTERPOLATOR, builder);
}
- mCurrentAnimation = builder.createPlaybackController()
- .setOnCancelRunnable(this::clearState);
+ mCurrentAnimation = builder.createPlaybackController();
+ mCurrentAnimation.getTarget().addListener(newCancelListener(this::clearState));
}
private void clearState() {
@@ -233,8 +234,7 @@
AbstractFloatingView.closeAllOpenViews(mLauncher);
// TODO: add to WW log
}
- ActivityManagerWrapper.getInstance()
- .closeSystemWindows(CLOSE_SYSTEM_WINDOWS_REASON_RECENTS);
+ TaskUtils.closeSystemWindowsAsync(CLOSE_SYSTEM_WINDOWS_REASON_RECENTS);
} else {
// Quickly return to the state we came from (we didn't move far).
ValueAnimator anim = mCurrentAnimation.getAnimationPlayer();
diff --git a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonNavbarToOverviewTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonNavbarToOverviewTouchController.java
index 2a3bdbf..702c519 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonNavbarToOverviewTouchController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonNavbarToOverviewTouchController.java
@@ -16,6 +16,7 @@
package com.android.launcher3.uioverrides.touchcontrollers;
+import static com.android.launcher3.LauncherAnimUtils.newCancelListener;
import static com.android.launcher3.LauncherState.ALL_APPS;
import static com.android.launcher3.LauncherState.HINT_STATE;
import static com.android.launcher3.LauncherState.NORMAL;
@@ -191,15 +192,17 @@
return;
}
mNormalToHintOverviewScrimAnimator = null;
- mCurrentAnimation.dispatchOnCancelWithoutCancelRunnable(() -> {
+ mCurrentAnimation.getTarget().addListener(newCancelListener(() ->
mLauncher.getStateManager().goToState(OVERVIEW, true, () -> {
mOverviewResistYAnim = AnimatorControllerWithResistance
.createRecentsResistanceFromOverviewAnim(mLauncher, null)
.createPlaybackController();
mReachedOverview = true;
maybeSwipeInteractionToOverviewComplete();
- });
- });
+ })));
+
+ mCurrentAnimation.getTarget().removeListener(mClearStateOnCancelListener);
+ mCurrentAnimation.dispatchOnCancel();
mStartedOverview = true;
VibratorWrapper.INSTANCE.get(mLauncher).vibrate(OVERVIEW_HAPTIC);
}
diff --git a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonQuickSwitchTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonQuickSwitchTouchController.java
index f378848..df433f8 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonQuickSwitchTouchController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonQuickSwitchTouchController.java
@@ -15,6 +15,7 @@
*/
package com.android.launcher3.uioverrides.touchcontrollers;
+import static com.android.launcher3.LauncherAnimUtils.newCancelListener;
import static com.android.launcher3.LauncherState.NORMAL;
import static com.android.launcher3.LauncherState.OVERVIEW;
import static com.android.launcher3.LauncherState.OVERVIEW_BUTTONS;
@@ -44,6 +45,7 @@
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_OVERVIEW_DISABLED;
import android.animation.Animator;
+import android.animation.Animator.AnimatorListener;
import android.animation.AnimatorListenerAdapter;
import android.animation.ValueAnimator;
import android.graphics.PointF;
@@ -92,6 +94,8 @@
private final MotionPauseDetector mMotionPauseDetector;
private final float mMotionPauseMinDisplacement;
private final LauncherRecentsView mRecentsView;
+ protected final AnimatorListener mClearStateOnCancelListener =
+ newCancelListener(this::clearState);
private boolean mNoIntercept;
private LauncherState mStartState;
@@ -204,8 +208,8 @@
config.duration = (long) (Math.max(mXRange, mYRange) * 2);
config.animFlags = config.animFlags | SKIP_OVERVIEW;
mNonOverviewAnim = mLauncher.getStateManager()
- .createAnimationToNewWorkspace(toState, config)
- .setOnCancelRunnable(this::clearState);
+ .createAnimationToNewWorkspace(toState, config);
+ mNonOverviewAnim.getTarget().addListener(mClearStateOnCancelListener);
}
private void setupOverviewAnimators() {
@@ -379,7 +383,8 @@
if (canceled) {
// Let the state manager know that the animation didn't go to the target state,
// but don't clean up yet (we already clean up when the animation completes).
- mNonOverviewAnim.dispatchOnCancelWithoutCancelRunnable();
+ mNonOverviewAnim.getTarget().removeListener(mClearStateOnCancelListener);
+ mNonOverviewAnim.dispatchOnCancel();
}
float startProgress = mNonOverviewAnim.getProgressFraction();
float endProgress = canceled ? 0 : 1;
diff --git a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/PortraitStatesTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/PortraitStatesTouchController.java
index 037d988..3c9b808 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/PortraitStatesTouchController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/PortraitStatesTouchController.java
@@ -245,29 +245,29 @@
config.animFlags = animFlags;
config.duration = maxAccuracy;
- cancelPendingAnim();
+ if (mCurrentAnimation != null) {
+ mCurrentAnimation.getTarget().removeListener(mClearStateOnCancelListener);
+ mCurrentAnimation.dispatchOnCancel();
+ }
+ mGoingBetweenStates = true;
if (mFromState == OVERVIEW && mToState == NORMAL
&& mOverviewPortraitStateTouchHelper.shouldSwipeDownReturnToApp()) {
// Reset the state manager, when changing the interaction mode
mLauncher.getStateManager().goToState(OVERVIEW, false /* animate */);
- mPendingAnimation = mOverviewPortraitStateTouchHelper
- .createSwipeDownToTaskAppAnimation(maxAccuracy, Interpolators.LINEAR);
- Runnable onCancelRunnable = () -> {
- cancelPendingAnim();
- clearState();
- };
- mCurrentAnimation = mPendingAnimation.createPlaybackController()
- .setOnCancelRunnable(onCancelRunnable);
+ mGoingBetweenStates = false;
+ mCurrentAnimation = mOverviewPortraitStateTouchHelper
+ .createSwipeDownToTaskAppAnimation(maxAccuracy, Interpolators.LINEAR)
+ .createPlaybackController();
mLauncher.getStateManager().setCurrentUserControlledAnimation(mCurrentAnimation);
RecentsView recentsView = mLauncher.getOverviewPanel();
totalShift = LayoutUtils.getShelfTrackingDistance(mLauncher,
mLauncher.getDeviceProfile(), recentsView.getPagedOrientationHandler());
} else {
mCurrentAnimation = mLauncher.getStateManager()
- .createAnimationToNewWorkspace(mToState, config)
- .setOnCancelRunnable(this::clearState);
+ .createAnimationToNewWorkspace(mToState, config);
}
+ mCurrentAnimation.getTarget().addListener(mClearStateOnCancelListener);
if (totalShift == 0) {
totalShift = Math.signum(mFromState.ordinal - mToState.ordinal)
@@ -276,13 +276,6 @@
return 1 / totalShift;
}
- private void cancelPendingAnim() {
- if (mPendingAnimation != null) {
- mPendingAnimation.finish(false);
- mPendingAnimation = null;
- }
- }
-
@Override
protected void updateSwipeCompleteAnimation(ValueAnimator animator, long expectedDuration,
LauncherState targetState, float velocity, boolean isFling) {
diff --git a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/QuickSwitchTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/QuickSwitchTouchController.java
index b8c2030..fc9e1bb 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/QuickSwitchTouchController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/QuickSwitchTouchController.java
@@ -45,9 +45,9 @@
import com.android.quickstep.SysUINavigationMode;
import com.android.quickstep.SysUINavigationMode.Mode;
import com.android.quickstep.SystemUiProxy;
+import com.android.quickstep.TaskUtils;
import com.android.quickstep.views.RecentsView;
import com.android.quickstep.views.TaskView;
-import com.android.systemui.shared.system.ActivityManagerWrapper;
/**
* Handles quick switching to a recent task from the home screen.
@@ -92,8 +92,7 @@
public void onDragStart(boolean start, float startDisplacement) {
super.onDragStart(start, startDisplacement);
mStartContainerType = LAUNCHER_STATE_BACKGROUND;
- ActivityManagerWrapper.getInstance()
- .closeSystemWindows(CLOSE_SYSTEM_WINDOWS_REASON_RECENTS);
+ TaskUtils.closeSystemWindowsAsync(CLOSE_SYSTEM_WINDOWS_REASON_RECENTS);
}
@Override
@@ -107,8 +106,8 @@
setupInterpolators(config);
config.duration = (long) (getShiftRange() * 2);
mCurrentAnimation = mLauncher.getStateManager()
- .createAnimationToNewWorkspace(mToState, config)
- .setOnCancelRunnable(this::clearState);
+ .createAnimationToNewWorkspace(mToState, config);
+ mCurrentAnimation.getTarget().addListener(mClearStateOnCancelListener);
mCurrentAnimation.getAnimationPlayer().addUpdateListener(valueAnimator ->
updateFullscreenProgress((Float) valueAnimator.getAnimatedValue()));
return 1 / getShiftRange();
diff --git a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/TaskViewTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/TaskViewTouchController.java
index 186caf6..9729695 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/TaskViewTouchController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/TaskViewTouchController.java
@@ -16,6 +16,7 @@
package com.android.launcher3.uioverrides.touchcontrollers;
import static com.android.launcher3.AbstractFloatingView.TYPE_ACCESSIBLE;
+import static com.android.launcher3.LauncherAnimUtils.SUCCESS_TRANSITION_PROGRESS;
import static com.android.launcher3.touch.SingleAxisSwipeDetector.DIRECTION_BOTH;
import static com.android.launcher3.touch.SingleAxisSwipeDetector.DIRECTION_NEGATIVE;
import static com.android.launcher3.touch.SingleAxisSwipeDetector.DIRECTION_POSITIVE;
@@ -50,16 +51,12 @@
extends AnimatorListenerAdapter implements TouchController,
SingleAxisSwipeDetector.Listener {
- // Progress after which the transition is assumed to be a success in case user does not fling
- public static final float SUCCESS_TRANSITION_PROGRESS = 0.5f;
-
protected final T mActivity;
private final SingleAxisSwipeDetector mDetector;
private final RecentsView mRecentsView;
private final int[] mTempCords = new int[2];
private final boolean mIsRtl;
- private PendingAnimation mPendingAnimation;
private AnimatorPlaybackController mCurrentAnimation;
private boolean mCurrentAnimationIsGoingUp;
@@ -200,10 +197,8 @@
}
if (mCurrentAnimation != null) {
mCurrentAnimation.setPlayFraction(0);
- }
- if (mPendingAnimation != null) {
- mPendingAnimation.finish(false);
- mPendingAnimation = null;
+ mCurrentAnimation.getTarget().removeListener(this);
+ mCurrentAnimation.dispatchOnCancel();
}
PagedOrientationHandler orientationHandler = mRecentsView.getPagedOrientationHandler();
@@ -216,15 +211,16 @@
// The interpolator controlling the most prominent visual movement. We use this to determine
// whether we passed SUCCESS_TRANSITION_PROGRESS.
final Interpolator currentInterpolator;
+ PendingAnimation pa;
if (goingUp) {
currentInterpolator = Interpolators.LINEAR;
- mPendingAnimation = mRecentsView.createTaskDismissAnimation(mTaskBeingDragged,
+ pa = mRecentsView.createTaskDismissAnimation(mTaskBeingDragged,
true /* animateTaskView */, true /* removeTask */, maxDuration);
mEndDisplacement = -secondaryTaskDimension;
} else {
currentInterpolator = Interpolators.ZOOM_IN;
- mPendingAnimation = mRecentsView.createTaskLaunchAnimation(
+ pa = mRecentsView.createTaskLaunchAnimation(
mTaskBeingDragged, maxDuration, currentInterpolator);
// Since the thumbnail is what is filling the screen, based the end displacement on it.
@@ -234,12 +230,8 @@
mEndDisplacement = secondaryLayerDimension - mTempCords[1];
}
mEndDisplacement *= verticalFactor;
+ mCurrentAnimation = pa.createPlaybackController();
- if (mCurrentAnimation != null) {
- mCurrentAnimation.setOnCancelRunnable(null);
- }
- mCurrentAnimation = mPendingAnimation.createPlaybackController()
- .setOnCancelRunnable(this::clearState);
// Setting this interpolator doesn't affect the visual motion, but is used to determine
// whether we successfully reached the target state in onDragEnd().
mCurrentAnimation.getTarget().setInterpolator(currentInterpolator);
@@ -303,27 +295,15 @@
animationDuration *= LauncherAnimUtils.blockedFlingDurationFactor(velocity);
}
- mCurrentAnimation.setEndAction(() -> onCurrentAnimationEnd(goingToEnd));
+ mCurrentAnimation.setEndAction(this::clearState);
mCurrentAnimation.startWithVelocity(mActivity, goingToEnd,
velocity, mEndDisplacement, animationDuration);
}
- private void onCurrentAnimationEnd(boolean wasSuccess) {
- if (mPendingAnimation != null) {
- mPendingAnimation.finish(wasSuccess);
- mPendingAnimation = null;
- }
- clearState();
- }
-
private void clearState() {
mDetector.finishedScrolling();
mDetector.setDetectableScrollConditions(0, false);
mTaskBeingDragged = null;
mCurrentAnimation = null;
- if (mPendingAnimation != null) {
- mPendingAnimation.finish(false);
- mPendingAnimation = null;
- }
}
}
diff --git a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
index 6cf3c7a..041f679 100644
--- a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
+++ b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
@@ -378,7 +378,7 @@
if (mStateCallback.hasStates(STATE_HANDLER_INVALIDATED)) {
return;
}
- mTaskViewSimulator.setRecentsRotation(mActivity.getDisplay().getRotation());
+ mTaskViewSimulator.setOrientationState(mRecentsView.getPagedViewOrientedState());
// If we've already ended the gesture and are going home, don't prepare recents UI,
// as that will set the state as BACKGROUND_APP, overriding the animation to NORMAL.
@@ -686,6 +686,7 @@
dp.updateInsets(targets.homeContentInsets);
dp.updateIsSeascape(mContext);
initTransitionEndpoints(dp);
+ mTaskViewSimulator.getOrientationState().setMultiWindowMode(dp.isMultiWindowMode);
}
// Notify when the animation starts
@@ -1020,7 +1021,7 @@
protected abstract HomeAnimationFactory createHomeAnimationFactory(long duration);
- private TaskStackChangeListener mActivityRestartListener = new TaskStackChangeListener() {
+ private final TaskStackChangeListener mActivityRestartListener = new TaskStackChangeListener() {
@Override
public void onActivityRestartAttempt(ActivityManager.RunningTaskInfo task,
boolean homeTaskVisible, boolean clearedTask, boolean wasVisible) {
@@ -1459,13 +1460,33 @@
protected abstract void finishRecentsControllerToHome(Runnable callback);
+ private final TaskStackChangeListener mLiveTileRestartListener = new TaskStackChangeListener() {
+ @Override
+ public void onActivityRestartAttempt(ActivityManager.RunningTaskInfo task,
+ boolean homeTaskVisible, boolean clearedTask, boolean wasVisible) {
+ if (mRecentsAnimationTargets.hasTask(task.taskId)) {
+ launchOtherTaskInLiveTileMode(task.taskId, mRecentsAnimationTargets.apps);
+ }
+ ActivityManagerWrapper.getInstance().unregisterTaskStackListener(
+ mLiveTileRestartListener);
+ }
+ };
+
private void setupLauncherUiAfterSwipeUpToRecentsAnimation() {
endLauncherTransitionController();
mActivityInterface.onSwipeUpToRecentsComplete();
mRecentsView.onSwipeUpAnimationSuccess();
if (ENABLE_QUICKSTEP_LIVE_TILE.get()) {
mTaskAnimationManager.setLaunchOtherTaskInLiveTileModeHandler(
- this::launchOtherTaskInLiveTileMode);
+ appearedTaskTarget -> {
+ RemoteAnimationTargetCompat[] apps = Arrays.copyOf(
+ mRecentsAnimationTargets.apps,
+ mRecentsAnimationTargets.apps.length + 1);
+ apps[apps.length - 1] = appearedTaskTarget;
+ launchOtherTaskInLiveTileMode(appearedTaskTarget.taskId, apps);
+ });
+ ActivityManagerWrapper.getInstance().registerTaskStackListener(
+ mLiveTileRestartListener);
}
SystemUiProxy.INSTANCE.get(mContext).onOverviewShown(false, TAG);
@@ -1473,17 +1494,12 @@
reset();
}
- private void launchOtherTaskInLiveTileMode(RemoteAnimationTargetCompat appearedTaskTarget) {
- TaskView taskView = mRecentsView.getTaskView(appearedTaskTarget.taskId);
+ private void launchOtherTaskInLiveTileMode(int taskId, RemoteAnimationTargetCompat[] apps) {
+ TaskView taskView = mRecentsView.getTaskView(taskId);
if (taskView == null) {
return;
}
- RemoteAnimationTargetCompat[] apps = Arrays.copyOf(
- mRecentsAnimationTargets.apps,
- mRecentsAnimationTargets.apps.length + 1);
- apps[apps.length - 1] = appearedTaskTarget;
-
AnimatorSet anim = new AnimatorSet();
TaskViewUtils.composeRecentsLaunchAnimator(
anim, taskView, apps,
diff --git a/quickstep/src/com/android/quickstep/AppToOverviewAnimationProvider.java b/quickstep/src/com/android/quickstep/AppToOverviewAnimationProvider.java
index 55f5424..efd4530 100644
--- a/quickstep/src/com/android/quickstep/AppToOverviewAnimationProvider.java
+++ b/quickstep/src/com/android/quickstep/AppToOverviewAnimationProvider.java
@@ -132,9 +132,8 @@
TaskViewSimulator tsv = new TaskViewSimulator(mActivity, mRecentsView.getSizeStrategy());
tsv.setDp(mActivity.getDeviceProfile());
+ tsv.setOrientationState(mRecentsView.getPagedViewOrientedState());
tsv.setPreview(runningTaskTarget);
- tsv.setLayoutRotation(mRecentsView.getPagedViewOrientedState().getTouchRotation(),
- mRecentsView.getPagedViewOrientedState().getDisplayRotation());
TransformParams params = new TransformParams()
.setTargetSet(targets)
diff --git a/quickstep/src/com/android/quickstep/OverviewCommandHelper.java b/quickstep/src/com/android/quickstep/OverviewCommandHelper.java
index 9f7871a..1badfbc 100644
--- a/quickstep/src/com/android/quickstep/OverviewCommandHelper.java
+++ b/quickstep/src/com/android/quickstep/OverviewCommandHelper.java
@@ -65,16 +65,14 @@
return;
}
- ActivityManagerWrapper.getInstance()
- .closeSystemWindows(CLOSE_SYSTEM_WINDOWS_REASON_RECENTS);
+ TaskUtils.closeSystemWindowsAsync(CLOSE_SYSTEM_WINDOWS_REASON_RECENTS);
MAIN_EXECUTOR.execute(new RecentsActivityCommand<>());
}
@BinderThread
public void onOverviewShown(boolean triggeredFromAltTab) {
if (triggeredFromAltTab) {
- ActivityManagerWrapper.getInstance()
- .closeSystemWindows(CLOSE_SYSTEM_WINDOWS_REASON_RECENTS);
+ TaskUtils.closeSystemWindowsAsync(CLOSE_SYSTEM_WINDOWS_REASON_RECENTS);
}
MAIN_EXECUTOR.execute(new ShowRecentsCommand(triggeredFromAltTab));
}
diff --git a/quickstep/src/com/android/quickstep/RecentsAnimationTargets.java b/quickstep/src/com/android/quickstep/RecentsAnimationTargets.java
index 718c5ba..da0a664 100644
--- a/quickstep/src/com/android/quickstep/RecentsAnimationTargets.java
+++ b/quickstep/src/com/android/quickstep/RecentsAnimationTargets.java
@@ -41,4 +41,13 @@
public boolean hasTargets() {
return unfilteredApps.length != 0;
}
+
+ public boolean hasTask(int taskId) {
+ for (RemoteAnimationTargetCompat target : unfilteredApps) {
+ if (target.taskId == taskId) {
+ return true;
+ }
+ }
+ return false;
+ }
}
diff --git a/quickstep/src/com/android/quickstep/SwipeUpAnimationLogic.java b/quickstep/src/com/android/quickstep/SwipeUpAnimationLogic.java
index 8f7ec3b..4bb1bb5 100644
--- a/quickstep/src/com/android/quickstep/SwipeUpAnimationLogic.java
+++ b/quickstep/src/com/android/quickstep/SwipeUpAnimationLogic.java
@@ -79,7 +79,7 @@
mTaskViewSimulator = new TaskViewSimulator(context, gestureState.getActivityInterface());
mTransformParams = transformParams;
- mTaskViewSimulator.setLayoutRotation(
+ mTaskViewSimulator.getOrientationState().update(
mDeviceState.getRotationTouchHelper().getCurrentActiveRotation(),
mDeviceState.getRotationTouchHelper().getDisplayRotation());
mTaskViewSimulator.setDrawsBelowRecents(true);
diff --git a/quickstep/src/com/android/quickstep/TaskUtils.java b/quickstep/src/com/android/quickstep/TaskUtils.java
index 04b488d..c9db153 100644
--- a/quickstep/src/com/android/quickstep/TaskUtils.java
+++ b/quickstep/src/com/android/quickstep/TaskUtils.java
@@ -16,6 +16,8 @@
package com.android.quickstep;
+import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
+
import android.content.ComponentName;
import android.content.Context;
import android.content.pm.ApplicationInfo;
@@ -27,6 +29,7 @@
import com.android.launcher3.util.ComponentKey;
import com.android.launcher3.util.PackageManagerHelper;
import com.android.systemui.shared.recents.model.Task;
+import com.android.systemui.shared.system.ActivityManagerWrapper;
import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
import java.util.List;
@@ -86,4 +89,12 @@
}
return false;
}
+
+ /**
+ * Requests that the system close any open system windows (including other SystemUI).
+ */
+ public static void closeSystemWindowsAsync(String reason) {
+ UI_HELPER_EXECUTOR.execute(
+ () -> ActivityManagerWrapper.getInstance().closeSystemWindows(reason));
+ }
}
diff --git a/quickstep/src/com/android/quickstep/TaskViewUtils.java b/quickstep/src/com/android/quickstep/TaskViewUtils.java
index ed761cf..2aed76a 100644
--- a/quickstep/src/com/android/quickstep/TaskViewUtils.java
+++ b/quickstep/src/com/android/quickstep/TaskViewUtils.java
@@ -179,16 +179,17 @@
Context context = v.getContext();
DeviceProfile dp = BaseActivity.fromContext(context).getDeviceProfile();
- // RecentsView never updates the display rotation until swipe-up so the value may be stale.
- // Use the display value instead.
- int displayRotation = DisplayController.getDefaultDisplay(context).getInfo().rotation;
-
TaskViewSimulator topMostSimulator = null;
if (tsv == null && targets.apps.length > 0) {
tsv = new TaskViewSimulator(context, recentsView.getSizeStrategy());
tsv.setDp(dp);
- tsv.setLayoutRotation(displayRotation, displayRotation);
+
+ // RecentsView never updates the display rotation until swipe-up so the value may
+ // be stale. Use the display value instead.
+ int displayRotation = DisplayController.getDefaultDisplay(context).getInfo().rotation;
+ tsv.getOrientationState().update(displayRotation, displayRotation);
+
tsv.setPreview(targets.apps[targets.apps.length - 1]);
tsv.fullScreenProgress.value = 0;
tsv.recentsViewScale.value = 1;
diff --git a/quickstep/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java b/quickstep/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java
index 82f489f..f2f9fb7 100644
--- a/quickstep/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java
+++ b/quickstep/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java
@@ -63,6 +63,7 @@
import com.android.quickstep.RecentsAnimationDeviceState;
import com.android.quickstep.RotationTouchHelper;
import com.android.quickstep.TaskAnimationManager;
+import com.android.quickstep.TaskUtils;
import com.android.quickstep.util.ActiveGestureLog;
import com.android.quickstep.util.CachedEventDispatcher;
import com.android.quickstep.util.MotionPauseDetector;
@@ -362,8 +363,7 @@
mInputEventReceiver.setBatchingEnabled(true);
mActivityInterface.closeOverlay();
- ActivityManagerWrapper.getInstance().closeSystemWindows(
- CLOSE_SYSTEM_WINDOWS_REASON_RECENTS);
+ TaskUtils.closeSystemWindowsAsync(CLOSE_SYSTEM_WINDOWS_REASON_RECENTS);
// Notify the handler that the gesture has actually started
mInteractionHandler.onGestureStarted(isLikelyToStartNewTask);
diff --git a/quickstep/src/com/android/quickstep/inputconsumers/OverviewInputConsumer.java b/quickstep/src/com/android/quickstep/inputconsumers/OverviewInputConsumer.java
index 32b1c58..f9c52f9 100644
--- a/quickstep/src/com/android/quickstep/inputconsumers/OverviewInputConsumer.java
+++ b/quickstep/src/com/android/quickstep/inputconsumers/OverviewInputConsumer.java
@@ -32,8 +32,8 @@
import com.android.quickstep.BaseActivityInterface;
import com.android.quickstep.GestureState;
import com.android.quickstep.InputConsumer;
+import com.android.quickstep.TaskUtils;
import com.android.quickstep.util.ActiveGestureLog;
-import com.android.systemui.shared.system.ActivityManagerWrapper;
import com.android.systemui.shared.system.InputMonitorCompat;
/**
@@ -91,8 +91,7 @@
mTargetHandledTouch = true;
if (!mStartingInActivityBounds) {
mActivityInterface.closeOverlay();
- ActivityManagerWrapper.getInstance()
- .closeSystemWindows(CLOSE_SYSTEM_WINDOWS_REASON_RECENTS);
+ TaskUtils.closeSystemWindowsAsync(CLOSE_SYSTEM_WINDOWS_REASON_RECENTS);
ActiveGestureLog.INSTANCE.addLog("startQuickstep");
}
if (mInputMonitor != null) {
diff --git a/quickstep/src/com/android/quickstep/util/RecentsOrientedState.java b/quickstep/src/com/android/quickstep/util/RecentsOrientedState.java
index bb84380..e273aeb 100644
--- a/quickstep/src/com/android/quickstep/util/RecentsOrientedState.java
+++ b/quickstep/src/com/android/quickstep/util/RecentsOrientedState.java
@@ -72,7 +72,6 @@
private static final String TAG = "RecentsOrientedState";
private static final boolean DEBUG = false;
- private static final String DELIMITER_DOT = "\\.";
private ContentObserver mSystemAutoRotateObserver =
newContentObserver(new Handler(), t -> updateAutoRotateSetting());
@@ -129,6 +128,9 @@
private int mFlags;
private int mPreviousRotation = ROTATION_0;
+ // Combined int which encodes the full state.
+ private int mStateId = 0;
+
/**
* @param rotationChangeListener Callback for receiving rotation events when rotation watcher
* is enabled
@@ -169,7 +171,7 @@
*/
public boolean setRecentsRotation(@SurfaceRotation int recentsRotation) {
mRecentsRotation = recentsRotation;
- return update(mTouchRotation, mDisplayRotation);
+ return updateHandler();
}
/**
@@ -183,8 +185,7 @@
* Sets if the swipe up gesture is currently running or not
*/
public boolean setGestureActive(boolean isGestureActive) {
- setFlag(FLAG_SWIPE_UP_NOT_RUNNING, !isGestureActive);
- return update(mTouchRotation, mDisplayRotation);
+ return setFlag(FLAG_SWIPE_UP_NOT_RUNNING, !isGestureActive);
}
/**
@@ -201,14 +202,13 @@
mDisplayRotation = displayRotation;
mTouchRotation = touchRotation;
mPreviousRotation = touchRotation;
+ return updateHandler();
+ }
- PagedOrientationHandler oldHandler = mOrientationHandler;
+ private boolean updateHandler() {
if (mRecentsActivityRotation == mTouchRotation
|| (canRecentsActivityRotate() && (mFlags & FLAG_SWIPE_UP_NOT_RUNNING) != 0)) {
mOrientationHandler = PagedOrientationHandler.PORTRAIT;
- if (DEBUG) {
- Log.d(TAG, "current RecentsOrientedState: " + this);
- }
} else if (mTouchRotation == ROTATION_90) {
mOrientationHandler = PagedOrientationHandler.LANDSCAPE;
} else if (mTouchRotation == ROTATION_270) {
@@ -219,19 +219,26 @@
if (DEBUG) {
Log.d(TAG, "current RecentsOrientedState: " + this);
}
- return oldHandler != mOrientationHandler;
+
+ int oldStateId = mStateId;
+ // Each SurfaceRotation value takes two bits
+ mStateId = (((((mFlags << 2)
+ | mDisplayRotation) << 2)
+ | mTouchRotation) << 3)
+ | (mRecentsRotation < 0 ? 7 : mRecentsRotation);
+ return mStateId != oldStateId;
}
@SurfaceRotation
private int inferRecentsActivityRotation(@SurfaceRotation int displayRotation) {
if (isRecentsActivityRotationAllowed()) {
- return mRecentsRotation < ROTATION_0 ? displayRotation : mRecentsRotation;
+ return mRecentsRotation < 0 ? displayRotation : mRecentsRotation;
} else {
return ROTATION_0;
}
}
- private void setFlag(int mask, boolean enabled) {
+ private boolean setFlag(int mask, boolean enabled) {
boolean wasRotationEnabled = !TestProtocol.sDisableSensorRotation
&& (mFlags & VALUE_ROTATION_WATCHER_ENABLED) == VALUE_ROTATION_WATCHER_ENABLED
&& !canRecentsActivityRotate();
@@ -253,6 +260,7 @@
}
});
}
+ return updateHandler();
}
@Override
@@ -327,6 +335,13 @@
return mRecentsActivityRotation;
}
+ /**
+ * Returns an id that can be used to tracking internal changes
+ */
+ public int getStateId() {
+ return mStateId;
+ }
+
public boolean isMultipleOrientationSupportedByDevice() {
return (mFlags & MASK_MULTIPLE_ORIENTATION_SUPPORTED_BY_DEVICE)
== MASK_MULTIPLE_ORIENTATION_SUPPORTED_BY_DEVICE;
@@ -509,14 +524,15 @@
public String toString() {
boolean systemRotationOn = (mFlags & FLAG_SYSTEM_ROTATION_ALLOWED) != 0;
return "["
- + "this=" + extractObjectNameAndAddress(super.toString())
- + " mOrientationHandler=" +
- extractObjectNameAndAddress(mOrientationHandler.toString())
+ + "this=" + nameAndAddress(this)
+ + " mOrientationHandler=" + nameAndAddress(mOrientationHandler)
+ " mDisplayRotation=" + mDisplayRotation
+ " mTouchRotation=" + mTouchRotation
+ " mRecentsActivityRotation=" + mRecentsActivityRotation
+ + " mRecentsRotation=" + mRecentsRotation
+ " isRecentsActivityRotationAllowed=" + isRecentsActivityRotationAllowed()
+ " mSystemRotation=" + systemRotationOn
+ + " mStateId=" + mStateId
+ " mFlags=" + mFlags
+ "]";
}
@@ -533,13 +549,7 @@
: idp.portraitProfile;
}
- /**
- * String conversion for only the helpful parts of {@link Object#toString()} method
- * @param stringToExtract "foo.bar.baz.MyObject@1234"
- * @return "MyObject@1234"
- */
- private static String extractObjectNameAndAddress(String stringToExtract) {
- int index = stringToExtract.lastIndexOf(DELIMITER_DOT);
- return index >= 0 ? stringToExtract.substring(index) : "";
+ private static String nameAndAddress(Object obj) {
+ return obj.getClass().getSimpleName() + "@" + obj.hashCode();
}
}
diff --git a/quickstep/src/com/android/quickstep/util/TaskViewSimulator.java b/quickstep/src/com/android/quickstep/util/TaskViewSimulator.java
index 61ba411..2f4bb8e 100644
--- a/quickstep/src/com/android/quickstep/util/TaskViewSimulator.java
+++ b/quickstep/src/com/android/quickstep/util/TaskViewSimulator.java
@@ -23,7 +23,6 @@
import android.animation.TimeInterpolator;
import android.content.Context;
-import android.content.res.Configuration;
import android.graphics.Matrix;
import android.graphics.Point;
import android.graphics.PointF;
@@ -31,6 +30,8 @@
import android.graphics.RectF;
import android.util.IntProperty;
+import androidx.annotation.NonNull;
+
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.Utilities;
import com.android.launcher3.anim.PendingAnimation;
@@ -67,10 +68,12 @@
private final RectF mTempRectF = new RectF();
private final float[] mTempPoint = new float[2];
- private final RecentsOrientedState mOrientationState;
private final Context mContext;
private final BaseActivityInterface mSizeStrategy;
+ @NonNull
+ private RecentsOrientedState mOrientationState;
+
private final Rect mTaskRect = new Rect();
private boolean mDrawsBelowRecents;
private final PointF mPivot = new PointF();
@@ -100,6 +103,7 @@
// Cached calculations
private boolean mLayoutValid = false;
private boolean mScrollValid = false;
+ private int mOrientationStateId;
public TaskViewSimulator(Context context, BaseActivityInterface sizeStrategy) {
mContext = context;
@@ -107,8 +111,8 @@
mOrientationState = new RecentsOrientedState(context, sizeStrategy, i -> { });
mOrientationState.setGestureActive(true);
-
mCurrentFullscreenParams = new FullscreenDrawParams(context);
+ mOrientationStateId = mOrientationState.getStateId();
}
/**
@@ -116,23 +120,14 @@
*/
public void setDp(DeviceProfile dp) {
mDp = dp;
- mOrientationState.setMultiWindowMode(mDp.isMultiWindowMode);
mLayoutValid = false;
}
/**
- * @see com.android.quickstep.views.RecentsView#setLayoutRotation(int, int)
+ * Sets the orientation state used for this animation
*/
- public void setLayoutRotation(int touchRotation, int displayRotation) {
- mOrientationState.update(touchRotation, displayRotation);
- mLayoutValid = false;
- }
-
- /**
- * @see com.android.quickstep.views.RecentsView#onConfigurationChanged(Configuration)
- */
- public void setRecentsRotation(int recentsRotation) {
- mOrientationState.setRecentsRotation(recentsRotation);
+ public void setOrientationState(@NonNull RecentsOrientedState orientationState) {
+ mOrientationState = orientationState;
mLayoutValid = false;
}
@@ -251,8 +246,9 @@
if (mDp == null || mThumbnailPosition.isEmpty()) {
return;
}
- if (!mLayoutValid) {
+ if (!mLayoutValid || mOrientationStateId != mOrientationState.getStateId()) {
mLayoutValid = true;
+ mOrientationStateId = mOrientationState.getStateId();
getFullScreenScale();
mThumbnailData.rotation = mOrientationState.getDisplayRotation();
diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java
index 264a182..f281296 100644
--- a/quickstep/src/com/android/quickstep/views/RecentsView.java
+++ b/quickstep/src/com/android/quickstep/views/RecentsView.java
@@ -22,6 +22,7 @@
import static com.android.launcher3.BaseActivity.STATE_HANDLER_INVISIBILITY_FLAGS;
import static com.android.launcher3.InvariantDeviceProfile.CHANGE_FLAG_ICON_PARAMS;
+import static com.android.launcher3.LauncherAnimUtils.SUCCESS_TRANSITION_PROGRESS;
import static com.android.launcher3.LauncherAnimUtils.VIEW_ALPHA;
import static com.android.launcher3.LauncherState.BACKGROUND_APP;
import static com.android.launcher3.LauncherState.OVERVIEW_MODAL_TASK;
@@ -39,7 +40,6 @@
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TASK_DISMISS_SWIPE_UP;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TASK_LAUNCH_SWIPE_DOWN;
import static com.android.launcher3.statehandlers.DepthController.DEPTH;
-import static com.android.launcher3.uioverrides.touchcontrollers.TaskViewTouchController.SUCCESS_TRANSITION_PROGRESS;
import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
import static com.android.launcher3.util.SystemUiController.UI_STATE_OVERVIEW;
import static com.android.quickstep.TaskUtils.checkCurrentOrManagedUserId;
@@ -89,6 +89,7 @@
import androidx.annotation.Nullable;
import com.android.launcher3.BaseActivity;
+import com.android.launcher3.BaseActivity.MultiWindowModeChangedListener;
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.Insettable;
import com.android.launcher3.InvariantDeviceProfile;
@@ -99,7 +100,6 @@
import com.android.launcher3.anim.AnimationSuccessListener;
import com.android.launcher3.anim.AnimatorPlaybackController;
import com.android.launcher3.anim.PendingAnimation;
-import com.android.launcher3.anim.PendingAnimation.EndState;
import com.android.launcher3.anim.SpringProperty;
import com.android.launcher3.compat.AccessibilityManagerCompat;
import com.android.launcher3.config.FeatureFlags;
@@ -107,7 +107,6 @@
import com.android.launcher3.statemanager.StatefulActivity;
import com.android.launcher3.touch.PagedOrientationHandler;
import com.android.launcher3.touch.PagedOrientationHandler.CurveProperties;
-import com.android.launcher3.util.ComponentKey;
import com.android.launcher3.util.DynamicResource;
import com.android.launcher3.util.MultiValueAlpha;
import com.android.launcher3.util.OverScroller;
@@ -124,7 +123,6 @@
import com.android.quickstep.SystemUiProxy;
import com.android.quickstep.TaskOverlayFactory;
import com.android.quickstep.TaskThumbnailCache;
-import com.android.quickstep.TaskUtils;
import com.android.quickstep.ViewUtils;
import com.android.quickstep.util.LayoutUtils;
import com.android.quickstep.util.RecentsOrientedState;
@@ -242,7 +240,7 @@
}
};
- protected RecentsOrientedState mOrientationState;
+ protected final RecentsOrientedState mOrientationState;
protected final BaseActivityInterface mSizeStrategy;
protected RecentsAnimationController mRecentsAnimationController;
protected SurfaceTransactionApplier mSyncTransactionApplier;
@@ -411,17 +409,18 @@
private int mTaskViewStartIndex = 0;
private OverviewActionsView mActionsView;
- private BaseActivity.MultiWindowModeChangedListener mMultiWindowModeChangedListener =
- (inMultiWindowMode) -> {
- if (mOrientationState != null) {
+ private MultiWindowModeChangedListener mMultiWindowModeChangedListener =
+ new MultiWindowModeChangedListener() {
+ @Override
+ public void onMultiWindowModeChanged(boolean inMultiWindowMode) {
mOrientationState.setMultiWindowMode(inMultiWindowMode);
setLayoutRotation(mOrientationState.getTouchRotation(),
mOrientationState.getDisplayRotation());
updateChildTaskOrientations();
- }
- if (!inMultiWindowMode && mOverviewStateEnabled) {
- // TODO: Re-enable layout transitions for addition of the unpinned task
- reloadIfNeeded();
+ if (!inMultiWindowMode && mOverviewStateEnabled) {
+ // TODO: Re-enable layout transitions for addition of the unpinned task
+ reloadIfNeeded();
+ }
}
};
@@ -479,9 +478,7 @@
mLiveTileTaskViewSimulator = new TaskViewSimulator(getContext(), getSizeStrategy());
mLiveTileTaskViewSimulator.recentsViewScale.value = 1;
- mLiveTileTaskViewSimulator.setLayoutRotation(getPagedViewOrientedState().getTouchRotation(),
- getPagedViewOrientedState().getDisplayRotation());
- mLiveTileTaskViewSimulator.setRecentsRotation(rotation);
+ mLiveTileTaskViewSimulator.setOrientationState(mOrientationState);
mLiveTileTaskViewSimulator.setDrawsBelowRecents(true);
}
@@ -774,7 +771,7 @@
protected void applyLoadPlan(ArrayList<Task> tasks) {
if (mPendingAnimation != null) {
- mPendingAnimation.addEndListener((endState) -> applyLoadPlan(tasks));
+ mPendingAnimation.addEndListener(success -> applyLoadPlan(tasks));
return;
}
@@ -1466,19 +1463,10 @@
verticalFactor * secondaryTaskDimension).setDuration(duration), LINEAR, sp);
}
- private void removeTask(TaskView taskView, int index, EndState endState) {
- if (taskView.getTask() != null) {
- ActivityManagerWrapper.getInstance().removeTask(taskView.getTask().key.id);
- ComponentKey compKey = TaskUtils.getLaunchComponentKeyForTask(taskView.getTask().key);
- mActivity.getStatsLogManager().logger().withItemInfo(taskView.getItemInfo())
- .log(LAUNCHER_TASK_DISMISS_SWIPE_UP);
- }
- }
-
public PendingAnimation createTaskDismissAnimation(TaskView taskView, boolean animateTaskView,
boolean shouldRemoveTask, long duration) {
if (mPendingAnimation != null) {
- mPendingAnimation.finish(false);
+ mPendingAnimation.createPlaybackController().dispatchOnCancel();
}
PendingAnimation anim = new PendingAnimation(duration);
@@ -1561,22 +1549,27 @@
}
mPendingAnimation = anim;
- mPendingAnimation.addEndListener(new Consumer<EndState>() {
+ mPendingAnimation.addEndListener(new Consumer<Boolean>() {
@Override
- public void accept(EndState endState) {
- if (ENABLE_QUICKSTEP_LIVE_TILE.get() &&
- taskView.isRunningTask() && endState.isSuccess) {
- finishRecentsAnimation(true /* toHome */, () -> onEnd(endState));
+ public void accept(Boolean success) {
+ if (ENABLE_QUICKSTEP_LIVE_TILE.get() && taskView.isRunningTask() && success) {
+ finishRecentsAnimation(true /* toHome */, () -> onEnd(success));
} else {
- onEnd(endState);
+ onEnd(success);
}
}
@SuppressWarnings("WrongCall")
- private void onEnd(EndState endState) {
- if (endState.isSuccess) {
+ private void onEnd(boolean success) {
+ if (success) {
if (shouldRemoveTask) {
- removeTask(taskView, draggedIndex, endState);
+ if (taskView.getTask() != null) {
+ UI_HELPER_EXECUTOR.execute(() -> ActivityManagerWrapper.getInstance()
+ .removeTask(taskView.getTask().key.id));
+ mActivity.getStatsLogManager().logger()
+ .withItemInfo(taskView.getItemInfo())
+ .log(LAUNCHER_TASK_DISMISS_SWIPE_UP);
+ }
}
int pageToSnapTo = mCurrentPage;
@@ -1615,10 +1608,11 @@
}
mPendingAnimation = anim;
- mPendingAnimation.addEndListener((endState) -> {
- if (endState.isSuccess) {
+ mPendingAnimation.addEndListener(isSuccess -> {
+ if (isSuccess) {
// Remove all the task views now
- ActivityManagerWrapper.getInstance().removeAllRecentTasks();
+ UI_HELPER_EXECUTOR.execute(
+ ActivityManagerWrapper.getInstance()::removeAllRecentTasks);
removeTasksViewsAndClearAllButton();
startHome();
}
@@ -1643,7 +1637,6 @@
protected void runDismissAnimation(PendingAnimation pendingAnim) {
AnimatorPlaybackController controller = pendingAnim.createPlaybackController();
controller.dispatchOnStart();
- controller.setEndAction(() -> pendingAnim.finish(true));
controller.getAnimationPlayer().setInterpolator(FAST_OUT_SLOW_IN);
controller.start();
}
@@ -1770,7 +1763,7 @@
if (mOrientationState.setRecentsRotation(rotation)) {
updateOrientationHandler();
}
- mLiveTileTaskViewSimulator.setRecentsRotation(rotation);
+
// If overview is in modal state when rotate, reset it to overview state without running
// animation.
if (mActivity.isInState(OVERVIEW_MODAL_TASK)) {
@@ -1805,8 +1798,6 @@
requestLayout();
// Reapply the current page to update page scrolls.
setCurrentPage(mCurrentPage);
- mLiveTileTaskViewSimulator.setLayoutRotation(getPagedViewOrientedState().getTouchRotation(),
- getPagedViewOrientedState().getDisplayRotation());
}
public RecentsOrientedState getPagedViewOrientedState() {
@@ -2187,8 +2178,8 @@
mLiveTileTaskViewSimulator.addOverviewToAppAnim(mPendingAnimation, interpolator);
mPendingAnimation.addOnFrameCallback(this::redrawLiveTile);
}
- mPendingAnimation.addEndListener((endState) -> {
- if (endState.isSuccess) {
+ mPendingAnimation.addEndListener(isSuccess -> {
+ if (isSuccess) {
Consumer<Boolean> onLaunchResult = (result) -> {
onTaskLaunchAnimationEnd(result);
if (!result) {
diff --git a/quickstep/src/com/android/quickstep/views/TaskView.java b/quickstep/src/com/android/quickstep/views/TaskView.java
index 23da783..3230348 100644
--- a/quickstep/src/com/android/quickstep/views/TaskView.java
+++ b/quickstep/src/com/android/quickstep/views/TaskView.java
@@ -71,7 +71,6 @@
import com.android.launcher3.Utilities;
import com.android.launcher3.anim.AnimatorPlaybackController;
import com.android.launcher3.anim.Interpolators;
-import com.android.launcher3.anim.PendingAnimation;
import com.android.launcher3.model.data.WorkspaceItemInfo;
import com.android.launcher3.popup.SystemShortcut;
import com.android.launcher3.statemanager.StatefulActivity;
@@ -373,11 +372,9 @@
}
public AnimatorPlaybackController createLaunchAnimationForRunningTask() {
- final PendingAnimation pendingAnimation = getRecentsView().createTaskLaunchAnimation(
- this, RECENTS_LAUNCH_DURATION, TOUCH_RESPONSE_INTERPOLATOR);
- AnimatorPlaybackController currentAnimation = pendingAnimation.createPlaybackController();
- currentAnimation.setEndAction(() -> pendingAnimation.finish(true));
- return currentAnimation;
+ return getRecentsView().createTaskLaunchAnimation(
+ this, RECENTS_LAUNCH_DURATION, TOUCH_RESPONSE_INTERPOLATOR)
+ .createPlaybackController();
}
public void launchTask(boolean animate) {
diff --git a/res/layout/search_result_hero_app.xml b/res/layout/search_result_hero_app.xml
deleted file mode 100644
index bd0e42b..0000000
--- a/res/layout/search_result_hero_app.xml
+++ /dev/null
@@ -1,74 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- 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.
--->
-<com.android.launcher3.views.HeroSearchResultView
- xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:launcher="http://schemas.android.com/apk/res-auto"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:orientation="horizontal"
- android:gravity="center_vertical"
- android:padding="@dimen/dynamic_grid_edge_margin">
-
- <FrameLayout
- android:layout_width="0dp"
- android:layout_height="match_parent"
- android:layout_gravity="center_vertical"
- android:layout_weight="1">
- <com.android.launcher3.BubbleTextView
- android:id="@+id/bubble_text"
- style="@style/BaseIcon"
- android:drawablePadding="@dimen/dynamic_grid_icon_drawable_padding"
- android:gravity="start|center_vertical"
- android:textAlignment="viewStart"
- android:textColor="?android:attr/textColorPrimary"
- android:textSize="16sp"
- android:layout_height="wrap_content"
- launcher:iconDisplay="hero_app"
- launcher:layoutHorizontal="true"/>
-
- <View
- android:id="@+id/icon"
- android:layout_width="@dimen/deep_shortcut_icon_size"
- android:layout_height="@dimen/deep_shortcut_icon_size"
- android:layout_gravity="start|center_vertical"
- android:background="@drawable/ic_deepshortcut_placeholder"/>
- </FrameLayout>
-
- <com.android.launcher3.BubbleTextView
- android:id="@+id/shortcut_0"
- style="@style/BaseIcon"
- android:layout_width="@dimen/deep_shortcut_icon_size"
- android:layout_height="match_parent"
- android:gravity="start|center_vertical"
- android:textAlignment="center"
- launcher:iconDisplay="shortcut_popup"
- android:textSize="12sp"
- launcher:iconSizeOverride="@dimen/deep_shortcut_icon_size"
- launcher:layoutHorizontal="false"/>
-
- <com.android.launcher3.BubbleTextView
- android:id="@+id/shortcut_1"
- style="@style/BaseIcon"
- android:layout_width="@dimen/deep_shortcut_icon_size"
- android:layout_height="match_parent"
- android:gravity="start|center_vertical"
- android:textAlignment="center"
- launcher:iconDisplay="shortcut_popup"
- android:textSize="12sp"
- launcher:iconSizeOverride="@dimen/deep_shortcut_icon_size"
- launcher:layoutHorizontal="false"/>
-
-</com.android.launcher3.views.HeroSearchResultView>
\ No newline at end of file
diff --git a/res/layout/search_result_icon_row.xml b/res/layout/search_result_icon_row.xml
index ef3c8b2..81c23e4 100644
--- a/res/layout/search_result_icon_row.xml
+++ b/res/layout/search_result_icon_row.xml
@@ -1,4 +1,4 @@
-<?xml version="1.0" encoding="utf-8"?><!-- Copyright (C) 2020 The Android Open Source Projectza
+<?xml version="1.0" encoding="utf-8"?><!-- 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.
@@ -14,18 +14,63 @@
-->
<com.android.launcher3.views.SearchResultIconRow xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:launcher="http://schemas.android.com/apk/res-auto"
- style="@style/BaseIcon"
+ android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:orientation="horizontal"
- android:drawablePadding="@dimen/dynamic_grid_icon_drawable_padding"
- android:gravity="start|center_vertical"
- android:textAlignment="viewStart"
- android:textColor="?android:attr/textColorPrimary"
- android:textSize="16sp"
- android:padding="@dimen/dynamic_grid_edge_margin"
- launcher:iconDisplay="hero_app"
- launcher:layoutHorizontal="true"
- >
+ android:padding="@dimen/dynamic_grid_edge_margin">
+
+ <com.android.launcher3.views.SearchResultIcon
+ android:layout_width="wrap_content"
+ android:id="@+id/icon"
+ launcher:iconDisplay="hero_app"
+ android:layout_height="wrap_content" />
+
+ <LinearLayout
+ android:layout_width="0dp"
+ android:layout_weight="1"
+ android:layout_height="wrap_content"
+ android:padding="@dimen/dynamic_grid_edge_margin"
+ android:orientation="vertical"
+ android:layout_gravity="center_vertical">
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:id="@id/title"
+ android:layout_height="wrap_content"
+ android:gravity="start|center_vertical"
+ android:maxLines="1"
+ android:textAlignment="viewStart"
+ android:textColor="?android:attr/textColorPrimary"
+ android:textSize="@dimen/search_hero_title_size" />
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:id="@+id/desc"
+ android:maxLines="1"
+ android:textColor="?android:attr/textColorTertiary"
+ android:textSize="@dimen/search_hero_subtitle_size"
+ android:layout_height="wrap_content" />
+ </LinearLayout>
+
+ <com.android.launcher3.BubbleTextView
+ android:id="@+id/shortcut_0"
+ style="@style/BaseIcon"
+ android:layout_width="@dimen/deep_shortcut_icon_size"
+ android:layout_height="match_parent"
+ android:gravity="start|center_vertical"
+ launcher:iconDisplay="shortcut_popup"
+ android:textSize="@dimen/search_hero_subtitle_size"
+ launcher:iconSizeOverride="@dimen/deep_shortcut_icon_size"
+ launcher:layoutHorizontal="false" />
+
+ <com.android.launcher3.BubbleTextView
+ android:id="@+id/shortcut_1"
+ style="@style/BaseIcon"
+ android:layout_width="@dimen/deep_shortcut_icon_size"
+ android:layout_height="match_parent"
+ launcher:iconDisplay="shortcut_popup"
+ android:textSize="@dimen/search_hero_inline_button_size"
+ launcher:iconSizeOverride="@dimen/deep_shortcut_icon_size"
+ launcher:layoutHorizontal="false" />
</com.android.launcher3.views.SearchResultIconRow>
\ No newline at end of file
diff --git a/res/layout/search_result_people_item.xml b/res/layout/search_result_people_item.xml
index a603941..7526f6f 100644
--- a/res/layout/search_result_people_item.xml
+++ b/res/layout/search_result_people_item.xml
@@ -29,6 +29,7 @@
android:layout_width="0dp"
android:textColor="?android:attr/textColorPrimary"
android:id="@+id/title"
+ android:textSize="@dimen/search_hero_title_size"
android:layout_height="wrap_content"
android:layout_weight="1" />
diff --git a/res/layout/search_result_settings_row.xml b/res/layout/search_result_settings_row.xml
index 19daf34..22c08bf 100644
--- a/res/layout/search_result_settings_row.xml
+++ b/res/layout/search_result_settings_row.xml
@@ -18,40 +18,43 @@
android:background="?android:attr/selectableItemBackground"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:orientation="vertical"
+ android:orientation="horizontal"
android:gravity="center_vertical"
- android:padding="4dp"
- android:minHeight="48dp"
- android:textColor="?android:attr/textColorPrimary"
- android:textSize="14sp">
+ android:padding="@dimen/dynamic_grid_cell_padding_x"
+ android:textColor="?android:attr/textColorPrimary">
- <TextView
- android:id="@+id/title"
- style="@style/TextTitle"
- android:layout_width="wrap_content"
+ <View
+ android:layout_width="@dimen/search_settings_icon_size"
+ android:src="@drawable/ic_setting"
+ android:id="@+id/icon"
+ android:layout_height="@dimen/search_settings_icon_size" />
+
+ <LinearLayout
+ android:layout_width="0dp"
+ android:orientation="vertical"
+ android:paddingRight="@dimen/dynamic_grid_cell_padding_x"
+ android:paddingLeft="@dimen/dynamic_grid_cell_padding_x"
android:layout_height="wrap_content"
- android:layout_marginBottom="4dp"
- android:textColor="?android:attr/textColorPrimary"
- android:textSize="16sp" />
-
- <TextView
- android:id="@+id/description"
- style="@style/TextTitle"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:visibility="gone"
- android:textColor="?android:attr/textColorPrimary"
- android:textSize="14sp" />
-
- <TextView
- android:id="@+id/breadcrumbs"
- style="@style/TextTitle"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:visibility="gone"
- android:alpha=".7"
- android:textColor="?android:attr/textColorSecondary"
- android:textSize="14sp" />
+ android:layout_weight="1">
+ <TextView
+ android:id="@+id/title"
+ style="@style/TextTitle"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginBottom="@dimen/search_line_spacing"
+ android:maxLines="1"
+ android:textColor="?android:attr/textColorPrimary"
+ android:textSize="@dimen/search_hero_title_size" />
+
+ <TextView
+ android:id="@+id/breadcrumbs"
+ style="@style/TextTitle"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:visibility="gone"
+ android:textColor="?android:attr/textColorSecondary"
+ android:textSize="@dimen/search_hero_subtitle_size" />
+ </LinearLayout>
</com.android.launcher3.views.SearchSettingsRowView>
\ No newline at end of file
diff --git a/res/layout/search_result_slice.xml b/res/layout/search_result_slice.xml
index ea1d49a..24d75e9 100644
--- a/res/layout/search_result_slice.xml
+++ b/res/layout/search_result_slice.xml
@@ -1,5 +1,4 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2020 The Android Open Source Project
+<?xml version="1.0" encoding="utf-8"?><!-- 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.
@@ -13,7 +12,29 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<androidx.slice.widget.SliceView xmlns:android="http://schemas.android.com/apk/res/android"
+<com.android.launcher3.views.SearchResultSettingsSlice xmlns:android="http://schemas.android.com/apk/res/android"
+ android:paddingHorizontal="@dimen/dynamic_grid_cell_padding_x"
android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:paddingHorizontal="4dp" />
\ No newline at end of file
+ android:layout_height="wrap_content">
+
+ <FrameLayout
+ android:layout_width="wrap_content"
+ android:paddingTop="@dimen/search_settings_icon_vertical_offset"
+ android:layout_height="wrap_content">
+
+ <View
+ android:layout_width="@dimen/search_settings_icon_size"
+ android:src="@drawable/ic_setting"
+ android:id="@+id/icon"
+ android:layout_height="@dimen/search_settings_icon_size" />
+ </FrameLayout>
+
+ <androidx.slice.widget.SliceView
+ android:id="@+id/slice"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:layout_marginStart="@dimen/dynamic_grid_cell_padding_x"
+ android:layout_width="0dp" />
+
+</com.android.launcher3.views.SearchResultSettingsSlice>
+
diff --git a/res/layout/search_result_suggest.xml b/res/layout/search_result_suggest.xml
index 1d8c803..01e25d5 100644
--- a/res/layout/search_result_suggest.xml
+++ b/res/layout/search_result_suggest.xml
@@ -12,7 +12,7 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<com.android.launcher3.views.SearchResultIconRow xmlns:android="http://schemas.android.com/apk/res/android"
+<com.android.launcher3.views.SearchResultSuggestion xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:launcher="http://schemas.android.com/apk/res-auto"
style="@style/BaseIcon"
android:layout_width="match_parent"
@@ -26,10 +26,9 @@
launcher:iconDisplay="hero_app"
android:drawableTint="?android:attr/textColorPrimary"
launcher:customIcon="@drawable/ic_allapps_search"
- launcher:iconSizeOverride="48dp"
+ launcher:iconSizeOverride="24dp"
launcher:matchTextInsetWithQuery="true"
launcher:layoutHorizontal="true"
- android:drawablePadding="@dimen/dynamic_grid_icon_drawable_padding"
- >
+ android:drawablePadding="@dimen/dynamic_grid_icon_drawable_padding">
-</com.android.launcher3.views.SearchResultIconRow>
\ No newline at end of file
+</com.android.launcher3.views.SearchResultSuggestion>
\ No newline at end of file
diff --git a/res/layout/search_result_widget_live.xml b/res/layout/search_result_widget_live.xml
new file mode 100644
index 0000000..0dd8a06
--- /dev/null
+++ b/res/layout/search_result_widget_live.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<com.android.launcher3.views.SearchResultWidget android:layout_height="wrap_content"
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:gravity="center"
+ android:layout_width="match_parent" />
\ No newline at end of file
diff --git a/res/values/attrs.xml b/res/values/attrs.xml
index c3ad1eb..96c30b5 100644
--- a/res/values/attrs.xml
+++ b/res/values/attrs.xml
@@ -1,5 +1,4 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
+<?xml version="1.0" encoding="utf-8"?><!--
/* Copyright 2008, The Android Open Source Project
**
** Licensed under the Apache License, Version 2.0 (the "License");
@@ -30,13 +29,13 @@
<attr name="isWorkspaceDarkText" format="boolean" />
<attr name="workspaceTextColor" format="color" />
<attr name="workspaceShadowColor" format="color" />
- <attr name="workspaceAmbientShadowColor" format="color"/>
+ <attr name="workspaceAmbientShadowColor" format="color" />
<attr name="workspaceKeyShadowColor" format="color" />
<attr name="workspaceStatusBarScrim" format="reference" />
<attr name="widgetsTheme" format="reference" />
<attr name="loadingIconColor" format="color" />
- <attr name="iconOnlyShortcutColor" format="color"/>
- <attr name="eduHalfSheetBGColor" format="color"/>
+ <attr name="iconOnlyShortcutColor" format="color" />
+ <attr name="eduHalfSheetBGColor" format="color" />
<attr name="folderDotColor" format="color" />
<attr name="folderFillColor" format="color" />
@@ -69,13 +68,12 @@
<attr name="folderDotColor" />
</declare-styleable>
- <declare-styleable name="SearchResultIconRow">
+ <declare-styleable name="SearchResultSuggestion">
<attr name="customIcon" format="reference" />
<attr name="matchTextInsetWithQuery" format="boolean" />
</declare-styleable>
-
<declare-styleable name="ShadowInfo">
<attr name="ambientShadowColor" format="color" />
<attr name="ambientShadowBlur" format="dimension" />
@@ -167,7 +165,7 @@
<attr name="android:src" />
<attr name="android:shadowColor" />
<attr name="android:elevation" />
- <attr name="darkTintColor" format="color"/>
+ <attr name="darkTintColor" format="color" />
</declare-styleable>
<declare-styleable name="RecyclerViewFastScroller">
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index f59f02f..7df3f77 100644
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -248,4 +248,12 @@
<!-- Onboarding bottomsheet related -->
<dimen name="bottom_sheet_edu_padding">24dp</dimen>
+ <!-- Search related -->
+ <dimen name="search_hero_title_size">16sp</dimen>
+ <dimen name="search_hero_subtitle_size">15sp</dimen>
+ <dimen name="search_hero_inline_button_size">12sp</dimen>
+ <dimen name="search_settings_icon_size">36dp</dimen>
+ <dimen name="search_settings_icon_vertical_offset">16dp</dimen>
+ <dimen name="search_line_spacing">4dp</dimen>
+
</resources>
diff --git a/src/com/android/launcher3/AppWidgetResizeFrame.java b/src/com/android/launcher3/AppWidgetResizeFrame.java
index 168d9c4..bc3e341 100644
--- a/src/com/android/launcher3/AppWidgetResizeFrame.java
+++ b/src/com/android/launcher3/AppWidgetResizeFrame.java
@@ -36,7 +36,7 @@
private static final Rect sTmpRect = new Rect();
// Represents the cell size on the grid in the two orientations.
- private static final MainThreadInitializedObject<Point[]> CELL_SIZE =
+ public static final MainThreadInitializedObject<Point[]> CELL_SIZE =
new MainThreadInitializedObject<>(c -> {
InvariantDeviceProfile inv = LauncherAppState.getIDP(c);
return new Point[] {inv.landscapeProfile.getCellSize(),
diff --git a/src/com/android/launcher3/BubbleTextView.java b/src/com/android/launcher3/BubbleTextView.java
index 1015a32..5cd6372 100644
--- a/src/com/android/launcher3/BubbleTextView.java
+++ b/src/com/android/launcher3/BubbleTextView.java
@@ -446,6 +446,7 @@
canvas.restoreToCount(count);
}
super.onDraw(canvas);
+ drawDotIfNecessary(canvas);
}
protected void drawFocusHighlight(Canvas canvas) {
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index 699734c..aa123f6 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -111,6 +111,7 @@
import com.android.launcher3.allapps.AllAppsStore;
import com.android.launcher3.allapps.AllAppsTransitionController;
import com.android.launcher3.allapps.DiscoveryBounce;
+import com.android.launcher3.allapps.search.LiveSearchManager;
import com.android.launcher3.anim.PropertyListBuilder;
import com.android.launcher3.compat.AccessibilityManagerCompat;
import com.android.launcher3.config.FeatureFlags;
@@ -276,6 +277,8 @@
private LifecycleRegistry mLifecycleRegistry;
+ private LiveSearchManager mLiveSearchManager;
+
@Thunk
Workspace mWorkspace;
@Thunk
@@ -389,6 +392,8 @@
mIconCache = app.getIconCache();
mAccessibilityDelegate = new LauncherAccessibilityDelegate(this);
+ mLiveSearchManager = new LiveSearchManager(this);
+
mDragController = new DragController(this);
mAllAppsController = new AllAppsTransitionController(this);
mStateManager = new StateManager<>(this, NORMAL);
@@ -492,6 +497,10 @@
return mLifecycleRegistry;
}
+ public LiveSearchManager getLiveSearchManager() {
+ return mLiveSearchManager;
+ }
+
protected LauncherOverlayManager getDefaultOverlay() {
return new LauncherOverlayManager() { };
}
@@ -1583,6 +1592,7 @@
mAppTransitionManager.unregisterRemoteAnimations();
mUserChangedCallbackCloseable.close();
mLifecycleRegistry.setCurrentState(Lifecycle.State.DESTROYED);
+ mLiveSearchManager.stop();
}
public LauncherAccessibilityDelegate getAccessibilityDelegate() {
@@ -2487,6 +2497,7 @@
@Override
public void bindAllApplications(AppInfo[] apps, int flags) {
mAppsView.getAppsStore().setApps(apps, flags);
+ PopupContainerWithArrow.dismissInvalidPopup(this);
}
/**
@@ -2518,6 +2529,7 @@
public void bindWorkspaceItemsChanged(List<WorkspaceItemInfo> updated) {
if (!updated.isEmpty()) {
mWorkspace.updateShortcuts(updated);
+ PopupContainerWithArrow.dismissInvalidPopup(this);
}
}
@@ -2542,6 +2554,7 @@
public void bindWorkspaceComponentsRemoved(final ItemInfoMatcher matcher) {
mWorkspace.removeItemsByMatcher(matcher);
mDragController.onAppsRemoved(matcher);
+ PopupContainerWithArrow.dismissInvalidPopup(this);
}
@Override
diff --git a/src/com/android/launcher3/LauncherAnimUtils.java b/src/com/android/launcher3/LauncherAnimUtils.java
index d9cf7f1..803f8d2 100644
--- a/src/com/android/launcher3/LauncherAnimUtils.java
+++ b/src/com/android/launcher3/LauncherAnimUtils.java
@@ -16,6 +16,9 @@
package com.android.launcher3;
+import android.animation.Animator;
+import android.animation.Animator.AnimatorListener;
+import android.animation.AnimatorListenerAdapter;
import android.graphics.drawable.Drawable;
import android.util.FloatProperty;
import android.util.IntProperty;
@@ -29,8 +32,8 @@
*/
public static final int SPRING_LOADED_EXIT_DELAY = 500;
- // The progress of an animation to all apps must be at least this far along to snap to all apps.
- public static final float MIN_PROGRESS_TO_ALL_APPS = 0.5f;
+ // Progress after which the transition is assumed to be a success
+ public static final float SUCCESS_TRANSITION_PROGRESS = 0.5f;
public static final IntProperty<Drawable> DRAWABLE_ALPHA =
new IntProperty<Drawable>("drawableAlpha") {
@@ -131,4 +134,23 @@
return view.getAlpha();
}
};
+
+ /**
+ * Utility method to create an {@link AnimatorListener} which executes a callback on animation
+ * cancel.
+ */
+ public static AnimatorListener newCancelListener(Runnable callback) {
+ return new AnimatorListenerAdapter() {
+
+ boolean mDispatched = false;
+
+ @Override
+ public void onAnimationCancel(Animator animation) {
+ if (!mDispatched) {
+ mDispatched = true;
+ callback.run();
+ }
+ }
+ };
+ }
}
diff --git a/src/com/android/launcher3/allapps/AllAppsGridAdapter.java b/src/com/android/launcher3/allapps/AllAppsGridAdapter.java
index f773191..d049352 100644
--- a/src/com/android/launcher3/allapps/AllAppsGridAdapter.java
+++ b/src/com/android/launcher3/allapps/AllAppsGridAdapter.java
@@ -37,7 +37,6 @@
import androidx.core.view.accessibility.AccessibilityRecordCompat;
import androidx.recyclerview.widget.GridLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
-import androidx.slice.widget.SliceView;
import com.android.launcher3.BaseDraggingActivity;
import com.android.launcher3.BubbleTextView;
@@ -47,7 +46,7 @@
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.model.data.AppInfo;
import com.android.launcher3.util.PackageManagerHelper;
-import com.android.launcher3.views.SearchSliceWrapper;
+import com.android.launcher3.views.SearchResultWidget;
import com.android.systemui.plugins.shared.SearchTarget;
import java.util.List;
@@ -75,8 +74,6 @@
public static final int VIEW_TYPE_SEARCH_CORPUS_TITLE = 1 << 5;
- public static final int VIEW_TYPE_SEARCH_HERO_APP = 1 << 6;
-
public static final int VIEW_TYPE_SEARCH_ROW_WITH_BUTTON = 1 << 7;
public static final int VIEW_TYPE_SEARCH_ROW = 1 << 8;
@@ -93,6 +90,8 @@
public static final int VIEW_TYPE_SEARCH_ICON = 1 << 14;
+ public static final int VIEW_TYPE_SEARCH_WIDGET_LIVE = 1 << 15;
+
// Common view type masks
public static final int VIEW_TYPE_MASK_DIVIDER = VIEW_TYPE_ALL_APPS_DIVIDER;
public static final int VIEW_TYPE_MASK_ICON = VIEW_TYPE_ICON | VIEW_TYPE_SEARCH_ICON;
@@ -178,7 +177,6 @@
boolean isCountedForAccessibility() {
return viewType == VIEW_TYPE_ICON
- || viewType == VIEW_TYPE_SEARCH_HERO_APP
|| viewType == VIEW_TYPE_SEARCH_ROW_WITH_BUTTON
|| viewType == VIEW_TYPE_SEARCH_SLICE
|| viewType == VIEW_TYPE_SEARCH_ROW
@@ -411,9 +409,6 @@
case VIEW_TYPE_SEARCH_CORPUS_TITLE:
return new ViewHolder(
mLayoutInflater.inflate(R.layout.search_section_title, parent, false));
- case VIEW_TYPE_SEARCH_HERO_APP:
- return new ViewHolder(mLayoutInflater.inflate(
- R.layout.search_result_hero_app, parent, false));
case VIEW_TYPE_SEARCH_ROW_WITH_BUTTON:
return new ViewHolder(mLayoutInflater.inflate(
R.layout.search_result_play_item, parent, false));
@@ -435,6 +430,9 @@
case VIEW_TYPE_SEARCH_SUGGEST:
return new ViewHolder(mLayoutInflater.inflate(
R.layout.search_result_suggest, parent, false));
+ case VIEW_TYPE_SEARCH_WIDGET_LIVE:
+ return new ViewHolder(mLayoutInflater.inflate(
+ R.layout.search_result_widget_live, parent, false));
default:
throw new RuntimeException("Unexpected view type");
}
@@ -468,23 +466,16 @@
searchView.setVisibility(View.GONE);
}
break;
- case VIEW_TYPE_SEARCH_SLICE:
- SliceView sliceView = (SliceView) holder.itemView;
- SearchAdapterItem slicePayload = (SearchAdapterItem) mApps.getAdapterItems().get(
- position);
- SearchTarget searchTarget = slicePayload.getSearchTarget();
- sliceView.setTag(new SearchSliceWrapper(mLauncher, sliceView, searchTarget));
-
- break;
case VIEW_TYPE_SEARCH_CORPUS_TITLE:
case VIEW_TYPE_SEARCH_ROW_WITH_BUTTON:
- case VIEW_TYPE_SEARCH_HERO_APP:
+ case VIEW_TYPE_SEARCH_SLICE:
case VIEW_TYPE_SEARCH_ROW:
case VIEW_TYPE_SEARCH_ICON:
case VIEW_TYPE_SEARCH_ICON_ROW:
case VIEW_TYPE_SEARCH_PEOPLE:
case VIEW_TYPE_SEARCH_THUMBNAIL:
case VIEW_TYPE_SEARCH_SUGGEST:
+ case VIEW_TYPE_SEARCH_WIDGET_LIVE:
SearchAdapterItem item =
(SearchAdapterItem) mApps.getAdapterItems().get(position);
SearchTargetHandler payloadResultView = (SearchTargetHandler) holder.itemView;
@@ -503,12 +494,8 @@
if (holder.itemView instanceof AllAppsSectionDecorator.SelfDecoratingView) {
((AllAppsSectionDecorator.SelfDecoratingView) holder.itemView).removeDecoration();
}
- if (holder.itemView instanceof SliceView) {
- SliceView sliceView = (SliceView) holder.itemView;
- if (sliceView.getTag() instanceof SearchSliceWrapper) {
- ((SearchSliceWrapper) sliceView.getTag()).destroy();
- }
- sliceView.setTag(null);
+ if (holder.itemView instanceof SearchResultWidget) {
+ ((SearchResultWidget) holder.itemView).removeListener();
}
}
diff --git a/src/com/android/launcher3/allapps/AllAppsInsetTransitionController.java b/src/com/android/launcher3/allapps/AllAppsInsetTransitionController.java
index 08d573f..93da1c0 100644
--- a/src/com/android/launcher3/allapps/AllAppsInsetTransitionController.java
+++ b/src/com/android/launcher3/allapps/AllAppsInsetTransitionController.java
@@ -15,6 +15,7 @@
*/
package com.android.launcher3.allapps;
+import android.annotation.TargetApi;
import android.graphics.Insets;
import android.os.Build;
import android.util.Log;
@@ -26,9 +27,8 @@
import android.view.animation.LinearInterpolator;
import androidx.annotation.Nullable;
-import androidx.annotation.RequiresApi;
-import androidx.core.os.BuildCompat;
+import com.android.launcher3.Utilities;
import com.android.launcher3.util.UiThreadHelper;
/**
@@ -57,7 +57,8 @@
// Only purpose of these states is to keep track of fast fling transition
enum State {
- RESET, DRAG_START_BOTTOM, FLING_END_TOP,
+ RESET, DRAG_START_BOTTOM, DRAG_START_BOTTOM_IME_CANCELLED,
+ FLING_END_TOP, FLING_END_TOP_IME_CANCELLED,
DRAG_START_TOP, FLING_END_BOTTOM
}
private State mState;
@@ -68,7 +69,7 @@
}
public void hide() {
- if (!BuildCompat.isAtLeastR()) return;
+ if (!Utilities.ATLEAST_R) return;
WindowInsets insets = mApps.getRootWindowInsets();
if (insets == null) return;
@@ -89,9 +90,9 @@
*
* @param progress value between 0..1
*/
- @RequiresApi(api = Build.VERSION_CODES.R)
+ @TargetApi(Build.VERSION_CODES.R)
public void onDragStart(float progress) {
- if (!BuildCompat.isAtLeastR()) return;
+ if (!Utilities.ATLEAST_R) return;
// Until getRootWindowInsets().isVisible(...) method returns correct value,
// only support InsetController based IME transition during swipe up and
@@ -149,13 +150,12 @@
+ " mAnimationController=" + mAnimationController);
}
if (mState == State.DRAG_START_BOTTOM) {
- mApps.getWindowInsetsController().show(WindowInsets.Type.ime());
+ mState = State.DRAG_START_BOTTOM_IME_CANCELLED;
}
mAnimationController = null;
if (controller != null) {
controller.finish(true);
}
-
}
});
}
@@ -164,7 +164,7 @@
* If IME bounds after touch sequence finishes, call finish.
*/
private boolean handleFinishOnFling(WindowInsetsAnimationController controller) {
- if (!BuildCompat.isAtLeastR()) return false;
+ if (!Utilities.ATLEAST_R) return false;
if (mState == State.FLING_END_TOP) {
controller.finish(true);
@@ -181,9 +181,9 @@
*
* @param progress value between 0..1
*/
- @RequiresApi(api = 30)
+ @TargetApi(Build.VERSION_CODES.R)
public void setProgress(float progress) {
- if (!BuildCompat.isAtLeastR()) return;
+ if (!Utilities.ATLEAST_R) return;
// progress that equals to 0 or 1 is error prone. Do not use them.
// Instead use onDragStart and onAnimationEnd
if (mAnimationController == null || progress <= 0f || progress >= 1f) return;
@@ -200,7 +200,7 @@
final int end = mShownAtDown ? mHiddenInsetBottom : mShownInsetBottom;
inset = Math.max(inset, mHiddenInsetBottom);
inset = Math.min(inset, mShownInsetBottom);
- if (DEBUG || false) {
+ if (DEBUG && false) {
Log.d(TAG, "updateInset mCurrent=" + mCurrent + " mDown="
+ mDown + " hidden=" + mHiddenInsetBottom
+ " shown=" + mShownInsetBottom
@@ -218,7 +218,7 @@
*
* @param progress value between 0..1
*/
- @RequiresApi(api = 30)
+ @TargetApi(Build.VERSION_CODES.R)
public void onAnimationEnd(float progress) {
if (DEBUG) {
Log.d(TAG, "onAnimationEnd progress=" + progress
@@ -228,8 +228,14 @@
// only called when launcher restarting.
UiThreadHelper.hideKeyboardAsync(mApps.getContext(), mApps.getWindowToken());
}
+
setState(false, true, progress);
+
+
if (mAnimationController == null) {
+ if (mState == State.FLING_END_TOP_IME_CANCELLED) {
+ mApps.getWindowInsetsController().show(WindowInsets.Type.ime());
+ }
return;
}
@@ -268,8 +274,12 @@
} else if (end) {
if (Float.compare(progress, 1f) == 0 && mState == State.DRAG_START_TOP) {
state = State.FLING_END_BOTTOM;
- } else if (Float.compare(progress, 0f) == 0 && mState == State.DRAG_START_BOTTOM) {
- state = State.FLING_END_TOP;
+ } else if (Float.compare(progress, 0f) == 0) {
+ if (mState == State.DRAG_START_BOTTOM) {
+ state = State.FLING_END_TOP;
+ } else if (mState == State.DRAG_START_BOTTOM_IME_CANCELLED) {
+ state = State.FLING_END_TOP_IME_CANCELLED;
+ }
}
}
if (DEBUG) {
diff --git a/src/com/android/launcher3/allapps/AllAppsSectionDecorator.java b/src/com/android/launcher3/allapps/AllAppsSectionDecorator.java
index 3c81811..1d31975 100644
--- a/src/com/android/launcher3/allapps/AllAppsSectionDecorator.java
+++ b/src/com/android/launcher3/allapps/AllAppsSectionDecorator.java
@@ -98,7 +98,8 @@
mAppsView.getActiveRecyclerView().getLayoutManager();
if (layoutManager.findFirstVisibleItemPosition() <= index
&& index < parent.getChildCount()) {
- decorationHandler.onFocusDraw(c, parent.getChildAt(index));
+ RecyclerView.ViewHolder vh = parent.findViewHolderForAdapterPosition(index);
+ if (vh != null) decorationHandler.onFocusDraw(c, vh.itemView);
}
}
decorationHandler.reset();
diff --git a/src/com/android/launcher3/allapps/AllAppsTransitionController.java b/src/com/android/launcher3/allapps/AllAppsTransitionController.java
index 0c488a6..f9ab196 100644
--- a/src/com/android/launcher3/allapps/AllAppsTransitionController.java
+++ b/src/com/android/launcher3/allapps/AllAppsTransitionController.java
@@ -264,11 +264,15 @@
if (FeatureFlags.ENABLE_DEVICE_SEARCH.get() && BuildCompat.isAtLeastR()) {
mInsetController.onAnimationEnd(mProgress);
if (Float.compare(mProgress, 0f) == 0) {
+ mLauncher.getLiveSearchManager().start();
EditText editText = mAppsView.getSearchUiManager().getEditText();
if (editText != null) {
editText.requestFocus();
}
}
+ else {
+ mLauncher.getLiveSearchManager().stop();
+ }
// TODO: should make the controller hide synchronously
}
}
diff --git a/src/com/android/launcher3/allapps/AlphabeticalAppsList.java b/src/com/android/launcher3/allapps/AlphabeticalAppsList.java
index 2450787..354f97c 100644
--- a/src/com/android/launcher3/allapps/AlphabeticalAppsList.java
+++ b/src/com/android/launcher3/allapps/AlphabeticalAppsList.java
@@ -132,6 +132,9 @@
* Returns the child adapter item with IME launch focus.
*/
public AdapterItem getFocusedChild() {
+ if (mAdapterItems.size() == 0) {
+ return null;
+ }
return mAdapterItems.get(getFocusedChildIndex());
}
diff --git a/src/com/android/launcher3/allapps/search/LiveSearchManager.java b/src/com/android/launcher3/allapps/search/LiveSearchManager.java
new file mode 100644
index 0000000..e8a00d9
--- /dev/null
+++ b/src/com/android/launcher3/allapps/search/LiveSearchManager.java
@@ -0,0 +1,125 @@
+/*
+ * 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.allapps.search;
+
+import static com.android.launcher3.widget.WidgetHostViewLoader.getDefaultOptionsForWidget;
+
+import android.appwidget.AppWidgetHost;
+import android.appwidget.AppWidgetHostView;
+import android.appwidget.AppWidgetManager;
+import android.appwidget.AppWidgetProviderInfo;
+import android.content.ComponentName;
+import android.content.Context;
+import android.os.Bundle;
+import android.os.UserHandle;
+
+import com.android.launcher3.Launcher;
+import com.android.launcher3.LauncherAppWidgetProviderInfo;
+import com.android.launcher3.util.ComponentKey;
+import com.android.launcher3.widget.PendingAddWidgetInfo;
+
+import java.util.HashMap;
+
+/**
+ * Manages Lifecycle for Live search results
+ */
+public class LiveSearchManager {
+
+ public static final int SEARCH_APPWIDGET_HOST_ID = 2048;
+
+ private final Launcher mLauncher;
+ private final AppWidgetManager mAppWidgetManger;
+ private HashMap<ComponentKey, SearchWidgetInfoContainer> mWidgetPlaceholders = new HashMap<>();
+ private SearchWidgetHost mSearchWidgetHost;
+
+ public LiveSearchManager(Launcher launcher) {
+ mLauncher = launcher;
+ mAppWidgetManger = AppWidgetManager.getInstance(launcher);
+ }
+
+ /**
+ * Creates new {@link AppWidgetHostView} from {@link AppWidgetProviderInfo}. Caches views for
+ * quicker result within the same search session
+ */
+ public SearchWidgetInfoContainer getPlaceHolderWidget(AppWidgetProviderInfo providerInfo) {
+ if (mSearchWidgetHost == null) {
+ throw new RuntimeException("AppWidgetHost has not been created yet");
+ }
+
+ ComponentName provider = providerInfo.provider;
+ UserHandle userHandle = providerInfo.getProfile();
+
+ ComponentKey key = new ComponentKey(provider, userHandle);
+ SearchWidgetInfoContainer view = mWidgetPlaceholders.getOrDefault(key, null);
+ if (mWidgetPlaceholders.containsKey(key)) {
+ return mWidgetPlaceholders.get(key);
+ }
+ LauncherAppWidgetProviderInfo pinfo = LauncherAppWidgetProviderInfo.fromProviderInfo(
+ mLauncher, providerInfo);
+ PendingAddWidgetInfo pendingAddWidgetInfo = new PendingAddWidgetInfo(pinfo);
+
+ Bundle options = getDefaultOptionsForWidget(mLauncher, pendingAddWidgetInfo);
+ int appWidgetId = mSearchWidgetHost.allocateAppWidgetId();
+ boolean success = mAppWidgetManger.bindAppWidgetIdIfAllowed(appWidgetId, userHandle,
+ provider, options);
+ if (!success) {
+ mWidgetPlaceholders.put(key, null);
+ return null;
+ }
+
+ view = (SearchWidgetInfoContainer) mSearchWidgetHost.createView(mLauncher, appWidgetId,
+ providerInfo);
+ view.setTag(pendingAddWidgetInfo);
+ mWidgetPlaceholders.put(key, view);
+ return view;
+ }
+
+ /**
+ * Start search session
+ */
+ public void start() {
+ stop();
+ mSearchWidgetHost = new SearchWidgetHost(mLauncher);
+ mSearchWidgetHost.startListening();
+ }
+
+ /**
+ * Stop search session
+ */
+ public void stop() {
+ if (mSearchWidgetHost != null) {
+ mSearchWidgetHost.stopListening();
+ mSearchWidgetHost.deleteHost();
+ for (SearchWidgetInfoContainer placeholder : mWidgetPlaceholders.values()) {
+ placeholder.clearListeners();
+ }
+ mWidgetPlaceholders.clear();
+ mSearchWidgetHost = null;
+ }
+ }
+
+ static class SearchWidgetHost extends AppWidgetHost {
+ SearchWidgetHost(Context context) {
+ super(context, SEARCH_APPWIDGET_HOST_ID);
+ }
+
+ @Override
+ protected AppWidgetHostView onCreateView(Context context, int appWidgetId,
+ AppWidgetProviderInfo appWidget) {
+ return new SearchWidgetInfoContainer(context);
+ }
+ }
+}
diff --git a/src/com/android/launcher3/allapps/search/SearchWidgetInfoContainer.java b/src/com/android/launcher3/allapps/search/SearchWidgetInfoContainer.java
new file mode 100644
index 0000000..b5c2268
--- /dev/null
+++ b/src/com/android/launcher3/allapps/search/SearchWidgetInfoContainer.java
@@ -0,0 +1,79 @@
+/*
+ * 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.allapps.search;
+
+import android.appwidget.AppWidgetHostView;
+import android.appwidget.AppWidgetProviderInfo;
+import android.content.Context;
+import android.widget.RemoteViews;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * A placeholder {@link AppWidgetHostView} used for managing widget search results
+ */
+public class SearchWidgetInfoContainer extends AppWidgetHostView {
+ private int mAppWidgetId;
+ private AppWidgetProviderInfo mProviderInfo;
+ private RemoteViews mViews;
+ private List<AppWidgetHostView> mListeners = new ArrayList<>();
+
+ public SearchWidgetInfoContainer(Context context) {
+ super(context);
+ }
+
+ @Override
+ public void setAppWidget(int appWidgetId, AppWidgetProviderInfo info) {
+ mAppWidgetId = appWidgetId;
+ mProviderInfo = info;
+ for (AppWidgetHostView listener : mListeners) {
+ listener.setAppWidget(mAppWidgetId, mProviderInfo);
+ }
+ }
+
+ @Override
+ public void updateAppWidget(RemoteViews remoteViews) {
+ mViews = remoteViews;
+ for (AppWidgetHostView listener : mListeners) {
+ listener.updateAppWidget(remoteViews);
+ }
+ }
+
+ /**
+ * Create a live {@link AppWidgetHostView} from placeholder
+ */
+ public void attachWidget(AppWidgetHostView hv) {
+ hv.setTag(getTag());
+ hv.setAppWidget(mAppWidgetId, mProviderInfo);
+ hv.updateAppWidget(mViews);
+ mListeners.add(hv);
+ }
+
+ /**
+ * stops AppWidgetHostView from getting updates
+ */
+ public void detachWidget(AppWidgetHostView hostView) {
+ mListeners.remove(hostView);
+ }
+
+ /**
+ * Removes all AppWidgetHost update listeners
+ */
+ public void clearListeners() {
+ mListeners.clear();
+ }
+}
diff --git a/src/com/android/launcher3/anim/AnimatorPlaybackController.java b/src/com/android/launcher3/anim/AnimatorPlaybackController.java
index dcdfb6e..edaf51d 100644
--- a/src/com/android/launcher3/anim/AnimatorPlaybackController.java
+++ b/src/com/android/launcher3/anim/AnimatorPlaybackController.java
@@ -29,8 +29,6 @@
import android.animation.ValueAnimator;
import android.content.Context;
-import androidx.annotation.Nullable;
-
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
@@ -72,7 +70,6 @@
private Runnable mEndAction;
protected boolean mTargetCancelled = false;
- protected Runnable mOnCancelRunnable;
/** package private */
AnimatorPlaybackController(AnimatorSet anim, long duration, ArrayList<Holder> childAnims) {
@@ -88,16 +85,11 @@
@Override
public void onAnimationCancel(Animator animation) {
mTargetCancelled = true;
- if (mOnCancelRunnable != null) {
- mOnCancelRunnable.run();
- mOnCancelRunnable = null;
- }
}
@Override
public void onAnimationEnd(Animator animation) {
mTargetCancelled = false;
- mOnCancelRunnable = null;
}
@Override
@@ -269,33 +261,6 @@
}
}
- /** @see #dispatchOnCancelWithoutCancelRunnable(Runnable) */
- public void dispatchOnCancelWithoutCancelRunnable() {
- dispatchOnCancelWithoutCancelRunnable(null);
- }
-
- /**
- * Sets mOnCancelRunnable = null before dispatching the cancel and restoring the runnable. This
- * is intended to be used only if you need to cancel but want to defer cleaning up yourself.
- * @param callback An optional callback to run after dispatching the cancel but before resetting
- * the onCancelRunnable.
- */
- public void dispatchOnCancelWithoutCancelRunnable(@Nullable Runnable callback) {
- Runnable onCancel = mOnCancelRunnable;
- setOnCancelRunnable(null);
- dispatchOnCancel();
- if (callback != null) {
- callback.run();
- }
- setOnCancelRunnable(onCancel);
- }
-
-
- public AnimatorPlaybackController setOnCancelRunnable(Runnable runnable) {
- mOnCancelRunnable = runnable;
- return this;
- }
-
public void dispatchOnStart() {
callListenerCommandRecursively(mAnim, AnimatorListener::onAnimationStart);
}
diff --git a/src/com/android/launcher3/anim/PendingAnimation.java b/src/com/android/launcher3/anim/PendingAnimation.java
index 6dd316e..4e90c9e 100644
--- a/src/com/android/launcher3/anim/PendingAnimation.java
+++ b/src/com/android/launcher3/anim/PendingAnimation.java
@@ -15,10 +15,12 @@
*/
package com.android.launcher3.anim;
+import static com.android.launcher3.LauncherAnimUtils.SUCCESS_TRANSITION_PROGRESS;
import static com.android.launcher3.anim.AnimatorPlaybackController.addAnimationHoldersRecur;
import android.animation.Animator;
import android.animation.Animator.AnimatorListener;
+import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.animation.TimeInterpolator;
@@ -43,8 +45,6 @@
*/
public class PendingAnimation implements PropertySetter {
- private final ArrayList<Consumer<EndState>> mEndListeners = new ArrayList<>();
-
private final ArrayList<Holder> mAnimHolders = new ArrayList<>();
private final AnimatorSet mAnim;
private final long mDuration;
@@ -73,13 +73,6 @@
addAnimationHoldersRecur(a, mDuration, springProperty, mAnimHolders);
}
- public void finish(boolean isSuccess) {
- for (Consumer<EndState> listeners : mEndListeners) {
- listeners.accept(new EndState(isSuccess));
- }
- mEndListeners.clear();
- }
-
@Override
public void setViewAlpha(View view, float alpha, TimeInterpolator interpolator) {
if (view == null || view.getAlpha() == alpha) {
@@ -163,19 +156,38 @@
}
/**
- * Add a listener of receiving the end state.
- * Note that the listeners are called as a result of calling {@link #finish(boolean)}
- * and not automatically
+ * Add a listener of receiving the success/failure callback in the end.
*/
- public void addEndListener(Consumer<EndState> listener) {
- mEndListeners.add(listener);
+ public void addEndListener(Consumer<Boolean> listener) {
+ if (mProgressAnimator == null) {
+ mProgressAnimator = ValueAnimator.ofFloat(0, 1);
+ }
+ mProgressAnimator.addListener(new EndStateCallbackWrapper(listener));
}
- public static class EndState {
- public boolean isSuccess;
+ private static class EndStateCallbackWrapper extends AnimatorListenerAdapter {
- public EndState(boolean isSuccess) {
- this.isSuccess = isSuccess;
+ private final Consumer<Boolean> mListener;
+ private boolean mCalled = false;
+
+ EndStateCallbackWrapper(Consumer<Boolean> listener) {
+ mListener = listener;
+ }
+
+ @Override
+ public void onAnimationCancel(Animator animation) {
+ if (!mCalled) {
+ mCalled = true;
+ mListener.accept(false);
+ }
+ }
+
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ if (!mCalled) {
+ ValueAnimator anim = (ValueAnimator) animation;
+ mListener.accept(anim.getAnimatedFraction() > SUCCESS_TRANSITION_PROGRESS);
+ }
}
}
}
diff --git a/src/com/android/launcher3/logging/StatsLogManager.java b/src/com/android/launcher3/logging/StatsLogManager.java
index 7e90769..0b445bc 100644
--- a/src/com/android/launcher3/logging/StatsLogManager.java
+++ b/src/com/android/launcher3/logging/StatsLogManager.java
@@ -297,12 +297,6 @@
@UiEvent(doc = "User tapped on image content in Overview Select mode.")
LAUNCHER_SELECT_MODE_IMAGE(627),
- @UiEvent(doc = "A folder was replaced by a single item")
- LAUNCHER_FOLDER_CONVERTED_TO_ICON(628),
-
- @UiEvent(doc = "A hotseat prediction item was pinned")
- LAUNCHER_HOTSEAT_PREDICTION_PINNED(629),
-
@UiEvent(doc = "Activity to add external item was started")
LAUNCHER_ADD_EXTERNAL_ITEM_START(641),
@@ -318,6 +312,12 @@
@UiEvent(doc = "Item was dragged in external item addition flow")
LAUNCHER_ADD_EXTERNAL_ITEM_DRAGGED(645),
+ @UiEvent(doc = "A folder was replaced by a single item")
+ LAUNCHER_FOLDER_CONVERTED_TO_ICON(646),
+
+ @UiEvent(doc = "A hotseat prediction item was pinned")
+ LAUNCHER_HOTSEAT_PREDICTION_PINNED(647),
+
@UiEvent(doc = "Undo event was tapped.")
LAUNCHER_UNDO(648),
diff --git a/src/com/android/launcher3/popup/PopupContainerWithArrow.java b/src/com/android/launcher3/popup/PopupContainerWithArrow.java
index 6d92b8b..59930ff 100644
--- a/src/com/android/launcher3/popup/PopupContainerWithArrow.java
+++ b/src/com/android/launcher3/popup/PopupContainerWithArrow.java
@@ -600,6 +600,17 @@
}
/**
+ * Dismisses the popup if it is no longer valid
+ */
+ public static void dismissInvalidPopup(BaseDraggingActivity activity) {
+ PopupContainerWithArrow popup = getOpen(activity);
+ if (popup != null && (!popup.mOriginalIcon.isAttachedToWindow()
+ || !canShow(popup.mOriginalIcon, (ItemInfo) popup.mOriginalIcon.getTag()))) {
+ popup.animateClose();
+ }
+ }
+
+ /**
* Handler to control drag-and-drop for popup items
*/
public interface PopupItemDragHandler extends OnLongClickListener, OnTouchListener { }
diff --git a/src/com/android/launcher3/secondarydisplay/SecondaryDisplayLauncher.java b/src/com/android/launcher3/secondarydisplay/SecondaryDisplayLauncher.java
index 2b04365..2adf8ce 100644
--- a/src/com/android/launcher3/secondarydisplay/SecondaryDisplayLauncher.java
+++ b/src/com/android/launcher3/secondarydisplay/SecondaryDisplayLauncher.java
@@ -39,6 +39,7 @@
import com.android.launcher3.model.data.LauncherAppWidgetInfo;
import com.android.launcher3.model.data.PromiseAppInfo;
import com.android.launcher3.model.data.WorkspaceItemInfo;
+import com.android.launcher3.popup.PopupContainerWithArrow;
import com.android.launcher3.popup.PopupDataProvider;
import com.android.launcher3.util.ComponentKey;
import com.android.launcher3.util.IntArray;
@@ -296,6 +297,7 @@
@Override
public void bindAllApplications(AppInfo[] apps, int flags) {
mAppsView.getAppsStore().setApps(apps, flags);
+ PopupContainerWithArrow.dismissInvalidPopup(this);
}
public PopupDataProvider getPopupDataProvider() {
diff --git a/src/com/android/launcher3/shortcuts/DeepShortcutTextView.java b/src/com/android/launcher3/shortcuts/DeepShortcutTextView.java
index eb68592..ad3f8df 100644
--- a/src/com/android/launcher3/shortcuts/DeepShortcutTextView.java
+++ b/src/com/android/launcher3/shortcuts/DeepShortcutTextView.java
@@ -132,6 +132,12 @@
mLoadingStatePlaceholder.draw(canvas);
}
+ @Override
+ protected void drawDotIfNecessary(Canvas canvas) {
+ // This view (with the text label to the side of the icon) is not designed for a dot to be
+ // drawn on top of it, so never draw one even if a notification for this shortcut exists.
+ }
+
private void showLoadingState(boolean loading) {
if (loading == mShowLoadingState) {
return;
diff --git a/src/com/android/launcher3/touch/AbstractStateChangeTouchController.java b/src/com/android/launcher3/touch/AbstractStateChangeTouchController.java
index 57c0ad9..a9d0e61 100644
--- a/src/com/android/launcher3/touch/AbstractStateChangeTouchController.java
+++ b/src/com/android/launcher3/touch/AbstractStateChangeTouchController.java
@@ -15,7 +15,8 @@
*/
package com.android.launcher3.touch;
-import static com.android.launcher3.LauncherAnimUtils.MIN_PROGRESS_TO_ALL_APPS;
+import static com.android.launcher3.LauncherAnimUtils.SUCCESS_TRANSITION_PROGRESS;
+import static com.android.launcher3.LauncherAnimUtils.newCancelListener;
import static com.android.launcher3.LauncherState.ALL_APPS;
import static com.android.launcher3.LauncherState.NORMAL;
import static com.android.launcher3.LauncherState.OVERVIEW;
@@ -32,6 +33,7 @@
import static com.android.launcher3.util.DisplayController.getSingleFrameMs;
import android.animation.Animator;
+import android.animation.Animator.AnimatorListener;
import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
import android.animation.ValueAnimator;
@@ -48,7 +50,6 @@
import com.android.launcher3.Utilities;
import com.android.launcher3.anim.AnimationSuccessListener;
import com.android.launcher3.anim.AnimatorPlaybackController;
-import com.android.launcher3.anim.PendingAnimation;
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.logger.LauncherAtom;
import com.android.launcher3.logging.StatsLogManager;
@@ -64,9 +65,6 @@
public abstract class AbstractStateChangeTouchController
implements TouchController, SingleAxisSwipeDetector.Listener {
- // Progress after which the transition is assumed to be a success in case user does not fling
- public static final float SUCCESS_TRANSITION_PROGRESS = 0.5f;
-
/**
* Play an atomic recents animation when the progress from NORMAL to OVERVIEW reaches this.
*/
@@ -77,6 +75,9 @@
protected final SingleAxisSwipeDetector mDetector;
protected final SingleAxisSwipeDetector.Direction mSwipeDirection;
+ protected final AnimatorListener mClearStateOnCancelListener =
+ newCancelListener(this::clearState);
+
private boolean mNoIntercept;
private boolean mIsLogContainerSet;
protected int mStartContainerType;
@@ -85,7 +86,7 @@
protected LauncherState mFromState;
protected LauncherState mToState;
protected AnimatorPlaybackController mCurrentAnimation;
- protected PendingAnimation mPendingAnimation;
+ protected boolean mGoingBetweenStates = true;
private float mStartProgress;
// Ratio of transition process [0, 1] to drag displacement (px)
@@ -209,7 +210,7 @@
mStartProgress = 0;
mPassedOverviewAtomicThreshold = false;
if (mCurrentAnimation != null) {
- mCurrentAnimation.setOnCancelRunnable(null);
+ mCurrentAnimation.getTarget().removeListener(mClearStateOnCancelListener);
}
int animComponents = goingBetweenNormalAndOverview(mFromState, mToState)
? PLAY_NON_ATOMIC : ANIM_ALL_COMPONENTS;
@@ -237,7 +238,7 @@
LauncherState toState) {
return (fromState == NORMAL || fromState == OVERVIEW)
&& (toState == NORMAL || toState == OVERVIEW)
- && mPendingAnimation == null;
+ && mGoingBetweenStates;
}
@Override
@@ -412,9 +413,8 @@
? mToState : mFromState;
// snap to top or bottom using the release velocity
} else {
- float successProgress = mToState == ALL_APPS
- ? MIN_PROGRESS_TO_ALL_APPS : SUCCESS_TRANSITION_PROGRESS;
- targetState = (interpolatedProgress > successProgress) ? mToState : mFromState;
+ targetState =
+ (interpolatedProgress > SUCCESS_TRANSITION_PROGRESS) ? mToState : mFromState;
}
final float endProgress;
@@ -438,7 +438,8 @@
} else {
// Let the state manager know that the animation didn't go to the target state,
// but don't cancel ourselves (we already clean up when the animation completes).
- mCurrentAnimation.dispatchOnCancelWithoutCancelRunnable();
+ mCurrentAnimation.getTarget().removeListener(mClearStateOnCancelListener);
+ mCurrentAnimation.dispatchOnCancel();
endProgress = 0;
if (progress <= 0) {
@@ -522,13 +523,7 @@
mAtomicComponentsController = null;
}
clearState();
- boolean shouldGoToTargetState = true;
- if (mPendingAnimation != null) {
- boolean reachedTarget = mToState == targetState;
- mPendingAnimation.finish(reachedTarget);
- mPendingAnimation = null;
- shouldGoToTargetState = !reachedTarget;
- }
+ boolean shouldGoToTargetState = mGoingBetweenStates || (mToState != targetState);
if (shouldGoToTargetState) {
goToTargetState(targetState);
}
@@ -568,6 +563,7 @@
mAtomicAnim.cancel();
mAtomicAnim = null;
}
+ mGoingBetweenStates = true;
mScheduleResumeAtomicComponent = false;
mDetector.finishedScrolling();
mDetector.setDetectableScrollConditions(0, false);
diff --git a/src/com/android/launcher3/touch/ItemClickHandler.java b/src/com/android/launcher3/touch/ItemClickHandler.java
index d56391d..9b9cb0a 100644
--- a/src/com/android/launcher3/touch/ItemClickHandler.java
+++ b/src/com/android/launcher3/touch/ItemClickHandler.java
@@ -96,6 +96,8 @@
if (v instanceof PendingAppWidgetHostView) {
onClickPendingWidget((PendingAppWidgetHostView) v, launcher);
}
+ } else if (tag instanceof RemoteActionItemInfo) {
+ onClickRemoteAction(launcher, (RemoteActionItemInfo) tag);
}
}
diff --git a/src/com/android/launcher3/views/HeroSearchResultView.java b/src/com/android/launcher3/views/HeroSearchResultView.java
deleted file mode 100644
index a098df9..0000000
--- a/src/com/android/launcher3/views/HeroSearchResultView.java
+++ /dev/null
@@ -1,209 +0,0 @@
-/*
- * 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.views;
-
-import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_ALL_APPS;
-import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
-import static com.android.launcher3.util.Executors.MODEL_EXECUTOR;
-
-import android.content.Context;
-import android.content.pm.ShortcutInfo;
-import android.graphics.Point;
-import android.util.AttributeSet;
-import android.util.Pair;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.LinearLayout;
-
-import com.android.launcher3.BubbleTextView;
-import com.android.launcher3.DeviceProfile;
-import com.android.launcher3.DragSource;
-import com.android.launcher3.DropTarget;
-import com.android.launcher3.Launcher;
-import com.android.launcher3.LauncherAppState;
-import com.android.launcher3.R;
-import com.android.launcher3.allapps.AllAppsStore;
-import com.android.launcher3.allapps.search.AllAppsSearchBarController.SearchTargetHandler;
-import com.android.launcher3.allapps.search.SearchEventTracker;
-import com.android.launcher3.dragndrop.DragOptions;
-import com.android.launcher3.dragndrop.DraggableView;
-import com.android.launcher3.graphics.DragPreviewProvider;
-import com.android.launcher3.model.data.AppInfo;
-import com.android.launcher3.model.data.ItemInfo;
-import com.android.launcher3.model.data.ItemInfoWithIcon;
-import com.android.launcher3.model.data.WorkspaceItemInfo;
-import com.android.launcher3.shortcuts.ShortcutDragPreviewProvider;
-import com.android.launcher3.touch.ItemLongClickListener;
-import com.android.launcher3.util.ComponentKey;
-import com.android.systemui.plugins.shared.SearchTarget;
-import com.android.systemui.plugins.shared.SearchTargetEvent;
-
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * A view representing a high confidence app search result that includes shortcuts
- * TODO (sfufa@) consolidate this with SearchResultIconRow
- */
-public class HeroSearchResultView extends LinearLayout implements DragSource, SearchTargetHandler {
-
- public static final String TARGET_TYPE_HERO_APP = "hero_app";
-
- public static final int MAX_SHORTCUTS_COUNT = 2;
-
- private SearchTarget mSearchTarget;
- private BubbleTextView mBubbleTextView;
- private View mIconView;
- private BubbleTextView[] mDeepShortcutTextViews = new BubbleTextView[2];
-
-
- public HeroSearchResultView(Context context) {
- super(context);
- }
-
- public HeroSearchResultView(Context context, AttributeSet attrs) {
- super(context, attrs);
- }
-
- public HeroSearchResultView(Context context, AttributeSet attrs, int defStyleAttr) {
- super(context, attrs, defStyleAttr);
- }
-
- @Override
- protected void onFinishInflate() {
- super.onFinishInflate();
- Launcher launcher = Launcher.getLauncher(getContext());
- DeviceProfile grid = launcher.getDeviceProfile();
- mIconView = findViewById(R.id.icon);
- ViewGroup.LayoutParams iconParams = mIconView.getLayoutParams();
- iconParams.height = grid.allAppsIconSizePx;
- iconParams.width = grid.allAppsIconSizePx;
-
-
- mBubbleTextView = findViewById(R.id.bubble_text);
- mBubbleTextView.setOnClickListener(view -> {
- handleSelection(SearchTargetEvent.SELECT);
- launcher.getItemOnClickListener().onClick(view);
- });
- mBubbleTextView.setOnLongClickListener(new HeroItemDragHandler(getContext(), this));
-
-
- mDeepShortcutTextViews[0] = findViewById(R.id.shortcut_0);
- mDeepShortcutTextViews[1] = findViewById(R.id.shortcut_1);
- for (BubbleTextView bubbleTextView : mDeepShortcutTextViews) {
- bubbleTextView.setLayoutParams(
- new LinearLayout.LayoutParams(grid.allAppsIconSizePx,
- grid.allAppsIconSizePx));
- bubbleTextView.setOnClickListener(view -> {
- WorkspaceItemInfo itemInfo = (WorkspaceItemInfo) bubbleTextView.getTag();
- SearchTargetEvent event = new SearchTargetEvent.Builder(mSearchTarget,
- SearchTargetEvent.CHILD_SELECT).setShortcutPosition(itemInfo.rank).build();
- SearchEventTracker.getInstance(getContext()).notifySearchTargetEvent(event);
- launcher.getItemOnClickListener().onClick(view);
- });
- }
- }
-
- @Override
- public void applySearchTarget(SearchTarget searchTarget) {
- mSearchTarget = searchTarget;
- AllAppsStore apps = Launcher.getLauncher(getContext()).getAppsView().getAppsStore();
- AppInfo appInfo = apps.getApp(new ComponentKey(searchTarget.getComponentName(),
- searchTarget.getUserHandle()));
- List<ShortcutInfo> infos = mSearchTarget.getShortcutInfos();
-
- ArrayList<Pair<ShortcutInfo, ItemInfoWithIcon>> shortcuts = new ArrayList<>();
- for (int i = 0; infos != null && i < infos.size() && i < MAX_SHORTCUTS_COUNT; i++) {
- ShortcutInfo shortcutInfo = infos.get(i);
- ItemInfoWithIcon si = new WorkspaceItemInfo(shortcutInfo, getContext());
- si.rank = i;
- shortcuts.add(new Pair<>(shortcutInfo, si));
- }
-
- mBubbleTextView.applyFromApplicationInfo(appInfo);
- mIconView.setBackground(mBubbleTextView.getIcon());
- mIconView.setTag(appInfo);
- LauncherAppState appState = LauncherAppState.getInstance(getContext());
- for (int i = 0; i < mDeepShortcutTextViews.length; i++) {
- BubbleTextView shortcutView = mDeepShortcutTextViews[i];
- mDeepShortcutTextViews[i].setVisibility(shortcuts.size() > i ? VISIBLE : GONE);
- if (i < shortcuts.size()) {
- Pair<ShortcutInfo, ItemInfoWithIcon> p = shortcuts.get(i);
- //apply ItemInfo and prepare view
- shortcutView.applyFromWorkspaceItem((WorkspaceItemInfo) p.second);
- MODEL_EXECUTOR.execute(() -> {
- // load unbadged shortcut in background and update view when icon ready
- appState.getIconCache().getUnbadgedShortcutIcon(p.second, p.first);
- MAIN_EXECUTOR.post(() -> shortcutView.reapplyItemInfo(p.second));
- });
- }
- }
- SearchEventTracker.INSTANCE.get(getContext()).registerWeakHandler(searchTarget, this);
- }
-
- @Override
- public void onDropCompleted(View target, DropTarget.DragObject d, boolean success) {
- mBubbleTextView.setVisibility(VISIBLE);
- mBubbleTextView.setIconVisible(true);
- }
-
- private void setWillDrawIcon(boolean willDraw) {
- mIconView.setVisibility(willDraw ? View.VISIBLE : View.INVISIBLE);
- }
-
- /**
- * Drag and drop handler for popup items in Launcher activity
- */
- public static class HeroItemDragHandler implements OnLongClickListener {
- private final Launcher mLauncher;
- private final HeroSearchResultView mContainer;
-
- HeroItemDragHandler(Context context, HeroSearchResultView container) {
- mLauncher = Launcher.getLauncher(context);
- mContainer = container;
- }
-
- @Override
- public boolean onLongClick(View v) {
- if (!ItemLongClickListener.canStartDrag(mLauncher)) return false;
- mContainer.setWillDrawIcon(false);
-
- DraggableView draggableView = DraggableView.ofType(DraggableView.DRAGGABLE_ICON);
- WorkspaceItemInfo itemInfo = new WorkspaceItemInfo((AppInfo) v.getTag());
- itemInfo.container = CONTAINER_ALL_APPS;
- DragPreviewProvider previewProvider = new ShortcutDragPreviewProvider(
- mContainer.mIconView, new Point());
- mLauncher.getWorkspace().beginDragShared(mContainer.mBubbleTextView,
- draggableView, mContainer, itemInfo, previewProvider, new DragOptions());
-
- SearchTargetEvent event = new SearchTargetEvent.Builder(mContainer.mSearchTarget,
- SearchTargetEvent.LONG_PRESS).build();
- SearchEventTracker.INSTANCE.get(mLauncher).notifySearchTargetEvent(event);
- return false;
- }
- }
-
- @Override
- public void handleSelection(int eventType) {
- ItemInfo itemInfo = (ItemInfo) mBubbleTextView.getTag();
- if (itemInfo == null) return;
- Launcher launcher = Launcher.getLauncher(getContext());
- launcher.startActivitySafely(this, itemInfo.getIntent(), itemInfo);
-
- SearchEventTracker.INSTANCE.get(getContext()).notifySearchTargetEvent(
- new SearchTargetEvent.Builder(mSearchTarget, eventType).build());
- }
-}
diff --git a/src/com/android/launcher3/views/SearchResultIcon.java b/src/com/android/launcher3/views/SearchResultIcon.java
index ea06d5b..51c741b 100644
--- a/src/com/android/launcher3/views/SearchResultIcon.java
+++ b/src/com/android/launcher3/views/SearchResultIcon.java
@@ -15,21 +15,40 @@
*/
package com.android.launcher3.views;
+import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
+import static com.android.launcher3.util.Executors.MODEL_EXECUTOR;
+import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
+
+import android.app.RemoteAction;
+import android.content.ComponentName;
import android.content.Context;
+import android.content.pm.ShortcutInfo;
+import android.graphics.drawable.Drawable;
+import android.os.Build;
+import android.os.UserHandle;
import android.util.AttributeSet;
import android.view.View;
+import android.view.ViewGroup;
import com.android.launcher3.BubbleTextView;
import com.android.launcher3.Launcher;
+import com.android.launcher3.LauncherAppState;
import com.android.launcher3.allapps.AllAppsStore;
import com.android.launcher3.allapps.search.AllAppsSearchBarController;
import com.android.launcher3.allapps.search.SearchEventTracker;
+import com.android.launcher3.icons.BitmapInfo;
+import com.android.launcher3.icons.LauncherIcons;
import com.android.launcher3.model.data.AppInfo;
+import com.android.launcher3.model.data.ItemInfoWithIcon;
+import com.android.launcher3.model.data.RemoteActionItemInfo;
+import com.android.launcher3.model.data.WorkspaceItemInfo;
import com.android.launcher3.touch.ItemLongClickListener;
import com.android.launcher3.util.ComponentKey;
import com.android.systemui.plugins.shared.SearchTarget;
import com.android.systemui.plugins.shared.SearchTargetEvent;
+import java.util.function.Consumer;
+
/**
* A {@link BubbleTextView} representing a single cell result in AllApps
*/
@@ -39,10 +58,21 @@
public static final String TARGET_TYPE_APP = "app";
+ public static final String TARGET_TYPE_HERO_APP = "hero_app";
+ public static final String TARGET_TYPE_SHORTCUT = "shortcut";
+ public static final String TARGET_TYPE_REMOTE_ACTION = "remote_action";
+
+ public static final String REMOTE_ACTION_SHOULD_START = "should_start_for_result";
+ public static final String REMOTE_ACTION_TOKEN = "action_token";
+
+
+ private static final String[] LONG_PRESS_SUPPORTED_TYPES =
+ new String[]{TARGET_TYPE_APP, TARGET_TYPE_SHORTCUT, TARGET_TYPE_HERO_APP};
private final Launcher mLauncher;
private SearchTarget mSearchTarget;
+ private Consumer<ItemInfoWithIcon> mOnItemInfoChanged;
public SearchResultIcon(Context context) {
this(context, null, 0);
@@ -64,26 +94,96 @@
setOnFocusChangeListener(mLauncher.getFocusHandler());
setOnClickListener(this);
setOnLongClickListener(this);
- getLayoutParams().height = mLauncher.getDeviceProfile().allAppsCellHeightPx;
+ setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
+ mLauncher.getDeviceProfile().allAppsCellHeightPx));
+ }
+
+ /**
+ * Applies search target with a ItemInfoWithIcon consumer to be called after itemInfo is
+ * constructed
+ */
+ public void applySearchTarget(SearchTarget searchTarget, Consumer<ItemInfoWithIcon> cb) {
+ mOnItemInfoChanged = cb;
+ applySearchTarget(searchTarget);
}
@Override
public void applySearchTarget(SearchTarget searchTarget) {
mSearchTarget = searchTarget;
- AllAppsStore appsStore = mLauncher.getAppsView().getAppsStore();
SearchEventTracker.getInstance(getContext()).registerWeakHandler(mSearchTarget, this);
- if (searchTarget.getItemType().equals(TARGET_TYPE_APP)) {
- AppInfo appInfo = appsStore.getApp(new ComponentKey(searchTarget.getComponentName(),
- searchTarget.getUserHandle()));
- applyFromApplicationInfo(appInfo);
+ switch (searchTarget.getItemType()) {
+ case TARGET_TYPE_APP:
+ case TARGET_TYPE_HERO_APP:
+ prepareUsingApp(searchTarget.getComponentName(), searchTarget.getUserHandle());
+ break;
+ case TARGET_TYPE_SHORTCUT:
+ prepareUsingShortcutInfo(searchTarget.getShortcutInfos().get(0));
+ break;
+ case TARGET_TYPE_REMOTE_ACTION:
+ prepareUsingRemoteAction(searchTarget.getRemoteAction(),
+ searchTarget.getExtras().getString(REMOTE_ACTION_TOKEN),
+ searchTarget.getExtras().getBoolean(REMOTE_ACTION_SHOULD_START),
+ searchTarget.getItemType().equals(TARGET_TYPE_REMOTE_ACTION));
+ break;
}
}
+ private void prepareUsingApp(ComponentName componentName, UserHandle userHandle) {
+ AllAppsStore appsStore = mLauncher.getAppsView().getAppsStore();
+ AppInfo appInfo = appsStore.getApp(new ComponentKey(componentName, userHandle));
+ applyFromApplicationInfo(appInfo);
+ notifyItemInfoChanged(appInfo);
+ }
+
+
+ private void prepareUsingShortcutInfo(ShortcutInfo shortcutInfo) {
+ WorkspaceItemInfo workspaceItemInfo = new WorkspaceItemInfo(shortcutInfo, getContext());
+ notifyItemInfoChanged(workspaceItemInfo);
+ LauncherAppState launcherAppState = LauncherAppState.getInstance(getContext());
+ MODEL_EXECUTOR.execute(() -> {
+ launcherAppState.getIconCache().getShortcutIcon(workspaceItemInfo, shortcutInfo);
+ MAIN_EXECUTOR.post(() -> applyFromWorkspaceItem(workspaceItemInfo));
+ });
+ }
+
+ private void prepareUsingRemoteAction(RemoteAction remoteAction, String token, boolean start,
+ boolean useIconToBadge) {
+ RemoteActionItemInfo itemInfo = new RemoteActionItemInfo(remoteAction, token, start);
+ notifyItemInfoChanged(itemInfo);
+ UI_HELPER_EXECUTOR.post(() -> {
+ // If the Drawable from the remote action is not AdaptiveBitmap, styling will not
+ // work.
+ try (LauncherIcons li = LauncherIcons.obtain(getContext())) {
+ Drawable d = itemInfo.getRemoteAction().getIcon().loadDrawable(getContext());
+ BitmapInfo bitmap = li.createBadgedIconBitmap(d, itemInfo.user,
+ Build.VERSION.SDK_INT);
+
+ if (useIconToBadge) {
+ BitmapInfo placeholder = li.createIconBitmap(
+ itemInfo.getRemoteAction().getTitle().toString().substring(0, 1),
+ bitmap.color);
+ itemInfo.bitmap = li.badgeBitmap(placeholder.icon, bitmap);
+ } else {
+ itemInfo.bitmap = bitmap;
+ }
+ }
+ MAIN_EXECUTOR.post(() -> applyFromRemoteActionInfo(itemInfo));
+ });
+ }
+
@Override
public void handleSelection(int eventType) {
mLauncher.getItemOnClickListener().onClick(this);
- SearchEventTracker.INSTANCE.get(mLauncher).notifySearchTargetEvent(
- new SearchTargetEvent.Builder(mSearchTarget, eventType).build());
+ reportEvent(eventType);
+ }
+
+ private void reportEvent(int eventType) {
+ SearchTargetEvent.Builder b = new SearchTargetEvent.Builder(mSearchTarget, eventType);
+ if (mSearchTarget.getItemType().equals(TARGET_TYPE_SHORTCUT)) {
+ b.setShortcutPosition(0);
+ }
+ SearchEventTracker.INSTANCE.get(mLauncher).notifySearchTargetEvent(b.build());
+
}
@Override
@@ -93,8 +193,25 @@
@Override
public boolean onLongClick(View view) {
- SearchEventTracker.INSTANCE.get(mLauncher).notifySearchTargetEvent(
- new SearchTargetEvent.Builder(mSearchTarget, SearchTargetEvent.LONG_PRESS).build());
+ if (!supportsLongPress(mSearchTarget.getItemType())) {
+ return false;
+ }
+ reportEvent(SearchTargetEvent.LONG_PRESS);
return ItemLongClickListener.INSTANCE_ALL_APPS.onLongClick(view);
+
+ }
+
+ private boolean supportsLongPress(String type) {
+ for (String t : LONG_PRESS_SUPPORTED_TYPES) {
+ if (t.equals(type)) return true;
+ }
+ return false;
+ }
+
+ private void notifyItemInfoChanged(ItemInfoWithIcon itemInfoWithIcon) {
+ if (mOnItemInfoChanged != null) {
+ mOnItemInfoChanged.accept(itemInfoWithIcon);
+ mOnItemInfoChanged = null;
+ }
}
}
diff --git a/src/com/android/launcher3/views/SearchResultIconRow.java b/src/com/android/launcher3/views/SearchResultIconRow.java
index bdbe890..e3c7661 100644
--- a/src/com/android/launcher3/views/SearchResultIconRow.java
+++ b/src/com/android/launcher3/views/SearchResultIconRow.java
@@ -17,188 +17,185 @@
import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
import static com.android.launcher3.util.Executors.MODEL_EXECUTOR;
-import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
-import android.app.RemoteAction;
+import android.content.ComponentName;
import android.content.Context;
import android.content.pm.ShortcutInfo;
-import android.content.res.TypedArray;
-import android.graphics.Canvas;
-import android.graphics.drawable.Drawable;
-import android.os.Build;
+import android.os.UserHandle;
+import android.text.TextUtils;
import android.util.AttributeSet;
-import android.widget.EditText;
+import android.util.Pair;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.LinearLayout;
+import android.widget.TextView;
-import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
+import com.android.launcher3.BubbleTextView;
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherAppState;
import com.android.launcher3.R;
import com.android.launcher3.allapps.search.AllAppsSearchBarController;
import com.android.launcher3.allapps.search.SearchEventTracker;
-import com.android.launcher3.icons.BitmapInfo;
-import com.android.launcher3.icons.LauncherIcons;
-import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.model.data.ItemInfoWithIcon;
-import com.android.launcher3.model.data.RemoteActionItemInfo;
+import com.android.launcher3.model.data.PackageItemInfo;
import com.android.launcher3.model.data.WorkspaceItemInfo;
-import com.android.launcher3.touch.ItemClickHandler;
-import com.android.launcher3.util.Themes;
import com.android.systemui.plugins.shared.SearchTarget;
import com.android.systemui.plugins.shared.SearchTargetEvent;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.function.Consumer;
+
/**
- * A view representing a stand alone shortcut search result
+ * A full width representation of {@link SearchResultIcon} with a secondary label and inline
+ * shortcuts
*/
-public class SearchResultIconRow extends DoubleShadowBubbleTextView implements
- AllAppsSearchBarController.SearchTargetHandler {
+public class SearchResultIconRow extends LinearLayout implements
+ AllAppsSearchBarController.SearchTargetHandler, View.OnClickListener,
+ View.OnLongClickListener, Consumer<ItemInfoWithIcon> {
+ public static final int MAX_SHORTCUTS_COUNT = 2;
- public static final String TARGET_TYPE_REMOTE_ACTION = "remote_action";
- public static final String TARGET_TYPE_SUGGEST = "suggest";
- public static final String TARGET_TYPE_SHORTCUT = "shortcut";
-
-
- public static final String REMOTE_ACTION_SHOULD_START = "should_start_for_result";
- public static final String REMOTE_ACTION_TOKEN = "action_token";
-
- private final boolean mMatchesInset;
+ private final Launcher mLauncher;
+ private final LauncherAppState mLauncherAppState;
+ private SearchResultIcon mResultIcon;
+ private TextView mTitleView;
+ private TextView mDescriptionView;
+ private BubbleTextView[] mShortcutViews = new BubbleTextView[2];
private SearchTarget mSearchTarget;
+ private PackageItemInfo mProviderInfo;
- @Nullable private Drawable mCustomIcon;
- public SearchResultIconRow(@NonNull Context context) {
+ public SearchResultIconRow(Context context) {
this(context, null, 0);
}
- public SearchResultIconRow(@NonNull Context context,
+ public SearchResultIconRow(Context context,
@Nullable AttributeSet attrs) {
this(context, attrs, 0);
}
- public SearchResultIconRow(@NonNull Context context, @Nullable AttributeSet attrs,
- int defStyleAttr) {
+ public SearchResultIconRow(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
- TypedArray a = context.obtainStyledAttributes(attrs,
- R.styleable.SearchResultIconRow, defStyleAttr, 0);
- mMatchesInset = a.getBoolean(R.styleable.SearchResultIconRow_matchTextInsetWithQuery,
- false);
-
- int customIconResId = a.getResourceId(R.styleable.SearchResultIconRow_customIcon, 0);
-
- if (customIconResId != 0) {
- mCustomIcon = Launcher.getLauncher(context).getDrawable(customIconResId);
- }
-
- a.recycle();
- }
-
-
- @Override
- protected void onAttachedToWindow() {
- super.onAttachedToWindow();
- Launcher launcher = Launcher.getLauncher(getContext());
- if (mMatchesInset && launcher.getAppsView() != null && getParent() != null) {
- EditText editText = launcher.getAppsView().getSearchUiManager().getEditText();
- if (editText != null) {
- int counterOffset = getIconSize() + getCompoundDrawablePadding() / 2;
- setPadding(editText.getLeft() - counterOffset, getPaddingTop(),
- getPaddingRight(), getPaddingBottom());
- }
- }
+ mLauncher = Launcher.getLauncher(getContext());
+ mLauncherAppState = LauncherAppState.getInstance(getContext());
}
@Override
- protected void drawFocusHighlight(Canvas canvas) {
- mHighlightPaint.setColor(mHighlightColor);
- float r = Themes.getDialogCornerRadius(getContext());
- canvas.drawRoundRect(0, 0, getWidth(), getHeight(), r, r, mHighlightPaint);
- }
+ protected void onFinishInflate() {
+ super.onFinishInflate();
+ int iconSize = mLauncher.getDeviceProfile().allAppsIconSizePx;
+ mResultIcon = findViewById(R.id.icon);
+ mTitleView = findViewById(R.id.title);
+ mDescriptionView = findViewById(R.id.desc);
+ mShortcutViews[0] = findViewById(R.id.shortcut_0);
+ mShortcutViews[1] = findViewById(R.id.shortcut_1);
+ mResultIcon.getLayoutParams().height = iconSize;
+ mResultIcon.getLayoutParams().width = iconSize;
+ mResultIcon.setTextVisibility(false);
+ for (BubbleTextView bubbleTextView : mShortcutViews) {
+ ViewGroup.LayoutParams lp = bubbleTextView.getLayoutParams();
+ lp.width = iconSize;
+ bubbleTextView.setOnClickListener(view -> {
+ WorkspaceItemInfo itemInfo = (WorkspaceItemInfo) bubbleTextView.getTag();
+ SearchTargetEvent event = new SearchTargetEvent.Builder(mSearchTarget,
+ SearchTargetEvent.CHILD_SELECT).setShortcutPosition(itemInfo.rank).build();
+ SearchEventTracker.getInstance(getContext()).notifySearchTargetEvent(event);
+ mLauncher.getItemOnClickListener().onClick(view);
+ });
+ }
+ setOnClickListener(this);
+ setOnLongClickListener(this);
+ }
@Override
public void applySearchTarget(SearchTarget searchTarget) {
mSearchTarget = searchTarget;
- String type = searchTarget.getItemType();
- if (type.equals(TARGET_TYPE_REMOTE_ACTION) || type.equals(TARGET_TYPE_SUGGEST)) {
- prepareUsingRemoteAction(searchTarget.getRemoteAction(),
- searchTarget.getExtras().getString(REMOTE_ACTION_TOKEN),
- searchTarget.getExtras().getBoolean(REMOTE_ACTION_SHOULD_START),
- type.equals(TARGET_TYPE_REMOTE_ACTION));
+ mResultIcon.applySearchTarget(searchTarget, this);
+ String itemType = searchTarget.getItemType();
+ boolean showDesc = itemType.equals(SearchResultIcon.TARGET_TYPE_SHORTCUT);
+ mDescriptionView.setVisibility(showDesc ? VISIBLE : GONE);
- } else if (type.equals(TARGET_TYPE_SHORTCUT)) {
- prepareUsingShortcutInfo(searchTarget.getShortcutInfos().get(0));
+ if (itemType.equals(SearchResultIcon.TARGET_TYPE_SHORTCUT)) {
+ ShortcutInfo shortcutInfo = searchTarget.getShortcutInfos().get(0);
+ setProviderDetails(new ComponentName(shortcutInfo.getPackage(), ""),
+ shortcutInfo.getUserHandle());
+ } else if (itemType.equals(SearchResultIcon.TARGET_TYPE_HERO_APP)) {
+ showInlineShortcuts(mSearchTarget.getShortcutInfos());
+ } else if (itemType.equals(SearchResultIcon.TARGET_TYPE_REMOTE_ACTION)) {
+ CharSequence desc = mSearchTarget.getRemoteAction().getContentDescription();
+ if (!TextUtils.isEmpty(desc)) {
+ mDescriptionView.setVisibility(VISIBLE);
+ mDescriptionView.setText(desc);
+ }
}
- setOnClickListener(v -> handleSelection(SearchTargetEvent.SELECT));
- SearchEventTracker.INSTANCE.get(getContext()).registerWeakHandler(searchTarget, this);
+ if (!itemType.equals(SearchResultIcon.TARGET_TYPE_HERO_APP)) {
+ showInlineShortcuts(new ArrayList<>());
+ }
}
- private void prepareUsingShortcutInfo(ShortcutInfo shortcutInfo) {
- WorkspaceItemInfo workspaceItemInfo = new WorkspaceItemInfo(shortcutInfo, getContext());
- applyFromWorkspaceItem(workspaceItemInfo);
- LauncherAppState launcherAppState = LauncherAppState.getInstance(getContext());
- if (!loadIconFromResource()) {
- MODEL_EXECUTOR.execute(() -> {
- launcherAppState.getIconCache().getShortcutIcon(workspaceItemInfo, shortcutInfo);
- reapplyItemInfoAsync(workspaceItemInfo);
+ @Override
+ public void accept(ItemInfoWithIcon itemInfoWithIcon) {
+ mTitleView.setText(itemInfoWithIcon.title);
+ }
+
+ private void showInlineShortcuts(List<ShortcutInfo> infos) {
+ if (infos == null) return;
+ ArrayList<Pair<ShortcutInfo, ItemInfoWithIcon>> shortcuts = new ArrayList<>();
+ for (int i = 0; infos != null && i < infos.size() && i < MAX_SHORTCUTS_COUNT; i++) {
+ ShortcutInfo shortcutInfo = infos.get(i);
+ ItemInfoWithIcon si = new WorkspaceItemInfo(shortcutInfo, getContext());
+ si.rank = i;
+ shortcuts.add(new Pair<>(shortcutInfo, si));
+ }
+
+ for (int i = 0; i < mShortcutViews.length; i++) {
+ BubbleTextView shortcutView = mShortcutViews[i];
+ mShortcutViews[i].setVisibility(shortcuts.size() > i ? VISIBLE : GONE);
+ if (i < shortcuts.size()) {
+ Pair<ShortcutInfo, ItemInfoWithIcon> p = shortcuts.get(i);
+ //apply ItemInfo and prepare view
+ shortcutView.applyFromWorkspaceItem((WorkspaceItemInfo) p.second);
+ MODEL_EXECUTOR.execute(() -> {
+ // load unbadged shortcut in background and update view when icon ready
+ mLauncherAppState.getIconCache().getUnbadgedShortcutIcon(p.second, p.first);
+ MAIN_EXECUTOR.post(() -> shortcutView.reapplyItemInfo(p.second));
+ });
+ }
+ }
+ }
+
+
+ private void setProviderDetails(ComponentName componentName, UserHandle userHandle) {
+ PackageItemInfo packageItemInfo = new PackageItemInfo(componentName.getPackageName());
+ if (mProviderInfo == packageItemInfo) return;
+ MODEL_EXECUTOR.post(() -> {
+ packageItemInfo.user = userHandle;
+ mLauncherAppState.getIconCache().getTitleAndIconForApp(packageItemInfo, true);
+ MAIN_EXECUTOR.post(() -> {
+ mDescriptionView.setText(packageItemInfo.title);
+ mProviderInfo = packageItemInfo;
});
- }
- }
-
- private void prepareUsingRemoteAction(RemoteAction remoteAction, String token, boolean start,
- boolean useIconToBadge) {
- RemoteActionItemInfo itemInfo = new RemoteActionItemInfo(remoteAction, token, start);
-
- applyFromRemoteActionInfo(itemInfo);
- if (itemInfo.isEscapeHatch() || !loadIconFromResource()) {
- UI_HELPER_EXECUTOR.post(() -> {
- // If the Drawable from the remote action is not AdaptiveBitmap, styling will not
- // work.
- try (LauncherIcons li = LauncherIcons.obtain(getContext())) {
- Drawable d = itemInfo.getRemoteAction().getIcon().loadDrawable(getContext());
- BitmapInfo bitmap = li.createBadgedIconBitmap(d, itemInfo.user,
- Build.VERSION.SDK_INT);
-
- if (useIconToBadge) {
- BitmapInfo placeholder = li.createIconBitmap(
- itemInfo.getRemoteAction().getTitle().toString().substring(0, 1),
- bitmap.color);
- itemInfo.bitmap = li.badgeBitmap(placeholder.icon, bitmap);
- } else {
- itemInfo.bitmap = bitmap;
- }
- reapplyItemInfoAsync(itemInfo);
- }
- });
- }
-
- }
-
- private boolean loadIconFromResource() {
- if (mCustomIcon == null) return false;
- setIcon(mCustomIcon);
- return true;
- }
-
- void reapplyItemInfoAsync(ItemInfoWithIcon itemInfoWithIcon) {
- MAIN_EXECUTOR.post(() -> {
- reapplyItemInfo(itemInfoWithIcon);
- mCustomIcon = getIcon();
});
}
@Override
public void handleSelection(int eventType) {
- ItemInfo itemInfo = (ItemInfo) getTag();
- Launcher launcher = Launcher.getLauncher(getContext());
- if (itemInfo instanceof WorkspaceItemInfo) {
- ItemClickHandler.onClickAppShortcut(this, (WorkspaceItemInfo) itemInfo, launcher);
- } else {
- ItemClickHandler.onClickRemoteAction(launcher, (RemoteActionItemInfo) itemInfo);
- }
- SearchEventTracker.INSTANCE.get(getContext()).notifySearchTargetEvent(
- new SearchTargetEvent.Builder(mSearchTarget, eventType).build());
+ mResultIcon.handleSelection(eventType);
+ }
+
+ @Override
+ public void onClick(View view) {
+ mResultIcon.performClick();
+ }
+
+ @Override
+ public boolean onLongClick(View view) {
+ mResultIcon.performLongClick();
+ return false;
}
}
diff --git a/src/com/android/launcher3/views/SearchResultSettingsSlice.java b/src/com/android/launcher3/views/SearchResultSettingsSlice.java
new file mode 100644
index 0000000..2d726e7
--- /dev/null
+++ b/src/com/android/launcher3/views/SearchResultSettingsSlice.java
@@ -0,0 +1,129 @@
+/*
+ * 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.views;
+
+import android.content.Context;
+import android.net.Uri;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.View;
+import android.widget.LinearLayout;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.lifecycle.LiveData;
+import androidx.slice.Slice;
+import androidx.slice.SliceItem;
+import androidx.slice.widget.EventInfo;
+import androidx.slice.widget.SliceLiveData;
+import androidx.slice.widget.SliceView;
+
+import com.android.launcher3.Launcher;
+import com.android.launcher3.R;
+import com.android.launcher3.allapps.search.AllAppsSearchBarController;
+import com.android.launcher3.allapps.search.SearchEventTracker;
+import com.android.systemui.plugins.shared.SearchTarget;
+import com.android.systemui.plugins.shared.SearchTargetEvent;
+
+/**
+ * A slice view wrapper with settings app icon at start
+ */
+public class SearchResultSettingsSlice extends LinearLayout implements
+ AllAppsSearchBarController.SearchTargetHandler, SliceView.OnSliceActionListener {
+
+
+ public static final String TARGET_TYPE_SLICE = "settings_slice";
+
+ private static final String TAG = "SearchSliceController";
+ private static final String URI_EXTRA_KEY = "slice_uri";
+
+ private SliceView mSliceView;
+ private View mIcon;
+ private LiveData<Slice> mSliceLiveData;
+ private SearchTarget mSearchTarget;
+ private Launcher mLauncher;
+
+ public SearchResultSettingsSlice(Context context) {
+ this(context, null, 0);
+ }
+
+ public SearchResultSettingsSlice(Context context,
+ @Nullable AttributeSet attrs) {
+ this(context, attrs, 0);
+ }
+
+ public SearchResultSettingsSlice(Context context, @Nullable AttributeSet attrs,
+ int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ mLauncher = Launcher.getLauncher(getContext());
+ }
+
+ @Override
+ protected void onFinishInflate() {
+ super.onFinishInflate();
+ mSliceView = findViewById(R.id.slice);
+ mIcon = findViewById(R.id.icon);
+ SearchSettingsRowView.applySettingsIcon(mLauncher, mIcon);
+ }
+
+ @Override
+ public void applySearchTarget(SearchTarget searchTarget) {
+ reset();
+ mSearchTarget = searchTarget;
+ try {
+ mSliceLiveData = SliceLiveData.fromUri(mLauncher, getSliceUri());
+ mSliceLiveData.observe(mLauncher, mSliceView);
+ } catch (Exception ex) {
+ Log.e(TAG, "unable to bind slice", ex);
+ }
+ }
+
+ @Override
+ protected void onAttachedToWindow() {
+ super.onAttachedToWindow();
+ mSliceView.setOnSliceActionListener(this);
+ }
+
+ @Override
+ protected void onDetachedFromWindow() {
+ super.onDetachedFromWindow();
+ reset();
+ }
+
+ @Override
+ public void handleSelection(int eventType) {
+ SearchEventTracker.INSTANCE.get(mLauncher).notifySearchTargetEvent(
+ new SearchTargetEvent.Builder(mSearchTarget,
+ SearchTargetEvent.CHILD_SELECT).build());
+ }
+
+ private void reset() {
+ mSliceView.setOnSliceActionListener(null);
+ if (mSliceLiveData != null) {
+ mSliceLiveData.removeObservers(mLauncher);
+ }
+ }
+
+ @Override
+ public void onSliceAction(@NonNull EventInfo eventInfo, @NonNull SliceItem sliceItem) {
+ handleSelection(SearchTargetEvent.CHILD_SELECT);
+ }
+
+ private Uri getSliceUri() {
+ return mSearchTarget.getExtras().getParcelable(URI_EXTRA_KEY);
+ }
+
+}
diff --git a/src/com/android/launcher3/views/SearchResultSuggestion.java b/src/com/android/launcher3/views/SearchResultSuggestion.java
new file mode 100644
index 0000000..c67b1cf
--- /dev/null
+++ b/src/com/android/launcher3/views/SearchResultSuggestion.java
@@ -0,0 +1,62 @@
+/*
+ * 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.views;
+
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.graphics.drawable.Drawable;
+import android.util.AttributeSet;
+import android.view.ViewGroup;
+
+import com.android.launcher3.R;
+
+/**
+ * {@link SearchResultIconRow} with custom drawable resource
+ */
+public class SearchResultSuggestion extends SearchResultIcon {
+
+ public static final String TARGET_TYPE_SUGGEST = "suggest";
+ private final Drawable mCustomIcon;
+
+ public SearchResultSuggestion(Context context) {
+ this(context, null, 0);
+ }
+
+ public SearchResultSuggestion(Context context, AttributeSet attrs) {
+ this(context, attrs, 0);
+ }
+
+ public SearchResultSuggestion(Context context, AttributeSet attrs, int defStyle) {
+ super(context, attrs, defStyle);
+
+ TypedArray a = context.obtainStyledAttributes(attrs,
+ R.styleable.SearchResultSuggestion, defStyle, 0);
+ mCustomIcon = a.getDrawable(R.styleable.SearchResultSuggestion_customIcon);
+ a.recycle();
+ }
+
+ @Override
+ protected void onFinishInflate() {
+ super.onFinishInflate();
+ ViewGroup.LayoutParams lp = getLayoutParams();
+ lp.height = BaseDragLayer.LayoutParams.WRAP_CONTENT;
+ }
+
+ @Override
+ protected void setIcon(Drawable icon) {
+ super.setIcon(mCustomIcon);
+ }
+}
diff --git a/src/com/android/launcher3/views/SearchResultWidget.java b/src/com/android/launcher3/views/SearchResultWidget.java
new file mode 100644
index 0000000..7d53955
--- /dev/null
+++ b/src/com/android/launcher3/views/SearchResultWidget.java
@@ -0,0 +1,202 @@
+/*
+ * 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.views;
+
+import android.appwidget.AppWidgetHostView;
+import android.appwidget.AppWidgetProviderInfo;
+import android.content.Context;
+import android.graphics.Rect;
+import android.util.AttributeSet;
+import android.view.GestureDetector;
+import android.view.MotionEvent;
+import android.view.View;
+import android.widget.RelativeLayout;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+import com.android.launcher3.AppWidgetResizeFrame;
+import com.android.launcher3.CheckLongPressHelper;
+import com.android.launcher3.DeviceProfile;
+import com.android.launcher3.Launcher;
+import com.android.launcher3.allapps.search.AllAppsSearchBarController;
+import com.android.launcher3.allapps.search.SearchEventTracker;
+import com.android.launcher3.allapps.search.SearchWidgetInfoContainer;
+import com.android.launcher3.dragndrop.DraggableView;
+import com.android.launcher3.touch.ItemLongClickListener;
+import com.android.launcher3.widget.PendingAddWidgetInfo;
+import com.android.systemui.plugins.shared.SearchTarget;
+import com.android.systemui.plugins.shared.SearchTargetEvent;
+
+/**
+ * displays live version of a widget upon receiving {@link AppWidgetProviderInfo} from Search
+ * provider
+ */
+public class SearchResultWidget extends RelativeLayout implements
+ AllAppsSearchBarController.SearchTargetHandler, DraggableView, View.OnLongClickListener {
+
+ private static final String TAG = "SearchResultWidget";
+
+ public static final String TARGET_TYPE_WIDGET_LIVE = "widget";
+
+ private final Rect mWidgetOffset = new Rect();
+
+ private final Launcher mLauncher;
+ private final CheckLongPressHelper mLongPressHelper;
+ private final GestureDetector mClickDetector;
+ private final AppWidgetHostView mHostView;
+ private final float mScaleToFit;
+
+ private SearchTarget mSearchTarget;
+ private AppWidgetProviderInfo mProviderInfo;
+
+ private SearchWidgetInfoContainer mInfoContainer;
+
+ public SearchResultWidget(@NonNull Context context) {
+ this(context, null, 0);
+ }
+
+ public SearchResultWidget(@NonNull Context context,
+ @Nullable AttributeSet attrs) {
+ this(context, attrs, 0);
+ }
+
+ public SearchResultWidget(@NonNull Context context, @Nullable AttributeSet attrs,
+ int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ mLauncher = Launcher.getLauncher(context);
+ mHostView = new AppWidgetHostView(context);
+ DeviceProfile grid = mLauncher.getDeviceProfile();
+ mScaleToFit = Math.min(grid.appWidgetScale.x, grid.appWidgetScale.y);
+
+ // detect tap event on widget container for search target event reporting
+ mClickDetector = new GestureDetector(context,
+ new ClickListener(() -> handleSelection(SearchTargetEvent.CHILD_SELECT)));
+
+ mLongPressHelper = new CheckLongPressHelper(this);
+ mLongPressHelper.setLongPressTimeoutFactor(1);
+ setOnLongClickListener(this);
+ }
+
+ @Override
+ protected void onFinishInflate() {
+ super.onFinishInflate();
+ addView(mHostView);
+ }
+
+ @Override
+ public void applySearchTarget(SearchTarget searchTarget) {
+ if (searchTarget.getExtras() == null
+ || searchTarget.getExtras().getParcelable("provider") == null) {
+ setVisibility(GONE);
+ return;
+ }
+ AppWidgetProviderInfo providerInfo = searchTarget.getExtras().getParcelable("provider");
+ if (mProviderInfo != null && providerInfo.provider.equals(mProviderInfo.provider)
+ && providerInfo.getProfile().equals(mProviderInfo.getProfile())) {
+ return;
+ }
+ removeListener();
+
+ mSearchTarget = searchTarget;
+ mProviderInfo = providerInfo;
+
+ mInfoContainer = mLauncher.getLiveSearchManager().getPlaceHolderWidget(providerInfo);
+ if (mInfoContainer == null) {
+ setVisibility(GONE);
+ return;
+ }
+ setVisibility(VISIBLE);
+ mInfoContainer.attachWidget(mHostView);
+ PendingAddWidgetInfo info = (PendingAddWidgetInfo) mHostView.getTag();
+ int[] size = mLauncher.getWorkspace().estimateItemSize(info);
+ mHostView.getLayoutParams().width = size[0];
+ mHostView.getLayoutParams().height = size[1];
+ AppWidgetResizeFrame.updateWidgetSizeRanges(mHostView, mLauncher, info.spanX,
+ info.spanY);
+ mHostView.requestLayout();
+ setTag(info);
+ }
+
+ /**
+ * Stops hostView from getting updates on a widget provider
+ */
+ public void removeListener() {
+ if (mInfoContainer != null) {
+ mInfoContainer.detachWidget(mHostView);
+ }
+ }
+
+ @Override
+ public void handleSelection(int eventType) {
+ SearchEventTracker.INSTANCE.get(getContext()).notifySearchTargetEvent(
+ new SearchTargetEvent.Builder(mSearchTarget, eventType).build());
+ }
+
+ @Override
+ public boolean onInterceptTouchEvent(MotionEvent ev) {
+ mLongPressHelper.onTouchEvent(ev);
+ mClickDetector.onTouchEvent(ev);
+ if (ev.getAction() == MotionEvent.ACTION_UP && !mLongPressHelper.hasPerformedLongPress()) {
+ handleSelection(SearchTargetEvent.CHILD_SELECT);
+ }
+ return super.onInterceptTouchEvent(ev);
+ }
+
+
+ @Override
+ public void cancelLongPress() {
+ super.cancelLongPress();
+ mLongPressHelper.cancelLongPress();
+ }
+
+ @Override
+ public int getViewType() {
+ return DraggableView.DRAGGABLE_WIDGET;
+ }
+
+ @Override
+ public void getSourceVisualDragBounds(Rect bounds) {
+ mHostView.getHitRect(mWidgetOffset);
+ int width = (int) (mHostView.getMeasuredWidth() * mScaleToFit);
+ int height = (int) (mHostView.getMeasuredHeight() * mScaleToFit);
+ bounds.set(mWidgetOffset.left,
+ mWidgetOffset.top,
+ width + mWidgetOffset.left,
+ height + mWidgetOffset.top);
+ }
+
+ @Override
+ public boolean onLongClick(View view) {
+ ItemLongClickListener.INSTANCE_ALL_APPS.onLongClick(view);
+ handleSelection(SearchTargetEvent.LONG_PRESS);
+ return false;
+ }
+
+ static class ClickListener extends GestureDetector.SimpleOnGestureListener {
+ private final Runnable mCb;
+
+ ClickListener(Runnable cb) {
+ mCb = cb;
+ }
+
+ @Override
+ public boolean onSingleTapConfirmed(MotionEvent e) {
+ mCb.run();
+ return super.onSingleTapConfirmed(e);
+ }
+ }
+}
diff --git a/src/com/android/launcher3/views/SearchSettingsRowView.java b/src/com/android/launcher3/views/SearchSettingsRowView.java
index f0884f8..160ee65 100644
--- a/src/com/android/launcher3/views/SearchSettingsRowView.java
+++ b/src/com/android/launcher3/views/SearchSettingsRowView.java
@@ -15,8 +15,14 @@
*/
package com.android.launcher3.views;
+import static com.android.launcher3.FastBitmapDrawable.newIcon;
+import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
+import static com.android.launcher3.util.Executors.MODEL_EXECUTOR;
+
import android.content.Context;
import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
import android.os.Bundle;
import android.text.TextUtils;
import android.util.AttributeSet;
@@ -27,38 +33,41 @@
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
+import com.android.launcher3.FastBitmapDrawable;
import com.android.launcher3.Launcher;
+import com.android.launcher3.LauncherAppState;
import com.android.launcher3.R;
import com.android.launcher3.allapps.search.AllAppsSearchBarController;
import com.android.launcher3.allapps.search.SearchEventTracker;
+import com.android.launcher3.model.data.PackageItemInfo;
import com.android.systemui.plugins.shared.SearchTarget;
import com.android.systemui.plugins.shared.SearchTargetEvent;
import java.util.ArrayList;
+import java.util.List;
/**
- * A row of tappable TextViews with a breadcrumb for settings search.
+ * A row of clickable TextViews with a breadcrumb for settings search.
*/
public class SearchSettingsRowView extends LinearLayout implements
View.OnClickListener, AllAppsSearchBarController.SearchTargetHandler {
public static final String TARGET_TYPE_SETTINGS_ROW = "settings_row";
-
+ private View mIconView;
private TextView mTitleView;
- private TextView mDescriptionView;
private TextView mBreadcrumbsView;
private Intent mIntent;
private SearchTarget mSearchTarget;
public SearchSettingsRowView(@NonNull Context context) {
- super(context);
+ this(context, null, 0);
}
public SearchSettingsRowView(@NonNull Context context,
@Nullable AttributeSet attrs) {
- super(context, attrs);
+ this(context, attrs, 0);
}
public SearchSettingsRowView(@NonNull Context context, @Nullable AttributeSet attrs,
@@ -69,10 +78,11 @@
@Override
protected void onFinishInflate() {
super.onFinishInflate();
+ mIconView = findViewById(R.id.icon);
mTitleView = findViewById(R.id.title);
- mDescriptionView = findViewById(R.id.description);
mBreadcrumbsView = findViewById(R.id.breadcrumbs);
setOnClickListener(this);
+ applySettingsIcon(Launcher.getLauncher(getContext()), mIconView);
}
@Override
@@ -81,6 +91,7 @@
Bundle bundle = searchTarget.getExtras();
mIntent = bundle.getParcelable("intent");
showIfAvailable(mTitleView, bundle.getString("title"));
+ mIconView.setContentDescription(bundle.getString("title"));
ArrayList<String> breadcrumbs = bundle.getStringArrayList("breadcrumbs");
//TODO: implement RTL friendly breadcrumbs view
showIfAvailable(mBreadcrumbsView, breadcrumbs != null
@@ -113,4 +124,30 @@
SearchEventTracker.INSTANCE.get(getContext()).notifySearchTargetEvent(
new SearchTargetEvent.Builder(mSearchTarget, eventType).build());
}
+
+ /**
+ * Requests settings app icon from {@link com.android.launcher3.icons.IconCache} and applies
+ * to to view
+ */
+ public static void applySettingsIcon(Launcher launcher, View view) {
+ LauncherAppState appState = LauncherAppState.getInstance(launcher);
+ MODEL_EXECUTOR.post(() -> {
+ PackageItemInfo packageItemInfo = new PackageItemInfo(getSettingsPackageName(launcher));
+ appState.getIconCache().getTitleAndIconForApp(packageItemInfo, false);
+ MAIN_EXECUTOR.post(() -> {
+ FastBitmapDrawable iconDrawable = newIcon(appState.getContext(), packageItemInfo);
+ view.setBackground(iconDrawable);
+ });
+ });
+ }
+
+ private static String getSettingsPackageName(Launcher launcher) {
+ Intent intent = new Intent(android.provider.Settings.ACTION_SETTINGS);
+ List<ResolveInfo> resolveInfos = launcher.getPackageManager().queryIntentActivities(intent,
+ PackageManager.MATCH_DEFAULT_ONLY);
+ if (resolveInfos.size() == 0) {
+ return "";
+ }
+ return resolveInfos.get(0).activityInfo.packageName;
+ }
}
diff --git a/src/com/android/launcher3/views/SearchSliceWrapper.java b/src/com/android/launcher3/views/SearchSliceWrapper.java
deleted file mode 100644
index f8a7dc0..0000000
--- a/src/com/android/launcher3/views/SearchSliceWrapper.java
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- * 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.views;
-
-import android.content.Context;
-import android.net.Uri;
-import android.util.Log;
-
-import androidx.annotation.NonNull;
-import androidx.lifecycle.LiveData;
-import androidx.slice.Slice;
-import androidx.slice.SliceItem;
-import androidx.slice.widget.EventInfo;
-import androidx.slice.widget.SliceLiveData;
-import androidx.slice.widget.SliceView;
-
-import com.android.launcher3.Launcher;
-import com.android.launcher3.allapps.search.SearchEventTracker;
-import com.android.systemui.plugins.shared.SearchTarget;
-import com.android.systemui.plugins.shared.SearchTargetEvent;
-
-/**
- * A Wrapper class for {@link SliceView} search results
- */
-public class SearchSliceWrapper implements SliceView.OnSliceActionListener {
-
- public static final String TARGET_TYPE_SLICE = "settings_slice";
-
- private static final String TAG = "SearchSliceController";
- private static final String URI_EXTRA_KEY = "slice_uri";
-
-
- private final Launcher mLauncher;
- private final SearchTarget mSearchTarget;
- private final SliceView mSliceView;
- private LiveData<Slice> mSliceLiveData;
-
- public SearchSliceWrapper(Context context, SliceView sliceView, SearchTarget searchTarget) {
- mLauncher = Launcher.getLauncher(context);
- mSearchTarget = searchTarget;
- mSliceView = sliceView;
- sliceView.setOnSliceActionListener(this);
- try {
- mSliceLiveData = SliceLiveData.fromUri(mLauncher, getSliceUri());
- mSliceLiveData.observe((Launcher) mLauncher, sliceView);
- } catch (Exception ex) {
- Log.e(TAG, "unable to bind slice", ex);
- }
- }
-
- /**
- * Unregisters event handlers and removes lifecycle observer
- */
- public void destroy() {
- mSliceView.setOnSliceActionListener(null);
- mSliceLiveData.removeObservers(mLauncher);
- }
-
- @Override
- public void onSliceAction(@NonNull EventInfo info, @NonNull SliceItem item) {
- SearchEventTracker.INSTANCE.get(mLauncher).notifySearchTargetEvent(
- new SearchTargetEvent.Builder(mSearchTarget,
- SearchTargetEvent.CHILD_SELECT).build());
- }
-
- private Uri getSliceUri() {
- return mSearchTarget.getExtras().getParcelable(URI_EXTRA_KEY);
- }
-}
diff --git a/src/com/android/launcher3/views/ThumbnailSearchResultView.java b/src/com/android/launcher3/views/ThumbnailSearchResultView.java
index e929d7f..f213f22 100644
--- a/src/com/android/launcher3/views/ThumbnailSearchResultView.java
+++ b/src/com/android/launcher3/views/ThumbnailSearchResultView.java
@@ -15,8 +15,9 @@
*/
package com.android.launcher3.views;
-import static com.android.launcher3.views.SearchResultIconRow.REMOTE_ACTION_SHOULD_START;
-import static com.android.launcher3.views.SearchResultIconRow.REMOTE_ACTION_TOKEN;
+
+import static com.android.launcher3.views.SearchResultIcon.REMOTE_ACTION_SHOULD_START;
+import static com.android.launcher3.views.SearchResultIcon.REMOTE_ACTION_TOKEN;
import android.content.Context;
import android.content.Intent;
diff --git a/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java b/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
index d3fc89e..e118481 100644
--- a/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
+++ b/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
@@ -234,11 +234,25 @@
return mDevice;
}
+ private boolean hasSystemUiObject(String resId) {
+ return mDevice.hasObject(By.res(SYSTEMUI_PACKAGE, resId));
+ }
+
@Before
public void setUp() throws Exception {
- Assert.assertTrue("Keyguard is visible",
+ Log.d(TAG, "Before disabling battery defender");
+ mDevice.executeShellCommand("setprop vendor.battery.defender.disable 1");
+ Log.d(TAG, "Before enabling stay awake");
+ mDevice.executeShellCommand("settings put global stay_on_while_plugged_in 3");
+ for (int i = 0; i < 10 && hasSystemUiObject("keyguard_status_view"); ++i) {
+ Log.d(TAG, "Before unlocking the phone");
+ mDevice.executeShellCommand("input keyevent 82");
+ mDevice.waitForIdle();
+ }
+ Assert.assertTrue("Keyguard still visible",
mDevice.wait(
Until.gone(By.res(SYSTEMUI_PACKAGE, "keyguard_status_view")), 60000));
+ Log.d(TAG, "Keyguard is not visible");
final String launcherPackageName = mDevice.getLauncherPackageName();
try {
diff --git a/tests/src/com/android/launcher3/ui/WorkTabTest.java b/tests/src/com/android/launcher3/ui/WorkTabTest.java
index 8d594de..df0770d 100644
--- a/tests/src/com/android/launcher3/ui/WorkTabTest.java
+++ b/tests/src/com/android/launcher3/ui/WorkTabTest.java
@@ -65,12 +65,13 @@
String[] tokens = output.split("\\s+");
mProfileUserId = Integer.parseInt(tokens[tokens.length - 1]);
-
+ Log.d(TestProtocol.WORK_PROFILE_REMOVED, "Created new user uid" + mProfileUserId);
mDevice.executeShellCommand("am start-user " + mProfileUserId);
}
@After
public void removeWorkProfile() throws Exception {
+ Log.d(TestProtocol.WORK_PROFILE_REMOVED, "(teardown) removing uid" + mProfileUserId);
mDevice.executeShellCommand("pm remove-user " + mProfileUserId);
}