Merge "Fix window transition when opening app from deep shortcut menu." into ub-launcher3-master
diff --git a/proguard.flags b/proguard.flags
index b8cade5..cac8930 100644
--- a/proguard.flags
+++ b/proguard.flags
@@ -102,6 +102,11 @@
public <init>(...);
}
+# InstantAppResolver
+-keep class com.android.quickstep.InstantAppResolverImpl {
+ public <init>(...);
+}
+
-keep interface com.android.launcher3.userevent.nano.LauncherLogProto.** {
*;
}
diff --git a/quickstep/libs/sysui_shared.jar b/quickstep/libs/sysui_shared.jar
index 6e62add..662069a 100644
--- a/quickstep/libs/sysui_shared.jar
+++ b/quickstep/libs/sysui_shared.jar
Binary files differ
diff --git a/quickstep/res/layout/overview_panel.xml b/quickstep/res/layout/overview_panel.xml
index 9f4f8a1..54190ec 100644
--- a/quickstep/res/layout/overview_panel.xml
+++ b/quickstep/res/layout/overview_panel.xml
@@ -24,8 +24,4 @@
android:alpha="0.0"
android:visibility="invisible" >
- <com.android.launcher3.uioverrides.WorkspaceCard
- android:layout_width="match_parent"
- android:layout_height="match_parent" />
-
</com.android.quickstep.RecentsView>
\ No newline at end of file
diff --git a/quickstep/res/values/dimens.xml b/quickstep/res/values/dimens.xml
index cf86176..6a76b45 100644
--- a/quickstep/res/values/dimens.xml
+++ b/quickstep/res/values/dimens.xml
@@ -33,8 +33,6 @@
<dimen name="quickstep_fling_threshold_velocity">500dp</dimen>
<dimen name="quickstep_fling_min_velocity">250dp</dimen>
- <dimen name="workspace_overview_offset_x">-24dp</dimen>
-
<!-- Launcher app transition -->
<dimen name="content_trans_y">25dp</dimen>
<dimen name="workspace_trans_y">80dp</dimen>
diff --git a/quickstep/res/values/override.xml b/quickstep/res/values/override.xml
index ba99d81..2bd9f8f 100644
--- a/quickstep/res/values/override.xml
+++ b/quickstep/res/values/override.xml
@@ -16,5 +16,7 @@
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_transition_manager_class" translatable="false">com.android.launcher3.LauncherAppTransitionManagerImpl</string>
+
+ <string name="instant_app_resolver_class" translatable="false">com.android.quickstep.InstantAppResolverImpl</string>
</resources>
diff --git a/quickstep/src/com/android/launcher3/LauncherAppTransitionManagerImpl.java b/quickstep/src/com/android/launcher3/LauncherAppTransitionManagerImpl.java
index 14232ae..6fc1447 100644
--- a/quickstep/src/com/android/launcher3/LauncherAppTransitionManagerImpl.java
+++ b/quickstep/src/com/android/launcher3/LauncherAppTransitionManagerImpl.java
@@ -295,7 +295,7 @@
boolean launchingCenterTask = launchedTaskIndex == centerTaskIndex;
boolean isRtl = recentsView.isRtl();
if (launchingCenterTask) {
- if (launchedTaskIndex - 1 >= recentsView.getFirstTaskIndex()) {
+ if (launchedTaskIndex - 1 >= 0) {
TaskView adjacentPage1 = (TaskView) recentsView.getPageAt(launchedTaskIndex - 1);
ObjectAnimator adjacentTask1ScaleAndTranslate =
LauncherAnimUtils.ofPropertyValuesHolder(adjacentPage1,
@@ -317,7 +317,7 @@
.build());
launcherAnimator.play(adjacentTask2ScaleAndTranslate);
}
- } else if (centerTaskIndex >= recentsView.getFirstTaskIndex()) {
+ } else {
// We are launching an adjacent task, so parallax the center and other adjacent task.
TaskView centerTask = (TaskView) recentsView.getPageAt(centerTaskIndex);
float translationX = Math.abs(v.getTranslationX());
@@ -329,7 +329,7 @@
.build());
launcherAnimator.play(centerTaskParallaxToRight);
int otherAdjacentTaskIndex = centerTaskIndex + (centerTaskIndex - launchedTaskIndex);
- if (otherAdjacentTaskIndex >= recentsView.getFirstTaskIndex()
+ if (otherAdjacentTaskIndex >= 0
&& otherAdjacentTaskIndex < recentsView.getPageCount()) {
TaskView otherAdjacentTask = (TaskView) recentsView.getPageAt(
otherAdjacentTaskIndex);
diff --git a/quickstep/src/com/android/launcher3/uioverrides/FastOverviewState.java b/quickstep/src/com/android/launcher3/uioverrides/FastOverviewState.java
index acd4fc1..8a5c55a 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/FastOverviewState.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/FastOverviewState.java
@@ -16,6 +16,8 @@
package com.android.launcher3.uioverrides;
import com.android.launcher3.Launcher;
+import com.android.quickstep.QuickScrubController;
+import com.android.quickstep.RecentsView;
/**
* Extension of overview state used for QuickScrub
@@ -23,12 +25,19 @@
public class FastOverviewState extends OverviewState {
private static final int STATE_FLAGS = FLAG_SHOW_SCRIM | FLAG_DISABLE_RESTORE
- | FLAG_PAGE_BACKGROUNDS | FLAG_DISABLE_INTERACTION | FLAG_OVERVIEW_UI;
+ | FLAG_DISABLE_INTERACTION | FLAG_OVERVIEW_UI;
private static final boolean DEBUG_DIFFERENT_UI = false;
public FastOverviewState(int id) {
- super(id, STATE_FLAGS);
+ super(id, QuickScrubController.QUICK_SWITCH_START_DURATION, STATE_FLAGS);
+ }
+
+ @Override
+ public void onStateTransitionEnd(Launcher launcher) {
+ super.onStateTransitionEnd(launcher);
+ RecentsView recentsView = launcher.getOverviewPanel();
+ recentsView.getQuickScrubController().onFinishedTransitionToQuickScrub();
}
@Override
diff --git a/quickstep/src/com/android/launcher3/uioverrides/OverviewState.java b/quickstep/src/com/android/launcher3/uioverrides/OverviewState.java
index 854fb4f..a88369d 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/OverviewState.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/OverviewState.java
@@ -16,7 +16,7 @@
package com.android.launcher3.uioverrides;
import static com.android.launcher3.LauncherAnimUtils.OVERVIEW_TRANSITION_MS;
-import static com.android.launcher3.anim.Interpolators.ACCEL_2;
+import static com.android.launcher3.anim.Interpolators.DEACCEL_2;
import static com.android.launcher3.states.RotationHelper.REQUEST_ROTATE;
import android.graphics.Rect;
@@ -24,7 +24,6 @@
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherState;
-import com.android.launcher3.R;
import com.android.launcher3.Workspace;
import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType;
import com.android.quickstep.RecentsView;
@@ -35,31 +34,26 @@
public class OverviewState extends LauncherState {
private static final int STATE_FLAGS = FLAG_SHOW_SCRIM | FLAG_WORKSPACE_ICONS_CAN_BE_DRAGGED
- | FLAG_DISABLE_RESTORE | FLAG_PAGE_BACKGROUNDS | FLAG_OVERVIEW_UI;
+ | FLAG_DISABLE_RESTORE | FLAG_OVERVIEW_UI;
public OverviewState(int id) {
- this(id, STATE_FLAGS);
+ this(id, OVERVIEW_TRANSITION_MS, STATE_FLAGS);
}
- protected OverviewState(int id, int stateFlags) {
- super(id, ContainerType.TASKSWITCHER, OVERVIEW_TRANSITION_MS, stateFlags);
+ protected OverviewState(int id, int transitionDuration, int stateFlags) {
+ super(id, ContainerType.TASKSWITCHER, transitionDuration, stateFlags);
}
@Override
public float[] getWorkspaceScaleAndTranslation(Launcher launcher) {
Rect pageRect = new Rect();
- RecentsView.getScaledDownPageRect(launcher.getDeviceProfile(), launcher, pageRect);
- RecentsView rv = launcher.getOverviewPanel();
+ RecentsView.getPageRect(launcher.getDeviceProfile(), launcher, pageRect);
if (launcher.getWorkspace().getNormalChildWidth() <= 0 || pageRect.isEmpty()) {
return super.getWorkspaceScaleAndTranslation(launcher);
}
- float overlap = 0;
- if (rv.getCurrentPage() >= rv.getFirstTaskIndex()) {
- overlap = launcher.getResources().getDimension(R.dimen.workspace_overview_offset_x);
- }
- return getScaleAndTranslationForPageRect(launcher, overlap, pageRect);
+ return getScaleAndTranslationForPageRect(launcher, pageRect);
}
@Override
@@ -85,40 +79,25 @@
}
public PageAlphaProvider getWorkspacePageAlphaProvider(Launcher launcher) {
- final int centerPage = launcher.getWorkspace().getNextPage();
- return new PageAlphaProvider(ACCEL_2) {
+ return new PageAlphaProvider(DEACCEL_2) {
@Override
public float getPageAlpha(int pageIndex) {
- return pageIndex != centerPage ? 0 : 1f;
+ return 0;
}
};
}
- public static float[] getScaleAndTranslationForPageRect(Launcher launcher, float offsetX,
- Rect pageRect) {
+ public static float[] getScaleAndTranslationForPageRect(Launcher launcher, Rect pageRect) {
Workspace ws = launcher.getWorkspace();
float childWidth = ws.getNormalChildWidth();
- float childHeight = ws.getNormalChildHeight();
- float scale = pageRect.height() / childHeight;
+ float scale = pageRect.width() / childWidth;
Rect insets = launcher.getDragLayer().getInsets();
float halfHeight = ws.getExpectedHeight() / 2;
float childTop = halfHeight - scale * (halfHeight - ws.getPaddingTop() - insets.top);
float translationY = pageRect.top - childTop;
- // Align the workspace horizontally centered with the task rect
- float halfWidth = ws.getExpectedWidth() / 2;
- float childCenter = halfWidth -
- scale * (halfWidth - ws.getPaddingLeft() - insets.left - childWidth / 2);
- float translationX = pageRect.centerX() - childCenter;
-
- if (launcher.<RecentsView>getOverviewPanel().isRtl()) {
- translationX -= offsetX / scale;
- } else {
- translationX += offsetX / scale;
- }
-
- return new float[] {scale, translationX, translationY};
+ return new float[] {scale, 0, translationY};
}
}
diff --git a/quickstep/src/com/android/launcher3/uioverrides/OverviewSwipeController.java b/quickstep/src/com/android/launcher3/uioverrides/OverviewSwipeController.java
index 468a561..eb14d60 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/OverviewSwipeController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/OverviewSwipeController.java
@@ -15,6 +15,13 @@
*/
package com.android.launcher3.uioverrides;
+import static com.android.launcher3.LauncherState.ALL_APPS;
+import static com.android.launcher3.LauncherState.NORMAL;
+import static com.android.launcher3.LauncherState.OVERVIEW;
+import static com.android.launcher3.anim.Interpolators.DEACCEL_1_5;
+import static com.android.launcher3.anim.Interpolators.LINEAR;
+import static com.android.launcher3.anim.Interpolators.scrollInterpolatorForVelocity;
+
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
@@ -32,20 +39,13 @@
import com.android.launcher3.dragndrop.DragLayer;
import com.android.launcher3.touch.SwipeDetector;
import com.android.launcher3.userevent.nano.LauncherLogProto;
-import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType;
import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Direction;
import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Touch;
+import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType;
import com.android.launcher3.util.TouchController;
import com.android.quickstep.RecentsView;
import com.android.quickstep.TaskView;
-import static com.android.launcher3.LauncherState.ALL_APPS;
-import static com.android.launcher3.LauncherState.NORMAL;
-import static com.android.launcher3.LauncherState.OVERVIEW;
-import static com.android.launcher3.anim.Interpolators.DEACCEL_1_5;
-import static com.android.launcher3.anim.Interpolators.LINEAR;
-import static com.android.launcher3.anim.Interpolators.scrollInterpolatorForVelocity;
-
/**
* Touch controller for swipe interaction in Overview state
*/
@@ -132,28 +132,21 @@
mTaskBeingDragged = null;
mSwipeDownEnabled = true;
- int currentPage = mRecentsView.getCurrentPage();
- if (currentPage == 0) {
- // User is on home tile
+ View view = mRecentsView.getChildAt(mRecentsView.getCurrentPage());
+ if (view instanceof TaskView && mLauncher.getDragLayer().isEventOverView(view, ev)) {
+ // The tile can be dragged down to open the task.
+ mTaskBeingDragged = (TaskView) view;
directionsToDetectScroll = SwipeDetector.DIRECTION_BOTH;
+ mStartingTarget = LauncherLogProto.ItemType.TASK;
+ } else if (isEventOverHotseat(ev)) {
+ // The hotseat is being dragged
+ directionsToDetectScroll = SwipeDetector.DIRECTION_POSITIVE;
+ mSwipeDownEnabled = false;
+ mStartingTarget = ContainerType.HOTSEAT;
} else {
- View view = mRecentsView.getChildAt(currentPage);
- if (mLauncher.getDragLayer().isEventOverView(view, ev) &&
- view instanceof TaskView) {
- // The tile can be dragged down to open the task.
- mTaskBeingDragged = (TaskView) view;
- directionsToDetectScroll = SwipeDetector.DIRECTION_BOTH;
- mStartingTarget = LauncherLogProto.ItemType.TASK;
- } else if (isEventOverHotseat(ev)) {
- // The hotseat is being dragged
- directionsToDetectScroll = SwipeDetector.DIRECTION_POSITIVE;
- mSwipeDownEnabled = false;
- mStartingTarget = ContainerType.HOTSEAT;
- } else {
- mNoIntercept = true;
- mStartingTarget = ContainerType.WORKSPACE;
- return false;
- }
+ mNoIntercept = true;
+ mStartingTarget = ContainerType.WORKSPACE;
+ return false;
}
}
diff --git a/quickstep/src/com/android/launcher3/uioverrides/RecentsViewStateController.java b/quickstep/src/com/android/launcher3/uioverrides/RecentsViewStateController.java
index 92d071a..2a2e9c5 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/RecentsViewStateController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/RecentsViewStateController.java
@@ -16,7 +16,7 @@
package com.android.launcher3.uioverrides;
import static com.android.launcher3.LauncherState.NORMAL;
-import static com.android.launcher3.LauncherState.OVERVIEW;
+import static com.android.launcher3.anim.Interpolators.ACCEL;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
@@ -28,7 +28,6 @@
import com.android.launcher3.LauncherStateManager.AnimationConfig;
import com.android.launcher3.LauncherStateManager.StateHandler;
import com.android.launcher3.PagedView;
-import com.android.launcher3.Utilities;
import com.android.launcher3.anim.AnimationSuccessListener;
import com.android.launcher3.anim.AnimatorSetBuilder;
import com.android.launcher3.anim.Interpolators;
@@ -40,31 +39,26 @@
private final Launcher mLauncher;
private final RecentsView mRecentsView;
- private final WorkspaceCard mWorkspaceCard;
private final AnimatedFloat mTransitionProgress = new AnimatedFloat(this::onTransitionProgress);
// The fraction representing the visibility of the RecentsView. This allows delaying the
// overall transition while the RecentsView is being shown or hidden.
private final AnimatedFloat mVisibilityMultiplier = new AnimatedFloat(this::onVisibilityProgress);
- private boolean mIsRecentsScrollingToFirstTask;
+ private boolean mIsRecentsSlidingInOrOut;
public RecentsViewStateController(Launcher launcher) {
mLauncher = launcher;
mRecentsView = launcher.getOverviewPanel();
mRecentsView.setStateController(this);
-
- mWorkspaceCard = (WorkspaceCard) mRecentsView.getChildAt(0);
- mWorkspaceCard.setup(launcher);
}
@Override
public void setState(LauncherState state) {
- mWorkspaceCard.setWorkspaceScrollingEnabled(state.overviewUi);
setVisibility(state.overviewUi);
setTransitionProgress(state.overviewUi ? 1 : 0);
if (state.overviewUi) {
- for (int i = mRecentsView.getFirstTaskIndex(); i < mRecentsView.getPageCount(); i++) {
+ for (int i = 0; i < mRecentsView.getPageCount(); i++) {
((TaskView) mRecentsView.getPageAt(i)).resetVisualProperties();
}
mRecentsView.updateCurveProperties();
@@ -74,22 +68,19 @@
@Override
public void setStateWithAnimation(final LauncherState toState,
AnimatorSetBuilder builder, AnimationConfig config) {
- boolean settingEnabled = Utilities.getPrefs(mLauncher)
- .getBoolean("pref_scroll_to_first_task_default_true", true);
- mIsRecentsScrollingToFirstTask = mLauncher.isInState(NORMAL) && toState == OVERVIEW
- && settingEnabled;
- // TODO: Instead of animating the workspace translationX, move the contents
- mWorkspaceCard.setWorkspaceScrollingEnabled(mIsRecentsScrollingToFirstTask);
+ LauncherState fromState = mLauncher.getStateManager().getState();
+ mIsRecentsSlidingInOrOut = fromState == NORMAL && toState.overviewUi
+ || fromState.overviewUi && toState == NORMAL;
// Scroll to the workspace card before changing to the NORMAL state.
int currPage = mRecentsView.getCurrentPage();
- LauncherState fromState = mLauncher.getStateManager().getState();
if (fromState.overviewUi && toState == NORMAL && currPage != 0 && !config.userControlled) {
int maxSnapDuration = PagedView.SLOW_PAGE_SNAP_ANIMATION_DURATION;
int durationPerPage = maxSnapDuration / 10;
int snapDuration = Math.min(maxSnapDuration, durationPerPage * currPage);
mRecentsView.snapToPage(0, snapDuration);
- builder.setStartDelay(snapDuration);
+ // Let the snapping animation play for a bit before we translate off screen.
+ builder.setStartDelay(snapDuration / 4);
}
ObjectAnimator progressAnim =
@@ -100,7 +91,6 @@
@Override
public void onAnimationSuccess(Animator animator) {
- mWorkspaceCard.setWorkspaceScrollingEnabled(toState.overviewUi);
mRecentsView.setCurrentPage(mRecentsView.getPageNearestToCenterOfScreen());
}
});
@@ -145,11 +135,14 @@
private void onTransitionProgress() {
applyProgress();
- if (mIsRecentsScrollingToFirstTask) {
- int scrollForFirstTask = mRecentsView.getScrollForPage(mRecentsView.getFirstTaskIndex());
- int scrollForPage0 = mRecentsView.getScrollForPage(0);
- mRecentsView.setScrollX((int) (mTransitionProgress.value * scrollForFirstTask
- + (1 - mTransitionProgress.value) * scrollForPage0));
+ if (mIsRecentsSlidingInOrOut) {
+ float interpolatedProgress = ACCEL.getInterpolation(mTransitionProgress.value);
+ // Slide in from the side as we swipe.
+ int translation = mRecentsView.getWidth();
+ if (mRecentsView.isRtl()) {
+ translation = -translation;
+ }
+ mRecentsView.setTranslationX(translation * (1 - interpolatedProgress));
}
}
diff --git a/quickstep/src/com/android/launcher3/uioverrides/WorkspaceCard.java b/quickstep/src/com/android/launcher3/uioverrides/WorkspaceCard.java
deleted file mode 100644
index 8533502..0000000
--- a/quickstep/src/com/android/launcher3/uioverrides/WorkspaceCard.java
+++ /dev/null
@@ -1,127 +0,0 @@
-/*
- * Copyright (C) 2017 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.uioverrides;
-
-import static com.android.launcher3.LauncherState.NORMAL;
-import static com.android.quickstep.RecentsView.SCROLL_TYPE_WORKSPACE;
-
-import android.content.Context;
-import android.graphics.Canvas;
-import android.graphics.Rect;
-import android.util.AttributeSet;
-import android.view.View;
-import android.view.View.OnClickListener;
-
-import com.android.launcher3.Launcher;
-import com.android.launcher3.R;
-import com.android.launcher3.Workspace;
-import com.android.quickstep.RecentsView;
-import com.android.quickstep.RecentsView.PageCallbacks;
-import com.android.quickstep.RecentsView.ScrollState;
-
-public class WorkspaceCard extends View implements PageCallbacks, OnClickListener {
-
- private final Rect mTempRect = new Rect();
-
- private Launcher mLauncher;
- private Workspace mWorkspace;
-
- private float mLinearInterpolationForPage2 = 1;
- private float mTranslateXPage0, mTranslateXPage1;
- private float mExtraScrollShift;
-
- private boolean mIsWorkspaceScrollingEnabled;
-
- public WorkspaceCard(Context context) {
- this(context, null);
- }
-
- public WorkspaceCard(Context context, AttributeSet attrs) {
- this(context, attrs, 0);
- }
-
- public WorkspaceCard(Context context, AttributeSet attrs, int defStyleAttr) {
- super(context, attrs, defStyleAttr);
- setOnClickListener(this);
- }
-
- /**
- * Draw nothing.
- */
- @Override
- public void draw(Canvas canvas) { }
-
- @Override
- protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
- super.onLayout(changed, left, top, right, bottom);
-
- // Initiate data
- mLinearInterpolationForPage2 = RecentsView.getScaledDownPageRect(
- mLauncher.getDeviceProfile(), mLauncher, mTempRect);
-
- float[] scale = OverviewState.getScaleAndTranslationForPageRect(mLauncher, 0, mTempRect);
- mTranslateXPage0 = scale[1];
- mTranslateXPage1 = OverviewState
- .getScaleAndTranslationForPageRect(mLauncher,
- getResources().getDimension(R.dimen.workspace_overview_offset_x) / scale[0],
- mTempRect)[1];
-
- mExtraScrollShift = 0;
- if (mWorkspace != null && getWidth() > 0) {
- float workspaceWidth = mWorkspace.getNormalChildWidth() * scale[0];
- mExtraScrollShift = (workspaceWidth - getWidth()) / 2;
- setScaleX(workspaceWidth / getWidth());
- }
- }
-
- @Override
- public void onClick(View view) {
- mLauncher.getStateManager().goToState(NORMAL);
- }
-
- public void setup(Launcher launcher) {
- mLauncher = launcher;
- mWorkspace = mLauncher.getWorkspace();
- }
-
- public void setWorkspaceScrollingEnabled(boolean isEnabled) {
- mIsWorkspaceScrollingEnabled = isEnabled;
- }
-
- @Override
- public int onPageScroll(ScrollState scrollState) {
- float factor = scrollState.linearInterpolation;
- float translateX = scrollState.distanceFromScreenCenter;
- if (mIsWorkspaceScrollingEnabled) {
- float shift = factor * (mTranslateXPage1 - mTranslateXPage0);
- mWorkspace.setTranslationX(shift + mTranslateXPage0);
- translateX += shift;
- }
-
- setTranslationX(translateX);
-
- // If the workspace card is still the first page, shift all the other pages.
- if (scrollState.linearInterpolation > mLinearInterpolationForPage2) {
- scrollState.prevPageExtraWidth = 0;
- } else if (mLinearInterpolationForPage2 > 0) {
- scrollState.prevPageExtraWidth = mExtraScrollShift *
- (1 - scrollState.linearInterpolation / mLinearInterpolationForPage2);
- } else {
- scrollState.prevPageExtraWidth = mExtraScrollShift;
- }
- return SCROLL_TYPE_WORKSPACE;
- }
-}
diff --git a/quickstep/src/com/android/quickstep/AnimatedFloat.java b/quickstep/src/com/android/quickstep/AnimatedFloat.java
index 214b3f3..84dfa45 100644
--- a/quickstep/src/com/android/quickstep/AnimatedFloat.java
+++ b/quickstep/src/com/android/quickstep/AnimatedFloat.java
@@ -77,6 +77,12 @@
}
}
+ public void finishAnimation() {
+ if (mValueAnimator != null && mValueAnimator.isRunning()) {
+ mValueAnimator.end();
+ }
+ }
+
public ObjectAnimator getCurrentAnimation() {
return mValueAnimator;
}
diff --git a/quickstep/src/com/android/quickstep/BaseSwipeInteractionHandler.java b/quickstep/src/com/android/quickstep/BaseSwipeInteractionHandler.java
index b3ebd77..5871a6d 100644
--- a/quickstep/src/com/android/quickstep/BaseSwipeInteractionHandler.java
+++ b/quickstep/src/com/android/quickstep/BaseSwipeInteractionHandler.java
@@ -23,6 +23,7 @@
public abstract class BaseSwipeInteractionHandler extends InternalStateHandler {
protected Runnable mGestureEndCallback;
+ protected boolean mIsGoingToHome;
public void setGestureEndCallback(Runnable gestureEndCallback) {
mGestureEndCallback = gestureEndCallback;
diff --git a/quickstep/src/com/android/quickstep/DeferredTouchConsumer.java b/quickstep/src/com/android/quickstep/DeferredTouchConsumer.java
new file mode 100644
index 0000000..b92678a
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/DeferredTouchConsumer.java
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.quickstep;
+
+import android.annotation.TargetApi;
+import android.os.Build;
+import android.view.Choreographer;
+import android.view.MotionEvent;
+import android.view.VelocityTracker;
+
+/**
+ * A TouchConsumer which defers all events on the UIThread until the consumer is created.
+ */
+@TargetApi(Build.VERSION_CODES.P)
+public class DeferredTouchConsumer implements TouchConsumer {
+
+ private final VelocityTracker mVelocityTracker;
+ private final DeferredTouchProvider mTouchProvider;
+
+ private MotionEventQueue mMyQueue;
+ private TouchConsumer mTarget;
+
+ public DeferredTouchConsumer(DeferredTouchProvider touchProvider) {
+ mVelocityTracker = VelocityTracker.obtain();
+ mTouchProvider = touchProvider;
+ }
+
+ @Override
+ public void accept(MotionEvent event) {
+ mTarget.accept(event);
+ }
+
+ @Override
+ public void reset() {
+ mTarget.reset();
+ }
+
+ @Override
+ public void updateTouchTracking(int interactionType) {
+ mTarget.updateTouchTracking(interactionType);
+ }
+
+ @Override
+ public void onQuickScrubEnd() {
+ mTarget.onQuickScrubEnd();
+ }
+
+ @Override
+ public void onQuickScrubProgress(float progress) {
+ mTarget.onQuickScrubProgress(progress);
+ }
+
+ @Override
+ public void preProcessMotionEvent(MotionEvent ev) {
+ mVelocityTracker.addMovement(ev);
+ }
+
+ @Override
+ public Choreographer getIntrimChoreographer(MotionEventQueue queue) {
+ mMyQueue = queue;
+ return null;
+ }
+
+ @Override
+ public void deferInit() {
+ mTarget = mTouchProvider.createTouchConsumer(mVelocityTracker);
+ mTarget.getIntrimChoreographer(mMyQueue);
+ }
+
+ @Override
+ public boolean forceToLauncherConsumer() {
+ return mTarget.forceToLauncherConsumer();
+ }
+
+ @Override
+ public boolean deferNextEventToMainThread() {
+ // If our target is still null, defer the next target as well
+ TouchConsumer target = mTarget;
+ return target == null ? true : target.deferNextEventToMainThread();
+ }
+
+ public interface DeferredTouchProvider {
+
+ TouchConsumer createTouchConsumer(VelocityTracker tracker);
+ }
+}
diff --git a/quickstep/src/com/android/quickstep/InstantAppResolverImpl.java b/quickstep/src/com/android/quickstep/InstantAppResolverImpl.java
new file mode 100644
index 0000000..12757c0
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/InstantAppResolverImpl.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.quickstep;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.InstantAppInfo;
+import android.content.pm.PackageManager;
+import android.util.Log;
+
+import com.android.launcher3.AppInfo;
+import com.android.launcher3.util.InstantAppResolver;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Implementation of InstantAppResolver using platform APIs
+ */
+@SuppressWarnings("unused")
+public class InstantAppResolverImpl extends InstantAppResolver {
+
+ private static final String TAG = "InstantAppResolverImpl";
+ public static final String COMPONENT_CLASS_MARKER = "@instantapp";
+
+ private final PackageManager mPM;
+
+ public InstantAppResolverImpl(Context context)
+ throws NoSuchMethodException, ClassNotFoundException {
+ mPM = context.getPackageManager();
+ }
+
+ @Override
+ public boolean isInstantApp(ApplicationInfo info) {
+ return info.isInstantApp();
+ }
+
+ @Override
+ public boolean isInstantApp(AppInfo info) {
+ ComponentName cn = info.getTargetComponent();
+ return cn != null && cn.getClassName().equals(COMPONENT_CLASS_MARKER);
+ }
+
+ @Override
+ public List<ApplicationInfo> getInstantApps() {
+ try {
+ List<ApplicationInfo> result = new ArrayList<>();
+ for (InstantAppInfo iai : mPM.getInstantApps()) {
+ ApplicationInfo info = iai.getApplicationInfo();
+ if (info != null) {
+ result.add(info);
+ }
+ }
+ return result;
+ } catch (SecurityException se) {
+ Log.w(TAG, "getInstantApps failed. Launcher may not be the default home app.", se);
+ } catch (Exception e) {
+ Log.e(TAG, "Error calling API: getInstantApps", e);
+ }
+ return super.getInstantApps();
+ }
+}
diff --git a/quickstep/src/com/android/quickstep/MotionEventQueue.java b/quickstep/src/com/android/quickstep/MotionEventQueue.java
index 6e92d83..94b6faa 100644
--- a/quickstep/src/com/android/quickstep/MotionEventQueue.java
+++ b/quickstep/src/com/android/quickstep/MotionEventQueue.java
@@ -53,6 +53,8 @@
ACTION_VIRTUAL | (4 << ACTION_POINTER_INDEX_SHIFT);
private static final int ACTION_RESET =
ACTION_VIRTUAL | (5 << ACTION_POINTER_INDEX_SHIFT);
+ private static final int ACTION_DEFER_INIT =
+ ACTION_VIRTUAL | (6 << ACTION_POINTER_INDEX_SHIFT);
private final EventArray mEmptyArray = new EventArray();
private final Object mExecutionLock = new Object();
@@ -76,10 +78,10 @@
public MotionEventQueue(Choreographer choreographer, TouchConsumer consumer) {
mMainChoreographer = choreographer;
mConsumer = consumer;
-
mCurrentChoreographer = mMainChoreographer;
mCurrentRunnable = mMainFrameCallback;
- setInterimChoreographerLocked(consumer.getIntrimChoreographer(this));
+
+ setInterimChoreographer(consumer.getIntrimChoreographer(this));
}
public void setInterimChoreographer(Choreographer choreographer) {
@@ -156,6 +158,9 @@
case ACTION_RESET:
mConsumer.reset();
break;
+ case ACTION_DEFER_INIT:
+ mConsumer.deferInit();
+ break;
default:
Log.e(TAG, "Invalid virtual event: " + event.getAction());
}
@@ -204,6 +209,14 @@
queueVirtualAction(ACTION_RESET, 0);
}
+ public void deferInit() {
+ queueVirtualAction(ACTION_DEFER_INIT, 0);
+ }
+
+ public TouchConsumer getConsumer() {
+ return mConsumer;
+ }
+
private static class EventArray extends ArrayList<MotionEvent> {
public int lastEventAction = ACTION_CANCEL;
diff --git a/quickstep/src/com/android/quickstep/NavBarSwipeInteractionHandler.java b/quickstep/src/com/android/quickstep/NavBarSwipeInteractionHandler.java
index ff7d434..fca844c 100644
--- a/quickstep/src/com/android/quickstep/NavBarSwipeInteractionHandler.java
+++ b/quickstep/src/com/android/quickstep/NavBarSwipeInteractionHandler.java
@@ -319,13 +319,14 @@
/** Animates to the given progress, where 0 is the current app and 1 is overview. */
private void animateToProgress(float progress, long duration) {
+ mIsGoingToHome = Float.compare(progress, 1) == 0;
ObjectAnimator anim = mCurrentShift.animateToValue(progress).setDuration(duration);
anim.setInterpolator(Interpolators.SCROLL);
anim.addListener(new AnimationSuccessListener() {
@Override
public void onAnimationSuccess(Animator animator) {
- mStateCallback.setState((Float.compare(mCurrentShift.value, 0) == 0)
- ? STATE_SCALED_SNAPSHOT_APP : STATE_SCALED_SNAPSHOT_RECENTS);
+ mStateCallback.setState(mIsGoingToHome
+ ? STATE_SCALED_SNAPSHOT_RECENTS : STATE_SCALED_SNAPSHOT_APP);
}
});
anim.start();
diff --git a/quickstep/src/com/android/quickstep/NormalizedIconLoader.java b/quickstep/src/com/android/quickstep/NormalizedIconLoader.java
index 431fb30..3247312 100644
--- a/quickstep/src/com/android/quickstep/NormalizedIconLoader.java
+++ b/quickstep/src/com/android/quickstep/NormalizedIconLoader.java
@@ -29,6 +29,7 @@
import com.android.launcher3.FastBitmapDrawable;
import com.android.launcher3.graphics.BitmapInfo;
+import com.android.launcher3.graphics.DrawableFactory;
import com.android.launcher3.graphics.LauncherIcons;
import com.android.systemui.shared.recents.model.IconLoader;
import com.android.systemui.shared.recents.model.TaskKeyLruCache;
@@ -40,11 +41,13 @@
public class NormalizedIconLoader extends IconLoader {
private final SparseArray<BitmapInfo> mDefaultIcons = new SparseArray<>();
+ private final DrawableFactory mDrawableFactory;
private LauncherIcons mLauncherIcons;
public NormalizedIconLoader(Context context, TaskKeyLruCache<Drawable> iconCache,
LruCache<ComponentName, ActivityInfo> activityInfoCache) {
super(context, iconCache, activityInfoCache);
+ mDrawableFactory = DrawableFactory.get(context);
}
@Override
@@ -53,7 +56,7 @@
BitmapInfo info = mDefaultIcons.get(userId);
if (info == null) {
info = getBitmapInfo(Resources.getSystem()
- .getDrawable(android.R.drawable.sym_def_app_icon), userId);
+ .getDrawable(android.R.drawable.sym_def_app_icon), userId, false);
mDefaultIcons.put(userId, info);
}
@@ -63,22 +66,26 @@
@Override
protected Drawable createBadgedDrawable(Drawable drawable, int userId) {
- return new FastBitmapDrawable(getBitmapInfo(drawable, userId));
+ return new FastBitmapDrawable(getBitmapInfo(drawable, userId, false));
}
- private synchronized BitmapInfo getBitmapInfo(Drawable drawable, int userId) {
+ private synchronized BitmapInfo getBitmapInfo(Drawable drawable, int userId,
+ boolean isInstantApp) {
if (mLauncherIcons == null) {
mLauncherIcons = LauncherIcons.obtain(mContext);
}
// User version code O, so that the icon is always wrapped in an adaptive icon container.
return mLauncherIcons.createBadgedIconBitmap(drawable, UserHandle.of(userId),
- Build.VERSION_CODES.O);
+ Build.VERSION_CODES.O, isInstantApp);
}
@Override
- protected Drawable getBadgedActivityIcon(ActivityInfo activityInfo, int userId) {
- return createBadgedDrawable(
- activityInfo.loadUnbadgedIcon(mContext.getPackageManager()), userId);
+ protected synchronized Drawable getBadgedActivityIcon(ActivityInfo activityInfo, int userId) {
+ BitmapInfo bitmapInfo = getBitmapInfo(
+ activityInfo.loadUnbadgedIcon(mContext.getPackageManager()),
+ userId,
+ activityInfo.applicationInfo.isInstantApp());
+ return mDrawableFactory.newIcon(bitmapInfo, activityInfo);
}
}
diff --git a/quickstep/src/com/android/quickstep/OtherActivityTouchConsumer.java b/quickstep/src/com/android/quickstep/OtherActivityTouchConsumer.java
index 73cd503..c96f6d7 100644
--- a/quickstep/src/com/android/quickstep/OtherActivityTouchConsumer.java
+++ b/quickstep/src/com/android/quickstep/OtherActivityTouchConsumer.java
@@ -23,9 +23,11 @@
import static android.view.MotionEvent.INVALID_POINTER_ID;
import static com.android.quickstep.RemoteRunnable.executeSafely;
+import static com.android.quickstep.TouchInteractionService.DEBUG_SHOW_OVERVIEW_BUTTON;
import static com.android.systemui.shared.system.NavigationBarCompat.HIT_TARGET_BACK;
-import static com.android.systemui.shared.system.NavigationBarCompat.HIT_TARGET_NONE;
+import static com.android.systemui.shared.system.NavigationBarCompat.HIT_TARGET_OVERVIEW;
+import android.annotation.TargetApi;
import android.app.ActivityManager.RunningTaskInfo;
import android.app.ActivityOptions;
import android.content.Context;
@@ -37,6 +39,7 @@
import android.graphics.Point;
import android.graphics.PointF;
import android.graphics.Rect;
+import android.os.Build;
import android.os.Bundle;
import android.os.Looper;
import android.util.Log;
@@ -61,16 +64,20 @@
import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
import com.android.systemui.shared.system.WindowManagerWrapper;
+import java.util.Arrays;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
/**
* Touch consumer for handling events originating from an activity other than Launcher
*/
+@TargetApi(Build.VERSION_CODES.P)
public class OtherActivityTouchConsumer extends ContextWrapper implements TouchConsumer {
private static final String TAG = "ActivityTouchConsumer";
private static final long LAUNCHER_DRAW_TIMEOUT_MS = 150;
+ private static final int[] DEFERRED_HIT_TARGETS = DEBUG_SHOW_OVERVIEW_BUTTON
+ ? new int[] {HIT_TARGET_BACK, HIT_TARGET_OVERVIEW} : new int[] {HIT_TARGET_BACK};
private final RunningTaskInfo mRunningTask;
private final RecentsModel mRecentsModel;
@@ -79,6 +86,7 @@
private final MainThreadExecutor mMainThreadExecutor;
private final Choreographer mBackgroundThreadChoreographer;
+ private final boolean mIsDeferredDownTarget;
private final PointF mDownPos = new PointF();
private final PointF mLastPos = new PointF();
private int mActivePointerId = INVALID_POINTER_ID;
@@ -88,24 +96,24 @@
private BaseSwipeInteractionHandler mInteractionHandler;
private int mDisplayRotation;
private Rect mStableInsets = new Rect();
- private @HitTarget int mDownHitTarget = HIT_TARGET_NONE;
private VelocityTracker mVelocityTracker;
private MotionEventQueue mEventQueue;
+ private boolean mIsGoingToHome;
public OtherActivityTouchConsumer(Context base, RunningTaskInfo runningTaskInfo,
RecentsModel recentsModel, Intent homeIntent, ISystemUiProxy systemUiProxy,
MainThreadExecutor mainThreadExecutor, Choreographer backgroundThreadChoreographer,
- @HitTarget int downHitTarget) {
+ @HitTarget int downHitTarget, VelocityTracker velocityTracker) {
super(base);
mRunningTask = runningTaskInfo;
mRecentsModel = recentsModel;
mHomeIntent = homeIntent;
- mVelocityTracker = VelocityTracker.obtain();
+ mVelocityTracker = velocityTracker;
mISystemUiProxy = systemUiProxy;
mMainThreadExecutor = mainThreadExecutor;
mBackgroundThreadChoreographer = backgroundThreadChoreographer;
- mDownHitTarget = downHitTarget;
+ mIsDeferredDownTarget = Arrays.binarySearch(DEFERRED_HIT_TARGETS, downHitTarget) >= 0;
}
@Override
@@ -124,7 +132,7 @@
// Start the window animation on down to give more time for launcher to draw if the
// user didn't start the gesture over the back button
- if (!isUsingScreenShot() && mDownHitTarget != HIT_TARGET_BACK) {
+ if (!isUsingScreenShot() && !mIsDeferredDownTarget) {
startTouchTrackingForWindowAnimation(ev.getEventTime());
}
@@ -166,7 +174,7 @@
if (isUsingScreenShot()) {
startTouchTrackingForScreenshotAnimation();
- } else if (mDownHitTarget == HIT_TARGET_BACK) {
+ } else if (mIsDeferredDownTarget) {
// If we deferred starting the window animation on touch down, then
// start tracking now
startTouchTrackingForWindowAnimation(ev.getEventTime());
@@ -369,6 +377,7 @@
if (mInteractionHandler != null) {
final BaseSwipeInteractionHandler handler = mInteractionHandler;
mInteractionHandler = null;
+ mIsGoingToHome = handler.mIsGoingToHome;
mMainThreadExecutor.execute(handler::reset);
}
}
@@ -423,4 +432,15 @@
}
}
}
+
+ @Override
+ public boolean forceToLauncherConsumer() {
+ return mIsGoingToHome;
+ }
+
+ @Override
+ public boolean deferNextEventToMainThread() {
+ // TODO: Consider also check if the eventQueue is using mainThread of not.
+ return mInteractionHandler != null;
+ }
}
diff --git a/quickstep/src/com/android/quickstep/OverviewCommandHelper.java b/quickstep/src/com/android/quickstep/OverviewCommandHelper.java
new file mode 100644
index 0000000..b60d1e2
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/OverviewCommandHelper.java
@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.quickstep;
+
+import static com.android.launcher3.LauncherState.OVERVIEW;
+
+import android.annotation.TargetApi;
+import android.app.ActivityManager.RecentTaskInfo;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.ResolveInfo;
+import android.os.Build;
+import android.os.SystemClock;
+import android.os.UserHandle;
+import android.view.ViewConfiguration;
+
+import com.android.launcher3.AbstractFloatingView;
+import com.android.launcher3.Launcher;
+import com.android.launcher3.LauncherAppState;
+import com.android.launcher3.states.InternalStateHandler;
+import com.android.systemui.shared.system.ActivityManagerWrapper;
+
+/**
+ * Helper class to handle various atomic commands for switching between Overview.
+ */
+@TargetApi(Build.VERSION_CODES.P)
+public class OverviewCommandHelper extends InternalStateHandler {
+
+ private final Context mContext;
+ private final ActivityManagerWrapper mAM;
+
+ public final Intent homeIntent;
+ public final ComponentName launcher;
+
+ private long mLastToggleTime;
+
+ public OverviewCommandHelper(Context context) {
+ mContext = context;
+ mAM = ActivityManagerWrapper.getInstance();
+
+ homeIntent = new Intent(Intent.ACTION_MAIN)
+ .addCategory(Intent.CATEGORY_HOME)
+ .setPackage(context.getPackageName())
+ .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ ResolveInfo info = context.getPackageManager().resolveActivity(homeIntent, 0);
+ launcher = new ComponentName(context.getPackageName(), info.activityInfo.name);
+ // Clear the packageName as system can fail to dedupe it b/64108432
+ homeIntent.setComponent(launcher).setPackage(null);
+ }
+
+ public void onOverviewToggle() {
+ long elapsedTime = SystemClock.elapsedRealtime() - mLastToggleTime;
+ mLastToggleTime = SystemClock.elapsedRealtime();
+
+ if (isOverviewAlmostVisible()) {
+ boolean isQuickTap = elapsedTime < ViewConfiguration.getDoubleTapTimeout();
+ startNonLauncherTask(isQuickTap ? 2 : 1);
+ } else {
+ Intent intent = addToIntent(new Intent(homeIntent));
+ mContext.startActivity(intent);
+ initWhenReady();
+ }
+ }
+
+ private void startNonLauncherTask(int backStackCount) {
+ for (RecentTaskInfo rti : mAM.getRecentTasks(backStackCount, UserHandle.myUserId())) {
+ backStackCount--;
+ if (backStackCount == 0) {
+ mAM.startActivityFromRecents(rti.id, null);
+ }
+ }
+ }
+
+ private boolean isOverviewAlmostVisible() {
+ if (clearReference()) {
+ return true;
+ }
+ if (!mAM.getRunningTask().topActivity.equals(launcher)) {
+ return false;
+ }
+ Launcher launcher = getLauncher();
+ return launcher != null && launcher.isStarted() && launcher.isInState(OVERVIEW);
+ }
+
+ private Launcher getLauncher() {
+ return (Launcher) LauncherAppState.getInstance(mContext).getModel().getCallback();
+ }
+
+ @Override
+ protected boolean init(Launcher launcher, boolean alreadyOnHome) {
+ AbstractFloatingView.closeAllOpenViews(launcher, alreadyOnHome);
+ launcher.getStateManager().goToState(OVERVIEW, alreadyOnHome);
+ clearReference();
+ return false;
+ }
+
+}
diff --git a/quickstep/src/com/android/quickstep/OverviewInteractionState.java b/quickstep/src/com/android/quickstep/OverviewInteractionState.java
index 3c68281..4af89bf 100644
--- a/quickstep/src/com/android/quickstep/OverviewInteractionState.java
+++ b/quickstep/src/com/android/quickstep/OverviewInteractionState.java
@@ -15,7 +15,9 @@
*/
package com.android.quickstep;
+import static com.android.quickstep.TouchInteractionService.DEBUG_SHOW_OVERVIEW_BUTTON;
import static com.android.systemui.shared.system.NavigationBarCompat.FLAG_HIDE_BACK_BUTTON;
+import static com.android.systemui.shared.system.NavigationBarCompat.FLAG_SHOW_OVERVIEW_BUTTON;
import android.content.Context;
import android.os.Handler;
@@ -60,7 +62,7 @@
}
};
- private static int sFlags;
+ private static int sFlags = DEBUG_SHOW_OVERVIEW_BUTTON ? FLAG_SHOW_OVERVIEW_BUTTON : 0;
public static void setBackButtonVisible(Context context, boolean visible) {
updateFlagOnUi(context, FLAG_HIDE_BACK_BUTTON, !visible);
diff --git a/quickstep/src/com/android/quickstep/QuickScrubController.java b/quickstep/src/com/android/quickstep/QuickScrubController.java
index f28d51c..0ccd7f2 100644
--- a/quickstep/src/com/android/quickstep/QuickScrubController.java
+++ b/quickstep/src/com/android/quickstep/QuickScrubController.java
@@ -22,10 +22,9 @@
import com.android.launcher3.Launcher;
import com.android.launcher3.OnAlarmListener;
import com.android.launcher3.Utilities;
-import com.android.launcher3.userevent.nano.LauncherLogProto;
import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Touch;
-import com.android.launcher3.userevent.nano.LauncherLogProto.ControlType;
import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType;
+import com.android.launcher3.userevent.nano.LauncherLogProto.ControlType;
/**
* Responds to quick scrub callbacks to page through and launch recent tasks.
@@ -35,8 +34,7 @@
*/
public class QuickScrubController implements OnAlarmListener {
- public static final int QUICK_SWITCH_START_DURATION = 133;
- public static final int QUICK_SWITCH_SNAP_DURATION = 120;
+ public static final int QUICK_SWITCH_START_DURATION = 210;
private static final boolean ENABLE_AUTO_ADVANCE = true;
private static final int NUM_QUICK_SCRUB_SECTIONS = 3;
@@ -51,8 +49,10 @@
private boolean mInQuickScrub;
private int mQuickScrubSection;
- private int mStartPage;
+ private boolean mStartedFromHome;
private boolean mHasAlarmRun;
+ private boolean mQuickSwitched;
+ private boolean mFinishedTransitionToQuickScrub;
public QuickScrubController(Launcher launcher, RecentsView recentsView) {
mLauncher = launcher;
@@ -65,9 +65,13 @@
public void onQuickScrubStart(boolean startingFromHome) {
mInQuickScrub = true;
- mStartPage = startingFromHome ? 0 : mRecentsView.getFirstTaskIndex();
+ mStartedFromHome = startingFromHome;
mQuickScrubSection = 0;
mHasAlarmRun = false;
+ mQuickSwitched = false;
+ mFinishedTransitionToQuickScrub = false;
+
+ snapToNextTaskIfAvailable();
mLauncher.getUserEventDispatcher().resetActionDurationMillis();
}
@@ -78,11 +82,7 @@
}
int page = mRecentsView.getNextPage();
Runnable launchTaskRunnable = () -> {
- if (page < mRecentsView.getFirstTaskIndex()) {
- mRecentsView.getPageAt(page).performClick();
- } else {
- ((TaskView) mRecentsView.getPageAt(page)).launchTask(true);
- }
+ ((TaskView) mRecentsView.getPageAt(page)).launchTask(true);
};
int snapDuration = Math.abs(page - mRecentsView.getPageNearestToCenterOfScreen())
* QUICKSCRUB_END_SNAP_DURATION_PER_PAGE;
@@ -94,7 +94,7 @@
launchTaskRunnable.run();
}
mLauncher.getUserEventDispatcher().logActionOnControl(Touch.DRAGDROP,
- ControlType.QUICK_SCRUB_BUTTON, null, mStartPage == 0 ?
+ ControlType.QUICK_SCRUB_BUTTON, null, mStartedFromHome ?
ContainerType.WORKSPACE : ContainerType.APP);
}
@@ -102,7 +102,9 @@
int quickScrubSection = Math.round(progress * NUM_QUICK_SCRUB_SECTIONS);
if (quickScrubSection != mQuickScrubSection) {
int pageToGoTo = mRecentsView.getNextPage() + quickScrubSection - mQuickScrubSection;
- goToPageWithHaptic(pageToGoTo);
+ if (mFinishedTransitionToQuickScrub) {
+ goToPageWithHaptic(pageToGoTo);
+ }
if (ENABLE_AUTO_ADVANCE) {
if (quickScrubSection == NUM_QUICK_SCRUB_SECTIONS || quickScrubSection == 0) {
mAutoAdvanceAlarm.setAlarm(mHasAlarmRun
@@ -116,36 +118,45 @@
}
public void onQuickSwitch() {
- for (int i = mRecentsView.getFirstTaskIndex(); i < mRecentsView.getPageCount(); i++) {
- TaskView taskView = (TaskView) mRecentsView.getPageAt(i);
- if (taskView.getTask().key.id != mRecentsView.getRunningTaskId()) {
- Runnable launchTaskRunnable = () -> taskView.launchTask(true);
- if (mRecentsView.snapToPage(i, QUICK_SWITCH_SNAP_DURATION)) {
- // Snap to the new page then launch it
- mRecentsView.setNextPageSwitchRunnable(launchTaskRunnable);
- } else {
- // No need to move page, just launch task directly
- launchTaskRunnable.run();
- }
- break;
- }
- }
- mLauncher.getUserEventDispatcher().logActionOnControl(Touch.FLING,
- ControlType.QUICK_SCRUB_BUTTON, null, mStartPage == 0 ?
- ContainerType.WORKSPACE : ContainerType.APP);
+ mQuickSwitched = true;
+ quickSwitchIfReady();
}
- public void snapToPageForCurrentQuickScrubSection() {
- if (mInQuickScrub) {
- goToPageWithHaptic(mRecentsView.getFirstTaskIndex() + mQuickScrubSection);
+ public void onFinishedTransitionToQuickScrub() {
+ mFinishedTransitionToQuickScrub = true;
+ quickSwitchIfReady();
+ }
+
+ /**
+ * Immediately launches the current task (which we snapped to in onQuickScrubStart) if we've
+ * gotten the onQuickSwitch callback and the transition to quick scrub has completed.
+ */
+ private void quickSwitchIfReady() {
+ if (mQuickSwitched && mFinishedTransitionToQuickScrub) {
+ onQuickScrubEnd();
+ mLauncher.getUserEventDispatcher().logActionOnControl(Touch.FLING,
+ ControlType.QUICK_SCRUB_BUTTON, null, mStartedFromHome ?
+ ContainerType.WORKSPACE : ContainerType.APP);
+ }
+ }
+
+ public void snapToNextTaskIfAvailable() {
+ if (mInQuickScrub && mRecentsView.getChildCount() > 0) {
+ int toPage = mStartedFromHome ? 0 : mRecentsView.getNextPage() + 1;
+ goToPageWithHaptic(toPage, QUICK_SWITCH_START_DURATION);
}
}
private void goToPageWithHaptic(int pageToGoTo) {
- pageToGoTo = Utilities.boundToRange(pageToGoTo, mStartPage, mRecentsView.getPageCount() - 1);
+ goToPageWithHaptic(pageToGoTo, -1);
+ }
+
+ private void goToPageWithHaptic(int pageToGoTo, int overrideDuration) {
+ pageToGoTo = Utilities.boundToRange(pageToGoTo, 0, mRecentsView.getPageCount() - 1);
if (pageToGoTo != mRecentsView.getNextPage()) {
- int duration = Math.abs(pageToGoTo - mRecentsView.getNextPage())
- * QUICKSCRUB_SNAP_DURATION_PER_PAGE;
+ int duration = overrideDuration > -1 ? overrideDuration
+ : Math.abs(pageToGoTo - mRecentsView.getNextPage())
+ * QUICKSCRUB_SNAP_DURATION_PER_PAGE;
mRecentsView.snapToPage(pageToGoTo, duration);
mRecentsView.performHapticFeedback(HapticFeedbackConstants.KEYBOARD_TAP,
HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING);
@@ -158,7 +169,7 @@
if (mQuickScrubSection == NUM_QUICK_SCRUB_SECTIONS
&& currPage < mRecentsView.getPageCount() - 1) {
goToPageWithHaptic(currPage + 1);
- } else if (mQuickScrubSection == 0 && currPage > mStartPage) {
+ } else if (mQuickScrubSection == 0 && currPage > 0) {
goToPageWithHaptic(currPage - 1);
}
mHasAlarmRun = true;
diff --git a/quickstep/src/com/android/quickstep/RecentsModel.java b/quickstep/src/com/android/quickstep/RecentsModel.java
index 3e3b3b2..b4ce646 100644
--- a/quickstep/src/com/android/quickstep/RecentsModel.java
+++ b/quickstep/src/com/android/quickstep/RecentsModel.java
@@ -31,7 +31,6 @@
import android.util.LruCache;
import android.util.SparseArray;
-import com.android.launcher3.Launcher;
import com.android.launcher3.MainThreadExecutor;
import com.android.launcher3.R;
import com.android.launcher3.util.Preconditions;
diff --git a/quickstep/src/com/android/quickstep/RecentsView.java b/quickstep/src/com/android/quickstep/RecentsView.java
index 9ae41eb..3cd1179 100644
--- a/quickstep/src/com/android/quickstep/RecentsView.java
+++ b/quickstep/src/com/android/quickstep/RecentsView.java
@@ -17,9 +17,6 @@
package com.android.quickstep;
import static com.android.launcher3.LauncherState.NORMAL;
-import static com.android.launcher3.LauncherState.OVERVIEW;
-import static com.android.quickstep.TaskView.CURVE_FACTOR;
-import static com.android.quickstep.TaskView.CURVE_INTERPOLATOR;
import android.animation.LayoutTransition;
import android.animation.LayoutTransition.TransitionListener;
@@ -52,7 +49,6 @@
import com.android.launcher3.PagedView;
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
-import com.android.launcher3.uioverrides.OverviewState;
import com.android.launcher3.uioverrides.RecentsViewStateController;
import com.android.systemui.shared.recents.model.RecentsTaskLoadPlan;
import com.android.systemui.shared.recents.model.RecentsTaskLoader;
@@ -72,10 +68,6 @@
private static final Rect sTempStableInsets = new Rect();
- public static final int SCROLL_TYPE_NONE = 0;
- public static final int SCROLL_TYPE_TASK = 1;
- public static final int SCROLL_TYPE_WORKSPACE = 2;
-
private static final String PREF_FLIP_RECENTS = "pref_flip_recents";
private final Launcher mLauncher;
@@ -94,7 +86,7 @@
private TaskStackChangeListener mTaskStackListener = new TaskStackChangeListener() {
@Override
public void onTaskSnapshotChanged(int taskId, ThumbnailData snapshot) {
- for (int i = mFirstTaskIndex; i < getChildCount(); i++) {
+ for (int i = 0; i < getChildCount(); i++) {
final TaskView taskView = (TaskView) getChildAt(i);
if (taskView.getTask().key.id == taskId) {
taskView.getThumbnail().setThumbnail(taskView.getTask(), snapshot);
@@ -105,7 +97,6 @@
};
private RecentsViewStateController mStateController;
- private int mFirstTaskIndex;
private final RecentsModel mModel;
private int mLoadPlanId = -1;
@@ -152,7 +143,6 @@
mIsRtl = !mIsRtl;
}
setLayoutDirection(mIsRtl ? View.LAYOUT_DIRECTION_RTL : View.LAYOUT_DIRECTION_LTR);
- mScrollState.isRtl = mIsRtl;
}
}
@@ -161,7 +151,7 @@
}
public TaskView updateThumbnail(int taskId, ThumbnailData thumbnailData) {
- for (int i = mFirstTaskIndex; i < getChildCount(); i++) {
+ for (int i = 0; i < getChildCount(); i++) {
final TaskView taskView = (TaskView) getChildAt(i);
if (taskView.getTask().key.id == taskId) {
taskView.onTaskDataLoaded(taskView.getTask(), thumbnailData);
@@ -203,7 +193,6 @@
protected void onFinishInflate() {
super.onFinishInflate();
Resources res = getResources();
- mFirstTaskIndex = getPageCount();
mFastFlingVelocity = res.getDimensionPixelSize(R.dimen.recents_fast_fling_velocity);
}
@@ -264,17 +253,13 @@
}
}
- public int getFirstTaskIndex() {
- return mFirstTaskIndex;
- }
-
public boolean isTaskViewVisible(TaskView tv) {
// For now, just check if it's the active task or an adjacent task
return Math.abs(indexOfChild(tv) - getNextPage()) <= 1;
}
public TaskView getTaskView(int taskId) {
- for (int i = getFirstTaskIndex(); i < getChildCount(); i++) {
+ for (int i = 0; i < getChildCount(); i++) {
TaskView tv = (TaskView) getChildAt(i);
if (tv.getTask().key.id == taskId) {
return tv;
@@ -325,7 +310,7 @@
final ArrayList<Task> tasks = new ArrayList<>(stack.getTasks());
setLayoutTransition(null);
- final int requiredChildCount = tasks.size() + mFirstTaskIndex;
+ final int requiredChildCount = tasks.size();
for (int i = getChildCount(); i < requiredChildCount; i++) {
final TaskView taskView = (TaskView) inflater.inflate(R.layout.task, this, false);
addView(taskView);
@@ -340,8 +325,8 @@
setLayoutTransition(mLayoutTransition);
// Rebind and reset all task views
- for (int i = tasks.size() - 1; i >= 0; i--) {
- final int pageIndex = tasks.size() - i - 1 + mFirstTaskIndex;
+ for (int i = requiredChildCount - 1; i >= 0; i--) {
+ final int pageIndex = requiredChildCount - i - 1;
final Task task = tasks.get(i);
final TaskView taskView = (TaskView) getChildAt(pageIndex);
taskView.bind(task);
@@ -354,7 +339,7 @@
applyIconScale(false /* animate */);
if (oldChildCount != getChildCount()) {
- mQuickScrubController.snapToPageForCurrentQuickScrubSection();
+ mQuickScrubController.snapToNextTaskIfAvailable();
}
}
@@ -407,33 +392,6 @@
return padding;
}
- /**
- * Sets the {@param outRect} to match the position of the first tile such that it is scaled
- * down to match the 2nd taskView.
- * @return returns the factor which determines the scaling factor for the second task.
- */
- public static float getScaledDownPageRect(DeviceProfile dp, Context context, Rect outRect) {
- getPageRect(dp, context, outRect);
-
- int pageSpacing = context.getResources()
- .getDimensionPixelSize(R.dimen.recents_page_spacing);
- float halfScreenWidth = dp.widthPx * 0.5f;
- float halfPageWidth = outRect.width() * 0.5f;
- float pageCenter = outRect.right + pageSpacing + halfPageWidth;
- float distanceFromCenter = Math.abs(halfScreenWidth - pageCenter);
- float distanceToReachEdge = halfScreenWidth + halfPageWidth + pageSpacing;
- float linearInterpolation = Math.min(1, distanceFromCenter / distanceToReachEdge);
-
- float scale = 1 - CURVE_INTERPOLATOR.getInterpolation(linearInterpolation) * CURVE_FACTOR;
-
- int topMargin = context.getResources()
- .getDimensionPixelSize(R.dimen.task_thumbnail_top_margin);
- outRect.top -= topMargin;
- Utilities.scaleRectAboutCenter(outRect, scale);
- outRect.top += (int) (scale * topMargin);
- return linearInterpolation;
- }
-
public static void getPageRect(DeviceProfile grid, Context context, Rect outRect) {
Rect targetPadding = getPadding(grid, context);
Rect insets = grid.getInsets();
@@ -474,8 +432,7 @@
if (getPageCount() == 0 || getPageAt(0).getMeasuredWidth() == 0) {
return;
}
- final int halfPageWidth = mScrollState.halfPageWidth = getNormalChildWidth() / 2;
- mScrollState.lastScrollType = SCROLL_TYPE_NONE;
+ final int halfPageWidth = getNormalChildWidth() / 2;
final int screenCenter = mInsets.left + getPaddingLeft() + getScrollX() + halfPageWidth;
final int halfScreenWidth = getMeasuredWidth() / 2;
final int pageSpacing = mPageSpacing;
@@ -484,11 +441,11 @@
for (int i = 0; i < pageCount; i++) {
View page = getPageAt(i);
int pageCenter = page.getLeft() + halfPageWidth;
- mScrollState.distanceFromScreenCenter = screenCenter - pageCenter;
+ float distanceFromScreenCenter = screenCenter - pageCenter;
float distanceToReachEdge = halfScreenWidth + halfPageWidth + pageSpacing;
mScrollState.linearInterpolation = Math.min(1,
- Math.abs(mScrollState.distanceFromScreenCenter) / distanceToReachEdge);
- mScrollState.lastScrollType = ((PageCallbacks) page).onPageScroll(mScrollState);
+ Math.abs(distanceFromScreenCenter) / distanceToReachEdge);
+ ((PageCallbacks) page).onPageScroll(mScrollState);
}
}
@@ -499,9 +456,9 @@
private void loadVisibleTaskData() {
RecentsTaskLoader loader = mModel.getRecentsTaskLoader();
int centerPageIndex = getPageNearestToCenterOfScreen();
- int lower = Math.max(mFirstTaskIndex, centerPageIndex - 2);
+ int lower = Math.max(0, centerPageIndex - 2);
int upper = Math.min(centerPageIndex + 2, getChildCount() - 1);
- for (int i = mFirstTaskIndex; i < getChildCount(); i++) {
+ for (int i = 0; i < getChildCount(); i++) {
TaskView taskView = (TaskView) getChildAt(i);
Task task = taskView.getTask();
boolean visible = lower <= i && i <= upper;
@@ -523,7 +480,7 @@
public void onTaskDismissed(TaskView taskView) {
ActivityManagerWrapper.getInstance().removeTask(taskView.getTask().key.id);
removeView(taskView);
- if (getTaskCount() == 0) {
+ if (getChildCount() == 0) {
mLauncher.getStateManager().goToState(NORMAL);
}
}
@@ -533,10 +490,6 @@
setCurrentPage(0);
}
- public int getTaskCount() {
- return getChildCount() - mFirstTaskIndex;
- }
-
public int getRunningTaskId() {
return mRunningTaskId;
}
@@ -560,17 +513,17 @@
*/
public void showTask(int runningTaskId) {
boolean needsReload = false;
- if (getTaskCount() == 0) {
+ if (getChildCount() == 0) {
needsReload = true;
// Add an empty view for now
setLayoutTransition(null);
final TaskView taskView = (TaskView) LayoutInflater.from(getContext())
.inflate(R.layout.task, this, false);
- addView(taskView, mFirstTaskIndex);
+ addView(taskView, 0);
setLayoutTransition(mLayoutTransition);
}
mRunningTaskId = runningTaskId;
- setCurrentPage(mFirstTaskIndex);
+ setCurrentPage(0);
if (!needsReload) {
needsReload = !mModel.isLoadPlanValid(mLoadPlanId);
}
@@ -579,9 +532,7 @@
} else {
loadVisibleTaskData();
}
- if (mCurrentPage >= mFirstTaskIndex) {
- getPageAt(mCurrentPage).setAlpha(0);
- }
+ getPageAt(mCurrentPage).setAlpha(0);
}
public QuickScrubController getQuickScrubController() {
@@ -598,7 +549,7 @@
private void applyIconScale(boolean animate) {
float scale = mFirstTaskIconScaledDown ? 0 : 1;
- TaskView firstTask = (TaskView) getChildAt(mFirstTaskIndex);
+ TaskView firstTask = (TaskView) getChildAt(0);
if (firstTask != null) {
if (animate) {
firstTask.animateIconToScale(scale);
@@ -640,25 +591,17 @@
public interface PageCallbacks {
/**
- * Updates the page UI based on scroll params and returns the type of scroll
- * effect performed.
- *
- * @see #SCROLL_TYPE_NONE
- * @see #SCROLL_TYPE_TASK
- * @see #SCROLL_TYPE_WORKSPACE
+ * Updates the page UI based on scroll params.
*/
- int onPageScroll(ScrollState scrollState);
+ default void onPageScroll(ScrollState scrollState) {};
}
public static class ScrollState {
- public boolean isRtl;
- public int lastScrollType;
-
- public int halfPageWidth;
- public float distanceFromScreenCenter;
+ /**
+ * The progress from 0 to 1, where 0 is the center
+ * of the screen and 1 is the edge of the screen.
+ */
public float linearInterpolation;
-
- public float prevPageExtraWidth;
}
}
diff --git a/quickstep/src/com/android/quickstep/TaskView.java b/quickstep/src/com/android/quickstep/TaskView.java
index b407f75..e0b03b8 100644
--- a/quickstep/src/com/android/quickstep/TaskView.java
+++ b/quickstep/src/com/android/quickstep/TaskView.java
@@ -16,9 +16,6 @@
package com.android.quickstep;
-import static com.android.quickstep.RecentsView.SCROLL_TYPE_TASK;
-import static com.android.quickstep.RecentsView.SCROLL_TYPE_WORKSPACE;
-
import android.animation.TimeInterpolator;
import android.app.ActivityOptions;
import android.content.Context;
@@ -47,17 +44,15 @@
*/
public class TaskView extends FrameLayout implements TaskCallbacks, PageCallbacks {
- /** Designates how "curvy" the carousel is from 0 to 1, where 0 is a straight line. */
- public static final float CURVE_FACTOR = 0.25f;
- /** A circular curve of x from 0 to 1, where 0 is the center of the screen and 1 is the edge. */
- public static final TimeInterpolator CURVE_INTERPOLATOR
- = x -> (float) (1 - Math.sqrt(1 - Math.pow(x, 2)));
+ /** A curve of x from 0 to 1, where 0 is the center of the screen and 1 is the edge. */
+ private static final TimeInterpolator CURVE_INTERPOLATOR
+ = x -> (float) -Math.cos(x * Math.PI) / 2f + .5f;
/**
* The alpha of a black scrim on a page in the carousel as it leaves the screen.
* In the resting position of the carousel, the adjacent pages have about half this scrim.
*/
- private static final float MAX_PAGE_SCRIM_ALPHA = 0.8f;
+ private static final float MAX_PAGE_SCRIM_ALPHA = 0.4f;
private static final long SCALE_ICON_DURATION = 120;
@@ -163,34 +158,11 @@
}
@Override
- public int onPageScroll(ScrollState scrollState) {
+ public void onPageScroll(ScrollState scrollState) {
float curveInterpolation =
CURVE_INTERPOLATOR.getInterpolation(scrollState.linearInterpolation);
- float scale = 1 - curveInterpolation * CURVE_FACTOR;
- setScaleX(scale);
- setScaleY(scale);
-
- // Make sure the biggest card (i.e. the one in front) shows on top of the adjacent ones.
- setTranslationZ(scale);
mSnapshotView.setDimAlpha(1 - curveInterpolation * MAX_PAGE_SCRIM_ALPHA);
-
- float translation =
- scrollState.distanceFromScreenCenter * curveInterpolation * CURVE_FACTOR;
-
- if (scrollState.lastScrollType == SCROLL_TYPE_WORKSPACE) {
- // Make sure that the task cards do not overlap with the workspace card
- float min = scrollState.halfPageWidth * (1 - scale);
- if (scrollState.isRtl) {
- setTranslationX(Math.min(translation, min) - scrollState.prevPageExtraWidth);
- } else {
- setTranslationX(Math.max(translation, -min) + scrollState.prevPageExtraWidth);
- }
- } else {
- setTranslationX(translation);
- }
- scrollState.prevPageExtraWidth = 0;
- return SCROLL_TYPE_TASK;
}
private static final class TaskOutlineProvider extends ViewOutlineProvider {
diff --git a/quickstep/src/com/android/quickstep/TouchConsumer.java b/quickstep/src/com/android/quickstep/TouchConsumer.java
index f35f6a6..768fbda 100644
--- a/quickstep/src/com/android/quickstep/TouchConsumer.java
+++ b/quickstep/src/com/android/quickstep/TouchConsumer.java
@@ -21,8 +21,6 @@
import android.view.Choreographer;
import android.view.MotionEvent;
-import com.android.systemui.shared.system.NavigationBarCompat.HitTarget;
-
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.function.Consumer;
@@ -64,4 +62,14 @@
default Choreographer getIntrimChoreographer(MotionEventQueue queue) {
return null;
}
+
+ default void deferInit() { }
+
+ default boolean deferNextEventToMainThread() {
+ return false;
+ }
+
+ default boolean forceToLauncherConsumer() {
+ return false;
+ }
}
diff --git a/quickstep/src/com/android/quickstep/TouchInteractionService.java b/quickstep/src/com/android/quickstep/TouchInteractionService.java
index e5af3e5..04740d9 100644
--- a/quickstep/src/com/android/quickstep/TouchInteractionService.java
+++ b/quickstep/src/com/android/quickstep/TouchInteractionService.java
@@ -21,17 +21,13 @@
import static android.view.MotionEvent.ACTION_POINTER_DOWN;
import static android.view.MotionEvent.ACTION_POINTER_UP;
import static android.view.MotionEvent.ACTION_UP;
-
import static com.android.launcher3.LauncherState.FAST_OVERVIEW;
-import static com.android.launcher3.LauncherState.OVERVIEW;
-import static com.android.quickstep.QuickScrubController.QUICK_SWITCH_START_DURATION;
+import static com.android.launcher3.LauncherState.NORMAL;
import android.annotation.TargetApi;
import android.app.ActivityManager.RunningTaskInfo;
import android.app.Service;
-import android.content.ComponentName;
import android.content.Intent;
-import android.content.pm.ResolveInfo;
import android.graphics.PointF;
import android.os.Build;
import android.os.Handler;
@@ -42,11 +38,13 @@
import android.util.SparseArray;
import android.view.Choreographer;
import android.view.MotionEvent;
+import android.view.VelocityTracker;
import android.view.View;
import android.view.ViewConfiguration;
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherAppState;
+import com.android.launcher3.LauncherState;
import com.android.launcher3.MainThreadExecutor;
import com.android.launcher3.R;
import com.android.launcher3.uioverrides.UiFactory;
@@ -62,6 +60,8 @@
@TargetApi(Build.VERSION_CODES.O)
public class TouchInteractionService extends Service {
+ public static final boolean DEBUG_SHOW_OVERVIEW_BUTTON = false;
+
private static final SparseArray<String> sMotionEventNames;
static {
@@ -132,6 +132,17 @@
mEventQueue.onQuickScrubEnd();
TraceHelper.endSection("SysUiBinder", "onQuickScrubEnd");
}
+
+ @Override
+ public void onOverviewToggle() {
+ mOverviewCommandHelper.onOverviewToggle();
+ }
+
+ @Override
+ public void onOverviewShown(boolean triggeredFromAltTab) { }
+
+ @Override
+ public void onOverviewHidden(boolean triggeredFromAltTab, boolean triggeredFromHomeKey) { }
};
private final TouchConsumer mNoOpTouchConsumer = (ev) -> {};
@@ -143,17 +154,14 @@
}
private ActivityManagerWrapper mAM;
- private RunningTaskInfo mRunningTask;
private RecentsModel mRecentsModel;
- private Intent mHomeIntent;
- private ComponentName mLauncher;
private MotionEventQueue mEventQueue;
private MainThreadExecutor mMainThreadExecutor;
private ISystemUiProxy mISystemUiProxy;
+ private OverviewCommandHelper mOverviewCommandHelper;
private Choreographer mMainThreadChoreographer;
private Choreographer mBackgroundThreadChoreographer;
- private MotionEventQueue mNoOpEventQueue;
@Override
public void onCreate() {
@@ -161,19 +169,9 @@
mAM = ActivityManagerWrapper.getInstance();
mRecentsModel = RecentsModel.getInstance(this);
mMainThreadExecutor = new MainThreadExecutor();
-
- mHomeIntent = new Intent(Intent.ACTION_MAIN)
- .addCategory(Intent.CATEGORY_HOME)
- .setPackage(getPackageName())
- .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- ResolveInfo info = getPackageManager().resolveActivity(mHomeIntent, 0);
- mLauncher = new ComponentName(getPackageName(), info.activityInfo.name);
- // Clear the packageName as system can fail to dedupe it b/64108432
- mHomeIntent.setComponent(mLauncher).setPackage(null);
-
+ mOverviewCommandHelper = new OverviewCommandHelper(this);
mMainThreadChoreographer = Choreographer.getInstance();
- mNoOpEventQueue = new MotionEventQueue(mMainThreadChoreographer, mNoOpTouchConsumer);
- mEventQueue = mNoOpEventQueue;
+ mEventQueue = new MotionEventQueue(mMainThreadChoreographer, mNoOpTouchConsumer);
sConnected = true;
@@ -195,31 +193,45 @@
}
private void onBinderPreMotionEvent(@HitTarget int downHitTarget) {
- mRunningTask = mAM.getRunningTask();
-
mEventQueue.reset();
-
- if (mRunningTask == null) {
- mEventQueue = mNoOpEventQueue;
- } else if (mRunningTask.topActivity.equals(mLauncher)) {
- mEventQueue = getLauncherEventQueue();
- } else {
+ TouchConsumer oldConsumer = mEventQueue.getConsumer();
+ if (oldConsumer.deferNextEventToMainThread()) {
mEventQueue = new MotionEventQueue(mMainThreadChoreographer,
- new OtherActivityTouchConsumer(this, mRunningTask, mRecentsModel,
- mHomeIntent, mISystemUiProxy, mMainThreadExecutor,
- mBackgroundThreadChoreographer, downHitTarget));
+ new DeferredTouchConsumer((v) -> getCurrentTouchConsumer(downHitTarget,
+ oldConsumer.forceToLauncherConsumer(), v)));
+ mEventQueue.deferInit();
+ } else {
+ mEventQueue = new MotionEventQueue(
+ mMainThreadChoreographer, getCurrentTouchConsumer(downHitTarget, false, null));
}
}
- private MotionEventQueue getLauncherEventQueue() {
+ private TouchConsumer getCurrentTouchConsumer(
+ @HitTarget int downHitTarget, boolean forceToLauncher, VelocityTracker tracker) {
+ RunningTaskInfo runningTaskInfo = mAM.getRunningTask();
+
+ if (runningTaskInfo == null && !forceToLauncher) {
+ return mNoOpTouchConsumer;
+ } else if (forceToLauncher ||
+ runningTaskInfo.topActivity.equals(mOverviewCommandHelper.launcher)) {
+ return getLauncherConsumer();
+ } else {
+ if (tracker == null) {
+ tracker = VelocityTracker.obtain();
+ }
+ return new OtherActivityTouchConsumer(this, runningTaskInfo, mRecentsModel,
+ mOverviewCommandHelper.homeIntent, mISystemUiProxy, mMainThreadExecutor,
+ mBackgroundThreadChoreographer, downHitTarget, tracker);
+ }
+ }
+
+ private TouchConsumer getLauncherConsumer() {
Launcher launcher = (Launcher) LauncherAppState.getInstance(this).getModel().getCallback();
if (launcher == null) {
- return mNoOpEventQueue;
+ return mNoOpTouchConsumer;
}
-
View target = launcher.getDragLayer();
- return new MotionEventQueue(mMainThreadChoreographer,
- new LauncherTouchConsumer(launcher, target));
+ return new LauncherTouchConsumer(launcher, target);
}
private static class LauncherTouchConsumer implements TouchConsumer {
@@ -304,13 +316,12 @@
if (TouchConsumer.isInteractionQuick(interactionType)) {
Runnable action = () -> {
Runnable onComplete = null;
- if (interactionType == INTERACTION_QUICK_SCRUB) {
- mQuickScrubController.onQuickScrubStart(true);
- } else if (interactionType == INTERACTION_QUICK_SWITCH) {
+ if (interactionType == INTERACTION_QUICK_SWITCH) {
onComplete = mQuickScrubController::onQuickSwitch;
}
- mLauncher.getStateManager().goToState(FAST_OVERVIEW, true, 0,
- QUICK_SWITCH_START_DURATION, onComplete);
+ LauncherState fromState = mLauncher.getStateManager().getState();
+ mLauncher.getStateManager().goToState(FAST_OVERVIEW, true, onComplete);
+ mQuickScrubController.onQuickScrubStart(fromState == NORMAL);
};
if (mLauncher.getWorkspace().runOnOverlayHidden(action)) {
diff --git a/quickstep/src/com/android/quickstep/WindowTransformSwipeHandler.java b/quickstep/src/com/android/quickstep/WindowTransformSwipeHandler.java
index ede0ad2..0d308a0 100644
--- a/quickstep/src/com/android/quickstep/WindowTransformSwipeHandler.java
+++ b/quickstep/src/com/android/quickstep/WindowTransformSwipeHandler.java
@@ -74,6 +74,7 @@
import com.android.systemui.shared.recents.model.ThumbnailData;
import com.android.systemui.shared.recents.utilities.RectFEvaluator;
import com.android.systemui.shared.system.InputConsumerController;
+import com.android.systemui.shared.system.LatencyTrackerCompat;
import com.android.systemui.shared.system.RecentsAnimationControllerCompat;
import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
import com.android.systemui.shared.system.TransactionCompat;
@@ -468,6 +469,7 @@
mLauncherLayoutListener.setHandler(this);
onLauncherLayoutChanged();
+ final long transitionDelay = mLauncherFrameDrawnTime - mTouchTimeMs;
// Mimic ActivityMetricsLogger.logAppTransitionMultiEvents() logging for
// "Recents" activity for app transition tests for the app-to-recents case.
final LogMaker builder = new LogMaker(761/*APP_TRANSITION*/);
@@ -475,8 +477,11 @@
builder.addTaggedData(871/*FIELD_CLASS_NAME*/,
"com.android.systemui.recents.RecentsActivity");
builder.addTaggedData(319/*APP_TRANSITION_DELAY_MS*/,
- mLauncherFrameDrawnTime - mTouchTimeMs);
+ transitionDelay);
mMetricsLogger.write(builder);
+ if (LatencyTrackerCompat.isEnabled(mContext)) {
+ LatencyTrackerCompat.logToggleRecents((int) transitionDelay);
+ }
}
public void updateInteractionType(@InteractionType int interactionType) {
@@ -588,9 +593,8 @@
mLauncherTransitionController.setPlayFraction(shift);
// Make sure the window follows the first task if it moves, e.g. during quick scrub.
- int firstTaskIndex = mRecentsView.getFirstTaskIndex();
- View firstTask = mRecentsView.getPageAt(firstTaskIndex);
- int scrollForFirstTask = mRecentsView.getScrollForPage(firstTaskIndex);
+ View firstTask = mRecentsView.getPageAt(0);
+ int scrollForFirstTask = mRecentsView.getScrollForPage(0);
int offsetFromFirstTask = (scrollForFirstTask - mRecentsView.getScrollX());
if (offsetFromFirstTask != 0) {
synchronized (mTargetRect) {
@@ -721,13 +725,14 @@
/** Animates to the given progress, where 0 is the current app and 1 is overview. */
private void animateToProgress(float progress, long duration) {
+ mIsGoingToHome = Float.compare(progress, 1) == 0;
ObjectAnimator anim = mCurrentShift.animateToValue(progress).setDuration(duration);
anim.setInterpolator(Interpolators.SCROLL);
anim.addListener(new AnimationSuccessListener() {
@Override
public void onAnimationSuccess(Animator animator) {
- setStateOnUiThread((Float.compare(mCurrentShift.value, 0) == 0)
- ? STATE_SCALED_CONTROLLER_APP : STATE_SCALED_CONTROLLER_RECENTS);
+ setStateOnUiThread(mIsGoingToHome ?
+ STATE_SCALED_CONTROLLER_RECENTS : STATE_SCALED_CONTROLLER_APP);
}
});
anim.start();
@@ -748,7 +753,7 @@
}
private void invalidateHandler() {
- mCurrentShift.cancelAnimation();
+ mCurrentShift.finishAnimation();
if (mGestureEndCallback != null) {
mGestureEndCallback.run();
diff --git a/src/com/android/launcher3/FastBitmapDrawable.java b/src/com/android/launcher3/FastBitmapDrawable.java
index 5354edf..3873a81 100644
--- a/src/com/android/launcher3/FastBitmapDrawable.java
+++ b/src/com/android/launcher3/FastBitmapDrawable.java
@@ -58,7 +58,7 @@
private static final ColorMatrix sTempFilterMatrix = new ColorMatrix();
protected final Paint mPaint = new Paint(Paint.FILTER_BITMAP_FLAG | Paint.ANTI_ALIAS_FLAG);
- private final Bitmap mBitmap;
+ protected Bitmap mBitmap;
protected final int mIconColor;
private boolean mIsPressed;
@@ -324,10 +324,9 @@
return new MyConstantState(mBitmap, mIconColor);
}
- private static class MyConstantState extends ConstantState {
- private final Bitmap mBitmap;
- private final int mIconColor;
-
+ protected static class MyConstantState extends ConstantState {
+ protected final Bitmap mBitmap;
+ protected final int mIconColor;
public MyConstantState(Bitmap bitmap, int color) {
mBitmap = bitmap;
diff --git a/src/com/android/launcher3/IconCache.java b/src/com/android/launcher3/IconCache.java
index f4ae62a..ab73074 100644
--- a/src/com/android/launcher3/IconCache.java
+++ b/src/com/android/launcher3/IconCache.java
@@ -641,11 +641,8 @@
// Load the full res icon for the application, but if useLowResIcon is set, then
// only keep the low resolution icon instead of the larger full-sized icon
BitmapInfo iconInfo = li.createBadgedIconBitmap(
- appInfo.loadIcon(mPackageManager), user, appInfo.targetSdkVersion);
- if (mInstantAppResolver.isInstantApp(appInfo)) {
- li.badgeWithDrawable(iconInfo.icon,
- mContext.getDrawable(R.drawable.ic_instant_app_badge));
- }
+ appInfo.loadIcon(mPackageManager), user, appInfo.targetSdkVersion,
+ mInstantAppResolver.isInstantApp(appInfo));
li.recycle();
Bitmap lowResIcon = generateLowResIcon(iconInfo.icon);
diff --git a/src/com/android/launcher3/LauncherStateManager.java b/src/com/android/launcher3/LauncherStateManager.java
index d5813f3..950a8ac 100644
--- a/src/com/android/launcher3/LauncherStateManager.java
+++ b/src/com/android/launcher3/LauncherStateManager.java
@@ -157,11 +157,6 @@
}
private void goToState(LauncherState state, boolean animated, long delay,
- Runnable onCompleteRunnable) {
- goToState(state, animated, delay, -1, onCompleteRunnable);
- }
-
- public void goToState(LauncherState state, boolean animated, long delay, long overrideDuration,
final Runnable onCompleteRunnable) {
if (mLauncher.isInState(state)) {
if (mConfig.mCurrentAnimation == null) {
@@ -208,9 +203,6 @@
// Since state NORMAL can be reached from multiple states, just assume that the
// transition plays in reverse and use the same duration as previous state.
mConfig.duration = state == NORMAL ? mState.transitionDuration : state.transitionDuration;
- if (overrideDuration > -1) {
- mConfig.duration = overrideDuration;
- }
AnimatorSet animation = createAnimationToNewWorkspaceInternal(
state, new AnimatorSetBuilder(), onCompleteRunnable);
@@ -333,6 +325,10 @@
}
public void moveToRestState() {
+ if (mConfig.mCurrentAnimation != null && mConfig.userControlled) {
+ // The user is doing something. Lets not mess it up
+ return;
+ }
if (mState.disableRestore) {
goToState(getRestState());
// Reset history
diff --git a/src/com/android/launcher3/graphics/DrawableFactory.java b/src/com/android/launcher3/graphics/DrawableFactory.java
index 3393469..34a4e2d 100644
--- a/src/com/android/launcher3/graphics/DrawableFactory.java
+++ b/src/com/android/launcher3/graphics/DrawableFactory.java
@@ -17,6 +17,7 @@
package com.android.launcher3.graphics;
import android.content.Context;
+import android.content.pm.ActivityInfo;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.Canvas;
@@ -70,6 +71,10 @@
return drawable;
}
+ public FastBitmapDrawable newIcon(BitmapInfo info, ActivityInfo target) {
+ return new FastBitmapDrawable(info);
+ }
+
/**
* Returns a FastBitmapDrawable with the icon.
*/
@@ -80,7 +85,6 @@
return new PreloadIconDrawable(info, mPreloadProgressPath, context);
}
-
protected Path getPreloadProgressPath(Context context) {
if (Utilities.ATLEAST_OREO) {
try {
diff --git a/src/com/android/launcher3/graphics/LauncherIcons.java b/src/com/android/launcher3/graphics/LauncherIcons.java
index 4a9cdd9..2e9ff23 100644
--- a/src/com/android/launcher3/graphics/LauncherIcons.java
+++ b/src/com/android/launcher3/graphics/LauncherIcons.java
@@ -104,6 +104,7 @@
private IconNormalizer mNormalizer;
private ShadowGenerator mShadowGenerator;
+ private Drawable mWrapperIcon;
// sometimes we store linked lists of these things
private LauncherIcons next;
@@ -172,6 +173,16 @@
* The bitmap is also visually normalized with other icons.
*/
public BitmapInfo createBadgedIconBitmap(Drawable icon, UserHandle user, int iconAppTargetSdk) {
+ return createBadgedIconBitmap(icon, user, iconAppTargetSdk, false);
+ }
+
+ /**
+ * Returns a bitmap suitable for displaying as an icon at various launcher UIs like all apps
+ * view or workspace. The icon is badged for {@param user}.
+ * The bitmap is also visually normalized with other icons.
+ */
+ public BitmapInfo createBadgedIconBitmap(Drawable icon, UserHandle user, int iconAppTargetSdk,
+ boolean isInstantApp) {
float[] scale = new float[1];
icon = normalizeAndWrapToAdaptiveIcon(icon, iconAppTargetSdk, null, scale);
Bitmap bitmap = createIconBitmap(icon, scale[0]);
@@ -190,6 +201,9 @@
} else {
result = createIconBitmap(badged, 1f);
}
+ } else if (isInstantApp) {
+ badgeWithDrawable(bitmap, mContext.getDrawable(R.drawable.ic_instant_app_badge));
+ result = bitmap;
} else {
result = bitmap;
}
@@ -213,8 +227,11 @@
float scale = 1f;
if (Utilities.ATLEAST_OREO && iconAppTargetSdk >= Build.VERSION_CODES.O) {
boolean[] outShape = new boolean[1];
- AdaptiveIconDrawable dr = (AdaptiveIconDrawable)
- mContext.getDrawable(R.drawable.adaptive_icon_drawable_wrapper).mutate();
+ if (mWrapperIcon == null) {
+ mWrapperIcon = mContext.getDrawable(R.drawable.adaptive_icon_drawable_wrapper)
+ .mutate();
+ }
+ AdaptiveIconDrawable dr = (AdaptiveIconDrawable) mWrapperIcon;
dr.setBounds(0, 0, 1, 1);
scale = getNormalizer().getScale(icon, outIconBounds, dr.getIconMask(), outShape);
if (Utilities.ATLEAST_OREO && !outShape[0] && !(icon instanceof AdaptiveIconDrawable)) {
diff --git a/src/com/android/launcher3/states/InternalStateHandler.java b/src/com/android/launcher3/states/InternalStateHandler.java
index d3c0fef..0a2c3e4 100644
--- a/src/com/android/launcher3/states/InternalStateHandler.java
+++ b/src/com/android/launcher3/states/InternalStateHandler.java
@@ -56,8 +56,8 @@
sScheduler.schedule(this);
}
- public void clearReference() {
- sScheduler.clearReference(this);
+ public boolean clearReference() {
+ return sScheduler.clearReference(this);
}
public static boolean handleCreate(Launcher launcher, Intent intent) {
@@ -125,10 +125,12 @@
return false;
}
- public synchronized void clearReference(InternalStateHandler handler) {
+ public synchronized boolean clearReference(InternalStateHandler handler) {
if (mPendingHandler.get() == handler) {
mPendingHandler.clear();
+ return true;
}
+ return false;
}
}
}
\ No newline at end of file