Merge "Fix logic around launchTask in the live tile case" into ub-launcher3-master
diff --git a/quickstep/res/values/strings.xml b/quickstep/res/values/strings.xml
index 769d298..b913ba4 100644
--- a/quickstep/res/values/strings.xml
+++ b/quickstep/res/values/strings.xml
@@ -149,6 +149,21 @@
<!-- Feedback shown during interactive parts of Assistant gesture tutorial when the gesture doesn't go far enough. [CHAR LIMIT=100] -->
<string name="assistant_gesture_feedback_swipe_not_long_enough" translatable="false">Try swiping further</string>
+ <!-- Title shown in sandbox mode part of gesture tutorial. [CHAR LIMIT=30] -->
+ <string name="sandbox_mode_title" translatable="false">Sandbox Mode</string>
+ <!-- Subtitle shown in sandbox mode part of gesture tutorial. [CHAR LIMIT=60] -->
+ <string name="sandbox_mode_subtitle" translatable="false">Try any navigation gesture</string>
+ <!-- Feedback shown in sandbox mode when the back gesture is successfully issued. [CHAR LIMIT=60] -->
+ <string name="sandbox_mode_back_gesture_feedback_successful" translatable="false">Back gesture successful</string>
+ <!-- Feedback shown in sandbox mode when the assistant gesture is a successfully issued. [CHAR LIMIT=60] -->
+ <string name="sandbox_mode_assistant_gesture_feedback_successful" translatable="false">Assistant gesture successful</string>
+ <!-- Feedback shown in sandbox mode when the home gesture is a successfully issued. [CHAR LIMIT=60] -->
+ <string name="sandbox_mode_home_gesture_feedback_successful" translatable="false">Home gesture successful</string>
+ <!-- Feedback shown in sandbox mode when the overview gesture is a successfully issued. [CHAR LIMIT=60] -->
+ <string name="sandbox_mode_overview_gesture_feedback_successful" translatable="false">Overview gesture successful</string>
+ <!-- Feedback shown in sandbox mode when the back gesture swipe is too far from the edge. [CHAR LIMIT=60] -->
+ <string name="sandbox_mode_back_gesture_feedback_swipe_too_far_from_edge" translatable="false">Make sure you swipe from the left/right edge of the screen</string>
+
<!-- Title shown on the confirmation screen after successful gesture. [CHAR LIMIT=30] -->
<string name="gesture_tutorial_confirm_title" translatable="false">All set</string>
<!-- Button text shown on a button on the confirm screen to leave the tutorial. [CHAR LIMIT=14] -->
diff --git a/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java b/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java
index 68111d2..54c2383 100644
--- a/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java
+++ b/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java
@@ -22,6 +22,8 @@
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.content.Intent;
@@ -307,4 +309,10 @@
public void setHintUserWillBeActive() {
addActivityFlags(ACTIVITY_STATE_USER_WILL_BE_ACTIVE);
}
+
+ @Override
+ public void onAttachedToWindow() {
+ super.onAttachedToWindow();
+ InteractionJankMonitorWrapper.init(getWindow().getDecorView());
+ }
}
diff --git a/quickstep/src/com/android/launcher3/LauncherAnimationRunner.java b/quickstep/src/com/android/launcher3/LauncherAnimationRunner.java
index 199cf63..75355c9 100644
--- a/quickstep/src/com/android/launcher3/LauncherAnimationRunner.java
+++ b/quickstep/src/com/android/launcher3/LauncherAnimationRunner.java
@@ -34,8 +34,7 @@
import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
@TargetApi(Build.VERSION_CODES.P)
-public abstract class LauncherAnimationRunner implements RemoteAnimationRunnerCompat,
- WrappedAnimationRunnerImpl {
+public abstract class LauncherAnimationRunner implements RemoteAnimationRunnerCompat {
private static final String TAG = "LauncherAnimationRunner";
diff --git a/quickstep/src/com/android/launcher3/QuickstepAppTransitionManagerImpl.java b/quickstep/src/com/android/launcher3/QuickstepAppTransitionManagerImpl.java
index dddcc86..d453bc3 100644
--- a/quickstep/src/com/android/launcher3/QuickstepAppTransitionManagerImpl.java
+++ b/quickstep/src/com/android/launcher3/QuickstepAppTransitionManagerImpl.java
@@ -66,6 +66,7 @@
import com.android.launcher3.DeviceProfile.OnDeviceProfileChangeListener;
import com.android.launcher3.allapps.AllAppsTransitionController;
+import com.android.launcher3.anim.AnimationSuccessListener;
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.dragndrop.DragLayer;
import com.android.launcher3.shortcuts.DeepShortcutView;
@@ -81,6 +82,7 @@
import com.android.quickstep.util.SurfaceTransactionApplier;
import com.android.systemui.shared.system.ActivityCompat;
import com.android.systemui.shared.system.ActivityOptionsCompat;
+import com.android.systemui.shared.system.InteractionJankMonitorWrapper;
import com.android.systemui.shared.system.QuickStepContract;
import com.android.systemui.shared.system.RemoteAnimationAdapterCompat;
import com.android.systemui.shared.system.RemoteAnimationDefinitionCompat;
@@ -791,6 +793,36 @@
== PackageManager.PERMISSION_GRANTED;
}
+ private void addCujInstrumentation(Animator anim, int cuj, String transition) {
+ if (Trace.isEnabled()) {
+ anim.addListener(new AnimationSuccessListener() {
+ @Override
+ public void onAnimationStart(Animator animation) {
+ Trace.beginAsyncSection(transition, 0);
+ InteractionJankMonitorWrapper.begin(cuj);
+ super.onAnimationStart(animation);
+ }
+
+ @Override
+ public void onAnimationCancel(Animator animation) {
+ super.onAnimationCancel(animation);
+ InteractionJankMonitorWrapper.cancel(cuj);
+ }
+
+ @Override
+ public void onAnimationSuccess(Animator animator) {
+ InteractionJankMonitorWrapper.end(cuj);
+ }
+
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ super.onAnimationEnd(animation);
+ Trace.endAsyncSection(TRANSITION_OPEN_LAUNCHER, 0);
+ }
+ });
+ }
+ }
+
/**
* Remote animation runner for animation from the app to Launcher, including recents.
*/
@@ -855,21 +887,9 @@
// is initialized.
if (launcherIsATargetWithMode(appTargets, MODE_OPENING)
|| mLauncher.isForceInvisible()) {
- if (Trace.isEnabled()) {
- anim.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationStart(Animator animation) {
- Trace.beginAsyncSection(TRANSITION_OPEN_LAUNCHER, 0);
- super.onAnimationStart(animation);
- }
-
- @Override
- public void onAnimationEnd(Animator animation) {
- super.onAnimationEnd(animation);
- Trace.endAsyncSection(TRANSITION_OPEN_LAUNCHER, 0);
- }
- });
- }
+ addCujInstrumentation(
+ anim, InteractionJankMonitorWrapper.CUJ_APP_CLOSE_TO_HOME,
+ TRANSITION_OPEN_LAUNCHER);
// Only register the content animation for cancellation when state changes
mLauncher.getStateManager().setCurrentAnimation(anim);
@@ -938,25 +958,12 @@
launcherClosing);
}
- if (Trace.isEnabled()) {
- final String section =
- launchingFromRecents
- ? TRANSITION_LAUNCH_FROM_RECENTS : TRANSITION_LAUNCH_FROM_ICON;
-
- anim.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationStart(Animator animation) {
- Trace.beginAsyncSection(section, 0);
- super.onAnimationStart(animation);
- }
-
- @Override
- public void onAnimationEnd(Animator animation) {
- super.onAnimationEnd(animation);
- Trace.endAsyncSection(section, 0);
- }
- });
- }
+ addCujInstrumentation(anim,
+ launchingFromRecents
+ ? InteractionJankMonitorWrapper.CUJ_APP_LAUNCH_FROM_RECENTS
+ : InteractionJankMonitorWrapper.CUJ_APP_LAUNCH_FROM_ICON,
+ launchingFromRecents
+ ? TRANSITION_LAUNCH_FROM_RECENTS : TRANSITION_LAUNCH_FROM_ICON);
if (launcherClosing) {
anim.addListener(mForceInvisibleListener);
diff --git a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
index 6774433..5e05a7d 100644
--- a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
+++ b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
@@ -97,6 +97,7 @@
import com.android.systemui.shared.recents.model.ThumbnailData;
import com.android.systemui.shared.system.ActivityManagerWrapper;
import com.android.systemui.shared.system.InputConsumerController;
+import com.android.systemui.shared.system.InteractionJankMonitorWrapper;
import com.android.systemui.shared.system.LatencyTrackerCompat;
import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
import com.android.systemui.shared.system.TaskInfoCompat;
@@ -1130,10 +1131,12 @@
anim.addOnUpdateListener((r, p) -> {
updateSysUiFlags(Math.max(p, mCurrentShift.value));
});
+ final int cuj = InteractionJankMonitorWrapper.CUJ_APP_CLOSE_TO_HOME;
anim.addAnimatorListener(new AnimationSuccessListener() {
@Override
public void onAnimationStart(Animator animation) {
Trace.beginAsyncSection(TRANSITION_OPEN_LAUNCHER, 0);
+ InteractionJankMonitorWrapper.begin(cuj);
if (mActivity != null) {
removeLiveTileOverlay();
}
@@ -1147,6 +1150,13 @@
// Make sure recents is in its final state
maybeUpdateRecentsAttachedState(false);
mActivityInterface.onSwipeUpToHomeComplete(mDeviceState);
+ InteractionJankMonitorWrapper.end(cuj);
+ }
+
+ @Override
+ public void onAnimationCancel(Animator animation) {
+ super.onAnimationCancel(animation);
+ InteractionJankMonitorWrapper.cancel(cuj);
}
@Override
diff --git a/quickstep/src/com/android/quickstep/RecentsActivity.java b/quickstep/src/com/android/quickstep/RecentsActivity.java
index 0e32c95..2f55f14 100644
--- a/quickstep/src/com/android/quickstep/RecentsActivity.java
+++ b/quickstep/src/com/android/quickstep/RecentsActivity.java
@@ -41,7 +41,10 @@
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.InvariantDeviceProfile;
import com.android.launcher3.LauncherAnimationRunner;
+import com.android.launcher3.LauncherAnimationRunner.AnimationResult;
import com.android.launcher3.R;
+import com.android.launcher3.WrappedAnimationRunnerImpl;
+import com.android.launcher3.WrappedLauncherAnimationRunner;
import com.android.launcher3.anim.Interpolators;
import com.android.launcher3.anim.PendingAnimation;
import com.android.launcher3.compat.AccessibilityManagerCompat;
@@ -87,6 +90,9 @@
private StateManager<RecentsState> mStateManager;
+ // Strong refs to runners which are cleared when the activity is destroyed
+ private WrappedAnimationRunnerImpl mActivityLaunchAnimationRunner;
+
/**
* Init drag layer and overview panel views.
*/
@@ -169,8 +175,11 @@
}
final TaskView taskView = (TaskView) v;
- RemoteAnimationRunnerCompat runner = new LauncherAnimationRunner(mUiHandler,
- true /* startAtFrontOfQueue */) {
+ mActivityLaunchAnimationRunner = new WrappedAnimationRunnerImpl() {
+ @Override
+ public Handler getHandler() {
+ return mUiHandler;
+ }
@Override
public void onCreateAnimation(RemoteAnimationTargetCompat[] appTargets,
@@ -181,8 +190,10 @@
result.setAnimation(anim, RecentsActivity.this);
}
};
+ final LauncherAnimationRunner wrapper = new WrappedLauncherAnimationRunner<>(
+ mActivityLaunchAnimationRunner, true /* startAtFrontOfQueue */);
return ActivityOptionsCompat.makeRemoteAnimation(new RemoteAnimationAdapterCompat(
- runner, RECENTS_LAUNCH_DURATION,
+ wrapper, RECENTS_LAUNCH_DURATION,
RECENTS_LAUNCH_DURATION - STATUS_BAR_TRANSITION_DURATION
- STATUS_BAR_TRANSITION_PRE_DELAY));
}
@@ -287,6 +298,7 @@
protected void onDestroy() {
super.onDestroy();
ACTIVITY_TRACKER.onActivityDestroyed(this);
+ mActivityLaunchAnimationRunner = null;
}
@Override
diff --git a/quickstep/src/com/android/quickstep/TouchInteractionService.java b/quickstep/src/com/android/quickstep/TouchInteractionService.java
index 4b5adcb..7bf8fba 100644
--- a/quickstep/src/com/android/quickstep/TouchInteractionService.java
+++ b/quickstep/src/com/android/quickstep/TouchInteractionService.java
@@ -683,7 +683,7 @@
final boolean disableHorizontalSwipe = mDeviceState.isInExclusionRegion(event);
return new OtherActivityInputConsumer(this, mDeviceState, mTaskAnimationManager,
gestureState, shouldDefer, this::onConsumerInactive,
- mInputMonitorCompat, disableHorizontalSwipe, factory);
+ mInputMonitorCompat, mInputEventReceiver, disableHorizontalSwipe, factory);
}
private InputConsumer createDeviceLockedInputConsumer(GestureState gestureState) {
@@ -732,6 +732,8 @@
private void reset() {
mConsumer = mUncheckedConsumer = mResetGestureInputConsumer;
mGestureState = DEFAULT_STATE;
+ // By default, use batching of the input events
+ mInputEventReceiver.setBatchingEnabled(true);
}
private void preloadOverview(boolean fromInit) {
diff --git a/quickstep/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java b/quickstep/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java
index b1a1133..35dbee9 100644
--- a/quickstep/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java
+++ b/quickstep/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java
@@ -67,6 +67,7 @@
import com.android.quickstep.util.MotionPauseDetector;
import com.android.quickstep.util.NavBarPosition;
import com.android.systemui.shared.system.ActivityManagerWrapper;
+import com.android.systemui.shared.system.InputChannelCompat.InputEventReceiver;
import com.android.systemui.shared.system.InputMonitorCompat;
import java.util.function.Consumer;
@@ -92,6 +93,7 @@
private RecentsAnimationCallbacks mActiveCallbacks;
private final CachedEventDispatcher mRecentsViewDispatcher = new CachedEventDispatcher();
private final InputMonitorCompat mInputMonitorCompat;
+ private final InputEventReceiver mInputEventReceiver;
private final BaseActivityInterface mActivityInterface;
private final AbsSwipeUpHandler.Factory mHandlerFactory;
@@ -135,8 +137,8 @@
public OtherActivityInputConsumer(Context base, RecentsAnimationDeviceState deviceState,
TaskAnimationManager taskAnimationManager, GestureState gestureState,
boolean isDeferredDownTarget, Consumer<OtherActivityInputConsumer> onCompleteCallback,
- InputMonitorCompat inputMonitorCompat, boolean disableHorizontalSwipe,
- Factory handlerFactory) {
+ InputMonitorCompat inputMonitorCompat, InputEventReceiver inputEventReceiver,
+ boolean disableHorizontalSwipe, Factory handlerFactory) {
super(base);
mDeviceState = deviceState;
mNavBarPosition = mDeviceState.getNavBarPosition();
@@ -154,6 +156,7 @@
mOnCompleteCallback = onCompleteCallback;
mVelocityTracker = VelocityTracker.obtain();
mInputMonitorCompat = inputMonitorCompat;
+ mInputEventReceiver = inputEventReceiver;
boolean continuingPreviousGesture = mTaskAnimationManager.isRecentsAnimationRunning();
mIsDeferredDownTarget = !continuingPreviousGesture && isDeferredDownTarget;
@@ -215,6 +218,9 @@
switch (ev.getActionMasked()) {
case ACTION_DOWN: {
+ // Until we detect the gesture, handle events as we receive them
+ mInputEventReceiver.setBatchingEnabled(false);
+
Object traceToken = TraceHelper.INSTANCE.beginSection(DOWN_EVT,
FLAG_CHECK_FOR_RACE_CONDITIONS);
mActivePointerId = ev.getPointerId(0);
@@ -351,6 +357,8 @@
}
TestLogging.recordEvent(TestProtocol.SEQUENCE_PILFER, "pilferPointers");
mInputMonitorCompat.pilferPointers();
+ // Once we detect the gesture, we can enable batching to reduce further updates
+ mInputEventReceiver.setBatchingEnabled(true);
mActivityInterface.closeOverlay();
ActivityManagerWrapper.getInstance().closeSystemWindows(
diff --git a/quickstep/src/com/android/quickstep/interaction/AssistantGestureTutorialFragment.java b/quickstep/src/com/android/quickstep/interaction/AssistantGestureTutorialFragment.java
index 70181fb..16886ec 100644
--- a/quickstep/src/com/android/quickstep/interaction/AssistantGestureTutorialFragment.java
+++ b/quickstep/src/com/android/quickstep/interaction/AssistantGestureTutorialFragment.java
@@ -24,7 +24,7 @@
/** Shows the Home gesture interactive tutorial. */
public class AssistantGestureTutorialFragment extends TutorialFragment {
@Override
- int getHandAnimationResId() {
+ Integer getHandAnimationResId() {
return R.drawable.assistant_gesture;
}
diff --git a/quickstep/src/com/android/quickstep/interaction/BackGestureTutorialFragment.java b/quickstep/src/com/android/quickstep/interaction/BackGestureTutorialFragment.java
index bef50ea..41db684 100644
--- a/quickstep/src/com/android/quickstep/interaction/BackGestureTutorialFragment.java
+++ b/quickstep/src/com/android/quickstep/interaction/BackGestureTutorialFragment.java
@@ -24,7 +24,7 @@
/** Shows the Back gesture interactive tutorial. */
public class BackGestureTutorialFragment extends TutorialFragment {
@Override
- int getHandAnimationResId() {
+ Integer getHandAnimationResId() {
return R.drawable.back_gesture;
}
diff --git a/quickstep/src/com/android/quickstep/interaction/HomeGestureTutorialFragment.java b/quickstep/src/com/android/quickstep/interaction/HomeGestureTutorialFragment.java
index e2a9d12..63595a5 100644
--- a/quickstep/src/com/android/quickstep/interaction/HomeGestureTutorialFragment.java
+++ b/quickstep/src/com/android/quickstep/interaction/HomeGestureTutorialFragment.java
@@ -21,7 +21,7 @@
/** Shows the Home gesture interactive tutorial. */
public class HomeGestureTutorialFragment extends TutorialFragment {
@Override
- int getHandAnimationResId() {
+ Integer getHandAnimationResId() {
return R.drawable.home_gesture;
}
diff --git a/quickstep/src/com/android/quickstep/interaction/OverviewGestureTutorialFragment.java b/quickstep/src/com/android/quickstep/interaction/OverviewGestureTutorialFragment.java
index 3357b70..93200bb 100644
--- a/quickstep/src/com/android/quickstep/interaction/OverviewGestureTutorialFragment.java
+++ b/quickstep/src/com/android/quickstep/interaction/OverviewGestureTutorialFragment.java
@@ -21,7 +21,7 @@
/** Shows the Overview gesture interactive tutorial. */
public class OverviewGestureTutorialFragment extends TutorialFragment {
@Override
- int getHandAnimationResId() {
+ Integer getHandAnimationResId() {
return R.drawable.overview_gesture;
}
diff --git a/quickstep/src/com/android/quickstep/interaction/SandboxModeTutorialController.java b/quickstep/src/com/android/quickstep/interaction/SandboxModeTutorialController.java
new file mode 100644
index 0000000..d54efc5
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/interaction/SandboxModeTutorialController.java
@@ -0,0 +1,102 @@
+/*
+ * 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.interaction;
+
+import android.graphics.PointF;
+import android.view.View;
+
+import androidx.annotation.Nullable;
+
+import com.android.launcher3.R;
+import com.android.quickstep.interaction.EdgeBackGestureHandler.BackGestureResult;
+import com.android.quickstep.interaction.NavBarGestureHandler.NavBarGestureResult;
+
+/** A {@link TutorialController} for the Sandbox Mode. */
+public class SandboxModeTutorialController extends SwipeUpGestureTutorialController {
+
+ SandboxModeTutorialController(SandboxModeTutorialFragment fragment, TutorialType tutorialType) {
+ super(fragment, tutorialType);
+ }
+
+ @Nullable
+ @Override
+ Integer getTitleStringId() {
+ return R.string.sandbox_mode_title;
+ }
+
+ @Nullable
+ @Override
+ Integer getSubtitleStringId() {
+ return R.string.sandbox_mode_subtitle;
+ }
+
+ @Nullable
+ @Override
+ Integer getActionButtonStringId() {
+ return R.string.gesture_tutorial_action_button_label_done;
+ }
+
+ @Override
+ void onActionButtonClicked(View button) {
+ mTutorialFragment.closeTutorial();
+ }
+
+ @Override
+ public void onBackGestureAttempted(BackGestureResult result) {
+ switch (result) {
+ case BACK_COMPLETED_FROM_LEFT:
+ case BACK_COMPLETED_FROM_RIGHT:
+ showRippleEffect(null);
+ showFeedback(R.string.sandbox_mode_back_gesture_feedback_successful);
+ break;
+ case BACK_CANCELLED_FROM_RIGHT:
+ showFeedback(R.string.back_gesture_feedback_cancelled_right_edge);
+ break;
+ case BACK_CANCELLED_FROM_LEFT:
+ showFeedback(R.string.back_gesture_feedback_cancelled_left_edge);
+ break;
+ case BACK_NOT_STARTED_TOO_FAR_FROM_EDGE:
+ showFeedback(R.string.sandbox_mode_back_gesture_feedback_swipe_too_far_from_edge);
+ break;
+ }
+ }
+
+ @Override
+ public void onNavBarGestureAttempted(NavBarGestureResult result, PointF finalVelocity) {
+ switch (result) {
+ case ASSISTANT_COMPLETED:
+ showRippleEffect(null);
+ showFeedback(R.string.sandbox_mode_assistant_gesture_feedback_successful);
+ break;
+ case HOME_GESTURE_COMPLETED:
+ animateFakeTaskViewHome(finalVelocity, () -> {
+ showFeedback(R.string.sandbox_mode_home_gesture_feedback_successful);
+ });
+ break;
+ case OVERVIEW_GESTURE_COMPLETED:
+ fadeOutFakeTaskView(true, () -> {
+ showFeedback(R.string.sandbox_mode_overview_gesture_feedback_successful);
+ });
+ break;
+ case HOME_OR_OVERVIEW_NOT_STARTED_WRONG_SWIPE_DIRECTION:
+ case HOME_OR_OVERVIEW_CANCELLED:
+ case HOME_NOT_STARTED_TOO_FAR_FROM_EDGE:
+ case OVERVIEW_NOT_STARTED_TOO_FAR_FROM_EDGE:
+ showFeedback(R.string.home_gesture_feedback_swipe_too_far_from_edge);
+ break;
+ }
+ }
+}
diff --git a/quickstep/src/com/android/quickstep/interaction/SandboxModeTutorialFragment.java b/quickstep/src/com/android/quickstep/interaction/SandboxModeTutorialFragment.java
new file mode 100644
index 0000000..955a2f7
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/interaction/SandboxModeTutorialFragment.java
@@ -0,0 +1,43 @@
+/*
+ * 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.interaction;
+
+import android.view.MotionEvent;
+import android.view.View;
+
+import com.android.quickstep.interaction.TutorialController.TutorialType;
+
+/** Shows the general navigation gesture sandbox environment. */
+public class SandboxModeTutorialFragment extends TutorialFragment {
+
+ @Override
+ TutorialController createController(TutorialType type) {
+ return new SandboxModeTutorialController(this, type);
+ }
+
+ @Override
+ Class<? extends TutorialController> getControllerClass() {
+ return SandboxModeTutorialController.class;
+ }
+
+ @Override
+ public boolean onTouch(View view, MotionEvent motionEvent) {
+ if (motionEvent.getAction() == MotionEvent.ACTION_DOWN && mTutorialController != null) {
+ mTutorialController.setRippleHotspot(motionEvent.getX(), motionEvent.getY());
+ }
+ return super.onTouch(view, motionEvent);
+ }
+}
diff --git a/quickstep/src/com/android/quickstep/interaction/TutorialController.java b/quickstep/src/com/android/quickstep/interaction/TutorialController.java
index db80342..2198ade 100644
--- a/quickstep/src/com/android/quickstep/interaction/TutorialController.java
+++ b/quickstep/src/com/android/quickstep/interaction/TutorialController.java
@@ -52,7 +52,7 @@
final View mFakeTaskView;
final View mRippleView;
final RippleDrawable mRippleDrawable;
- final TutorialHandAnimation mHandCoachingAnimation;
+ @Nullable final TutorialHandAnimation mHandCoachingAnimation;
final ImageView mHandCoachingView;
final Button mActionTextButton;
final Button mActionButton;
@@ -145,13 +145,16 @@
void onActionTextButtonClicked(View button) {}
void showHandCoachingAnimation() {
- if (isComplete()) {
+ if (isComplete() || mHandCoachingAnimation == null) {
return;
}
mHandCoachingAnimation.startLoopedAnimation(mTutorialType);
}
void hideHandCoachingAnimation() {
+ if (mHandCoachingAnimation == null) {
+ return;
+ }
mHandCoachingAnimation.stop();
mHandCoachingView.setVisibility(View.INVISIBLE);
}
@@ -210,7 +213,8 @@
return mTutorialType == TutorialType.BACK_NAVIGATION_COMPLETE
|| mTutorialType == TutorialType.HOME_NAVIGATION_COMPLETE
|| mTutorialType == TutorialType.OVERVIEW_NAVIGATION_COMPLETE
- || mTutorialType == TutorialType.ASSISTANT_COMPLETE;
+ || mTutorialType == TutorialType.ASSISTANT_COMPLETE
+ || mTutorialType == TutorialType.SANDBOX_MODE;
}
/** Denotes the type of the tutorial. */
@@ -223,6 +227,7 @@
OVERVIEW_NAVIGATION,
OVERVIEW_NAVIGATION_COMPLETE,
ASSISTANT,
- ASSISTANT_COMPLETE
+ ASSISTANT_COMPLETE,
+ SANDBOX_MODE
}
}
diff --git a/quickstep/src/com/android/quickstep/interaction/TutorialFragment.java b/quickstep/src/com/android/quickstep/interaction/TutorialFragment.java
index c90ad94..f297d5a 100644
--- a/quickstep/src/com/android/quickstep/interaction/TutorialFragment.java
+++ b/quickstep/src/com/android/quickstep/interaction/TutorialFragment.java
@@ -43,7 +43,7 @@
TutorialType mTutorialType;
@Nullable TutorialController mTutorialController = null;
View mRootView;
- TutorialHandAnimation mHandCoachingAnimation;
+ @Nullable TutorialHandAnimation mHandCoachingAnimation = null;
EdgeBackGestureHandler mEdgeBackGestureHandler;
NavBarGestureHandler mNavBarGestureHandler;
private View mLauncherView;
@@ -76,13 +76,17 @@
case ASSISTANT:
case ASSISTANT_COMPLETE:
return new AssistantGestureTutorialFragment();
+ case SANDBOX_MODE:
+ return new SandboxModeTutorialFragment();
default:
Log.e(LOG_TAG, "Failed to find an appropriate fragment for " + tutorialType.name());
}
return null;
}
- abstract int getHandAnimationResId();
+ @Nullable Integer getHandAnimationResId() {
+ return null;
+ }
abstract TutorialController createController(TutorialType type);
@@ -116,8 +120,11 @@
return insets;
});
mRootView.setOnTouchListener(this);
- mHandCoachingAnimation =
- new TutorialHandAnimation(getContext(), mRootView, getHandAnimationResId());
+ Integer handAnimationResId = getHandAnimationResId();
+ if (handAnimationResId != null) {
+ mHandCoachingAnimation =
+ new TutorialHandAnimation(getContext(), mRootView, handAnimationResId);
+ }
InvariantDeviceProfile dp = InvariantDeviceProfile.INSTANCE.get(getContext());
mLauncherView = new SandboxLauncherRenderer(getContext(), dp, true).getRenderedView();
((ViewGroup) mRootView).addView(mLauncherView, 0);
@@ -133,7 +140,10 @@
@Override
public void onPause() {
super.onPause();
- mHandCoachingAnimation.stop();
+
+ if (mHandCoachingAnimation != null) {
+ mHandCoachingAnimation.stop();
+ }
}
@Override
@@ -183,7 +193,7 @@
return mLauncherView;
}
- TutorialHandAnimation getHandAnimation() {
+ @Nullable TutorialHandAnimation getHandAnimation() {
return mHandCoachingAnimation;
}
diff --git a/quickstep/src/com/android/quickstep/util/RemoteAnimationProvider.java b/quickstep/src/com/android/quickstep/util/RemoteAnimationProvider.java
index 04308c8..19c6588 100644
--- a/quickstep/src/com/android/quickstep/util/RemoteAnimationProvider.java
+++ b/quickstep/src/com/android/quickstep/util/RemoteAnimationProvider.java
@@ -21,6 +21,8 @@
import android.os.Handler;
import com.android.launcher3.LauncherAnimationRunner;
+import com.android.launcher3.LauncherAnimationRunner.AnimationResult;
+import com.android.launcher3.WrappedAnimationRunnerImpl;
import com.android.launcher3.WrappedLauncherAnimationRunner;
import com.android.systemui.shared.system.ActivityOptionsCompat;
import com.android.systemui.shared.system.RemoteAnimationAdapterCompat;
@@ -28,14 +30,17 @@
public abstract class RemoteAnimationProvider {
- LauncherAnimationRunner mAnimationRunner;
+ WrappedAnimationRunnerImpl mAnimationRunner;
public abstract AnimatorSet createWindowAnimation(RemoteAnimationTargetCompat[] appTargets,
RemoteAnimationTargetCompat[] wallpaperTargets);
ActivityOptions toActivityOptions(Handler handler, long duration, Context context) {
- mAnimationRunner = new LauncherAnimationRunner(handler,
- false /* startAtFrontOfQueue */) {
+ mAnimationRunner = new WrappedAnimationRunnerImpl() {
+ @Override
+ public Handler getHandler() {
+ return handler;
+ }
@Override
public void onCreateAnimation(RemoteAnimationTargetCompat[] appTargets,
@@ -45,7 +50,6 @@
};
final LauncherAnimationRunner wrapper = new WrappedLauncherAnimationRunner(
mAnimationRunner, false /* startAtFrontOfQueue */);
-
return ActivityOptionsCompat.makeRemoteAnimation(
new RemoteAnimationAdapterCompat(wrapper, duration, 0));
}
diff --git a/res/layout/search_result_suggest.xml b/res/layout/search_result_suggest.xml
new file mode 100644
index 0000000..c5d96f0
--- /dev/null
+++ b/res/layout/search_result_suggest.xml
@@ -0,0 +1,38 @@
+<?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.SearchResultSuggestRow xmlns:android="http://schemas.android.com/apk/res/android"
+ style="@style/TextHeadline"
+ android:id="@+id/section_title"
+ android:background="?android:attr/selectableItemBackground"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical"
+ android:gravity="center_vertical"
+ android:padding="4dp"
+ android:minHeight="48dp"
+ android:textColor="?android:attr/textColorPrimary"
+ android:textSize="14sp">
+
+ <TextView
+ android:id="@+id/title"
+ style="@style/TextTitle"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:paddingStart="8dp"
+ android:layout_marginBottom="4dp"
+ android:textColor="?android:attr/textColorPrimary"
+ android:textSize="14sp" />
+
+</com.android.launcher3.views.SearchResultSuggestRow>
\ No newline at end of file
diff --git a/src/com/android/launcher3/allapps/AllAppsGridAdapter.java b/src/com/android/launcher3/allapps/AllAppsGridAdapter.java
index 81d94ba..8bc8e53 100644
--- a/src/com/android/launcher3/allapps/AllAppsGridAdapter.java
+++ b/src/com/android/launcher3/allapps/AllAppsGridAdapter.java
@@ -98,6 +98,8 @@
public static final int VIEW_TYPE_SEARCH_THUMBNAIL = 1 << 12;
+ public static final int VIEW_TYPE_SEARCH_SUGGEST = 1 << 13;
+
// 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;
@@ -189,7 +191,8 @@
|| viewType == VIEW_TYPE_SEARCH_ROW
|| viewType == VIEW_TYPE_SEARCH_PEOPLE
|| viewType == VIEW_TYPE_SEARCH_THUMBNAIL
- || viewType == VIEW_TYPE_SEARCH_ICON_ROW;
+ || viewType == VIEW_TYPE_SEARCH_ICON_ROW
+ || viewType == VIEW_TYPE_SEARCH_SUGGEST;
}
}
@@ -467,6 +470,9 @@
case VIEW_TYPE_SEARCH_THUMBNAIL:
return new ViewHolder(mLayoutInflater.inflate(
R.layout.search_result_thumbnail, parent, false));
+ case VIEW_TYPE_SEARCH_SUGGEST:
+ return new ViewHolder(mLayoutInflater.inflate(
+ R.layout.search_result_suggest, parent, false));
default:
throw new RuntimeException("Unexpected view type");
}
@@ -554,6 +560,7 @@
case VIEW_TYPE_SEARCH_ICON_ROW:
case VIEW_TYPE_SEARCH_PEOPLE:
case VIEW_TYPE_SEARCH_THUMBNAIL:
+ case VIEW_TYPE_SEARCH_SUGGEST:
AdapterItemWithPayload item =
(AdapterItemWithPayload) mApps.getAdapterItems().get(position);
PayloadResultHandler payloadResultView = (PayloadResultHandler) holder.itemView;
diff --git a/src/com/android/launcher3/model/LoaderTask.java b/src/com/android/launcher3/model/LoaderTask.java
index c0d5882..2b4520b 100644
--- a/src/com/android/launcher3/model/LoaderTask.java
+++ b/src/com/android/launcher3/model/LoaderTask.java
@@ -49,7 +49,6 @@
import android.util.TimingLogger;
import com.android.launcher3.LauncherAppState;
-import com.android.launcher3.LauncherAppWidgetProviderInfo;
import com.android.launcher3.LauncherModel;
import com.android.launcher3.LauncherSettings;
import com.android.launcher3.Utilities;
@@ -307,7 +306,6 @@
final PackageManagerHelper pmHelper = new PackageManagerHelper(context);
final boolean isSafeMode = pmHelper.isSafeMode();
final boolean isSdCardReady = Utilities.isBootCompleted();
- final WidgetManagerHelper widgetHelper = new WidgetManagerHelper(context);
boolean clearDb = false;
try {
@@ -393,7 +391,6 @@
WorkspaceItemInfo info;
LauncherAppWidgetInfo appWidgetInfo;
- LauncherAppWidgetProviderInfo widgetProviderInfo;
Intent intent;
String targetPkg;
@@ -723,19 +720,6 @@
+ appWidgetInfo.spanX + "x" + appWidgetInfo.spanY);
continue;
}
- widgetProviderInfo =
- widgetHelper.getLauncherAppWidgetInfo(appWidgetId);
- if (widgetProviderInfo != null
- && (appWidgetInfo.spanX < widgetProviderInfo.minSpanX
- || appWidgetInfo.spanY < widgetProviderInfo.minSpanY)) {
- // This can happen when display size changes.
- c.markDeleted("Widget removed, min sizes not met: "
- + "span=" + appWidgetInfo.spanX + "x"
- + appWidgetInfo.spanY + " minSpan="
- + widgetProviderInfo.minSpanX + "x"
- + widgetProviderInfo.minSpanY);
- continue;
- }
if (!c.isOnWorkspaceOrHotseat()) {
c.markDeleted("Widget found where container != " +
"CONTAINER_DESKTOP nor CONTAINER_HOTSEAT - ignoring!");
diff --git a/src/com/android/launcher3/popup/ArrowPopup.java b/src/com/android/launcher3/popup/ArrowPopup.java
index d5b32fc..90285c4 100644
--- a/src/com/android/launcher3/popup/ArrowPopup.java
+++ b/src/com/android/launcher3/popup/ArrowPopup.java
@@ -151,32 +151,52 @@
* @param viewsToFlip number of views from the top to to flip in case of reverse order
*/
protected void reorderAndShow(int viewsToFlip) {
+ setupForDisplay();
+ boolean reverseOrder = mIsAboveIcon;
+ if (reverseOrder) {
+ reverseOrder(viewsToFlip);
+ }
+ onInflationComplete(reverseOrder);
+ addArrow();
+ animateOpen();
+ }
+
+ /**
+ * Shows the popup at the desired location.
+ */
+ protected void show() {
+ setupForDisplay();
+ onInflationComplete(false);
+ addArrow();
+ animateOpen();
+ }
+
+ private void setupForDisplay() {
setVisibility(View.INVISIBLE);
mIsOpen = true;
getPopupContainer().addView(this);
orientAboutObject();
+ }
- boolean reverseOrder = mIsAboveIcon;
- if (reverseOrder) {
- int count = getChildCount();
- ArrayList<View> allViews = new ArrayList<>(count);
- for (int i = 0; i < count; i++) {
- if (i == viewsToFlip) {
- Collections.reverse(allViews);
- }
- allViews.add(getChildAt(i));
+ private void reverseOrder(int viewsToFlip) {
+ int count = getChildCount();
+ ArrayList<View> allViews = new ArrayList<>(count);
+ for (int i = 0; i < count; i++) {
+ if (i == viewsToFlip) {
+ Collections.reverse(allViews);
}
- Collections.reverse(allViews);
- removeAllViews();
- for (int i = 0; i < count; i++) {
- addView(allViews.get(i));
- }
-
- orientAboutObject();
+ allViews.add(getChildAt(i));
}
- onInflationComplete(reverseOrder);
+ Collections.reverse(allViews);
+ removeAllViews();
+ for (int i = 0; i < count; i++) {
+ addView(allViews.get(i));
+ }
- // Add the arrow.
+ orientAboutObject();
+ }
+
+ private void addArrow() {
final Resources res = getResources();
final int arrowCenterOffset = res.getDimensionPixelSize(isAlignedWithStart()
? R.dimen.popup_arrow_horizontal_center_start
@@ -214,8 +234,6 @@
mArrow.setPivotX(arrowLp.width / 2);
mArrow.setPivotY(mIsAboveIcon ? arrowLp.height : 0);
-
- animateOpen();
}
protected boolean isAlignedWithStart() {
diff --git a/src/com/android/launcher3/settings/DeveloperOptionsFragment.java b/src/com/android/launcher3/settings/DeveloperOptionsFragment.java
index 4baecb7..f4b059d 100644
--- a/src/com/android/launcher3/settings/DeveloperOptionsFragment.java
+++ b/src/com/android/launcher3/settings/DeveloperOptionsFragment.java
@@ -306,6 +306,15 @@
return true;
});
sandboxCategory.addPreference(launchAssistantTutorialPreference);
+ Preference launchSandboxModeTutorialPreference = new Preference(context);
+ launchSandboxModeTutorialPreference.setKey("launchSandboxMode");
+ launchSandboxModeTutorialPreference.setTitle("Launch Sandbox Mode");
+ launchSandboxModeTutorialPreference.setSummary("Practice navigation gestures");
+ launchSandboxModeTutorialPreference.setOnPreferenceClickListener(preference -> {
+ startActivity(launchSandboxIntent.putExtra("tutorial_type", "SANDBOX_MODE"));
+ return true;
+ });
+ sandboxCategory.addPreference(launchSandboxModeTutorialPreference);
}
private String toName(String action) {
diff --git a/src/com/android/launcher3/views/FloatingIconView.java b/src/com/android/launcher3/views/FloatingIconView.java
index 52a82f8..d9a14e9 100644
--- a/src/com/android/launcher3/views/FloatingIconView.java
+++ b/src/com/android/launcher3/views/FloatingIconView.java
@@ -15,7 +15,6 @@
*/
package com.android.launcher3.views;
-import static com.android.launcher3.LauncherAnimUtils.DRAWABLE_ALPHA;
import static com.android.launcher3.Utilities.getBadge;
import static com.android.launcher3.Utilities.getFullDrawable;
import static com.android.launcher3.config.FeatureFlags.ADAPTIVE_ICON_WINDOW_ANIM;
@@ -23,9 +22,6 @@
import static com.android.launcher3.views.IconLabelDotView.setIconAndDotVisible;
import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
-import android.animation.AnimatorSet;
-import android.animation.ObjectAnimator;
import android.annotation.TargetApi;
import android.content.Context;
import android.graphics.Canvas;
@@ -74,7 +70,6 @@
private static @Nullable IconLoadResult sIconLoadResult;
public static final float SHAPE_PROGRESS_DURATION = 0.10f;
- private static final int FADE_DURATION_MS = 200;
private static final RectF sTmpRectF = new RectF();
private static final Object[] sTmpObjArray = new Object[1];
@@ -89,6 +84,9 @@
private IconLoadResult mIconLoadResult;
+ // Draw the drawable of the BubbleTextView behind ClipIconView to reveal the built in shadow.
+ private View mBtvDrawable;
+
private ClipIconView mClipIconView;
private @Nullable Drawable mBadge;
@@ -98,7 +96,6 @@
private final Rect mFinalDrawableBounds = new Rect();
- private AnimatorSet mFadeAnimatorSet;
private ListenerView mListenerView;
private Runnable mFastFinishRunnable;
@@ -116,6 +113,8 @@
mIsRtl = Utilities.isRtl(getResources());
mListenerView = new ListenerView(context, attrs);
mClipIconView = new ClipIconView(context, attrs);
+ mBtvDrawable = new ImageView(context, attrs);
+ addView(mBtvDrawable);
addView(mClipIconView);
setWillNotDraw(false);
}
@@ -176,6 +175,7 @@
setLayoutParams(lp);
mClipIconView.setLayoutParams(new FrameLayout.LayoutParams(lp.width, lp.height));
+ mBtvDrawable.setLayoutParams(new FrameLayout.LayoutParams(lp.width, lp.height));
}
private void updatePosition(RectF pos, InsettableFrameLayout.LayoutParams lp) {
@@ -292,6 +292,8 @@
drawable = drawable == null ? null : drawable.getConstantState().newDrawable();
int iconOffset = getOffsetForIconBounds(l, drawable, pos);
synchronized (iconLoadResult) {
+ iconLoadResult.btvDrawable = btvIcon == null || drawable == btvIcon
+ ? null : btvIcon.getConstantState().newDrawable();
iconLoadResult.drawable = drawable;
iconLoadResult.badge = badge;
iconLoadResult.iconOffset = iconOffset;
@@ -311,7 +313,8 @@
* @param iconOffset The amount of offset needed to match this view with the original view.
*/
@UiThread
- private void setIcon(@Nullable Drawable drawable, @Nullable Drawable badge, int iconOffset) {
+ private void setIcon(@Nullable Drawable drawable, @Nullable Drawable badge,
+ @Nullable Drawable btvIcon, int iconOffset) {
final InsettableFrameLayout.LayoutParams lp =
(InsettableFrameLayout.LayoutParams) getLayoutParams();
mBadge = badge;
@@ -342,6 +345,10 @@
mBadge.setBounds(0, 0, clipViewOgWidth, clipViewOgHeight);
}
}
+
+ if (!mIsOpening && btvIcon != null) {
+ mBtvDrawable.setBackground(btvIcon);
+ }
invalidate();
}
@@ -360,7 +367,7 @@
synchronized (mIconLoadResult) {
if (mIconLoadResult.isIconLoaded) {
setIcon(mIconLoadResult.drawable, mIconLoadResult.badge,
- mIconLoadResult.iconOffset);
+ mIconLoadResult.btvDrawable, mIconLoadResult.iconOffset);
setIconAndDotVisible(originalView, false);
} else {
mIconLoadResult.onIconLoaded = () -> {
@@ -369,7 +376,7 @@
}
setIcon(mIconLoadResult.drawable, mIconLoadResult.badge,
- mIconLoadResult.iconOffset);
+ mIconLoadResult.btvDrawable, mIconLoadResult.iconOffset);
setVisibility(VISIBLE);
setIconAndDotVisible(originalView, false);
@@ -434,10 +441,6 @@
mEndRunnable.run();
mEndRunnable = null;
}
- if (mFadeAnimatorSet != null) {
- mFadeAnimatorSet.end();
- mFadeAnimatorSet = null;
- }
}
@Override
@@ -546,8 +549,16 @@
setIconAndDotVisible(originalView, true);
view.finish(dragLayer);
} else {
- view.mFadeAnimatorSet = view.createFadeAnimation(originalView, dragLayer);
- view.mFadeAnimatorSet.start();
+ originalView.setVisibility(VISIBLE);
+ if (originalView instanceof IconLabelDotView) {
+ setIconAndDotVisible(originalView, true);
+ }
+ if (originalView instanceof BubbleTextView) {
+ BubbleTextView btv = (BubbleTextView) originalView;
+ btv.setIconVisible(true);
+ btv.setForceHideDot(true);
+ }
+ view.finish(dragLayer);
}
} else {
view.finish(dragLayer);
@@ -564,47 +575,6 @@
return view;
}
- private AnimatorSet createFadeAnimation(View originalView, DragLayer dragLayer) {
- AnimatorSet fade = new AnimatorSet();
- fade.setDuration(FADE_DURATION_MS);
- fade.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationStart(Animator animation) {
- originalView.setVisibility(VISIBLE);
- }
-
- @Override
- public void onAnimationEnd(Animator animation) {
- finish(dragLayer);
- }
- });
-
- if (originalView instanceof IconLabelDotView) {
- fade.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- setIconAndDotVisible(originalView, true);
- }
- });
- }
-
- if (originalView instanceof BubbleTextView) {
- BubbleTextView btv = (BubbleTextView) originalView;
- fade.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationStart(Animator animation) {
- btv.setIconVisible(true);
- btv.setForceHideDot(true);
- }
- });
- fade.play(ObjectAnimator.ofInt(btv.getIcon(), DRAWABLE_ALPHA, 0, 255));
- } else if (!(originalView instanceof FolderIcon)) {
- fade.play(ObjectAnimator.ofFloat(originalView, ALPHA, 0f, 1f));
- }
-
- return fade;
- }
-
private void finish(DragLayer dragLayer) {
((ViewGroup) dragLayer.getParent()).removeView(this);
dragLayer.removeView(mListenerView);
@@ -628,11 +598,7 @@
mLoadIconSignal = null;
mEndRunnable = null;
mFinalDrawableBounds.setEmpty();
- if (mFadeAnimatorSet != null) {
- mFadeAnimatorSet.cancel();
- }
mPositionOut = null;
- mFadeAnimatorSet = null;
mListenerView.setListener(null);
mOriginalIcon = null;
mOnTargetChangeRunnable = null;
@@ -640,11 +606,13 @@
sTmpObjArray[0] = null;
mIconLoadResult = null;
mClipIconView.recycle();
+ mBtvDrawable.setBackground(null);
mFastFinishRunnable = null;
}
private static class IconLoadResult {
final ItemInfo itemInfo;
+ Drawable btvDrawable;
Drawable drawable;
Drawable badge;
int iconOffset;
diff --git a/src/com/android/launcher3/views/OptionsPopupView.java b/src/com/android/launcher3/views/OptionsPopupView.java
index a8caa9e..80f0981 100644
--- a/src/com/android/launcher3/views/OptionsPopupView.java
+++ b/src/com/android/launcher3/views/OptionsPopupView.java
@@ -133,7 +133,7 @@
view.setOnLongClickListener(popup);
popup.mItemMap.put(view, item);
}
- popup.reorderAndShow(popup.getChildCount());
+ popup.show();
}
@VisibleForTesting
diff --git a/src/com/android/launcher3/views/SearchResultIconRow.java b/src/com/android/launcher3/views/SearchResultIconRow.java
index 57c85cf..313ae5e 100644
--- a/src/com/android/launcher3/views/SearchResultIconRow.java
+++ b/src/com/android/launcher3/views/SearchResultIconRow.java
@@ -42,6 +42,7 @@
import com.android.launcher3.touch.ItemClickHandler;
import com.android.systemui.plugins.AllAppsSearchPlugin;
import com.android.systemui.plugins.shared.SearchTarget;
+import com.android.systemui.plugins.shared.SearchTarget.ItemType;
import com.android.systemui.plugins.shared.SearchTargetEvent;
/**
@@ -138,7 +139,7 @@
} else {
RemoteActionItemInfo remoteItemInfo = (RemoteActionItemInfo) itemInfo;
ItemClickHandler.onClickRemoteAction(launcher, remoteItemInfo);
- searchTargetEvent = getSearchTargetEvent(SearchTarget.ItemType.REMOTE_ACTION,
+ searchTargetEvent = getSearchTargetEvent(ItemType.ACTION,
eventType);
searchTargetEvent.bundle = new Bundle();
searchTargetEvent.remoteAction = remoteItemInfo.getRemoteAction();
diff --git a/src/com/android/launcher3/views/SearchResultPeopleView.java b/src/com/android/launcher3/views/SearchResultPeopleView.java
index eacc095..0c9a22f 100644
--- a/src/com/android/launcher3/views/SearchResultPeopleView.java
+++ b/src/com/android/launcher3/views/SearchResultPeopleView.java
@@ -15,9 +15,6 @@
*/
package com.android.launcher3.views;
-import static android.content.Intent.URI_ALLOW_UNSAFE;
-import static android.content.Intent.URI_ANDROID_APP_SCHEME;
-
import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
@@ -28,7 +25,6 @@
import android.graphics.Bitmap;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
-import android.net.Uri;
import android.os.Bundle;
import android.util.AttributeSet;
import android.view.View;
@@ -50,7 +46,6 @@
import com.android.systemui.plugins.shared.SearchTarget;
import com.android.systemui.plugins.shared.SearchTargetEvent;
-import java.net.URISyntaxException;
import java.util.ArrayList;
/**
@@ -66,7 +61,7 @@
private TextView mTitleView;
private ImageButton[] mProviderButtons = new ImageButton[3];
private AllAppsSearchPlugin mPlugin;
- private Uri mContactUri;
+ private Intent mIntent;
private final Object[] mTargetInfo = createTargetInfo();
public SearchResultPeopleView(Context context) {
@@ -109,7 +104,7 @@
Bundle payload = adapterItemWithPayload.getPayload();
mPlugin = adapterItemWithPayload.getPlugin();
mTitleView.setText(payload.getString("title"));
- mContactUri = payload.getParcelable("contact_uri");
+ mIntent = payload.getParcelable("intent");
Bitmap icon = payload.getParcelable("icon");
if (icon != null) {
RoundedBitmapDrawable d = RoundedBitmapDrawableFactory.create(getResources(), icon);
@@ -125,25 +120,20 @@
for (int i = 0; i < mProviderButtons.length; i++) {
ImageButton button = mProviderButtons[i];
if (providers != null && i < providers.size()) {
- try {
- Bundle provider = providers.get(i);
- Intent intent = Intent.parseUri(provider.getString("intent_uri_str"),
- URI_ANDROID_APP_SCHEME | URI_ALLOW_UNSAFE);
- setupProviderButton(button, provider, intent, adapterItemWithPayload);
- String pkg = provider.getString("package_name");
- UI_HELPER_EXECUTOR.post(() -> {
- try {
- ApplicationInfo applicationInfo = mPackageManager.getApplicationInfo(
- pkg, 0);
- Drawable appIcon = applicationInfo.loadIcon(mPackageManager);
- MAIN_EXECUTOR.post(() -> button.setImageDrawable(appIcon));
- } catch (PackageManager.NameNotFoundException ignored) {
- }
+ Bundle provider = providers.get(i);
+ Intent intent = provider.getParcelable("intent");
+ setupProviderButton(button, provider, intent, adapterItemWithPayload);
+ String pkg = provider.getString("package_name");
+ UI_HELPER_EXECUTOR.post(() -> {
+ try {
+ ApplicationInfo applicationInfo = mPackageManager.getApplicationInfo(
+ pkg, 0);
+ Drawable appIcon = applicationInfo.loadIcon(mPackageManager);
+ MAIN_EXECUTOR.post(() -> button.setImageDrawable(appIcon));
+ } catch (PackageManager.NameNotFoundException ignored) {
+ }
- });
- } catch (URISyntaxException ex) {
- button.setVisibility(GONE);
- }
+ });
} else {
button.setVisibility(GONE);
}
@@ -165,7 +155,7 @@
SearchTarget.ItemType.PEOPLE,
SearchTargetEvent.CHILD_SELECT);
searchTargetEvent.bundle = new Bundle();
- searchTargetEvent.bundle.putParcelable("contact_uri", mContactUri);
+ searchTargetEvent.bundle.putParcelable("intent", mIntent);
searchTargetEvent.bundle.putBundle("provider", provider);
if (mPlugin != null) {
mPlugin.notifySearchTargetEvent(searchTargetEvent);
@@ -175,14 +165,13 @@
private void handleSelection(int eventType) {
- if (mContactUri != null) {
+ if (mIntent != null) {
Launcher launcher = Launcher.getLauncher(getContext());
- launcher.startActivitySafely(this, new Intent(Intent.ACTION_VIEW, mContactUri).setFlags(
- Intent.FLAG_ACTIVITY_NEW_TASK), null);
+ launcher.startActivitySafely(this, mIntent, null);
SearchTargetEvent searchTargetEvent = getSearchTargetEvent(SearchTarget.ItemType.PEOPLE,
eventType);
searchTargetEvent.bundle = new Bundle();
- searchTargetEvent.bundle.putParcelable("contact_uri", mContactUri);
+ searchTargetEvent.bundle.putParcelable("intent", mIntent);
if (mPlugin != null) {
mPlugin.notifySearchTargetEvent(searchTargetEvent);
}
diff --git a/src/com/android/launcher3/views/SearchResultSuggestRow.java b/src/com/android/launcher3/views/SearchResultSuggestRow.java
new file mode 100644
index 0000000..b5abbcc
--- /dev/null
+++ b/src/com/android/launcher3/views/SearchResultSuggestRow.java
@@ -0,0 +1,131 @@
+/*
+ * 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.systemui.plugins.shared.SearchTarget.ItemType.SUGGEST;
+
+import android.content.Context;
+import android.os.Bundle;
+import android.text.TextUtils;
+import android.util.AttributeSet;
+import android.view.View;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+import com.android.launcher3.Launcher;
+import com.android.launcher3.R;
+import com.android.launcher3.allapps.AllAppsGridAdapter.AdapterItemWithPayload;
+import com.android.launcher3.allapps.search.AllAppsSearchBarController;
+import com.android.launcher3.model.data.ItemInfo;
+import com.android.launcher3.model.data.RemoteActionItemInfo;
+import com.android.launcher3.touch.ItemClickHandler;
+import com.android.systemui.plugins.AllAppsSearchPlugin;
+import com.android.systemui.plugins.shared.SearchTarget;
+import com.android.systemui.plugins.shared.SearchTargetEvent;
+
+/**
+ * A view representing a fallback search suggestion row.
+ */
+public class SearchResultSuggestRow extends LinearLayout implements
+ View.OnClickListener, AllAppsSearchBarController.PayloadResultHandler<SearchTarget> {
+
+ private final Object[] mTargetInfo = createTargetInfo();
+ private AllAppsSearchPlugin mPlugin;
+ private AdapterItemWithPayload<SearchTarget> mAdapterItem;
+ private TextView mTitle;
+
+
+ public SearchResultSuggestRow(@NonNull Context context) {
+ super(context);
+ }
+
+ public SearchResultSuggestRow(@NonNull Context context,
+ @Nullable AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ public SearchResultSuggestRow(@NonNull Context context, @Nullable AttributeSet attrs,
+ int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ }
+
+ @Override
+ protected void onFinishInflate() {
+ super.onFinishInflate();
+ mTitle = findViewById(R.id.title);
+ setOnClickListener(this);
+ }
+ @Override
+ public void applyAdapterInfo(AdapterItemWithPayload<SearchTarget> adapterItemWithPayload) {
+ mAdapterItem = adapterItemWithPayload;
+ SearchTarget payload = adapterItemWithPayload.getPayload();
+ mPlugin = adapterItemWithPayload.getPlugin();
+
+ if (payload.mRemoteAction != null) {
+ RemoteActionItemInfo itemInfo = new RemoteActionItemInfo(payload.mRemoteAction,
+ payload.bundle.getString(SearchTarget.REMOTE_ACTION_TOKEN),
+ payload.bundle.getBoolean(SearchTarget.REMOTE_ACTION_SHOULD_START));
+ setTag(itemInfo);
+ }
+ showIfAvailable(mTitle, payload.mRemoteAction.getTitle().toString());
+ setOnClickListener(v -> handleSelection(SearchTargetEvent.SELECT));
+ adapterItemWithPayload.setSelectionHandler(this::handleSelection);
+ }
+
+ @Override
+ public Object[] getTargetInfo() {
+ return mTargetInfo;
+ }
+
+ private void handleSelection(int eventType) {
+ ItemInfo itemInfo = (ItemInfo) getTag();
+ Launcher launcher = Launcher.getLauncher(getContext());
+ if (itemInfo instanceof RemoteActionItemInfo) return;
+
+ RemoteActionItemInfo remoteItemInfo = (RemoteActionItemInfo) itemInfo;
+ ItemClickHandler.onClickRemoteAction(launcher, remoteItemInfo);
+ SearchTargetEvent searchTargetEvent = getSearchTargetEvent(SUGGEST, eventType);
+ searchTargetEvent.bundle = new Bundle();
+ searchTargetEvent.remoteAction = remoteItemInfo.getRemoteAction();
+ searchTargetEvent.bundle.putBoolean(SearchTarget.REMOTE_ACTION_SHOULD_START,
+ remoteItemInfo.shouldStartInLauncher());
+ searchTargetEvent.bundle.putString(SearchTarget.REMOTE_ACTION_TOKEN,
+ remoteItemInfo.getToken());
+
+ if (mPlugin != null) {
+ mPlugin.notifySearchTargetEvent(searchTargetEvent);
+ }
+ }
+
+ @Override
+ public void onClick(View view) {
+ handleSelection(SearchTargetEvent.SELECT);
+ }
+
+ private void showIfAvailable(TextView view, @Nullable String string) {
+ System.out.println("Plugin suggest string:" + string);
+ if (TextUtils.isEmpty(string)) {
+ view.setVisibility(GONE);
+ } else {
+ System.out.println("Plugin suggest string:" + string);
+ view.setVisibility(VISIBLE);
+ view.setText(string);
+ }
+ }
+}
diff --git a/src/com/android/launcher3/views/ThumbnailSearchResultView.java b/src/com/android/launcher3/views/ThumbnailSearchResultView.java
index 1d58a06..bbc4773 100644
--- a/src/com/android/launcher3/views/ThumbnailSearchResultView.java
+++ b/src/com/android/launcher3/views/ThumbnailSearchResultView.java
@@ -18,8 +18,8 @@
import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
+import android.graphics.drawable.BitmapDrawable;
import android.net.Uri;
-import android.os.Bundle;
import android.util.AttributeSet;
import androidx.core.graphics.drawable.RoundedBitmapDrawable;
@@ -28,6 +28,10 @@
import com.android.launcher3.Launcher;
import com.android.launcher3.allapps.AllAppsGridAdapter.AdapterItemWithPayload;
import com.android.launcher3.allapps.search.AllAppsSearchBarController;
+import com.android.launcher3.model.data.ItemInfo;
+import com.android.launcher3.model.data.RemoteActionItemInfo;
+import com.android.launcher3.model.data.WorkspaceItemInfo;
+import com.android.launcher3.touch.ItemClickHandler;
import com.android.launcher3.util.Themes;
import com.android.systemui.plugins.AllAppsSearchPlugin;
import com.android.systemui.plugins.shared.SearchTarget;
@@ -37,10 +41,9 @@
* A view representing a high confidence app search result that includes shortcuts
*/
public class ThumbnailSearchResultView extends androidx.appcompat.widget.AppCompatImageView
- implements AllAppsSearchBarController.PayloadResultHandler<Bundle> {
+ implements AllAppsSearchBarController.PayloadResultHandler<SearchTarget> {
private final Object[] mTargetInfo = createTargetInfo();
- Intent mIntent;
AllAppsSearchPlugin mPlugin;
int mPosition;
@@ -58,26 +61,48 @@
private void handleSelection(int eventType) {
Launcher launcher = Launcher.getLauncher(getContext());
- launcher.startActivitySafely(this, mIntent, null);
-
- SearchTargetEvent event = getSearchTargetEvent(
- SearchTarget.ItemType.SCREENSHOT, eventType);
+ ItemInfo itemInfo = (ItemInfo) getTag();
+ if (itemInfo instanceof RemoteActionItemInfo) {
+ RemoteActionItemInfo remoteItemInfo = (RemoteActionItemInfo) itemInfo;
+ ItemClickHandler.onClickRemoteAction(launcher, remoteItemInfo);
+ } else {
+ ItemClickHandler.onClickAppShortcut(this, (WorkspaceItemInfo) itemInfo, launcher);
+ }
if (mPlugin != null) {
+ SearchTargetEvent event = getSearchTargetEvent(
+ SearchTarget.ItemType.SCREENSHOT, eventType);
mPlugin.notifySearchTargetEvent(event);
}
}
@Override
- public void applyAdapterInfo(AdapterItemWithPayload<Bundle> adapterItem) {
+ public void applyAdapterInfo(AdapterItemWithPayload<SearchTarget> adapterItem) {
+ Launcher launcher = Launcher.getLauncher(getContext());
mPosition = adapterItem.position;
- RoundedBitmapDrawable drawable = RoundedBitmapDrawableFactory.create(null,
- (Bitmap) adapterItem.getPayload().getParcelable("bitmap"));
+
+ SearchTarget target = adapterItem.getPayload();
+ Bitmap bitmap;
+ if (target.mRemoteAction != null) {
+ RemoteActionItemInfo itemInfo = new RemoteActionItemInfo(target.mRemoteAction,
+ target.bundle.getString(SearchTarget.REMOTE_ACTION_TOKEN),
+ target.bundle.getBoolean(SearchTarget.REMOTE_ACTION_SHOULD_START));
+ ItemClickHandler.onClickRemoteAction(launcher, itemInfo);
+ bitmap = ((BitmapDrawable) target.mRemoteAction.getIcon()
+ .loadDrawable(getContext())).getBitmap();
+ setTag(itemInfo);
+ } else {
+ bitmap = (Bitmap) target.bundle.getParcelable("bitmap");
+ WorkspaceItemInfo itemInfo = new WorkspaceItemInfo();
+ itemInfo.intent = new Intent(Intent.ACTION_VIEW)
+ .setData(Uri.parse(target.bundle.getString("uri")))
+ .setType("image/*")
+ .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ setTag(itemInfo);
+ }
+ RoundedBitmapDrawable drawable = RoundedBitmapDrawableFactory.create(null, bitmap);
drawable.setCornerRadius(Themes.getDialogCornerRadius(getContext()));
setImageDrawable(drawable);
- mIntent = new Intent(Intent.ACTION_VIEW)
- .setData(Uri.parse(adapterItem.getPayload().getString("uri")))
- .setType("image/*")
- .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ setOnClickListener(v -> handleSelection(SearchTargetEvent.SELECT));
mPlugin = adapterItem.getPlugin();
adapterItem.setSelectionHandler(this::handleSelection);
}
diff --git a/src_plugins/com/android/systemui/plugins/shared/SearchTarget.java b/src_plugins/com/android/systemui/plugins/shared/SearchTarget.java
index 9d9ccba..3f0dc39 100644
--- a/src_plugins/com/android/systemui/plugins/shared/SearchTarget.java
+++ b/src_plugins/com/android/systemui/plugins/shared/SearchTarget.java
@@ -80,7 +80,12 @@
* N number of 1x1 ratio thumbnail is rendered.
* (current N = 3)
*/
- THUMBNAIL(8);
+ THUMBNAIL(8),
+
+ /**
+ * Fallback search icon and relevant text is rendered.
+ */
+ SUGGEST(9);
private final int mId;
@@ -102,7 +107,9 @@
SHORTCUT(5, "Shortcuts", ViewType.SHORTCUT),
PEOPLE(6, "People", ViewType.PEOPLE),
SCREENSHOT(7, "Screenshots", ViewType.THUMBNAIL),
- REMOTE_ACTION(8, "Remote Actions", ViewType.SHORTCUT);
+ ACTION(8, "Actions", ViewType.SHORTCUT),
+ SUGGEST(9, "Fallback Search", ViewType.SUGGEST),
+ CHROME_TAB(10, "Chrome Tab", ViewType.SHORTCUT);
private final int mId;
diff --git a/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java b/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
index 5e42d9b..e118481 100644
--- a/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
+++ b/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
@@ -279,6 +279,8 @@
if (userManager != null) {
for (UserHandle userHandle : userManager.getUserProfiles()) {
if (!userHandle.isSystem()) {
+ Log.d(TestProtocol.WORK_PROFILE_REMOVED,
+ "removing user " + userHandle.getIdentifier());
mDevice.executeShellCommand("pm remove-user " + userHandle.getIdentifier());
}
}
diff --git a/tests/src/com/android/launcher3/ui/WorkTabTest.java b/tests/src/com/android/launcher3/ui/WorkTabTest.java
index 488e763..8d594de 100644
--- a/tests/src/com/android/launcher3/ui/WorkTabTest.java
+++ b/tests/src/com/android/launcher3/ui/WorkTabTest.java
@@ -55,7 +55,9 @@
private static final int WORK_PAGE = AllAppsContainerView.AdapterHolder.WORK;
@Before
- public void createWorkProfile() throws Exception {
+ @Override
+ public void setUp() throws Exception {
+ super.setUp();
String output =
mDevice.executeShellCommand(
"pm create-user --profileOf 0 --managed TestProfile");