Merge "Temporarily disable visibility-gated hotseat and prediction row updates."
diff --git a/quickstep/res/drawable/default_sandbox_app_previous_task_thumbnail.xml b/quickstep/res/drawable/default_sandbox_app_previous_task_thumbnail.xml
new file mode 100644
index 0000000..9c95497
--- /dev/null
+++ b/quickstep/res/drawable/default_sandbox_app_previous_task_thumbnail.xml
@@ -0,0 +1,17 @@
+<?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.
+-->
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+ android:shape="rectangle">
+ <solid android:color="@color/gesture_tutorial_fake_previous_task_view_color" />
+</shape>
diff --git a/quickstep/res/layout/gesture_tutorial_fragment.xml b/quickstep/res/layout/gesture_tutorial_fragment.xml
index 2ff3a5e..9d06dfb 100644
--- a/quickstep/res/layout/gesture_tutorial_fragment.xml
+++ b/quickstep/res/layout/gesture_tutorial_fragment.xml
@@ -31,6 +31,14 @@
android:visibility="invisible" />
<View
+ android:id="@+id/gesture_tutorial_fake_previous_task_view"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:scaleX="0.98"
+ android:scaleY="0.98"
+ android:visibility="invisible" />
+
+ <View
android:id="@+id/gesture_tutorial_fake_task_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
diff --git a/quickstep/res/values/dimens.xml b/quickstep/res/values/dimens.xml
index c7c0c7e..727fbd3 100644
--- a/quickstep/res/values/dimens.xml
+++ b/quickstep/res/values/dimens.xml
@@ -55,11 +55,9 @@
<!-- Total space (start + end) between the task card and the edge of the screen
in various configurations -->
- <dimen name="task_card_vert_space">40dp</dimen>
<dimen name="task_card_menu_option_vertical_padding">8dp</dimen>
<dimen name="task_card_menu_shadow_height">3dp</dimen>
<dimen name="task_card_menu_horizontal_padding">0dp</dimen>
- <dimen name="portrait_task_card_horz_space">136dp</dimen>
<dimen name="portrait_task_card_horz_space_big_overview">96dp</dimen>
<dimen name="portrait_modal_task_card_horz_space">60dp</dimen>
<dimen name="landscape_task_card_horz_space">200dp</dimen>
diff --git a/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java b/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java
index f02acab..4204597 100644
--- a/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java
+++ b/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java
@@ -20,7 +20,6 @@
import static com.android.launcher3.LauncherState.FLAG_HIDE_BACK_BUTTON;
import static com.android.launcher3.LauncherState.NORMAL;
import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
-import static com.android.quickstep.SysUINavigationMode.removeShelfFromOverview;
import static com.android.systemui.shared.system.ActivityManagerWrapper.CLOSE_SYSTEM_WINDOWS_REASON_HOME_KEY;
import android.animation.AnimatorSet;
@@ -93,7 +92,7 @@
@Override
public void onNavigationModeChanged(Mode newMode) {
getDragLayer().recreateControllers();
- if (mActionsView != null && isOverviewActionsEnabled()) {
+ if (mActionsView != null) {
mActionsView.updateVerticalMargin(newMode);
}
}
@@ -190,17 +189,7 @@
SysUINavigationMode.INSTANCE.get(this).updateMode();
mActionsView = findViewById(R.id.overview_actions_view);
((RecentsView) getOverviewPanel()).init(mActionsView);
-
- if (isOverviewActionsEnabled()) {
- // Overview is above all other launcher elements, including qsb, so move it to the top.
- getOverviewPanel().bringToFront();
- mActionsView.bringToFront();
- mActionsView.updateVerticalMargin(SysUINavigationMode.getMode(this));
- }
- }
-
- private boolean isOverviewActionsEnabled() {
- return removeShelfFromOverview(this);
+ mActionsView.updateVerticalMargin(SysUINavigationMode.getMode(this));
}
public <T extends OverviewActionsView> T getActionsView() {
@@ -251,7 +240,7 @@
@Override
public float[] getNormalOverviewScaleAndOffset() {
- return SysUINavigationMode.getMode(this) == Mode.NO_BUTTON
+ return SysUINavigationMode.getMode(this).hasGestures
? new float[] {1, 1} : new float[] {1.1f, 0};
}
diff --git a/quickstep/src/com/android/launcher3/hybridhotseat/HotseatPredictionModel.java b/quickstep/src/com/android/launcher3/hybridhotseat/HotseatPredictionModel.java
index 8f31c22..080633a 100644
--- a/quickstep/src/com/android/launcher3/hybridhotseat/HotseatPredictionModel.java
+++ b/quickstep/src/com/android/launcher3/hybridhotseat/HotseatPredictionModel.java
@@ -52,8 +52,7 @@
public static Bundle convertDataModelToAppTargetBundle(Context context, BgDataModel dataModel) {
Bundle bundle = new Bundle();
ArrayList<AppTargetEvent> events = new ArrayList<>();
- ArrayList<ItemInfo> workspaceItems = new ArrayList<>(dataModel.workspaceItems);
- workspaceItems.addAll(dataModel.appWidgets);
+ ArrayList<ItemInfo> workspaceItems = dataModel.getAllWorkspaceItems();
for (ItemInfo item : workspaceItems) {
AppTarget target = getAppTargetFromInfo(context, item);
if (target != null && !isTrackedForPrediction(item)) continue;
diff --git a/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java b/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
index 2d704f8..8c3b57a 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
@@ -29,7 +29,6 @@
import static com.android.launcher3.testing.TestProtocol.OVERVIEW_STATE_ORDINAL;
import static com.android.launcher3.testing.TestProtocol.QUICK_SWITCH_STATE_ORDINAL;
import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
-import static com.android.quickstep.SysUINavigationMode.Mode.NO_BUTTON;
import static com.android.systemui.shared.system.ActivityManagerWrapper.CLOSE_SYSTEM_WINDOWS_REASON_HOME_KEY;
import android.content.Intent;
@@ -43,7 +42,6 @@
import com.android.launcher3.LauncherSettings.Favorites;
import com.android.launcher3.LauncherState;
import com.android.launcher3.Workspace;
-import com.android.launcher3.allapps.DiscoveryBounce;
import com.android.launcher3.anim.AnimatorPlaybackController;
import com.android.launcher3.appprediction.PredictionRowView;
import com.android.launcher3.config.FeatureFlags;
@@ -55,16 +53,15 @@
import com.android.launcher3.popup.SystemShortcut;
import com.android.launcher3.statemanager.StateManager.AtomicAnimationFactory;
import com.android.launcher3.uioverrides.states.QuickstepAtomicAnimationFactory;
-import com.android.launcher3.uioverrides.touchcontrollers.LandscapeEdgeSwipeController;
import com.android.launcher3.uioverrides.touchcontrollers.NavBarToHomeTouchController;
import com.android.launcher3.uioverrides.touchcontrollers.NoButtonNavbarToOverviewTouchController;
import com.android.launcher3.uioverrides.touchcontrollers.NoButtonQuickSwitchTouchController;
-import com.android.launcher3.uioverrides.touchcontrollers.OverviewToAllAppsTouchController;
import com.android.launcher3.uioverrides.touchcontrollers.PortraitStatesTouchController;
import com.android.launcher3.uioverrides.touchcontrollers.QuickSwitchTouchController;
import com.android.launcher3.uioverrides.touchcontrollers.StatusBarTouchController;
import com.android.launcher3.uioverrides.touchcontrollers.TaskViewTouchController;
import com.android.launcher3.uioverrides.touchcontrollers.TransposedQuickSwitchTouchController;
+import com.android.launcher3.uioverrides.touchcontrollers.TwoButtonNavbarToOverviewTouchController;
import com.android.launcher3.util.OnboardingPrefs;
import com.android.launcher3.util.TouchController;
import com.android.launcher3.util.UiThreadHelper;
@@ -240,9 +237,6 @@
break;
}
case OVERVIEW_STATE_ORDINAL: {
- RecentsView recentsView = getOverviewPanel();
- DiscoveryBounce.showForOverviewIfNeeded(this,
- recentsView.getPagedOrientationHandler());
RecentsView rv = getOverviewPanel();
sendCustomAccessibilityEvent(
rv.getPageAt(rv.getCurrentPage()), TYPE_VIEW_FOCUSED, null);
@@ -275,24 +269,22 @@
ArrayList<TouchController> list = new ArrayList<>();
list.add(getDragController());
- if (mode == NO_BUTTON) {
- list.add(new NoButtonQuickSwitchTouchController(this));
- list.add(new NavBarToHomeTouchController(this));
- list.add(new NoButtonNavbarToOverviewTouchController(this));
- } else {
- if (getDeviceProfile().isVerticalBarLayout()) {
- list.add(new OverviewToAllAppsTouchController(this));
- list.add(new LandscapeEdgeSwipeController(this));
- if (mode.hasGestures) {
- list.add(new TransposedQuickSwitchTouchController(this));
- }
- } else {
- list.add(new PortraitStatesTouchController(this,
- mode.hasGestures /* allowDragToOverview */));
- if (mode.hasGestures) {
- list.add(new QuickSwitchTouchController(this));
- }
- }
+ switch (mode) {
+ case NO_BUTTON:
+ list.add(new NoButtonQuickSwitchTouchController(this));
+ list.add(new NavBarToHomeTouchController(this));
+ list.add(new NoButtonNavbarToOverviewTouchController(this));
+ break;
+ case TWO_BUTTONS:
+ list.add(new TwoButtonNavbarToOverviewTouchController(this));
+ list.add(getDeviceProfile().isVerticalBarLayout()
+ ? new TransposedQuickSwitchTouchController(this)
+ : new QuickSwitchTouchController(this));
+ list.add(new PortraitStatesTouchController(this));
+ break;
+ case THREE_BUTTONS:
+ default:
+ list.add(new PortraitStatesTouchController(this));
}
if (!getDeviceProfile().isMultiWindowMode) {
diff --git a/quickstep/src/com/android/launcher3/uioverrides/states/AllAppsState.java b/quickstep/src/com/android/launcher3/uioverrides/states/AllAppsState.java
index a2e3bdf..37c774b 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/states/AllAppsState.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/states/AllAppsState.java
@@ -17,7 +17,6 @@
import static com.android.launcher3.anim.Interpolators.DEACCEL_2;
import static com.android.launcher3.logging.StatsLogManager.LAUNCHER_STATE_ALLAPPS;
-import static com.android.quickstep.SysUINavigationMode.removeShelfFromOverview;
import android.content.Context;
@@ -84,8 +83,7 @@
@Override
public float[] getOverviewScaleAndOffset(Launcher launcher) {
- float offset = removeShelfFromOverview(launcher) ? 1 : 0;
- return new float[] {0.9f, offset};
+ return new float[] {0.9f, 1};
}
@Override
diff --git a/quickstep/src/com/android/launcher3/uioverrides/states/OverviewState.java b/quickstep/src/com/android/launcher3/uioverrides/states/OverviewState.java
index 525ff58..b295e79 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/states/OverviewState.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/states/OverviewState.java
@@ -18,8 +18,6 @@
import static com.android.launcher3.anim.Interpolators.DEACCEL_2;
import static com.android.launcher3.logging.StatsLogManager.LAUNCHER_STATE_OVERVIEW;
import static com.android.quickstep.SysUINavigationMode.Mode.NO_BUTTON;
-import static com.android.quickstep.SysUINavigationMode.hideShelfInTwoButtonLandscape;
-import static com.android.quickstep.SysUINavigationMode.removeShelfFromOverview;
import android.content.Context;
import android.graphics.Rect;
@@ -105,7 +103,7 @@
@Override
public ScaleAndTranslation getQsbScaleAndTranslation(Launcher launcher) {
- if (this == OVERVIEW && removeShelfFromOverview(launcher)) {
+ if (this == OVERVIEW) {
// Treat the QSB as part of the hotseat so they move together.
return getHotseatScaleAndTranslation(launcher);
}
@@ -124,18 +122,7 @@
@Override
public int getVisibleElements(Launcher launcher) {
- RecentsView recentsView = launcher.getOverviewPanel();
- if (removeShelfFromOverview(launcher) ||
- hideShelfInTwoButtonLandscape(launcher, recentsView.getPagedOrientationHandler())) {
- return OVERVIEW_BUTTONS;
- } else if (launcher.getDeviceProfile().isVerticalBarLayout()) {
- return VERTICAL_SWIPE_INDICATOR | OVERVIEW_BUTTONS;
- } else {
- boolean hasAllAppsHeaderExtra = launcher.getAppsView() != null
- && launcher.getAppsView().getFloatingHeaderView().hasVisibleContent();
- return HOTSEAT_SEARCH_BOX | VERTICAL_SWIPE_INDICATOR | OVERVIEW_BUTTONS
- | (hasAllAppsHeaderExtra ? ALL_APPS_HEADER_EXTRA : HOTSEAT_ICONS);
- }
+ return OVERVIEW_BUTTONS;
}
@Override
@@ -144,20 +131,6 @@
}
@Override
- public float getVerticalProgress(Launcher launcher) {
- if ((getVisibleElements(launcher) & ALL_APPS_HEADER_EXTRA) == 0) {
- // We have no all apps content, so we're still at the fully down progress.
- return super.getVerticalProgress(launcher);
- }
- return getDefaultVerticalProgress(launcher);
- }
-
- public static float getDefaultVerticalProgress(Launcher launcher) {
- return 1 - (getDefaultSwipeHeight(launcher)
- / launcher.getAllAppsController().getShiftRange());
- }
-
- @Override
public String getDescription(Launcher launcher) {
return launcher.getString(R.string.accessibility_recent_apps);
}
diff --git a/quickstep/src/com/android/launcher3/uioverrides/states/QuickstepAtomicAnimationFactory.java b/quickstep/src/com/android/launcher3/uioverrides/states/QuickstepAtomicAnimationFactory.java
index 77fd103..efb91c6 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/states/QuickstepAtomicAnimationFactory.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/states/QuickstepAtomicAnimationFactory.java
@@ -17,9 +17,7 @@
import static android.view.View.VISIBLE;
-import static com.android.launcher3.LauncherState.BACKGROUND_APP;
import static com.android.launcher3.LauncherState.HINT_STATE;
-import static com.android.launcher3.LauncherState.HOTSEAT_ICONS;
import static com.android.launcher3.LauncherState.NORMAL;
import static com.android.launcher3.LauncherState.OVERVIEW;
import static com.android.launcher3.WorkspaceStateTransitionAnimation.getSpringScaleAnimator;
@@ -30,9 +28,7 @@
import static com.android.launcher3.anim.Interpolators.DEACCEL_3;
import static com.android.launcher3.anim.Interpolators.FINAL_FRAME;
import static com.android.launcher3.anim.Interpolators.INSTANT;
-import static com.android.launcher3.anim.Interpolators.LINEAR;
import static com.android.launcher3.anim.Interpolators.OVERSHOOT_1_2;
-import static com.android.launcher3.anim.Interpolators.OVERSHOOT_1_7;
import static com.android.launcher3.anim.Interpolators.clampToProgress;
import static com.android.launcher3.states.StateAnimationConfig.ANIM_ALL_APPS_FADE;
import static com.android.launcher3.states.StateAnimationConfig.ANIM_DEPTH;
@@ -44,23 +40,17 @@
import static com.android.launcher3.states.StateAnimationConfig.ANIM_WORKSPACE_SCALE;
import static com.android.launcher3.states.StateAnimationConfig.ANIM_WORKSPACE_TRANSLATE;
import static com.android.quickstep.SysUINavigationMode.Mode.NO_BUTTON;
-import static com.android.quickstep.SysUINavigationMode.removeShelfFromOverview;
import static com.android.quickstep.views.RecentsView.RECENTS_SCALE_PROPERTY;
-import android.animation.Animator;
-import android.animation.AnimatorSet;
import android.animation.ValueAnimator;
import android.view.View;
-import android.view.animation.Interpolator;
import com.android.launcher3.CellLayout;
import com.android.launcher3.Hotseat;
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherState;
-import com.android.launcher3.LauncherState.ScaleAndTranslation;
import com.android.launcher3.Workspace;
import com.android.launcher3.allapps.AllAppsContainerView;
-import com.android.launcher3.allapps.AllAppsTransitionController;
import com.android.launcher3.states.StateAnimationConfig;
import com.android.launcher3.uioverrides.QuickstepLauncher;
import com.android.quickstep.SysUINavigationMode;
@@ -76,57 +66,12 @@
// Scale recents takes before animating in
private static final float RECENTS_PREPARE_SCALE = 1.33f;
- public static final int INDEX_SHELF_ANIM = RecentsAtomicAnimationFactory.NEXT_INDEX + 0;
-
- private static final int MY_ANIM_COUNT = 1;
- protected static final int NEXT_INDEX = RecentsAtomicAnimationFactory.NEXT_INDEX
- + MY_ANIM_COUNT;
-
// Due to use of physics, duration may differ between devices so we need to calculate and
// cache the value.
private int mHintToNormalDuration = -1;
public QuickstepAtomicAnimationFactory(QuickstepLauncher activity) {
- super(activity, MY_ANIM_COUNT);
- }
-
- @Override
- public Animator createStateElementAnimation(int index, float... values) {
- switch (index) {
- case INDEX_SHELF_ANIM: {
- AllAppsTransitionController aatc = mActivity.getAllAppsController();
- Animator springAnim = aatc.createSpringAnimation(values);
-
- if ((OVERVIEW.getVisibleElements(mActivity) & HOTSEAT_ICONS) != 0) {
- // Translate hotseat with the shelf until reaching overview.
- float overviewProgress = OVERVIEW.getVerticalProgress(mActivity);
- ScaleAndTranslation sat = OVERVIEW.getHotseatScaleAndTranslation(mActivity);
- float shiftRange = aatc.getShiftRange();
- if (values.length == 1) {
- values = new float[] {aatc.getProgress(), values[0]};
- }
- ValueAnimator hotseatAnim = ValueAnimator.ofFloat(values);
- hotseatAnim.addUpdateListener(anim -> {
- float progress = (Float) anim.getAnimatedValue();
- if (progress >= overviewProgress || mActivity.isInState(BACKGROUND_APP)) {
- float hotseatShift = (progress - overviewProgress) * shiftRange;
- mActivity.getHotseat().setTranslationY(hotseatShift + sat.translationY);
- }
- });
- hotseatAnim.setInterpolator(LINEAR);
- hotseatAnim.setDuration(springAnim.getDuration());
-
- AnimatorSet anim = new AnimatorSet();
- anim.play(hotseatAnim);
- anim.play(springAnim);
- return anim;
- }
-
- return springAnim;
- }
- default:
- return super.createStateElementAnimation(index, values);
- }
+ super(activity);
}
@Override
@@ -191,11 +136,8 @@
config.setInterpolator(ANIM_ALL_APPS_FADE, OVERSHOOT_1_2);
config.setInterpolator(ANIM_OVERVIEW_SCALE, OVERSHOOT_1_2);
config.setInterpolator(ANIM_DEPTH, OVERSHOOT_1_2);
- Interpolator translationInterpolator = removeShelfFromOverview(mActivity)
- ? OVERSHOOT_1_2
- : OVERSHOOT_1_7;
- config.setInterpolator(ANIM_OVERVIEW_TRANSLATE_X, translationInterpolator);
- config.setInterpolator(ANIM_OVERVIEW_TRANSLATE_Y, translationInterpolator);
+ config.setInterpolator(ANIM_OVERVIEW_TRANSLATE_X, OVERSHOOT_1_2);
+ config.setInterpolator(ANIM_OVERVIEW_TRANSLATE_Y, OVERSHOOT_1_2);
} else if (fromState == HINT_STATE && toState == NORMAL) {
config.setInterpolator(ANIM_DEPTH, DEACCEL_3);
if (mHintToNormalDuration == -1) {
diff --git a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/LandscapeEdgeSwipeController.java b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/LandscapeEdgeSwipeController.java
deleted file mode 100644
index 7a0f634..0000000
--- a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/LandscapeEdgeSwipeController.java
+++ /dev/null
@@ -1,67 +0,0 @@
-package com.android.launcher3.uioverrides.touchcontrollers;
-
-import static com.android.launcher3.LauncherState.NORMAL;
-import static com.android.launcher3.LauncherState.OVERVIEW;
-import static com.android.launcher3.Utilities.EDGE_NAV_BAR;
-
-import android.view.MotionEvent;
-
-import com.android.launcher3.AbstractFloatingView;
-import com.android.launcher3.Launcher;
-import com.android.launcher3.LauncherState;
-import com.android.launcher3.states.StateAnimationConfig.AnimationFlags;
-import com.android.launcher3.touch.AbstractStateChangeTouchController;
-import com.android.launcher3.touch.SingleAxisSwipeDetector;
-import com.android.quickstep.SystemUiProxy;
-
-/**
- * Touch controller for handling edge swipes in landscape/seascape UI
- */
-public class LandscapeEdgeSwipeController extends AbstractStateChangeTouchController {
-
- private static final String TAG = "LandscapeEdgeSwipeCtrl";
-
- public LandscapeEdgeSwipeController(Launcher l) {
- super(l, SingleAxisSwipeDetector.HORIZONTAL);
- }
-
- @Override
- protected boolean canInterceptTouch(MotionEvent ev) {
- if (mCurrentAnimation != null) {
- // If we are already animating from a previous state, we can intercept.
- return true;
- }
- if (AbstractFloatingView.getTopOpenView(mLauncher) != null) {
- return false;
- }
- return mLauncher.isInState(NORMAL) && (ev.getEdgeFlags() & EDGE_NAV_BAR) != 0;
- }
-
- @Override
- protected LauncherState getTargetState(LauncherState fromState, boolean isDragTowardPositive) {
- boolean draggingFromNav = mLauncher.getDeviceProfile().isSeascape() == isDragTowardPositive;
- return draggingFromNav ? OVERVIEW : NORMAL;
- }
-
- @Override
- protected float getShiftRange() {
- return mLauncher.getDragLayer().getWidth();
- }
-
- @Override
- protected float initCurrentAnimation(@AnimationFlags int animComponent) {
- float range = getShiftRange();
- long maxAccuracy = (long) (2 * range);
- mCurrentAnimation = mLauncher.getStateManager().createAnimationToNewWorkspace(mToState,
- maxAccuracy, animComponent);
- return (mLauncher.getDeviceProfile().isSeascape() ? 2 : -2) / range;
- }
-
- @Override
- protected void onSwipeInteractionCompleted(LauncherState targetState) {
- super.onSwipeInteractionCompleted(targetState);
- if (mStartState == NORMAL && targetState == OVERVIEW) {
- SystemUiProxy.INSTANCE.get(mLauncher).onOverviewShown(true, TAG);
- }
- }
-}
diff --git a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonNavbarToOverviewTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonNavbarToOverviewTouchController.java
index addfe92..45cb46f 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonNavbarToOverviewTouchController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonNavbarToOverviewTouchController.java
@@ -84,7 +84,7 @@
private ObjectAnimator mNormalToHintOverviewScrimAnimator;
public NoButtonNavbarToOverviewTouchController(Launcher l) {
- super(l, false /* allowDragToOverview */);
+ super(l);
mRecentsView = l.getOverviewPanel();
mMotionPauseDetector = new MotionPauseDetector(l);
mMotionPauseMinDisplacement = ViewConfiguration.get(l).getScaledTouchSlop();
diff --git a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/OverviewToAllAppsTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/OverviewToAllAppsTouchController.java
deleted file mode 100644
index 45e5e2f..0000000
--- a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/OverviewToAllAppsTouchController.java
+++ /dev/null
@@ -1,75 +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.touchcontrollers;
-
-import static com.android.launcher3.LauncherState.ALL_APPS;
-import static com.android.launcher3.LauncherState.NORMAL;
-import static com.android.launcher3.LauncherState.OVERVIEW;
-
-import android.view.MotionEvent;
-
-import com.android.launcher3.AbstractFloatingView;
-import com.android.launcher3.Launcher;
-import com.android.launcher3.LauncherState;
-import com.android.launcher3.Utilities;
-import com.android.quickstep.TouchInteractionService;
-import com.android.quickstep.views.RecentsView;
-
-/**
- * Touch controller from going from OVERVIEW to ALL_APPS.
- *
- * This is used in landscape mode. It is also used in portrait mode for the fallback recents.
- */
-public class OverviewToAllAppsTouchController extends PortraitStatesTouchController {
-
- public OverviewToAllAppsTouchController(Launcher l) {
- super(l, true /* allowDragToOverview */);
- }
-
- @Override
- protected boolean canInterceptTouch(MotionEvent ev) {
- if (mCurrentAnimation != null) {
- // If we are already animating from a previous state, we can intercept.
- return true;
- }
- if (AbstractFloatingView.getTopOpenView(mLauncher) != null) {
- return false;
- }
- if (mLauncher.isInState(ALL_APPS)) {
- // In all-apps only listen if the container cannot scroll itself
- return mLauncher.getAppsView().shouldContainerScroll(ev);
- } else if (mLauncher.isInState(NORMAL)) {
- return (ev.getEdgeFlags() & Utilities.EDGE_NAV_BAR) == 0;
- } else if (mLauncher.isInState(OVERVIEW)) {
- RecentsView rv = mLauncher.getOverviewPanel();
- return ev.getY() > (rv.getBottom() - rv.getPaddingBottom());
- } else {
- return false;
- }
- }
-
- @Override
- protected LauncherState getTargetState(LauncherState fromState, boolean isDragTowardPositive) {
- if (fromState == ALL_APPS && !isDragTowardPositive) {
- // Should swipe down go to OVERVIEW instead?
- return TouchInteractionService.isConnected() ?
- mLauncher.getStateManager().getLastState() : NORMAL;
- } else if (isDragTowardPositive) {
- return ALL_APPS;
- }
- return fromState;
- }
-}
diff --git a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/PortraitStatesTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/PortraitStatesTouchController.java
index 3c9b808..73f4ff2 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/PortraitStatesTouchController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/PortraitStatesTouchController.java
@@ -28,8 +28,6 @@
import static com.android.launcher3.states.StateAnimationConfig.ANIM_ALL_APPS_FADE;
import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_FADE;
import static com.android.launcher3.states.StateAnimationConfig.ANIM_VERTICAL_PROGRESS;
-import static com.android.quickstep.SysUINavigationMode.removeShelfFromOverview;
-import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_OVERVIEW_DISABLED;
import android.animation.TimeInterpolator;
import android.animation.ValueAnimator;
@@ -49,7 +47,6 @@
import com.android.launcher3.touch.SingleAxisSwipeDetector;
import com.android.launcher3.uioverrides.states.OverviewState;
import com.android.quickstep.SystemUiProxy;
-import com.android.quickstep.TouchInteractionService;
import com.android.quickstep.util.LayoutUtils;
import com.android.quickstep.views.RecentsView;
@@ -74,21 +71,18 @@
private final InterpolatorWrapper mAllAppsInterpolatorWrapper = new InterpolatorWrapper();
- private final boolean mAllowDragToOverview;
-
// If true, we will finish the current animation instantly on second touch.
private boolean mFinishFastOnSecondTouch;
- public PortraitStatesTouchController(Launcher l, boolean allowDragToOverview) {
+ public PortraitStatesTouchController(Launcher l) {
super(l, SingleAxisSwipeDetector.VERTICAL);
mOverviewPortraitStateTouchHelper = new PortraitOverviewStateTouchHelper(l);
- mAllowDragToOverview = allowDragToOverview;
}
@Override
protected boolean canInterceptTouch(MotionEvent ev) {
// If we are swiping to all apps instead of overview, allow it from anywhere.
- boolean interceptAnywhere = mLauncher.isInState(NORMAL) && !mAllowDragToOverview;
+ boolean interceptAnywhere = mLauncher.isInState(NORMAL);
if (mCurrentAnimation != null) {
if (mFinishFastOnSecondTouch) {
mCurrentAnimation.getAnimationPlayer().end();
@@ -135,37 +129,23 @@
Log.d(TestProtocol.OVERIEW_NOT_ALLAPPS, "PortraitStatesTouchController.getTargetState");
}
if (fromState == ALL_APPS && !isDragTowardPositive) {
- // Should swipe down go to OVERVIEW instead?
if (TestProtocol.sDebugTracing) {
Log.d(TestProtocol.OVERIEW_NOT_ALLAPPS,
"PortraitStatesTouchController.getTargetState 1");
}
- if (removeShelfFromOverview(mLauncher)) {
- // Don't allow swiping down to overview.
- return NORMAL;
- }
- return TouchInteractionService.isConnected() ?
- mLauncher.getStateManager().getLastState() : NORMAL;
+ return NORMAL;
} else if (fromState == OVERVIEW) {
if (TestProtocol.sDebugTracing) {
Log.d(TestProtocol.OVERIEW_NOT_ALLAPPS,
"PortraitStatesTouchController.getTargetState 2");
}
- LauncherState positiveDragTarget = ALL_APPS;
- if (removeShelfFromOverview(mLauncher)) {
- // Don't allow swiping up to all apps.
- positiveDragTarget = OVERVIEW;
- }
- return isDragTowardPositive ? positiveDragTarget : NORMAL;
+ return isDragTowardPositive ? OVERVIEW : NORMAL;
} else if (fromState == NORMAL && isDragTowardPositive) {
if (TestProtocol.sDebugTracing) {
Log.d(TestProtocol.OVERIEW_NOT_ALLAPPS,
"PortraitStatesTouchController.getTargetState 3");
}
- int stateFlags = SystemUiProxy.INSTANCE.get(mLauncher).getLastSystemUiStateFlags();
- return mAllowDragToOverview && TouchInteractionService.isConnected()
- && (stateFlags & SYSUI_STATE_OVERVIEW_DISABLED) == 0
- ? OVERVIEW : ALL_APPS;
+ return ALL_APPS;
}
return fromState;
}
diff --git a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/TaskViewTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/TaskViewTouchController.java
index 9a3a67f..7675a79 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/TaskViewTouchController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/TaskViewTouchController.java
@@ -304,7 +304,8 @@
mCurrentAnimation.setEndAction(this::clearState);
mCurrentAnimation.startWithVelocity(mActivity, goingToEnd,
- velocity, mEndDisplacement, animationDuration);
+ velocity * orientationHandler.getSecondaryTranslationDirectionFactor(),
+ mEndDisplacement, animationDuration);
}
private void clearState() {
diff --git a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/TwoButtonNavbarToOverviewTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/TwoButtonNavbarToOverviewTouchController.java
new file mode 100644
index 0000000..ff4bfe6
--- /dev/null
+++ b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/TwoButtonNavbarToOverviewTouchController.java
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.launcher3.uioverrides.touchcontrollers;
+
+import static com.android.launcher3.LauncherState.NORMAL;
+import static com.android.launcher3.LauncherState.OVERVIEW;
+import static com.android.launcher3.Utilities.EDGE_NAV_BAR;
+
+import android.view.MotionEvent;
+
+import com.android.launcher3.AbstractFloatingView;
+import com.android.launcher3.Launcher;
+import com.android.launcher3.LauncherState;
+import com.android.launcher3.states.StateAnimationConfig.AnimationFlags;
+import com.android.launcher3.touch.AbstractStateChangeTouchController;
+import com.android.launcher3.touch.SingleAxisSwipeDetector;
+import com.android.quickstep.SystemUiProxy;
+
+/**
+ * Touch controller for handling edge swipes in 2-button mode
+ */
+public class TwoButtonNavbarToOverviewTouchController extends AbstractStateChangeTouchController {
+
+ private static final String TAG = "2BtnNavbarTouchCtrl";
+
+ public TwoButtonNavbarToOverviewTouchController(Launcher l) {
+ super(l, l.getDeviceProfile().isVerticalBarLayout()
+ ? SingleAxisSwipeDetector.HORIZONTAL : SingleAxisSwipeDetector.VERTICAL);
+ }
+
+ @Override
+ protected boolean canInterceptTouch(MotionEvent ev) {
+ if (mCurrentAnimation != null) {
+ // If we are already animating from a previous state, we can intercept.
+ return true;
+ }
+ if (AbstractFloatingView.getTopOpenView(mLauncher) != null) {
+ return false;
+ }
+ return mLauncher.isInState(NORMAL) && (ev.getEdgeFlags() & EDGE_NAV_BAR) != 0;
+ }
+
+ @Override
+ protected LauncherState getTargetState(LauncherState fromState, boolean isDragTowardPositive) {
+ if (mLauncher.getDeviceProfile().isVerticalBarLayout()) {
+ boolean draggingFromNav =
+ mLauncher.getDeviceProfile().isSeascape() == isDragTowardPositive;
+ return draggingFromNav ? OVERVIEW : NORMAL;
+ } else {
+ return isDragTowardPositive ? OVERVIEW : NORMAL;
+ }
+ }
+
+ @Override
+ protected float getShiftRange() {
+ return mLauncher.getDeviceProfile().isVerticalBarLayout()
+ ? mLauncher.getDragLayer().getWidth() : super.getShiftRange();
+ }
+
+ @Override
+ protected float initCurrentAnimation(@AnimationFlags int animComponent) {
+ float range = getShiftRange();
+ long maxAccuracy = (long) (2 * range);
+ mCurrentAnimation = mLauncher.getStateManager().createAnimationToNewWorkspace(mToState,
+ maxAccuracy, animComponent);
+ return (mLauncher.getDeviceProfile().isSeascape() ? 2 : -2) / range;
+ }
+
+ @Override
+ protected void onSwipeInteractionCompleted(LauncherState targetState) {
+ super.onSwipeInteractionCompleted(targetState);
+ if (mStartState == NORMAL && targetState == OVERVIEW) {
+ SystemUiProxy.INSTANCE.get(mLauncher).onOverviewShown(true, TAG);
+ }
+ }
+}
diff --git a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
index 3c6299f..f82bc2d 100644
--- a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
+++ b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
@@ -15,6 +15,9 @@
*/
package com.android.quickstep;
+import static android.view.Surface.ROTATION_0;
+import static android.view.Surface.ROTATION_270;
+import static android.view.Surface.ROTATION_90;
import static android.widget.Toast.LENGTH_SHORT;
import static com.android.launcher3.BaseActivity.INVISIBLE_BY_STATE_HANDLER;
@@ -724,6 +727,7 @@
setIsLikelyToStartNewTask(isLikelyToStartNewTask, false /* animate */);
mStateCallback.setStateOnUiThread(STATE_GESTURE_STARTED);
mGestureStarted = true;
+ mTaskViewSimulator.setDrawsBelowRecents(true);
}
/**
@@ -1064,7 +1068,7 @@
runningTaskTarget.pictureInPictureParams) != null;
if (mIsSwipingPipToHome) {
mSwipePipToHomeAnimator = getSwipePipToHomeAnimator(
- homeAnimFactory, runningTaskTarget);
+ homeAnimFactory, runningTaskTarget, start);
mSwipePipToHomeAnimator.setDuration(SWIPE_PIP_TO_HOME_DURATION);
mSwipePipToHomeAnimator.setInterpolator(interpolator);
mSwipePipToHomeAnimator.setFloatValues(0f, 1f);
@@ -1134,23 +1138,34 @@
}
private SwipePipToHomeAnimator getSwipePipToHomeAnimator(HomeAnimationFactory homeAnimFactory,
- RemoteAnimationTargetCompat runningTaskTarget) {
+ RemoteAnimationTargetCompat runningTaskTarget, float startProgress) {
// Directly animate the app to PiP (picture-in-picture) mode
final ActivityManager.RunningTaskInfo taskInfo = mGestureState.getRunningTask();
final RecentsOrientedState orientationState = mTaskViewSimulator.getOrientationState();
+ final int windowRotation = orientationState.getDisplayRotation();
+ final int homeRotation = orientationState.getRecentsActivityRotation();
final Rect destinationBounds = SystemUiProxy.INSTANCE.get(mContext)
.startSwipePipToHome(taskInfo.topActivity,
TaskInfoCompat.getTopActivityInfo(taskInfo),
runningTaskTarget.pictureInPictureParams,
- orientationState.getRecentsActivityRotation(),
+ homeRotation,
mDp.hotseatBarSizePx);
+ final Rect startBounds = new Rect();
+ updateProgressForStartRect(new Matrix(), startProgress).round(startBounds);
final SwipePipToHomeAnimator swipePipToHomeAnimator = new SwipePipToHomeAnimator(
runningTaskTarget.taskId,
taskInfo.topActivity,
runningTaskTarget.leash.getSurfaceControl(),
TaskInfoCompat.getPipSourceRectHint(runningTaskTarget.pictureInPictureParams),
TaskInfoCompat.getWindowConfigurationBounds(taskInfo),
+ startBounds,
destinationBounds);
+ // We would assume home and app window always in the same rotation While homeRotation
+ // is not ROTATION_0 (which implies the rotation is turned on in launcher settings).
+ if (homeRotation == ROTATION_0
+ && (windowRotation == ROTATION_90 || windowRotation == ROTATION_270)) {
+ swipePipToHomeAnimator.setFromRotation(mTaskViewSimulator, windowRotation);
+ }
swipePipToHomeAnimator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationStart(Animator animation) {
diff --git a/quickstep/src/com/android/quickstep/BaseActivityInterface.java b/quickstep/src/com/android/quickstep/BaseActivityInterface.java
index 9089ae5..b4f20d1 100644
--- a/quickstep/src/com/android/quickstep/BaseActivityInterface.java
+++ b/quickstep/src/com/android/quickstep/BaseActivityInterface.java
@@ -20,8 +20,6 @@
import static com.android.launcher3.anim.Interpolators.LINEAR;
import static com.android.quickstep.AbsSwipeUpHandler.RECENTS_ATTACH_DURATION;
import static com.android.quickstep.SysUINavigationMode.getMode;
-import static com.android.quickstep.SysUINavigationMode.hideShelfInTwoButtonLandscape;
-import static com.android.quickstep.SysUINavigationMode.removeShelfFromOverview;
import static com.android.quickstep.util.RecentsAtomicAnimationFactory.INDEX_RECENTS_FADE_ANIM;
import static com.android.quickstep.util.RecentsAtomicAnimationFactory.INDEX_RECENTS_TRANSLATE_X_ANIM;
import static com.android.quickstep.views.RecentsView.ADJACENT_PAGE_OFFSET;
@@ -186,33 +184,26 @@
*/
public final void calculateTaskSize(Context context, DeviceProfile dp, Rect outRect,
PagedOrientationHandler orientedState) {
- calculateTaskSize(context, dp, getExtraSpace(context, dp, orientedState),
- outRect, orientedState);
+ calculateTaskSize(context, dp, getExtraSpace(context, dp, orientedState), outRect);
}
protected abstract float getExtraSpace(Context context, DeviceProfile dp,
PagedOrientationHandler orientedState);
- private void calculateTaskSize(
- Context context, DeviceProfile dp, float extraVerticalSpace, Rect outRect,
- PagedOrientationHandler orientationHandler) {
+ private void calculateTaskSize(Context context, DeviceProfile dp, float extraVerticalSpace,
+ Rect outRect) {
Resources res = context.getResources();
- final boolean showLargeTaskSize = showOverviewActions(context) ||
- hideShelfInTwoButtonLandscape(context, orientationHandler);
final int paddingResId;
if (dp.isMultiWindowMode) {
paddingResId = R.dimen.multi_window_task_card_horz_space;
} else if (dp.isVerticalBarLayout()) {
paddingResId = R.dimen.landscape_task_card_horz_space;
- } else if (showLargeTaskSize) {
- paddingResId = R.dimen.portrait_task_card_horz_space_big_overview;
} else {
- paddingResId = R.dimen.portrait_task_card_horz_space;
+ paddingResId = R.dimen.portrait_task_card_horz_space_big_overview;
}
float paddingHorz = res.getDimension(paddingResId);
- float paddingVert = showLargeTaskSize
- ? 0 : res.getDimension(R.dimen.task_card_vert_space);
+ float paddingVert = 0;
calculateTaskSizeInternal(context, dp, extraVerticalSpace, paddingHorz, paddingVert,
res.getDimension(R.dimen.task_thumbnail_top_margin), outRect);
@@ -405,8 +396,4 @@
pa.addFloat(recentsView, FULLSCREEN_PROGRESS, 1, 0, LINEAR);
}
}
-
- protected static boolean showOverviewActions(Context context) {
- return removeShelfFromOverview(context);
- }
}
diff --git a/quickstep/src/com/android/quickstep/FallbackActivityInterface.java b/quickstep/src/com/android/quickstep/FallbackActivityInterface.java
index 2885abf..96e4f38 100644
--- a/quickstep/src/com/android/quickstep/FallbackActivityInterface.java
+++ b/quickstep/src/com/android/quickstep/FallbackActivityInterface.java
@@ -58,9 +58,7 @@
calculateTaskSize(context, dp, outRect, orientationHandler);
if (dp.isVerticalBarLayout()
&& SysUINavigationMode.INSTANCE.get(context).getMode() != NO_BUTTON) {
- Rect targetInsets = dp.getInsets();
- int hotseatInset = dp.isSeascape() ? targetInsets.left : targetInsets.right;
- return dp.hotseatBarSizePx + hotseatInset;
+ return dp.isSeascape() ? outRect.left : (dp.widthPx - outRect.right);
} else {
return dp.heightPx - outRect.bottom;
}
@@ -161,8 +159,6 @@
@Override
protected float getExtraSpace(Context context, DeviceProfile dp,
PagedOrientationHandler orientationHandler) {
- return showOverviewActions(context)
- ? context.getResources().getDimensionPixelSize(R.dimen.overview_actions_height)
- : 0;
+ return context.getResources().getDimensionPixelSize(R.dimen.overview_actions_height);
}
}
diff --git a/quickstep/src/com/android/quickstep/FallbackSwipeHandler.java b/quickstep/src/com/android/quickstep/FallbackSwipeHandler.java
index ffb05df..901040d 100644
--- a/quickstep/src/com/android/quickstep/FallbackSwipeHandler.java
+++ b/quickstep/src/com/android/quickstep/FallbackSwipeHandler.java
@@ -294,8 +294,12 @@
if (mSurfaceControl != null) {
currentRect.roundOut(mTempRect);
Transaction t = new Transaction();
- t.setGeometry(mSurfaceControl, null, mTempRect, Surface.ROTATION_0);
- t.apply();
+ try {
+ t.setGeometry(mSurfaceControl, null, mTempRect, Surface.ROTATION_0);
+ t.apply();
+ } catch (RuntimeException e) {
+ // Ignore
+ }
}
}
diff --git a/quickstep/src/com/android/quickstep/LauncherActivityInterface.java b/quickstep/src/com/android/quickstep/LauncherActivityInterface.java
index 98b8455..9f435f5 100644
--- a/quickstep/src/com/android/quickstep/LauncherActivityInterface.java
+++ b/quickstep/src/com/android/quickstep/LauncherActivityInterface.java
@@ -18,10 +18,7 @@
import static com.android.launcher3.LauncherState.BACKGROUND_APP;
import static com.android.launcher3.LauncherState.OVERVIEW;
import static com.android.launcher3.anim.Interpolators.LINEAR;
-import static com.android.launcher3.uioverrides.states.QuickstepAtomicAnimationFactory.INDEX_SHELF_ANIM;
import static com.android.quickstep.SysUINavigationMode.getMode;
-import static com.android.quickstep.SysUINavigationMode.hideShelfInTwoButtonLandscape;
-import static com.android.quickstep.util.LayoutUtils.getDefaultSwipeHeight;
import android.content.Context;
import android.content.res.Resources;
@@ -37,7 +34,6 @@
import com.android.launcher3.LauncherInitListener;
import com.android.launcher3.LauncherState;
import com.android.launcher3.R;
-import com.android.launcher3.allapps.DiscoveryBounce;
import com.android.launcher3.anim.PendingAnimation;
import com.android.launcher3.statehandlers.DepthController;
import com.android.launcher3.statehandlers.DepthController.ClampedDepthProperty;
@@ -72,26 +68,13 @@
PagedOrientationHandler orientationHandler) {
calculateTaskSize(context, dp, outRect, orientationHandler);
if (dp.isVerticalBarLayout() && SysUINavigationMode.getMode(context) != Mode.NO_BUTTON) {
- Rect targetInsets = dp.getInsets();
- int hotseatInset = dp.isSeascape() ? targetInsets.left : targetInsets.right;
- return dp.hotseatBarSizePx + hotseatInset;
+ return dp.isSeascape() ? outRect.left : (dp.widthPx - outRect.right);
} else {
return LayoutUtils.getShelfTrackingDistance(context, dp, orientationHandler);
}
}
@Override
- public void onSwipeUpToRecentsComplete() {
- super.onSwipeUpToRecentsComplete();
- Launcher launcher = getCreatedActivity();
- if (launcher != null) {
- RecentsView recentsView = launcher.getOverviewPanel();
- DiscoveryBounce.showForOverviewIfNeeded(launcher,
- recentsView.getPagedOrientationHandler());
- }
- }
-
- @Override
public void onSwipeUpToHomeComplete(RecentsAnimationDeviceState deviceState) {
Launcher launcher = getCreatedActivity();
if (launcher == null) {
@@ -123,16 +106,6 @@
PendingAnimation pa) {
super.createBackgroundToOverviewAnim(activity, pa);
- if (!activity.getDeviceProfile().isVerticalBarLayout()
- && SysUINavigationMode.getMode(activity) != Mode.NO_BUTTON) {
- // Don't animate the shelf when the mode is NO_BUTTON, because we
- // update it atomically.
- pa.add(activity.getStateManager().createStateElementAnimation(
- INDEX_SHELF_ANIM,
- BACKGROUND_APP.getVerticalProgress(activity),
- OVERVIEW.getVerticalProgress(activity)));
- }
-
// Animate the blur and wallpaper zoom
float fromDepthRatio = BACKGROUND_APP.getDepth(activity);
float toDepthRatio = OVERVIEW.getDepth(activity);
@@ -280,35 +253,21 @@
@Override
protected float getExtraSpace(Context context, DeviceProfile dp,
PagedOrientationHandler orientationHandler) {
- if ((dp.isVerticalBarLayout() && !showOverviewActions(context))
- || hideShelfInTwoButtonLandscape(context, orientationHandler)) {
- return 0;
- } else {
- Resources res = context.getResources();
- if (showOverviewActions(context)) {
- //TODO: this needs to account for the swipe gesture height and accessibility
- // UI when shown.
- float actionsBottomMargin = 0;
- if (!dp.isVerticalBarLayout()) {
- if (getMode(context) == Mode.THREE_BUTTONS) {
- actionsBottomMargin = res.getDimensionPixelSize(
- R.dimen.overview_actions_bottom_margin_three_button);
- } else {
- actionsBottomMargin = res.getDimensionPixelSize(
- R.dimen.overview_actions_bottom_margin_gesture);
- }
- }
- float actionsHeight = actionsBottomMargin
- + res.getDimensionPixelSize(R.dimen.overview_actions_height);
- return actionsHeight;
+ Resources res = context.getResources();
+ //TODO: this needs to account for the swipe gesture height and accessibility
+ // UI when shown.
+ float actionsBottomMargin = 0;
+ if (!dp.isVerticalBarLayout()) {
+ if (getMode(context) == Mode.THREE_BUTTONS) {
+ actionsBottomMargin = res.getDimensionPixelSize(
+ R.dimen.overview_actions_bottom_margin_three_button);
} else {
- return getDefaultSwipeHeight(context, dp) + dp.workspacePageIndicatorHeight
- + res.getDimensionPixelSize(
- R.dimen.dynamic_grid_hotseat_extra_vertical_size)
- + res.getDimensionPixelSize(
- R.dimen.dynamic_grid_hotseat_bottom_padding);
+ actionsBottomMargin = res.getDimensionPixelSize(
+ R.dimen.overview_actions_bottom_margin_gesture);
}
}
+ float actionsHeight = actionsBottomMargin
+ + res.getDimensionPixelSize(R.dimen.overview_actions_height);
+ return actionsHeight;
}
-
}
\ No newline at end of file
diff --git a/quickstep/src/com/android/quickstep/OverviewCommandHelper.java b/quickstep/src/com/android/quickstep/OverviewCommandHelper.java
index 2559a6f..fd9c315 100644
--- a/quickstep/src/com/android/quickstep/OverviewCommandHelper.java
+++ b/quickstep/src/com/android/quickstep/OverviewCommandHelper.java
@@ -175,8 +175,7 @@
return;
}
- InteractionJankMonitorWrapper.begin(
- InteractionJankMonitorWrapper.CUJ_QUICK_SWITCH, 2000 /* ms timout */);
+ InteractionJankMonitorWrapper.begin(InteractionJankMonitorWrapper.CUJ_QUICK_SWITCH);
// Otherwise, start overview.
mListener = mActivityInterface.createActivityInitListener(this::onActivityReady);
diff --git a/quickstep/src/com/android/quickstep/RecentsActivity.java b/quickstep/src/com/android/quickstep/RecentsActivity.java
index 2f55f14..d050030 100644
--- a/quickstep/src/com/android/quickstep/RecentsActivity.java
+++ b/quickstep/src/com/android/quickstep/RecentsActivity.java
@@ -65,7 +65,6 @@
import com.android.quickstep.views.TaskView;
import com.android.systemui.shared.system.ActivityOptionsCompat;
import com.android.systemui.shared.system.RemoteAnimationAdapterCompat;
-import com.android.systemui.shared.system.RemoteAnimationRunnerCompat;
import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
import java.io.FileDescriptor;
@@ -332,7 +331,7 @@
@Override
public AtomicAnimationFactory<RecentsState> createAtomicAnimationFactory() {
- return new RecentsAtomicAnimationFactory<>(this, 0);
+ return new RecentsAtomicAnimationFactory<>(this);
}
private AnimatorListenerAdapter resetStateListener() {
diff --git a/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java b/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java
index d8064a2..960abeb 100644
--- a/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java
+++ b/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java
@@ -21,7 +21,6 @@
import static com.android.launcher3.util.DisplayController.DisplayHolder.CHANGE_FRAME_DELAY;
import static com.android.quickstep.SysUINavigationMode.Mode.NO_BUTTON;
import static com.android.quickstep.SysUINavigationMode.Mode.THREE_BUTTONS;
-import static com.android.quickstep.SysUINavigationMode.Mode.TWO_BUTTONS;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_A11Y_BUTTON_CLICKABLE;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_A11Y_BUTTON_LONG_CLICKABLE;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_BUBBLES_EXPANDED;
@@ -296,7 +295,7 @@
* @return whether the current nav mode has some gestures (either 2 or 0 button mode).
*/
public boolean isGesturalNavMode() {
- return mMode == TWO_BUTTONS || mMode == NO_BUTTON;
+ return mMode.hasGestures;
}
/**
diff --git a/quickstep/src/com/android/quickstep/SwipeUpAnimationLogic.java b/quickstep/src/com/android/quickstep/SwipeUpAnimationLogic.java
index 4bb1bb5..c0087b0 100644
--- a/quickstep/src/com/android/quickstep/SwipeUpAnimationLogic.java
+++ b/quickstep/src/com/android/quickstep/SwipeUpAnimationLogic.java
@@ -82,7 +82,6 @@
mTaskViewSimulator.getOrientationState().update(
mDeviceState.getRotationTouchHelper().getCurrentActiveRotation(),
mDeviceState.getRotationTouchHelper().getDisplayRotation());
- mTaskViewSimulator.setDrawsBelowRecents(true);
mMaxShadowRadius = context.getResources().getDimensionPixelSize(R.dimen.max_shadow_radius);
mTransformParams.setShadowRadius(mMaxShadowRadius);
@@ -176,6 +175,24 @@
}
/**
+ * Update with start progress for window animation to home.
+ * @param outMatrix {@link Matrix} to map a rect in Launcher space to window space.
+ * @param startProgress The progress of {@link #mCurrentShift} to start thw window from.
+ * @return {@link RectF} represents the bounds as starting point in window space.
+ */
+ protected RectF updateProgressForStartRect(Matrix outMatrix, float startProgress) {
+ mCurrentShift.updateValue(startProgress);
+ mTaskViewSimulator.apply(mTransformParams.setProgress(startProgress));
+ RectF cropRectF = new RectF(mTaskViewSimulator.getCurrentCropRect());
+
+ mTaskViewSimulator.applyWindowToHomeRotation(outMatrix);
+
+ final RectF startRect = new RectF(cropRectF);
+ mTaskViewSimulator.getCurrentMatrix().mapRect(startRect);
+ return startRect;
+ }
+
+ /**
* Creates an animation that transforms the current app window into the home app.
* @param startProgress The progress of {@link #mCurrentShift} to start the window from.
* @param homeAnimationFactory The home animation factory.
@@ -184,16 +201,11 @@
HomeAnimationFactory homeAnimationFactory) {
final RectF targetRect = homeAnimationFactory.getWindowTargetRect();
- mCurrentShift.updateValue(startProgress);
- mTaskViewSimulator.apply(mTransformParams.setProgress(startProgress));
+ Matrix homeToWindowPositionMap = new Matrix();
+ final RectF startRect = updateProgressForStartRect(
+ homeToWindowPositionMap, startProgress);
RectF cropRectF = new RectF(mTaskViewSimulator.getCurrentCropRect());
- // Matrix to map a rect in Launcher space to window space
- Matrix homeToWindowPositionMap = new Matrix();
- mTaskViewSimulator.applyWindowToHomeRotation(homeToWindowPositionMap);
-
- final RectF startRect = new RectF(cropRectF);
- mTaskViewSimulator.getCurrentMatrix().mapRect(startRect);
// Move the startRect to Launcher space as floatingIconView runs in Launcher
Matrix windowToHomePositionMap = new Matrix();
homeToWindowPositionMap.invert(windowToHomePositionMap);
diff --git a/quickstep/src/com/android/quickstep/SysUINavigationMode.java b/quickstep/src/com/android/quickstep/SysUINavigationMode.java
index 6b50218..71bf1bb 100644
--- a/quickstep/src/com/android/quickstep/SysUINavigationMode.java
+++ b/quickstep/src/com/android/quickstep/SysUINavigationMode.java
@@ -29,7 +29,6 @@
import com.android.launcher3.ResourceUtils;
import com.android.launcher3.logging.StatsLogManager.LauncherEvent;
-import com.android.launcher3.touch.PagedOrientationHandler;
import com.android.launcher3.util.MainThreadInitializedObject;
import java.io.PrintWriter;
@@ -170,18 +169,6 @@
return mMode;
}
- /** @return Whether we can remove the shelf from overview. */
- public static boolean removeShelfFromOverview(Context context) {
- // The shelf is core to the two-button mode model, so we need to continue supporting it.
- return getMode(context) != Mode.TWO_BUTTONS;
- }
-
- public static boolean hideShelfInTwoButtonLandscape(Context context,
- PagedOrientationHandler pagedOrientationHandler) {
- return getMode(context) == Mode.TWO_BUTTONS &&
- !pagedOrientationHandler.isLayoutNaturalToLauncher();
- }
-
public void dump(PrintWriter pw) {
pw.println("SysUINavigationMode:");
pw.println(" mode=" + mMode.name());
diff --git a/quickstep/src/com/android/quickstep/interaction/NavBarGestureHandler.java b/quickstep/src/com/android/quickstep/interaction/NavBarGestureHandler.java
index d1b0a70..a9a9e2a 100644
--- a/quickstep/src/com/android/quickstep/interaction/NavBarGestureHandler.java
+++ b/quickstep/src/com/android/quickstep/interaction/NavBarGestureHandler.java
@@ -56,7 +56,7 @@
/** Utility class to handle Home and Assistant gestures. */
public class NavBarGestureHandler implements OnTouchListener,
- TriggerSwipeUpTouchTracker.OnSwipeUpListener {
+ TriggerSwipeUpTouchTracker.OnSwipeUpListener, MotionPauseDetector.OnMotionPauseListener {
private static final String LOG_TAG = "NavBarGestureHandler";
private static final long RETRACT_GESTURE_ANIMATION_DURATION_MS = 300;
@@ -181,7 +181,7 @@
mLaunchedAssistant = false;
mSwipeUpTouchTracker.init();
mMotionPauseDetector.clear();
- mMotionPauseDetector.setOnMotionPauseListener(this::onMotionPauseDetected);
+ mMotionPauseDetector.setOnMotionPauseListener(this);
break;
case MotionEvent.ACTION_MOVE:
mLastPos.set(event.getX(), event.getY());
@@ -256,7 +256,13 @@
|| event.getY() >= mDisplaySize.y - mBottomGestureHeight;
}
- protected void onMotionPauseDetected() {
+ @Override
+ public void onMotionPauseChanged(boolean isPaused) {
+ mGestureCallback.onMotionPaused(isPaused);
+ }
+
+ @Override
+ public void onMotionPauseDetected() {
VibratorWrapper.INSTANCE.get(mContext).vibrate(OVERVIEW_HAPTIC);
}
@@ -311,6 +317,9 @@
/** Called whenever any touch is completed. */
void onNavBarGestureAttempted(NavBarGestureResult result, PointF finalVelocity);
+ /** Called when a motion stops or resumes */
+ default void onMotionPaused(boolean isPaused) {}
+
/** Indicates how far a touch originating in the nav bar has moved from the nav bar. */
default void setNavBarGestureProgress(@Nullable Float displacement) {}
diff --git a/quickstep/src/com/android/quickstep/interaction/SwipeUpGestureTutorialController.java b/quickstep/src/com/android/quickstep/interaction/SwipeUpGestureTutorialController.java
index 865b66e..68c63bf 100644
--- a/quickstep/src/com/android/quickstep/interaction/SwipeUpGestureTutorialController.java
+++ b/quickstep/src/com/android/quickstep/interaction/SwipeUpGestureTutorialController.java
@@ -61,16 +61,21 @@
@TargetApi(Build.VERSION_CODES.R)
abstract class SwipeUpGestureTutorialController extends TutorialController {
- private final ViewSwipeUpAnimation mViewSwipeUpAnimation;
+
+ private static final int FAKE_PREVIOUS_TASK_MARGIN = Utilities.dpToPx(12);
+
+ private final ViewSwipeUpAnimation mTaskViewSwipeUpAnimation;
private float mFakeTaskViewRadius;
private Rect mFakeTaskViewRect = new Rect();
private RunningWindowAnim mRunningWindowAnim;
+ private boolean mShowTasks = false;
+ private boolean mShowPreviousTasks = false;
SwipeUpGestureTutorialController(TutorialFragment tutorialFragment, TutorialType tutorialType) {
super(tutorialFragment, tutorialType);
RecentsAnimationDeviceState deviceState = new RecentsAnimationDeviceState(mContext);
OverviewComponentObserver observer = new OverviewComponentObserver(mContext, deviceState);
- mViewSwipeUpAnimation = new ViewSwipeUpAnimation(mContext, deviceState,
+ mTaskViewSwipeUpAnimation = new ViewSwipeUpAnimation(mContext, deviceState,
new GestureState(observer, -1));
observer.onDestroy();
deviceState.destroy();
@@ -83,16 +88,22 @@
.getWindowInsets()
.getInsets(WindowInsets.Type.systemBars());
dp.updateInsets(new Rect(insets.left, insets.top, insets.right, insets.bottom));
- mViewSwipeUpAnimation.initDp(dp);
+ mTaskViewSwipeUpAnimation.initDp(dp);
mFakeTaskViewRadius = QuickStepContract.getWindowCornerRadius(mContext.getResources());
- mFakeTaskView.setClipToOutline(true);
- mFakeTaskView.setOutlineProvider(new ViewOutlineProvider() {
+
+ ViewOutlineProvider outlineProvider = new ViewOutlineProvider() {
@Override
public void getOutline(View view, Outline outline) {
outline.setRoundRect(mFakeTaskViewRect, mFakeTaskViewRadius);
}
- });
+ };
+
+ mFakeTaskView.setClipToOutline(true);
+ mFakeTaskView.setOutlineProvider(outlineProvider);
+
+ mFakePreviousTaskView.setClipToOutline(true);
+ mFakePreviousTaskView.setOutlineProvider(outlineProvider);
}
private void cancelRunningAnimation() {
@@ -114,16 +125,22 @@
mFakeIconView.setVisibility(View.INVISIBLE);
mFakeTaskView.setVisibility(View.INVISIBLE);
mFakeTaskView.setAlpha(1);
+ mFakePreviousTaskView.setVisibility(View.INVISIBLE);
+ mFakePreviousTaskView.setAlpha(1);
+ mShowTasks = false;
+ mShowPreviousTasks = false;
mRunningWindowAnim = null;
}
};
if (toOverviewFirst) {
- anim.setFloat(mViewSwipeUpAnimation.getCurrentShift(), AnimatedFloat.VALUE, 1, ACCEL);
+ anim.setFloat(mTaskViewSwipeUpAnimation
+ .getCurrentShift(), AnimatedFloat.VALUE, 1, ACCEL);
anim.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation, boolean isReverse) {
PendingAnimation fadeAnim = new PendingAnimation(300);
fadeAnim.setViewAlpha(mFakeTaskView, 0, ACCEL);
+ fadeAnim.setViewAlpha(mFakePreviousTaskView, 0, ACCEL);
fadeAnim.addListener(resetTaskView);
AnimatorSet animset = fadeAnim.buildAnim();
animset.setStartDelay(100);
@@ -133,6 +150,7 @@
});
} else {
anim.setViewAlpha(mFakeTaskView, 0, ACCEL);
+ anim.setViewAlpha(mFakePreviousTaskView, 0, ACCEL);
anim.setViewAlpha(mFakeIconView, 0, ACCEL);
anim.addListener(resetTaskView);
}
@@ -148,8 +166,10 @@
hideFeedback();
hideHandCoachingAnimation();
cancelRunningAnimation();
+ mFakePreviousTaskView.setVisibility(View.INVISIBLE);
+ mShowPreviousTasks = false;
RectFSpringAnim rectAnim =
- mViewSwipeUpAnimation.handleSwipeUpToHome(finalVelocity);
+ mTaskViewSwipeUpAnimation.handleSwipeUpToHome(finalVelocity);
// After home animation finishes, fade out and run onEndRunnable.
rectAnim.addAnimatorListener(AnimationSuccessListener.forRunnable(
() -> fadeOutFakeTaskView(false, onEndRunnable)));
@@ -161,11 +181,31 @@
if (displacement == null || mTutorialType == HOME_NAVIGATION_COMPLETE
|| mTutorialType == OVERVIEW_NAVIGATION_COMPLETE) {
mFakeTaskView.setVisibility(View.INVISIBLE);
+ mFakePreviousTaskView.setVisibility(View.INVISIBLE);
} else {
+ mShowTasks = true;
mFakeTaskView.setVisibility(View.VISIBLE);
- if (mRunningWindowAnim == null) {
- mViewSwipeUpAnimation.updateDisplacement(displacement);
+ if (mShowPreviousTasks) {
+ mFakePreviousTaskView.setVisibility(View.VISIBLE);
}
+ if (mRunningWindowAnim == null) {
+ mTaskViewSwipeUpAnimation.updateDisplacement(displacement);
+ }
+ }
+ }
+
+ @Override
+ public void onMotionPaused(boolean unused) {
+ if (mShowTasks) {
+ if (!mShowPreviousTasks) {
+ mFakePreviousTaskView.setTranslationX(
+ -(2 * mFakePreviousTaskView.getWidth() + FAKE_PREVIOUS_TASK_MARGIN));
+ mFakePreviousTaskView.animate()
+ .setDuration(300)
+ .translationX(-(mFakePreviousTaskView.getWidth() + FAKE_PREVIOUS_TASK_MARGIN))
+ .start();
+ }
+ mShowPreviousTasks = true;
}
}
@@ -232,6 +272,7 @@
false /* isVerticalBarLayout */);
mFakeIconView.setAlpha(1);
mFakeTaskView.setAlpha(getWindowAlpha(progress));
+ mFakePreviousTaskView.setAlpha(getWindowAlpha(progress));
}
@Override
@@ -258,9 +299,11 @@
public void applySurfaceParams(SurfaceParams[] params) {
SurfaceParams p = params[0];
mFakeTaskView.setAnimationMatrix(p.matrix);
+ mFakePreviousTaskView.setAnimationMatrix(p.matrix);
mFakeTaskViewRect.set(p.windowCrop);
mFakeTaskViewRadius = p.cornerRadius;
mFakeTaskView.invalidateOutline();
+ mFakePreviousTaskView.invalidateOutline();
}
}
}
diff --git a/quickstep/src/com/android/quickstep/interaction/TutorialController.java b/quickstep/src/com/android/quickstep/interaction/TutorialController.java
index 0d5a110..12d2efc 100644
--- a/quickstep/src/com/android/quickstep/interaction/TutorialController.java
+++ b/quickstep/src/com/android/quickstep/interaction/TutorialController.java
@@ -52,6 +52,7 @@
final View mLauncherView;
final ClipIconView mFakeIconView;
final View mFakeTaskView;
+ final View mFakePreviousTaskView;
final View mRippleView;
final RippleDrawable mRippleDrawable;
@Nullable final TutorialHandAnimation mHandCoachingAnimation;
@@ -74,6 +75,8 @@
mLauncherView = getMockLauncherView();
mFakeIconView = rootView.findViewById(R.id.gesture_tutorial_fake_icon_view);
mFakeTaskView = rootView.findViewById(R.id.gesture_tutorial_fake_task_view);
+ mFakePreviousTaskView =
+ rootView.findViewById(R.id.gesture_tutorial_fake_previous_task_view);
mRippleView = rootView.findViewById(R.id.gesture_tutorial_ripple_view);
mRippleDrawable = (RippleDrawable) mRippleView.getBackground();
mHandCoachingAnimation = tutorialFragment.getHandAnimation();
@@ -93,6 +96,8 @@
if (mContext != null) {
rootView.setBackground(mContext.getDrawable(getMockWallpaperResId()));
mFakeTaskView.setBackground(mContext.getDrawable(getMockAppTaskThumbnailResId()));
+ mFakePreviousTaskView.setBackground(
+ mContext.getDrawable(getMockPreviousAppTaskThumbnailResId()));
mFakeIconView.setBackground(mContext.getDrawable(getMockAppIconResId()));
}
}
@@ -126,6 +131,11 @@
return R.drawable.default_sandbox_app_task_thumbnail;
}
+ @DrawableRes
+ protected int getMockPreviousAppTaskThumbnailResId() {
+ return R.drawable.default_sandbox_app_previous_task_thumbnail;
+ }
+
@Nullable
public View getMockLauncherView() {
InvariantDeviceProfile dp = InvariantDeviceProfile.INSTANCE.get(mContext);
diff --git a/quickstep/src/com/android/quickstep/util/LayoutUtils.java b/quickstep/src/com/android/quickstep/util/LayoutUtils.java
index b88a195..8834dc2 100644
--- a/quickstep/src/com/android/quickstep/util/LayoutUtils.java
+++ b/quickstep/src/com/android/quickstep/util/LayoutUtils.java
@@ -15,15 +15,12 @@
*/
package com.android.quickstep.util;
-import static com.android.quickstep.SysUINavigationMode.removeShelfFromOverview;
-
import android.content.Context;
import android.graphics.Rect;
import android.view.View;
import android.view.ViewGroup;
import com.android.launcher3.DeviceProfile;
-import com.android.launcher3.R;
import com.android.launcher3.touch.PagedOrientationHandler;
import com.android.quickstep.LauncherActivityInterface;
import com.android.quickstep.SysUINavigationMode;
@@ -44,16 +41,10 @@
public static int getShelfTrackingDistance(Context context, DeviceProfile dp,
PagedOrientationHandler orientationHandler) {
// Track the bottom of the window.
- if (removeShelfFromOverview(context)) {
- Rect taskSize = new Rect();
- LauncherActivityInterface.INSTANCE.calculateTaskSize(context, dp, taskSize,
- orientationHandler);
- return orientationHandler.getDistanceToBottomOfRect(dp, taskSize);
- }
- int shelfHeight = dp.hotseatBarSizePx + dp.getInsets().bottom;
- int spaceBetweenShelfAndRecents = (int) context.getResources().getDimension(
- R.dimen.task_card_vert_space);
- return shelfHeight + spaceBetweenShelfAndRecents;
+ Rect taskSize = new Rect();
+ LauncherActivityInterface.INSTANCE.calculateTaskSize(
+ context, dp, taskSize, orientationHandler);
+ return orientationHandler.getDistanceToBottomOfRect(dp, taskSize);
}
/**
diff --git a/quickstep/src/com/android/quickstep/util/QuickstepOnboardingPrefs.java b/quickstep/src/com/android/quickstep/util/QuickstepOnboardingPrefs.java
index b10adb4..a85f0d2 100644
--- a/quickstep/src/com/android/quickstep/util/QuickstepOnboardingPrefs.java
+++ b/quickstep/src/com/android/quickstep/util/QuickstepOnboardingPrefs.java
@@ -22,7 +22,6 @@
import static com.android.launcher3.LauncherState.NORMAL;
import static com.android.launcher3.LauncherState.OVERVIEW;
import static com.android.quickstep.SysUINavigationMode.Mode.NO_BUTTON;
-import static com.android.quickstep.SysUINavigationMode.removeShelfFromOverview;
import android.content.SharedPreferences;
@@ -64,27 +63,6 @@
});
}
- boolean shelfBounceSeen = getBoolean(SHELF_BOUNCE_SEEN);
- if (!shelfBounceSeen && removeShelfFromOverview(launcher)) {
- // There's no shelf in overview, so don't bounce it (can't get to all apps anyway).
- shelfBounceSeen = true;
- mSharedPrefs.edit().putBoolean(SHELF_BOUNCE_SEEN, shelfBounceSeen).apply();
- }
- if (!shelfBounceSeen) {
- stateManager.addStateListener(new StateListener<LauncherState>() {
- @Override
- public void onStateTransitionComplete(LauncherState finalState) {
- LauncherState prevState = stateManager.getLastState();
-
- if ((finalState == ALL_APPS && prevState == OVERVIEW) ||
- hasReachedMaxCount(SHELF_BOUNCE_COUNT)) {
- mSharedPrefs.edit().putBoolean(SHELF_BOUNCE_SEEN, true).apply();
- stateManager.removeStateListener(this);
- }
- }
- });
- }
-
if (FeatureFlags.ENABLE_HYBRID_HOTSEAT.get() && !hasReachedMaxCount(
HOTSEAT_DISCOVERY_TIP_COUNT)) {
stateManager.addStateListener(new StateListener<LauncherState>() {
diff --git a/quickstep/src/com/android/quickstep/util/RecentsAtomicAnimationFactory.java b/quickstep/src/com/android/quickstep/util/RecentsAtomicAnimationFactory.java
index 5b0d503..ba70bf7 100644
--- a/quickstep/src/com/android/quickstep/util/RecentsAtomicAnimationFactory.java
+++ b/quickstep/src/com/android/quickstep/util/RecentsAtomicAnimationFactory.java
@@ -32,16 +32,11 @@
public static final int INDEX_RECENTS_TRANSLATE_X_ANIM = AtomicAnimationFactory.NEXT_INDEX + 1;
private static final int MY_ANIM_COUNT = 2;
- protected static final int NEXT_INDEX = AtomicAnimationFactory.NEXT_INDEX + MY_ANIM_COUNT;
protected final ACTIVITY_TYPE mActivity;
- /**
- * @param extraAnims number of animations supported by the subclass. This should not include
- * the 2 animations supported by this class.
- */
- public RecentsAtomicAnimationFactory(ACTIVITY_TYPE activity, int extraAnims) {
- super(MY_ANIM_COUNT + extraAnims);
+ public RecentsAtomicAnimationFactory(ACTIVITY_TYPE activity) {
+ super(MY_ANIM_COUNT);
mActivity = activity;
}
diff --git a/quickstep/src/com/android/quickstep/util/RecentsOrientedState.java b/quickstep/src/com/android/quickstep/util/RecentsOrientedState.java
index facc99a..dd3e31f 100644
--- a/quickstep/src/com/android/quickstep/util/RecentsOrientedState.java
+++ b/quickstep/src/com/android/quickstep/util/RecentsOrientedState.java
@@ -26,7 +26,6 @@
import static com.android.launcher3.Utilities.newContentObserver;
import static com.android.launcher3.states.RotationHelper.ALLOW_ROTATION_PREFERENCE_KEY;
import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
-import static com.android.quickstep.SysUINavigationMode.Mode.TWO_BUTTONS;
import static java.lang.annotation.RetentionPolicy.SOURCE;
@@ -55,7 +54,6 @@
import com.android.launcher3.touch.PagedOrientationHandler;
import com.android.launcher3.util.WindowBounds;
import com.android.quickstep.BaseActivityInterface;
-import com.android.quickstep.SysUINavigationMode;
import java.lang.annotation.Retention;
import java.util.function.IntConsumer;
@@ -281,10 +279,7 @@
}
private void initFlags() {
- SysUINavigationMode.Mode currentMode = SysUINavigationMode.getMode(mContext);
- boolean rotationWatcherSupported = mOrientationListener.canDetectOrientation() &&
- currentMode != TWO_BUTTONS;
- setFlag(FLAG_ROTATION_WATCHER_SUPPORTED, rotationWatcherSupported);
+ setFlag(FLAG_ROTATION_WATCHER_SUPPORTED, mOrientationListener.canDetectOrientation());
// initialize external flags
updateAutoRotateSetting();
diff --git a/quickstep/src/com/android/quickstep/util/SwipePipToHomeAnimator.java b/quickstep/src/com/android/quickstep/util/SwipePipToHomeAnimator.java
index 87fee79..8fbd645 100644
--- a/quickstep/src/com/android/quickstep/util/SwipePipToHomeAnimator.java
+++ b/quickstep/src/com/android/quickstep/util/SwipePipToHomeAnimator.java
@@ -16,17 +16,24 @@
package com.android.quickstep.util;
+import static com.android.systemui.shared.system.InteractionJankMonitorWrapper.CUJ_APP_CLOSE_TO_PIP;
+
import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
import android.animation.RectEvaluator;
import android.animation.ValueAnimator;
import android.content.ComponentName;
+import android.graphics.Matrix;
import android.graphics.Rect;
+import android.graphics.RectF;
+import android.util.Log;
+import android.view.Surface;
import android.view.SurfaceControl;
import androidx.annotation.NonNull;
+import com.android.launcher3.anim.AnimationSuccessListener;
import com.android.systemui.shared.pip.PipSurfaceTransactionHelper;
+import com.android.systemui.shared.system.InteractionJankMonitorWrapper;
/**
* An {@link Animator} that animates an Activity to PiP (picture-in-picture) window when
@@ -39,9 +46,12 @@
*/
public class SwipePipToHomeAnimator extends ValueAnimator implements
ValueAnimator.AnimatorUpdateListener {
+ private static final String TAG = SwipePipToHomeAnimator.class.getSimpleName();
+
private final int mTaskId;
private final ComponentName mComponentName;
private final SurfaceControl mLeash;
+ private final Rect mAppBounds = new Rect();
private final Rect mStartBounds = new Rect();
private final Rect mDestinationBounds = new Rect();
private final PipSurfaceTransactionHelper mSurfaceTransactionHelper;
@@ -52,49 +62,134 @@
private final Rect mSourceHintRectInsets = new Rect();
private final Rect mSourceInsets = new Rect();
+ /** for rotation via {@link #setFromRotation(TaskViewSimulator, int)} */
+ private @RecentsOrientedState.SurfaceRotation int mFromRotation = Surface.ROTATION_0;
+ private final Rect mDestinationBoundsTransformed = new Rect();
+ private final Rect mDestinationBoundsAnimation = new Rect();
+
/**
* Flag to avoid the double-end problem since the leash would have been released
* after the first end call and any further operations upon it would lead to NPE.
*/
private boolean mHasAnimationEnded;
+ /**
+ * @param taskId Task id associated with this animator, see also {@link #getTaskId()}
+ * @param componentName Component associated with this animator,
+ * see also {@link #getComponentName()}
+ * @param leash {@link SurfaceControl} this animator operates on
+ * @param sourceRectHint See the definition in {@link android.app.PictureInPictureParams}
+ * @param appBounds Bounds of the application, sourceRectHint is based on this bounds
+ * @param startBounds Bounds of the application when this animator starts. This can be
+ * different from the appBounds if user has swiped a certain distance and
+ * Launcher has performed transform on the leash.
+ * @param destinationBounds Bounds of the destination this animator ends to
+ */
public SwipePipToHomeAnimator(int taskId,
@NonNull ComponentName componentName,
@NonNull SurfaceControl leash,
@NonNull Rect sourceRectHint,
+ @NonNull Rect appBounds,
@NonNull Rect startBounds,
@NonNull Rect destinationBounds) {
mTaskId = taskId;
mComponentName = componentName;
mLeash = leash;
+ mAppBounds.set(appBounds);
mStartBounds.set(startBounds);
mDestinationBounds.set(destinationBounds);
+ mDestinationBoundsTransformed.set(mDestinationBounds);
+ mDestinationBoundsAnimation.set(mDestinationBounds);
mSurfaceTransactionHelper = new PipSurfaceTransactionHelper();
- mSourceHintRectInsets.set(sourceRectHint.left - startBounds.left,
- sourceRectHint.top - startBounds.top,
- startBounds.right - sourceRectHint.right,
- startBounds.bottom - sourceRectHint.bottom);
+ mSourceHintRectInsets.set(sourceRectHint.left - appBounds.left,
+ sourceRectHint.top - appBounds.top,
+ appBounds.right - sourceRectHint.right,
+ appBounds.bottom - sourceRectHint.bottom);
- addListener(new AnimatorListenerAdapter() {
+ addListener(new AnimationSuccessListener() {
+ @Override
+ public void onAnimationStart(Animator animation) {
+ InteractionJankMonitorWrapper.begin(CUJ_APP_CLOSE_TO_PIP);
+ super.onAnimationStart(animation);
+ }
+
+ @Override
+ public void onAnimationCancel(Animator animation) {
+ super.onAnimationCancel(animation);
+ InteractionJankMonitorWrapper.cancel(CUJ_APP_CLOSE_TO_PIP);
+ }
+
+ @Override
+ public void onAnimationSuccess(Animator animator) {
+ InteractionJankMonitorWrapper.end(CUJ_APP_CLOSE_TO_PIP);
+ }
+
@Override
public void onAnimationEnd(Animator animation) {
+ if (!mHasAnimationEnded) super.onAnimationEnd(animation);
SwipePipToHomeAnimator.this.onAnimationEnd();
}
});
addUpdateListener(this);
}
+ /** sets the from rotation if it's different from the target rotation. */
+ public void setFromRotation(TaskViewSimulator taskViewSimulator,
+ @RecentsOrientedState.SurfaceRotation int fromRotation) {
+ if (fromRotation != Surface.ROTATION_90 && fromRotation != Surface.ROTATION_270) {
+ Log.wtf(TAG, "Not a supported rotation, rotation=" + fromRotation);
+ return;
+ }
+ mFromRotation = fromRotation;
+ final Matrix matrix = new Matrix();
+ taskViewSimulator.applyWindowToHomeRotation(matrix);
+
+ // map the destination bounds into window space. mDestinationBounds is always calculated
+ // in the final home space and the animation runs in original window space.
+ final RectF transformed = new RectF(mDestinationBounds);
+ matrix.mapRect(transformed, new RectF(mDestinationBounds));
+ transformed.round(mDestinationBoundsTransformed);
+
+ // set the animation destination bounds for RectEvaluator calculation.
+ // bounds and insets are calculated as if the transition is from mAppBounds to
+ // mDestinationBoundsAnimation, separated from rotate / scale / position.
+ mDestinationBoundsAnimation.set(mAppBounds.left, mAppBounds.top,
+ mAppBounds.left + mDestinationBounds.width(),
+ mAppBounds.top + mDestinationBounds.height());
+ }
+
@Override
public void onAnimationUpdate(ValueAnimator animator) {
if (mHasAnimationEnded) return;
final float fraction = animator.getAnimatedFraction();
- final Rect bounds = mRectEvaluator.evaluate(fraction, mStartBounds, mDestinationBounds);
+ final Rect bounds = mRectEvaluator.evaluate(fraction, mStartBounds,
+ mDestinationBoundsAnimation);
final Rect insets = mInsetsEvaluator.evaluate(fraction, mSourceInsets,
mSourceHintRectInsets);
- final SurfaceControl.Transaction tx = new SurfaceControl.Transaction();
- mSurfaceTransactionHelper.scaleAndCrop(tx, mLeash, mStartBounds, bounds, insets);
+ final SurfaceControl.Transaction tx =
+ PipSurfaceTransactionHelper.newSurfaceControlTransaction();
+ if (mFromRotation == Surface.ROTATION_90 || mFromRotation == Surface.ROTATION_270) {
+ final float degree, positionX, positionY;
+ if (mFromRotation == Surface.ROTATION_90) {
+ degree = -90 * fraction;
+ positionX = fraction * (mDestinationBoundsTransformed.left - mAppBounds.left)
+ + mAppBounds.left;
+ positionY = fraction * (mDestinationBoundsTransformed.bottom - mAppBounds.top)
+ + mAppBounds.top;
+ } else {
+ degree = 90 * fraction;
+ positionX = fraction * (mDestinationBoundsTransformed.right - mAppBounds.left)
+ + mAppBounds.left;
+ positionY = fraction * (mDestinationBoundsTransformed.top - mAppBounds.top)
+ + mAppBounds.top;
+ }
+ mSurfaceTransactionHelper.scaleAndRotate(tx, mLeash, mAppBounds, bounds, insets,
+ degree, positionX, positionY);
+ } else {
+ mSurfaceTransactionHelper.scaleAndCrop(tx, mLeash, mAppBounds, bounds, insets);
+ }
mSurfaceTransactionHelper.resetCornerRadius(tx, mLeash);
tx.apply();
}
@@ -114,8 +209,9 @@
private void onAnimationEnd() {
if (mHasAnimationEnded) return;
- final SurfaceControl.Transaction tx = new SurfaceControl.Transaction();
- mSurfaceTransactionHelper.reset(tx, mLeash, mDestinationBounds);
+ final SurfaceControl.Transaction tx =
+ PipSurfaceTransactionHelper.newSurfaceControlTransaction();
+ mSurfaceTransactionHelper.reset(tx, mLeash, mDestinationBoundsTransformed, mFromRotation);
tx.apply();
mHasAnimationEnded = true;
}
diff --git a/quickstep/src/com/android/quickstep/views/OverviewActionsView.java b/quickstep/src/com/android/quickstep/views/OverviewActionsView.java
index b8e07cb..8fb7e03 100644
--- a/quickstep/src/com/android/quickstep/views/OverviewActionsView.java
+++ b/quickstep/src/com/android/quickstep/views/OverviewActionsView.java
@@ -17,7 +17,6 @@
package com.android.quickstep.views;
import static com.android.launcher3.config.FeatureFlags.ENABLE_OVERVIEW_SHARE;
-import static com.android.quickstep.SysUINavigationMode.removeShelfFromOverview;
import android.content.Context;
import android.content.res.Configuration;
@@ -51,17 +50,15 @@
private final Rect mInsets = new Rect();
@IntDef(flag = true, value = {
- HIDDEN_UNSUPPORTED_NAVIGATION,
HIDDEN_NON_ZERO_ROTATION,
HIDDEN_NO_TASKS,
HIDDEN_NO_RECENTS})
@Retention(RetentionPolicy.SOURCE)
public @interface ActionsHiddenFlags { }
- public static final int HIDDEN_UNSUPPORTED_NAVIGATION = 1 << 0;
- public static final int HIDDEN_NON_ZERO_ROTATION = 1 << 1;
- public static final int HIDDEN_NO_TASKS = 1 << 2;
- public static final int HIDDEN_NO_RECENTS = 1 << 3;
+ public static final int HIDDEN_NON_ZERO_ROTATION = 1 << 0;
+ public static final int HIDDEN_NO_TASKS = 1 << 1;
+ public static final int HIDDEN_NO_RECENTS = 1 << 2;
@IntDef(flag = true, value = {
DISABLED_SCROLLING,
@@ -138,12 +135,6 @@
}
@Override
- protected void onAttachedToWindow() {
- super.onAttachedToWindow();
- updateHiddenFlags(HIDDEN_UNSUPPORTED_NAVIGATION, !removeShelfFromOverview(getContext()));
- }
-
- @Override
protected void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
updateVerticalMargin(SysUINavigationMode.getMode(getContext()));
diff --git a/quickstep/src/com/android/quickstep/views/ShelfScrimView.java b/quickstep/src/com/android/quickstep/views/ShelfScrimView.java
index e6613eb..db04fc0 100644
--- a/quickstep/src/com/android/quickstep/views/ShelfScrimView.java
+++ b/quickstep/src/com/android/quickstep/views/ShelfScrimView.java
@@ -15,7 +15,6 @@
*/
package com.android.quickstep.views;
-import static com.android.launcher3.LauncherState.ALL_APPS_HEADER_EXTRA;
import static com.android.launcher3.LauncherState.OVERVIEW;
import static com.android.launcher3.anim.Interpolators.ACCEL;
import static com.android.launcher3.anim.Interpolators.ACCEL_2;
@@ -30,7 +29,6 @@
import android.graphics.Path;
import android.graphics.Path.Direction;
import android.graphics.Path.Op;
-import android.graphics.Rect;
import android.util.AttributeSet;
import android.view.animation.Interpolator;
@@ -45,7 +43,6 @@
import com.android.quickstep.SysUINavigationMode;
import com.android.quickstep.SysUINavigationMode.Mode;
import com.android.quickstep.SysUINavigationMode.NavigationModeChangeListener;
-import com.android.quickstep.util.LayoutUtils;
/**
* Scrim used for all-apps and shelf in Overview
@@ -149,25 +146,11 @@
mRemainingScreenPathValid = false;
mShiftRange = mLauncher.getAllAppsController().getShiftRange();
- Context context = getContext();
- if ((OVERVIEW.getVisibleElements(mLauncher) & ALL_APPS_HEADER_EXTRA) == 0) {
- if (SysUINavigationMode.removeShelfFromOverview(context)) {
- // Fade in all apps background quickly to distinguish from swiping from nav bar.
- mMidAlpha = Themes.getAttrInteger(context, R.attr.allAppsInterimScrimAlpha);
- mMidProgress = OverviewState.getDefaultVerticalProgress(mLauncher);
- } else {
- mMidAlpha = 0;
- mMidProgress = 1;
- }
- } else {
- mMidAlpha = Themes.getAttrInteger(context, R.attr.allAppsInterimScrimAlpha);
- mMidProgress = OVERVIEW.getVerticalProgress(mLauncher);
- Rect hotseatPadding = dp.getHotseatLayoutPadding();
- int hotseatSize = dp.hotseatBarSizePx + dp.getInsets().bottom
- + hotseatPadding.bottom + hotseatPadding.top;
- float dragHandleTop =
- Math.min(hotseatSize, LayoutUtils.getDefaultSwipeHeight(context, dp));
- }
+ // Fade in all apps background quickly to distinguish from swiping from nav bar.
+ mMidAlpha = Themes.getAttrInteger(getContext(), R.attr.allAppsInterimScrimAlpha);
+ mMidProgress = 1 - (OverviewState.getDefaultSwipeHeight(mLauncher)
+ / mLauncher.getAllAppsController().getShiftRange());
+
mTopOffset = dp.getInsets().top;
mShelfTopAtThreshold = mShiftRange * SCRIM_CATCHUP_THRESHOLD + mTopOffset;
}
diff --git a/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java b/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java
index cc97f4b..0fe5432 100644
--- a/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java
+++ b/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java
@@ -31,14 +31,11 @@
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherState;
-import com.android.launcher3.tapl.AllApps;
-import com.android.launcher3.tapl.AllAppsFromOverview;
import com.android.launcher3.tapl.Background;
import com.android.launcher3.tapl.LauncherInstrumentation.NavigationModel;
import com.android.launcher3.tapl.Overview;
import com.android.launcher3.tapl.OverviewActions;
import com.android.launcher3.tapl.OverviewTask;
-import com.android.launcher3.tapl.TestHelpers;
import com.android.launcher3.ui.TaplTestsLauncher3;
import com.android.quickstep.NavigationModeSwitchRule.NavigationModeSwitch;
import com.android.quickstep.views.RecentsView;
@@ -94,19 +91,6 @@
}
@Test
- public void testAllAppsFromOverview() throws Exception {
- if (!mLauncher.hasAllAppsInOverview()) {
- return;
- }
-
- // Test opening all apps from Overview.
- assertNotNull("switchToAllApps() returned null",
- mLauncher.getWorkspace().switchToOverview().switchToAllApps());
-
- TaplTestsLauncher3.runAllAppsTest(this, mLauncher.getAllAppsFromOverview());
- }
-
- @Test
@PortraitLandscape
public void testOverview() throws Exception {
startTestAppsWithCheck();
@@ -159,28 +143,6 @@
launcher -> assertEquals("Dismissing a task didn't remove 1 task from Overview",
numTasks - 1, getTaskCount(launcher)));
- if (mLauncher.hasAllAppsInOverview() && (!TestHelpers.isInLauncherProcess()
- || getFromLauncher(launcher -> !launcher.getDeviceProfile().isLandscape))) {
- // Test switching to all apps and back.
- final AllAppsFromOverview allApps = overview.switchToAllApps();
- assertNotNull("overview.switchToAllApps() returned null (1)", allApps);
- assertTrue("Launcher internal state is not All Apps (1)",
- isInState(() -> LauncherState.ALL_APPS));
-
- overview = allApps.switchBackToOverview();
- assertNotNull("allApps.switchBackToOverview() returned null", overview);
- assertTrue("Launcher internal state didn't switch to Overview",
- isInState(() -> LauncherState.OVERVIEW));
-
- // Test UIDevice.pressBack()
- overview.switchToAllApps();
- assertNotNull("overview.switchToAllApps() returned null (2)", allApps);
- assertTrue("Launcher internal state is not All Apps (2)",
- isInState(() -> LauncherState.ALL_APPS));
- mDevice.pressBack();
- mLauncher.getOverview();
- }
-
// Test UIDevice.pressHome, once we are in AllApps.
mDevice.pressHome();
waitForState("Launcher internal state didn't switch to Home", () -> LauncherState.NORMAL);
@@ -200,19 +162,17 @@
@NavigationModeSwitch
@PortraitLandscape
public void testOverviewActions() throws Exception {
- if (mLauncher.getNavigationModel() != NavigationModel.TWO_BUTTON) {
- // Experimenting for b/165029151:
- final Overview overview = mLauncher.pressHome().switchToOverview();
- if (overview.hasTasks()) overview.dismissAllTasks();
- mLauncher.pressHome();
- //
+ // Experimenting for b/165029151:
+ final Overview overview = mLauncher.pressHome().switchToOverview();
+ if (overview.hasTasks()) overview.dismissAllTasks();
+ mLauncher.pressHome();
+ //
- startTestAppsWithCheck();
- OverviewActions actionsView =
- mLauncher.pressHome().switchToOverview().getOverviewActions();
- actionsView.clickAndDismissScreenshot();
- actionsView.clickAndDismissShare();
- }
+ startTestAppsWithCheck();
+ OverviewActions actionsView =
+ mLauncher.pressHome().switchToOverview().getOverviewActions();
+ actionsView.clickAndDismissScreenshot();
+ actionsView.clickAndDismissShare();
}
private int getCurrentOverviewPage(Launcher launcher) {
@@ -224,20 +184,6 @@
}
@Test
- public void testAppIconLaunchFromAllAppsFromOverview() throws Exception {
- if (!mLauncher.hasAllAppsInOverview()) {
- return;
- }
-
- final AllApps allApps =
- mLauncher.getWorkspace().switchToOverview().switchToAllApps();
- assertTrue("Launcher internal state is not All Apps",
- isInState(() -> LauncherState.ALL_APPS));
-
- TaplTestsLauncher3.runIconLaunchFromAllAppsTest(this, allApps);
- }
-
- @Test
@NavigationModeSwitch
@PortraitLandscape
public void testSwitchToOverview() throws Exception {
diff --git a/res/layout/launcher.xml b/res/layout/launcher.xml
index 0c18c8a..8451b77 100644
--- a/res/layout/launcher.xml
+++ b/res/layout/launcher.xml
@@ -49,11 +49,6 @@
android:id="@+id/hotseat"
layout="@layout/hotseat" />
- <include
- android:id="@+id/overview_panel"
- layout="@layout/overview_panel" />
-
-
<!-- Keep these behind the workspace so that they are not visible when
we go into AllApps -->
<com.android.launcher3.pageindicators.WorkspacePageIndicator
@@ -77,6 +72,10 @@
android:layout_width="match_parent"
android:layout_height="match_parent" />
+ <include
+ android:id="@+id/overview_panel"
+ layout="@layout/overview_panel" />
+
</com.android.launcher3.dragndrop.DragLayer>
</com.android.launcher3.LauncherRootView>
diff --git a/res/values/colors.xml b/res/values/colors.xml
index f56fbaa..78c2df6 100644
--- a/res/values/colors.xml
+++ b/res/values/colors.xml
@@ -37,6 +37,7 @@
<color name="gesture_tutorial_ripple_color">#A0C2F9</color> <!-- Light Blue -->
<color name="gesture_tutorial_fake_task_view_color">#6DA1FF</color> <!-- Light Blue -->
+ <color name="gesture_tutorial_fake_previous_task_view_color">#9CCC65</color> <!-- Light Green -->
<color name="gesture_tutorial_action_button_label_color">#FFFFFFFF</color>
<color name="gesture_tutorial_primary_color">#1A73E8</color> <!-- Blue -->
</resources>
diff --git a/robolectric_tests/src/com/android/launcher3/model/PackageInstallStateChangedTaskTest.java b/robolectric_tests/src/com/android/launcher3/model/PackageInstallStateChangedTaskTest.java
index e43df21..412ace0 100644
--- a/robolectric_tests/src/com/android/launcher3/model/PackageInstallStateChangedTaskTest.java
+++ b/robolectric_tests/src/com/android/launcher3/model/PackageInstallStateChangedTaskTest.java
@@ -67,7 +67,7 @@
for (ItemInfo info : mModelHelper.getBgDataModel().itemsIdMap) {
if (info instanceof WorkspaceItemInfo) {
assertEquals(updates.contains(info.id) ? progress: 0,
- ((WorkspaceItemInfo) info).getInstallProgress());
+ ((WorkspaceItemInfo) info).getProgressLevel());
} else {
assertEquals(updates.contains(info.id) ? progress: -1,
((LauncherAppWidgetInfo) info).installProgress);
diff --git a/src/com/android/launcher3/BubbleTextView.java b/src/com/android/launcher3/BubbleTextView.java
index 3eb52ad..f44f88b 100644
--- a/src/com/android/launcher3/BubbleTextView.java
+++ b/src/com/android/launcher3/BubbleTextView.java
@@ -50,6 +50,7 @@
import android.view.ViewDebug;
import android.widget.TextView;
+import androidx.annotation.Nullable;
import androidx.core.graphics.ColorUtils;
import com.android.launcher3.Launcher.OnResumeCallback;
@@ -71,7 +72,6 @@
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.model.data.ItemInfoWithIcon;
import com.android.launcher3.model.data.PackageItemInfo;
-import com.android.launcher3.model.data.PromiseAppInfo;
import com.android.launcher3.model.data.RemoteActionItemInfo;
import com.android.launcher3.model.data.WorkspaceItemInfo;
import com.android.launcher3.util.SafeCloseable;
@@ -287,10 +287,7 @@
public void applyFromWorkspaceItem(WorkspaceItemInfo info, boolean promiseStateChanged) {
applyIconAndLabel(info);
setTag(info);
- if (promiseStateChanged || (info.hasPromiseIconUi())) {
- applyPromiseState(promiseStateChanged);
- }
-
+ applyLoadingState(promiseStateChanged);
applyDotState(info, false /* animate */);
}
@@ -303,9 +300,8 @@
// Verify high res immediately
verifyHighRes();
- if (info instanceof PromiseAppInfo) {
- PromiseAppInfo promiseAppInfo = (PromiseAppInfo) info;
- applyProgressLevel(promiseAppInfo.level);
+ if ((info.runtimeStatusFlags & ItemInfoWithIcon.FLAG_SHOW_DOWNLOAD_PROGRESS_MASK) != 0) {
+ applyProgressLevel(info.getProgressLevel());
}
applyDotState(info, false /* animate */);
}
@@ -335,6 +331,10 @@
mDotParams.color = IconPalette.getMutedColor(info.bitmap.color, 0.54f);
setIcon(iconDrawable);
+ applyLabel(info);
+ }
+
+ private void applyLabel(ItemInfoWithIcon info) {
setText(info.title);
if (info.contentDescription != null) {
setContentDescription(info.isDisabled()
@@ -595,21 +595,35 @@
mLongPressHelper.cancelLongPress();
}
- public void applyPromiseState(boolean promiseStateChanged) {
+ /** Applies the loading progress value to the progress bar.
+ *
+ * If this app is installing, the progress bar will be updated with the installation progress.
+ * If this app is installed and downloading incrementally, the progress bar will be updated
+ * with the total download progress.
+ */
+ public void applyLoadingState(boolean promiseStateChanged) {
if (getTag() instanceof WorkspaceItemInfo) {
WorkspaceItemInfo info = (WorkspaceItemInfo) getTag();
- final boolean isPromise = info.hasPromiseIconUi();
- final int progressLevel = isPromise ?
- ((info.hasStatusFlag(WorkspaceItemInfo.FLAG_INSTALL_SESSION_ACTIVE) ?
- info.getInstallProgress() : 0)) : 100;
-
- PreloadIconDrawable preloadDrawable = applyProgressLevel(progressLevel);
- if (preloadDrawable != null && promiseStateChanged) {
- preloadDrawable.maybePerformFinishedAnimation();
+ int progressLevel = info.getProgressLevel();
+ if ((info.runtimeStatusFlags & ItemInfoWithIcon.FLAG_INCREMENTAL_DOWNLOAD_ACTIVE)
+ != 0) {
+ updateProgressBarUi(progressLevel, progressLevel == 100);
+ } else if (info.hasPromiseIconUi() || (info.runtimeStatusFlags
+ & ItemInfoWithIcon.FLAG_INSTALL_SESSION_ACTIVE) != 0) {
+ updateProgressBarUi(progressLevel, promiseStateChanged);
}
}
}
+ private void updateProgressBarUi(int progressLevel, boolean maybePerformFinishedAnimation) {
+ PreloadIconDrawable preloadDrawable = applyProgressLevel(progressLevel);
+ if (preloadDrawable != null && maybePerformFinishedAnimation) {
+ preloadDrawable.maybePerformFinishedAnimation();
+ }
+ }
+
+ /** Applies the given progress level to the this icon's progress bar. */
+ @Nullable
public PreloadIconDrawable applyProgressLevel(int progressLevel) {
if (getTag() instanceof ItemInfoWithIcon) {
ItemInfoWithIcon info = (ItemInfoWithIcon) getTag();
@@ -629,9 +643,11 @@
if (mIcon instanceof PreloadIconDrawable) {
preloadDrawable = (PreloadIconDrawable) mIcon;
preloadDrawable.setLevel(progressLevel);
+ preloadDrawable.setIsDisabled(!info.isAppStartable());
} else {
preloadDrawable = newPendingIcon(getContext(), info);
preloadDrawable.setLevel(progressLevel);
+ preloadDrawable.setIsDisabled(!info.isAppStartable());
setIcon(preloadDrawable);
}
return preloadDrawable;
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index a96fabd..5b55c4b 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -137,7 +137,6 @@
import com.android.launcher3.model.data.FolderInfo;
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.model.data.LauncherAppWidgetInfo;
-import com.android.launcher3.model.data.PromiseAppInfo;
import com.android.launcher3.model.data.WorkspaceItemInfo;
import com.android.launcher3.notification.NotificationListener;
import com.android.launcher3.pm.PinRequestHelper;
@@ -2516,8 +2515,8 @@
}
@Override
- public void bindPromiseAppProgressUpdated(PromiseAppInfo app) {
- mAppsView.getAppsStore().updatePromiseAppProgress(app);
+ public void bindIncrementalDownloadProgressUpdated(AppInfo app) {
+ mAppsView.getAppsStore().updateProgressBar(app);
}
@Override
diff --git a/src/com/android/launcher3/LauncherModel.java b/src/com/android/launcher3/LauncherModel.java
index 8458152..e89b9b0 100644
--- a/src/com/android/launcher3/LauncherModel.java
+++ b/src/com/android/launcher3/LauncherModel.java
@@ -48,6 +48,7 @@
import com.android.launcher3.model.LoaderTask;
import com.android.launcher3.model.ModelDelegate;
import com.android.launcher3.model.ModelWriter;
+import com.android.launcher3.model.PackageIncrementalDownloadUpdatedTask;
import com.android.launcher3.model.PackageInstallStateChangedTask;
import com.android.launcher3.model.PackageUpdatedTask;
import com.android.launcher3.model.ShortcutsChangedTask;
@@ -196,6 +197,15 @@
}
@Override
+ public void onPackageLoadingProgressChanged(
+ String packageName, UserHandle user, float progress) {
+ if (Utilities.ATLEAST_S) {
+ enqueueModelUpdateTask(new PackageIncrementalDownloadUpdatedTask(
+ packageName, user, progress));
+ }
+ }
+
+ @Override
public void onShortcutsChanged(String packageName, List<ShortcutInfo> shortcuts,
UserHandle user) {
enqueueModelUpdateTask(new ShortcutsChangedTask(packageName, shortcuts, user, true));
diff --git a/src/com/android/launcher3/LauncherProvider.java b/src/com/android/launcher3/LauncherProvider.java
index aeed16a..e151777 100644
--- a/src/com/android/launcher3/LauncherProvider.java
+++ b/src/com/android/launcher3/LauncherProvider.java
@@ -1099,11 +1099,20 @@
* @return the max _id in the provided table.
*/
@Thunk static int getMaxId(SQLiteDatabase db, String query, Object... args) {
- int max = (int) DatabaseUtils.longForQuery(db,
- String.format(Locale.ENGLISH, query, args),
- null);
- if (max < 0) {
- throw new RuntimeException("Error: could not query max id");
+ int max = 0;
+ try (SQLiteStatement prog = db.compileStatement(
+ String.format(Locale.ENGLISH, query, args))) {
+ max = (int) DatabaseUtils.longForQuery(prog, null);
+ if (max < 0) {
+ throw new RuntimeException("Error: could not query max id");
+ }
+ } catch (IllegalArgumentException exception) {
+ String message = exception.getMessage();
+ if (message.contains("re-open") && message.contains("already-closed")) {
+ // Don't crash trying to end a transaction an an already closed DB. See b/173162852.
+ } else {
+ throw exception;
+ }
}
return max;
}
diff --git a/src/com/android/launcher3/Utilities.java b/src/com/android/launcher3/Utilities.java
index 1e023df..df5d234 100644
--- a/src/com/android/launcher3/Utilities.java
+++ b/src/com/android/launcher3/Utilities.java
@@ -107,12 +107,13 @@
public static final String[] EMPTY_STRING_ARRAY = new String[0];
public static final Person[] EMPTY_PERSON_ARRAY = new Person[0];
- public static final boolean ATLEAST_R = BuildCompat.isAtLeastR();
+ public static final boolean ATLEAST_P = Build.VERSION.SDK_INT >= Build.VERSION_CODES.P;
public static final boolean ATLEAST_Q = Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q;
- public static final boolean ATLEAST_P =
- Build.VERSION.SDK_INT >= Build.VERSION_CODES.P;
+ public static final boolean ATLEAST_R = Build.VERSION.SDK_INT >= Build.VERSION_CODES.R;
+
+ public static final boolean ATLEAST_S = BuildCompat.isAtLeastS();
/**
* Set on a motion event dispatched from the nav bar. See {@link MotionEvent#setEdgeFlags(int)}.
@@ -404,6 +405,11 @@
return (size / densityRatio);
}
+ /** Converts a dp value to pixels for the current device. */
+ public static int dpToPx(float dp) {
+ return (int) (dp * Resources.getSystem().getDisplayMetrics().density);
+ }
+
public static int pxFromSp(float size, DisplayMetrics metrics) {
return (int) Math.round(TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP,
size, metrics));
diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java
index 777ea3c..65eba20 100644
--- a/src/com/android/launcher3/Workspace.java
+++ b/src/com/android/launcher3/Workspace.java
@@ -3154,7 +3154,7 @@
ItemOperator op = (info, v) -> {
if (info instanceof WorkspaceItemInfo && v instanceof BubbleTextView
&& updates.contains(info)) {
- ((BubbleTextView) v).applyPromiseState(false /* promiseStateChanged */);
+ ((BubbleTextView) v).applyLoadingState(false /* promiseStateChanged */);
} else if (v instanceof PendingAppWidgetHostView
&& info instanceof LauncherAppWidgetInfo
&& updates.contains(info)) {
diff --git a/src/com/android/launcher3/allapps/AllAppsStore.java b/src/com/android/launcher3/allapps/AllAppsStore.java
index 3ae0a18..00bdb70 100644
--- a/src/com/android/launcher3/allapps/AllAppsStore.java
+++ b/src/com/android/launcher3/allapps/AllAppsStore.java
@@ -24,7 +24,6 @@
import com.android.launcher3.BubbleTextView;
import com.android.launcher3.model.data.AppInfo;
import com.android.launcher3.model.data.ItemInfo;
-import com.android.launcher3.model.data.PromiseAppInfo;
import com.android.launcher3.util.ComponentKey;
import com.android.launcher3.util.PackageUserKey;
@@ -145,10 +144,17 @@
});
}
- public void updatePromiseAppProgress(PromiseAppInfo app) {
+ /**
+ * Sets the AppInfo's associated icon's progress bar.
+ *
+ * If this app is installed and supports incremental downloads, the progress bar will be updated
+ * the app's total download progress. Otherwise, the progress bar will be updated to the app's
+ * installation progress.
+ */
+ public void updateProgressBar(AppInfo app) {
updateAllIcons((child) -> {
if (child.getTag() == app) {
- child.applyProgressLevel(app.level);
+ child.applyProgressLevel(app.getProgressLevel());
}
});
}
diff --git a/src/com/android/launcher3/allapps/DiscoveryBounce.java b/src/com/android/launcher3/allapps/DiscoveryBounce.java
index 0005db8..d8ef18e 100644
--- a/src/com/android/launcher3/allapps/DiscoveryBounce.java
+++ b/src/com/android/launcher3/allapps/DiscoveryBounce.java
@@ -17,7 +17,6 @@
package com.android.launcher3.allapps;
import static com.android.launcher3.LauncherState.NORMAL;
-import static com.android.launcher3.LauncherState.OVERVIEW;
import android.animation.Animator;
import android.animation.AnimatorInflater;
@@ -32,7 +31,6 @@
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
import com.android.launcher3.statemanager.StateManager.StateListener;
-import com.android.launcher3.touch.PagedOrientationHandler;
import com.android.launcher3.util.OnboardingPrefs;
/**
@@ -147,39 +145,6 @@
new DiscoveryBounce(launcher, 0).show();
}
- public static void showForOverviewIfNeeded(Launcher launcher,
- PagedOrientationHandler orientationHandler) {
- showForOverviewIfNeeded(launcher, true, orientationHandler);
- }
-
- private static void showForOverviewIfNeeded(Launcher launcher, boolean withDelay,
- PagedOrientationHandler orientationHandler) {
- OnboardingPrefs onboardingPrefs = launcher.getOnboardingPrefs();
- if (!launcher.isInState(OVERVIEW)
- || !launcher.hasBeenResumed()
- || launcher.isForceInvisible()
- || launcher.getDeviceProfile().isVerticalBarLayout()
- || !orientationHandler.isLayoutNaturalToLauncher()
- || onboardingPrefs.getBoolean(OnboardingPrefs.SHELF_BOUNCE_SEEN)
- || launcher.getSystemService(UserManager.class).isDemoUser()
- || Utilities.IS_RUNNING_IN_TEST_HARNESS) {
- return;
- }
-
- if (withDelay) {
- new Handler().postDelayed(() -> showForOverviewIfNeeded(launcher, false,
- orientationHandler), DELAY_MS);
- return;
- } else if (AbstractFloatingView.getTopOpenView(launcher) != null) {
- // TODO: Move these checks to the top and call this method after invalidate handler.
- return;
- }
- onboardingPrefs.incrementEventCount(OnboardingPrefs.SHELF_BOUNCE_COUNT);
-
- new DiscoveryBounce(launcher, (1 - OVERVIEW.getVerticalProgress(launcher)))
- .show();
- }
-
/**
* A wrapper around {@link AllAppsTransitionController} allowing a fixed shift in the value.
*/
diff --git a/src/com/android/launcher3/anim/AnimatorPlaybackController.java b/src/com/android/launcher3/anim/AnimatorPlaybackController.java
index edaf51d..f6d1651 100644
--- a/src/com/android/launcher3/anim/AnimatorPlaybackController.java
+++ b/src/com/android/launcher3/anim/AnimatorPlaybackController.java
@@ -29,6 +29,8 @@
import android.animation.ValueAnimator;
import android.content.Context;
+import com.android.launcher3.Utilities;
+
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
@@ -133,15 +135,20 @@
/**
* Starts playing the animation with the provided velocity optionally playing any
- * physics based animations
+ * physics based animations.
+ * @param goingToEnd Whether we are going to the end (progress = 1) or not (progress = 0).
+ * @param velocityPxPerMs The velocity at which to start the animation, in pixels / millisecond.
+ * @param endDistance The distance (pixels) that the animation will travel from progress 0 to 1.
+ * @param animationDuration The duration of the non-physics based animation.
*/
public void startWithVelocity(Context context, boolean goingToEnd,
- float velocity, float scale, long animationDuration) {
- float scaleInverse = 1 / Math.abs(scale);
- float scaledVelocity = velocity * scaleInverse;
+ float velocityPxPerMs, float endDistance, long animationDuration) {
+ float distanceInverse = 1 / Math.abs(endDistance);
+ float velocityProgressPerMs = velocityPxPerMs * distanceInverse;
+ float oneFrameProgress = velocityProgressPerMs * getSingleFrameMs(context);
float nextFrameProgress = boundToRange(getProgressFraction()
- + scaledVelocity * getSingleFrameMs(context), 0f, 1f);
+ + oneFrameProgress, 0f, 1f);
// Update setters for spring
int springFlag = goingToEnd
@@ -154,8 +161,8 @@
SpringAnimationBuilder s = new SpringAnimationBuilder(context)
.setStartValue(mCurrentFraction)
.setEndValue(goingToEnd ? 1 : 0)
- .setStartVelocity(scaledVelocity)
- .setMinimumVisibleChange(scaleInverse)
+ .setStartVelocity(velocityProgressPerMs)
+ .setMinimumVisibleChange(distanceInverse)
.setDampingRatio(h.springProperty.mDampingRatio)
.setStiffness(h.springProperty.mStiffness)
.computeParams();
@@ -164,8 +171,18 @@
springDuration = Math.max(expectedDurationL, springDuration);
float expectedDuration = expectedDurationL;
- h.mapper = (progress, globalEndProgress) ->
- mAnimationPlayer.getCurrentPlayTime() / expectedDuration;
+ h.mapper = (progress, globalEndProgress) -> {
+ if (expectedDuration <= 0 || oneFrameProgress >= 1) {
+ return 1;
+ } else {
+ // Start from one frame ahead of the current position.
+ return Utilities.mapToRange(
+ mAnimationPlayer.getCurrentPlayTime() / expectedDuration,
+ 0, 1,
+ Math.abs(oneFrameProgress), 1,
+ LINEAR);
+ }
+ };
h.anim.setInterpolator(s::getInterpolatedValue);
}
}
@@ -174,7 +191,7 @@
if (springDuration <= animationDuration) {
mAnimationPlayer.setDuration(animationDuration);
- mAnimationPlayer.setInterpolator(scrollInterpolatorForVelocity(velocity));
+ mAnimationPlayer.setInterpolator(scrollInterpolatorForVelocity(velocityPxPerMs));
} else {
// Since spring requires more time to run, we let the other animations play with
// current time and interpolation and by clamping the duration.
@@ -182,7 +199,7 @@
float cutOff = animationDuration / (float) springDuration;
mAnimationPlayer.setInterpolator(
- clampToProgress(scrollInterpolatorForVelocity(velocity), 0, cutOff));
+ clampToProgress(scrollInterpolatorForVelocity(velocityPxPerMs), 0, cutOff));
}
mAnimationPlayer.start();
}
diff --git a/src/com/android/launcher3/config/FeatureFlags.java b/src/com/android/launcher3/config/FeatureFlags.java
index 839f0f4..68641d9 100644
--- a/src/com/android/launcher3/config/FeatureFlags.java
+++ b/src/com/android/launcher3/config/FeatureFlags.java
@@ -149,6 +149,10 @@
public static final BooleanFlag ENABLE_OVERVIEW_SHARE = getDebugFlag(
"ENABLE_OVERVIEW_SHARE", false, "Show Share button in Overview Actions");
+ public static final BooleanFlag ENABLE_OVERVIEW_SHARING_TO_PEOPLE = getDebugFlag(
+ "ENABLE_OVERVIEW_SHARING_TO_PEOPLE", false,
+ "Show indicators for content on Overview to share with top people. ");
+
public static final BooleanFlag ENABLE_OVERVIEW_CONTENT_PUSH = getDebugFlag(
"ENABLE_OVERVIEW_CONTENT_PUSH", false, "Show Content Push button in Overview Actions");
diff --git a/src/com/android/launcher3/folder/PreviewItemManager.java b/src/com/android/launcher3/folder/PreviewItemManager.java
index 7f8a15c..9ae7faf 100644
--- a/src/com/android/launcher3/folder/PreviewItemManager.java
+++ b/src/com/android/launcher3/folder/PreviewItemManager.java
@@ -39,6 +39,7 @@
import com.android.launcher3.Utilities;
import com.android.launcher3.graphics.PreloadIconDrawable;
+import com.android.launcher3.model.data.ItemInfoWithIcon;
import com.android.launcher3.model.data.WorkspaceItemInfo;
import com.android.launcher3.views.ActivityContext;
@@ -394,9 +395,10 @@
}
private void setDrawable(PreviewItemDrawingParams p, WorkspaceItemInfo item) {
- if (item.hasPromiseIconUi()) {
+ if (item.hasPromiseIconUi() || (item.runtimeStatusFlags
+ & ItemInfoWithIcon.FLAG_SHOW_DOWNLOAD_PROGRESS_MASK) != 0) {
PreloadIconDrawable drawable = newPendingIcon(mContext, item);
- drawable.setLevel(item.getInstallProgress());
+ drawable.setLevel(item.getProgressLevel());
p.drawable = drawable;
} else {
p.drawable = newIcon(mContext, item);
diff --git a/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java b/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java
index effb3a4..efc1201 100644
--- a/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java
+++ b/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java
@@ -629,11 +629,13 @@
private WorkspaceResult(BgDataModel dataModel,
WidgetsModel widgetsModel,
Map<ComponentKey, AppWidgetProviderInfo> widgetProviderInfoMap) {
- mWorkspaceItems = dataModel.workspaceItems;
- mAppWidgets = dataModel.appWidgets;
- mHotseatPredictions = dataModel.extraItems.get(CONTAINER_HOTSEAT_PREDICTION);
- mWidgetsModel = widgetsModel;
- mWidgetProvidersMap = widgetProviderInfoMap;
+ synchronized (dataModel) {
+ mWorkspaceItems = dataModel.workspaceItems;
+ mAppWidgets = dataModel.appWidgets;
+ mHotseatPredictions = dataModel.extraItems.get(CONTAINER_HOTSEAT_PREDICTION);
+ mWidgetsModel = widgetsModel;
+ mWidgetProvidersMap = widgetProviderInfoMap;
+ }
}
}
}
diff --git a/src/com/android/launcher3/graphics/PreloadIconDrawable.java b/src/com/android/launcher3/graphics/PreloadIconDrawable.java
index e85b056..9971990 100644
--- a/src/com/android/launcher3/graphics/PreloadIconDrawable.java
+++ b/src/com/android/launcher3/graphics/PreloadIconDrawable.java
@@ -117,6 +117,8 @@
mIndicatorColor = IconPalette.getPreloadProgressColor(context, mIconColor);
setInternalProgress(0);
+
+ setIsDisabled(!info.isAppStartable());
}
@Override
@@ -266,14 +268,12 @@
mIconScale = SMALL_SCALE;
mScaledTrackPath.reset();
mTrackAlpha = MAX_PAINT_ALPHA;
- setIsDisabled(true);
}
if (progress < 1 && progress > 0) {
mPathMeasure.getSegment(0, progress * mTrackLength, mScaledProgressPath, true);
mIconScale = SMALL_SCALE;
mTrackAlpha = MAX_PAINT_ALPHA;
- setIsDisabled(true);
} else if (progress >= 1) {
setIsDisabled(mItem.isDisabled());
mScaledTrackPath.set(mScaledProgressPath);
diff --git a/src/com/android/launcher3/model/AddWorkspaceItemsTask.java b/src/com/android/launcher3/model/AddWorkspaceItemsTask.java
index c236fa6..56dbbd3 100644
--- a/src/com/android/launcher3/model/AddWorkspaceItemsTask.java
+++ b/src/com/android/launcher3/model/AddWorkspaceItemsTask.java
@@ -34,6 +34,7 @@
import com.android.launcher3.model.data.LauncherAppWidgetInfo;
import com.android.launcher3.model.data.WorkspaceItemInfo;
import com.android.launcher3.pm.InstallSessionHelper;
+import com.android.launcher3.pm.PackageInstallInfo;
import com.android.launcher3.util.GridOccupancy;
import com.android.launcher3.util.IntArray;
import com.android.launcher3.util.PackageManagerHelper;
@@ -132,7 +133,9 @@
continue;
}
} else {
- workspaceInfo.setInstallProgress((int) sessionInfo.getProgress());
+ workspaceInfo.setProgressLevel(
+ (int) (sessionInfo.getProgress() * 100),
+ PackageInstallInfo.STATUS_INSTALLING);
}
if (hasActivity) {
diff --git a/src/com/android/launcher3/model/AllAppsList.java b/src/com/android/launcher3/model/AllAppsList.java
index 2695e66..8d5cf74 100644
--- a/src/com/android/launcher3/model/AllAppsList.java
+++ b/src/com/android/launcher3/model/AllAppsList.java
@@ -21,11 +21,11 @@
import android.content.ComponentName;
import android.content.Context;
+import android.content.Intent;
import android.content.pm.ApplicationInfo;
import android.content.pm.LauncherActivityInfo;
import android.content.pm.LauncherApps;
import android.os.LocaleList;
-import android.os.Process;
import android.os.UserHandle;
import android.util.Log;
@@ -37,7 +37,6 @@
import com.android.launcher3.icons.IconCache;
import com.android.launcher3.model.BgDataModel.Callbacks;
import com.android.launcher3.model.data.AppInfo;
-import com.android.launcher3.model.data.PromiseAppInfo;
import com.android.launcher3.pm.PackageInstallInfo;
import com.android.launcher3.util.FlagOp;
import com.android.launcher3.util.ItemInfoMatcher;
@@ -150,7 +149,7 @@
.getApplicationInfo(installInfo.packageName, installInfo.user, 0);
// only if not yet installed
if (applicationInfo == null) {
- PromiseAppInfo info = new PromiseAppInfo(installInfo);
+ AppInfo info = new AppInfo(installInfo);
mIconCache.getTitleAndIcon(info, info.usingLowResIcon());
info.sectionName = mIndex.computeSectionName(info.title);
@@ -159,24 +158,26 @@
}
}
- public PromiseAppInfo updatePromiseInstallInfo(PackageInstallInfo installInfo) {
- UserHandle user = Process.myUserHandle();
- for (int i=0; i < data.size(); i++) {
+ /** Updates the given PackageInstallInfo's associated AppInfo's installation info. */
+ public List<AppInfo> updatePromiseInstallInfo(PackageInstallInfo installInfo) {
+ List<AppInfo> updatedAppInfos = new ArrayList<>();
+ UserHandle user = installInfo.user;
+ for (int i = data.size() - 1; i >= 0; i--) {
final AppInfo appInfo = data.get(i);
final ComponentName tgtComp = appInfo.getTargetComponent();
if (tgtComp != null && tgtComp.getPackageName().equals(installInfo.packageName)
- && appInfo.user.equals(user)
- && appInfo instanceof PromiseAppInfo) {
- final PromiseAppInfo promiseAppInfo = (PromiseAppInfo) appInfo;
- if (installInfo.state == PackageInstallInfo.STATUS_INSTALLING) {
- promiseAppInfo.level = installInfo.progress;
- return promiseAppInfo;
+ && appInfo.user.equals(user)) {
+ if (installInfo.state == PackageInstallInfo.STATUS_INSTALLED_DOWNLOADING
+ || installInfo.state == PackageInstallInfo.STATUS_INSTALLING) {
+ appInfo.setProgressLevel(installInfo);
+
+ updatedAppInfos.add(appInfo);
} else if (installInfo.state == PackageInstallInfo.STATUS_FAILED) {
removeApp(i);
}
}
}
- return null;
+ return updatedAppInfos;
}
private void removeApp(int index) {
@@ -268,8 +269,14 @@
if (applicationInfo == null) {
add(new AppInfo(context, info, user), info);
} else {
+ Intent launchIntent = AppInfo.makeLaunchIntent(info);
+
mIconCache.getTitleAndIcon(applicationInfo, info, true /* useLowResIcon */);
applicationInfo.sectionName = mIndex.computeSectionName(applicationInfo.title);
+ applicationInfo.setProgressLevel(
+ PackageManagerHelper.getLoadingProgress(info),
+ PackageInstallInfo.STATUS_INSTALLED_DOWNLOADING);
+ applicationInfo.intent = launchIntent;
mDataChanged = true;
}
diff --git a/src/com/android/launcher3/model/BgDataModel.java b/src/com/android/launcher3/model/BgDataModel.java
index 49b40ed..2d860a4 100644
--- a/src/com/android/launcher3/model/BgDataModel.java
+++ b/src/com/android/launcher3/model/BgDataModel.java
@@ -39,7 +39,6 @@
import com.android.launcher3.model.data.FolderInfo;
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.model.data.LauncherAppWidgetInfo;
-import com.android.launcher3.model.data.PromiseAppInfo;
import com.android.launcher3.model.data.WorkspaceItemInfo;
import com.android.launcher3.pm.UserCache;
import com.android.launcher3.shortcuts.ShortcutKey;
@@ -376,6 +375,16 @@
}
/**
+ * Returns a list containing all workspace items including widgets.
+ */
+ public synchronized ArrayList<ItemInfo> getAllWorkspaceItems() {
+ ArrayList<ItemInfo> items = new ArrayList<>(workspaceItems.size() + appWidgets.size());
+ items.addAll(workspaceItems);
+ items.addAll(appWidgets);
+ return items;
+ }
+
+ /**
* Calls the provided {@code op} for all workspaceItems in the in-memory model (both persisted
* items and dynamic/predicted items for the provided {@code userHandle}.
* Note the call is not synchronized over the model, that should be handled by the called.
@@ -449,7 +458,11 @@
void preAddApps();
void bindAppsAdded(IntArray newScreens,
ArrayList<ItemInfo> addNotAnimated, ArrayList<ItemInfo> addAnimated);
- void bindPromiseAppProgressUpdated(PromiseAppInfo app);
+
+ /**
+ * Binds updated incremental download progress
+ */
+ void bindIncrementalDownloadProgressUpdated(AppInfo app);
void bindWorkspaceItemsChanged(List<WorkspaceItemInfo> updated);
void bindWidgetsRestored(ArrayList<LauncherAppWidgetInfo> widgets);
void bindRestoreItemsChange(HashSet<ItemInfo> updates);
diff --git a/src/com/android/launcher3/model/LoaderCursor.java b/src/com/android/launcher3/model/LoaderCursor.java
index 532834e..19d9af9 100644
--- a/src/com/android/launcher3/model/LoaderCursor.java
+++ b/src/com/android/launcher3/model/LoaderCursor.java
@@ -35,11 +35,13 @@
import android.util.Log;
import android.util.LongSparseArray;
+import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;
import com.android.launcher3.InvariantDeviceProfile;
import com.android.launcher3.LauncherAppState;
import com.android.launcher3.LauncherSettings;
+import com.android.launcher3.LauncherSettings.Favorites;
import com.android.launcher3.Utilities;
import com.android.launcher3.Workspace;
import com.android.launcher3.config.FeatureFlags;
@@ -92,6 +94,9 @@
private final int restoredIndex;
private final int intentIndex;
+ @Nullable
+ private LauncherActivityInfo mActivityInfo;
+
// Properties loaded per iteration
public long serialNumber;
public UserHandle user;
@@ -132,6 +137,8 @@
public boolean moveToNext() {
boolean result = super.moveToNext();
if (result) {
+ mActivityInfo = null;
+
// Load common properties.
itemType = getInt(itemTypeIndex);
container = getInt(containerIndex);
@@ -245,6 +252,10 @@
return info;
}
+ public LauncherActivityInfo getLauncherActivityInfo() {
+ return mActivityInfo;
+ }
+
/**
* Make an WorkspaceItemInfo object for a shortcut that is an application.
*/
@@ -264,25 +275,25 @@
Intent newIntent = new Intent(Intent.ACTION_MAIN, null);
newIntent.addCategory(Intent.CATEGORY_LAUNCHER);
newIntent.setComponent(componentName);
- LauncherActivityInfo lai = mContext.getSystemService(LauncherApps.class)
+ mActivityInfo = mContext.getSystemService(LauncherApps.class)
.resolveActivity(newIntent, user);
- if ((lai == null) && !allowMissingTarget) {
+ if ((mActivityInfo == null) && !allowMissingTarget) {
Log.d(TAG, "Missing activity found in getShortcutInfo: " + componentName);
return null;
}
final WorkspaceItemInfo info = new WorkspaceItemInfo();
- info.itemType = LauncherSettings.Favorites.ITEM_TYPE_APPLICATION;
+ info.itemType = Favorites.ITEM_TYPE_APPLICATION;
info.user = user;
info.intent = newIntent;
- mIconCache.getTitleAndIcon(info, lai, useLowResIcon);
+ mIconCache.getTitleAndIcon(info, mActivityInfo, useLowResIcon);
if (mIconCache.isDefaultIcon(info.bitmap, user)) {
loadIcon(info);
}
- if (lai != null) {
- AppInfo.updateRuntimeFlagsForActivityTarget(info, lai);
+ if (mActivityInfo != null) {
+ AppInfo.updateRuntimeFlagsForActivityTarget(info, mActivityInfo);
}
// from the db
diff --git a/src/com/android/launcher3/model/LoaderTask.java b/src/com/android/launcher3/model/LoaderTask.java
index b108788..f74c8b5 100644
--- a/src/com/android/launcher3/model/LoaderTask.java
+++ b/src/com/android/launcher3/model/LoaderTask.java
@@ -69,6 +69,7 @@
import com.android.launcher3.model.data.AppInfo;
import com.android.launcher3.model.data.FolderInfo;
import com.android.launcher3.model.data.ItemInfo;
+import com.android.launcher3.model.data.ItemInfoWithIcon;
import com.android.launcher3.model.data.LauncherAppWidgetInfo;
import com.android.launcher3.model.data.PackageItemInfo;
import com.android.launcher3.model.data.WorkspaceItemInfo;
@@ -166,12 +167,7 @@
private void sendFirstScreenActiveInstallsBroadcast() {
ArrayList<ItemInfo> firstScreenItems = new ArrayList<>();
-
- ArrayList<ItemInfo> allItems = new ArrayList<>();
- synchronized (mBgDataModel) {
- allItems.addAll(mBgDataModel.workspaceItems);
- allItems.addAll(mBgDataModel.appWidgets);
- }
+ ArrayList<ItemInfo> allItems = mBgDataModel.getAllWorkspaceItems();
// Screen set is never empty
final int firstScreen = mBgDataModel.collectWorkspaceScreens().get(0);
@@ -596,11 +592,24 @@
if (c.restoreFlag != 0 && !TextUtils.isEmpty(targetPkg)) {
tempPackageKey.update(targetPkg, c.user);
SessionInfo si = installingPkgs.get(tempPackageKey);
- if (si == null) {
- info.status &= ~WorkspaceItemInfo.FLAG_INSTALL_SESSION_ACTIVE;
- } else {
- info.setInstallProgress((int) (si.getProgress() * 100));
- }
+ LauncherActivityInfo activityInfo =
+ c.getLauncherActivityInfo();
+ if (si == null) {
+ info.runtimeStatusFlags &=
+ ~ItemInfoWithIcon.FLAG_INSTALL_SESSION_ACTIVE;
+ } else if (activityInfo == null) {
+ int installProgress = (int) (si.getProgress() * 100);
+
+ info.setProgressLevel(
+ installProgress,
+ PackageInstallInfo.STATUS_INSTALLING);
+ } else {
+ info.setProgressLevel(
+ PackageManagerHelper
+ .getLoadingProgress(activityInfo),
+ PackageInstallInfo
+ .STATUS_INSTALLED_DOWNLOADING);
+ }
}
c.checkAndAddItem(info, mBgDataModel);
@@ -858,10 +867,12 @@
.call(contentResolver,
LauncherSettings.Settings.METHOD_DELETE_EMPTY_FOLDERS)
.getIntArray(LauncherSettings.Settings.EXTRA_VALUE);
- for (int folderId : deletedFolderIds) {
- mBgDataModel.workspaceItems.remove(mBgDataModel.folders.get(folderId));
- mBgDataModel.folders.remove(folderId);
- mBgDataModel.itemsIdMap.remove(folderId);
+ synchronized (mBgDataModel) {
+ for (int folderId : deletedFolderIds) {
+ mBgDataModel.workspaceItems.remove(mBgDataModel.folders.get(folderId));
+ mBgDataModel.folders.remove(folderId);
+ mBgDataModel.itemsIdMap.remove(folderId);
+ }
}
// Remove any ghost widgets
diff --git a/src/com/android/launcher3/model/PackageIncrementalDownloadUpdatedTask.java b/src/com/android/launcher3/model/PackageIncrementalDownloadUpdatedTask.java
new file mode 100644
index 0000000..e3e8769
--- /dev/null
+++ b/src/com/android/launcher3/model/PackageIncrementalDownloadUpdatedTask.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.launcher3.model;
+
+import android.content.ComponentName;
+import android.os.UserHandle;
+
+import com.android.launcher3.LauncherAppState;
+import com.android.launcher3.model.data.AppInfo;
+import com.android.launcher3.model.data.ItemInfoWithIcon;
+import com.android.launcher3.model.data.WorkspaceItemInfo;
+import com.android.launcher3.pm.PackageInstallInfo;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Handles updates due to incremental download progress updates.
+ */
+public class PackageIncrementalDownloadUpdatedTask extends BaseModelUpdateTask {
+
+ private final UserHandle mUser;
+ private final int mProgress;
+ private final String mPackageName;
+
+ public PackageIncrementalDownloadUpdatedTask(
+ String packageName, UserHandle user, float progress) {
+ mUser = user;
+ mProgress = 1 - progress > 0.001 ? (int) (100 * progress) : 100;
+ mPackageName = packageName;
+ }
+
+ @Override
+ public void execute(LauncherAppState app, BgDataModel dataModel, AllAppsList appsList) {
+ PackageInstallInfo downloadInfo = new PackageInstallInfo(
+ mPackageName,
+ PackageInstallInfo.STATUS_INSTALLED_DOWNLOADING,
+ mProgress,
+ mUser);
+
+ synchronized (appsList) {
+ List<AppInfo> updatedAppInfos = appsList.updatePromiseInstallInfo(downloadInfo);
+ if (!updatedAppInfos.isEmpty()) {
+ for (AppInfo appInfo : updatedAppInfos) {
+ appInfo.runtimeStatusFlags &= ~ItemInfoWithIcon.FLAG_INSTALL_SESSION_ACTIVE;
+ scheduleCallbackTask(
+ c -> c.bindIncrementalDownloadProgressUpdated(appInfo));
+ }
+ }
+ bindApplicationsIfNeeded();
+ }
+
+ final ArrayList<WorkspaceItemInfo> updatedWorkspaceItems = new ArrayList<>();
+ synchronized (dataModel) {
+ dataModel.forAllWorkspaceItemInfos(mUser, si -> {
+ ComponentName cn = si.getTargetComponent();
+ if ((cn != null) && cn.getPackageName().equals(mPackageName)) {
+ si.runtimeStatusFlags &= ~ItemInfoWithIcon.FLAG_INSTALL_SESSION_ACTIVE;
+ si.setProgressLevel(downloadInfo);
+ updatedWorkspaceItems.add(si);
+ }
+ });
+ }
+ bindUpdatedWorkspaceItems(updatedWorkspaceItems);
+ }
+}
diff --git a/src/com/android/launcher3/model/PackageInstallStateChangedTask.java b/src/com/android/launcher3/model/PackageInstallStateChangedTask.java
index 8369c48..8215edd 100644
--- a/src/com/android/launcher3/model/PackageInstallStateChangedTask.java
+++ b/src/com/android/launcher3/model/PackageInstallStateChangedTask.java
@@ -20,14 +20,15 @@
import android.content.pm.PackageManager;
import com.android.launcher3.LauncherAppState;
+import com.android.launcher3.model.data.AppInfo;
import com.android.launcher3.model.data.ItemInfo;
+import com.android.launcher3.model.data.ItemInfoWithIcon;
import com.android.launcher3.model.data.LauncherAppWidgetInfo;
-import com.android.launcher3.model.data.PromiseAppInfo;
-import com.android.launcher3.model.data.WorkspaceItemInfo;
import com.android.launcher3.pm.PackageInstallInfo;
import com.android.launcher3.util.InstantAppResolver;
import java.util.HashSet;
+import java.util.List;
/**
* Handles changes due to a sessions updates for a currently installing app.
@@ -59,9 +60,11 @@
}
synchronized (apps) {
- PromiseAppInfo updated = apps.updatePromiseInstallInfo(mInstallInfo);
- if (updated != null) {
- scheduleCallbackTask(c -> c.bindPromiseAppProgressUpdated(updated));
+ List<AppInfo> updatedAppInfos = apps.updatePromiseInstallInfo(mInstallInfo);
+ if (!updatedAppInfos.isEmpty()) {
+ for (AppInfo appInfo : updatedAppInfos) {
+ scheduleCallbackTask(c -> c.bindIncrementalDownloadProgressUpdated(appInfo));
+ }
}
bindApplicationsIfNeeded();
}
@@ -71,11 +74,13 @@
dataModel.forAllWorkspaceItemInfos(mInstallInfo.user, si -> {
ComponentName cn = si.getTargetComponent();
if (si.hasPromiseIconUi() && (cn != null)
- && mInstallInfo.packageName.equals(cn.getPackageName())) {
- si.setInstallProgress(mInstallInfo.progress);
+ && cn.getPackageName().equals(mInstallInfo.packageName)) {
+ int installProgress = mInstallInfo.progress;
+
+ si.setProgressLevel(installProgress, PackageInstallInfo.STATUS_INSTALLING);
if (mInstallInfo.state == PackageInstallInfo.STATUS_FAILED) {
// Mark this info as broken.
- si.status &= ~WorkspaceItemInfo.FLAG_INSTALL_SESSION_ACTIVE;
+ si.runtimeStatusFlags &= ~ItemInfoWithIcon.FLAG_INSTALL_SESSION_ACTIVE;
}
updates.add(si);
}
diff --git a/src/com/android/launcher3/model/data/AppInfo.java b/src/com/android/launcher3/model/data/AppInfo.java
index aee1f2a..39247c2 100644
--- a/src/com/android/launcher3/model/data/AppInfo.java
+++ b/src/com/android/launcher3/model/data/AppInfo.java
@@ -28,10 +28,13 @@
import android.os.UserHandle;
import android.os.UserManager;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;
import com.android.launcher3.LauncherSettings;
import com.android.launcher3.Utilities;
+import com.android.launcher3.pm.PackageInstallInfo;
import com.android.launcher3.util.ComponentKey;
import com.android.launcher3.util.PackageManagerHelper;
@@ -104,13 +107,37 @@
this.intent = intent;
}
+ public AppInfo(@NonNull PackageInstallInfo installInfo) {
+ componentName = installInfo.componentName;
+ intent = new Intent(Intent.ACTION_MAIN)
+ .addCategory(Intent.CATEGORY_LAUNCHER)
+ .setComponent(componentName)
+ .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
+ | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
+ user = installInfo.user;
+ }
+
@Override
protected String dumpProperties() {
return super.dumpProperties() + " componentName=" + componentName;
}
public WorkspaceItemInfo makeWorkspaceItem() {
- return new WorkspaceItemInfo(this);
+ WorkspaceItemInfo workspaceItemInfo = new WorkspaceItemInfo(this);
+
+ if ((runtimeStatusFlags & FLAG_INSTALL_SESSION_ACTIVE) != 0) {
+ // We need to update the component name when the apk is installed
+ workspaceItemInfo.status |= WorkspaceItemInfo.FLAG_AUTOINSTALL_ICON;
+ // Since the user is manually placing it on homescreen, it should not be auto-removed
+ // later
+ workspaceItemInfo.status |= WorkspaceItemInfo.FLAG_RESTORE_STARTED;
+ workspaceItemInfo.status |= FLAG_INSTALL_SESSION_ACTIVE;
+ }
+ if ((runtimeStatusFlags & FLAG_INCREMENTAL_DOWNLOAD_ACTIVE) != 0) {
+ workspaceItemInfo.runtimeStatusFlags |= FLAG_INCREMENTAL_DOWNLOAD_ACTIVE;
+ }
+
+ return workspaceItemInfo;
}
public ComponentKey toComponentKey() {
@@ -129,6 +156,12 @@
| Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
}
+ @Nullable
+ @Override
+ public ComponentName getTargetComponent() {
+ return componentName;
+ }
+
public static void updateRuntimeFlagsForActivityTarget(
ItemInfoWithIcon info, LauncherActivityInfo lai) {
ApplicationInfo appInfo = lai.getApplicationInfo();
@@ -143,6 +176,11 @@
// The icon for a non-primary user is badged, hence it's not exactly an adaptive icon.
info.runtimeStatusFlags |= FLAG_ADAPTIVE_ICON;
}
+
+ // Sets the progress level, installation and incremental download flags.
+ info.setProgressLevel(
+ PackageManagerHelper.getLoadingProgress(lai),
+ PackageInstallInfo.STATUS_INSTALLED);
}
@Override
diff --git a/src/com/android/launcher3/model/data/ItemInfoWithIcon.java b/src/com/android/launcher3/model/data/ItemInfoWithIcon.java
index d95f94f..b8a71d3 100644
--- a/src/com/android/launcher3/model/data/ItemInfoWithIcon.java
+++ b/src/com/android/launcher3/model/data/ItemInfoWithIcon.java
@@ -16,7 +16,15 @@
package com.android.launcher3.model.data;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+
+import androidx.annotation.Nullable;
+
import com.android.launcher3.icons.BitmapInfo;
+import com.android.launcher3.pm.PackageInstallInfo;
+import com.android.launcher3.util.PackageManagerHelper;
/**
* Represents an ItemInfo which also holds an icon.
@@ -88,11 +96,34 @@
public static final int FLAG_ICON_BADGED = 1 << 9;
/**
+ * The icon is being installed. If {@link WorkspaceItemInfo#FLAG_RESTORED_ICON} or
+ * {@link WorkspaceItemInfo#FLAG_AUTOINSTALL_ICON} is set, then the icon is either being
+ * installed or is in a broken state.
+ */
+ public static final int FLAG_INSTALL_SESSION_ACTIVE = 1 << 10;
+
+ /**
+ * This icon is still being downloaded.
+ */
+ public static final int FLAG_INCREMENTAL_DOWNLOAD_ACTIVE = 1 << 11;
+
+ public static final int FLAG_SHOW_DOWNLOAD_PROGRESS_MASK = FLAG_INSTALL_SESSION_ACTIVE
+ | FLAG_INCREMENTAL_DOWNLOAD_ACTIVE;
+
+ /**
* Status associated with the system state of the underlying item. This is calculated every
* time a new info is created and not persisted on the disk.
*/
public int runtimeStatusFlags = 0;
+ /**
+ * The download progress of the package that this shortcut represents. For legacy apps, this
+ * will always be the installation progress. For apps that support incremental downloads, this
+ * will only match be the installation progress until the app is installed, then this will the
+ * total download progress.
+ */
+ private int mProgressLevel = 100;
+
protected ItemInfoWithIcon() { }
protected ItemInfoWithIcon(ItemInfoWithIcon info) {
@@ -114,6 +145,72 @@
}
/**
+ * Returns whether the app this shortcut represents is able to be started. For legacy apps,
+ * this returns whether it is fully installed. For apps that support incremental downloads,
+ * this returns whether the app is either fully downloaded or has installed and is downloading
+ * incrementally.
+ */
+ public boolean isAppStartable() {
+ return ((runtimeStatusFlags & FLAG_INSTALL_SESSION_ACTIVE) == 0)
+ && (((runtimeStatusFlags & FLAG_INCREMENTAL_DOWNLOAD_ACTIVE) != 0)
+ || mProgressLevel == 100);
+ }
+
+ /**
+ * Returns the download progress for the app this shortcut represents. If this app is not yet
+ * installed or does not support incremental downloads, this will return the installation
+ * progress.
+ */
+ public int getProgressLevel() {
+ if ((runtimeStatusFlags & FLAG_SHOW_DOWNLOAD_PROGRESS_MASK) != 0) {
+ return mProgressLevel;
+ }
+ return 100;
+ }
+
+ /**
+ * Sets the download progress for the app this shortcut represents. If this app is not yet
+ * installed or does not support incremental downloads, this will set
+ * {@code FLAG_INSTALL_SESSION_ACTIVE}. If this app is downloading incrementally, this will
+ * set {@code FLAG_INCREMENTAL_DOWNLOAD_ACTIVE}. Otherwise, this will remove both flags.
+ */
+ public void setProgressLevel(PackageInstallInfo installInfo) {
+ setProgressLevel(installInfo.progress, installInfo.state);
+ }
+
+ /**
+ * Sets the download progress for the app this shortcut represents.
+ */
+ public void setProgressLevel(int progress, int status) {
+ if (status == PackageInstallInfo.STATUS_INSTALLING) {
+ mProgressLevel = progress;
+ runtimeStatusFlags = progress < 100
+ ? runtimeStatusFlags | FLAG_INSTALL_SESSION_ACTIVE
+ : runtimeStatusFlags & ~FLAG_INSTALL_SESSION_ACTIVE;
+ } else if (status == PackageInstallInfo.STATUS_INSTALLED_DOWNLOADING) {
+ mProgressLevel = progress;
+ runtimeStatusFlags = runtimeStatusFlags & ~FLAG_INSTALL_SESSION_ACTIVE;
+ runtimeStatusFlags = progress < 100
+ ? runtimeStatusFlags | FLAG_INCREMENTAL_DOWNLOAD_ACTIVE
+ : runtimeStatusFlags & ~FLAG_INCREMENTAL_DOWNLOAD_ACTIVE;
+ } else {
+ mProgressLevel = status == PackageInstallInfo.STATUS_INSTALLED ? 100 : 0;
+ runtimeStatusFlags = runtimeStatusFlags & ~FLAG_INSTALL_SESSION_ACTIVE;
+ runtimeStatusFlags = runtimeStatusFlags & ~FLAG_INCREMENTAL_DOWNLOAD_ACTIVE;
+ }
+ }
+
+ /** Creates an intent to that launches the app store at this app's page. */
+ @Nullable
+ public Intent getMarketIntent(Context context) {
+ ComponentName componentName = getTargetComponent();
+
+ return componentName != null
+ ? new PackageManagerHelper(context).getMarketIntent(componentName.getPackageName())
+ : null;
+ }
+
+ /**
* @return a copy of this
*/
public abstract ItemInfoWithIcon clone();
diff --git a/src/com/android/launcher3/model/data/PromiseAppInfo.java b/src/com/android/launcher3/model/data/PromiseAppInfo.java
deleted file mode 100644
index b6231ed..0000000
--- a/src/com/android/launcher3/model/data/PromiseAppInfo.java
+++ /dev/null
@@ -1,54 +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.model.data;
-
-import android.content.Context;
-import android.content.Intent;
-
-import androidx.annotation.NonNull;
-
-import com.android.launcher3.pm.PackageInstallInfo;
-import com.android.launcher3.util.PackageManagerHelper;
-
-public class PromiseAppInfo extends AppInfo {
-
- public int level = 0;
-
- public PromiseAppInfo(@NonNull PackageInstallInfo installInfo) {
- componentName = installInfo.componentName;
- intent = new Intent(Intent.ACTION_MAIN)
- .addCategory(Intent.CATEGORY_LAUNCHER)
- .setComponent(componentName)
- .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
- | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
- }
-
- @Override
- public WorkspaceItemInfo makeWorkspaceItem() {
- WorkspaceItemInfo shortcut = new WorkspaceItemInfo(this);
- shortcut.setInstallProgress(level);
- // We need to update the component name when the apk is installed
- shortcut.status |= WorkspaceItemInfo.FLAG_AUTOINSTALL_ICON;
- // Since the user is manually placing it on homescreen, it should not be auto-removed later
- shortcut.status |= WorkspaceItemInfo.FLAG_RESTORE_STARTED;
- return shortcut;
- }
-
- public Intent getMarketIntent(Context context) {
- return new PackageManagerHelper(context).getMarketIntent(componentName.getPackageName());
- }
-}
diff --git a/src/com/android/launcher3/model/data/WorkspaceItemInfo.java b/src/com/android/launcher3/model/data/WorkspaceItemInfo.java
index 1e1d093..690e904 100644
--- a/src/com/android/launcher3/model/data/WorkspaceItemInfo.java
+++ b/src/com/android/launcher3/model/data/WorkspaceItemInfo.java
@@ -58,20 +58,14 @@
public static final int FLAG_AUTOINSTALL_ICON = 1 << 1;
/**
- * The icon is being installed. If {@link #FLAG_RESTORED_ICON} or {@link #FLAG_AUTOINSTALL_ICON}
- * is set, then the icon is either being installed or is in a broken state.
- */
- public static final int FLAG_INSTALL_SESSION_ACTIVE = 1 << 2;
-
- /**
* Indicates that the widget restore has started.
*/
- public static final int FLAG_RESTORE_STARTED = 1 << 3;
+ public static final int FLAG_RESTORE_STARTED = 1 << 2;
/**
* Web UI supported.
*/
- public static final int FLAG_SUPPORTS_WEB_UI = 1 << 4;
+ public static final int FLAG_SUPPORTS_WEB_UI = 1 << 3;
/**
* The intent used to start the application.
@@ -98,11 +92,6 @@
*/
@NonNull private String[] personKeys = Utilities.EMPTY_STRING_ARRAY;
- /**
- * The installation progress [0-100] of the package that this shortcut represents.
- */
- private int mInstallProgress;
-
public WorkspaceItemInfo() {
itemType = LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT;
@@ -114,7 +103,6 @@
intent = new Intent(info.intent);
iconResource = info.iconResource;
status = info.status;
- mInstallProgress = info.mInstallProgress;
personKeys = info.personKeys.clone();
}
@@ -168,15 +156,6 @@
return isPromise() && !hasStatusFlag(FLAG_SUPPORTS_WEB_UI);
}
- public int getInstallProgress() {
- return mInstallProgress;
- }
-
- public void setInstallProgress(int progress) {
- mInstallProgress = progress;
- status |= FLAG_INSTALL_SESSION_ACTIVE;
- }
-
public void updateFromDeepShortcutInfo(ShortcutInfo shortcutInfo, Context context) {
// {@link ShortcutInfo#getActivity} can change during an update. Recreate the intent
intent = ShortcutKey.makeIntent(shortcutInfo);
diff --git a/src/com/android/launcher3/pm/PackageInstallInfo.java b/src/com/android/launcher3/pm/PackageInstallInfo.java
index 7997d16..fad904f 100644
--- a/src/com/android/launcher3/pm/PackageInstallInfo.java
+++ b/src/com/android/launcher3/pm/PackageInstallInfo.java
@@ -25,7 +25,8 @@
public static final int STATUS_INSTALLED = 0;
public static final int STATUS_INSTALLING = 1;
- public static final int STATUS_FAILED = 2;
+ public static final int STATUS_INSTALLED_DOWNLOADING = 2;
+ public static final int STATUS_FAILED = 3;
public final ComponentName componentName;
public final String packageName;
@@ -56,5 +57,4 @@
public static PackageInstallInfo fromState(int state, String packageName, UserHandle user) {
return new PackageInstallInfo(packageName, state, 0 /* progress */, user);
}
-
}
diff --git a/src/com/android/launcher3/secondarydisplay/SecondaryDisplayLauncher.java b/src/com/android/launcher3/secondarydisplay/SecondaryDisplayLauncher.java
index b496608..0266345 100644
--- a/src/com/android/launcher3/secondarydisplay/SecondaryDisplayLauncher.java
+++ b/src/com/android/launcher3/secondarydisplay/SecondaryDisplayLauncher.java
@@ -35,8 +35,8 @@
import com.android.launcher3.model.BgDataModel;
import com.android.launcher3.model.data.AppInfo;
import com.android.launcher3.model.data.ItemInfo;
+import com.android.launcher3.model.data.ItemInfoWithIcon;
import com.android.launcher3.model.data.LauncherAppWidgetInfo;
-import com.android.launcher3.model.data.PromiseAppInfo;
import com.android.launcher3.model.data.WorkspaceItemInfo;
import com.android.launcher3.popup.PopupContainerWithArrow;
import com.android.launcher3.popup.PopupDataProvider;
@@ -215,8 +215,8 @@
ArrayList<ItemInfo> addAnimated) { }
@Override
- public void bindPromiseAppProgressUpdated(PromiseAppInfo app) {
- mAppsView.getAppsStore().updatePromiseAppProgress(app);
+ public void bindIncrementalDownloadProgressUpdated(AppInfo app) {
+ mAppsView.getAppsStore().updateProgressBar(app);
}
@Override
@@ -315,9 +315,11 @@
if (tag instanceof ItemInfo) {
ItemInfo item = (ItemInfo) tag;
Intent intent;
- if (item instanceof PromiseAppInfo) {
- PromiseAppInfo promiseAppInfo = (PromiseAppInfo) item;
- intent = promiseAppInfo.getMarketIntent(this);
+ if (item instanceof ItemInfoWithIcon
+ && (((ItemInfoWithIcon) item).runtimeStatusFlags
+ & ItemInfoWithIcon.FLAG_INSTALL_SESSION_ACTIVE) != 0) {
+ ItemInfoWithIcon appInfo = (ItemInfoWithIcon) item;
+ intent = appInfo.getMarketIntent(this);
} else {
intent = item.getIntent();
}
diff --git a/src/com/android/launcher3/touch/ItemClickHandler.java b/src/com/android/launcher3/touch/ItemClickHandler.java
index 9b9cb0a..4158735 100644
--- a/src/com/android/launcher3/touch/ItemClickHandler.java
+++ b/src/com/android/launcher3/touch/ItemClickHandler.java
@@ -49,8 +49,8 @@
import com.android.launcher3.model.data.AppInfo;
import com.android.launcher3.model.data.FolderInfo;
import com.android.launcher3.model.data.ItemInfo;
+import com.android.launcher3.model.data.ItemInfoWithIcon;
import com.android.launcher3.model.data.LauncherAppWidgetInfo;
-import com.android.launcher3.model.data.PromiseAppInfo;
import com.android.launcher3.model.data.RemoteActionItemInfo;
import com.android.launcher3.model.data.WorkspaceItemInfo;
import com.android.launcher3.pm.InstallSessionHelper;
@@ -231,8 +231,12 @@
? shortcut.getIntent().getComponent().getPackageName()
: shortcut.getIntent().getPackage();
if (!TextUtils.isEmpty(packageName)) {
- onClickPendingAppItem(v, launcher, packageName,
- shortcut.hasStatusFlag(WorkspaceItemInfo.FLAG_INSTALL_SESSION_ACTIVE));
+ onClickPendingAppItem(
+ v,
+ launcher,
+ packageName,
+ (shortcut.runtimeStatusFlags
+ & ItemInfoWithIcon.FLAG_INSTALL_SESSION_ACTIVE) != 0);
return;
}
}
@@ -266,9 +270,12 @@
TestLogging.recordEvent(
TestProtocol.SEQUENCE_MAIN, "start: startAppShortcutOrInfoActivity");
Intent intent;
- if (item instanceof PromiseAppInfo) {
- PromiseAppInfo promiseAppInfo = (PromiseAppInfo) item;
- intent = promiseAppInfo.getMarketIntent(launcher);
+ if (item instanceof ItemInfoWithIcon
+ && (((ItemInfoWithIcon) item).runtimeStatusFlags
+ & ItemInfoWithIcon.FLAG_INSTALL_SESSION_ACTIVE) != 0) {
+ ItemInfoWithIcon appInfo = (ItemInfoWithIcon) item;
+ intent = new PackageManagerHelper(launcher)
+ .getMarketIntent(appInfo.getTargetComponent().getPackageName());
} else {
intent = item.getIntent();
}
diff --git a/src/com/android/launcher3/util/OnboardingPrefs.java b/src/com/android/launcher3/util/OnboardingPrefs.java
index 1b33197..539768e 100644
--- a/src/com/android/launcher3/util/OnboardingPrefs.java
+++ b/src/com/android/launcher3/util/OnboardingPrefs.java
@@ -33,7 +33,6 @@
public class OnboardingPrefs<T extends Launcher> {
public static final String HOME_BOUNCE_SEEN = "launcher.apps_view_shown";
- public static final String SHELF_BOUNCE_SEEN = "launcher.shelf_bounce_seen";
public static final String HOME_BOUNCE_COUNT = "launcher.home_bounce_count";
public static final String SHELF_BOUNCE_COUNT = "launcher.shelf_bounce_count";
public static final String HOTSEAT_DISCOVERY_TIP_COUNT = "launcher.hotseat_discovery_tip_count";
@@ -44,7 +43,6 @@
*/
@StringDef(value = {
HOME_BOUNCE_SEEN,
- SHELF_BOUNCE_SEEN,
HOTSEAT_LONGPRESS_TIP_SEEN
})
@Retention(RetentionPolicy.SOURCE)
@@ -55,7 +53,6 @@
*/
@StringDef(value = {
HOME_BOUNCE_COUNT,
- SHELF_BOUNCE_COUNT,
HOTSEAT_DISCOVERY_TIP_COUNT
})
@Retention(RetentionPolicy.SOURCE)
@@ -65,7 +62,6 @@
static {
Map<String, Integer> maxCounts = new ArrayMap<>(4);
maxCounts.put(HOME_BOUNCE_COUNT, 3);
- maxCounts.put(SHELF_BOUNCE_COUNT, 3);
maxCounts.put(HOTSEAT_DISCOVERY_TIP_COUNT, 5);
MAX_COUNTS = Collections.unmodifiableMap(maxCounts);
}
diff --git a/src/com/android/launcher3/util/PackageManagerHelper.java b/src/com/android/launcher3/util/PackageManagerHelper.java
index 523545a..7b26427 100644
--- a/src/com/android/launcher3/util/PackageManagerHelper.java
+++ b/src/com/android/launcher3/util/PackageManagerHelper.java
@@ -45,10 +45,11 @@
import com.android.launcher3.PendingAddItemInfo;
import com.android.launcher3.R;
+import com.android.launcher3.Utilities;
import com.android.launcher3.model.data.AppInfo;
import com.android.launcher3.model.data.ItemInfo;
+import com.android.launcher3.model.data.ItemInfoWithIcon;
import com.android.launcher3.model.data.LauncherAppWidgetInfo;
-import com.android.launcher3.model.data.PromiseAppInfo;
import com.android.launcher3.model.data.WorkspaceItemInfo;
import java.net.URISyntaxException;
@@ -200,9 +201,12 @@
* Starts the details activity for {@code info}
*/
public void startDetailsActivityForInfo(ItemInfo info, Rect sourceBounds, Bundle opts) {
- if (info instanceof PromiseAppInfo) {
- PromiseAppInfo promiseAppInfo = (PromiseAppInfo) info;
- mContext.startActivity(promiseAppInfo.getMarketIntent(mContext));
+ if (info instanceof ItemInfoWithIcon
+ && (((ItemInfoWithIcon) info).runtimeStatusFlags
+ & ItemInfoWithIcon.FLAG_INSTALL_SESSION_ACTIVE) != 0) {
+ ItemInfoWithIcon appInfo = (ItemInfoWithIcon) info;
+ mContext.startActivity(new PackageManagerHelper(mContext)
+ .getMarketIntent(appInfo.getTargetComponent().getPackageName()));
return;
}
ComponentName componentName = null;
@@ -319,4 +323,12 @@
}
return false;
}
+
+ /** Returns the incremental download progress for the given shortcut's app. */
+ public static int getLoadingProgress(LauncherActivityInfo info) {
+ if (Utilities.ATLEAST_S) {
+ return (int) (100 * info.getLoadingProgress());
+ }
+ return 100;
+ }
}
diff --git a/src/com/android/launcher3/util/SecureSettingsObserver.java b/src/com/android/launcher3/util/SecureSettingsObserver.java
index 4b22429..9fe72ad 100644
--- a/src/com/android/launcher3/util/SecureSettingsObserver.java
+++ b/src/com/android/launcher3/util/SecureSettingsObserver.java
@@ -88,7 +88,7 @@
public static SecureSettingsObserver newOneHandedSettingsObserver(Context context,
OnChangeListener listener) {
return new SecureSettingsObserver(
- context.getContentResolver(), listener, ONE_HANDED_ENABLED, 1);
+ context.getContentResolver(), listener, ONE_HANDED_ENABLED, 0);
}
/**
diff --git a/tests/src/com/android/launcher3/ui/TaplTestsLauncher3.java b/tests/src/com/android/launcher3/ui/TaplTestsLauncher3.java
index a39f215..1648bdd 100644
--- a/tests/src/com/android/launcher3/ui/TaplTestsLauncher3.java
+++ b/tests/src/com/android/launcher3/ui/TaplTestsLauncher3.java
@@ -299,7 +299,9 @@
launcher -> assertTrue("Launcher internal state didn't switch to Showing Menu",
isOptionsPopupVisible(launcher)));
- menu.getMenuItem(1).launch(getAppPackageName());
+ final AppIconMenuItem menuItem = menu.getMenuItem(1);
+ assertEquals("Wrong menu item", "Shortcut 2", menuItem.getText());
+ menuItem.launch(getAppPackageName());
} finally {
allApps.unfreeze();
}
@@ -342,6 +344,7 @@
openMenu().
getMenuItem(0);
final String shortcutName = menuItem.getText();
+ assertEquals("Wrong menu item", "Shortcut 3", shortcutName);
menuItem.dragToWorkspace(false, false);
mLauncher.getWorkspace().getWorkspaceAppIcon(shortcutName).launch(getAppPackageName());
diff --git a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
index 3c89cfd..e2a442d 100644
--- a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
+++ b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
@@ -595,11 +595,7 @@
return waitForLauncherObject(APPS_RES_ID);
}
case OVERVIEW: {
- if (hasAllAppsInOverview()) {
- waitForLauncherObject(APPS_RES_ID);
- } else {
- waitUntilLauncherObjectGone(APPS_RES_ID);
- }
+ waitUntilLauncherObjectGone(APPS_RES_ID);
waitUntilLauncherObjectGone(WORKSPACE_RES_ID);
waitUntilLauncherObjectGone(WIDGETS_RES_ID);
@@ -1297,19 +1293,6 @@
getTestInfo(TestProtocol.REQUEST_ENABLE_DEBUG_TRACING);
}
- public boolean hasAllAppsInOverview() {
- // Vertical bar layouts don't contain all apps
- if (!mDevice.isNaturalOrientation()) {
- return false;
- }
- // Portrait two button (quickstep) always has all apps.
- if (getNavigationModel() == NavigationModel.TWO_BUTTON) {
- return true;
- }
- // ...otherwise there are overview actions, which hide all apps
- return false;
- }
-
boolean overviewShareEnabled() {
return getTestInfo(TestProtocol.REQUEST_OVERVIEW_SHARE_ENABLED).getBoolean(
TestProtocol.TEST_INFO_RESPONSE_FIELD);