Merging from ub-launcher3-rvc-dev @ build 6492476

Bug: 150504032
Test: manual, presubmit on the source branch
    x20/teams/android-launcher/merge/ub-launcher3-rvc-dev_rvc-dev_6492476.html
Change-Id: I96b36965f7b471eb77aa78a8b923ed9298e8a02f
This commit is contained in:
Winson Chung 2020-05-13 16:11:53 -07:00
commit 6e0d05fc41
137 changed files with 3411 additions and 2327 deletions

View File

@ -129,6 +129,7 @@ LOCAL_AAPT2_ONLY := true
LOCAL_MODULE_TAGS := optional
LOCAL_STATIC_JAVA_LIBRARIES := \
SystemUI-statsd \
SystemUISharedLib \
launcherprotosnano \
launcher_log_protos_lite
@ -201,6 +202,7 @@ LOCAL_USE_AAPT2 := true
LOCAL_MODULE_TAGS := optional
LOCAL_STATIC_JAVA_LIBRARIES := \
SystemUI-statsd \
SystemUISharedLib \
launcherprotosnano \
launcher_log_protos_lite

View File

@ -26,6 +26,7 @@ message ItemInfo {
Task task = 2;
Shortcut shortcut = 3;
Widget widget = 4;
FolderIcon folder_icon = 9;
}
// When used for launch event, stores the global predictive rank
optional int32 rank = 5;
@ -92,6 +93,11 @@ message Task {
optional int32 index = 3;
}
// Represents folder in a closed state.
message FolderIcon {
optional int32 cardinality = 1;
}
//////////////////////////////////////////////
// Containers

View File

@ -24,13 +24,13 @@
<View
android:layout_width="match_parent"
android:layout_height="32dp"
android:backgroundTint="?android:attr/colorAccent"
android:backgroundTint="?attr/eduHalfSheetBGColor"
android:background="@drawable/bottom_sheet_top_border" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?android:attr/colorAccent"
android:background="?attr/eduHalfSheetBGColor"
android:orientation="vertical">
<TextView

View File

@ -16,39 +16,24 @@
package com.android.launcher3;
import static com.android.launcher3.LauncherState.BACKGROUND_APP;
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.anim.Interpolators.AGGRESSIVE_EASE;
import static com.android.launcher3.anim.Interpolators.DEACCEL_3;
import static com.android.launcher3.anim.Interpolators.LINEAR;
import static com.android.launcher3.anim.Interpolators.OVERSHOOT_1_2;
import static com.android.launcher3.states.StateAnimationConfig.ANIM_ALL_APPS_FADE;
import static com.android.launcher3.states.StateAnimationConfig.ANIM_HOTSEAT_SCALE;
import static com.android.launcher3.states.StateAnimationConfig.ANIM_HOTSEAT_TRANSLATE;
import static com.android.launcher3.states.StateAnimationConfig.ANIM_VERTICAL_PROGRESS;
import static com.android.quickstep.TaskViewUtils.findTaskViewToLaunch;
import static com.android.quickstep.TaskViewUtils.getRecentsWindowAnimator;
import static com.android.quickstep.views.RecentsView.ADJACENT_PAGE_OFFSET;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
import android.content.Context;
import android.view.View;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.android.launcher3.LauncherState.ScaleAndTranslation;
import com.android.launcher3.allapps.AllAppsTransitionController;
import com.android.launcher3.anim.AnimatorPlaybackController;
import com.android.launcher3.anim.Interpolators;
import com.android.launcher3.anim.SpringAnimationBuilder;
import com.android.launcher3.states.StateAnimationConfig;
import com.android.quickstep.views.RecentsView;
import com.android.quickstep.views.TaskView;
import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
@ -59,13 +44,6 @@ import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
*/
public final class LauncherAppTransitionManagerImpl extends QuickstepAppTransitionManagerImpl {
public static final int INDEX_SHELF_ANIM = 0;
public static final int INDEX_RECENTS_FADE_ANIM = 1;
public static final int INDEX_RECENTS_TRANSLATE_X_ANIM = 2;
public static final int INDEX_PAUSE_TO_OVERVIEW_ANIM = 3;
public static final long ATOMIC_DURATION_FROM_PAUSED_TO_OVERVIEW = 300;
public LauncherAppTransitionManagerImpl(Context context) {
super(context);
}
@ -151,77 +129,4 @@ public final class LauncherAppTransitionManagerImpl extends QuickstepAppTransiti
mLauncher.getStateManager().reapplyState();
};
}
@Override
public int getStateElementAnimationsCount() {
return 4;
}
@Override
public Animator createStateElementAnimation(int index, float... values) {
switch (index) {
case INDEX_SHELF_ANIM: {
AllAppsTransitionController aatc = mLauncher.getAllAppsController();
Animator springAnim = aatc.createSpringAnimation(values);
if ((OVERVIEW.getVisibleElements(mLauncher) & HOTSEAT_ICONS) != 0) {
// Translate hotseat with the shelf until reaching overview.
float overviewProgress = OVERVIEW.getVerticalProgress(mLauncher);
ScaleAndTranslation sat = OVERVIEW.getHotseatScaleAndTranslation(mLauncher);
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 || mLauncher.isInState(BACKGROUND_APP)) {
float hotseatShift = (progress - overviewProgress) * shiftRange;
mLauncher.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;
}
case INDEX_RECENTS_FADE_ANIM:
return ObjectAnimator.ofFloat(mLauncher.getOverviewPanel(),
RecentsView.CONTENT_ALPHA, values);
case INDEX_RECENTS_TRANSLATE_X_ANIM: {
RecentsView rv = mLauncher.getOverviewPanel();
return new SpringAnimationBuilder(mLauncher)
.setMinimumVisibleChange(1f / rv.getPageOffsetScale())
.setDampingRatio(0.8f)
.setStiffness(250)
.setValues(values)
.build(rv, ADJACENT_PAGE_OFFSET);
}
case INDEX_PAUSE_TO_OVERVIEW_ANIM: {
StateAnimationConfig config = new StateAnimationConfig();
config.duration = ATOMIC_DURATION_FROM_PAUSED_TO_OVERVIEW;
config.setInterpolator(ANIM_VERTICAL_PROGRESS, OVERSHOOT_1_2);
config.setInterpolator(ANIM_ALL_APPS_FADE, DEACCEL_3);
if ((OVERVIEW.getVisibleElements(mLauncher) & HOTSEAT_ICONS) != 0) {
config.setInterpolator(ANIM_HOTSEAT_SCALE, OVERSHOOT_1_2);
config.setInterpolator(ANIM_HOTSEAT_TRANSLATE, OVERSHOOT_1_2);
}
LauncherStateManager stateManager = mLauncher.getStateManager();
return stateManager.createAtomicAnimation(
stateManager.getCurrentStableState(), OVERVIEW, config);
}
default:
return super.createStateElementAnimation(index, values);
}
}
}

View File

@ -26,10 +26,10 @@ import android.os.UserManager;
import com.android.launcher3.AbstractFloatingView;
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherState;
import com.android.launcher3.LauncherStateManager;
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
import com.android.launcher3.allapps.FloatingHeaderView;
import com.android.launcher3.statemanager.StateManager.StateListener;
import com.android.launcher3.views.ArrowTipView;
import com.android.systemui.shared.system.LauncherEventUtil;
@ -71,17 +71,16 @@ public class AllAppsTipView {
public static void scheduleShowIfNeeded(Launcher launcher) {
if (!hasSeenAllAppsTip(launcher)) {
launcher.getStateManager().addStateListener(
new LauncherStateManager.StateListener() {
@Override
public void onStateTransitionComplete(LauncherState finalState) {
if (finalState == ALL_APPS) {
if (showAllAppsTipIfNecessary(launcher)) {
launcher.getStateManager().removeStateListener(this);
}
}
launcher.getStateManager().addStateListener(new StateListener<LauncherState>() {
@Override
public void onStateTransitionComplete(LauncherState finalState) {
if (finalState == ALL_APPS) {
if (showAllAppsTipIfNecessary(launcher)) {
launcher.getStateManager().removeStateListener(this);
}
});
}
}
});
}
}
}

View File

@ -38,18 +38,18 @@ import androidx.core.content.ContextCompat;
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherState;
import com.android.launcher3.LauncherStateManager;
import com.android.launcher3.R;
import com.android.launcher3.allapps.FloatingHeaderRow;
import com.android.launcher3.allapps.FloatingHeaderView;
import com.android.launcher3.anim.PropertySetter;
import com.android.launcher3.statemanager.StateManager.StateListener;
import com.android.launcher3.util.Themes;
/**
* A view which shows a horizontal divider
*/
@TargetApi(Build.VERSION_CODES.O)
public class AppsDividerView extends View implements LauncherStateManager.StateListener,
public class AppsDividerView extends View implements StateListener<LauncherState>,
FloatingHeaderRow {
private static final String ALL_APPS_VISITED_COUNT = "launcher.all_apps_visited_count";

View File

@ -32,7 +32,6 @@ import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherAppState;
import com.android.launcher3.LauncherSettings;
import com.android.launcher3.LauncherState;
import com.android.launcher3.LauncherStateManager.StateListener;
import com.android.launcher3.Utilities;
import com.android.launcher3.allapps.AllAppsContainerView;
import com.android.launcher3.allapps.AllAppsStore.OnUpdateListener;
@ -41,6 +40,7 @@ import com.android.launcher3.icons.IconCache.ItemInfoUpdateReceiver;
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.model.data.ItemInfoWithIcon;
import com.android.launcher3.shortcuts.ShortcutKey;
import com.android.launcher3.statemanager.StateManager.StateListener;
import com.android.launcher3.userevent.nano.LauncherLogProto;
import com.android.launcher3.util.ComponentKey;
import com.android.launcher3.util.MainThreadInitializedObject;
@ -63,8 +63,8 @@ import java.util.stream.IntStream;
* 4) Maintains the current active client id (for the predictions) and all updates are performed on
* that client id.
*/
public class PredictionUiStateManager implements StateListener, ItemInfoUpdateReceiver,
OnIDPChangeListener, OnUpdateListener {
public class PredictionUiStateManager implements StateListener<LauncherState>,
ItemInfoUpdateReceiver, OnIDPChangeListener, OnUpdateListener {
public static final String LAST_PREDICTION_ENABLED_STATE = "last_prediction_enabled_state";

View File

@ -46,6 +46,7 @@ import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.model.data.WorkspaceItemInfo;
import com.android.launcher3.touch.ItemClickHandler;
import com.android.launcher3.touch.ItemLongClickListener;
import com.android.launcher3.util.SafeCloseable;
import com.android.launcher3.views.DoubleShadowBubbleTextView;
/**
@ -65,6 +66,7 @@ public class PredictedAppIcon extends DoubleShadowBubbleTextView implements
private final int mNormalizedIconRadius;
private final BlurMaskFilter mShadowFilter;
private int mPlateColor;
boolean mDrawForDrag = false;
public PredictedAppIcon(Context context) {
@ -188,6 +190,10 @@ public class PredictedAppIcon extends DoubleShadowBubbleTextView implements
}
private void drawEffect(Canvas canvas, boolean isBadged) {
// Don't draw ring effect if item is about to be dragged.
if (mDrawForDrag) {
return;
}
mRingPath.reset();
getShape().addToPath(mRingPath, getOutlineOffsetX(), getOutlineOffsetY(),
mNormalizedIconRadius);
@ -208,6 +214,26 @@ public class PredictedAppIcon extends DoubleShadowBubbleTextView implements
canvas.drawPath(mRingPath, mIconRingPaint);
}
@Override
public void getSourceVisualDragBounds(Rect bounds) {
super.getSourceVisualDragBounds(bounds);
if (!mIsPinned) {
int internalSize = (int) (bounds.width() * RING_EFFECT_RATIO);
bounds.inset(internalSize, internalSize);
}
}
@Override
public SafeCloseable prepareDrawDragView() {
mDrawForDrag = true;
invalidate();
SafeCloseable r = super.prepareDrawDragView();
return () -> {
r.close();
mDrawForDrag = false;
};
}
/**
* Creates and returns a new instance of PredictedAppIcon from WorkspaceItemInfo
*/

View File

@ -30,6 +30,7 @@ import static com.android.quickstep.SysUINavigationMode.Mode.NO_BUTTON;
import android.content.Intent;
import android.content.res.Configuration;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import androidx.annotation.Nullable;
@ -48,6 +49,9 @@ import com.android.launcher3.model.data.AppInfo;
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.model.data.WorkspaceItemInfo;
import com.android.launcher3.popup.SystemShortcut;
import com.android.launcher3.statemanager.StateManager.AtomicAnimationFactory;
import com.android.launcher3.testing.TestProtocol;
import com.android.launcher3.uioverrides.states.QuickstepAtomicAnimationFactory;
import com.android.launcher3.uioverrides.touchcontrollers.FlingAndHoldTouchController;
import com.android.launcher3.uioverrides.touchcontrollers.LandscapeEdgeSwipeController;
import com.android.launcher3.uioverrides.touchcontrollers.NavBarToHomeTouchController;
@ -243,6 +247,9 @@ public class QuickstepLauncher extends BaseQuickstepLauncher {
@Override
public TouchController[] createTouchControllers() {
if (TestProtocol.sDebugTracing) {
Log.d(TestProtocol.PAUSE_NOT_DETECTED, "createTouchControllers.1");
}
Mode mode = SysUINavigationMode.getMode(this);
ArrayList<TouchController> list = new ArrayList<>();
@ -250,7 +257,13 @@ public class QuickstepLauncher extends BaseQuickstepLauncher {
if (mode == NO_BUTTON) {
list.add(new NoButtonQuickSwitchTouchController(this));
list.add(new NavBarToHomeTouchController(this));
if (TestProtocol.sDebugTracing) {
Log.d(TestProtocol.PAUSE_NOT_DETECTED, "createTouchControllers.2");
}
if (FeatureFlags.ENABLE_OVERVIEW_ACTIONS.get()) {
if (TestProtocol.sDebugTracing) {
Log.d(TestProtocol.PAUSE_NOT_DETECTED, "createTouchControllers.3");
}
list.add(new NoButtonNavbarToOverviewTouchController(this));
} else {
list.add(new FlingAndHoldTouchController(this));
@ -279,6 +292,11 @@ public class QuickstepLauncher extends BaseQuickstepLauncher {
return list.toArray(new TouchController[list.size()]);
}
@Override
public AtomicAnimationFactory createAtomicAnimationFactory() {
return new QuickstepAtomicAnimationFactory(this);
}
private static final class LauncherTaskViewController extends
TaskViewTouchController<Launcher> {

View File

@ -17,6 +17,7 @@ package com.android.launcher3.uioverrides.states;
import android.content.Context;
import com.android.launcher3.BaseDraggingActivity;
import com.android.launcher3.Launcher;
import com.android.launcher3.allapps.AllAppsTransitionController;
import com.android.launcher3.userevent.nano.LauncherLogProto;
@ -54,11 +55,7 @@ public class BackgroundAppState extends OverviewState {
@Override
public float[] getOverviewScaleAndOffset(Launcher launcher) {
return new float[] {getOverviewScale(launcher), NO_OFFSET};
}
private float getOverviewScale(Launcher launcher) {
return ((RecentsView) launcher.getOverviewPanel()).getMaxScaleForFullScreen();
return getOverviewScaleAndOffsetForBackgroundState(launcher);
}
@Override
@ -88,4 +85,11 @@ public class BackgroundAppState extends OverviewState {
protected float getDepthUnchecked(Context context) {
return 1f;
}
public static float[] getOverviewScaleAndOffsetForBackgroundState(
BaseDraggingActivity activity) {
return new float[] {
((RecentsView) activity.getOverviewPanel()).getMaxScaleForFullScreen(),
NO_OFFSET};
}
}

View File

@ -19,8 +19,8 @@ import android.content.Context;
import android.content.res.Resources;
import android.graphics.Rect;
import com.android.launcher3.BaseDraggingActivity;
import com.android.launcher3.Launcher;
import com.android.launcher3.R;
import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType;
import com.android.quickstep.views.RecentsView;
@ -49,22 +49,25 @@ public class OverviewModalTaskState extends OverviewState {
@Override
public float[] getOverviewScaleAndOffset(Launcher launcher) {
Resources res = launcher.getBaseContext().getResources();
Rect out = new Rect();
launcher.<RecentsView>getOverviewPanel().getTaskSize(out);
int taskHeight = out.height();
float topMargin = res.getDimension(R.dimen.task_thumbnail_top_margin);
float bottomMargin = res.getDimension(R.dimen.task_thumbnail_bottom_margin_with_actions);
float newHeight = taskHeight + topMargin + bottomMargin;
float scale = newHeight / taskHeight;
return new float[] {scale, 0};
return getOverviewScaleAndOffsetForModalState(launcher);
}
@Override
public float getOverviewModalness() {
return 1.0f;
}
public static float[] getOverviewScaleAndOffsetForModalState(BaseDraggingActivity activity) {
Resources res = activity.getResources();
Rect out = new Rect();
activity.<RecentsView>getOverviewPanel().getTaskSize(out);
int taskHeight = out.height();
activity.<RecentsView>getOverviewPanel().getModalTaskSize(out);
int newHeight = out.height();
float scale = (float) newHeight / taskHeight;
return new float[] {scale, NO_OFFSET};
}
}

View File

@ -15,16 +15,7 @@
*/
package com.android.launcher3.uioverrides.states;
import static com.android.launcher3.anim.Interpolators.FAST_OUT_SLOW_IN;
import static com.android.launcher3.anim.Interpolators.INSTANT;
import static com.android.launcher3.anim.Interpolators.OVERSHOOT_1_7;
import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_FADE;
import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_SCRIM_FADE;
import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_TRANSLATE_X;
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherState;
import com.android.launcher3.states.StateAnimationConfig;
public class OverviewPeekState extends OverviewState {
private static final float OVERVIEW_OFFSET = 0.7f;
@ -37,14 +28,4 @@ public class OverviewPeekState extends OverviewState {
public float[] getOverviewScaleAndOffset(Launcher launcher) {
return new float[] {NO_SCALE, OVERVIEW_OFFSET};
}
@Override
public void prepareForAtomicAnimation(Launcher launcher, LauncherState fromState,
StateAnimationConfig config) {
if (this == OVERVIEW_PEEK && fromState == NORMAL) {
config.setInterpolator(ANIM_OVERVIEW_FADE, INSTANT);
config.setInterpolator(ANIM_OVERVIEW_TRANSLATE_X, OVERSHOOT_1_7);
config.setInterpolator(ANIM_OVERVIEW_SCRIM_FADE, FAST_OUT_SLOW_IN);
}
}
}

View File

@ -15,36 +15,21 @@
*/
package com.android.launcher3.uioverrides.states;
import static android.view.View.VISIBLE;
import static com.android.launcher3.LauncherAnimUtils.SCALE_PROPERTY;
import static com.android.launcher3.anim.Interpolators.ACCEL;
import static com.android.launcher3.anim.Interpolators.DEACCEL_2;
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.config.FeatureFlags.ENABLE_OVERVIEW_ACTIONS;
import static com.android.launcher3.logging.LoggerUtils.newContainerTarget;
import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_FADE;
import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_SCALE;
import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_TRANSLATE_X;
import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_TRANSLATE_Y;
import static com.android.launcher3.states.StateAnimationConfig.ANIM_WORKSPACE_FADE;
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 android.content.Context;
import android.graphics.Rect;
import android.view.View;
import android.view.animation.Interpolator;
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherState;
import com.android.launcher3.R;
import com.android.launcher3.Workspace;
import com.android.launcher3.states.StateAnimationConfig;
import com.android.launcher3.userevent.nano.LauncherLogProto.Action;
import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType;
import com.android.quickstep.SysUINavigationMode;
@ -57,9 +42,6 @@ import com.android.quickstep.views.TaskView;
*/
public class OverviewState extends LauncherState {
// Scale recents takes before animating in
private static final float RECENTS_PREPARE_SCALE = 1.33f;
protected static final Rect sTempRect = new Rect();
private static final int STATE_FLAGS = FLAG_WORKSPACE_ICONS_CAN_BE_DRAGGED
@ -202,35 +184,6 @@ public class OverviewState extends LauncherState {
}
}
@Override
public void prepareForAtomicAnimation(Launcher launcher, LauncherState fromState,
StateAnimationConfig config) {
if ((fromState == NORMAL || fromState == HINT_STATE) && this == OVERVIEW) {
if (SysUINavigationMode.getMode(launcher) == NO_BUTTON) {
config.setInterpolator(ANIM_WORKSPACE_SCALE,
fromState == NORMAL ? ACCEL : OVERSHOOT_1_2);
config.setInterpolator(ANIM_WORKSPACE_TRANSLATE, ACCEL);
} else {
config.setInterpolator(ANIM_WORKSPACE_SCALE, OVERSHOOT_1_2);
// Scale up the recents, if it is not coming from the side
RecentsView overview = launcher.getOverviewPanel();
if (overview.getVisibility() != VISIBLE || overview.getContentAlpha() == 0) {
SCALE_PROPERTY.set(overview, RECENTS_PREPARE_SCALE);
}
}
config.setInterpolator(ANIM_WORKSPACE_FADE, OVERSHOOT_1_2);
config.setInterpolator(ANIM_OVERVIEW_SCALE, OVERSHOOT_1_2);
Interpolator translationInterpolator = ENABLE_OVERVIEW_ACTIONS.get()
&& removeShelfFromOverview(launcher)
? OVERSHOOT_1_2
: OVERSHOOT_1_7;
config.setInterpolator(ANIM_OVERVIEW_TRANSLATE_X, translationInterpolator);
config.setInterpolator(ANIM_OVERVIEW_TRANSLATE_Y, translationInterpolator);
config.setInterpolator(ANIM_OVERVIEW_FADE, OVERSHOOT_1_2);
}
}
public static OverviewState newBackgroundState(int id) {
return new BackgroundAppState(id);
}

View File

@ -0,0 +1,236 @@
/*
* 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.states;
import static android.view.View.VISIBLE;
import static com.android.launcher3.LauncherAnimUtils.SCALE_PROPERTY;
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.LauncherState.OVERVIEW_PEEK;
import static com.android.launcher3.anim.Interpolators.ACCEL;
import static com.android.launcher3.anim.Interpolators.DEACCEL;
import static com.android.launcher3.anim.Interpolators.DEACCEL_1_7;
import static com.android.launcher3.anim.Interpolators.DEACCEL_3;
import static com.android.launcher3.anim.Interpolators.FAST_OUT_SLOW_IN;
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.config.FeatureFlags.ENABLE_OVERVIEW_ACTIONS;
import static com.android.launcher3.states.StateAnimationConfig.ANIM_ALL_APPS_FADE;
import static com.android.launcher3.states.StateAnimationConfig.ANIM_HOTSEAT_SCALE;
import static com.android.launcher3.states.StateAnimationConfig.ANIM_HOTSEAT_TRANSLATE;
import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_FADE;
import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_SCALE;
import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_SCRIM_FADE;
import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_TRANSLATE_X;
import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_TRANSLATE_Y;
import static com.android.launcher3.states.StateAnimationConfig.ANIM_VERTICAL_PROGRESS;
import static com.android.launcher3.states.StateAnimationConfig.ANIM_WORKSPACE_FADE;
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.ADJACENT_PAGE_OFFSET;
import android.animation.Animator;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
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.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.anim.SpringAnimationBuilder;
import com.android.launcher3.statemanager.StateManager;
import com.android.launcher3.statemanager.StateManager.AtomicAnimationFactory;
import com.android.launcher3.states.StateAnimationConfig;
import com.android.launcher3.uioverrides.QuickstepLauncher;
import com.android.quickstep.SysUINavigationMode;
import com.android.quickstep.views.RecentsView;
/**
* Animation factory for quickstep specific transitions
*/
public class QuickstepAtomicAnimationFactory extends AtomicAnimationFactory<LauncherState> {
// Scale recents takes before animating in
private static final float RECENTS_PREPARE_SCALE = 1.33f;
public static final int INDEX_SHELF_ANIM = 0;
public static final int INDEX_RECENTS_FADE_ANIM = 1;
public static final int INDEX_RECENTS_TRANSLATE_X_ANIM = 2;
public static final int INDEX_PAUSE_TO_OVERVIEW_ANIM = 3;
private static final int ANIM_COUNT = 4;
public static final long ATOMIC_DURATION_FROM_PAUSED_TO_OVERVIEW = 300;
private final QuickstepLauncher mLauncher;
public QuickstepAtomicAnimationFactory(QuickstepLauncher launcher) {
super(ANIM_COUNT);
mLauncher = launcher;
}
@Override
public Animator createStateElementAnimation(int index, float... values) {
switch (index) {
case INDEX_SHELF_ANIM: {
AllAppsTransitionController aatc = mLauncher.getAllAppsController();
Animator springAnim = aatc.createSpringAnimation(values);
if ((OVERVIEW.getVisibleElements(mLauncher) & HOTSEAT_ICONS) != 0) {
// Translate hotseat with the shelf until reaching overview.
float overviewProgress = OVERVIEW.getVerticalProgress(mLauncher);
ScaleAndTranslation sat = OVERVIEW.getHotseatScaleAndTranslation(mLauncher);
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 || mLauncher.isInState(BACKGROUND_APP)) {
float hotseatShift = (progress - overviewProgress) * shiftRange;
mLauncher.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;
}
case INDEX_RECENTS_FADE_ANIM:
return ObjectAnimator.ofFloat(mLauncher.getOverviewPanel(),
RecentsView.CONTENT_ALPHA, values);
case INDEX_RECENTS_TRANSLATE_X_ANIM: {
RecentsView rv = mLauncher.getOverviewPanel();
return new SpringAnimationBuilder(mLauncher)
.setMinimumVisibleChange(1f / rv.getPageOffsetScale())
.setDampingRatio(0.8f)
.setStiffness(250)
.setValues(values)
.build(rv, ADJACENT_PAGE_OFFSET);
}
case INDEX_PAUSE_TO_OVERVIEW_ANIM: {
StateAnimationConfig config = new StateAnimationConfig();
config.duration = ATOMIC_DURATION_FROM_PAUSED_TO_OVERVIEW;
config.setInterpolator(ANIM_VERTICAL_PROGRESS, OVERSHOOT_1_2);
config.setInterpolator(ANIM_ALL_APPS_FADE, DEACCEL_3);
if ((OVERVIEW.getVisibleElements(mLauncher) & HOTSEAT_ICONS) != 0) {
config.setInterpolator(ANIM_HOTSEAT_SCALE, OVERSHOOT_1_2);
config.setInterpolator(ANIM_HOTSEAT_TRANSLATE, OVERSHOOT_1_2);
}
StateManager<LauncherState> stateManager = mLauncher.getStateManager();
return stateManager.createAtomicAnimation(
stateManager.getCurrentStableState(), OVERVIEW, config);
}
default:
return super.createStateElementAnimation(index, values);
}
}
@Override
public void prepareForAtomicAnimation(LauncherState fromState, LauncherState toState,
StateAnimationConfig config) {
if (toState == NORMAL && fromState == OVERVIEW) {
config.setInterpolator(ANIM_WORKSPACE_SCALE, DEACCEL);
config.setInterpolator(ANIM_WORKSPACE_FADE, ACCEL);
config.setInterpolator(ANIM_OVERVIEW_SCALE, clampToProgress(ACCEL, 0, 0.9f));
config.setInterpolator(ANIM_OVERVIEW_TRANSLATE_X, ACCEL);
config.setInterpolator(ANIM_OVERVIEW_FADE, DEACCEL_1_7);
Workspace workspace = mLauncher.getWorkspace();
// Start from a higher workspace scale, but only if we're invisible so we don't jump.
boolean isWorkspaceVisible = workspace.getVisibility() == VISIBLE;
if (isWorkspaceVisible) {
CellLayout currentChild = (CellLayout) workspace.getChildAt(
workspace.getCurrentPage());
isWorkspaceVisible = currentChild.getVisibility() == VISIBLE
&& currentChild.getShortcutsAndWidgets().getAlpha() > 0;
}
if (!isWorkspaceVisible) {
workspace.setScaleX(0.92f);
workspace.setScaleY(0.92f);
}
Hotseat hotseat = mLauncher.getHotseat();
boolean isHotseatVisible = hotseat.getVisibility() == VISIBLE && hotseat.getAlpha() > 0;
if (!isHotseatVisible) {
hotseat.setScaleX(0.92f);
hotseat.setScaleY(0.92f);
if (ENABLE_OVERVIEW_ACTIONS.get()) {
AllAppsContainerView qsbContainer = mLauncher.getAppsView();
View qsb = qsbContainer.getSearchView();
boolean qsbVisible = qsb.getVisibility() == VISIBLE && qsb.getAlpha() > 0;
if (!qsbVisible) {
qsbContainer.setScaleX(0.92f);
qsbContainer.setScaleY(0.92f);
}
}
}
} else if (toState == NORMAL && fromState == OVERVIEW_PEEK) {
// Keep fully visible until the very end (when overview is offscreen) to make invisible.
config.setInterpolator(ANIM_OVERVIEW_FADE, t -> t < 1 ? 0 : 1);
} else if (toState == OVERVIEW_PEEK && fromState == NORMAL) {
config.setInterpolator(ANIM_OVERVIEW_FADE, INSTANT);
config.setInterpolator(ANIM_OVERVIEW_TRANSLATE_X, OVERSHOOT_1_7);
config.setInterpolator(ANIM_OVERVIEW_SCRIM_FADE, FAST_OUT_SLOW_IN);
} else if ((fromState == NORMAL || fromState == HINT_STATE) && toState == OVERVIEW) {
if (SysUINavigationMode.getMode(mLauncher) == NO_BUTTON) {
config.setInterpolator(ANIM_WORKSPACE_SCALE,
fromState == NORMAL ? ACCEL : OVERSHOOT_1_2);
config.setInterpolator(ANIM_WORKSPACE_TRANSLATE, ACCEL);
} else {
config.setInterpolator(ANIM_WORKSPACE_SCALE, OVERSHOOT_1_2);
// Scale up the recents, if it is not coming from the side
RecentsView overview = mLauncher.getOverviewPanel();
if (overview.getVisibility() != VISIBLE || overview.getContentAlpha() == 0) {
SCALE_PROPERTY.set(overview, RECENTS_PREPARE_SCALE);
}
}
config.setInterpolator(ANIM_WORKSPACE_FADE, OVERSHOOT_1_2);
config.setInterpolator(ANIM_OVERVIEW_SCALE, OVERSHOOT_1_2);
Interpolator translationInterpolator = ENABLE_OVERVIEW_ACTIONS.get()
&& removeShelfFromOverview(mLauncher)
? OVERSHOOT_1_2
: OVERSHOOT_1_7;
config.setInterpolator(ANIM_OVERVIEW_TRANSLATE_X, translationInterpolator);
config.setInterpolator(ANIM_OVERVIEW_TRANSLATE_Y, translationInterpolator);
config.setInterpolator(ANIM_OVERVIEW_FADE, OVERSHOOT_1_2);
}
}
}

View File

@ -16,7 +16,6 @@
package com.android.launcher3.uioverrides.touchcontrollers;
import static com.android.launcher3.LauncherAppTransitionManagerImpl.INDEX_PAUSE_TO_OVERVIEW_ANIM;
import static com.android.launcher3.LauncherState.ALL_APPS;
import static com.android.launcher3.LauncherState.NORMAL;
import static com.android.launcher3.LauncherState.OVERVIEW;
@ -31,23 +30,26 @@ import static com.android.launcher3.states.StateAnimationConfig.ANIM_WORKSPACE_S
import static com.android.launcher3.states.StateAnimationConfig.ANIM_WORKSPACE_TRANSLATE;
import static com.android.launcher3.states.StateAnimationConfig.PLAY_ATOMIC_OVERVIEW_PEEK;
import static com.android.launcher3.states.StateAnimationConfig.SKIP_OVERVIEW;
import static com.android.launcher3.uioverrides.states.QuickstepAtomicAnimationFactory.INDEX_PAUSE_TO_OVERVIEW_ANIM;
import static com.android.launcher3.util.VibratorWrapper.OVERVIEW_HAPTIC;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_OVERVIEW_DISABLED;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewConfiguration;
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherAppTransitionManagerImpl;
import com.android.launcher3.LauncherState;
import com.android.launcher3.anim.AnimationSuccessListener;
import com.android.launcher3.anim.Interpolators;
import com.android.launcher3.states.StateAnimationConfig;
import com.android.launcher3.states.StateAnimationConfig.AnimationFlags;
import com.android.launcher3.testing.TestProtocol;
import com.android.launcher3.uioverrides.states.QuickstepAtomicAnimationFactory;
import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Touch;
import com.android.launcher3.util.VibratorWrapper;
import com.android.quickstep.SystemUiProxy;
@ -82,7 +84,7 @@ public class FlingAndHoldTouchController extends PortraitStatesTouchController {
@Override
protected long getAtomicDuration() {
return LauncherAppTransitionManagerImpl.ATOMIC_DURATION_FROM_PAUSED_TO_OVERVIEW;
return QuickstepAtomicAnimationFactory.ATOMIC_DURATION_FROM_PAUSED_TO_OVERVIEW;
}
@Override
@ -178,6 +180,9 @@ public class FlingAndHoldTouchController extends PortraitStatesTouchController {
@Override
public boolean onDrag(float displacement, MotionEvent event) {
if (TestProtocol.sDebugTracing) {
Log.d(TestProtocol.PAUSE_NOT_DETECTED, "FlingAndHoldTouchController");
}
float upDisplacement = -displacement;
mMotionPauseDetector.setDisallowPause(!handlingOverviewAnim()
|| upDisplacement < mMotionPauseMinDisplacement
@ -206,8 +211,8 @@ public class FlingAndHoldTouchController extends PortraitStatesTouchController {
mPeekAnim.cancel();
}
Animator overviewAnim = mLauncher.getAppTransitionManager().createStateElementAnimation(
INDEX_PAUSE_TO_OVERVIEW_ANIM);
Animator overviewAnim = mLauncher.createAtomicAnimationFactory()
.createStateElementAnimation(INDEX_PAUSE_TO_OVERVIEW_ANIM);
mAtomicAnim = new AnimatorSet();
mAtomicAnim.addListener(new AnimationSuccessListener() {
@Override

View File

@ -25,6 +25,7 @@ import static com.android.quickstep.views.RecentsView.ADJACENT_PAGE_OFFSET;
import static com.android.systemui.shared.system.ActivityManagerWrapper.CLOSE_SYSTEM_WINDOWS_REASON_RECENTS;
import android.animation.ValueAnimator;
import android.util.Log;
import android.view.MotionEvent;
import android.view.animation.Interpolator;
@ -41,6 +42,7 @@ import com.android.launcher3.anim.PendingAnimation;
import com.android.launcher3.compat.AccessibilityManagerCompat;
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.states.StateAnimationConfig;
import com.android.launcher3.testing.TestProtocol;
import com.android.launcher3.touch.SingleAxisSwipeDetector;
import com.android.launcher3.userevent.nano.LauncherLogProto;
import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Touch;
@ -94,18 +96,37 @@ public class NavBarToHomeTouchController implements TouchController,
}
private boolean canInterceptTouch(MotionEvent ev) {
if (TestProtocol.sDebugTracing) {
Log.d(TestProtocol.PAUSE_NOT_DETECTED, "NavBarToHomeTouchController.canInterceptTouch "
+ ev);
}
boolean cameFromNavBar = (ev.getEdgeFlags() & Utilities.EDGE_NAV_BAR) != 0;
if (!cameFromNavBar) {
return false;
}
if (mStartState.overviewUi || mStartState == ALL_APPS) {
if (TestProtocol.sDebugTracing) {
Log.d(TestProtocol.PAUSE_NOT_DETECTED,
"NavBarToHomeTouchController.canInterceptTouch true 1 "
+ mStartState.overviewUi + " " + (mStartState == ALL_APPS));
}
return true;
}
if (AbstractFloatingView.getTopOpenView(mLauncher) != null) {
if (TestProtocol.sDebugTracing) {
Log.d(TestProtocol.PAUSE_NOT_DETECTED,
"NavBarToHomeTouchController.canInterceptTouch true 2 "
+ AbstractFloatingView.getTopOpenView(mLauncher).getClass()
.getSimpleName());
}
return true;
}
if (FeatureFlags.ASSISTANT_GIVES_LAUNCHER_FOCUS.get()
&& AssistantUtilities.isExcludedAssistantRunning()) {
if (TestProtocol.sDebugTracing) {
Log.d(TestProtocol.PAUSE_NOT_DETECTED,
"NavBarToHomeTouchController.canInterceptTouch true 3");
}
return true;
}
return false;

View File

@ -27,14 +27,16 @@ import static com.android.launcher3.util.VibratorWrapper.OVERVIEW_HAPTIC;
import android.animation.AnimatorSet;
import android.animation.ValueAnimator;
import android.graphics.PointF;
import android.util.Log;
import android.view.MotionEvent;
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherState;
import com.android.launcher3.LauncherStateManager;
import com.android.launcher3.Utilities;
import com.android.launcher3.anim.AnimationSuccessListener;
import com.android.launcher3.statemanager.StateManager;
import com.android.launcher3.states.StateAnimationConfig;
import com.android.launcher3.testing.TestProtocol;
import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Touch;
import com.android.launcher3.util.VibratorWrapper;
import com.android.quickstep.util.StaggeredWorkspaceAnim;
@ -63,6 +65,9 @@ public class NoButtonNavbarToOverviewTouchController extends FlingAndHoldTouchCo
public NoButtonNavbarToOverviewTouchController(Launcher l) {
super(l);
mRecentsView = l.getOverviewPanel();
if (TestProtocol.sDebugTracing) {
Log.d(TestProtocol.PAUSE_NOT_DETECTED, "NoButtonNavbarToOverviewTouchController.ctor");
}
}
@Override
@ -146,6 +151,9 @@ public class NoButtonNavbarToOverviewTouchController extends FlingAndHoldTouchCo
@Override
public boolean onDrag(float yDisplacement, float xDisplacement, MotionEvent event) {
if (TestProtocol.sDebugTracing) {
Log.d(TestProtocol.PAUSE_NOT_DETECTED, "NoButtonNavbarToOverviewTouchController");
}
if (mMotionPauseDetector.isPaused()) {
if (!mReachedOverview) {
mStartDisplacement.set(xDisplacement, yDisplacement);
@ -165,7 +173,7 @@ public class NoButtonNavbarToOverviewTouchController extends FlingAndHoldTouchCo
protected void goToOverviewOnDragEnd(float velocity) {
float velocityDp = dpiFromPx(velocity);
boolean isFling = Math.abs(velocityDp) > 1;
LauncherStateManager stateManager = mLauncher.getStateManager();
StateManager<LauncherState> stateManager = mLauncher.getStateManager();
boolean goToHomeInsteadOfOverview = isFling;
if (goToHomeInsteadOfOverview) {
if (velocity > 0) {

View File

@ -16,7 +16,6 @@
package com.android.launcher3.uioverrides.touchcontrollers;
import static com.android.launcher3.LauncherAnimUtils.SCALE_PROPERTY;
import static com.android.launcher3.LauncherAppTransitionManagerImpl.INDEX_PAUSE_TO_OVERVIEW_ANIM;
import static com.android.launcher3.LauncherState.HOTSEAT_ICONS;
import static com.android.launcher3.LauncherState.NORMAL;
import static com.android.launcher3.LauncherState.OVERVIEW;
@ -35,6 +34,7 @@ import static com.android.launcher3.states.StateAnimationConfig.ANIM_WORKSPACE_T
import static com.android.launcher3.states.StateAnimationConfig.SKIP_OVERVIEW;
import static com.android.launcher3.touch.BothAxesSwipeDetector.DIRECTION_RIGHT;
import static com.android.launcher3.touch.BothAxesSwipeDetector.DIRECTION_UP;
import static com.android.launcher3.uioverrides.states.QuickstepAtomicAnimationFactory.INDEX_PAUSE_TO_OVERVIEW_ANIM;
import static com.android.launcher3.util.DefaultDisplay.getSingleFrameMs;
import static com.android.launcher3.util.VibratorWrapper.OVERVIEW_HAPTIC;
import static com.android.quickstep.util.ShelfPeekAnim.ShelfAnimState.CANCEL;
@ -312,8 +312,8 @@ public class NoButtonQuickSwitchTouchController implements TouchController,
if (mMotionPauseDetector.isPaused() && noFling) {
cancelAnimations();
Animator overviewAnim = mLauncher.getAppTransitionManager().createStateElementAnimation(
INDEX_PAUSE_TO_OVERVIEW_ANIM);
Animator overviewAnim = mLauncher.createAtomicAnimationFactory()
.createStateElementAnimation(INDEX_PAUSE_TO_OVERVIEW_ANIM);
overviewAnim.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {

View File

@ -58,6 +58,7 @@ public abstract class TaskViewTouchController<T extends BaseDraggingActivity>
private final SingleAxisSwipeDetector mDetector;
private final RecentsView mRecentsView;
private final int[] mTempCords = new int[2];
private final boolean mIsRtl;
private PendingAnimation mPendingAnimation;
private AnimatorPlaybackController mCurrentAnimation;
@ -75,6 +76,7 @@ public abstract class TaskViewTouchController<T extends BaseDraggingActivity>
public TaskViewTouchController(T activity) {
mActivity = activity;
mRecentsView = activity.getOverviewPanel();
mIsRtl = Utilities.isRtl(activity.getResources());
SingleAxisSwipeDetector.Direction dir =
mRecentsView.getPagedOrientationHandler().getOppositeSwipeDirection();
mDetector = new SingleAxisSwipeDetector(activity, this, dir);
@ -201,8 +203,8 @@ public abstract class TaskViewTouchController<T extends BaseDraggingActivity>
mCurrentAnimationIsGoingUp = goingUp;
BaseDragLayer dl = mActivity.getDragLayer();
final int secondaryLayerDimension = orientationHandler.getSecondaryDimension(dl);
long maxDuration = (long) (2 * secondaryLayerDimension);
int verticalFactor = -orientationHandler.getTaskDismissDirectionFactor();
long maxDuration = 2 * secondaryLayerDimension;
int verticalFactor = orientationHandler.getTaskDragDisplacementFactor(mIsRtl);
int secondaryTaskDimension = orientationHandler.getSecondaryDimension(mTaskBeingDragged);
if (goingUp) {
mPendingAnimation = mRecentsView.createTaskDismissAnimation(mTaskBeingDragged,
@ -236,7 +238,7 @@ public abstract class TaskViewTouchController<T extends BaseDraggingActivity>
public void onDragStart(boolean start, float startDisplacement) {
PagedOrientationHandler orientationHandler = mRecentsView.getPagedOrientationHandler();
if (mCurrentAnimation == null) {
reInitAnimationController(orientationHandler.isGoingUp(startDisplacement));
reInitAnimationController(orientationHandler.isGoingUp(startDisplacement, mIsRtl));
mDisplacementShift = 0;
} else {
mDisplacementShift = mCurrentAnimation.getProgressFraction() / mProgressMultiplier;
@ -250,7 +252,7 @@ public abstract class TaskViewTouchController<T extends BaseDraggingActivity>
PagedOrientationHandler orientationHandler = mRecentsView.getPagedOrientationHandler();
float totalDisplacement = displacement + mDisplacementShift;
boolean isGoingUp = totalDisplacement == 0 ? mCurrentAnimationIsGoingUp :
orientationHandler.isGoingUp(totalDisplacement);
orientationHandler.isGoingUp(totalDisplacement, mIsRtl);
if (isGoingUp != mCurrentAnimationIsGoingUp) {
reInitAnimationController(isGoingUp);
mFlingBlockCheck.blockFling();
@ -282,7 +284,7 @@ public abstract class TaskViewTouchController<T extends BaseDraggingActivity>
float interpolatedProgress = mCurrentAnimation.getInterpolatedProgress();
if (fling) {
logAction = Touch.FLING;
boolean goingUp = orientationHandler.isGoingUp(velocity);
boolean goingUp = orientationHandler.isGoingUp(velocity, mIsRtl);
goingToEnd = goingUp == mCurrentAnimationIsGoingUp;
} else {
logAction = Touch.SWIPE;

View File

@ -17,7 +17,6 @@ package com.android.quickstep;
import static com.android.launcher3.LauncherState.BACKGROUND_APP;
import static com.android.launcher3.LauncherState.OVERVIEW;
import static com.android.launcher3.anim.Interpolators.FAST_OUT_SLOW_IN;
import static com.android.launcher3.anim.Interpolators.TOUCH_RESPONSE_INTERPOLATOR;
import static com.android.launcher3.statehandlers.DepthController.DEPTH;
import static com.android.systemui.shared.system.RemoteAnimationTargetCompat.MODE_CLOSING;
@ -36,8 +35,8 @@ import com.android.launcher3.BaseDraggingActivity;
import com.android.launcher3.anim.AnimationSuccessListener;
import com.android.launcher3.statehandlers.DepthController;
import com.android.quickstep.util.AppWindowAnimationHelper;
import com.android.quickstep.util.AppWindowAnimationHelper.TransformParams;
import com.android.quickstep.util.RemoteAnimationProvider;
import com.android.quickstep.util.TransformParams;
import com.android.quickstep.views.RecentsView;
import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
import com.android.systemui.shared.system.SyncRtSurfaceTransactionApplierCompat;
@ -75,14 +74,10 @@ final class AppToOverviewAnimationProvider<T extends BaseDraggingActivity> exten
boolean onActivityReady(T activity, Boolean wasVisible) {
activity.<RecentsView>getOverviewPanel().showCurrentTask(mTargetTaskId);
AbstractFloatingView.closeAllOpenViews(activity, wasVisible);
BaseActivityInterface.AnimationFactory factory =
mActivityInterface.prepareRecentsUI(wasVisible,
false /* animate activity */, (controller) -> {
BaseActivityInterface.AnimationFactory factory = mActivityInterface.prepareRecentsUI(
wasVisible, (controller) -> {
controller.dispatchOnStart();
ValueAnimator anim = controller.getAnimationPlayer()
.setDuration(RECENTS_LAUNCH_DURATION);
anim.setInterpolator(FAST_OUT_SLOW_IN);
anim.start();
controller.getAnimationPlayer().end();
});
factory.onRemoteAnimationReceived(null);
factory.createActivityInterface(RECENTS_LAUNCH_DURATION);
@ -164,9 +159,7 @@ final class AppToOverviewAnimationProvider<T extends BaseDraggingActivity> exten
valueAnimator.setDuration(RECENTS_LAUNCH_DURATION);
valueAnimator.setInterpolator(TOUCH_RESPONSE_INTERPOLATOR);
valueAnimator.addUpdateListener((v) -> {
params.setProgress((float) v.getAnimatedValue())
.setTargetSet(targets)
.setLauncherOnTop(true);
params.setProgress((float) v.getAnimatedValue()).setTargetSet(targets);
clipHelper.applyTransform(params);
});

View File

@ -15,6 +15,8 @@
*/
package com.android.quickstep;
import static com.android.launcher3.LauncherState.BACKGROUND_APP;
import static com.android.launcher3.LauncherState.OVERVIEW;
import static com.android.launcher3.anim.Interpolators.ACCEL_1_5;
import static com.android.launcher3.anim.Interpolators.DEACCEL;
import static com.android.launcher3.config.FeatureFlags.ENABLE_QUICKSTEP_LIVE_TILE;
@ -23,44 +25,49 @@ import static com.android.launcher3.util.VibratorWrapper.OVERVIEW_HAPTIC;
import static com.android.launcher3.views.FloatingIconView.SHAPE_PROGRESS_DURATION;
import android.animation.Animator;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.annotation.TargetApi;
import android.content.Context;
import android.content.Intent;
import android.graphics.Matrix;
import android.graphics.Matrix.ScaleToFit;
import android.graphics.PointF;
import android.graphics.Rect;
import android.graphics.RectF;
import android.os.Build;
import android.util.Pair;
import android.view.MotionEvent;
import android.view.View;
import android.view.animation.Interpolator;
import androidx.annotation.CallSuper;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.UiThread;
import com.android.launcher3.BaseDraggingActivity;
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.InvariantDeviceProfile;
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
import com.android.launcher3.anim.AnimationSuccessListener;
import com.android.launcher3.anim.AnimatorPlaybackController;
import com.android.launcher3.touch.PagedOrientationHandler;
import com.android.launcher3.util.VibratorWrapper;
import com.android.launcher3.views.FloatingIconView;
import com.android.quickstep.BaseActivityInterface.HomeAnimationFactory;
import com.android.quickstep.RecentsAnimationCallbacks.RecentsAnimationListener;
import com.android.quickstep.util.ActiveGestureLog;
import com.android.quickstep.util.ActivityInitListener;
import com.android.quickstep.util.AppWindowAnimationHelper;
import com.android.quickstep.util.AppWindowAnimationHelper.TransformParams;
import com.android.quickstep.util.RecentsOrientedState;
import com.android.quickstep.util.RectFSpringAnim;
import com.android.quickstep.util.TaskViewSimulator;
import com.android.quickstep.util.TransformParams;
import com.android.quickstep.util.TransformParams.BuilderProxy;
import com.android.quickstep.util.WindowSizeStrategy;
import com.android.quickstep.views.RecentsView;
import com.android.quickstep.views.TaskView;
import com.android.systemui.shared.recents.model.ThumbnailData;
import com.android.systemui.shared.system.InputConsumerController;
import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
import com.android.systemui.shared.system.SyncRtSurfaceTransactionApplierCompat;
import com.android.systemui.shared.system.SyncRtSurfaceTransactionApplierCompat.SurfaceParams.Builder;
import java.util.ArrayList;
import java.util.function.Consumer;
@ -93,7 +100,9 @@ public abstract class BaseSwipeUpHandler<T extends BaseDraggingActivity, Q exten
protected final BaseActivityInterface<T> mActivityInterface;
protected final InputConsumerController mInputConsumer;
protected AppWindowAnimationHelper mAppWindowAnimationHelper;
protected final TaskViewSimulator mTaskViewSimulator;
private AnimatorPlaybackController mWindowTransitionController;
protected final TransformParams mTransformParams = new TransformParams();
// Shift in the range of [0, 1].
@ -113,27 +122,25 @@ public abstract class BaseSwipeUpHandler<T extends BaseDraggingActivity, Q exten
protected T mActivity;
protected Q mRecentsView;
protected DeviceProfile mDp;
private final int mPageSpacing;
protected Runnable mGestureEndCallback;
protected MultiStateCallback mStateCallback;
protected boolean mCanceled;
protected int mFinishingRecentsAnimationForNewTaskId = -1;
private RecentsOrientedState mOrientedState;
private boolean mRecentsViewScrollLinked = false;
protected BaseSwipeUpHandler(Context context, RecentsAnimationDeviceState deviceState,
GestureState gestureState, InputConsumerController inputConsumer) {
GestureState gestureState, InputConsumerController inputConsumer,
WindowSizeStrategy windowSizeStrategy) {
mContext = context;
mDeviceState = deviceState;
mGestureState = gestureState;
mActivityInterface = gestureState.getActivityInterface();
mActivityInitListener = mActivityInterface.createActivityInitListener(this::onActivityInit);
mInputConsumer = inputConsumer;
mAppWindowAnimationHelper = new AppWindowAnimationHelper(context);
mPageSpacing = context.getResources().getDimensionPixelSize(R.dimen.recents_page_spacing);
mTaskViewSimulator = new TaskViewSimulator(context, windowSizeStrategy);
}
/**
@ -193,13 +200,13 @@ public abstract class BaseSwipeUpHandler<T extends BaseDraggingActivity, Q exten
updateFinalShift();
}
});
mRecentsView.setAppWindowAnimationHelper(mAppWindowAnimationHelper);
runOnRecentsAnimationStart(() ->
mRecentsView.setRecentsAnimationTargets(mRecentsAnimationController,
mRecentsAnimationTargets));
mRecentsViewScrollLinked = true;
}
protected void startNewTask(int successStateFlag, Consumer<Boolean> resultCallback) {
protected void startNewTask(Consumer<Boolean> resultCallback) {
// Launch the task user scrolled to (mRecentsView.getNextPage()).
if (ENABLE_QUICKSTEP_LIVE_TILE.get()) {
// We finish recents animation inside launchTask() when live tile is enabled.
@ -210,24 +217,41 @@ public abstract class BaseSwipeUpHandler<T extends BaseDraggingActivity, Q exten
if (!mCanceled) {
TaskView nextTask = mRecentsView.getTaskView(taskId);
if (nextTask != null) {
mGestureState.updateLastStartedTaskId(taskId);
nextTask.launchTask(false /* animate */, true /* freezeTaskList */,
success -> {
resultCallback.accept(success);
if (!success) {
if (success) {
if (mRecentsView.indexOfChild(nextTask)
== getLastAppearedTaskIndex()) {
onRestartLastAppearedTask();
}
} else {
mActivityInterface.onLaunchTaskFailed();
nextTask.notifyTaskLaunchFailed(TAG);
} else {
mActivityInterface.onLaunchTaskSuccess();
mRecentsAnimationController.finish(true /* toRecents */, null);
}
}, MAIN_EXECUTOR.getHandler());
}
mStateCallback.setStateOnUiThread(successStateFlag);
}
mCanceled = false;
}
ActiveGestureLog.INSTANCE.addLog("finishRecentsAnimation", true);
}
/**
* Called when we successfully startNewTask() on the task that was previously running. Normally
* we call resumeLastTask() when returning to the previously running task, but this handles a
* specific edge case: if we switch from A to B, and back to A before B appears, we need to
* start A again to ensure it stays on top.
*/
@CallSuper
protected void onRestartLastAppearedTask() {
// Finish the controller here, since we won't get onTaskAppeared() for a task that already
// appeared.
mRecentsAnimationController.finish(false, null);
}
/**
* Runs the given {@param action} if the recents animation has already started, or queues it to
* be run when it is next started.
@ -241,42 +265,36 @@ public abstract class BaseSwipeUpHandler<T extends BaseDraggingActivity, Q exten
}
/**
* TODO can we remove this now that we don't finish the controller until onTaskAppeared()?
* @return whether the recents animation has started and there are valid app targets.
*/
protected boolean hasTargets() {
return mRecentsAnimationTargets != null && mRecentsAnimationTargets.hasTargets();
}
protected void updateSource(Rect stackBounds, RemoteAnimationTargetCompat runningTarget) {
mAppWindowAnimationHelper.updateSource(stackBounds, runningTarget);
}
@Override
public void onRecentsAnimationStart(RecentsAnimationController recentsAnimationController,
RecentsAnimationTargets targets) {
mRecentsAnimationController = recentsAnimationController;
mRecentsAnimationTargets = targets;
DeviceProfile dp = InvariantDeviceProfile.INSTANCE.get(mContext).getDeviceProfile(mContext);
final Rect overviewStackBounds;
RemoteAnimationTargetCompat runningTaskTarget = targets.findTask(
mGestureState.getRunningTaskId());
if (targets.minimizedHomeBounds != null && runningTaskTarget != null) {
overviewStackBounds = mActivityInterface
Rect overviewStackBounds = mActivityInterface
.getOverviewWindowBounds(targets.minimizedHomeBounds, runningTaskTarget);
dp = dp.getMultiWindowProfile(mContext, overviewStackBounds);
} else {
// If we are not in multi-window mode, home insets should be same as system insets.
dp = dp.copy(mContext);
overviewStackBounds = getStackBounds(dp);
}
dp.updateInsets(targets.homeContentInsets);
dp.updateIsSeascape(mContext);
if (runningTaskTarget != null) {
updateSource(overviewStackBounds, runningTaskTarget);
mTaskViewSimulator.setPreview(runningTaskTarget);
}
mAppWindowAnimationHelper.prepareAnimation(dp);
initTransitionEndpoints(dp);
// Notify when the animation starts
@ -306,51 +324,73 @@ public abstract class BaseSwipeUpHandler<T extends BaseDraggingActivity, Q exten
}
}
private Rect getStackBounds(DeviceProfile dp) {
if (mActivity != null) {
int loc[] = new int[2];
View rootView = mActivity.getRootView();
rootView.getLocationOnScreen(loc);
return new Rect(loc[0], loc[1], loc[0] + rootView.getWidth(),
loc[1] + rootView.getHeight());
} else {
return new Rect(0, 0, dp.widthPx, dp.heightPx);
@Override
public void onTaskAppeared(RemoteAnimationTargetCompat appearedTaskTarget) {
if (mRecentsAnimationController != null) {
if (handleTaskAppeared(appearedTaskTarget)) {
mRecentsAnimationController.finish(false /* toRecents */,
null /* onFinishComplete */);
mActivityInterface.onLaunchTaskSuccess();
}
}
}
/** @return Whether this was the task we were waiting to appear, and thus handled it. */
protected abstract boolean handleTaskAppeared(RemoteAnimationTargetCompat appearedTaskTarget);
/**
* @return The index of the TaskView in RecentsView whose taskId matches the task that will
* resume if we finish the controller.
*/
protected int getLastAppearedTaskIndex() {
return mGestureState.getLastAppearedTaskId() != -1
? mRecentsView.getTaskIndexForId(mGestureState.getLastAppearedTaskId())
: mRecentsView.getRunningTaskIndex();
}
/**
* @return Whether we are continuing a gesture that already landed on a new task,
* but before that task appeared.
*/
protected boolean hasStartedNewTask() {
return mGestureState.getLastStartedTaskId() != -1;
}
protected void initTransitionEndpoints(DeviceProfile dp) {
mDp = dp;
mTransitionDragLength = mActivityInterface.getSwipeUpDestinationAndLength(
dp, mContext, TEMP_RECT);
mTaskViewSimulator.setDp(dp);
mTaskViewSimulator.setLayoutRotation(
mDeviceState.getCurrentActiveRotation(),
mDeviceState.getDisplayRotation());
if (!dp.isMultiWindowMode) {
// When updating the target rect, also update the home bounds since the location on
// screen of the launcher window may be stale (position is not updated until first
// traversal after the window is resized). We only do this for non-multiwindow because
// we otherwise use the minimized home bounds provided by the system.
mAppWindowAnimationHelper.updateHomeBounds(getStackBounds(dp));
}
int displayRotation = 0;
if (mOrientedState != null && mOrientedState.isMultipleOrientationSupportedByDevice()) {
// TODO(b/150300347): The first recents animation after launcher is started with the
// foreground app not in landscape will look funky until that bug is fixed
displayRotation = mOrientedState.getDisplayRotation();
RectF tempRectF = new RectF(TEMP_RECT);
mOrientedState.mapRectFromRotation(displayRotation,
tempRectF, dp.widthPx, dp.heightPx);
tempRectF.roundOut(TEMP_RECT);
}
mAppWindowAnimationHelper.updateTargetRect(TEMP_RECT);
if (mDeviceState.isFullyGesturalNavMode()) {
// We can drag all the way to the top of the screen.
mDragLengthFactor = (float) dp.heightPx / mTransitionDragLength;
Pair<Float, Float> dragFactorStartAndMaxProgress =
mActivityInterface.getSwipeUpPullbackStartAndMaxProgress();
mDragLengthFactorStartPullback = dragFactorStartAndMaxProgress.first;
mDragLengthFactorMaxPullback = dragFactorStartAndMaxProgress.second;
float startScale = mTaskViewSimulator.getFullScreenScale();
// Start pulling back when RecentsView scale is 0.75f, and let it go down to 0.5f.
mDragLengthFactorStartPullback = (0.75f - startScale) / (1 - startScale);
mDragLengthFactorMaxPullback = (0.5f - startScale) / (1 - startScale);
} else {
mDragLengthFactor = 1;
mDragLengthFactorStartPullback = mDragLengthFactorMaxPullback = 1;
}
AnimatorSet anim = new AnimatorSet();
anim.setDuration(mTransitionDragLength * 2);
anim.setInterpolator(t -> t * mDragLengthFactor);
anim.play(ObjectAnimator.ofFloat(mTaskViewSimulator.recentsViewScale,
AnimatedFloat.VALUE,
mTaskViewSimulator.getFullScreenScale(), 1));
anim.play(ObjectAnimator.ofFloat(mTaskViewSimulator.fullScreenProgress,
AnimatedFloat.VALUE,
BACKGROUND_APP.getOverviewFullscreenProgress(),
OVERVIEW.getOverviewFullscreenProgress()));
mWindowTransitionController =
AnimatorPlaybackController.wrap(anim, mTransitionDragLength * 2);
}
/**
@ -361,9 +401,6 @@ public abstract class BaseSwipeUpHandler<T extends BaseDraggingActivity, Q exten
protected boolean onActivityInit(Boolean alreadyOnHome) {
T createdActivity = mActivityInterface.getCreatedActivity();
if (createdActivity != null) {
mOrientedState = ((RecentsView) createdActivity.getOverviewPanel())
.getPagedViewOrientedState();
mAppWindowAnimationHelper = new AppWindowAnimationHelper(mOrientedState, mContext);
initTransitionEndpoints(InvariantDeviceProfile.INSTANCE.get(mContext)
.getDeviceProfile(mContext));
}
@ -412,35 +449,23 @@ public abstract class BaseSwipeUpHandler<T extends BaseDraggingActivity, Q exten
}
/**
* Applies the transform on the recents animation without any additional null checks
* Applies the transform on the recents animation
*/
protected void applyTransformUnchecked() {
float shift = mCurrentShift.value;
float offset = mRecentsView == null ? 0 : mRecentsView.getScrollOffsetScaled();
float taskSize = getOrientationHandler()
.getPrimarySize(mAppWindowAnimationHelper.getTargetRect());
float offsetScale = getTaskCurveScaleForOffset(offset, taskSize);
mTransformParams
.setProgress(shift)
.setOffset(offset)
.setOffsetScale(offsetScale)
.setTargetSet(mRecentsAnimationTargets)
.setLauncherOnTop(true);
mAppWindowAnimationHelper.applyTransform(mTransformParams);
}
protected void applyWindowTransform() {
if (mWindowTransitionController != null) {
float progress = mCurrentShift.value / mDragLengthFactor;
mWindowTransitionController.setPlayFraction(progress);
mTransformParams.setTargetSet(mRecentsAnimationTargets);
private float getTaskCurveScaleForOffset(float offset, float taskSize) {
int dpPixel = getOrientationHandler().getShortEdgeLength(mDp);
float distanceToReachEdge = dpPixel / 2 + taskSize / 2 + mPageSpacing;
float interpolation = Math.min(1, offset / distanceToReachEdge);
return TaskView.getCurveScaleForInterpolation(interpolation);
if (mRecentsViewScrollLinked) {
mTaskViewSimulator.setScroll(mRecentsView.getScrollOffset());
}
mTaskViewSimulator.apply(mTransformParams);
}
}
protected PagedOrientationHandler getOrientationHandler() {
if (mOrientedState == null) {
return PagedOrientationHandler.PORTRAIT;
}
return mOrientedState.getOrientationHandler();
return mTaskViewSimulator.getOrientationState().getOrientationHandler();
}
/**
@ -451,104 +476,40 @@ public abstract class BaseSwipeUpHandler<T extends BaseDraggingActivity, Q exten
protected RectFSpringAnim createWindowAnimationToHome(float startProgress,
HomeAnimationFactory homeAnimationFactory) {
final RectF targetRect = homeAnimationFactory.getWindowTargetRect();
final View floatingView = homeAnimationFactory.getFloatingView();
final boolean isFloatingIconView = floatingView instanceof FloatingIconView;
final RectF startRect = new RectF(
mAppWindowAnimationHelper.applyTransform(
mTransformParams.setProgress(startProgress)
.setTargetSet(mRecentsAnimationTargets)
.setLauncherOnTop(false)));
if (isFloatingIconView) {
mOrientedState.mapInverseRectFromNormalOrientation(
startRect, mDp.widthPx, mDp.heightPx);
}
final FloatingIconView fiv = homeAnimationFactory.mIconView;
final boolean isFloatingIconView = fiv != null;
mWindowTransitionController.setPlayFraction(startProgress / mDragLengthFactor);
mTaskViewSimulator.apply(mTransformParams
.setProgress(startProgress)
.setTargetSet(mRecentsAnimationTargets));
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);
windowToHomePositionMap.mapRect(startRect);
RectFSpringAnim anim = new RectFSpringAnim(startRect, targetRect, mContext);
if (isFloatingIconView) {
FloatingIconView fiv = (FloatingIconView) floatingView;
anim.addAnimatorListener(fiv);
fiv.setOnTargetChangeListener(anim::onTargetPositionChanged);
fiv.setFastFinishRunnable(anim::end);
}
AnimatorPlaybackController homeAnim = homeAnimationFactory.createActivityAnimationToHome();
// End on a "round-enough" radius so that the shape reveal doesn't have to do too much
// rounding at the end of the animation.
float startRadius = mAppWindowAnimationHelper.getCurrentCornerRadius();
float endRadius = startRect.width() / 6f;
float startTransformProgress = mTransformParams.getProgress();
float endTransformProgress = 1;
// We want the window alpha to be 0 once this threshold is met, so that the
// FolderIconView can be seen morphing into the icon shape.
final float windowAlphaThreshold = isFloatingIconView ? 1f - SHAPE_PROGRESS_DURATION : 1f;
final RectF rotatedRect = new RectF();
anim.addOnUpdateListener(new RectFSpringAnim.OnUpdateListener() {
@Override
public void onUpdate(RectF currentRect, float progress) {
homeAnim.setPlayFraction(progress);
rotatedRect.set(currentRect);
if (isFloatingIconView) {
mOrientedState.mapRectFromNormalOrientation(
rotatedRect, mDp.widthPx, mDp.heightPx);
mTransformParams.setCornerRadius(endRadius * progress + startRadius
* (1f - progress));
}
mTransformParams.setProgress(
Utilities.mapRange(progress, startTransformProgress, endTransformProgress))
.setCurrentRect(rotatedRect)
.setTargetAlpha(getWindowAlpha(progress));
mAppWindowAnimationHelper.applyTransform(mTransformParams);
if (isFloatingIconView) {
((FloatingIconView) floatingView).update(currentRect, 1f, progress,
windowAlphaThreshold, mAppWindowAnimationHelper.getCurrentCornerRadius(),
false);
}
}
@Override
public void onCancel() {
if (isFloatingIconView) {
((FloatingIconView) floatingView).fastFinish();
}
}
});
anim.addAnimatorListener(new AnimationSuccessListener() {
@Override
public void onAnimationStart(Animator animation) {
homeAnim.dispatchOnStart();
}
@Override
public void onAnimationSuccess(Animator animator) {
homeAnim.getAnimationPlayer().end();
}
});
SpringAnimationRunner runner = new SpringAnimationRunner(
homeAnimationFactory, cropRectF, homeToWindowPositionMap);
anim.addOnUpdateListener(runner);
anim.addAnimatorListener(runner);
return anim;
}
/**
* @param progress The progress of the animation to the home screen.
* @return The current alpha to set on the animating app window.
*/
protected float getWindowAlpha(float progress) {
// Alpha interpolates between [1, 0] between progress values [start, end]
final float start = 0f;
final float end = 0.85f;
if (progress <= start) {
return 1f;
}
if (progress >= end) {
return 0f;
}
return Utilities.mapToRange(progress, start, end, 1, 0, ACCEL_1_5);
}
public interface Factory {
BaseSwipeUpHandler newHandler(GestureState gestureState, long touchTimeMs,
@ -588,4 +549,135 @@ public abstract class BaseSwipeUpHandler<T extends BaseDraggingActivity, Q exten
};
}
}
/**
* @param progress The progress of the animation to the home screen.
* @return The current alpha to set on the animating app window.
*/
protected float getWindowAlpha(float progress) {
// Alpha interpolates between [1, 0] between progress values [start, end]
final float start = 0f;
final float end = 0.85f;
if (progress <= start) {
return 1f;
}
if (progress >= end) {
return 0f;
}
return Utilities.mapToRange(progress, start, end, 1, 0, ACCEL_1_5);
}
protected abstract class HomeAnimationFactory {
private FloatingIconView mIconView;
public HomeAnimationFactory(@Nullable FloatingIconView iconView) {
mIconView = iconView;
}
public @NonNull RectF getWindowTargetRect() {
PagedOrientationHandler orientationHandler = getOrientationHandler();
DeviceProfile dp = mDp;
final int halfIconSize = dp.iconSizePx / 2;
float primaryDimension = orientationHandler
.getPrimaryValue(dp.availableWidthPx, dp.availableHeightPx);
float secondaryDimension = orientationHandler
.getSecondaryValue(dp.availableWidthPx, dp.availableHeightPx);
final float targetX = primaryDimension / 2f;
final float targetY = secondaryDimension - dp.hotseatBarSizePx;
// Fallback to animate to center of screen.
return new RectF(targetX - halfIconSize, targetY - halfIconSize,
targetX + halfIconSize, targetY + halfIconSize);
}
public abstract @NonNull AnimatorPlaybackController createActivityAnimationToHome();
public void playAtomicAnimation(float velocity) {
// No-op
}
}
private class SpringAnimationRunner extends AnimationSuccessListener
implements RectFSpringAnim.OnUpdateListener, BuilderProxy {
final Rect mCropRect = new Rect();
final Matrix mMatrix = new Matrix();
final RectF mWindowCurrentRect = new RectF();
final Matrix mHomeToWindowPositionMap;
final FloatingIconView mFIV;
final AnimatorPlaybackController mHomeAnim;
final RectF mCropRectF;
final float mStartRadius;
final float mEndRadius;
final float mWindowAlphaThreshold;
SpringAnimationRunner(HomeAnimationFactory factory, RectF cropRectF,
Matrix homeToWindowPositionMap) {
mHomeAnim = factory.createActivityAnimationToHome();
mCropRectF = cropRectF;
mHomeToWindowPositionMap = homeToWindowPositionMap;
cropRectF.roundOut(mCropRect);
mFIV = factory.mIconView;
// End on a "round-enough" radius so that the shape reveal doesn't have to do too much
// rounding at the end of the animation.
mStartRadius = mTaskViewSimulator.getCurrentCornerRadius();
mEndRadius = cropRectF.width() / 2f;
// We want the window alpha to be 0 once this threshold is met, so that the
// FolderIconView can be seen morphing into the icon shape.
mWindowAlphaThreshold = mFIV != null ? 1f - SHAPE_PROGRESS_DURATION : 1f;
}
@Override
public void onUpdate(RectF currentRect, float progress) {
mHomeAnim.setPlayFraction(progress);
mHomeToWindowPositionMap.mapRect(mWindowCurrentRect, currentRect);
mMatrix.setRectToRect(mCropRectF, mWindowCurrentRect, ScaleToFit.FILL);
float cornerRadius = Utilities.mapRange(progress, mStartRadius, mEndRadius);
mTransformParams
.setTargetAlpha(getWindowAlpha(progress))
.setCornerRadius(cornerRadius);
mTransformParams.applySurfaceParams(mTransformParams.createSurfaceParams(this));
if (mFIV != null) {
mFIV.update(currentRect, 1f, progress,
mWindowAlphaThreshold, mMatrix.mapRadius(cornerRadius), false);
}
}
@Override
public void onBuildParams(Builder builder, RemoteAnimationTargetCompat app, int targetMode,
TransformParams params) {
if (app.mode == targetMode
&& app.activityType != RemoteAnimationTargetCompat.ACTIVITY_TYPE_HOME) {
builder.withMatrix(mMatrix)
.withWindowCrop(mCropRect)
.withCornerRadius(params.getCornerRadius());
}
}
@Override
public void onCancel() {
if (mFIV != null) {
mFIV.fastFinish();
}
}
@Override
public void onAnimationStart(Animator animation) {
mHomeAnim.dispatchOnStart();
}
@Override
public void onAnimationSuccess(Animator animator) {
mHomeAnim.getAnimationPlayer().end();
}
}
}

View File

@ -15,25 +15,23 @@
*/
package com.android.quickstep;
import static com.android.launcher3.LauncherAnimUtils.SCALE_PROPERTY;
import static com.android.launcher3.anim.Interpolators.LINEAR;
import static com.android.quickstep.SysUINavigationMode.Mode.NO_BUTTON;
import static com.android.quickstep.fallback.FallbackRecentsView.ZOOM_PROGRESS;
import static com.android.quickstep.fallback.RecentsState.BACKGROUND_APP;
import static com.android.quickstep.fallback.RecentsState.DEFAULT;
import static com.android.quickstep.util.WindowSizeStrategy.FALLBACK_RECENTS_SIZE_STRATEGY;
import static com.android.quickstep.views.RecentsView.CONTENT_ALPHA;
import static com.android.quickstep.views.RecentsView.FULLSCREEN_PROGRESS;
import android.animation.Animator;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.content.Context;
import android.graphics.Rect;
import android.graphics.RectF;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.anim.AnimationSuccessListener;
import com.android.launcher3.anim.AnimatorPlaybackController;
import com.android.launcher3.anim.PendingAnimation;
import com.android.launcher3.userevent.nano.LauncherLogProto;
import com.android.quickstep.fallback.FallbackRecentsView;
import com.android.quickstep.util.ActivityInitListener;
@ -89,54 +87,17 @@ public final class FallbackActivityInterface implements
// set to zero prior to this class becoming active.
}
@NonNull
@Override
public HomeAnimationFactory prepareHomeUI() {
public AnimationFactory prepareRecentsUI(
boolean activityVisible, Consumer<AnimatorPlaybackController> callback) {
RecentsActivity activity = getCreatedActivity();
RecentsView recentsView = activity.getOverviewPanel();
return new HomeAnimationFactory() {
@NonNull
@Override
public RectF getWindowTargetRect() {
float centerX = recentsView.getPivotX();
float centerY = recentsView.getPivotY();
return new RectF(centerX, centerY, centerX, centerY);
}
@NonNull
@Override
public AnimatorPlaybackController createActivityAnimationToHome() {
Animator anim = ObjectAnimator.ofFloat(recentsView, CONTENT_ALPHA, 0);
anim.addListener(new AnimationSuccessListener() {
@Override
public void onAnimationSuccess(Animator animator) {
recentsView.startHome();
}
});
AnimatorSet animatorSet = new AnimatorSet();
animatorSet.play(anim);
long accuracy = 2 * Math.max(recentsView.getWidth(), recentsView.getHeight());
return AnimatorPlaybackController.wrap(animatorSet, accuracy);
}
};
}
@Override
public AnimationFactory prepareRecentsUI(boolean activityVisible,
boolean animateActivity, Consumer<AnimatorPlaybackController> callback) {
RecentsActivity activity = getCreatedActivity();
if (activityVisible) {
if (activity == null) {
return (transitionLength) -> { };
}
activity.getStateManager().goToState(BACKGROUND_APP);
FallbackRecentsView rv = activity.getOverviewPanel();
rv.setContentAlpha(0);
rv.getClearAllButton().setVisibilityAlpha(0);
rv.setDisallowScrollToClearAll(true);
boolean fromState = !animateActivity;
rv.setInOverviewState(fromState);
return new AnimationFactory() {
@ -154,27 +115,19 @@ public final class FallbackActivityInterface implements
@Override
public void createActivityInterface(long transitionLength) {
AnimatorSet animatorSet = new AnimatorSet();
PendingAnimation pa = new PendingAnimation(transitionLength * 2);
if (isAnimatingToRecents) {
ObjectAnimator anim = ObjectAnimator.ofFloat(rv, CONTENT_ALPHA, 0, 1);
anim.setDuration(transitionLength).setInterpolator(LINEAR);
animatorSet.play(anim);
pa.addFloat(rv, CONTENT_ALPHA, 0, 1, LINEAR);
}
ObjectAnimator anim = ObjectAnimator.ofFloat(rv, ZOOM_PROGRESS, 1, 0);
anim.setDuration(transitionLength).setInterpolator(LINEAR);
animatorSet.play(anim);
AnimatorPlaybackController controller =
AnimatorPlaybackController.wrap(animatorSet, transitionLength);
pa.addFloat(rv, SCALE_PROPERTY, rv.getMaxScaleForFullScreen(), 1, LINEAR);
pa.addFloat(rv, FULLSCREEN_PROGRESS, 1, 0, LINEAR);
AnimatorPlaybackController controller = pa.createPlaybackController();
// Since we are changing the start position of the UI, reapply the state, at the end
controller.setEndAction(() -> {
boolean endState = true;
rv.setInOverviewState(controller.getInterpolatedProgress() > 0.5 ?
endState : fromState);
});
controller.setEndAction(() -> activity.getStateManager().goToState(
controller.getInterpolatedProgress() > 0.5 ? DEFAULT : BACKGROUND_APP));
callback.accept(controller);
}
};
@ -190,7 +143,7 @@ public final class FallbackActivityInterface implements
@Nullable
@Override
public RecentsActivity getCreatedActivity() {
return BaseRecentsActivity.ACTIVITY_TRACKER.getCreatedActivity();
return RecentsActivity.ACTIVITY_TRACKER.getCreatedActivity();
}
@Nullable

View File

@ -24,6 +24,7 @@ import static com.android.quickstep.GestureState.GestureEndTarget.RECENTS;
import static com.android.quickstep.MultiStateCallback.DEBUG_STATES;
import static com.android.quickstep.RecentsActivity.EXTRA_TASK_ID;
import static com.android.quickstep.RecentsActivity.EXTRA_THUMBNAIL;
import static com.android.quickstep.util.WindowSizeStrategy.FALLBACK_RECENTS_SIZE_STRATEGY;
import static com.android.quickstep.views.RecentsView.UPDATE_SYSUI_FLAGS_THRESHOLD;
import android.animation.Animator;
@ -32,25 +33,24 @@ import android.app.ActivityOptions;
import android.content.Context;
import android.content.Intent;
import android.graphics.PointF;
import android.graphics.RectF;
import android.os.Bundle;
import android.util.ArrayMap;
import android.view.MotionEvent;
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.R;
import com.android.launcher3.anim.AnimationSuccessListener;
import com.android.launcher3.anim.AnimatorPlaybackController;
import com.android.launcher3.touch.PagedOrientationHandler;
import com.android.launcher3.util.ObjectWrapper;
import com.android.quickstep.BaseActivityInterface.HomeAnimationFactory;
import com.android.quickstep.BaseActivityInterface.AnimationFactory;
import com.android.quickstep.GestureState.GestureEndTarget;
import com.android.quickstep.fallback.FallbackRecentsView;
import com.android.quickstep.util.RectFSpringAnim;
import com.android.quickstep.views.TaskView;
import com.android.systemui.shared.recents.model.ThumbnailData;
import com.android.systemui.shared.system.ActivityManagerWrapper;
import com.android.systemui.shared.system.ActivityOptionsCompat;
import com.android.systemui.shared.system.InputConsumerController;
import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
/**
* Handles the navigation gestures when a 3rd party launcher is the default home activity.
@ -105,10 +105,16 @@ public class FallbackSwipeHandler extends BaseSwipeUpHandler<RecentsActivity, Fa
private final PointF mEndVelocityPxPerMs = new PointF(0, 0.5f);
private RunningWindowAnim mFinishAnimation;
// Used to control Recents components throughout the swipe gesture.
private AnimatorPlaybackController mLauncherTransitionController;
private boolean mHasLauncherTransitionControllerStarted;
private AnimationFactory mAnimationFactory = (t) -> { };
public FallbackSwipeHandler(Context context, RecentsAnimationDeviceState deviceState,
GestureState gestureState, InputConsumerController inputConsumer,
boolean isLikelyToStartNewTask, boolean continuingLastGesture) {
super(context, deviceState, gestureState, inputConsumer);
super(context, deviceState, gestureState, inputConsumer, FALLBACK_RECENTS_SIZE_STRATEGY);
mInQuickSwitchMode = isLikelyToStartNewTask || continuingLastGesture;
mContinuingLastGesture = continuingLastGesture;
@ -118,9 +124,9 @@ public class FallbackSwipeHandler extends BaseSwipeUpHandler<RecentsActivity, Fa
// Keep the home launcher invisible until we decide to land there.
mLauncherAlpha.value = mRunningOverHome ? 1 : 0;
if (mSwipeUpOverHome) {
mAppWindowAnimationHelper.setBaseAlphaCallback((t, a) -> 1 - mLauncherAlpha.value);
mTransformParams.setBaseAlphaCallback((t, a) -> 1 - mLauncherAlpha.value);
} else {
mAppWindowAnimationHelper.setBaseAlphaCallback((t, a) -> mLauncherAlpha.value);
mTransformParams.setBaseAlphaCallback((t, a) -> mLauncherAlpha.value);
}
// Going home has an extra long progress to ensure that it animates into the screen
@ -156,7 +162,7 @@ public class FallbackSwipeHandler extends BaseSwipeUpHandler<RecentsActivity, Fa
private void onLauncherAlphaChanged() {
if (mRecentsAnimationTargets != null && mGestureState.getEndTarget() == null) {
applyTransformUnchecked();
applyWindowTransform();
}
}
@ -167,10 +173,6 @@ public class FallbackSwipeHandler extends BaseSwipeUpHandler<RecentsActivity, Fa
mRecentsView = mActivity.getOverviewPanel();
mRecentsView.setOnPageTransitionEndCallback(null);
linkRecentsViewScroll();
mRecentsView.setDisallowScrollToClearAll(true);
mRecentsView.getClearAllButton().setVisibilityAlpha(0);
mRecentsView.setZoomProgress(1);
if (!mContinuingLastGesture) {
if (mRunningOverHome) {
mRecentsView.onGestureAnimationStart(mGestureState.getRunningTask());
@ -180,9 +182,48 @@ public class FallbackSwipeHandler extends BaseSwipeUpHandler<RecentsActivity, Fa
}
mStateCallback.setStateOnUiThread(STATE_RECENTS_PRESENT);
mDeviceState.enableMultipleRegions(false);
mAnimationFactory = mActivityInterface.prepareRecentsUI(alreadyOnHome,
this::onAnimatorPlaybackControllerCreated);
mAnimationFactory.createActivityInterface(mTransitionDragLength);
return true;
}
@Override
protected void initTransitionEndpoints(DeviceProfile dp) {
super.initTransitionEndpoints(dp);
if (canCreateNewOrUpdateExistingLauncherTransitionController()) {
mAnimationFactory.createActivityInterface(mTransitionDragLength);
}
}
private void onAnimatorPlaybackControllerCreated(AnimatorPlaybackController anim) {
mLauncherTransitionController = anim;
mLauncherTransitionController.dispatchSetInterpolator(t -> t * mDragLengthFactor);
mLauncherTransitionController.dispatchOnStart();
updateLauncherTransitionProgress();
}
private void updateLauncherTransitionProgress() {
if (mLauncherTransitionController == null
|| !canCreateNewOrUpdateExistingLauncherTransitionController()) {
return;
}
// Normalize the progress to 0 to 1, as the animation controller will clamp it to that
// anyway. The controller mimics the drag length factor by applying it to its interpolators.
float progress = mCurrentShift.value / mDragLengthFactor;
mLauncherTransitionController.setPlayFraction(progress);
}
/**
* We don't want to change mLauncherTransitionController if mGestureState.getEndTarget() == HOME
* (it has its own animation) or if we're already animating the current controller.
* @return Whether we can create the launcher controller or update its progress.
*/
private boolean canCreateNewOrUpdateExistingLauncherTransitionController() {
return mGestureState.getEndTarget() != HOME && !mHasLauncherTransitionControllerStarted;
}
@Override
protected boolean moveWindowWithRecentsScroll() {
return mInQuickSwitchMode;
@ -261,9 +302,8 @@ public class FallbackSwipeHandler extends BaseSwipeUpHandler<RecentsActivity, Fa
updateOverviewThresholdPassed(mCurrentShift.value >= MIN_PROGRESS_FOR_OVERVIEW);
}
if (mRecentsAnimationTargets != null) {
applyTransformUnchecked();
}
applyWindowTransform();
updateLauncherTransitionProgress();
}
@Override
@ -320,15 +360,6 @@ public class FallbackSwipeHandler extends BaseSwipeUpHandler<RecentsActivity, Fa
}
if (mRecentsView != null) {
if (mFinishingRecentsAnimationForNewTaskId != -1) {
TaskView newRunningTaskView = mRecentsView.getTaskView(
mFinishingRecentsAnimationForNewTaskId);
int newRunningTaskId = newRunningTaskView != null
? newRunningTaskView.getTask().key.id
: -1;
mRecentsView.setCurrentTask(newRunningTaskId);
mGestureState.setFinishingRecentsAnimationTaskId(newRunningTaskId);
}
mRecentsView.setOnScrollChangeListener(null);
}
} else {
@ -401,7 +432,7 @@ public class FallbackSwipeHandler extends BaseSwipeUpHandler<RecentsActivity, Fa
break;
}
case NEW_TASK: {
startNewTask(STATE_HANDLER_INVALIDATED, b -> {});
startNewTask(success -> { });
break;
}
}
@ -416,7 +447,7 @@ public class FallbackSwipeHandler extends BaseSwipeUpHandler<RecentsActivity, Fa
if (mRecentsView == null || !hasTargets()) {
mGestureState.setEndTarget(LAST_TASK);
} else {
final int runningTaskIndex = mRecentsView.getRunningTaskIndex();
final int runningTaskIndex = getLastAppearedTaskIndex();
final int taskToLaunch = mRecentsView.getNextPage();
mGestureState.setEndTarget(
(runningTaskIndex >= 0 && taskToLaunch != runningTaskIndex)
@ -477,11 +508,7 @@ public class FallbackSwipeHandler extends BaseSwipeUpHandler<RecentsActivity, Fa
RecentsAnimationTargets targets) {
super.onRecentsAnimationStart(controller, targets);
mRecentsAnimationController.enableInputConsumer();
if (mRunningOverHome) {
mAppWindowAnimationHelper.prepareAnimation(mDp);
}
applyTransformUnchecked();
applyWindowTransform();
mStateCallback.setStateOnUiThread(STATE_APP_CONTROLLER_RECEIVED);
}
@ -494,23 +521,17 @@ public class FallbackSwipeHandler extends BaseSwipeUpHandler<RecentsActivity, Fa
super.onRecentsAnimationCanceled(thumbnailData);
}
@Override
protected boolean handleTaskAppeared(RemoteAnimationTargetCompat appearedTaskTarget) {
return true;
}
/**
* 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.
*/
private RectFSpringAnim createWindowAnimationToHome(float startProgress, long duration) {
HomeAnimationFactory factory = new HomeAnimationFactory() {
@Override
public RectF getWindowTargetRect() {
PagedOrientationHandler orientationHandler = mRecentsView != null
? mRecentsView.getPagedOrientationHandler()
: (mDp.isLandscape
? PagedOrientationHandler.LANDSCAPE
: PagedOrientationHandler.PORTRAIT);
return HomeAnimationFactory
.getDefaultWindowTargetRect(orientationHandler, mDp);
}
HomeAnimationFactory factory = new HomeAnimationFactory(null) {
@Override
public AnimatorPlaybackController createActivityAnimationToHome() {
AnimatorSet anim = new AnimatorSet();

View File

@ -16,32 +16,26 @@
package com.android.quickstep;
import static com.android.launcher3.LauncherAnimUtils.SCALE_PROPERTY;
import static com.android.launcher3.LauncherAppTransitionManagerImpl.INDEX_RECENTS_FADE_ANIM;
import static com.android.launcher3.LauncherAppTransitionManagerImpl.INDEX_RECENTS_TRANSLATE_X_ANIM;
import static com.android.launcher3.LauncherAppTransitionManagerImpl.INDEX_SHELF_ANIM;
import static com.android.launcher3.LauncherState.BACKGROUND_APP;
import static com.android.launcher3.LauncherState.NORMAL;
import static com.android.launcher3.LauncherState.OVERVIEW;
import static com.android.launcher3.anim.Interpolators.ACCEL_2;
import static com.android.launcher3.anim.Interpolators.INSTANT;
import static com.android.launcher3.anim.Interpolators.LINEAR;
import static com.android.launcher3.uioverrides.states.QuickstepAtomicAnimationFactory.INDEX_RECENTS_FADE_ANIM;
import static com.android.launcher3.uioverrides.states.QuickstepAtomicAnimationFactory.INDEX_RECENTS_TRANSLATE_X_ANIM;
import static com.android.launcher3.uioverrides.states.QuickstepAtomicAnimationFactory.INDEX_SHELF_ANIM;
import static com.android.quickstep.LauncherSwipeHandler.RECENTS_ATTACH_DURATION;
import static com.android.quickstep.util.WindowSizeStrategy.LAUNCHER_ACTIVITY_SIZE_STRATEGY;
import static com.android.quickstep.views.RecentsView.ADJACENT_PAGE_OFFSET;
import static com.android.quickstep.views.RecentsView.FULLSCREEN_PROGRESS;
import android.animation.Animator;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.content.Context;
import android.graphics.Rect;
import android.graphics.RectF;
import android.os.UserHandle;
import android.util.Pair;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.animation.Interpolator;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.UiThread;
@ -52,20 +46,19 @@ import com.android.launcher3.LauncherInitListener;
import com.android.launcher3.LauncherState;
import com.android.launcher3.allapps.DiscoveryBounce;
import com.android.launcher3.anim.AnimatorPlaybackController;
import com.android.launcher3.anim.PendingAnimation;
import com.android.launcher3.appprediction.PredictionUiStateManager;
import com.android.launcher3.statehandlers.DepthController;
import com.android.launcher3.statehandlers.DepthController.ClampedDepthProperty;
import com.android.launcher3.testing.TestProtocol;
import com.android.launcher3.userevent.nano.LauncherLogProto;
import com.android.launcher3.views.FloatingIconView;
import com.android.quickstep.SysUINavigationMode.Mode;
import com.android.quickstep.util.ActivityInitListener;
import com.android.quickstep.util.LayoutUtils;
import com.android.quickstep.util.ShelfPeekAnim;
import com.android.quickstep.util.ShelfPeekAnim.ShelfAnimState;
import com.android.quickstep.util.StaggeredWorkspaceAnim;
import com.android.quickstep.views.LauncherRecentsView;
import com.android.quickstep.views.RecentsView;
import com.android.quickstep.views.TaskView;
import com.android.systemui.plugins.shared.LauncherOverlayManager;
import com.android.systemui.shared.recents.model.ThumbnailData;
import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
@ -78,9 +71,6 @@ import java.util.function.Predicate;
*/
public final class LauncherActivityInterface implements BaseActivityInterface<Launcher> {
private Pair<Float, Float> mSwipeUpPullbackStartAndMaxProgress =
BaseActivityInterface.super.getSwipeUpPullbackStartAndMaxProgress();
@Override
public int getSwipeUpDestinationAndLength(DeviceProfile dp, Context context, Rect outRect) {
LAUNCHER_ACTIVITY_SIZE_STRATEGY.calculateTaskSize(context, dp, outRect);
@ -93,11 +83,6 @@ public final class LauncherActivityInterface implements BaseActivityInterface<La
}
}
@Override
public Pair<Float, Float> getSwipeUpPullbackStartAndMaxProgress() {
return mSwipeUpPullbackStartAndMaxProgress;
}
@Override
public void onTransitionCancelled(boolean activityVisible) {
Launcher launcher = getCreatedActivity();
@ -148,66 +133,9 @@ public final class LauncherActivityInterface implements BaseActivityInterface<La
launcher.onAssistantVisibilityChanged(visibility);
}
@NonNull
@Override
public HomeAnimationFactory prepareHomeUI() {
Launcher launcher = getCreatedActivity();
final DeviceProfile dp = launcher.getDeviceProfile();
final RecentsView recentsView = launcher.getOverviewPanel();
final TaskView runningTaskView = recentsView.getRunningTaskView();
final View workspaceView;
if (runningTaskView != null && runningTaskView.getTask().key.getComponent() != null) {
workspaceView = launcher.getWorkspace().getFirstMatchForAppClose(
runningTaskView.getTask().key.getComponent().getPackageName(),
UserHandle.of(runningTaskView.getTask().key.userId));
} else {
workspaceView = null;
}
final RectF iconLocation = new RectF();
boolean canUseWorkspaceView = workspaceView != null && workspaceView.isAttachedToWindow();
FloatingIconView floatingIconView = canUseWorkspaceView
? FloatingIconView.getFloatingIconView(launcher, workspaceView,
true /* hideOriginal */, iconLocation, false /* isOpening */)
: null;
setLauncherHideBackArrow(true);
return new HomeAnimationFactory() {
@Nullable
@Override
public View getFloatingView() {
return floatingIconView;
}
@NonNull
@Override
public RectF getWindowTargetRect() {
if (canUseWorkspaceView) {
return iconLocation;
} else {
return HomeAnimationFactory
.getDefaultWindowTargetRect(recentsView.getPagedOrientationHandler(), dp);
}
}
@NonNull
@Override
public AnimatorPlaybackController createActivityAnimationToHome() {
// Return an empty APC here since we have an non-user controlled animation to home.
long accuracy = 2 * Math.max(dp.widthPx, dp.heightPx);
return launcher.getStateManager().createAnimationToNewWorkspace(NORMAL, accuracy,
0 /* animComponents */);
}
@Override
public void playAtomicAnimation(float velocity) {
new StaggeredWorkspaceAnim(launcher, velocity, true /* animateOverviewScrim */)
.start();
}
};
}
@Override
public AnimationFactory prepareRecentsUI(boolean activityVisible,
boolean animateActivity, Consumer<AnimatorPlaybackController> callback) {
public AnimationFactory prepareRecentsUI(
boolean activityVisible, Consumer<AnimatorPlaybackController> callback) {
BaseQuickstepLauncher launcher = getCreatedActivity();
final LauncherState startState = launcher.getStateManager().getState();
@ -217,8 +145,7 @@ public final class LauncherActivityInterface implements BaseActivityInterface<La
}
launcher.getStateManager().setRestState(resetState);
final LauncherState fromState = animateActivity ? BACKGROUND_APP : OVERVIEW;
launcher.getStateManager().goToState(fromState, false);
launcher.getStateManager().goToState(BACKGROUND_APP, false);
// Since all apps is not visible, we can safely reset the scroll position.
// This ensures then the next swipe up to all-apps starts from scroll 0.
launcher.getAppsView().reset(false /* animate */);
@ -229,7 +156,7 @@ public final class LauncherActivityInterface implements BaseActivityInterface<La
@Override
public void createActivityInterface(long transitionLength) {
createActivityInterfaceInternal(launcher, fromState, transitionLength, callback);
callback.accept(createBackgroundToOverviewAnim(launcher, transitionLength));
// Creating the activity controller animation sometimes reapplies the launcher state
// (because we set the animation as the current state animation), so we reapply the
// attached state here as well to ensure recents is shown/hidden appropriately.
@ -283,74 +210,45 @@ public final class LauncherActivityInterface implements BaseActivityInterface<La
};
}
private void createActivityInterfaceInternal(Launcher activity, LauncherState fromState,
long transitionLength, Consumer<AnimatorPlaybackController> callback) {
LauncherState endState = OVERVIEW;
if (fromState == endState) {
return;
}
private AnimatorPlaybackController createBackgroundToOverviewAnim(
Launcher activity, long transitionLength) {
PendingAnimation pa = new PendingAnimation(transitionLength * 2);
AnimatorSet anim = new AnimatorSet();
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.
anim.play(activity.getStateManager().createStateElementAnimation(
pa.add(activity.getStateManager().createStateElementAnimation(
INDEX_SHELF_ANIM,
fromState.getVerticalProgress(activity),
endState.getVerticalProgress(activity)));
BACKGROUND_APP.getVerticalProgress(activity),
OVERVIEW.getVerticalProgress(activity)));
}
// Animate the blur and wallpaper zoom
DepthController depthController = getDepthController();
float fromDepthRatio = fromState.getDepth(activity);
float toDepthRatio = endState.getDepth(activity);
Animator depthAnimator = ObjectAnimator.ofFloat(depthController,
new ClampedDepthProperty(fromDepthRatio, toDepthRatio),
fromDepthRatio, toDepthRatio);
anim.play(depthAnimator);
float fromDepthRatio = BACKGROUND_APP.getDepth(activity);
float toDepthRatio = OVERVIEW.getDepth(activity);
pa.addFloat(getDepthController(), new ClampedDepthProperty(fromDepthRatio, toDepthRatio),
fromDepthRatio, toDepthRatio, LINEAR);
playScaleDownAnim(anim, activity, fromState, endState);
anim.setDuration(transitionLength * 2);
anim.setInterpolator(LINEAR);
AnimatorPlaybackController controller =
AnimatorPlaybackController.wrap(anim, transitionLength * 2);
// Scale down recents from being full screen to being in overview.
RecentsView recentsView = activity.getOverviewPanel();
pa.addFloat(recentsView, SCALE_PROPERTY,
BACKGROUND_APP.getOverviewScaleAndOffset(activity)[0],
OVERVIEW.getOverviewScaleAndOffset(activity)[0],
LINEAR);
pa.addFloat(recentsView, FULLSCREEN_PROGRESS,
BACKGROUND_APP.getOverviewFullscreenProgress(),
OVERVIEW.getOverviewFullscreenProgress(),
LINEAR);
AnimatorPlaybackController controller = pa.createPlaybackController();
activity.getStateManager().setCurrentUserControlledAnimation(controller);
// Since we are changing the start position of the UI, reapply the state, at the end
controller.setEndAction(() -> {
activity.getStateManager().goToState(
controller.getInterpolatedProgress() > 0.5 ? endState : fromState, false);
});
callback.accept(controller);
}
/**
* Scale down recents from the center task being full screen to being in overview.
*/
private void playScaleDownAnim(AnimatorSet anim, Launcher launcher, LauncherState fromState,
LauncherState endState) {
RecentsView recentsView = launcher.getOverviewPanel();
if (recentsView.getCurrentPageTaskView() == null) {
return;
}
float fromFullscreenProgress = fromState.getOverviewFullscreenProgress();
float endFullscreenProgress = endState.getOverviewFullscreenProgress();
float fromScale = fromState.getOverviewScaleAndOffset(launcher)[0];
float endScale = endState.getOverviewScaleAndOffset(launcher)[0];
Animator scale = ObjectAnimator.ofFloat(recentsView, SCALE_PROPERTY, fromScale, endScale);
Animator applyFullscreenProgress = ObjectAnimator.ofFloat(recentsView,
RecentsView.FULLSCREEN_PROGRESS, fromFullscreenProgress, endFullscreenProgress);
anim.playTogether(scale, applyFullscreenProgress);
// Start pulling back when RecentsView scale is 0.75f, and let it go down to 0.5f.
float pullbackStartProgress = (0.75f - fromScale) / (endScale - fromScale);
float pullbackMaxProgress = (0.5f - fromScale) / (endScale - fromScale);
mSwipeUpPullbackStartAndMaxProgress = new Pair<>(
pullbackStartProgress, pullbackMaxProgress);
controller.setEndAction(() -> activity.getStateManager().goToState(
controller.getInterpolatedProgress() > 0.5 ? OVERVIEW : BACKGROUND_APP, false));
return controller;
}
@Override
@ -383,6 +281,9 @@ public final class LauncherActivityInterface implements BaseActivityInterface<La
@Override
public boolean switchToRecentsIfVisible(Runnable onCompleteCallback) {
if (TestProtocol.sDebugTracing) {
Log.d(TestProtocol.OVERIEW_NOT_ALLAPPS, "switchToRecentsIfVisible");
}
Launcher launcher = getVisibleLauncher();
if (launcher == null) {
return false;

View File

@ -17,8 +17,7 @@ package com.android.quickstep;
import static com.android.launcher3.BaseActivity.INVISIBLE_BY_STATE_HANDLER;
import static com.android.launcher3.BaseActivity.STATE_HANDLER_INVISIBILITY_FLAGS;
import static com.android.launcher3.LauncherState.BACKGROUND_APP;
import static com.android.launcher3.LauncherState.OVERVIEW;
import static com.android.launcher3.LauncherState.NORMAL;
import static com.android.launcher3.anim.Interpolators.DEACCEL;
import static com.android.launcher3.anim.Interpolators.LINEAR;
import static com.android.launcher3.anim.Interpolators.OVERSHOOT_1_2;
@ -32,7 +31,6 @@ import static com.android.quickstep.GestureState.GestureEndTarget.NEW_TASK;
import static com.android.quickstep.GestureState.GestureEndTarget.RECENTS;
import static com.android.quickstep.GestureState.STATE_END_TARGET_ANIMATION_FINISHED;
import static com.android.quickstep.GestureState.STATE_RECENTS_SCROLLING_FINISHED;
import static com.android.quickstep.GestureState.STATE_TASK_APPEARED_DURING_SWITCH;
import static com.android.quickstep.MultiStateCallback.DEBUG_STATES;
import static com.android.quickstep.SysUINavigationMode.Mode.TWO_BUTTONS;
import static com.android.quickstep.util.ShelfPeekAnim.ShelfAnimState.HIDE;
@ -42,17 +40,16 @@ import static com.android.quickstep.views.RecentsView.UPDATE_SYSUI_FLAGS_THRESHO
import android.animation.Animator;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.animation.TimeInterpolator;
import android.animation.ValueAnimator;
import android.annotation.TargetApi;
import android.content.Context;
import android.content.Intent;
import android.graphics.PointF;
import android.graphics.Rect;
import android.graphics.RectF;
import android.os.Build;
import android.os.SystemClock;
import android.os.UserHandle;
import android.view.View;
import android.view.View.OnApplyWindowInsetsListener;
import android.view.ViewTreeObserver.OnDrawListener;
@ -65,6 +62,7 @@ import androidx.annotation.UiThread;
import com.android.launcher3.AbstractFloatingView;
import com.android.launcher3.BaseDraggingActivity;
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.Launcher;
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
import com.android.launcher3.anim.AnimationSuccessListener;
@ -75,16 +73,16 @@ import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Direction;
import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Touch;
import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType;
import com.android.launcher3.util.TraceHelper;
import com.android.launcher3.views.FloatingIconView;
import com.android.quickstep.BaseActivityInterface.AnimationFactory;
import com.android.quickstep.BaseActivityInterface.HomeAnimationFactory;
import com.android.quickstep.GestureState.GestureEndTarget;
import com.android.quickstep.inputconsumers.OverviewInputConsumer;
import com.android.quickstep.util.ActiveGestureLog;
import com.android.quickstep.util.AppWindowAnimationHelper.TargetAlphaProvider;
import com.android.quickstep.util.RectFSpringAnim;
import com.android.quickstep.util.ShelfPeekAnim;
import com.android.quickstep.util.ShelfPeekAnim.ShelfAnimState;
import com.android.quickstep.util.TaskViewSimulator;
import com.android.quickstep.util.StaggeredWorkspaceAnim;
import com.android.quickstep.util.TransformParams.TargetAlphaProvider;
import com.android.quickstep.views.LiveTileOverlay;
import com.android.quickstep.views.RecentsView;
import com.android.quickstep.views.TaskView;
@ -97,8 +95,8 @@ import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
* Handles the navigation gestures when Launcher is the default home activity.
*/
@TargetApi(Build.VERSION_CODES.O)
public class LauncherSwipeHandler<T extends BaseDraggingActivity>
extends BaseSwipeUpHandler<T, RecentsView> implements OnApplyWindowInsetsListener {
public class LauncherSwipeHandler extends BaseSwipeUpHandler<Launcher, RecentsView>
implements OnApplyWindowInsetsListener {
private static final String TAG = LauncherSwipeHandler.class.getSimpleName();
private static final String[] STATE_NAMES = DEBUG_STATES ? new String[16] : null;
@ -152,7 +150,6 @@ public class LauncherSwipeHandler<T extends BaseDraggingActivity>
STATE_LAUNCHER_PRESENT | STATE_LAUNCHER_DRAWN | STATE_LAUNCHER_STARTED;
public static final long MAX_SWIPE_DURATION = 350;
public static final long MIN_SWIPE_DURATION = 80;
public static final long MIN_OVERSHOOT_DURATION = 120;
public static final float MIN_PROGRESS_FOR_OVERVIEW = 0.7f;
@ -181,9 +178,6 @@ public class LauncherSwipeHandler<T extends BaseDraggingActivity>
private AnimatorPlaybackController mLauncherTransitionController;
private boolean mHasLauncherTransitionControllerStarted;
private final TaskViewSimulator mTaskViewSimulator;
private AnimatorPlaybackController mWindowTransitionController;
private AnimationFactory mAnimationFactory = (t) -> { };
private boolean mWasLauncherAlreadyVisible;
@ -204,11 +198,10 @@ public class LauncherSwipeHandler<T extends BaseDraggingActivity>
TaskAnimationManager taskAnimationManager, GestureState gestureState,
long touchTimeMs, boolean continuingLastGesture,
InputConsumerController inputConsumer) {
super(context, deviceState, gestureState, inputConsumer);
super(context, deviceState, gestureState, inputConsumer, LAUNCHER_ACTIVITY_SIZE_STRATEGY);
mTaskAnimationManager = taskAnimationManager;
mTouchTimeMs = touchTimeMs;
mContinuingLastGesture = continuingLastGesture;
mTaskViewSimulator = new TaskViewSimulator(context, LAUNCHER_ACTIVITY_SIZE_STRATEGY);
initAfterSubclassConstructor();
initStateCallbacks();
@ -264,8 +257,6 @@ public class LauncherSwipeHandler<T extends BaseDraggingActivity>
| STATE_RECENTS_SCROLLING_FINISHED,
this::onSettledOnEndTarget);
mGestureState.runOnceAtState(STATE_TASK_APPEARED_DURING_SWITCH, this::onTaskAppeared);
mStateCallback.runOnceAtState(STATE_HANDLER_INVALIDATED, this::invalidateHandler);
mStateCallback.runOnceAtState(STATE_LAUNCHER_PRESENT | STATE_HANDLER_INVALIDATED,
this::invalidateHandlerWithLauncher);
@ -282,7 +273,7 @@ public class LauncherSwipeHandler<T extends BaseDraggingActivity>
@Override
protected boolean onActivityInit(Boolean alreadyOnHome) {
super.onActivityInit(alreadyOnHome);
final T activity = mActivityInterface.getCreatedActivity();
final Launcher activity = mActivityInterface.getCreatedActivity();
if (mActivity == activity) {
return true;
}
@ -304,7 +295,6 @@ public class LauncherSwipeHandler<T extends BaseDraggingActivity>
mRecentsView = activity.getOverviewPanel();
mRecentsView.setOnPageTransitionEndCallback(null);
linkRecentsViewScroll();
addLiveTileOverlay();
mStateCallback.setState(STATE_LAUNCHER_PRESENT);
@ -321,6 +311,8 @@ public class LauncherSwipeHandler<T extends BaseDraggingActivity>
// so we need to kick off switching to the overview predictions as soon as possible
mActivityInterface.updateOverviewPredictionState();
}
linkRecentsViewScroll();
return true;
}
@ -330,7 +322,7 @@ public class LauncherSwipeHandler<T extends BaseDraggingActivity>
}
private void onLauncherStart() {
final T activity = mActivityInterface.getCreatedActivity();
final Launcher activity = mActivityInterface.getCreatedActivity();
if (mActivity != activity) {
return;
}
@ -343,8 +335,7 @@ public class LauncherSwipeHandler<T extends BaseDraggingActivity>
if (mGestureState.getEndTarget() != HOME) {
Runnable initAnimFactory = () -> {
mAnimationFactory = mActivityInterface.prepareRecentsUI(
mWasLauncherAlreadyVisible, true,
this::onAnimatorPlaybackControllerCreated);
mWasLauncherAlreadyVisible, this::onAnimatorPlaybackControllerCreated);
maybeUpdateRecentsAttachedState(false /* animate */);
};
if (mWasLauncherAlreadyVisible) {
@ -521,34 +512,6 @@ public class LauncherSwipeHandler<T extends BaseDraggingActivity>
mAnimationFactory.createActivityInterface(mTransitionDragLength);
}
@Override
protected void updateSource(Rect stackBounds, RemoteAnimationTargetCompat runningTarget) {
super.updateSource(stackBounds, runningTarget);
mTaskViewSimulator.setPreview(runningTarget, mRecentsAnimationTargets);
}
@Override
protected void initTransitionEndpoints(DeviceProfile dp) {
super.initTransitionEndpoints(dp);
mTaskViewSimulator.setDp(dp);
mTaskViewSimulator.setLayoutRotation(
mDeviceState.getCurrentActiveRotation(),
mDeviceState.getDisplayRotation());
AnimatorSet anim = new AnimatorSet();
anim.setDuration(mTransitionDragLength * 2);
anim.setInterpolator(t -> t * mDragLengthFactor);
anim.play(ObjectAnimator.ofFloat(mTaskViewSimulator.recentsViewScale,
AnimatedFloat.VALUE,
mTaskViewSimulator.getFullScreenScale(), 1));
anim.play(ObjectAnimator.ofFloat(mTaskViewSimulator.fullScreenProgress,
AnimatedFloat.VALUE,
BACKGROUND_APP.getOverviewFullscreenProgress(),
OVERVIEW.getOverviewFullscreenProgress()));
mWindowTransitionController =
AnimatorPlaybackController.wrap(anim, mTransitionDragLength * 2);
}
/**
* We don't want to change mLauncherTransitionController if mGestureState.getEndTarget() == HOME
* (it has its own animation) or if we're already animating the current controller.
@ -579,18 +542,11 @@ public class LauncherSwipeHandler<T extends BaseDraggingActivity>
@Override
public void updateFinalShift() {
if (mRecentsAnimationTargets != null) {
// Base class expects applyTransformUnchecked to be called here.
// TODO: Remove this dependency for swipe-up animation.
// applyTransformUnchecked();
updateSysUiFlags(mCurrentShift.value);
}
if (ENABLE_QUICKSTEP_LIVE_TILE.get()) {
if (mRecentsAnimationTargets != null) {
LiveTileOverlay.INSTANCE.update(
mAppWindowAnimationHelper.getCurrentRectWithInsets(),
mAppWindowAnimationHelper.getCurrentCornerRadius());
mTaskViewSimulator.getCurrentCropRect(),
mTaskViewSimulator.getCurrentCornerRadius());
}
}
@ -602,16 +558,8 @@ public class LauncherSwipeHandler<T extends BaseDraggingActivity>
}
}
if (mWindowTransitionController != null) {
float progress = mCurrentShift.value / mDragLengthFactor;
mWindowTransitionController.setPlayFraction(progress);
mTransformParams
.setTargetSet(mRecentsAnimationTargets)
.setLauncherOnTop(true);
mTaskViewSimulator.setScroll(mRecentsView == null ? 0 : mRecentsView.getScrollOffset());
mTaskViewSimulator.apply(mTransformParams);
}
updateSysUiFlags(mCurrentShift.value);
applyWindowTransform();
updateLauncherTransitionProgress();
}
@ -685,7 +633,7 @@ public class LauncherSwipeHandler<T extends BaseDraggingActivity>
*/
@UiThread
private void notifyGestureStartedAsync() {
final T curActivity = mActivity;
final Launcher curActivity = mActivity;
if (curActivity != null) {
// Once the gesture starts, we can no longer transition home through the button, so
// reset the force override of the activity visibility
@ -771,20 +719,17 @@ public class LauncherSwipeHandler<T extends BaseDraggingActivity>
}
}
private void onTaskAppeared() {
RemoteAnimationTargetCompat app = mGestureState.getAnimationTarget();
if (mRecentsAnimationController != null && app != null) {
// TODO(b/152480470): Update Task target animation after onTaskAppeared holistically.
/* android.util.Log.d("LauncherSwipeHandler", "onTaskAppeared");
final boolean result = mRecentsAnimationController.removeTaskTarget(app);
mGestureState.setAnimationTarget(null);
android.util.Log.d("LauncherSwipeHandler", "removeTask, result=" + result); */
mRecentsAnimationController.finish(false /* toRecents */,
null /* onFinishComplete */);
@Override
protected boolean handleTaskAppeared(RemoteAnimationTargetCompat appearedTaskTarget) {
if (mStateCallback.hasStates(STATE_HANDLER_INVALIDATED)) {
return false;
}
if (mStateCallback.hasStates(STATE_START_NEW_TASK)
&& appearedTaskTarget.taskId == mGestureState.getLastStartedTaskId()) {
reset();
return true;
}
return false;
}
private GestureEndTarget calculateEndTarget(PointF velocity, float endVelocity, boolean isFling,
@ -971,24 +916,61 @@ public class LauncherSwipeHandler<T extends BaseDraggingActivity>
Interpolator interpolator, GestureEndTarget target, PointF velocityPxPerMs) {
// Set the state, but don't notify until the animation completes
mGestureState.setEndTarget(target, false /* isAtomic */);
maybeUpdateRecentsAttachedState();
if (mGestureState.getEndTarget() == HOME) {
HomeAnimationFactory homeAnimFactory;
if (mActivity != null) {
homeAnimFactory = mActivityInterface.prepareHomeUI();
} else {
homeAnimFactory = new HomeAnimationFactory() {
@NonNull
final TaskView runningTaskView = mRecentsView.getRunningTaskView();
final View workspaceView;
if (runningTaskView != null
&& runningTaskView.getTask().key.getComponent() != null) {
workspaceView = mActivity.getWorkspace().getFirstMatchForAppClose(
runningTaskView.getTask().key.getComponent().getPackageName(),
UserHandle.of(runningTaskView.getTask().key.userId));
} else {
workspaceView = null;
}
final RectF iconLocation = new RectF();
boolean canUseWorkspaceView =
workspaceView != null && workspaceView.isAttachedToWindow();
FloatingIconView floatingIconView = canUseWorkspaceView
? FloatingIconView.getFloatingIconView(mActivity, workspaceView,
true /* hideOriginal */, iconLocation, false /* isOpening */)
: null;
mActivity.getRootView().setForceHideBackArrow(true);
homeAnimFactory = new HomeAnimationFactory(floatingIconView) {
@Override
public RectF getWindowTargetRect() {
RectF fallbackTarget = new RectF(mAppWindowAnimationHelper.getTargetRect());
Utilities.scaleRectFAboutCenter(fallbackTarget, 0.25f);
return fallbackTarget;
if (canUseWorkspaceView) {
return iconLocation;
} else {
return super.getWindowTargetRect();
}
}
@NonNull
@Override
public AnimatorPlaybackController createActivityAnimationToHome() {
// Return an empty APC here since we have an non-user controlled animation
// to home.
long accuracy = 2 * Math.max(mDp.widthPx, mDp.heightPx);
return mActivity.getStateManager().createAnimationToNewWorkspace(
NORMAL, accuracy, 0 /* animComponents */);
}
@Override
public void playAtomicAnimation(float velocity) {
new StaggeredWorkspaceAnim(mActivity, velocity,
true /* animateOverviewScrim */).start();
}
};
} else {
homeAnimFactory = new HomeAnimationFactory(null) {
@Override
public AnimatorPlaybackController createActivityAnimationToHome() {
return AnimatorPlaybackController.wrap(new AnimatorSet(), duration);
@ -1031,12 +1013,24 @@ public class LauncherSwipeHandler<T extends BaseDraggingActivity>
// skip doing any future work here for the current gesture.
return;
}
if (target == NEW_TASK && mRecentsView != null
&& mRecentsView.getNextPage() == mRecentsView.getRunningTaskIndex()) {
// We are about to launch the current running task, so use LAST_TASK state
// instead of NEW_TASK. This could happen, for example, if our scroll is
// aborted after we determined the target to be NEW_TASK.
mGestureState.setEndTarget(LAST_TASK);
if (mRecentsView != null) {
int taskToLaunch = mRecentsView.getNextPage();
int runningTask = getLastAppearedTaskIndex();
boolean hasStartedNewTask = hasStartedNewTask();
if (target == NEW_TASK && taskToLaunch == runningTask
&& !hasStartedNewTask) {
// We are about to launch the current running task, so use LAST_TASK
// state instead of NEW_TASK. This could happen, for example, if our
// scroll is aborted after we determined the target to be NEW_TASK.
mGestureState.setEndTarget(LAST_TASK);
} else if (target == LAST_TASK && hasStartedNewTask) {
// We are about to re-launch the previously running task, but we can't
// just finish the controller like we normally would because that would
// instead resume the last task that appeared, and not ensure that this
// task is restored to the top. To address this, re-launch the task as
// if it were a new task.
mGestureState.setEndTarget(NEW_TASK);
}
}
mGestureState.setState(STATE_END_TARGET_ANIMATION_FINISHED);
}
@ -1160,8 +1154,9 @@ public class LauncherSwipeHandler<T extends BaseDraggingActivity>
@UiThread
private void startNewTaskInternal() {
startNewTask(STATE_HANDLER_INVALIDATED, success -> {
startNewTask(success -> {
if (!success) {
reset();
// We couldn't launch the task, so take user to overview so they can
// decide what to do instead of staying in this broken state.
endLauncherTransitionController();
@ -1171,6 +1166,12 @@ public class LauncherSwipeHandler<T extends BaseDraggingActivity>
});
}
@Override
protected void onRestartLastAppearedTask() {
super.onRestartLastAppearedTask();
reset();
}
private void reset() {
mStateCallback.setStateOnUiThread(STATE_HANDLER_INVALIDATED);
}
@ -1186,19 +1187,6 @@ public class LauncherSwipeHandler<T extends BaseDraggingActivity>
.getAnimationPlayer().isStarted()) {
mLauncherTransitionController.getAnimationPlayer().cancel();
}
if (mFinishingRecentsAnimationForNewTaskId != -1) {
// If we are canceling mid-starting a new task, switch to the screenshot since the
// recents animation has finished
switchToScreenshot();
TaskView newRunningTaskView = mRecentsView.getTaskView(
mFinishingRecentsAnimationForNewTaskId);
int newRunningTaskId = newRunningTaskView != null
? newRunningTaskView.getTask().key.id
: -1;
mRecentsView.setCurrentTask(newRunningTaskId);
mGestureState.setFinishingRecentsAnimationTaskId(newRunningTaskId);
}
}
private void invalidateHandler() {
@ -1337,8 +1325,7 @@ public class LauncherSwipeHandler<T extends BaseDraggingActivity>
}
private void setTargetAlphaProvider(TargetAlphaProvider provider) {
mAppWindowAnimationHelper.setTaskAlphaCallback(provider);
mTaskViewSimulator.setTaskAlphaCallback(provider);
mTransformParams.setTaskAlphaCallback(provider);
updateFinalShift();
}

View File

@ -15,6 +15,9 @@
*/
package com.android.quickstep;
import static android.content.pm.ActivityInfo.CONFIG_ORIENTATION;
import static android.content.pm.ActivityInfo.CONFIG_SCREEN_SIZE;
import static com.android.launcher3.QuickstepAppTransitionManagerImpl.RECENTS_LAUNCH_DURATION;
import static com.android.launcher3.QuickstepAppTransitionManagerImpl.STATUS_BAR_TRANSITION_DURATION;
import static com.android.launcher3.QuickstepAppTransitionManagerImpl.STATUS_BAR_TRANSITION_PRE_DELAY;
@ -29,21 +32,32 @@ import android.animation.AnimatorSet;
import android.app.ActivityOptions;
import android.content.Intent;
import android.content.res.Configuration;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
import android.view.View;
import com.android.launcher3.AbstractFloatingView;
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.InvariantDeviceProfile;
import com.android.launcher3.LauncherAnimationRunner;
import com.android.launcher3.R;
import com.android.launcher3.anim.Interpolators;
import com.android.launcher3.compat.AccessibilityManagerCompat;
import com.android.launcher3.statemanager.StateManager;
import com.android.launcher3.statemanager.StateManager.StateHandler;
import com.android.launcher3.statemanager.StatefulActivity;
import com.android.launcher3.util.ActivityTracker;
import com.android.launcher3.util.ObjectWrapper;
import com.android.launcher3.util.SystemUiController;
import com.android.launcher3.util.Themes;
import com.android.launcher3.views.BaseDragLayer;
import com.android.quickstep.fallback.FallbackRecentsStateController;
import com.android.quickstep.fallback.FallbackRecentsView;
import com.android.quickstep.fallback.RecentsRootView;
import com.android.quickstep.fallback.RecentsState;
import com.android.quickstep.views.OverviewActionsView;
import com.android.quickstep.views.TaskView;
import com.android.systemui.shared.recents.model.ThumbnailData;
import com.android.systemui.shared.system.ActivityOptionsCompat;
@ -51,26 +65,40 @@ 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;
import java.io.PrintWriter;
/**
* A recents activity that shows the recently launched tasks as swipable task cards.
* See {@link com.android.quickstep.views.RecentsView}.
*/
public final class RecentsActivity extends BaseRecentsActivity {
public final class RecentsActivity extends StatefulActivity<RecentsState> {
public static final String EXTRA_THUMBNAIL = "thumbnailData";
public static final String EXTRA_TASK_ID = "taskID";
public static final ActivityTracker<RecentsActivity> ACTIVITY_TRACKER =
new ActivityTracker<>();
private Handler mUiHandler = new Handler(Looper.getMainLooper());
private RecentsRootView mRecentsRootView;
private FallbackRecentsView mFallbackRecentsView;
private OverviewActionsView mActionsView;
@Override
private Configuration mOldConfig;
private StateManager<RecentsState> mStateManager;
/**
* Init drag layer and overview panel views.
*/
protected void initViews() {
setContentView(R.layout.fallback_recents_activity);
mRecentsRootView = findViewById(R.id.drag_layer);
mFallbackRecentsView = findViewById(R.id.overview_panel);
mActionsView = findViewById(R.id.overview_actions_view);
mRecentsRootView.recreateControllers();
mFallbackRecentsView.init(findViewById(R.id.overview_actions_view));
mFallbackRecentsView.init(mActionsView);
}
@Override
@ -103,25 +131,38 @@ public final class RecentsActivity extends BaseRecentsActivity {
intent.removeExtra(EXTRA_TASK_ID);
intent.removeExtra(EXTRA_THUMBNAIL);
super.onNewIntent(intent);
ACTIVITY_TRACKER.handleNewIntent(this, intent);
}
@Override
/**
* Logic for when device configuration changes (rotation, screen size change, multi-window,
* etc.)
*/
protected void onHandleConfigChanged() {
super.onHandleConfigChanged();
mUserEventDispatcher = null;
initDeviceProfile();
AbstractFloatingView.closeOpenViews(this, true,
AbstractFloatingView.TYPE_ALL & ~AbstractFloatingView.TYPE_REBIND_SAFE);
dispatchDeviceProfileChanged();
reapplyUi();
mRecentsRootView.recreateControllers();
}
@Override
protected void reapplyUi() {
mRecentsRootView.dispatchInsets();
}
@Override
/**
* Generate the device profile to use in this activity.
* @return device profile
*/
protected DeviceProfile createDeviceProfile() {
DeviceProfile dp = InvariantDeviceProfile.INSTANCE.get(this).getDeviceProfile(this);
DeviceProfile dp1 = InvariantDeviceProfile.INSTANCE.get(this).getDeviceProfile(this);
// In case we are reusing IDP, create a copy so that we don't conflict with Launcher
// activity.
return (mRecentsRootView != null) && isInMultiWindowMode()
? dp.getMultiWindowProfile(this, getMultiWindowDisplaySize())
: super.createDeviceProfile();
: dp1.copy(this);
}
@Override
@ -139,6 +180,10 @@ public final class RecentsActivity extends BaseRecentsActivity {
return (T) mFallbackRecentsView;
}
public OverviewActionsView getActionsView() {
return mActionsView;
}
@Override
public void returnToHomescreen() {
super.returnToHomescreen();
@ -160,12 +205,7 @@ public final class RecentsActivity extends BaseRecentsActivity {
RemoteAnimationTargetCompat[] wallpaperTargets, AnimationResult result) {
AnimatorSet anim = composeRecentsLaunchAnimator(taskView, appTargets,
wallpaperTargets);
anim.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
mFallbackRecentsView.resetViewUI();
}
});
anim.addListener(resetStateListener());
result.setAnimation(anim, RecentsActivity.this);
}
};
@ -193,12 +233,7 @@ public final class RecentsActivity extends BaseRecentsActivity {
.createAdjacentPageAnimForTaskLaunch(taskView);
adjacentAnimation.setInterpolator(Interpolators.TOUCH_RESPONSE_INTERPOLATOR);
adjacentAnimation.setDuration(RECENTS_LAUNCH_DURATION);
adjacentAnimation.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
mFallbackRecentsView.resetTaskVisuals();
}
});
adjacentAnimation.addListener(resetStateListener());
target.play(adjacentAnimation);
}
return target;
@ -210,13 +245,14 @@ public final class RecentsActivity extends BaseRecentsActivity {
// onActivityStart callback.
mFallbackRecentsView.setContentAlpha(1);
super.onStart();
mFallbackRecentsView.resetTaskVisuals();
}
@Override
protected void onStop() {
super.onStop();
mFallbackRecentsView.reset();
// Workaround for b/78520668, explicitly trim memory once UI is hidden
onTrimMemory(TRIM_MEMORY_UI_HIDDEN);
}
@Override
@ -228,4 +264,98 @@ public final class RecentsActivity extends BaseRecentsActivity {
public void onTaskLaunched() {
mFallbackRecentsView.resetTaskVisuals();
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mStateManager = new StateManager<>(this, RecentsState.DEFAULT);
mOldConfig = new Configuration(getResources().getConfiguration());
initDeviceProfile();
initViews();
getSystemUiController().updateUiState(SystemUiController.UI_STATE_BASE_WINDOW,
Themes.getAttrBoolean(this, R.attr.isWorkspaceDarkText));
ACTIVITY_TRACKER.handleCreate(this);
}
@Override
public void onConfigurationChanged(Configuration newConfig) {
int diff = newConfig.diff(mOldConfig);
if ((diff & (CONFIG_ORIENTATION | CONFIG_SCREEN_SIZE)) != 0) {
onHandleConfigChanged();
}
mOldConfig.setTo(newConfig);
super.onConfigurationChanged(newConfig);
}
/**
* Initialize/update the device profile.
*/
private void initDeviceProfile() {
mDeviceProfile = createDeviceProfile();
onDeviceProfileInitiated();
}
@Override
public void onEnterAnimationComplete() {
super.onEnterAnimationComplete();
// After the transition to home, enable the high-res thumbnail loader if it wasn't enabled
// as a part of quickstep, so that high-res thumbnails can load the next time we enter
// overview
RecentsModel.INSTANCE.get(this).getThumbnailCache()
.getHighResLoadingState().setVisible(true);
}
@Override
public void onTrimMemory(int level) {
super.onTrimMemory(level);
RecentsModel.INSTANCE.get(this).onTrimMemory(level);
}
@Override
protected void onDestroy() {
super.onDestroy();
ACTIVITY_TRACKER.onActivityDestroyed(this);
}
@Override
public void onBackPressed() {
// TODO: Launch the task we came from
startHome();
}
public void startHome() {
startActivity(new Intent(Intent.ACTION_MAIN)
.addCategory(Intent.CATEGORY_HOME)
.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
}
@Override
protected StateHandler<RecentsState>[] createStateHandlers() {
return new StateHandler[] { new FallbackRecentsStateController(this) };
}
@Override
public StateManager<RecentsState> getStateManager() {
return mStateManager;
}
@Override
public void dump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args) {
super.dump(prefix, fd, writer, args);
writer.println(prefix + "Misc:");
dumpMisc(prefix + "\t", writer);
}
private AnimatorListenerAdapter resetStateListener() {
return new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
mFallbackRecentsView.resetTaskVisuals();
mStateManager.reapplyState();
}
};
}
}

View File

@ -22,6 +22,7 @@ import android.content.Context;
import android.graphics.Insets;
import android.graphics.Matrix;
import android.graphics.Rect;
import android.widget.Toast;
import com.android.launcher3.BaseActivity;
import com.android.launcher3.BaseDraggingActivity;
@ -109,16 +110,26 @@ public class TaskOverlayFactory implements ResourceBasedOverride {
public void initOverlay(Task task, ThumbnailData thumbnail, Matrix matrix) {
ImageActionsApi imageApi = new ImageActionsApi(
mApplicationContext, mThumbnailView::getThumbnail);
final boolean isAllowedByPolicy = thumbnail.isRealSnapshot;
getActionsView().setCallbacks(new OverlayUICallbacks() {
@Override
public void onShare() {
imageApi.startShareActivity();
if (isAllowedByPolicy) {
imageApi.startShareActivity();
} else {
showBlockedByPolicyMessage();
}
}
@Override
public void onScreenshot() {
imageApi.saveScreenshot(mThumbnailView.getThumbnail(),
getTaskSnapshotBounds(), getTaskSnapshotInsets(), task.key.id);
if (isAllowedByPolicy) {
imageApi.saveScreenshot(mThumbnailView.getThumbnail(),
getTaskSnapshotBounds(), getTaskSnapshotInsets(), task.key.id);
} else {
showBlockedByPolicyMessage();
}
}
});
}
@ -152,6 +163,13 @@ public class TaskOverlayFactory implements ResourceBasedOverride {
// TODO: return the real insets
return Insets.of(0, 0, 0, 0);
}
private void showBlockedByPolicyMessage() {
Toast.makeText(
mThumbnailView.getContext(),
R.string.blocked_by_policy,
Toast.LENGTH_LONG).show();
}
}
/**

View File

@ -38,6 +38,7 @@ import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.statehandlers.DepthController;
import com.android.quickstep.util.AppWindowAnimationHelper;
import com.android.quickstep.util.MultiValueUpdateListener;
import com.android.quickstep.util.TransformParams;
import com.android.quickstep.views.RecentsView;
import com.android.quickstep.views.TaskView;
import com.android.systemui.shared.recents.model.Task;
@ -132,11 +133,10 @@ public final class TaskViewUtils {
final RemoteAnimationTargets targets =
new RemoteAnimationTargets(appTargets, wallpaperTargets, MODE_OPENING);
targets.addDependentTransactionApplier(applier);
AppWindowAnimationHelper.TransformParams params =
new AppWindowAnimationHelper.TransformParams()
TransformParams params =
new TransformParams()
.setSyncTransactionApplier(applier)
.setTargetSet(targets)
.setLauncherOnTop(true);
.setTargetSet(targets);
AnimatorSet animatorSet = new AnimatorSet();
final RecentsView recentsView = v.getRecentsView();
@ -150,7 +150,7 @@ public final class TaskViewUtils {
final RectF mThumbnailRect;
{
inOutHelper.setTaskAlphaCallback((t, alpha) -> mTaskAlpha.value);
params.setTaskAlphaCallback((t, alpha) -> mTaskAlpha.value);
inOutHelper.prepareAnimation(
BaseActivity.fromContext(v.getContext()).getDeviceProfile());
inOutHelper.fromTaskThumbnailView(v.getThumbnail(), (RecentsView) v.getParent(),
@ -175,7 +175,7 @@ public final class TaskViewUtils {
v.getRecentsView().getClipAnimationHelper();
if (liveTileAnimationHelper != null) {
// Append the surface transform params for the live tile app.
AppWindowAnimationHelper.TransformParams liveTileParams =
TransformParams liveTileParams =
v.getRecentsView().getLiveTileParams(true /* mightNeedToRefill */);
if (liveTileParams != null) {
SurfaceParams[] liveTileSurfaceParams =
@ -186,7 +186,7 @@ public final class TaskViewUtils {
}
}
// Apply surface transform using the surface params list.
AppWindowAnimationHelper.applySurfaceParams(params.getSyncTransactionApplier(),
params.applySurfaceParams(
surfaceParamsList.toArray(new SurfaceParams[surfaceParamsList.size()]));
// Get the task bounds for the app that's being opened after surface transform
// update.

View File

@ -30,8 +30,6 @@ import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_SYS
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_TRACING_ENABLED;
import android.annotation.TargetApi;
import android.app.ActivityManager;
import android.app.ActivityManager.RunningTaskInfo;
import android.app.PendingIntent;
import android.app.RemoteAction;
import android.app.Service;
@ -40,6 +38,7 @@ import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.res.Configuration;
import android.graphics.Rect;
import android.graphics.Region;
import android.graphics.drawable.Icon;
import android.os.Build;
@ -71,6 +70,7 @@ import com.android.launcher3.tracing.nano.TouchInteractionServiceProto;
import com.android.launcher3.uioverrides.plugins.PluginManagerWrapper;
import com.android.launcher3.util.OnboardingPrefs;
import com.android.launcher3.util.TraceHelper;
import com.android.launcher3.util.WindowBounds;
import com.android.quickstep.inputconsumers.AccessibilityInputConsumer;
import com.android.quickstep.inputconsumers.AssistantInputConsumer;
import com.android.quickstep.inputconsumers.DeviceLockedInputConsumer;
@ -83,6 +83,7 @@ import com.android.quickstep.inputconsumers.ScreenPinnedInputConsumer;
import com.android.quickstep.util.ActiveGestureLog;
import com.android.quickstep.util.AssistantUtilities;
import com.android.quickstep.util.ProtoTracer;
import com.android.quickstep.util.SplitScreenBounds;
import com.android.quickstep.views.RecentsView;
import com.android.systemui.plugins.OverscrollPlugin;
import com.android.systemui.plugins.PluginListener;
@ -120,7 +121,7 @@ class ArgList extends LinkedList<String> {
/**
* Service connected by system-UI for handling touch interaction.
*/
@TargetApi(Build.VERSION_CODES.Q)
@TargetApi(Build.VERSION_CODES.R)
public class TouchInteractionService extends Service implements PluginListener<OverscrollPlugin>,
ProtoTraceable<LauncherTraceProto> {
@ -231,6 +232,11 @@ public class TouchInteractionService extends Service implements PluginListener<O
MAIN_EXECUTOR.execute(() -> mDeviceState.setDeferredGestureRegion(region));
}
public void onSplitScreenSecondaryBoundsChanged(Rect bounds, Rect insets) {
WindowBounds wb = new WindowBounds(bounds, insets);
MAIN_EXECUTOR.execute(() -> SplitScreenBounds.INSTANCE.setSecondaryWindowBounds(wb));
}
/** Deprecated methods **/
public void onQuickStep(MotionEvent motionEvent) { }
@ -518,8 +524,13 @@ public class TouchInteractionService extends Service implements PluginListener<O
private GestureState createGestureState() {
GestureState gestureState = new GestureState(mOverviewComponentObserver,
ActiveGestureLog.INSTANCE.generateAndSetLogId());
gestureState.updateRunningTask(TraceHelper.whitelistIpcs("getRunningTask.0",
() -> mAM.getRunningTask(false /* filterOnlyVisibleRecents */)));
if (mTaskAnimationManager.isRecentsAnimationRunning()) {
gestureState.updateRunningTask(mGestureState.getRunningTask());
gestureState.updateLastStartedTaskId(mGestureState.getLastStartedTaskId());
} else {
gestureState.updateRunningTask(TraceHelper.whitelistIpcs("getRunningTask.0",
() -> mAM.getRunningTask(false /* filterOnlyVisibleRecents */)));
}
return gestureState;
}
@ -599,15 +610,24 @@ public class TouchInteractionService extends Service implements PluginListener<O
}
private void handleOrientationSetup(InputConsumer baseInputConsumer) {
if (TestProtocol.sDebugTracing) {
Log.d(TestProtocol.PAUSE_NOT_DETECTED, "handleOrientationSetup.1");
}
if (!isFixedRotationTransformEnabled(this)) {
return;
}
mDeviceState.enableMultipleRegions(baseInputConsumer instanceof OtherActivityInputConsumer);
BaseDraggingActivity activity =
mOverviewComponentObserver.getActivityInterface().getCreatedActivity();
if (TestProtocol.sDebugTracing) {
Log.d(TestProtocol.PAUSE_NOT_DETECTED, "handleOrientationSetup.2");
}
if (activity == null || !(activity.getOverviewPanel() instanceof RecentsView)) {
return;
}
if (TestProtocol.sDebugTracing) {
Log.d(TestProtocol.PAUSE_NOT_DETECTED, "handleOrientationSetup.3");
}
((RecentsView) activity.getOverviewPanel())
.setLayoutRotation(mDeviceState.getCurrentActiveRotation(),
mDeviceState.getDisplayRotation());
@ -637,14 +657,7 @@ public class TouchInteractionService extends Service implements PluginListener<O
runningComponent != null && runningComponent.equals(homeComponent);
}
if (previousGestureState.getFinishingRecentsAnimationTaskId() > 0) {
// If the finish animation was interrupted, then continue using the other activity input
// consumer but with the next task as the running task
RunningTaskInfo info = new ActivityManager.RunningTaskInfo();
info.id = previousGestureState.getFinishingRecentsAnimationTaskId();
gestureState.updateRunningTask(info);
return createOtherActivityInputConsumer(previousGestureState, gestureState, event);
} else if (gestureState.getRunningTask() == null) {
if (gestureState.getRunningTask() == null) {
return mResetGestureInputConsumer;
} else if (previousGestureState.isRunningAnimationToLauncher()
|| gestureState.getActivityInterface().isResumed()
@ -658,25 +671,22 @@ public class TouchInteractionService extends Service implements PluginListener<O
} else if (mDeviceState.isGestureBlockedActivity(gestureState.getRunningTask())) {
return mResetGestureInputConsumer;
} else {
return createOtherActivityInputConsumer(previousGestureState, gestureState, event);
return createOtherActivityInputConsumer(gestureState, event);
}
}
private InputConsumer createOtherActivityInputConsumer(GestureState previousGestureState,
GestureState gestureState, MotionEvent event) {
private InputConsumer createOtherActivityInputConsumer(GestureState gestureState,
MotionEvent event) {
final boolean shouldDefer;
final BaseSwipeUpHandler.Factory factory;
if (!mOverviewComponentObserver.isHomeAndOverviewSame()) {
shouldDefer = previousGestureState.getFinishingRecentsAnimationTaskId() < 0;
factory = mFallbackSwipeHandlerFactory;
} else {
shouldDefer = gestureState.getActivityInterface().deferStartingActivity(mDeviceState,
event);
factory = mLauncherSwipeHandlerFactory;
}
final boolean shouldDefer = !mOverviewComponentObserver.isHomeAndOverviewSame()
|| gestureState.getActivityInterface().deferStartingActivity(mDeviceState, event);
final boolean disableHorizontalSwipe = mDeviceState.isInExclusionRegion(event);
return new OtherActivityInputConsumer(this, mDeviceState, mTaskAnimationManager,
gestureState, shouldDefer, this::onConsumerInactive,

View File

@ -0,0 +1,94 @@
/*
* Copyright (C) 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.quickstep.fallback;
import static com.android.launcher3.LauncherAnimUtils.SCALE_PROPERTY;
import static com.android.launcher3.anim.Interpolators.LINEAR;
import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_MODAL;
import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_SCALE;
import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_TRANSLATE_X;
import static com.android.launcher3.states.StateAnimationConfig.PLAY_ATOMIC_OVERVIEW_PEEK;
import static com.android.launcher3.states.StateAnimationConfig.PLAY_ATOMIC_OVERVIEW_SCALE;
import static com.android.launcher3.states.StateAnimationConfig.SKIP_OVERVIEW;
import static com.android.quickstep.views.RecentsView.ADJACENT_PAGE_OFFSET;
import static com.android.quickstep.views.RecentsView.FULLSCREEN_PROGRESS;
import static com.android.quickstep.views.RecentsView.TASK_MODALNESS;
import com.android.launcher3.anim.PendingAnimation;
import com.android.launcher3.anim.PropertySetter;
import com.android.launcher3.statemanager.StateManager.StateHandler;
import com.android.launcher3.states.StateAnimationConfig;
import com.android.launcher3.util.MultiValueAlpha;
import com.android.quickstep.RecentsActivity;
import com.android.quickstep.views.ClearAllButton;
/**
* State controller for fallback recents activity
*/
public class FallbackRecentsStateController implements StateHandler<RecentsState> {
private final StateAnimationConfig mNoConfig = new StateAnimationConfig();
private final RecentsActivity mActivity;
private final FallbackRecentsView mRecentsView;
public FallbackRecentsStateController(RecentsActivity activity) {
mActivity = activity;
mRecentsView = activity.getOverviewPanel();
}
@Override
public void setState(RecentsState state) {
mRecentsView.updateEmptyMessage();
mRecentsView.resetTaskVisuals();
setProperties(state, mNoConfig, PropertySetter.NO_ANIM_PROPERTY_SETTER);
}
@Override
public void setStateWithAnimation(RecentsState toState, StateAnimationConfig config,
PendingAnimation setter) {
if (!config.hasAnimationFlag(PLAY_ATOMIC_OVERVIEW_PEEK | PLAY_ATOMIC_OVERVIEW_SCALE)) {
// The entire recents animation is played atomically.
return;
}
if (config.hasAnimationFlag(SKIP_OVERVIEW)) {
return;
}
// While animating into recents, update the visible task data as needed
setter.addOnFrameCallback(mRecentsView::loadVisibleTaskData);
mRecentsView.updateEmptyMessage();
setProperties(toState, config, setter);
}
private void setProperties(RecentsState state, StateAnimationConfig config,
PropertySetter setter) {
float buttonAlpha = state.hasButtons() ? 1 : 0;
setter.setFloat(mRecentsView.getClearAllButton(), ClearAllButton.VISIBILITY_ALPHA,
buttonAlpha, LINEAR);
setter.setFloat(mActivity.getActionsView().getVisibilityAlpha(),
MultiValueAlpha.VALUE, buttonAlpha, LINEAR);
float[] scaleAndOffset = state.getOverviewScaleAndOffset(mActivity);
setter.setFloat(mRecentsView, SCALE_PROPERTY, scaleAndOffset[0],
config.getInterpolator(ANIM_OVERVIEW_SCALE, LINEAR));
setter.setFloat(mRecentsView, ADJACENT_PAGE_OFFSET, scaleAndOffset[1],
config.getInterpolator(ANIM_OVERVIEW_TRANSLATE_X, LINEAR));
setter.setFloat(mRecentsView, TASK_MODALNESS, state.getOverviewModalness(),
config.getInterpolator(ANIM_OVERVIEW_MODAL, LINEAR));
setter.setFloat(mRecentsView, FULLSCREEN_PROGRESS, state.isFullScreen() ? 1 : 0, LINEAR);
}
}

View File

@ -15,17 +15,17 @@
*/
package com.android.quickstep.fallback;
import static com.android.launcher3.LauncherAnimUtils.SCALE_PROPERTY;
import static com.android.quickstep.fallback.RecentsState.DEFAULT;
import static com.android.quickstep.fallback.RecentsState.MODAL_TASK;
import static com.android.quickstep.util.WindowSizeStrategy.FALLBACK_RECENTS_SIZE_STRATEGY;
import android.annotation.TargetApi;
import android.app.ActivityManager.RunningTaskInfo;
import android.content.Context;
import android.graphics.Canvas;
import android.os.Build;
import android.util.AttributeSet;
import android.util.FloatProperty;
import android.view.View;
import com.android.launcher3.Utilities;
import com.android.launcher3.statemanager.StateManager.StateListener;
import com.android.quickstep.RecentsActivity;
import com.android.quickstep.views.OverviewActionsView;
import com.android.quickstep.views.RecentsView;
@ -34,26 +34,9 @@ import com.android.systemui.shared.recents.model.Task.TaskKey;
import java.util.ArrayList;
public class FallbackRecentsView extends RecentsView<RecentsActivity> {
public static final FloatProperty<FallbackRecentsView> ZOOM_PROGRESS =
new FloatProperty<FallbackRecentsView> ("zoomInProgress") {
@Override
public void setValue(FallbackRecentsView view, float value) {
view.setZoomProgress(value);
}
@Override
public Float get(FallbackRecentsView view) {
return view.mZoomInProgress;
}
};
private float mZoomInProgress = 0;
private boolean mInOverviewState = true;
private float mZoomScale = 1f;
@TargetApi(Build.VERSION_CODES.R)
public class FallbackRecentsView extends RecentsView<RecentsActivity>
implements StateListener<RecentsState> {
private RunningTaskInfo mRunningTaskInfo;
@ -63,6 +46,7 @@ public class FallbackRecentsView extends RecentsView<RecentsActivity> {
public FallbackRecentsView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr, FALLBACK_RECENTS_SIZE_STRATEGY);
mActivity.getStateManager().addStateListener(this);
}
@Override
@ -77,71 +61,12 @@ public class FallbackRecentsView extends RecentsView<RecentsActivity> {
mActivity.startHome();
}
@Override
public void onViewAdded(View child) {
super.onViewAdded(child);
updateEmptyMessage();
}
@Override
public void onViewRemoved(View child) {
super.onViewRemoved(child);
updateEmptyMessage();
}
@Override
public void draw(Canvas canvas) {
maybeDrawEmptyMessage(canvas);
super.draw(canvas);
}
@Override
public void reset() {
super.reset();
resetViewUI();
}
@Override
public boolean shouldUseMultiWindowTaskSizeStrategy() {
// Just use the activity task size for multi-window as well.
return false;
}
public void resetViewUI() {
setZoomProgress(0);
resetTaskVisuals();
}
public void setInOverviewState(boolean inOverviewState) {
if (mInOverviewState != inOverviewState) {
mInOverviewState = inOverviewState;
if (mInOverviewState) {
resetTaskVisuals();
} else {
setZoomProgress(1);
}
}
}
@Override
public void resetTaskVisuals() {
super.resetTaskVisuals();
setFullscreenProgress(mFullscreenProgress);
}
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
mZoomScale = getMaxScaleForFullScreen();
setZoomProgress(mZoomInProgress);
}
public void setZoomProgress(float progress) {
mZoomInProgress = progress;
SCALE_PROPERTY.set(this, Utilities.mapRange(mZoomInProgress, 1, mZoomScale));
FULLSCREEN_PROGRESS.set(this, mZoomInProgress);
}
public void onGestureAnimationStart(RunningTaskInfo runningTaskInfo) {
mRunningTaskInfo = runningTaskInfo;
onGestureAnimationStart(runningTaskInfo == null ? -1 : runningTaskInfo.taskId);
@ -178,4 +103,37 @@ public class FallbackRecentsView extends RecentsView<RecentsActivity> {
}
super.applyLoadPlan(tasks);
}
@Override
public void setModalStateEnabled(boolean isModalState) {
super.setModalStateEnabled(isModalState);
if (isModalState) {
mActivity.getStateManager().goToState(RecentsState.MODAL_TASK);
} else {
if (mActivity.isInState(RecentsState.MODAL_TASK)) {
mActivity.getStateManager().goToState(DEFAULT);
}
}
}
@Override
public void onStateTransitionStart(RecentsState toState) {
setOverviewStateEnabled(true);
setFreezeViewVisibility(true);
}
@Override
public void onStateTransitionComplete(RecentsState finalState) {
setOverlayEnabled(finalState == DEFAULT || finalState == MODAL_TASK);
setFreezeViewVisibility(false);
}
@Override
public void setOverviewStateEnabled(boolean enabled) {
super.setOverviewStateEnabled(enabled);
if (enabled) {
RecentsState state = mActivity.getStateManager().getState();
setDisallowScrollToClearAll(!state.hasButtons());
}
}
}

View File

@ -0,0 +1,116 @@
/*
* Copyright (C) 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.quickstep.fallback;
import static com.android.launcher3.uioverrides.states.BackgroundAppState.getOverviewScaleAndOffsetForBackgroundState;
import static com.android.launcher3.uioverrides.states.OverviewModalTaskState.getOverviewScaleAndOffsetForModalState;
import android.content.Context;
import com.android.launcher3.statemanager.BaseState;
import com.android.quickstep.RecentsActivity;
/**
* State definition for Fallback recents
*/
public class RecentsState implements BaseState<RecentsState> {
private static final int FLAG_MODAL = BaseState.getFlag(0);
private static final int FLAG_HAS_BUTTONS = BaseState.getFlag(1);
private static final int FLAG_FULL_SCREEN = BaseState.getFlag(2);
public static final RecentsState DEFAULT = new RecentsState(0, FLAG_HAS_BUTTONS);
public static final RecentsState MODAL_TASK = new ModalState(1,
FLAG_DISABLE_RESTORE | FLAG_HAS_BUTTONS | FLAG_MODAL);
public static final RecentsState BACKGROUND_APP = new BackgroundAppState(2,
FLAG_DISABLE_RESTORE | FLAG_NON_INTERACTIVE | FLAG_FULL_SCREEN);
public final int ordinal;
private final int mFlags;
private static final float NO_OFFSET = 0;
private static final float NO_SCALE = 1;
public RecentsState(int id, int flags) {
this.ordinal = id;
this.mFlags = flags;
}
@Override
public String toString() {
return "Ordinal-" + ordinal;
}
@Override
public final boolean hasFlag(int mask) {
return (mFlags & mask) != 0;
}
@Override
public int getTransitionDuration(Context context) {
return 250;
}
@Override
public RecentsState getHistoryForState(RecentsState previousState) {
return DEFAULT;
}
/**
* For this state, how modal should over view been shown. 0 modalness means all tasks drawn,
* 1 modalness means the current task is show on its own.
*/
public float getOverviewModalness() {
return hasFlag(FLAG_MODAL) ? 1 : 0;
}
public boolean isFullScreen() {
return hasFlag(FLAG_FULL_SCREEN);
}
public boolean hasButtons() {
return hasFlag(FLAG_HAS_BUTTONS);
}
public float[] getOverviewScaleAndOffset(RecentsActivity activity) {
return new float[] { NO_SCALE, NO_OFFSET };
}
private static class ModalState extends RecentsState {
public ModalState(int id, int flags) {
super(id, flags);
}
@Override
public float[] getOverviewScaleAndOffset(RecentsActivity activity) {
return getOverviewScaleAndOffsetForModalState(activity);
}
}
private static class BackgroundAppState extends RecentsState {
public BackgroundAppState(int id, int flags) {
super(id, flags);
}
@Override
public float[] getOverviewScaleAndOffset(RecentsActivity activity) {
return getOverviewScaleAndOffsetForBackgroundState(activity);
}
}
}

View File

@ -21,8 +21,8 @@ import static android.view.MotionEvent.ACTION_UP;
import static com.android.launcher3.Utilities.squaredHypot;
import static com.android.launcher3.Utilities.squaredTouchSlop;
import static com.android.quickstep.MultiStateCallback.DEBUG_STATES;
import static com.android.quickstep.LauncherSwipeHandler.MIN_PROGRESS_FOR_OVERVIEW;
import static com.android.quickstep.MultiStateCallback.DEBUG_STATES;
import static com.android.quickstep.util.ActiveGestureLog.INTENT_EXTRA_LOG_TRACE_ID;
import android.content.ComponentName;
@ -44,12 +44,13 @@ import com.android.quickstep.GestureState;
import com.android.quickstep.InputConsumer;
import com.android.quickstep.LockScreenRecentsActivity;
import com.android.quickstep.MultiStateCallback;
import com.android.quickstep.RecentsAnimationCallbacks;
import com.android.quickstep.RecentsAnimationController;
import com.android.quickstep.RecentsAnimationDeviceState;
import com.android.quickstep.RecentsAnimationCallbacks;
import com.android.quickstep.RecentsAnimationTargets;
import com.android.quickstep.TaskAnimationManager;
import com.android.quickstep.util.AppWindowAnimationHelper;
import com.android.quickstep.util.TransformParams;
import com.android.systemui.shared.recents.model.ThumbnailData;
import com.android.systemui.shared.system.InputMonitorCompat;
import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
@ -84,7 +85,7 @@ public class DeviceLockedInputConsumer implements InputConsumer,
private final PointF mTouchDown = new PointF();
private final AppWindowAnimationHelper mAppWindowAnimationHelper;
private final AppWindowAnimationHelper.TransformParams mTransformParams;
private final TransformParams mTransformParams;
private final Point mDisplaySize;
private final MultiStateCallback mStateCallback;
@ -105,7 +106,7 @@ public class DeviceLockedInputConsumer implements InputConsumer,
mGestureState = gestureState;
mTouchSlopSquared = squaredTouchSlop(context);
mAppWindowAnimationHelper = new AppWindowAnimationHelper(context);
mTransformParams = new AppWindowAnimationHelper.TransformParams();
mTransformParams = new TransformParams();
mInputMonitorCompat = inputMonitorCompat;
// Do not use DeviceProfile as the user data might be locked
@ -230,8 +231,7 @@ public class DeviceLockedInputConsumer implements InputConsumer,
Utilities.scaleRectAboutCenter(displaySize, SCALE_DOWN);
displaySize.offsetTo(displaySize.left, 0);
mTransformParams.setTargetSet(mRecentsAnimationTargets)
.setLauncherOnTop(true);
mTransformParams.setTargetSet(mRecentsAnimationTargets);
mAppWindowAnimationHelper.updateTargetRect(displaySize);
mAppWindowAnimationHelper.applyTransform(mTransformParams);

View File

@ -18,6 +18,7 @@ package com.android.quickstep.inputconsumers;
import static com.android.launcher3.config.FeatureFlags.ENABLE_QUICKSTEP_LIVE_TILE;
import static com.android.systemui.shared.system.ActivityManagerWrapper.CLOSE_SYSTEM_WINDOWS_REASON_RECENTS;
import android.util.Log;
import android.view.KeyEvent;
import android.view.MotionEvent;
@ -95,6 +96,9 @@ public class OverviewInputConsumer<T extends BaseDraggingActivity>
ev.setEdgeFlags(flags | Utilities.EDGE_NAV_BAR);
}
ev.offsetLocation(-mLocationOnScreen[0], -mLocationOnScreen[1]);
if (TestProtocol.sDebugTracing) {
Log.d(TestProtocol.PAUSE_NOT_DETECTED, "OverviewInputConsumer");
}
boolean handled = mEventReceiver.test(ev);
ev.offsetLocation(mLocationOnScreen[0], mLocationOnScreen[1]);
ev.setEdgeFlags(flags);

View File

@ -15,11 +15,10 @@
*/
package com.android.quickstep.util;
import static com.android.launcher3.config.FeatureFlags.ENABLE_QUICKSTEP_LIVE_TILE;
import static com.android.launcher3.Utilities.boundToRange;
import static com.android.launcher3.Utilities.mapRange;
import static com.android.systemui.shared.system.QuickStepContract.getWindowCornerRadius;
import static com.android.systemui.shared.system.QuickStepContract.supportsRoundedCornersOnWindows;
import static com.android.systemui.shared.system.RemoteAnimationTargetCompat.ACTIVITY_TYPE_HOME;
import static com.android.systemui.shared.system.RemoteAnimationTargetCompat.MODE_CLOSING;
import android.annotation.TargetApi;
import android.content.Context;
@ -36,9 +35,7 @@ import com.android.launcher3.BaseDraggingActivity;
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
import com.android.launcher3.anim.Interpolators;
import com.android.launcher3.views.BaseDragLayer;
import com.android.quickstep.RemoteAnimationTargets;
import com.android.quickstep.SystemUiProxy;
import com.android.quickstep.views.RecentsView;
import com.android.quickstep.views.TaskThumbnailView;
@ -46,14 +43,14 @@ import com.android.systemui.shared.recents.utilities.RectFEvaluator;
import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
import com.android.systemui.shared.system.SyncRtSurfaceTransactionApplierCompat;
import com.android.systemui.shared.system.SyncRtSurfaceTransactionApplierCompat.SurfaceParams;
import com.android.systemui.shared.system.TransactionCompat;
import com.android.systemui.shared.system.SyncRtSurfaceTransactionApplierCompat.SurfaceParams.Builder;
import com.android.systemui.shared.system.WindowManagerWrapper;
/**
* Utility class to handle window clip animation
*/
@TargetApi(Build.VERSION_CODES.P)
public class AppWindowAnimationHelper {
public class AppWindowAnimationHelper implements TransformParams.BuilderProxy {
// The bounds of the source app in device coordinates
private final RectF mSourceStackBounds = new RectF();
@ -94,9 +91,6 @@ public class AppWindowAnimationHelper {
// Corner radius currently applied to transformed window.
private float mCurrentCornerRadius;
private TargetAlphaProvider mTaskAlphaCallback = (t, a) -> a;
private TargetAlphaProvider mBaseAlphaCallback = (t, a) -> 1;
public AppWindowAnimationHelper(RecentsOrientedState orientedState, Context context) {
Resources res = context.getResources();
mOrientedState = orientedState;
@ -167,7 +161,7 @@ public class AppWindowAnimationHelper {
if (surfaceParams == null) {
return null;
}
applySurfaceParams(params.mSyncTransactionApplier, surfaceParams);
params.applySurfaceParams(surfaceParams);
return mCurrentRect;
}
@ -176,97 +170,60 @@ public class AppWindowAnimationHelper {
* the SurfaceParams to apply via {@link SyncRtSurfaceTransactionApplierCompat#applyParams}.
*/
public SurfaceParams[] computeSurfaceParams(TransformParams params) {
if (params.mTargetSet == null) {
if (params.getTargetSet() == null) {
return null;
}
float progress = Utilities.boundToRange(params.mProgress, 0, 1);
updateCurrentRect(params);
return params.createSurfaceParams(this);
}
SurfaceParams[] surfaceParams = new SurfaceParams[params.mTargetSet.unfilteredApps.length];
for (int i = 0; i < params.mTargetSet.unfilteredApps.length; i++) {
RemoteAnimationTargetCompat app = params.mTargetSet.unfilteredApps[i];
SurfaceParams.Builder builder = new SurfaceParams.Builder(app.leash);
@Override
public void onBuildParams(Builder builder, RemoteAnimationTargetCompat app,
int targetMode, TransformParams params) {
Rect crop = mTmpRect;
crop.set(app.screenSpaceBounds);
crop.offsetTo(0, 0);
float cornerRadius = 0f;
float scale = Math.max(mCurrentRect.width(), mTargetRect.width()) / crop.width();
if (app.mode == targetMode
&& app.activityType != RemoteAnimationTargetCompat.ACTIVITY_TYPE_HOME) {
mTmpMatrix.setRectToRect(mSourceRect, mCurrentRect, ScaleToFit.FILL);
if (app.localBounds != null) {
mTmpMatrix.setTranslate(0, 0);
if (app.activityType == ACTIVITY_TYPE_HOME && app.mode == MODE_CLOSING) {
mTmpMatrix.setTranslate(app.localBounds.left, app.localBounds.top);
}
mTmpMatrix.postTranslate(app.localBounds.left, app.localBounds.top);
} else {
mTmpMatrix.setTranslate(app.position.x, app.position.y);
mTmpMatrix.postTranslate(app.position.x, app.position.y);
}
mCurrentClipRectF.roundOut(crop);
if (mSupportsRoundedCornersOnWindows) {
if (params.getCornerRadius() > -1) {
cornerRadius = params.getCornerRadius();
scale = mCurrentRect.width() / crop.width();
} else {
float windowCornerRadius = mUseRoundedCornersOnWindows
? mWindowCornerRadius : 0;
cornerRadius = mapRange(boundToRange(params.getProgress(), 0, 1),
windowCornerRadius, mTaskCornerRadius);
}
mCurrentCornerRadius = cornerRadius;
}
Rect crop = mTmpRect;
crop.set(app.screenSpaceBounds);
crop.offsetTo(0, 0);
float alpha;
float cornerRadius = 0f;
float scale = Math.max(mCurrentRect.width(), mTargetRect.width()) / crop.width();
if (app.mode == params.mTargetSet.targetMode) {
alpha = mTaskAlphaCallback.getAlpha(app, params.mTargetAlpha);
if (app.activityType != RemoteAnimationTargetCompat.ACTIVITY_TYPE_HOME) {
mTmpMatrix.setRectToRect(mSourceRect, mCurrentRect, ScaleToFit.FILL);
if (app.localBounds != null) {
mTmpMatrix.postTranslate(app.localBounds.left, app.localBounds.top);
} else {
mTmpMatrix.postTranslate(app.position.x, app.position.y);
}
mCurrentClipRectF.roundOut(crop);
if (mSupportsRoundedCornersOnWindows) {
if (params.mCornerRadius > -1) {
cornerRadius = params.mCornerRadius;
scale = mCurrentRect.width() / crop.width();
} else {
float windowCornerRadius = mUseRoundedCornersOnWindows
? mWindowCornerRadius : 0;
cornerRadius = Utilities.mapRange(progress, windowCornerRadius,
mTaskCornerRadius);
}
mCurrentCornerRadius = cornerRadius;
}
// Fade out Assistant overlay.
if (app.activityType == RemoteAnimationTargetCompat.ACTIVITY_TYPE_ASSISTANT
&& app.isNotInRecents) {
alpha = 1 - Interpolators.DEACCEL_2_5.getInterpolation(progress);
}
} else if (params.mTargetSet.hasRecents) {
// If home has a different target then recents, reverse anim the
// home target.
alpha = 1 - (progress * params.mTargetAlpha);
}
} else {
alpha = mBaseAlphaCallback.getAlpha(app, progress);
if (ENABLE_QUICKSTEP_LIVE_TILE.get() && params.mLauncherOnTop) {
crop = null;
}
}
builder.withAlpha(alpha)
.withMatrix(mTmpMatrix)
builder.withMatrix(mTmpMatrix)
.withWindowCrop(crop)
// Since radius is in Surface space, but we draw the rounded corners in screen
// space, we have to undo the scale
.withCornerRadius(cornerRadius / scale);
surfaceParams[i] = builder.build();
}
return surfaceParams;
}
public RectF updateCurrentRect(TransformParams params) {
if (params.mCurrentRect != null) {
mCurrentRect.set(params.mCurrentRect);
if (params.getCurrentRect() != null) {
mCurrentRect.set(params.getCurrentRect());
} else {
mTmpRectF.set(mTargetRect);
Utilities.scaleRectFAboutCenter(mTmpRectF, params.mOffsetScale);
mCurrentRect.set(mRectFEvaluator.evaluate(params.mProgress, mSourceRect, mTmpRectF));
if (mOrientedState == null
|| !mOrientedState.isMultipleOrientationSupportedByDevice()) {
mCurrentRect.offset(params.mOffset, 0);
} else {
int displayRotation = mOrientedState.getDisplayRotation();
int launcherRotation = mOrientedState.getLauncherRotation();
mOrientedState.getOrientationHandler().offsetTaskRect(mCurrentRect,
params.mOffset, displayRotation, launcherRotation);
}
mCurrentRect.set(mRectFEvaluator.evaluate(
params.getProgress(), mSourceRect, mTmpRectF));
}
updateClipRect(params);
@ -275,7 +232,7 @@ public class AppWindowAnimationHelper {
private void updateClipRect(TransformParams params) {
// Don't clip past progress > 1.
float progress = Math.min(1, params.mProgress);
float progress = Math.min(1, params.getProgress());
mCurrentClipRectF.left = mSourceWindowClipInsets.left * progress;
mCurrentClipRectF.top = mSourceWindowClipInsets.top * progress;
mCurrentClipRectF.right =
@ -289,28 +246,6 @@ public class AppWindowAnimationHelper {
return mCurrentRectWithInsets;
}
public static void applySurfaceParams(@Nullable SyncRtSurfaceTransactionApplierCompat
syncTransactionApplier, SurfaceParams[] params) {
if (syncTransactionApplier != null) {
syncTransactionApplier.scheduleApply(params);
} else {
TransactionCompat t = new TransactionCompat();
for (SurfaceParams param : params) {
SyncRtSurfaceTransactionApplierCompat.applyParams(t, param);
}
t.setEarlyWakeup();
t.apply();
}
}
public void setTaskAlphaCallback(TargetAlphaProvider callback) {
mTaskAlphaCallback = callback;
}
public void setBaseAlphaCallback(TargetAlphaProvider callback) {
mBaseAlphaCallback = callback;
}
public void fromTaskThumbnailView(TaskThumbnailView ttv, RecentsView rv,
@Nullable RemoteAnimationTargetCompat target) {
BaseDraggingActivity activity = BaseDraggingActivity.fromContext(ttv.getContext());
@ -386,157 +321,4 @@ public class AppWindowAnimationHelper {
return mCurrentCornerRadius;
}
public interface TargetAlphaProvider {
float getAlpha(RemoteAnimationTargetCompat target, float expectedAlpha);
}
public static class TransformParams {
private float mProgress;
private float mOffset;
private float mOffsetScale;
private @Nullable RectF mCurrentRect;
private float mTargetAlpha;
private float mCornerRadius;
private boolean mLauncherOnTop;
private RemoteAnimationTargets mTargetSet;
private SyncRtSurfaceTransactionApplierCompat mSyncTransactionApplier;
public TransformParams() {
mProgress = 0;
mOffset = 0;
mOffsetScale = 1;
mCurrentRect = null;
mTargetAlpha = 1;
mCornerRadius = -1;
mLauncherOnTop = false;
}
/**
* Sets the progress of the transformation, where 0 is the source and 1 is the target. We
* automatically adjust properties such as currentRect and cornerRadius based on this
* progress, unless they are manually overridden by setting them on this TransformParams.
*/
public TransformParams setProgress(float progress) {
mProgress = progress;
return this;
}
/**
* Sets the corner radius of the transformed window, in pixels. If unspecified (-1), we
* simply interpolate between the window's corner radius to the task view's corner radius,
* based on {@link #mProgress}.
*/
public TransformParams setCornerRadius(float cornerRadius) {
mCornerRadius = cornerRadius;
return this;
}
/**
* Sets the current rect to show the transformed window, in device coordinates. This gives
* the caller manual control of where to show the window. If unspecified (null), we
* interpolate between {@link AppWindowAnimationHelper#mSourceRect} and
* {@link AppWindowAnimationHelper#mTargetRect}, based on {@link #mProgress}.
*/
public TransformParams setCurrentRect(RectF currentRect) {
mCurrentRect = currentRect;
return this;
}
/**
* Specifies the alpha of the transformed window. Default is 1.
*/
public TransformParams setTargetAlpha(float targetAlpha) {
mTargetAlpha = targetAlpha;
return this;
}
/**
* If {@link #mCurrentRect} is null (i.e. {@link #setCurrentRect(RectF)} hasn't overridden
* the default), then offset the current rect by this amount after computing the rect based
* on {@link #mProgress}.
*/
public TransformParams setOffset(float offset) {
mOffset = offset;
return this;
}
/**
* If {@link #mCurrentRect} is null (i.e. {@link #setCurrentRect(RectF)} hasn't overridden
* the default), then scale the current rect by this amount after computing the rect based
* on {@link #mProgress}.
*/
public TransformParams setOffsetScale(float offsetScale) {
mOffsetScale = offsetScale;
return this;
}
/**
* If true, sets the crop = null and layer = Integer.MAX_VALUE for targets that don't match
* {@link #mTargetSet}.targetMode. (Currently only does this when live tiles are enabled.)
*/
public TransformParams setLauncherOnTop(boolean launcherOnTop) {
mLauncherOnTop = launcherOnTop;
return this;
}
/**
* Specifies the set of RemoteAnimationTargetCompats that are included in the transformation
* that these TransformParams help compute. These TransformParams generally only apply to
* the targetSet.apps which match the targetSet.targetMode (e.g. the MODE_CLOSING app when
* swiping to home).
*/
public TransformParams setTargetSet(RemoteAnimationTargets targetSet) {
mTargetSet = targetSet;
return this;
}
/**
* Sets the SyncRtSurfaceTransactionApplierCompat that will apply the SurfaceParams that
* are computed based on these TransformParams.
*/
public TransformParams setSyncTransactionApplier(
SyncRtSurfaceTransactionApplierCompat applier) {
mSyncTransactionApplier = applier;
return this;
}
// Pubic getters so outside packages can read the values.
public float getProgress() {
return mProgress;
}
public float getOffset() {
return mOffset;
}
public float getOffsetScale() {
return mOffsetScale;
}
@Nullable
public RectF getCurrentRect() {
return mCurrentRect;
}
public float getTargetAlpha() {
return mTargetAlpha;
}
public float getCornerRadius() {
return mCornerRadius;
}
public boolean isLauncherOnTop() {
return mLauncherOnTop;
}
public RemoteAnimationTargets getTargetSet() {
return mTargetSet;
}
public SyncRtSurfaceTransactionApplierCompat getSyncTransactionApplier() {
return mSyncTransactionApplier;
}
}
}

View File

@ -15,10 +15,10 @@
*/
package com.android.quickstep.util;
import static com.android.launcher3.LauncherAppTransitionManagerImpl.INDEX_SHELF_ANIM;
import static com.android.launcher3.LauncherState.BACKGROUND_APP;
import static com.android.launcher3.LauncherState.OVERVIEW;
import static com.android.launcher3.anim.Interpolators.OVERSHOOT_1_2;
import static com.android.launcher3.uioverrides.states.QuickstepAtomicAnimationFactory.INDEX_SHELF_ANIM;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;

View File

@ -19,8 +19,6 @@ import static android.view.Surface.ROTATION_0;
import static com.android.launcher3.states.RotationHelper.deltaRotation;
import static com.android.launcher3.touch.PagedOrientationHandler.MATRIX_POST_TRANSLATE;
import static com.android.quickstep.util.AppWindowAnimationHelper.applySurfaceParams;
import static com.android.quickstep.util.RecentsOrientedState.isFixedRotationTransformEnabled;
import static com.android.quickstep.util.RecentsOrientedState.postDisplayRotation;
import static com.android.systemui.shared.system.WindowManagerWrapper.WINDOWING_MODE_FULLSCREEN;
@ -33,24 +31,20 @@ import android.graphics.RectF;
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
import com.android.launcher3.anim.Interpolators;
import com.android.launcher3.touch.PagedOrientationHandler;
import com.android.quickstep.AnimatedFloat;
import com.android.quickstep.RecentsAnimationTargets;
import com.android.quickstep.util.AppWindowAnimationHelper.TargetAlphaProvider;
import com.android.quickstep.util.AppWindowAnimationHelper.TransformParams;
import com.android.quickstep.views.RecentsView.ScrollState;
import com.android.quickstep.views.TaskThumbnailView.PreviewPositionHelper;
import com.android.quickstep.views.TaskView;
import com.android.quickstep.views.TaskView.FullscreenDrawParams;
import com.android.systemui.shared.recents.model.ThumbnailData;
import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
import com.android.systemui.shared.system.SyncRtSurfaceTransactionApplierCompat.SurfaceParams;
import com.android.systemui.shared.system.SyncRtSurfaceTransactionApplierCompat.SurfaceParams.Builder;
/**
* A utility class which emulates the layout behavior of TaskView and RecentsView
*/
public class TaskViewSimulator {
public class TaskViewSimulator implements TransformParams.BuilderProxy {
private final Rect mTmpCropRect = new Rect();
private final RectF mTempRectF = new RectF();
@ -66,14 +60,11 @@ public class TaskViewSimulator {
private final Matrix mMatrix = new Matrix();
private RemoteAnimationTargetCompat mRunningTarget;
private RecentsAnimationTargets mAllTargets;
private TargetAlphaProvider mTaskAlphaCallback = (t, a) -> a;
// Thumbnail view properties
private final Rect mThumbnailPosition = new Rect();
private final ThumbnailData mThumbnailData = new ThumbnailData();
private final PreviewPositionHelper mPositionHelper;
private final PreviewPositionHelper mPositionHelper = new PreviewPositionHelper();
private final Matrix mInversePositionMatrix = new Matrix();
// TaskView properties
@ -93,12 +84,8 @@ public class TaskViewSimulator {
public TaskViewSimulator(Context context, WindowSizeStrategy sizeStrategy) {
mContext = context;
mSizeStrategy = sizeStrategy;
mPositionHelper = new PreviewPositionHelper(context);
mOrientationState = new RecentsOrientedState(context, sizeStrategy, i -> { });
// We do not need to attach listeners as the simulator is created just for the gesture
// duration, and any settings are unlikely to change during this
mOrientationState.initWithoutListeners();
mCurrentFullscreenParams = new FullscreenDrawParams(context);
mPageSpacing = context.getResources().getDimensionPixelSize(R.dimen.recents_page_spacing);
@ -117,15 +104,7 @@ public class TaskViewSimulator {
* @see com.android.quickstep.views.RecentsView#setLayoutRotation(int, int)
*/
public void setLayoutRotation(int touchRotation, int displayRotation) {
int launcherRotation;
if (!mOrientationState.isMultipleOrientationSupportedByDevice()
|| mOrientationState.isHomeRotationAllowed()) {
launcherRotation = displayRotation;
} else {
launcherRotation = ROTATION_0;
}
mOrientationState.update(touchRotation, displayRotation, launcherRotation);
mOrientationState.update(touchRotation, displayRotation);
mLayoutValid = false;
}
@ -143,10 +122,8 @@ public class TaskViewSimulator {
/**
* Sets the targets which the simulator will control
*/
public void setPreview(
RemoteAnimationTargetCompat runningTarget, RecentsAnimationTargets allTargets) {
public void setPreview(RemoteAnimationTargetCompat runningTarget) {
mRunningTarget = runningTarget;
mAllTargets = allTargets;
mThumbnailData.insets.set(mRunningTarget.contentInsets);
// TODO: What is this?
@ -169,10 +146,40 @@ public class TaskViewSimulator {
}
/**
* Sets an alternate function which can be used to control the alpha
* Returns the current clipped/visible window bounds in the window coordinate space
*/
public void setTaskAlphaCallback(TargetAlphaProvider callback) {
mTaskAlphaCallback = callback;
public RectF getCurrentCropRect() {
// Crop rect is the inverse of thumbnail matrix
RectF insets = mCurrentFullscreenParams.mCurrentDrawnInsets;
mTempRectF.set(-insets.left, -insets.top,
mTaskRect.width() + insets.right, mTaskRect.height() + insets.bottom);
mInversePositionMatrix.mapRect(mTempRectF);
return mTempRectF;
}
public RecentsOrientedState getOrientationState() {
return mOrientationState;
}
/**
* Returns the current transform applied to the window
*/
public Matrix getCurrentMatrix() {
return mMatrix;
}
/**
* Applies the rotation on the matrix to so that it maps from launcher coordinate space to
* window coordinate space.
*/
public void applyWindowToHomeRotation(Matrix matrix) {
mMatrix.postTranslate(mDp.windowX, mDp.windowY);
postDisplayRotation(deltaRotation(
mOrientationState.getLauncherRotation(), mOrientationState.getDisplayRotation()),
mDp.widthPx, mDp.heightPx, matrix);
if (mRunningTarget != null) {
matrix.postTranslate(-mRunningTarget.position.x, -mRunningTarget.position.y);
}
}
/**
@ -186,12 +193,12 @@ public class TaskViewSimulator {
mLayoutValid = true;
getFullScreenScale();
mThumbnailData.rotation = isFixedRotationTransformEnabled(mContext)
? mOrientationState.getDisplayRotation() : mPositionHelper.getCurrentRotation();
mPositionHelper.updateThumbnailMatrix(mThumbnailPosition, mThumbnailData,
mTaskRect.width(), mTaskRect.height(), mDp);
mThumbnailData.rotation = mOrientationState.getDisplayRotation();
mPositionHelper.updateThumbnailMatrix(
mThumbnailPosition, mThumbnailData,
mTaskRect.width(), mTaskRect.height(),
mDp, mOrientationState.getLauncherRotation());
mPositionHelper.getMatrix().invert(mInversePositionMatrix);
PagedOrientationHandler poh = mOrientationState.getOrientationHandler();
@ -201,7 +208,6 @@ public class TaskViewSimulator {
mScrollValid = false;
}
if (!mScrollValid) {
mScrollValid = true;
int start = mOrientationState.getOrientationHandler()
@ -233,11 +239,7 @@ public class TaskViewSimulator {
// Apply recensView matrix
mMatrix.postScale(recentsViewScale.value, recentsViewScale.value, mPivot.x, mPivot.y);
postDisplayRotation(deltaRotation(
mOrientationState.getLauncherRotation(), mOrientationState.getDisplayRotation()),
mDp.widthPx, mDp.heightPx, mMatrix);
mMatrix.postTranslate(mDp.windowX - mRunningTarget.position.x,
mDp.windowY - mRunningTarget.position.y);
applyWindowToHomeRotation(mMatrix);
// Crop rect is the inverse of thumbnail matrix
mTempRectF.set(-insets.left, -insets.top,
@ -245,35 +247,18 @@ public class TaskViewSimulator {
mInversePositionMatrix.mapRect(mTempRectF);
mTempRectF.roundOut(mTmpCropRect);
SurfaceParams[] surfaceParams = new SurfaceParams[mAllTargets.unfilteredApps.length];
for (int i = 0; i < mAllTargets.unfilteredApps.length; i++) {
RemoteAnimationTargetCompat app = mAllTargets.unfilteredApps[i];
SurfaceParams.Builder builder = new SurfaceParams.Builder(app.leash);
params.applySurfaceParams(params.createSurfaceParams(this));
}
if (app.mode == mAllTargets.targetMode) {
float alpha = mTaskAlphaCallback.getAlpha(app, params.getTargetAlpha());
if (app.activityType != RemoteAnimationTargetCompat.ACTIVITY_TYPE_HOME) {
// Fade out Assistant overlay.
if (app.activityType == RemoteAnimationTargetCompat.ACTIVITY_TYPE_ASSISTANT
&& app.isNotInRecents) {
alpha = Interpolators.ACCEL_2.getInterpolation(fullScreenProgress.value);
}
builder.withAlpha(alpha)
.withMatrix(mMatrix)
.withWindowCrop(mTmpCropRect)
.withCornerRadius(getCurrentCornerRadius());
} else if (params.getTargetSet().hasRecents) {
// If home has a different target then recents, reverse anim the home target.
builder.withAlpha(fullScreenProgress.value * params.getTargetAlpha());
}
} else {
builder.withAlpha(1);
}
surfaceParams[i] = builder.build();
@Override
public void onBuildParams(Builder builder, RemoteAnimationTargetCompat app,
int targetMode, TransformParams params) {
if (app.mode == targetMode
&& app.activityType != RemoteAnimationTargetCompat.ACTIVITY_TYPE_HOME) {
builder.withMatrix(mMatrix)
.withWindowCrop(mTmpCropRect)
.withCornerRadius(getCurrentCornerRadius());
}
applySurfaceParams(params.getSyncTransactionApplier(), surfaceParams);
}
/**

View File

@ -0,0 +1,205 @@
/*
* Copyright (C) 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.quickstep.util;
import android.graphics.RectF;
import androidx.annotation.Nullable;
import com.android.launcher3.Utilities;
import com.android.launcher3.anim.Interpolators;
import com.android.quickstep.RemoteAnimationTargets;
import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
import com.android.systemui.shared.system.SyncRtSurfaceTransactionApplierCompat;
import com.android.systemui.shared.system.SyncRtSurfaceTransactionApplierCompat.SurfaceParams;
import com.android.systemui.shared.system.TransactionCompat;
public class TransformParams {
private float mProgress;
private @Nullable RectF mCurrentRect;
private float mTargetAlpha;
private float mCornerRadius;
private RemoteAnimationTargets mTargetSet;
private SyncRtSurfaceTransactionApplierCompat mSyncTransactionApplier;
private TargetAlphaProvider mTaskAlphaCallback = (t, a) -> a;
private TargetAlphaProvider mBaseAlphaCallback = (t, a) -> 1;
public TransformParams() {
mProgress = 0;
mCurrentRect = null;
mTargetAlpha = 1;
mCornerRadius = -1;
}
/**
* Sets the progress of the transformation, where 0 is the source and 1 is the target. We
* automatically adjust properties such as currentRect and cornerRadius based on this
* progress, unless they are manually overridden by setting them on this TransformParams.
*/
public TransformParams setProgress(float progress) {
mProgress = progress;
return this;
}
/**
* Sets the corner radius of the transformed window, in pixels. If unspecified (-1), we
* simply interpolate between the window's corner radius to the task view's corner radius,
* based on {@link #mProgress}.
*/
public TransformParams setCornerRadius(float cornerRadius) {
mCornerRadius = cornerRadius;
return this;
}
/**
* Sets the current rect to show the transformed window, in device coordinates. This gives
* the caller manual control of where to show the window. If unspecified (null), we
* interpolate between {@link AppWindowAnimationHelper#mSourceRect} and
* {@link AppWindowAnimationHelper#mTargetRect}, based on {@link #mProgress}.
*/
public TransformParams setCurrentRect(RectF currentRect) {
mCurrentRect = currentRect;
return this;
}
/**
* Specifies the alpha of the transformed window. Default is 1.
*/
public TransformParams setTargetAlpha(float targetAlpha) {
mTargetAlpha = targetAlpha;
return this;
}
/**
* Specifies the set of RemoteAnimationTargetCompats that are included in the transformation
* that these TransformParams help compute. These TransformParams generally only apply to
* the targetSet.apps which match the targetSet.targetMode (e.g. the MODE_CLOSING app when
* swiping to home).
*/
public TransformParams setTargetSet(RemoteAnimationTargets targetSet) {
mTargetSet = targetSet;
return this;
}
/**
* Sets the SyncRtSurfaceTransactionApplierCompat that will apply the SurfaceParams that
* are computed based on these TransformParams.
*/
public TransformParams setSyncTransactionApplier(
SyncRtSurfaceTransactionApplierCompat applier) {
mSyncTransactionApplier = applier;
return this;
}
/**
* Sets an alternate function which can be used to control the alpha of target app
*/
public TransformParams setTaskAlphaCallback(TargetAlphaProvider callback) {
mTaskAlphaCallback = callback;
return this;
}
/**
* Sets an alternate function which can be used to control the alpha of non-target app
*/
public TransformParams setBaseAlphaCallback(TargetAlphaProvider callback) {
mBaseAlphaCallback = callback;
return this;
}
public SurfaceParams[] createSurfaceParams(BuilderProxy proxy) {
RemoteAnimationTargets targets = mTargetSet;
SurfaceParams[] surfaceParams = new SurfaceParams[targets.unfilteredApps.length];
for (int i = 0; i < targets.unfilteredApps.length; i++) {
RemoteAnimationTargetCompat app = targets.unfilteredApps[i];
SurfaceParams.Builder builder = new SurfaceParams.Builder(app.leash);
float progress = Utilities.boundToRange(getProgress(), 0, 1);
float alpha;
if (app.mode == targets.targetMode) {
alpha = mTaskAlphaCallback.getAlpha(app, getTargetAlpha());
if (app.activityType != RemoteAnimationTargetCompat.ACTIVITY_TYPE_HOME) {
// Fade out Assistant overlay.
if (app.activityType == RemoteAnimationTargetCompat.ACTIVITY_TYPE_ASSISTANT
&& app.isNotInRecents) {
alpha = 1 - Interpolators.DEACCEL_2_5.getInterpolation(progress);
}
} else if (targets.hasRecents) {
// If home has a different target then recents, reverse anim the
// home target.
alpha = 1 - (progress * getTargetAlpha());
}
} else {
alpha = mBaseAlphaCallback.getAlpha(app, progress);
}
proxy.onBuildParams(builder.withAlpha(alpha), app, targets.targetMode, this);
surfaceParams[i] = builder.build();
}
return surfaceParams;
}
// Pubic getters so outside packages can read the values.
public float getProgress() {
return mProgress;
}
@Nullable
public RectF getCurrentRect() {
return mCurrentRect;
}
public float getTargetAlpha() {
return mTargetAlpha;
}
public float getCornerRadius() {
return mCornerRadius;
}
public RemoteAnimationTargets getTargetSet() {
return mTargetSet;
}
public SyncRtSurfaceTransactionApplierCompat getSyncTransactionApplier() {
return mSyncTransactionApplier;
}
public void applySurfaceParams(SurfaceParams[] params) {
if (mSyncTransactionApplier != null) {
mSyncTransactionApplier.scheduleApply(params);
} else {
TransactionCompat t = new TransactionCompat();
for (SurfaceParams param : params) {
SyncRtSurfaceTransactionApplierCompat.applyParams(t, param);
}
t.setEarlyWakeup();
t.apply();
}
}
public interface TargetAlphaProvider {
float getAlpha(RemoteAnimationTargetCompat target, float expectedAlpha);
}
public interface BuilderProxy {
void onBuildParams(SurfaceParams.Builder builder,
RemoteAnimationTargetCompat app, int targetMode, TransformParams params);
}
}

View File

@ -64,7 +64,13 @@ public class ClearAllButton extends Button implements PageCallbacks {
protected void onAttachedToWindow() {
super.onAttachedToWindow();
mParent = (RecentsView) getParent();
mIsRtl = !mParent.getPagedOrientationHandler().getRecentsRtlSetting(getResources());
mIsRtl = getLayoutDirection() == LAYOUT_DIRECTION_RTL;
}
@Override
public void onRtlPropertiesChanged(int layoutDirection) {
super.onRtlPropertiesChanged(layoutDirection);
mIsRtl = getLayoutDirection() == LAYOUT_DIRECTION_RTL;
}
@Override

View File

@ -31,27 +31,24 @@ import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.annotation.TargetApi;
import android.content.Context;
import android.graphics.Canvas;
import android.os.Build;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.widget.FrameLayout;
import com.android.launcher3.BaseQuickstepLauncher;
import com.android.launcher3.Hotseat;
import com.android.launcher3.LauncherState;
import com.android.launcher3.LauncherStateManager.StateListener;
import com.android.launcher3.anim.Interpolators;
import com.android.launcher3.appprediction.PredictionUiStateManager;
import com.android.launcher3.appprediction.PredictionUiStateManager.Client;
import com.android.launcher3.statehandlers.DepthController;
import com.android.launcher3.statemanager.StateManager.StateListener;
import com.android.launcher3.uioverrides.plugins.PluginManagerWrapper;
import com.android.launcher3.util.TraceHelper;
import com.android.launcher3.views.ScrimView;
import com.android.quickstep.SysUINavigationMode;
import com.android.quickstep.util.AppWindowAnimationHelper;
import com.android.quickstep.util.AppWindowAnimationHelper.TransformParams;
import com.android.quickstep.util.TransformParams;
import com.android.systemui.plugins.PluginListener;
import com.android.systemui.plugins.RecentsExtraCard;
@ -60,7 +57,7 @@ import com.android.systemui.plugins.RecentsExtraCard;
*/
@TargetApi(Build.VERSION_CODES.O)
public class LauncherRecentsView extends RecentsView<BaseQuickstepLauncher>
implements StateListener {
implements StateListener<LauncherState> {
private final TransformParams mTransformParams = new TransformParams();
@ -124,24 +121,6 @@ public class LauncherRecentsView extends RecentsView<BaseQuickstepLauncher>
}
}
@Override
public void draw(Canvas canvas) {
maybeDrawEmptyMessage(canvas);
super.draw(canvas);
}
@Override
public void onViewAdded(View child) {
super.onViewAdded(child);
updateEmptyMessage();
}
@Override
protected void onTaskStackUpdated() {
// Lazily update the empty message only when the task stack is reapplied
updateEmptyMessage();
}
/**
* Animates adjacent tasks and translate hotseat off screen as well.
*/
@ -213,14 +192,14 @@ public class LauncherRecentsView extends RecentsView<BaseQuickstepLauncher>
@Override
public void redrawLiveTile(boolean mightNeedToRefill) {
AppWindowAnimationHelper.TransformParams transformParams = getLiveTileParams(mightNeedToRefill);
TransformParams transformParams = getLiveTileParams(mightNeedToRefill);
if (transformParams != null) {
mAppWindowAnimationHelper.applyTransform(transformParams);
}
}
@Override
public AppWindowAnimationHelper.TransformParams getLiveTileParams(
public TransformParams getLiveTileParams(
boolean mightNeedToRefill) {
if (!mEnableDrawingLiveTile || mRecentsAnimationController == null
|| mRecentsAnimationTargets == null || mAppWindowAnimationHelper == null) {
@ -248,8 +227,7 @@ public class LauncherRecentsView extends RecentsView<BaseQuickstepLauncher>
.setCurrentRect(mTempRectF)
.setTargetAlpha(taskView.getAlpha())
.setSyncTransactionApplier(mSyncTransactionApplier)
.setTargetSet(mRecentsAnimationTargets)
.setLauncherOnTop(true);
.setTargetSet(mRecentsAnimationTargets);
}
return mTransformParams;
}
@ -373,4 +351,16 @@ public class LauncherRecentsView extends RecentsView<BaseQuickstepLauncher>
protected DepthController getDepthController() {
return mActivity.getDepthController();
}
@Override
public void setModalStateEnabled(boolean isModalState) {
super.setModalStateEnabled(isModalState);
if (isModalState) {
mActivity.getStateManager().goToState(LauncherState.OVERVIEW_MODAL_TASK);
} else {
if (mActivity.isInState(LauncherState.OVERVIEW_MODAL_TASK)) {
mActivity.getStateManager().goToState(LauncherState.OVERVIEW);
}
}
}
}

View File

@ -31,6 +31,7 @@ import androidx.annotation.Nullable;
import com.android.launcher3.R;
import com.android.launcher3.util.MultiValueAlpha;
import com.android.launcher3.util.MultiValueAlpha.AlphaProperty;
import com.android.quickstep.SysUINavigationMode.Mode;
import com.android.quickstep.TaskOverlayFactory.OverlayUICallbacks;
import java.lang.annotation.Retention;
@ -141,4 +142,19 @@ public class OverviewActionsView<T extends OverlayUICallbacks> extends FrameLayo
public AlphaProperty getVisibilityAlpha() {
return mMultiValueAlpha.getProperty(INDEX_VISIBILITY_ALPHA);
}
/** Updates vertical margins for different navigation mode. */
public void updateVerticalMarginForNavModeChange(Mode mode) {
int bottomMargin = 0;
if (mode == Mode.THREE_BUTTONS) {
bottomMargin = getResources()
.getDimensionPixelSize(R.dimen.overview_actions_bottom_margin_three_button);
} else {
bottomMargin = getResources()
.getDimensionPixelSize(R.dimen.overview_actions_bottom_margin_gesture);
}
LayoutParams params = (LayoutParams) getLayoutParams();
params.setMargins(
params.leftMargin, params.topMargin, params.rightMargin, bottomMargin);
}
}

View File

@ -16,6 +16,8 @@
package com.android.quickstep.views;
import static android.view.Surface.ROTATION_0;
import static com.android.launcher3.BaseActivity.STATE_HANDLER_INVISIBILITY_FLAGS;
import static com.android.launcher3.InvariantDeviceProfile.CHANGE_FLAG_ICON_PARAMS;
import static com.android.launcher3.LauncherAnimUtils.SCALE_PROPERTY;
@ -30,8 +32,8 @@ import static com.android.launcher3.anim.Interpolators.ACCEL_2;
import static com.android.launcher3.anim.Interpolators.FAST_OUT_SLOW_IN;
import static com.android.launcher3.anim.Interpolators.LINEAR;
import static com.android.launcher3.config.FeatureFlags.ENABLE_QUICKSTEP_LIVE_TILE;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.TASK_DISMISS_SWIPE_UP;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.TASK_LAUNCH_SWIPE_DOWN;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TASK_DISMISS_SWIPE_UP;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TASK_LAUNCH_SWIPE_DOWN;
import static com.android.launcher3.statehandlers.DepthController.DEPTH;
import static com.android.launcher3.uioverrides.touchcontrollers.TaskViewTouchController.SUCCESS_TRANSITION_PROGRESS;
import static com.android.launcher3.userevent.nano.LauncherLogProto.Action.Touch.TAP;
@ -55,7 +57,6 @@ import android.app.ActivityManager;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.res.Configuration;
import android.graphics.Canvas;
import android.graphics.Point;
import android.graphics.PointF;
@ -123,14 +124,16 @@ import com.android.quickstep.TaskThumbnailCache;
import com.android.quickstep.TaskUtils;
import com.android.quickstep.ViewUtils;
import com.android.quickstep.util.AppWindowAnimationHelper;
import com.android.quickstep.util.LayoutUtils;
import com.android.quickstep.util.RecentsOrientedState;
import com.android.quickstep.util.SplitScreenBounds;
import com.android.quickstep.util.TransformParams;
import com.android.quickstep.util.WindowSizeStrategy;
import com.android.systemui.plugins.ResourceProvider;
import com.android.systemui.shared.recents.IPinnedStackAnimationListener;
import com.android.systemui.shared.recents.model.Task;
import com.android.systemui.shared.recents.model.ThumbnailData;
import com.android.systemui.shared.system.ActivityManagerWrapper;
import com.android.systemui.shared.system.ConfigurationCompat;
import com.android.systemui.shared.system.LauncherEventUtil;
import com.android.systemui.shared.system.PackageManagerWrapper;
import com.android.systemui.shared.system.SyncRtSurfaceTransactionApplierCompat;
@ -145,7 +148,8 @@ import java.util.function.Consumer;
@TargetApi(Build.VERSION_CODES.P)
public abstract class RecentsView<T extends BaseActivity> extends PagedView implements Insettable,
TaskThumbnailCache.HighResLoadingState.HighResLoadingStateChangedCallback,
InvariantDeviceProfile.OnIDPChangeListener, TaskVisualsChangeListener {
InvariantDeviceProfile.OnIDPChangeListener, TaskVisualsChangeListener,
SplitScreenBounds.OnChangeListener {
private static final String TAG = RecentsView.class.getSimpleName();
@ -507,7 +511,8 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl
mIPinnedStackAnimationListener.setActivity(mActivity);
SystemUiProxy.INSTANCE.get(getContext()).setPinnedStackAnimationListener(
mIPinnedStackAnimationListener);
mOrientationState.init();
mOrientationState.initListeners();
SplitScreenBounds.INSTANCE.addOnChangeListener(this);
}
@Override
@ -521,8 +526,9 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl
RecentsModel.INSTANCE.get(getContext()).removeThumbnailChangeListener(this);
mIdp.removeOnChangeListener(this);
SystemUiProxy.INSTANCE.get(getContext()).setPinnedStackAnimationListener(null);
SplitScreenBounds.INSTANCE.removeOnChangeListener(this);
mIPinnedStackAnimationListener.setActivity(null);
mOrientationState.destroy();
mOrientationState.destroyListeners();
}
@Override
@ -548,6 +554,13 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl
child.setLayoutDirection(mIsRtl ? View.LAYOUT_DIRECTION_LTR : View.LAYOUT_DIRECTION_RTL);
updateTaskStartIndex(child);
mActionsView.updateHiddenFlags(HIDDEN_NO_TASKS, false);
updateEmptyMessage();
}
@Override
public void draw(Canvas canvas) {
maybeDrawEmptyMessage(canvas);
super.draw(canvas);
}
private void updateTaskStartIndex(View affectingView) {
@ -598,20 +611,20 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl
}
@Override
protected void onPageEndTransition() {
super.onPageEndTransition();
if (getNextPage() > 0) {
setSwipeDownShouldLaunchApp(true);
}
protected void onPageBeginTransition() {
super.onPageBeginTransition();
LayoutUtils.setViewEnabled(mActionsView, false);
}
@Override
protected void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
int windowConfigurationRotation = ConfigurationCompat
.getWindowConfigurationRotation(getResources().getConfiguration());
setLayoutInternal(mOrientationState.getTouchRotation(),
mOrientationState.getDisplayRotation(), windowConfigurationRotation);
protected void onPageEndTransition() {
super.onPageEndTransition();
if (getScrollX() == getScrollForPage(getPageNearestToCenterOfScreen())) {
LayoutUtils.setViewEnabled(mActionsView, true);
}
if (getNextPage() > 0) {
setSwipeDownShouldLaunchApp(true);
}
}
@Override
@ -760,7 +773,10 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl
return taskViewCount;
}
protected void onTaskStackUpdated() { }
protected void onTaskStackUpdated() {
// Lazily update the empty message only when the task stack is reapplied
updateEmptyMessage();
}
public void resetTaskVisuals() {
for (int i = getTaskViewCount() - 1; i >= 0; i--) {
@ -827,6 +843,11 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl
mSizeStrategy.calculateTaskSize(mActivity, mActivity.getDeviceProfile(), outRect);
}
/** Gets the task size for modal state. */
public void getModalTaskSize(Rect outRect) {
mSizeStrategy.calculateModalTaskSize(mActivity, mActivity.getDeviceProfile(), outRect);
}
@Override
protected boolean computeScrollHelper() {
boolean scrolling = super.computeScrollHelper();
@ -958,6 +979,7 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl
setCurrentPage(0);
mDwbToastShown = false;
mActivity.getSystemUiController().updateUiState(UI_STATE_OVERVIEW, 0);
LayoutUtils.setViewEnabled(mActionsView, true);
}
public @Nullable TaskView getRunningTaskView() {
@ -965,7 +987,15 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl
}
public int getRunningTaskIndex() {
TaskView tv = getRunningTaskView();
return getTaskIndexForId(mRunningTaskId);
}
/**
* Get the index of the task view whose id matches {@param taskId}.
* @return -1 if there is no task view for the task id, else the index of the task view.
*/
public int getTaskIndexForId(int taskId) {
TaskView tv = getTaskView(taskId);
return tv == null ? -1 : indexOfChild(tv);
}
@ -1294,7 +1324,8 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl
ComponentKey compKey = TaskUtils.getLaunchComponentKeyForTask(taskView.getTask().key);
mActivity.getUserEventDispatcher().logTaskLaunchOrDismiss(
endState.logAction, Direction.UP, index, compKey);
mActivity.getStatsLogManager().log(TASK_DISMISS_SWIPE_UP, taskView.buildProto());
mActivity.getStatsLogManager().log(
LAUNCHER_TASK_DISMISS_SWIPE_UP, taskView.buildProto());
}
}
@ -1574,19 +1605,19 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl
}
public void setLayoutRotation(int touchRotation, int displayRotation) {
int launcherRotation = mOrientationState.getLauncherRotation();
setLayoutInternal(touchRotation, displayRotation, launcherRotation);
}
private void setLayoutInternal(int touchRotation, int displayRotation, int launcherRotation) {
if (mOrientationState.update(touchRotation, displayRotation, launcherRotation)) {
if (mOrientationState.update(touchRotation, displayRotation)) {
mOrientationHandler = mOrientationState.getOrientationHandler();
mIsRtl = mOrientationHandler.getRecentsRtlSetting(getResources());
setLayoutDirection(mIsRtl ? View.LAYOUT_DIRECTION_RTL : View.LAYOUT_DIRECTION_LTR);
setLayoutDirection(mIsRtl
? View.LAYOUT_DIRECTION_RTL
: View.LAYOUT_DIRECTION_LTR);
mClearAllButton.setLayoutDirection(mIsRtl
? View.LAYOUT_DIRECTION_LTR
: View.LAYOUT_DIRECTION_RTL);
mClearAllButton.setRotation(mOrientationHandler.getDegreesRotated());
mActivity.getDragLayer().recreateControllers();
mActionsView.updateHiddenFlags(HIDDEN_NON_ZERO_ROTATION,
touchRotation != 0 || launcherRotation != 0);
touchRotation != 0 || mOrientationState.getLauncherRotation() != ROTATION_0);
requestLayout();
}
}
@ -1682,7 +1713,8 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl
}
int count = getChildCount();
TaskView runningTask = mRunningTaskId == -1 ? null : getTaskView(mRunningTaskId);
TaskView runningTask = mRunningTaskId == -1 || !mRunningTaskTileHidden
? null : getTaskView(mRunningTaskId);
int midPoint = runningTask == null ? -1 : indexOfChild(runningTask);
int currentPage = getCurrentPage();
@ -1872,8 +1904,8 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl
mActivity.getUserEventDispatcher().logTaskLaunchOrDismiss(
endState.logAction, Direction.DOWN, indexOfChild(tv),
TaskUtils.getLaunchComponentKeyForTask(task.key));
mActivity.getStatsLogManager().log(TASK_LAUNCH_SWIPE_DOWN, tv.buildProto()
);
mActivity.getStatsLogManager().log(
LAUNCHER_TASK_LAUNCH_SWIPE_DOWN, tv.buildProto());
}
} else {
onTaskLaunched(false);
@ -2059,14 +2091,6 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl
return getScrollForPage(getRunningTaskIndex()) - mOrientationHandler.getPrimaryScroll(this);
}
/**
* @return How many pixels the running task is offset on the x-axis due to the current scrollX
* and parent scale.
*/
public float getScrollOffsetScaled() {
return getScrollOffset() * mOrientationHandler.getPrimaryScale(this);
}
public Consumer<MotionEvent> getEventDispatcher(float navbarRotation) {
float degreesRotated;
if (navbarRotation == 0) {
@ -2100,7 +2124,7 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl
return mAppWindowAnimationHelper;
}
public AppWindowAnimationHelper.TransformParams getLiveTileParams(
public TransformParams getLiveTileParams(
boolean mightNeedToRefill) {
return null;
}
@ -2145,18 +2169,6 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl
updatePageOffsets();
if (getCurrentPageTaskView() != null) {
getCurrentPageTaskView().setModalness(modalness);
TaskView tv = getCurrentPageTaskView();
// Move the task view up as it scales...
// ...the icon on taskview is hidden in modal state, so consider the top of the task
mTempFloatPoint[0] = 0;
mTempFloatPoint[1] = tv.getTop() + mTaskTopMargin;
// ...find the top after the transformation
getMatrix().mapPoints(mTempFloatPoint);
// ...make it match the top inset
float calcOffset = (mInsets.top - mTempFloatPoint[1]) * mTaskModalness;
tv.setTranslationY(calcOffset);
}
}
@ -2165,6 +2177,19 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl
return null;
}
@Override
public void onSecondaryWindowBoundsChanged() {
// Invalidate the task view size
setInsets(mInsets);
requestLayout();
}
/**
* Enables or disables modal state for RecentsView
* @param isModalState
*/
public void setModalStateEnabled(boolean isModalState) { }
/**
* Used to register callbacks for when our empty message state changes.
*

View File

@ -90,7 +90,7 @@ public class TaskThumbnailView extends View implements PluginListener<OverviewSc
// Contains the portion of the thumbnail that is clipped when fullscreen progress = 0.
private final Rect mPreviewRect = new Rect();
private final PreviewPositionHelper mPreviewPositionHelper;
private final PreviewPositionHelper mPreviewPositionHelper = new PreviewPositionHelper();
// Initialize with dummy value. It is overridden later by TaskView
private TaskView.FullscreenDrawParams mFullscreenParams = TEMP_PARAMS;
@ -122,7 +122,6 @@ public class TaskThumbnailView extends View implements PluginListener<OverviewSc
mDimmingPaintAfterClearing.setColor(Color.BLACK);
mActivity = BaseActivity.fromContext(context);
mIsDarkTextTheme = Themes.getAttrBoolean(mActivity, R.attr.isWorkspaceDarkText);
mPreviewPositionHelper = new PreviewPositionHelper(context);
}
/**
@ -349,8 +348,11 @@ public class TaskThumbnailView extends View implements PluginListener<OverviewSc
if (mBitmapShader != null && mThumbnailData != null) {
mPreviewRect.set(0, 0, mThumbnailData.thumbnail.getWidth(),
mThumbnailData.thumbnail.getHeight());
int currentRotation = ConfigurationCompat.getWindowConfigurationRotation(
mActivity.getResources().getConfiguration());
mPreviewPositionHelper.updateThumbnailMatrix(mPreviewRect, mThumbnailData,
getMeasuredWidth(), getMeasuredHeight(), mActivity.getDeviceProfile());
getMeasuredWidth(), getMeasuredHeight(), mActivity.getDeviceProfile(),
currentRotation);
mBitmapShader.setLocalMatrix(mPreviewPositionHelper.mMatrix);
mPaint.setShader(mBitmapShader);
@ -417,17 +419,6 @@ public class TaskThumbnailView extends View implements PluginListener<OverviewSc
private float mClipBottom = -1;
private boolean mIsOrientationChanged;
private final Context mContext;
public PreviewPositionHelper(Context context) {
mContext = context;
}
public int getCurrentRotation() {
return ConfigurationCompat.getWindowConfigurationRotation(
mContext.getResources().getConfiguration());
}
public Matrix getMatrix() {
return mMatrix;
}
@ -436,7 +427,7 @@ public class TaskThumbnailView extends View implements PluginListener<OverviewSc
* Updates the matrix based on the provided parameters
*/
public void updateThumbnailMatrix(Rect thumbnailPosition, ThumbnailData thumbnailData,
int canvasWidth, int canvasHeight, DeviceProfile dp) {
int canvasWidth, int canvasHeight, DeviceProfile dp, int currentRotation) {
boolean isRotated = false;
boolean isOrientationDifferent;
mClipBottom = -1;
@ -451,7 +442,6 @@ public class TaskThumbnailView extends View implements PluginListener<OverviewSc
final float thumbnailScale;
int thumbnailRotation = thumbnailData.rotation;
int currentRotation = getCurrentRotation();
int deltaRotate = getRotationDelta(currentRotation, thumbnailRotation);
Rect deviceInsets = dp.getInsets();

View File

@ -30,7 +30,7 @@ import static com.android.launcher3.anim.Interpolators.FAST_OUT_SLOW_IN;
import static com.android.launcher3.anim.Interpolators.LINEAR;
import static com.android.launcher3.anim.Interpolators.TOUCH_RESPONSE_INTERPOLATOR;
import static com.android.launcher3.config.FeatureFlags.ENABLE_QUICKSTEP_LIVE_TILE;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.TASK_LAUNCH_TAP;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TASK_LAUNCH_TAP;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
@ -212,7 +212,7 @@ public class TaskView extends FrameLayout implements PageCallbacks, Reusable {
mActivity.getUserEventDispatcher().logTaskLaunchOrDismiss(
Touch.TAP, Direction.NONE, getRecentsView().indexOfChild(this),
TaskUtils.getLaunchComponentKeyForTask(getTask().key));
mActivity.getStatsLogManager().log(TASK_LAUNCH_TAP, buildProto());
mActivity.getStatsLogManager().log(LAUNCHER_TASK_LAUNCH_TAP, buildProto());
});
mCurrentFullscreenParams = new FullscreenDrawParams(context);
@ -449,13 +449,13 @@ public class TaskView extends FrameLayout implements PageCallbacks, Reusable {
public void setOrientationState(RecentsOrientedState orientationState) {
PagedOrientationHandler orientationHandler = orientationState.getOrientationHandler();
boolean isRtl = orientationHandler.getRecentsRtlSetting(getResources());
boolean isRtl = getLayoutDirection() == LAYOUT_DIRECTION_RTL;
LayoutParams snapshotParams = (LayoutParams) mSnapshotView.getLayoutParams();
int thumbnailPadding = (int) getResources().getDimension(R.dimen.task_thumbnail_top_margin);
LayoutParams iconParams = (LayoutParams) mIconView.getLayoutParams();
switch (orientationHandler.getRotation()) {
case Surface.ROTATION_90:
iconParams.gravity = (isRtl ? END : START) | CENTER_VERTICAL;
iconParams.gravity = (isRtl ? START : END) | CENTER_VERTICAL;
iconParams.rightMargin = -thumbnailPadding;
iconParams.leftMargin = 0;
iconParams.topMargin = snapshotParams.topMargin / 2;

View File

@ -20,7 +20,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="recent_task_option_split_screen" msgid="5353188922202653570">"Splitscreen"</string>
<string name="recent_task_option_pin" msgid="7929860679018978258">"Anpinnen"</string>
<string name="recent_task_option_pin" msgid="7929860679018978258">"Fixieren"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Freeform-Modus"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"Keine kürzlich verwendeten Elemente"</string>
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Einstellungen zur App-Nutzung"</string>

View File

@ -17,14 +17,15 @@
<resources>
<dimen name="task_thumbnail_top_margin">24dp</dimen>
<dimen name="task_thumbnail_bottom_margin_with_actions">44dp</dimen>
<dimen name="task_thumbnail_half_top_margin">12dp</dimen>
<dimen name="task_thumbnail_icon_size">48dp</dimen>
<!-- For screens without rounded corners -->
<dimen name="task_corner_radius_small">2dp</dimen>
<!-- Overrideable in overlay that provides the Overview Actions. -->
<dimen name="overview_actions_height">110dp</dimen>
<dimen name="overview_actions_height">66dp</dimen>
<dimen name="overview_actions_bottom_margin_gesture">16dp</dimen>
<dimen name="overview_actions_bottom_margin_three_button">8dp</dimen>
<dimen name="overview_actions_horizontal_margin">16dp</dimen>
<dimen name="recents_page_spacing">10dp</dimen>
@ -61,7 +62,8 @@
<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">24dp</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>
<dimen name="multi_window_task_card_horz_space">100dp</dimen>
<!-- Copied from framework resource:

View File

@ -128,16 +128,18 @@
<!-- Feedback shown during interactive parts of Home gesture tutorial when the gesture is horizontal instead of vertical. [CHAR LIMIT=100] -->
<string name="home_gesture_feedback_wrong_swipe_direction" translatable="false">Make sure you swipe straight up</string>
<!-- Title shown on the confirmation screen after successful gesture. [CHAR LIMIT=30] -->
<string name="gesture_tutorial_confirm_title" translatable="false">All set</string>
<!-- Button text shown on a button on the confirm screen. [CHAR LIMIT=14] -->
<string name="gesture_tutorial_action_button_label" translatable="false">Done</string>
<!-- Button text shown on a text button on the confirm screen. [CHAR LIMIT=14] -->
<string name="gesture_tutorial_action_text_button_label" translatable="false">Settings</string>
<!-- Title shown on the confirmation screen after successful gesture. [CHAR LIMIT=30] -->
<string name="gesture_tutorial_confirm_title" translatable="false">All set</string>
<!-- Button text shown on a button on the confirm screen to leave the tutorial. [CHAR LIMIT=14] -->
<string name="gesture_tutorial_action_button_label_done" translatable="false">Done</string>
<!-- Button text shown on a button to go to Settings. [CHAR LIMIT=14] -->
<string name="gesture_tutorial_action_button_label_settings" translatable="false">Settings</string>
<!-- ******* Overview ******* -->
<!-- Label for a button that causes the current overview app to be shared. [CHAR_LIMIT=40] -->
<string name="action_share">Share</string>
<!-- Label for a button that causes a screen shot of the current app to be taken. [CHAR_LIMIT=40] -->
<string name="action_screenshot">Screenshot</string>
<!-- Message shown when an action is blocked by a policy enforced by the app or the organization managing the device. [CHAR_LIMIT=NONE] -->
<string name="blocked_by_policy">This action isn\'t allowed by the app or your organization</string>
</resources>

View File

@ -79,8 +79,8 @@
<style name="OverviewActionButton"
parent="@android:style/Widget.DeviceDefault.Button.Borderless">
<item name="android:textColor">?attr/workspaceTextColor</item>
<item name="android:drawableTint">?attr/workspaceTextColor</item>
<item name="android:textColor">@color/overview_button</item>
<item name="android:drawableTint">@color/overview_button</item>
<item name="android:tint">?attr/workspaceTextColor</item>
<item name="android:drawablePadding">4dp</item>
<item name="android:textAllCaps">false</item>

View File

@ -0,0 +1,70 @@
/*
* Copyright (C) 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.quickstep;
import static com.android.launcher3.util.LauncherUIHelper.doLayout;
import android.graphics.Bitmap;
import android.graphics.Bitmap.Config;
import com.android.quickstep.fallback.FallbackRecentsView;
import com.android.systemui.shared.recents.model.ThumbnailData;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.Robolectric;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.android.controller.ActivityController;
import org.robolectric.annotation.LooperMode;
import org.robolectric.annotation.LooperMode.Mode;
import org.robolectric.shadows.ShadowLooper;
import org.robolectric.util.ReflectionHelpers;
@RunWith(RobolectricTestRunner.class)
@LooperMode(Mode.PAUSED)
public class RecentsActivityTest {
@Test
public void testRecentsActivityCreates() {
ActivityController<RecentsActivity> controller =
Robolectric.buildActivity(RecentsActivity.class);
RecentsActivity launcher = controller.setup().get();
doLayout(launcher);
// TODO: Ensure that LauncherAppState is not created
}
@Test
public void testRecets_showCurrentTask() {
ActivityController<RecentsActivity> controller =
Robolectric.buildActivity(RecentsActivity.class);
RecentsActivity activity = controller.setup().get();
doLayout(activity);
FallbackRecentsView frv = activity.getOverviewPanel();
frv.showCurrentTask(22);
doLayout(activity);
ThumbnailData thumbnailData = new ThumbnailData();
ReflectionHelpers.setField(thumbnailData, "thumbnail",
Bitmap.createBitmap(300, 500, Config.ARGB_8888));
frv.switchToScreenshot(thumbnailData, () -> { });
ShadowLooper.idleMainLooper();
}
}

View File

@ -30,7 +30,6 @@ import android.content.SharedPreferences;
import android.os.Bundle;
import android.os.CancellationSignal;
import com.android.launcher3.LauncherStateManager.StateHandler;
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.model.WellbeingModel;
import com.android.launcher3.popup.SystemShortcut;
@ -38,6 +37,7 @@ import com.android.launcher3.proxy.ProxyActivityStarter;
import com.android.launcher3.proxy.StartActivityParams;
import com.android.launcher3.statehandlers.BackButtonAlphaHandler;
import com.android.launcher3.statehandlers.DepthController;
import com.android.launcher3.statemanager.StateManager.StateHandler;
import com.android.launcher3.uioverrides.RecentsViewStateController;
import com.android.launcher3.util.OnboardingPrefs;
import com.android.launcher3.util.UiThreadHelper;
@ -92,6 +92,9 @@ public abstract class BaseQuickstepLauncher extends Launcher
@Override
public void onNavigationModeChanged(Mode newMode) {
getDragLayer().recreateControllers();
if (mActionsView != null && isOverviewActionsEnabled()) {
mActionsView.updateVerticalMarginForNavModeChange(newMode);
}
}
@Override
@ -150,6 +153,7 @@ public abstract class BaseQuickstepLauncher extends Launcher
@Override
protected void onDeferredResumed() {
super.onDeferredResumed();
if (mPendingActivityRequestCode != -1 && isInState(NORMAL)) {
// Remove any active ProxyActivityStarter task and send RESULT_CANCELED to Launcher.
onActivityResult(mPendingActivityRequestCode, RESULT_CANCELED, null);
@ -167,13 +171,18 @@ public abstract class BaseQuickstepLauncher extends Launcher
mActionsView = findViewById(R.id.overview_actions_view);
((RecentsView) getOverviewPanel()).init(mActionsView);
if (FeatureFlags.ENABLE_OVERVIEW_ACTIONS.get() && removeShelfFromOverview(this)) {
if (isOverviewActionsEnabled()) {
// Overview is above all other launcher elements, including qsb, so move it to the top.
getOverviewPanel().bringToFront();
mActionsView.bringToFront();
mActionsView.updateVerticalMarginForNavModeChange(SysUINavigationMode.getMode(this));
}
}
private boolean isOverviewActionsEnabled() {
return FeatureFlags.ENABLE_OVERVIEW_ACTIONS.get() && removeShelfFromOverview(this);
}
public <T extends OverviewActionsView> T getActionsView() {
return (T) mActionsView;
}
@ -186,7 +195,7 @@ public abstract class BaseQuickstepLauncher extends Launcher
}
@Override
protected StateHandler[] createStateHandlers() {
protected StateHandler<LauncherState>[] createStateHandlers() {
return new StateHandler[] {
getAllAppsController(),
getWorkspace(),
@ -200,9 +209,8 @@ public abstract class BaseQuickstepLauncher extends Launcher
}
@Override
protected OnboardingPrefs createOnboardingPrefs(SharedPreferences sharedPrefs,
LauncherStateManager stateManager) {
return new QuickstepOnboardingPrefs(this, sharedPrefs, stateManager);
protected OnboardingPrefs createOnboardingPrefs(SharedPreferences sharedPrefs) {
return new QuickstepOnboardingPrefs(this, sharedPrefs);
}
@Override

View File

@ -16,14 +16,13 @@
package com.android.launcher3.statehandlers;
import static com.android.launcher3.LauncherState.FLAG_HIDE_BACK_BUTTON;
import static com.android.launcher3.anim.Interpolators.LINEAR;
import static com.android.quickstep.AnimatedFloat.VALUE;
import com.android.launcher3.BaseQuickstepLauncher;
import com.android.launcher3.LauncherState;
import com.android.launcher3.LauncherStateManager;
import com.android.launcher3.anim.PendingAnimation;
import com.android.launcher3.statemanager.StateManager.StateHandler;
import com.android.launcher3.states.StateAnimationConfig;
import com.android.launcher3.util.UiThreadHelper;
import com.android.quickstep.AnimatedFloat;
@ -33,7 +32,7 @@ import com.android.quickstep.SystemUiProxy;
/**
* State handler for animating back button alpha
*/
public class BackButtonAlphaHandler implements LauncherStateManager.StateHandler {
public class BackButtonAlphaHandler implements StateHandler<LauncherState> {
private final BaseQuickstepLauncher mLauncher;
private final AnimatedFloat mBackAlpha = new AnimatedFloat(this::updateBackAlpha);

View File

@ -26,10 +26,10 @@ import android.view.ViewTreeObserver;
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherState;
import com.android.launcher3.LauncherStateManager;
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
import com.android.launcher3.anim.PendingAnimation;
import com.android.launcher3.statemanager.StateManager.StateHandler;
import com.android.launcher3.states.StateAnimationConfig;
import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
import com.android.systemui.shared.system.SurfaceControlCompat;
@ -39,7 +39,7 @@ import com.android.systemui.shared.system.WallpaperManagerCompat;
/**
* Controls blur and wallpaper zoom, for the Launcher surface only.
*/
public class DepthController implements LauncherStateManager.StateHandler {
public class DepthController implements StateHandler<LauncherState> {
public static final FloatProperty<DepthController> DEPTH =
new FloatProperty<DepthController>("depth") {

View File

@ -36,9 +36,9 @@ import androidx.annotation.NonNull;
import com.android.launcher3.BaseQuickstepLauncher;
import com.android.launcher3.LauncherState;
import com.android.launcher3.LauncherStateManager.StateHandler;
import com.android.launcher3.anim.PendingAnimation;
import com.android.launcher3.graphics.OverviewScrim;
import com.android.launcher3.statemanager.StateManager.StateHandler;
import com.android.launcher3.states.StateAnimationConfig;
import com.android.quickstep.views.RecentsView;
@ -49,7 +49,7 @@ import com.android.quickstep.views.RecentsView;
* @param <T> the recents view
*/
public abstract class BaseRecentsViewStateController<T extends RecentsView>
implements StateHandler {
implements StateHandler<LauncherState> {
protected final T mRecentsView;
protected final BaseQuickstepLauncher mLauncher;

View File

@ -18,14 +18,11 @@ package com.android.quickstep;
import android.annotation.TargetApi;
import android.content.Context;
import android.graphics.Rect;
import android.graphics.RectF;
import android.os.Build;
import android.util.Pair;
import android.view.MotionEvent;
import android.view.View;
import android.view.animation.Interpolator;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.UiThread;
@ -33,7 +30,6 @@ import com.android.launcher3.BaseDraggingActivity;
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.anim.AnimatorPlaybackController;
import com.android.launcher3.statehandlers.DepthController;
import com.android.launcher3.touch.PagedOrientationHandler;
import com.android.quickstep.util.ActivityInitListener;
import com.android.quickstep.util.ShelfPeekAnim;
import com.android.systemui.shared.recents.model.ThumbnailData;
@ -52,24 +48,13 @@ public interface BaseActivityInterface<T extends BaseDraggingActivity> {
int getSwipeUpDestinationAndLength(DeviceProfile dp, Context context, Rect outRect);
/**
* @return The progress of the swipe where we start resisting the user, where 0 is fullscreen
* and 1 is recents. These values should probably be greater than 1 to let the user swipe past
* recents before we start resisting them.
*/
default Pair<Float, Float> getSwipeUpPullbackStartAndMaxProgress() {
return new Pair<>(1.4f, 1.8f);
}
void onSwipeUpToRecentsComplete();
default void onSwipeUpToHomeComplete() { }
void onAssistantVisibilityChanged(float visibility);
@NonNull HomeAnimationFactory prepareHomeUI();
AnimationFactory prepareRecentsUI(boolean activityVisible, boolean animateActivity,
Consumer<AnimatorPlaybackController> callback);
AnimationFactory prepareRecentsUI(
boolean activityVisible, Consumer<AnimatorPlaybackController> callback);
ActivityInitListener createActivityInitListener(Predicate<Boolean> onInitListener);
@ -152,35 +137,4 @@ public interface BaseActivityInterface<T extends BaseDraggingActivity> {
*/
default void setRecentsAttachedToAppWindow(boolean attached, boolean animate) { }
}
interface HomeAnimationFactory {
/** Return the floating view that will animate in sync with the closing window. */
default @Nullable View getFloatingView() {
return null;
}
@NonNull RectF getWindowTargetRect();
@NonNull AnimatorPlaybackController createActivityAnimationToHome();
default void playAtomicAnimation(float velocity) {
// No-op
}
static RectF getDefaultWindowTargetRect(PagedOrientationHandler orientationHandler,
DeviceProfile dp) {
final int halfIconSize = dp.iconSizePx / 2;
float primaryDimension = orientationHandler
.getPrimaryValue(dp.availableWidthPx, dp.availableHeightPx);
float secondaryDimension = orientationHandler
.getSecondaryValue(dp.availableWidthPx, dp.availableHeightPx);
final float targetX = primaryDimension / 2f;
final float targetY = secondaryDimension - dp.hotseatBarSizePx;
// Fallback to animate to center of screen.
return new RectF(targetX - halfIconSize, targetY - halfIconSize,
targetX + halfIconSize, targetY + halfIconSize);
}
}
}

View File

@ -1,168 +0,0 @@
/*
* Copyright (C) 2019 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.quickstep;
import static android.content.pm.ActivityInfo.CONFIG_ORIENTATION;
import static android.content.pm.ActivityInfo.CONFIG_SCREEN_SIZE;
import android.content.Intent;
import android.content.res.Configuration;
import android.os.Bundle;
import com.android.launcher3.AbstractFloatingView;
import com.android.launcher3.BaseDraggingActivity;
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.InvariantDeviceProfile;
import com.android.launcher3.R;
import com.android.launcher3.util.ActivityTracker;
import com.android.launcher3.util.SystemUiController;
import com.android.launcher3.util.Themes;
import java.io.FileDescriptor;
import java.io.PrintWriter;
/**
* A base fallback recents activity that provides support for device profile changes, activity
* lifecycle tracking, and basic input handling from recents.
*
* This class is only used as a fallback in case the default launcher does not have a recents
* implementation.
*/
public abstract class BaseRecentsActivity extends BaseDraggingActivity {
public static final ActivityTracker<BaseRecentsActivity> ACTIVITY_TRACKER =
new ActivityTracker<>();
private Configuration mOldConfig;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mOldConfig = new Configuration(getResources().getConfiguration());
initDeviceProfile();
initViews();
getSystemUiController().updateUiState(SystemUiController.UI_STATE_BASE_WINDOW,
Themes.getAttrBoolean(this, R.attr.isWorkspaceDarkText));
ACTIVITY_TRACKER.handleCreate(this);
}
/**
* Init drag layer and overview panel views.
*/
abstract protected void initViews();
@Override
public void onConfigurationChanged(Configuration newConfig) {
int diff = newConfig.diff(mOldConfig);
if ((diff & (CONFIG_ORIENTATION | CONFIG_SCREEN_SIZE)) != 0) {
onHandleConfigChanged();
}
mOldConfig.setTo(newConfig);
super.onConfigurationChanged(newConfig);
}
/**
* Logic for when device configuration changes (rotation, screen size change, multi-window,
* etc.)
*/
protected void onHandleConfigChanged() {
mUserEventDispatcher = null;
initDeviceProfile();
AbstractFloatingView.closeOpenViews(this, true,
AbstractFloatingView.TYPE_ALL & ~AbstractFloatingView.TYPE_REBIND_SAFE);
dispatchDeviceProfileChanged();
reapplyUi();
}
/**
* Initialize/update the device profile.
*/
private void initDeviceProfile() {
mDeviceProfile = createDeviceProfile();
onDeviceProfileInitiated();
}
/**
* Generate the device profile to use in this activity.
* @return device profile
*/
protected DeviceProfile createDeviceProfile() {
DeviceProfile dp = InvariantDeviceProfile.INSTANCE.get(this).getDeviceProfile(this);
// In case we are reusing IDP, create a copy so that we don't conflict with Launcher
// activity.
return dp.copy(this);
}
@Override
protected void onStop() {
super.onStop();
// Workaround for b/78520668, explicitly trim memory once UI is hidden
onTrimMemory(TRIM_MEMORY_UI_HIDDEN);
}
@Override
public void onEnterAnimationComplete() {
super.onEnterAnimationComplete();
// After the transition to home, enable the high-res thumbnail loader if it wasn't enabled
// as a part of quickstep, so that high-res thumbnails can load the next time we enter
// overview
RecentsModel.INSTANCE.get(this).getThumbnailCache()
.getHighResLoadingState().setVisible(true);
}
@Override
public void onTrimMemory(int level) {
super.onTrimMemory(level);
RecentsModel.INSTANCE.get(this).onTrimMemory(level);
}
@Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
ACTIVITY_TRACKER.handleNewIntent(this, intent);
}
@Override
protected void onDestroy() {
super.onDestroy();
ACTIVITY_TRACKER.onActivityDestroyed(this);
}
@Override
public void onBackPressed() {
// TODO: Launch the task we came from
startHome();
}
public void startHome() {
startActivity(new Intent(Intent.ACTION_MAIN)
.addCategory(Intent.CATEGORY_HOME)
.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
}
@Override
public void dump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args) {
super.dump(prefix, fd, writer, args);
writer.println(prefix + "Misc:");
dumpMisc(prefix + "\t", writer);
}
}

View File

@ -110,10 +110,6 @@ public class GestureState implements RecentsAnimationCallbacks.RecentsAnimationL
public static final int STATE_RECENTS_SCROLLING_FINISHED =
getFlagForIndex("STATE_RECENTS_SCROLLING_FINISHED");
// Called when the new task appeared from quick switching.
public static final int STATE_TASK_APPEARED_DURING_SWITCH =
getFlagForIndex("STATE_TASK_APPEARED_DURING_SWITCH");
// Needed to interact with the current activity
private final Intent mHomeIntent;
private final Intent mOverviewIntent;
@ -123,9 +119,8 @@ public class GestureState implements RecentsAnimationCallbacks.RecentsAnimationL
private ActivityManager.RunningTaskInfo mRunningTask;
private GestureEndTarget mEndTarget;
private RemoteAnimationTargetCompat mAnimationTarget;
// TODO: This can be removed once we stop finishing the animation when starting a new task
private int mFinishingRecentsAnimationTaskId = -1;
private RemoteAnimationTargetCompat mLastAppearedTaskTarget;
private int mLastStartedTaskId = -1;
public GestureState(OverviewComponentObserver componentObserver, int gestureId) {
mHomeIntent = componentObserver.getHomeIntent();
@ -143,7 +138,8 @@ public class GestureState implements RecentsAnimationCallbacks.RecentsAnimationL
mGestureId = other.mGestureId;
mRunningTask = other.mRunningTask;
mEndTarget = other.mEndTarget;
mFinishingRecentsAnimationTaskId = other.mFinishingRecentsAnimationTaskId;
mLastAppearedTaskTarget = other.mLastAppearedTaskTarget;
mLastStartedTaskId = other.mLastStartedTaskId;
}
public GestureState() {
@ -225,6 +221,35 @@ public class GestureState implements RecentsAnimationCallbacks.RecentsAnimationL
mRunningTask = runningTask;
}
/**
* Updates the last task that appeared during this gesture.
*/
public void updateLastAppearedTaskTarget(RemoteAnimationTargetCompat lastAppearedTaskTarget) {
mLastAppearedTaskTarget = lastAppearedTaskTarget;
}
/**
* @return The id of the task that appeared during this gesture.
*/
public int getLastAppearedTaskId() {
return mLastAppearedTaskTarget != null ? mLastAppearedTaskTarget.taskId : -1;
}
/**
* Updates the last task that we started via startActivityFromRecents() during this gesture.
*/
public void updateLastStartedTaskId(int lastStartedTaskId) {
mLastStartedTaskId = lastStartedTaskId;
}
/**
* @return The id of the task that was most recently started during this gesture, or -1 if
* no task has been started yet (i.e. we haven't settled on a new task).
*/
public int getLastStartedTaskId() {
return mLastStartedTaskId;
}
/**
* @return the end target for this gesture (if known).
*/
@ -232,14 +257,6 @@ public class GestureState implements RecentsAnimationCallbacks.RecentsAnimationL
return mEndTarget;
}
public void setAnimationTarget(RemoteAnimationTargetCompat target) {
mAnimationTarget = target;
}
public RemoteAnimationTargetCompat getAnimationTarget() {
return mAnimationTarget;
}
/**
* Sets the end target of this gesture and immediately notifies the state changes.
*/
@ -259,30 +276,9 @@ public class GestureState implements RecentsAnimationCallbacks.RecentsAnimationL
}
}
/**
* @return the id for the task that was about to be launched following the finish of the recents
* animation. Only defined between when the finish-recents call was made and the launch
* activity call is made.
*/
public int getFinishingRecentsAnimationTaskId() {
return mFinishingRecentsAnimationTaskId;
}
/**
* Sets the id for the task will be launched after the recents animation is finished. Once the
* animation has finished then the id will be reset to -1.
*/
public void setFinishingRecentsAnimationTaskId(int taskId) {
mFinishingRecentsAnimationTaskId = taskId;
mStateCallback.runOnceAtState(STATE_RECENTS_ANIMATION_FINISHED, () -> {
mFinishingRecentsAnimationTaskId = -1;
});
}
/**
* @return whether the current gesture is still running a recents animation to a state in the
* Launcher or Recents activity.
* Updates the running task for the gesture to be the given {@param runningTask}.
*/
public boolean isRunningAnimationToLauncher() {
return isRecentsAnimationRunning() && mEndTarget != null && mEndTarget.isLauncher;
@ -314,18 +310,13 @@ public class GestureState implements RecentsAnimationCallbacks.RecentsAnimationL
mStateCallback.setState(STATE_RECENTS_ANIMATION_ENDED);
}
@Override
public void onTaskAppeared(RemoteAnimationTargetCompat app) {
mAnimationTarget = app;
mStateCallback.setState(STATE_TASK_APPEARED_DURING_SWITCH);
}
public void dump(PrintWriter pw) {
pw.println("GestureState:");
pw.println(" gestureID=" + mGestureId);
pw.println(" runningTask=" + mRunningTask);
pw.println(" endTarget=" + mEndTarget);
pw.println(" finishingRecentsAnimationTaskId=" + mFinishingRecentsAnimationTaskId);
pw.println(" lastAppearedTaskTarget=" + mLastAppearedTaskTarget);
pw.println(" lastStartedTaskId=" + mLastStartedTaskId);
pw.println(" isRecentsAnimationRunning=" + isRecentsAnimationRunning());
}
}

View File

@ -154,8 +154,7 @@ public class RecentTasksList extends TaskStackChangeListener {
* Loads and creates a list of all the recent tasks.
*/
@VisibleForTesting
ArrayList<Task> loadTasksInBackground(int numTasks,
boolean loadKeysOnly) {
ArrayList<Task> loadTasksInBackground(int numTasks, boolean loadKeysOnly) {
int currentUserId = Process.myUserHandle().getIdentifier();
ArrayList<Task> allTasks = new ArrayList<>();
List<ActivityManager.RecentTaskInfo> rawTasks =
@ -174,9 +173,7 @@ public class RecentTasksList extends TaskStackChangeListener {
}
};
int taskCount = rawTasks.size();
for (int i = 0; i < taskCount; i++) {
ActivityManager.RecentTaskInfo rawTask = rawTasks.get(i);
for (ActivityManager.RecentTaskInfo rawTask : rawTasks) {
Task.TaskKey taskKey = new Task.TaskKey(rawTask);
Task task;
if (!loadKeysOnly) {

View File

@ -159,6 +159,6 @@ public class RecentsAnimationCallbacks implements
/**
* Callback made when a task started from the recents is ready for an app transition.
*/
default void onTaskAppeared(RemoteAnimationTargetCompat app) {}
default void onTaskAppeared(RemoteAnimationTargetCompat appearedTaskTarget) {}
}
}

View File

@ -18,6 +18,7 @@ package com.android.quickstep;
import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
import static com.android.quickstep.GestureState.STATE_RECENTS_ANIMATION_INITIALIZED;
import static com.android.quickstep.GestureState.STATE_RECENTS_ANIMATION_STARTED;
import android.content.Intent;
import android.util.Log;
@ -28,6 +29,7 @@ import com.android.launcher3.Utilities;
import com.android.launcher3.config.FeatureFlags;
import com.android.systemui.shared.recents.model.ThumbnailData;
import com.android.systemui.shared.system.ActivityManagerWrapper;
import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
public class TaskAnimationManager implements RecentsAnimationCallbacks.RecentsAnimationListener {
@ -36,6 +38,7 @@ public class TaskAnimationManager implements RecentsAnimationCallbacks.RecentsAn
private RecentsAnimationTargets mTargets;
// Temporary until we can hook into gesture state events
private GestureState mLastGestureState;
private RemoteAnimationTargetCompat mLastAppearedTaskTarget;
/**
* Preloads the recents animation.
@ -79,6 +82,8 @@ public class TaskAnimationManager implements RecentsAnimationCallbacks.RecentsAn
}
mController = controller;
mTargets = targets;
mLastAppearedTaskTarget = mTargets.findTask(mLastGestureState.getRunningTaskId());
mLastGestureState.updateLastAppearedTaskTarget(mLastAppearedTaskTarget);
}
@Override
@ -96,6 +101,20 @@ public class TaskAnimationManager implements RecentsAnimationCallbacks.RecentsAn
public void onRecentsAnimationFinished(RecentsAnimationController controller) {
cleanUpRecentsAnimation(null /* canceledThumbnail */);
}
@Override
public void onTaskAppeared(RemoteAnimationTargetCompat appearedTaskTarget) {
if (mController != null) {
if (mLastAppearedTaskTarget == null
|| appearedTaskTarget.taskId != mLastAppearedTaskTarget.taskId) {
if (mLastAppearedTaskTarget != null) {
mController.removeTaskTarget(mLastAppearedTaskTarget);
}
mLastAppearedTaskTarget = appearedTaskTarget;
mLastGestureState.updateLastAppearedTaskTarget(mLastAppearedTaskTarget);
}
}
}
});
mCallbacks.addListener(gestureState);
mCallbacks.addListener(listener);
@ -112,6 +131,9 @@ public class TaskAnimationManager implements RecentsAnimationCallbacks.RecentsAn
mCallbacks.removeListener(mLastGestureState);
mLastGestureState = gestureState;
mCallbacks.addListener(gestureState);
gestureState.setState(STATE_RECENTS_ANIMATION_INITIALIZED
| STATE_RECENTS_ANIMATION_STARTED);
gestureState.updateLastAppearedTaskTarget(mLastAppearedTaskTarget);
return mCallbacks;
}
@ -171,6 +193,7 @@ public class TaskAnimationManager implements RecentsAnimationCallbacks.RecentsAn
mCallbacks = null;
mTargets = null;
mLastGestureState = null;
mLastAppearedTaskTarget = null;
}
public void dump() {

View File

@ -68,7 +68,7 @@ final class BackGestureTutorialController extends TutorialController {
@Override
Integer getActionButtonStringId() {
if (mTutorialType == BACK_NAVIGATION_COMPLETE) {
return R.string.gesture_tutorial_action_button_label;
return R.string.gesture_tutorial_action_button_label_done;
}
return null;
}
@ -76,7 +76,7 @@ final class BackGestureTutorialController extends TutorialController {
@Override
Integer getActionTextButtonStringId() {
if (mTutorialType == BACK_NAVIGATION_COMPLETE) {
return R.string.gesture_tutorial_action_text_button_label;
return R.string.gesture_tutorial_action_button_label_settings;
}
return null;
}
@ -89,7 +89,6 @@ final class BackGestureTutorialController extends TutorialController {
@Override
void onActionTextButtonClicked(View button) {
mTutorialFragment.startSystemNavigationSetting();
mTutorialFragment.closeTutorial();
}
@Override

View File

@ -60,7 +60,7 @@ final class HomeGestureTutorialController extends TutorialController {
@Override
Integer getActionButtonStringId() {
if (mTutorialType == HOME_NAVIGATION_COMPLETE) {
return R.string.gesture_tutorial_action_button_label;
return R.string.gesture_tutorial_action_button_label_done;
}
return null;
}

View File

@ -15,7 +15,6 @@
*/
package com.android.quickstep.interaction;
import android.content.ActivityNotFoundException;
import android.content.Intent;
import android.graphics.Insets;
import android.os.Bundle;
@ -35,8 +34,6 @@ import androidx.fragment.app.FragmentActivity;
import com.android.launcher3.R;
import com.android.quickstep.interaction.TutorialController.TutorialType;
import java.net.URISyntaxException;
abstract class TutorialFragment extends Fragment implements OnTouchListener {
private static final String LOG_TAG = "TutorialFragment";
@ -182,14 +179,6 @@ abstract class TutorialFragment extends Fragment implements OnTouchListener {
}
void startSystemNavigationSetting() {
try {
startActivityForResult(
Intent.parseUri(SYSTEM_NAVIGATION_SETTING_INTENT, /* flags= */ 0),
/* requestCode= */ 0);
} catch (URISyntaxException e) {
Log.e(LOG_TAG, "The launch Intent Uri is wrong syntax: " + e);
} catch (ActivityNotFoundException e) {
Log.e(LOG_TAG, "The launch Activity not found: " + e);
}
startActivity(new Intent("com.android.settings.GESTURE_NAVIGATION_SETTINGS"));
}
}

View File

@ -16,17 +16,17 @@
package com.android.quickstep.logging;
import static android.stats.launcher.nano.Launcher.ALLAPPS;
import static android.stats.launcher.nano.Launcher.BACKGROUND;
import static android.stats.launcher.nano.Launcher.HOME;
import static android.stats.launcher.nano.Launcher.OVERVIEW;
import static com.android.launcher3.logger.LauncherAtom.ContainerInfo.ContainerCase.FOLDER;
import static com.android.launcher3.logger.LauncherAtom.ItemInfo.ItemCase.WIDGET;
import android.content.Context;
import android.util.Log;
import com.android.launcher3.LauncherAppState;
import com.android.launcher3.Utilities;
import com.android.launcher3.logger.LauncherAtom;
import com.android.launcher3.logging.InstanceId;
import com.android.launcher3.logging.StatsLogManager;
import com.android.launcher3.logging.StatsLogUtils;
import com.android.launcher3.model.AllAppsList;
import com.android.launcher3.model.BaseModelUpdateTask;
import com.android.launcher3.model.BgDataModel;
@ -34,11 +34,13 @@ 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.util.IntSparseArrayMap;
import com.android.launcher3.util.LogConfig;
import com.android.systemui.shared.system.SysUiStatsLog;
import java.util.ArrayList;
/**
* This method calls the StatsLog hidden method until they are made available public.
* This class calls StatsLog compile time generated methods.
*
* To see if the logs are properly sent to statsd, execute following command.
* $ adb root && adb shell statsd
@ -47,29 +49,69 @@ import java.util.ArrayList;
*/
public class StatsLogCompatManager extends StatsLogManager {
private static final int SUPPORTED_TARGET_DEPTH = 2;
private static final String TAG = "StatsLog";
private static final boolean DEBUG = false;
private static final boolean IS_VERBOSE = Utilities.isPropertyEnabled(LogConfig.STATSLOG);
private static Context sContext;
private static final int DEFAULT_WIDGET_SPAN_XY = 1;
private static final int DEFAULT_WORKSPACE_GRID_XY = -1;
private static final int DEFAULT_PAGE_INDEX = -2;
private static final InstanceId DEFAULT_INSTANCE_ID = InstanceId.fakeInstanceId(0);
public StatsLogCompatManager(Context context) {
sContext = context;
}
/**
* Logs an event and accompanying {@link ItemInfo}
*/
public void log(LauncherEvent event, LauncherAtom.ItemInfo itemInfo) {
log(event, DEFAULT_INSTANCE_ID, itemInfo);
}
/**
* Logs an event and accompanying {@link LauncherAtom.ItemInfo}
*/
@Override
public void verify() {
if (!(StatsLogUtils.LAUNCHER_STATE_ALLAPPS == ALLAPPS
&& StatsLogUtils.LAUNCHER_STATE_BACKGROUND == BACKGROUND
&& StatsLogUtils.LAUNCHER_STATE_OVERVIEW == OVERVIEW
&& StatsLogUtils.LAUNCHER_STATE_HOME == HOME)) {
throw new IllegalStateException(
"StatsLogUtil constants doesn't match enums in launcher.proto");
public void log(LauncherEvent event, InstanceId instanceId, LauncherAtom.ItemInfo itemInfo) {
if (IS_VERBOSE) {
Log.d(TAG, String.format("\n%s\n%s", event.name(), itemInfo));
}
if (!Utilities.ATLEAST_R) {
return;
}
SysUiStatsLog.write(SysUiStatsLog.LAUNCHER_EVENT,
SysUiStatsLog.LAUNCHER_UICHANGED__ACTION__DEFAULT_ACTION /* deprecated */,
SysUiStatsLog.LAUNCHER_UICHANGED__DST_STATE__HOME /* TODO */,
SysUiStatsLog.LAUNCHER_UICHANGED__DST_STATE__BACKGROUND /* TODO */,
null /* launcher extensions, deprecated */,
false /* quickstep_enabled, deprecated */,
event.getId() /* event_id */,
itemInfo.getItemCase().getNumber() /* target_id */,
instanceId.getId() /* instance_id TODO */,
0 /* uid TODO */,
getPackageName(itemInfo) /* package_name */,
getComponentName(itemInfo) /* component_name */,
getGridX(itemInfo, false) /* grid_x */,
getGridY(itemInfo, false) /* grid_y */,
getPageId(itemInfo, false) /* page_id */,
getGridX(itemInfo, true) /* grid_x_parent */,
getGridY(itemInfo, true) /* grid_y_parent */,
getPageId(itemInfo, true) /* page_id_parent */,
getHierarchy(itemInfo) /* hierarchy */,
itemInfo.getIsWork() /* is_work_profile */,
itemInfo.getRank() /* rank */,
0 /* fromState */,
0 /* toState */,
null /* edittext */,
0 /* cardinality */);
}
/**
* Logs the workspace layout information on the model thread.
*/
@Override
public void logSnapshot() {
LauncherAppState.getInstance(sContext).getModel().enqueueModelUpdateTask(
new SnapshotWorker());
@ -84,18 +126,160 @@ public class StatsLogCompatManager extends StatsLogManager {
for (ItemInfo info : workspaceItems) {
LauncherAtom.ItemInfo atomInfo = info.buildProto(null);
// call StatsLog method
writeSnapshot(atomInfo);
}
for (FolderInfo fInfo : folders) {
for (ItemInfo info : fInfo.contents) {
LauncherAtom.ItemInfo atomInfo = info.buildProto(fInfo);
// call StatsLog method
writeSnapshot(atomInfo);
}
}
for (ItemInfo info : appWidgets) {
LauncherAtom.ItemInfo atomInfo = info.buildProto(null);
// call StatsLog method
writeSnapshot(atomInfo);
}
}
}
private static void writeSnapshot(LauncherAtom.ItemInfo itemInfo) {
if (IS_VERBOSE) {
Log.d(TAG, "\nwriteSnapshot:" + itemInfo);
}
if (!Utilities.ATLEAST_R) {
return;
}
SysUiStatsLog.write(SysUiStatsLog.LAUNCHER_SNAPSHOT,
0 /* event_id */,
itemInfo.getItemCase().getNumber() /* target_id */,
0 /* instance_id */,
0 /* uid */,
getPackageName(itemInfo) /* package_name */,
getComponentName(itemInfo) /* component_name */,
getGridX(itemInfo, false) /* grid_x */,
getGridY(itemInfo, false) /* grid_y */,
getPageId(itemInfo, false) /* page_id */,
getGridX(itemInfo, true) /* grid_x_parent */,
getGridY(itemInfo, true) /* grid_y_parent */,
getPageId(itemInfo, true) /* page_id_parent */,
getHierarchy(itemInfo) /* hierarchy */,
itemInfo.getIsWork() /* is_work_profile */,
0 /* origin TODO */,
0 /* cardinality */,
getSpanX(itemInfo),
getSpanY(itemInfo));
}
private static int getSpanX(LauncherAtom.ItemInfo atomInfo) {
if (atomInfo.getItemCase() != WIDGET) {
return DEFAULT_WIDGET_SPAN_XY;
}
return atomInfo.getWidget().getSpanX();
}
private static int getSpanY(LauncherAtom.ItemInfo atomInfo) {
if (atomInfo.getItemCase() != WIDGET) {
return DEFAULT_WIDGET_SPAN_XY;
}
return atomInfo.getWidget().getSpanY();
}
private static String getPackageName(LauncherAtom.ItemInfo atomInfo) {
switch (atomInfo.getItemCase()) {
case APPLICATION:
return atomInfo.getApplication().getPackageName();
case SHORTCUT:
return atomInfo.getShortcut().getShortcutName();
case WIDGET:
return atomInfo.getWidget().getPackageName();
case TASK:
return atomInfo.getTask().getPackageName();
default:
return null;
}
}
private static String getComponentName(LauncherAtom.ItemInfo atomInfo) {
switch (atomInfo.getItemCase()) {
case APPLICATION:
return atomInfo.getApplication().getComponentName();
case SHORTCUT:
return atomInfo.getShortcut().getShortcutName();
case WIDGET:
return atomInfo.getWidget().getComponentName();
case TASK:
return atomInfo.getTask().getComponentName();
default:
return null;
}
}
private static int getGridX(LauncherAtom.ItemInfo info, boolean parent) {
switch (info.getContainerInfo().getContainerCase()) {
case WORKSPACE:
if (parent) {
return DEFAULT_WORKSPACE_GRID_XY;
} else {
return info.getContainerInfo().getWorkspace().getGridX();
}
case FOLDER:
if (parent) {
switch (info.getContainerInfo().getFolder().getParentContainerCase()) {
case WORKSPACE:
return info.getContainerInfo().getFolder().getWorkspace().getGridX();
default:
return DEFAULT_WORKSPACE_GRID_XY;
}
} else {
return info.getContainerInfo().getFolder().getGridX();
}
default:
return DEFAULT_WORKSPACE_GRID_XY;
}
}
private static int getGridY(LauncherAtom.ItemInfo info, boolean parent) {
switch (info.getContainerInfo().getContainerCase()) {
case WORKSPACE:
if (parent) {
return DEFAULT_WORKSPACE_GRID_XY;
} else {
return info.getContainerInfo().getWorkspace().getGridY();
}
case FOLDER:
if (parent) {
switch (info.getContainerInfo().getFolder().getParentContainerCase()) {
case WORKSPACE:
return info.getContainerInfo().getFolder().getWorkspace().getGridY();
default:
return DEFAULT_WORKSPACE_GRID_XY;
}
} else {
return info.getContainerInfo().getFolder().getGridY();
}
default:
return DEFAULT_WORKSPACE_GRID_XY;
}
}
private static int getPageId(LauncherAtom.ItemInfo info, boolean parent) {
switch (info.getContainerInfo().getContainerCase()) {
case HOTSEAT:
return info.getContainerInfo().getHotseat().getIndex();
case WORKSPACE:
return info.getContainerInfo().getWorkspace().getPageIndex();
default:
return DEFAULT_PAGE_INDEX;
}
}
/**
*
*/
private static int getHierarchy(LauncherAtom.ItemInfo info) {
// TODO
if (info.getContainerInfo().getContainerCase() == FOLDER) {
return info.getContainerInfo().getFolder().getParentContainerCase().getNumber() + 100;
} else {
return info.getContainerInfo().getContainerCase().getNumber();
}
}
}

View File

@ -21,6 +21,8 @@ import static com.android.quickstep.util.WindowSizeStrategy.LAUNCHER_ACTIVITY_SI
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;
@ -66,4 +68,21 @@ public class LayoutUtils {
return srcHeight / targetHeight;
}
}
/**
* Recursively sets view and all children enabled/disabled.
* @param viewGroup Top most parent view to change.
* @param enabled True = enable, False = disable.
*/
public static void setViewEnabled(ViewGroup viewGroup, boolean enabled) {
viewGroup.setEnabled(enabled);
for (int i = 0; i < viewGroup.getChildCount(); i++) {
View child = viewGroup.getChildAt(i);
if (child instanceof ViewGroup) {
setViewEnabled((ViewGroup) child, enabled);
} else {
child.setEnabled(enabled);
}
}
}
}

View File

@ -19,11 +19,13 @@ import static com.android.launcher3.config.FeatureFlags.ENABLE_LSQ_VELOCITY_PROV
import android.content.Context;
import android.content.res.Resources;
import android.util.Log;
import android.view.MotionEvent;
import com.android.launcher3.Alarm;
import com.android.launcher3.R;
import com.android.launcher3.compat.AccessibilityManagerCompat;
import com.android.launcher3.testing.TestProtocol;
/**
* Given positions along x- or y-axis, tracks velocity and acceleration and determines when there is
@ -84,6 +86,9 @@ public class MotionPauseDetector {
mSpeedSlow = res.getDimension(R.dimen.motion_pause_detector_speed_slow);
mSpeedSomewhatFast = res.getDimension(R.dimen.motion_pause_detector_speed_somewhat_fast);
mSpeedFast = res.getDimension(R.dimen.motion_pause_detector_speed_fast);
if (TestProtocol.sDebugTracing) {
Log.d(TestProtocol.PAUSE_NOT_DETECTED, "creating alarm");
}
mForcePauseTimeout = new Alarm();
mForcePauseTimeout.setOnAlarmListener(alarm -> updatePaused(true /* isPaused */));
mMakePauseHarderToTrigger = makePauseHarderToTrigger;
@ -120,6 +125,9 @@ public class MotionPauseDetector {
* @param pointerIndex Index for the pointer being tracked in the motion event
*/
public void addPosition(MotionEvent ev, int pointerIndex) {
if (TestProtocol.sDebugTracing) {
Log.d(TestProtocol.PAUSE_NOT_DETECTED, "setting alarm");
}
mForcePauseTimeout.setAlarm(mMakePauseHarderToTrigger
? HARDER_TRIGGER_TIMEOUT
: FORCE_PAUSE_TIMEOUT);
@ -167,6 +175,9 @@ public class MotionPauseDetector {
}
private void updatePaused(boolean isPaused) {
if (TestProtocol.sDebugTracing) {
Log.d(TestProtocol.PAUSE_NOT_DETECTED, "updatePaused: " + isPaused);
}
if (mDisallowPause) {
isPaused = false;
}
@ -188,6 +199,9 @@ public class MotionPauseDetector {
setOnMotionPauseListener(null);
mIsPaused = mHasEverBeenPaused = false;
mSlowStartTime = 0;
if (TestProtocol.sDebugTracing) {
Log.d(TestProtocol.PAUSE_NOT_DETECTED, "canceling alarm");
}
mForcePauseTimeout.cancelAlarm();
}

View File

@ -25,8 +25,8 @@ import android.content.SharedPreferences;
import com.android.launcher3.BaseQuickstepLauncher;
import com.android.launcher3.LauncherState;
import com.android.launcher3.LauncherStateManager;
import com.android.launcher3.LauncherStateManager.StateListener;
import com.android.launcher3.statemanager.StateManager;
import com.android.launcher3.statemanager.StateManager.StateListener;
import com.android.launcher3.util.OnboardingPrefs;
import com.android.quickstep.SysUINavigationMode;
@ -35,23 +35,23 @@ import com.android.quickstep.SysUINavigationMode;
*/
public class QuickstepOnboardingPrefs extends OnboardingPrefs<BaseQuickstepLauncher> {
public QuickstepOnboardingPrefs(BaseQuickstepLauncher launcher, SharedPreferences sharedPrefs,
LauncherStateManager stateManager) {
super(launcher, sharedPrefs, stateManager);
public QuickstepOnboardingPrefs(BaseQuickstepLauncher launcher, SharedPreferences sharedPrefs) {
super(launcher, sharedPrefs);
StateManager<LauncherState> stateManager = launcher.getStateManager();
if (!getBoolean(HOME_BOUNCE_SEEN)) {
mStateManager.addStateListener(new StateListener() {
stateManager.addStateListener(new StateListener<LauncherState>() {
@Override
public void onStateTransitionComplete(LauncherState finalState) {
boolean swipeUpEnabled = SysUINavigationMode.INSTANCE
.get(mLauncher).getMode().hasGestures;
LauncherState prevState = mStateManager.getLastState();
LauncherState prevState = stateManager.getLastState();
if (((swipeUpEnabled && finalState == OVERVIEW) || (!swipeUpEnabled
&& finalState == ALL_APPS && prevState == NORMAL) ||
hasReachedMaxCount(HOME_BOUNCE_COUNT))) {
mSharedPrefs.edit().putBoolean(HOME_BOUNCE_SEEN, true).apply();
mStateManager.removeStateListener(this);
stateManager.removeStateListener(this);
}
}
});
@ -65,27 +65,27 @@ public class QuickstepOnboardingPrefs extends OnboardingPrefs<BaseQuickstepLaunc
mSharedPrefs.edit().putBoolean(SHELF_BOUNCE_SEEN, shelfBounceSeen).apply();
}
if (!shelfBounceSeen) {
mStateManager.addStateListener(new StateListener() {
stateManager.addStateListener(new StateListener<LauncherState>() {
@Override
public void onStateTransitionComplete(LauncherState finalState) {
LauncherState prevState = mStateManager.getLastState();
LauncherState prevState = stateManager.getLastState();
if ((finalState == ALL_APPS && prevState == OVERVIEW) ||
hasReachedMaxCount(SHELF_BOUNCE_COUNT)) {
mSharedPrefs.edit().putBoolean(SHELF_BOUNCE_SEEN, true).apply();
mStateManager.removeStateListener(this);
stateManager.removeStateListener(this);
}
}
});
}
if (!hasReachedMaxCount(ALL_APPS_COUNT)) {
mStateManager.addStateListener(new StateListener() {
stateManager.addStateListener(new StateListener<LauncherState>() {
@Override
public void onStateTransitionComplete(LauncherState finalState) {
if (finalState == ALL_APPS) {
if (incrementEventCount(ALL_APPS_COUNT)) {
mStateManager.removeStateListener(this);
stateManager.removeStateListener(this);
mLauncher.getScrimView().updateDragHandleVisibility();
}
}

View File

@ -23,6 +23,7 @@ import static android.view.Surface.ROTATION_180;
import static android.view.Surface.ROTATION_270;
import static android.view.Surface.ROTATION_90;
import static com.android.launcher3.logging.LoggerUtils.extractObjectNameAndAddress;
import static com.android.launcher3.states.RotationHelper.ALLOW_ROTATION_PREFERENCE_KEY;
import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
@ -36,7 +37,6 @@ import android.database.ContentObserver;
import android.graphics.Matrix;
import android.graphics.PointF;
import android.graphics.Rect;
import android.graphics.RectF;
import android.os.Handler;
import android.provider.Settings;
import android.util.Log;
@ -51,6 +51,7 @@ import com.android.launcher3.DeviceProfile;
import com.android.launcher3.Utilities;
import com.android.launcher3.testing.TestProtocol;
import com.android.launcher3.touch.PagedOrientationHandler;
import com.android.launcher3.util.WindowBounds;
import java.lang.annotation.Retention;
import java.util.function.IntConsumer;
@ -84,7 +85,7 @@ public final class RecentsOrientedState implements SharedPreferences.OnSharedPre
private @SurfaceRotation int mTouchRotation = ROTATION_0;
private @SurfaceRotation int mDisplayRotation = ROTATION_0;
private @SurfaceRotation int mLauncherRotation = Surface.ROTATION_0;
private @SurfaceRotation int mLauncherRotation = ROTATION_0;
// Launcher activity supports multiple orientation, but fallback activity does not
private static final int FLAG_MULTIPLE_ORIENTATION_SUPPORTED_BY_ACTIVITY = 1 << 0;
@ -102,6 +103,8 @@ public final class RecentsOrientedState implements SharedPreferences.OnSharedPre
private static final int FLAG_ROTATION_WATCHER_SUPPORTED = 1 << 6;
// Whether to enable rotation watcher when multi-rotation is supported
private static final int FLAG_ROTATION_WATCHER_ENABLED = 1 << 7;
// Enable home rotation for UI tests, ignoring home rotation value from prefs
private static final int FLAG_HOME_ROTATION_FORCE_ENABLED_FOR_TESTING = 1 << 8;
private static final int MASK_MULTIPLE_ORIENTATION_SUPPORTED_BY_DEVICE =
FLAG_MULTIPLE_ORIENTATION_SUPPORTED_BY_ACTIVITY
@ -121,7 +124,6 @@ public final class RecentsOrientedState implements SharedPreferences.OnSharedPre
private final WindowSizeStrategy mSizeStrategy;
private final Matrix mTmpMatrix = new Matrix();
private final Matrix mTmpInverseMatrix = new Matrix();
private int mFlags;
private int mPreviousRotation = ROTATION_0;
@ -163,6 +165,10 @@ public final class RecentsOrientedState implements SharedPreferences.OnSharedPre
if (mOrientationListener.canDetectOrientation()) {
mFlags |= FLAG_ROTATION_WATCHER_SUPPORTED;
}
// initialize external flags
updateAutoRotateSetting();
updateHomeRotationSetting();
}
/**
@ -181,13 +187,15 @@ public final class RecentsOrientedState implements SharedPreferences.OnSharedPre
* false otherwise
*/
public boolean update(
@SurfaceRotation int touchRotation, @SurfaceRotation int displayRotation,
@SurfaceRotation int launcherRotation) {
@SurfaceRotation int touchRotation, @SurfaceRotation int displayRotation) {
if (!isMultipleOrientationSupportedByDevice()) {
return false;
}
if (mDisplayRotation == displayRotation && mTouchRotation == touchRotation
&& launcherRotation == mLauncherRotation) {
int launcherRotation = inferLauncherRotation(displayRotation);
if (mDisplayRotation == displayRotation
&& mTouchRotation == touchRotation
&& mLauncherRotation == launcherRotation) {
return false;
}
@ -195,11 +203,10 @@ public final class RecentsOrientedState implements SharedPreferences.OnSharedPre
mDisplayRotation = displayRotation;
mTouchRotation = touchRotation;
if (canLauncherRotate() || mLauncherRotation == mTouchRotation) {
// TODO(b/153476489) Need to determine when launcher is rotated
if (mLauncherRotation == mTouchRotation) {
mOrientationHandler = PagedOrientationHandler.HOME_ROTATED;
if (DEBUG) {
Log.d(TAG, "Set Orientation Handler: " + mOrientationHandler);
Log.d(TAG, "current RecentsOrientedState: " + this);
}
return true;
}
@ -212,11 +219,20 @@ public final class RecentsOrientedState implements SharedPreferences.OnSharedPre
mOrientationHandler = PagedOrientationHandler.PORTRAIT;
}
if (DEBUG) {
Log.d(TAG, "Set Orientation Handler: " + mOrientationHandler);
Log.d(TAG, "current RecentsOrientedState: " + this);
}
return true;
}
@SurfaceRotation
private int inferLauncherRotation(@SurfaceRotation int displayRotation) {
if (!isMultipleOrientationSupportedByDevice() || isHomeRotationAllowed()) {
return displayRotation;
} else {
return ROTATION_0;
}
}
private void setFlag(int mask, boolean enabled) {
boolean wasRotationEnabled = !TestProtocol.sDisableSensorRotation
&& mFlags == VALUE_ROTATION_WATCHER_ENABLED;
@ -241,7 +257,9 @@ public final class RecentsOrientedState implements SharedPreferences.OnSharedPre
@Override
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String s) {
updateHomeRotationSetting();
if (ALLOW_ROTATION_PREFERENCE_KEY.equals(s)) {
updateHomeRotationSetting();
}
}
private void updateAutoRotateSetting() {
@ -255,23 +273,24 @@ public final class RecentsOrientedState implements SharedPreferences.OnSharedPre
}
/**
* Initializes aany system values and registers corresponding change listeners. It must be
* paired with {@link #destroy()} call
* Initializes any system values and registers corresponding change listeners. It must be
* paired with {@link #destroyListeners()} call
*/
public void init() {
public void initListeners() {
if (isMultipleOrientationSupportedByDevice()) {
mSharedPrefs.registerOnSharedPreferenceChangeListener(this);
mContentResolver.registerContentObserver(
Settings.System.getUriFor(Settings.System.ACCELEROMETER_ROTATION),
false, mSystemAutoRotateObserver);
}
initWithoutListeners();
updateAutoRotateSetting();
updateHomeRotationSetting();
}
/**
* Unregisters any previously registered listeners.
*/
public void destroy() {
public void destroyListeners() {
if (isMultipleOrientationSupportedByDevice()) {
mSharedPrefs.unregisterOnSharedPreferenceChangeListener(this);
mContentResolver.unregisterContentObserver(mSystemAutoRotateObserver);
@ -279,13 +298,8 @@ public final class RecentsOrientedState implements SharedPreferences.OnSharedPre
setRotationWatcherEnabled(false);
}
/**
* Initializes the OrientationState without attaching any listeners. This can be used when
* the object is short lived.
*/
public void initWithoutListeners() {
updateAutoRotateSetting();
updateHomeRotationSetting();
public void forceAllowRotationForTesting(boolean forceAllow) {
setFlag(FLAG_HOME_ROTATION_FORCE_ENABLED_FOR_TESTING, forceAllow);
}
@SurfaceRotation
@ -310,7 +324,8 @@ public final class RecentsOrientedState implements SharedPreferences.OnSharedPre
public boolean isHomeRotationAllowed() {
return (mFlags & (FLAG_HOME_ROTATION_ALLOWED_IN_PREFS | FLAG_MULTIWINDOW_ROTATION_ALLOWED))
!= 0;
!= 0 ||
(mFlags & FLAG_HOME_ROTATION_FORCE_ENABLED_FOR_TESTING) != 0;
}
public boolean canLauncherRotate() {
@ -347,7 +362,8 @@ public final class RecentsOrientedState implements SharedPreferences.OnSharedPre
float fullHeight = dp.heightPx - insets.top - insets.bottom;
if (dp.isMultiWindowMode) {
mSizeStrategy.getMultiWindowSize(mContext, dp, outPivot);
WindowBounds bounds = SplitScreenBounds.INSTANCE.getSecondaryWindowBounds(mContext);
outPivot.set(bounds.availableSize.x, bounds.availableSize.y);
} else {
outPivot.set(fullWidth, fullHeight);
}
@ -403,23 +419,6 @@ public final class RecentsOrientedState implements SharedPreferences.OnSharedPre
*/
}
public void mapRectFromNormalOrientation(RectF src, int screenWidth, int screenHeight) {
mapRectFromRotation(mDisplayRotation, src, screenWidth, screenHeight);
}
public void mapRectFromRotation(int rotation, RectF src, int screenWidth, int screenHeight) {
mTmpMatrix.reset();
postDisplayRotation(rotation, screenWidth, screenHeight, mTmpMatrix);
mTmpMatrix.mapRect(src);
}
public void mapInverseRectFromNormalOrientation(RectF src, int screenWidth, int screenHeight) {
mTmpMatrix.reset();
postDisplayRotation(mDisplayRotation, screenWidth, screenHeight, mTmpMatrix);
mTmpMatrix.invert(mTmpInverseMatrix);
mTmpInverseMatrix.mapRect(src);
}
@SurfaceRotation
public static int getRotationForUserDegreesRotated(float degrees, int currentRotation) {
if (degrees == ORIENTATION_UNKNOWN) {
@ -440,9 +439,13 @@ public final class RecentsOrientedState implements SharedPreferences.OnSharedPre
if (degrees < (90 - threshold)) {
return ROTATION_0;
}
if (degrees > (90 + threshold)) {
if (degrees > (90 + threshold) && degrees < 180) {
return ROTATION_180;
}
// flip from seascape to landscape
if (degrees > (180 + threshold) && degrees < 360) {
return ROTATION_90;
}
break;
case ROTATION_180:
if (degrees < (180 - threshold)) {
@ -453,12 +456,16 @@ public final class RecentsOrientedState implements SharedPreferences.OnSharedPre
}
break;
case ROTATION_90:
if (degrees < (270 - threshold)) {
if (degrees < (270 - threshold) && degrees > 90) {
return ROTATION_180;
}
if (degrees > (270 + threshold)) {
if (degrees > (270 + threshold) && degrees < 360) {
return ROTATION_0;
}
// flip from landscape to seascape
if (degrees > threshold && degrees < 180) {
return ROTATION_270;
}
break;
}
@ -506,13 +513,15 @@ public final class RecentsOrientedState implements SharedPreferences.OnSharedPre
public String toString() {
boolean systemRotationOn = (mFlags & FLAG_SYSTEM_ROTATION_ALLOWED) != 0;
return "["
+ "mDisplayRotation=" + mDisplayRotation
+ "this=" + extractObjectNameAndAddress(super.toString())
+ " mOrientationHandler=" +
extractObjectNameAndAddress(mOrientationHandler.toString())
+ " mDisplayRotation=" + mDisplayRotation
+ " mTouchRotation=" + mTouchRotation
+ " mLauncherRotation=" + mLauncherRotation
+ " mHomeRotation=" + isHomeRotationAllowed()
+ " mSystemRotation=" + systemRotationOn
+ " mFlags=" + mFlags
+ " mOrientationHandler=" + mOrientationHandler
+ "]";
}
}

View File

@ -0,0 +1,112 @@
/*
* Copyright (C) 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.quickstep.util;
import static android.view.Surface.ROTATION_0;
import static android.view.Surface.ROTATION_180;
import android.annotation.TargetApi;
import android.content.Context;
import android.graphics.Insets;
import android.graphics.Rect;
import android.os.Build;
import android.view.WindowInsets.Type;
import android.view.WindowManager;
import android.view.WindowMetrics;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.UiThread;
import com.android.launcher3.R;
import com.android.launcher3.util.DefaultDisplay;
import com.android.launcher3.util.WindowBounds;
import java.util.ArrayList;
/**
* Utility class to hold the information abound a window bounds for split screen
*/
@TargetApi(Build.VERSION_CODES.R)
public class SplitScreenBounds {
public static final SplitScreenBounds INSTANCE = new SplitScreenBounds();
private final ArrayList<OnChangeListener> mListeners = new ArrayList<>();
@Nullable
private WindowBounds mBounds;
private SplitScreenBounds() { }
@UiThread
public void setSecondaryWindowBounds(@NonNull WindowBounds bounds) {
if (!bounds.equals(mBounds)) {
mBounds = bounds;
for (OnChangeListener listener : mListeners) {
listener.onSecondaryWindowBoundsChanged();
}
}
}
public @NonNull WindowBounds getSecondaryWindowBounds(Context context) {
if (mBounds == null) {
mBounds = createDefaultWindowBounds(context);
}
return mBounds;
}
/**
* Creates window bounds as 50% of device size
*/
private static WindowBounds createDefaultWindowBounds(Context context) {
WindowMetrics wm = context.getSystemService(WindowManager.class).getMaximumWindowMetrics();
Insets insets = wm.getWindowInsets().getInsets(Type.systemBars());
WindowBounds bounds = new WindowBounds(wm.getBounds(),
new Rect(insets.left, insets.top, insets.right, insets.bottom));
int rotation = DefaultDisplay.INSTANCE.get(context).getInfo().rotation;
int halfDividerSize = context.getResources()
.getDimensionPixelSize(R.dimen.multi_window_task_divider_size) / 2;
if (rotation == ROTATION_0 || rotation == ROTATION_180) {
bounds.bounds.top = bounds.insets.top + bounds.availableSize.y / 2 + halfDividerSize;
bounds.insets.top = 0;
} else {
bounds.bounds.left = bounds.insets.left + bounds.availableSize.x / 2 + halfDividerSize;
bounds.insets.left = 0;
}
return new WindowBounds(bounds.bounds, bounds.insets);
}
public void addOnChangeListener(OnChangeListener listener) {
mListeners.add(listener);
}
public void removeOnChangeListener(OnChangeListener listener) {
mListeners.remove(listener);
}
/**
* Interface to receive window bounds changes
*/
public interface OnChangeListener {
/**
* Called when window bounds for secondary window changes
*/
void onSecondaryWindowBoundsChanged();
}
}

View File

@ -16,36 +16,35 @@
package com.android.quickstep.util;
import static com.android.launcher3.config.FeatureFlags.ENABLE_OVERVIEW_ACTIONS;
import static com.android.quickstep.SysUINavigationMode.getMode;
import static com.android.quickstep.SysUINavigationMode.removeShelfFromOverview;
import static com.android.quickstep.util.LayoutUtils.getDefaultSwipeHeight;
import android.annotation.TargetApi;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.PointF;
import android.graphics.Rect;
import android.os.Build;
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.R;
import com.android.launcher3.util.WindowBounds;
import com.android.quickstep.SysUINavigationMode.Mode;
/**
* Utility class to wrap different layout behavior for Launcher and RecentsView
* TODO: Merge is with {@link com.android.quickstep.BaseActivityInterface} once we remove the
* state dependent members from {@link com.android.quickstep.LauncherActivityInterface}
*/
@TargetApi(Build.VERSION_CODES.R)
public abstract class WindowSizeStrategy {
private final PointF mTempPoint = new PointF();
public final boolean rotationSupportedByActivity;
private WindowSizeStrategy(boolean rotationSupportedByActivity) {
this.rotationSupportedByActivity = rotationSupportedByActivity;
}
/**
* Sets the expected window size in multi-window mode
*/
public abstract void getMultiWindowSize(Context context, DeviceProfile dp, PointF out);
/**
* Calculates the taskView size for the provided device configuration
*/
@ -57,35 +56,41 @@ public abstract class WindowSizeStrategy {
private void calculateTaskSize(
Context context, DeviceProfile dp, float extraVerticalSpace, Rect outRect) {
float taskWidth, taskHeight, paddingHorz;
Resources res = context.getResources();
Rect insets = dp.getInsets();
final boolean showLargeTaskSize = showOverviewActions(context);
final int paddingResId;
if (dp.isMultiWindowMode) {
getMultiWindowSize(context, dp, mTempPoint);
taskWidth = mTempPoint.x;
taskHeight = mTempPoint.y;
paddingHorz = res.getDimension(R.dimen.multi_window_task_card_horz_space);
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;
}
float paddingHorz = res.getDimension(paddingResId);
float paddingVert = showLargeTaskSize
? 0 : res.getDimension(R.dimen.task_card_vert_space);
calculateTaskSizeInternal(context, dp, extraVerticalSpace, paddingHorz, paddingVert,
res.getDimension(R.dimen.task_thumbnail_top_margin), outRect);
}
private void calculateTaskSizeInternal(Context context, DeviceProfile dp,
float extraVerticalSpace, float paddingHorz, float paddingVert, float topIconMargin,
Rect outRect) {
float taskWidth, taskHeight;
Rect insets = dp.getInsets();
if (dp.isMultiWindowMode) {
WindowBounds bounds = SplitScreenBounds.INSTANCE.getSecondaryWindowBounds(context);
taskWidth = bounds.availableSize.x;
taskHeight = bounds.availableSize.y;
} else {
taskWidth = dp.availableWidthPx;
taskHeight = dp.availableHeightPx;
final int paddingResId;
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;
}
paddingHorz = res.getDimension(paddingResId);
}
float topIconMargin = res.getDimension(R.dimen.task_thumbnail_top_margin);
float paddingVert = showLargeTaskSize
? 0 : res.getDimension(R.dimen.task_card_vert_space);
// Note this should be same as dp.availableWidthPx and dp.availableHeightPx unless
// we override the insets ourselves.
int launcherVisibleWidth = dp.widthPx - insets.left - insets.right;
@ -107,26 +112,41 @@ public abstract class WindowSizeStrategy {
Math.round(x) + Math.round(outWidth), Math.round(y) + Math.round(outHeight));
}
/**
* Calculates the modal taskView size for the provided device configuration
*/
public void calculateModalTaskSize(Context context, DeviceProfile dp, Rect outRect) {
float paddingHorz = context.getResources().getDimension(dp.isMultiWindowMode
? R.dimen.multi_window_task_card_horz_space
: dp.isVerticalBarLayout()
? R.dimen.landscape_task_card_horz_space
: R.dimen.portrait_modal_task_card_horz_space);
float extraVerticalSpace = getOverviewActionsHeight(context);
float paddingVert = 0;
float topIconMargin = 0;
calculateTaskSizeInternal(context, dp, extraVerticalSpace, paddingHorz, paddingVert,
topIconMargin, outRect);
}
/** Gets the space that the overview actions will take, including margins. */
public float getOverviewActionsHeight(Context context) {
Resources res = context.getResources();
float actionsBottomMargin = 0;
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 overviewActionsHeight = actionsBottomMargin
+ res.getDimensionPixelSize(R.dimen.overview_actions_height);
return overviewActionsHeight;
}
public static final WindowSizeStrategy LAUNCHER_ACTIVITY_SIZE_STRATEGY =
new WindowSizeStrategy(true) {
@Override
public void getMultiWindowSize(Context context, DeviceProfile dp, PointF out) {
DeviceProfile fullDp = dp.getFullScreenProfile();
// Use availableWidthPx and availableHeightPx instead of widthPx and heightPx to
// account for system insets
out.set(fullDp.availableWidthPx, fullDp.availableHeightPx);
float halfDividerSize = context.getResources()
.getDimension(R.dimen.multi_window_task_divider_size) / 2;
if (fullDp.isLandscape) {
out.x = out.x / 2 - halfDividerSize;
} else {
out.y = out.y / 2 - halfDividerSize;
}
}
@Override
float getExtraSpace(Context context, DeviceProfile dp) {
if (dp.isVerticalBarLayout()) {
@ -136,7 +156,7 @@ public abstract class WindowSizeStrategy {
if (showOverviewActions(context)) {
//TODO: this needs to account for the swipe gesture height and accessibility
// UI when shown.
return res.getDimensionPixelSize(R.dimen.overview_actions_height);
return getOverviewActionsHeight(context);
} else {
return getDefaultSwipeHeight(context, dp) + dp.workspacePageIndicatorHeight
+ res.getDimensionPixelSize(
@ -150,10 +170,6 @@ public abstract class WindowSizeStrategy {
public static final WindowSizeStrategy FALLBACK_RECENTS_SIZE_STRATEGY =
new WindowSizeStrategy(false) {
@Override
public void getMultiWindowSize(Context context, DeviceProfile dp, PointF out) {
out.set(dp.widthPx, dp.heightPx);
}
@Override
float getExtraSpace(Context context, DeviceProfile dp) {

View File

@ -42,6 +42,7 @@ import com.android.launcher3.ui.TaplTestsLauncher3;
import com.android.quickstep.NavigationModeSwitchRule.NavigationModeSwitch;
import com.android.quickstep.views.RecentsView;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@ -53,6 +54,18 @@ public class TaplTestsQuickstep extends AbstractQuickStepTest {
public void setUp() throws Exception {
super.setUp();
TaplTestsLauncher3.initialize(this);
executeOnLauncher(launcher -> {
RecentsView recentsView = launcher.getOverviewPanel();
recentsView.getPagedViewOrientedState().forceAllowRotationForTesting(true);
});
}
@After
public void tearDown() {
executeOnLauncher(launcher -> {
RecentsView recentsView = launcher.getOverviewPanel();
recentsView.getPagedViewOrientedState().forceAllowRotationForTesting(false);
});
}
private void startTestApps() throws Exception {

View File

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:alpha="1"
android:color="?attr/workspaceTextColor"
android:state_enabled="true" />
<item
android:alpha="?android:disabledAlpha"
android:color="?attr/workspaceTextColor"
android:state_enabled="false" />
</selector>

View File

@ -23,13 +23,13 @@
android:layout_width="match_parent"
android:layout_height="32dp"
android:background="@drawable/bottom_sheet_top_border"
android:backgroundTint="?android:attr/colorAccent" />
android:backgroundTint="?attr/eduHalfSheetBGColor" />
<LinearLayout
android:id="@+id/view_wrapper"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?android:attr/colorAccent"
android:background="?attr/eduHalfSheetBGColor"
android:orientation="vertical"
android:paddingLeft="@dimen/bottom_sheet_edu_padding"
android:paddingRight="@dimen/bottom_sheet_edu_padding">

View File

@ -131,7 +131,7 @@
<string name="accessibility_close" msgid="2277148124685870734">"بستن"</string>
<string name="notification_dismissed" msgid="6002233469409822874">"اعلان رد شد"</string>
<string name="all_apps_personal_tab" msgid="4190252696685155002">"شخصی"</string>
<string name="all_apps_work_tab" msgid="4884822796154055118">"محل کار"</string>
<string name="all_apps_work_tab" msgid="4884822796154055118">"کاری"</string>
<string name="work_profile_toggle_label" msgid="3081029915775481146">"نمایه کاری"</string>
<string name="work_profile_edu_personal_apps" msgid="4155536355149317441">"داده‌های شخصی از برنامه‌های کاری جدا است و از آن پنهان است"</string>
<string name="work_profile_edu_work_apps" msgid="237051938268703058">"برنامه‌های کاری و داده‌ها برای سرپرست فناوری اطلاعات نمایان هستند"</string>

View File

@ -20,7 +20,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_name" msgid="649227358658669779">"Launcher3"</string>
<string name="work_folder_name" msgid="3753320833950115786">"કાર્યાલય"</string>
<string name="work_folder_name" msgid="3753320833950115786">"ઑફિસ"</string>
<string name="activity_not_found" msgid="8071924732094499514">"ઍપ્લિકેશન ઇન્સ્ટોલ થઈ નથી."</string>
<string name="activity_not_available" msgid="7456344436509528827">"ઍપ્લિકેશન ઉપલબ્ધ નથી"</string>
<string name="safemode_shortcut_error" msgid="9160126848219158407">"સુરક્ષિત મોડમાં ડાઉનલોડ કરેલ ઍપ્લિકેશન અક્ષમ કરી"</string>
@ -131,7 +131,7 @@
<string name="accessibility_close" msgid="2277148124685870734">"બંધ કરો"</string>
<string name="notification_dismissed" msgid="6002233469409822874">"સૂચના છોડી દીધી"</string>
<string name="all_apps_personal_tab" msgid="4190252696685155002">"મનગમતી ઍપ"</string>
<string name="all_apps_work_tab" msgid="4884822796154055118">"કાર્યાલયની ઍપ"</string>
<string name="all_apps_work_tab" msgid="4884822796154055118">"ઑફિસની ઍપ"</string>
<string name="work_profile_toggle_label" msgid="3081029915775481146">"ઑફિસની પ્રોફાઇલ"</string>
<string name="work_profile_edu_personal_apps" msgid="4155536355149317441">"વ્યક્તિગત ડેટા ઑફિસ માટેની ઍપથી અલગ અને છુપાવીને રાખેલો છે"</string>
<string name="work_profile_edu_work_apps" msgid="237051938268703058">"ઑફિસ માટેની ઍપ અને ડેટા તમારા IT વ્યવસ્થાપકને દેખાય છે"</string>

View File

@ -53,11 +53,11 @@
<string name="app_info_drop_target_label" msgid="692894985365717661">"अनुप्रयोगको जानकारी"</string>
<string name="install_drop_target_label" msgid="2539096853673231757">"स्थापना गर्नुहोस्"</string>
<string name="permlab_install_shortcut" msgid="5632423390354674437">"सर्टकट स्थापना गर्नेहोस्"</string>
<string name="permdesc_install_shortcut" msgid="923466509822011139">"प्रयोगकर्ताको हस्तक्षेप बिना एउटा अनुप्रयोगलाई सर्टकटमा थप्नको लागि अनुमति दिनुहोस्।"</string>
<string name="permdesc_install_shortcut" msgid="923466509822011139">"प्रयोगकर्ताको हस्तक्षेप बिना एउटा एपलाई सर्टकटमा थप्नको लागि अनुमति दिनुहोस्।"</string>
<string name="permlab_read_settings" msgid="1941457408239617576">"गृह सेटिङहरू र सर्टकटहरू पढ्नुहोस्"</string>
<string name="permdesc_read_settings" msgid="5833423719057558387">"गृहमा एउटा अनुप्रयोगलाई सेटिङहरू र सर्टकटहरू पढ्न अनुमति दिनुहोस्।"</string>
<string name="permdesc_read_settings" msgid="5833423719057558387">"गृहमा एउटा एपलाई सेटिङहरू र सर्टकटहरू पढ्न अनुमति दिनुहोस्।"</string>
<string name="permlab_write_settings" msgid="3574213698004620587">"गृह सेटिङहरू र सर्टकटहरू लेख्नुहोस्"</string>
<string name="permdesc_write_settings" msgid="5440712911516509985">"गृहमा एउटा अनुप्रयोगलाई सेटिङ र सर्टकट बदल्न अनुमति दिनुहोस्।"</string>
<string name="permdesc_write_settings" msgid="5440712911516509985">"गृहमा एउटा एपलाई सेटिङ र सर्टकट बदल्न अनुमति दिनुहोस्।"</string>
<string name="msg_no_phone_permission" msgid="9208659281529857371">"<xliff:g id="APP_NAME">%1$s</xliff:g> ले फोन कलहरू गर्न अनुमति छैन"</string>
<string name="gadget_error_text" msgid="6081085226050792095">"समस्या लोडिङ गर्ने विजेट"</string>
<string name="gadget_setup_text" msgid="8274003207686040488">"सेटअप"</string>

View File

@ -20,7 +20,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_name" msgid="649227358658669779">"ଲଞ୍ଚର୍3"</string>
<string name="work_folder_name" msgid="3753320833950115786">"କାମ"</string>
<string name="work_folder_name" msgid="3753320833950115786">"ୱାର୍କ"</string>
<string name="activity_not_found" msgid="8071924732094499514">"ଆପ୍‌ ଇନଷ୍ଟଲ୍‌ ହୋଇନାହିଁ"</string>
<string name="activity_not_available" msgid="7456344436509528827">"ଆପ୍‌ ଉପଲବ୍ଧ ନାହିଁ"</string>
<string name="safemode_shortcut_error" msgid="9160126848219158407">"ନିରାପଦ ମୋଡରେ ଡାଉନଲୋଡ୍‌ ହେଇଥିବା ଆପ୍‌ ଅକ୍ଷମ କରାଗଲା"</string>
@ -131,7 +131,7 @@
<string name="accessibility_close" msgid="2277148124685870734">"ବନ୍ଦ କରନ୍ତୁ"</string>
<string name="notification_dismissed" msgid="6002233469409822874">"ବିଜ୍ଞପ୍ତି ଖାରଜ କରାଗଲା"</string>
<string name="all_apps_personal_tab" msgid="4190252696685155002">"ବ୍ୟକ୍ତିଗତ"</string>
<string name="all_apps_work_tab" msgid="4884822796154055118">"କାମ"</string>
<string name="all_apps_work_tab" msgid="4884822796154055118">"ୱାର୍କ"</string>
<string name="work_profile_toggle_label" msgid="3081029915775481146">"ୱର୍କ ପ୍ରୋଫାଇଲ୍‌"</string>
<string name="work_profile_edu_personal_apps" msgid="4155536355149317441">"ବ୍ୟକ୍ତିଗତ ଡାଟା କାର୍ଯ୍ୟସ୍ଥଳୀ ଆପଗୁଡ଼ିକ ଠାରୁ ପୃଥକ୍ ଓ ଲୁକ୍କାୟିତ ଅଟେ"</string>
<string name="work_profile_edu_work_apps" msgid="237051938268703058">"କାର୍ଯ୍ୟସ୍ଥଳୀ ଆପଗୁଡ଼ିକ ଓ ଡାଟା ଆପଣଙ୍କ IT ଆଡମିନଙ୍କୁ ଦେଖାଯାଏ"</string>

View File

@ -35,6 +35,7 @@
<attr name="widgetsTheme" format="reference" />
<attr name="loadingIconColor" format="color" />
<attr name="iconOnlyShortcutColor" format="color"/>
<attr name="eduHalfSheetBGColor" format="color"/>
<attr name="folderDotColor" format="color" />
<attr name="folderFillColor" format="color" />

View File

@ -103,9 +103,9 @@
<!-- Label for install drop target. [CHAR_LIMIT=20] -->
<string name="install_drop_target_label">Install</string>
<!-- Label for install dismiss prediction. -->
<string translatable="false" name="dismiss_prediction_label">Don\'t suggest app</string>
<string name="dismiss_prediction_label">Don\'t suggest app</string>
<!-- Label for pinning predicted app. -->
<string name="pin_prediction" translatable="false">Pin Prediction</string>
<string name="pin_prediction">Pin Prediction</string>
<!-- Permissions: -->
@ -342,7 +342,7 @@
<!--- heading shown when user opens work apps tab while work apps are paused -->
<string name="work_apps_paused_title">Work profile is paused</string>
<!--- body shown when user opens work apps tab while work apps are paused -->
<string name="work_apps_paused_body">Work apps can\t send you notifications, use your battery, or access your location</string>
<string name="work_apps_paused_body">Work apps can\'t send you notifications, use your battery, or access your location</string>
<!-- content description for paused work apps list -->
<string name="work_apps_paused_content_description">Work profile is paused. Work apps can\t send you notifications, use your battery, or access your location</string>

View File

@ -53,6 +53,7 @@
<item name="loadingIconColor">#CCFFFFFF</item>
<item name="iconOnlyShortcutColor">?android:attr/textColorSecondary</item>
<item name="workProfileOverlayTextColor">#FF212121</item>
<item name="eduHalfSheetBGColor">?android:attr/colorAccent</item>
<item name="android:windowTranslucentStatus">false</item>
<item name="android:windowTranslucentNavigation">false</item>
@ -90,7 +91,7 @@
<item name="android:textColorHint">#A0FFFFFF</item>
<item name="android:colorControlHighlight">#A0FFFFFF</item>
<item name="android:colorPrimary">#FF212121</item>
<item name="allAppsScrimColor">#FF212121</item>
<item name="allAppsScrimColor">#FF000000</item>
<item name="allAppsInterimScrimAlpha">102</item>
<item name="allAppsNavBarScrimColor">#80000000</item>
<item name="popupColorPrimary">#3C4043</item> <!-- Gray 800 -->
@ -106,6 +107,7 @@
<item name="loadingIconColor">#99FFFFFF</item>
<item name="iconOnlyShortcutColor">#B3FFFFFF</item>
<item name="workProfileOverlayTextColor">@android:color/white</item>
<item name="eduHalfSheetBGColor">#DD000000</item>
</style>
<style name="LauncherTheme.Dark.DarkMainColor" parent="@style/LauncherTheme.Dark">
@ -229,9 +231,7 @@
<style name="TextHeadline" parent="@android:style/TextAppearance.DeviceDefault.DialogWindowTitle" />
<style name="PrimaryMediumText" parent="@android:style/TextAppearance.DeviceDefault.Medium"/>
<style name="PrimaryHeadline" parent="@android:style/TextAppearance.DeviceDefault.DialogWindowTitle">
<item name="android:textStyle">bold</item>
</style>
<style name="PrimaryHeadline" parent="@android:style/TextAppearance.DeviceDefault.DialogWindowTitle"/>
<style name="TextTitle" parent="@android:style/TextAppearance.DeviceDefault" />

View File

@ -16,7 +16,7 @@
package com.android.launcher3;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.APP_LAUNCH_TAP;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_APP_LAUNCH_TAP;
import static com.android.launcher3.util.DefaultDisplay.CHANGE_ROTATION;
import android.app.ActivityOptions;
@ -183,8 +183,7 @@ public abstract class BaseDraggingActivity extends BaseActivity
sourceContainer);
}
getUserEventDispatcher().logAppLaunch(v, intent, user);
getStatsLogManager().log(APP_LAUNCH_TAP, item == null ? null
getStatsLogManager().log(LAUNCHER_APP_LAUNCH_TAP, item == null ? null
: item.buildProto(null));
return true;
} catch (NullPointerException|ActivityNotFoundException|SecurityException e) {

View File

@ -60,6 +60,7 @@ 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.WorkspaceItemInfo;
import com.android.launcher3.util.SafeCloseable;
import com.android.launcher3.views.ActivityContext;
import com.android.launcher3.views.IconLabelDotView;
@ -722,17 +723,34 @@ public class BubbleTextView extends TextView implements ItemInfoUpdateReceiver,
}
@Override
public void getVisualDragBounds(Rect bounds) {
public void getWorkspaceVisualDragBounds(Rect bounds) {
DeviceProfile grid = mActivity.getDeviceProfile();
BubbleTextView.getIconBounds(this, bounds, grid.iconSizePx);
}
private int getIconSizeForDisplay(int display) {
DeviceProfile grid = mActivity.getDeviceProfile();
switch (display) {
case DISPLAY_ALL_APPS:
return grid.allAppsIconSizePx;
case DISPLAY_WORKSPACE:
case DISPLAY_FOLDER:
default:
return grid.iconSizePx;
}
}
public void getSourceVisualDragBounds(Rect bounds) {
BubbleTextView.getIconBounds(this, bounds, getIconSizeForDisplay(mDisplay));
}
@Override
public void prepareDrawDragView() {
public SafeCloseable prepareDrawDragView() {
if (getIcon() instanceof FastBitmapDrawable) {
FastBitmapDrawable icon = (FastBitmapDrawable) getIcon();
icon.setScale(1f);
}
setForceHideDot(true);
return () -> { };
}
}

View File

@ -16,6 +16,8 @@
package com.android.launcher3;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_ITEM_DROPPED_ON_CANCEL;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_ITEM_DROPPED_ON_REMOVE;
import static com.android.launcher3.userevent.nano.LauncherLogProto.Action.Touch.TAP;
import static com.android.launcher3.userevent.nano.LauncherLogProto.ControlType.UNDO;
@ -27,6 +29,7 @@ import android.view.View;
import com.android.launcher3.accessibility.LauncherAccessibilityDelegate;
import com.android.launcher3.dragndrop.DragOptions;
import com.android.launcher3.logging.LoggerUtils;
import com.android.launcher3.logging.StatsLogManager;
import com.android.launcher3.model.ModelWriter;
import com.android.launcher3.model.data.FolderInfo;
import com.android.launcher3.model.data.ItemInfo;
@ -38,6 +41,8 @@ import com.android.launcher3.views.Snackbar;
public class DeleteDropTarget extends ButtonDropTarget {
private final StatsLogManager mStatsLogManager;
private int mControlType = ControlType.DEFAULT_CONTROLTYPE;
public DeleteDropTarget(Context context, AttributeSet attrs) {
@ -46,6 +51,7 @@ public class DeleteDropTarget extends ButtonDropTarget {
public DeleteDropTarget(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
this.mStatsLogManager = StatsLogManager.newInstance(context);
}
@Override
@ -120,6 +126,11 @@ public class DeleteDropTarget extends ButtonDropTarget {
d.dragInfo.container = NO_ID;
}
super.onDrop(d, options);
mStatsLogManager.log(
mControlType == ControlType.REMOVE_TARGET
? LAUNCHER_ITEM_DROPPED_ON_REMOVE
: LAUNCHER_ITEM_DROPPED_ON_CANCEL,
d.logInstanceId);
}
@Override

View File

@ -78,7 +78,7 @@ public interface DropTarget {
public DraggableView originalView = null;
/** Used for matching DROP event with its corresponding DRAG event on the server side. */
final InstanceId mLogInstanceId =
public final InstanceId logInstanceId =
new InstanceIdSequence(1 << 20 /*InstanceId.INSTANCE_ID_MAX*/)
.newInstanceId();

View File

@ -67,7 +67,6 @@ import android.database.sqlite.SQLiteDatabase;
import android.os.Build;
import android.os.Bundle;
import android.os.CancellationSignal;
import android.os.Handler;
import android.os.Parcelable;
import android.os.Process;
import android.os.StrictMode;
@ -87,12 +86,12 @@ import android.view.accessibility.AccessibilityEvent;
import android.view.animation.OvershootInterpolator;
import android.widget.Toast;
import androidx.annotation.CallSuper;
import androidx.annotation.Nullable;
import androidx.annotation.StringRes;
import androidx.annotation.VisibleForTesting;
import com.android.launcher3.DropTarget.DragObject;
import com.android.launcher3.LauncherStateManager.StateHandler;
import com.android.launcher3.accessibility.LauncherAccessibilityDelegate;
import com.android.launcher3.allapps.AllAppsContainerView;
import com.android.launcher3.allapps.AllAppsStore;
@ -130,6 +129,10 @@ import com.android.launcher3.popup.PopupContainerWithArrow;
import com.android.launcher3.popup.PopupDataProvider;
import com.android.launcher3.popup.SystemShortcut;
import com.android.launcher3.qsb.QsbContainerView;
import com.android.launcher3.statemanager.StateManager;
import com.android.launcher3.statemanager.StateManager.StateHandler;
import com.android.launcher3.statemanager.StateManager.StateListener;
import com.android.launcher3.statemanager.StatefulActivity;
import com.android.launcher3.states.RotationHelper;
import com.android.launcher3.testing.TestLogging;
import com.android.launcher3.testing.TestProtocol;
@ -193,7 +196,7 @@ import java.util.stream.Stream;
/**
* Default launcher application.
*/
public class Launcher extends BaseDraggingActivity implements LauncherExterns,
public class Launcher extends StatefulActivity<LauncherState> implements LauncherExterns,
Callbacks, InvariantDeviceProfile.OnIDPChangeListener, PluginListener<OverlayPlugin> {
public static final String TAG = "Launcher";
@ -240,7 +243,7 @@ public class Launcher extends BaseDraggingActivity implements LauncherExterns,
public static final String ON_RESUME_EVT = "Launcher.onResume";
public static final String ON_NEW_INTENT_EVT = "Launcher.onNewIntent";
private LauncherStateManager mStateManager;
private StateManager<LauncherState> mStateManager;
private static final int ON_ACTIVITY_RESULT_ANIMATION_DELAY = 500;
@ -324,10 +327,6 @@ public class Launcher extends BaseDraggingActivity implements LauncherExterns,
private RotationHelper mRotationHelper;
final Handler mHandler = new Handler();
private final Runnable mHandleDeferredResume = this::handleDeferredResume;
private boolean mDeferredResumePending;
private float mCurrentAssistantVisibility = 0f;
protected LauncherOverlayManager mOverlayManager;
@ -374,9 +373,9 @@ public class Launcher extends BaseDraggingActivity implements LauncherExterns,
mDragController = new DragController(this);
mAllAppsController = new AllAppsTransitionController(this);
mStateManager = new LauncherStateManager(this);
mStateManager = new StateManager<>(this, NORMAL);
mOnboardingPrefs = createOnboardingPrefs(mSharedPrefs, mStateManager);
mOnboardingPrefs = createOnboardingPrefs(mSharedPrefs);
mAppWidgetManager = new WidgetManagerHelper(this);
mAppWidgetHost = new LauncherAppWidgetHost(this,
@ -439,7 +438,7 @@ public class Launcher extends BaseDraggingActivity implements LauncherExterns,
mRotationHelper.initialize();
mStateManager.addStateListener(new LauncherStateManager.StateListener() {
mStateManager.addStateListener(new StateListener<LauncherState>() {
@Override
public void onStateTransitionComplete(LauncherState finalState) {
@ -466,9 +465,8 @@ public class Launcher extends BaseDraggingActivity implements LauncherExterns,
return new LauncherOverlayManager() { };
}
protected OnboardingPrefs createOnboardingPrefs(SharedPreferences sharedPrefs,
LauncherStateManager stateManager) {
return new OnboardingPrefs<>(this, sharedPrefs, stateManager);
protected OnboardingPrefs createOnboardingPrefs(SharedPreferences sharedPrefs) {
return new OnboardingPrefs<>(this, sharedPrefs);
}
public OnboardingPrefs getOnboardingPrefs() {
@ -522,13 +520,9 @@ public class Launcher extends BaseDraggingActivity implements LauncherExterns,
}
@Override
public void reapplyUi() {
reapplyUi(true /* cancelCurrentAnimation */);
}
public void reapplyUi(boolean cancelCurrentAnimation) {
getRootView().dispatchInsets();
getStateManager().reapplyState(cancelCurrentAnimation);
super.reapplyUi(cancelCurrentAnimation);
}
@Override
@ -582,7 +576,8 @@ public class Launcher extends BaseDraggingActivity implements LauncherExterns,
return mFocusHandler;
}
public LauncherStateManager getStateManager() {
@Override
public StateManager<LauncherState> getStateManager() {
return mStateManager;
}
@ -889,11 +884,7 @@ public class Launcher extends BaseDraggingActivity implements LauncherExterns,
@Override
protected void onStop() {
final boolean wasActive = isUserActive();
final LauncherState origState = getStateManager().getState();
final int origDragLayerChildCount = mDragLayer.getChildCount();
super.onStop();
if (mDeferOverlayCallbacks) {
checkIfOverlayStillDeferred();
} else {
@ -901,28 +892,8 @@ public class Launcher extends BaseDraggingActivity implements LauncherExterns,
}
logStopAndResume(Action.Command.STOP);
mAppWidgetHost.setListenIfResumed(false);
NotificationListener.removeNotificationsChangedListener();
getStateManager().moveToRestState();
// Workaround for b/78520668, explicitly trim memory once UI is hidden
onTrimMemory(TRIM_MEMORY_UI_HIDDEN);
if (wasActive) {
// The expected condition is that this activity is stopped because the device goes to
// sleep and the UI may have noticeable changes.
mDragLayer.post(() -> {
if ((!getStateManager().isInStableState(origState)
// The drag layer may be animating (e.g. dismissing QSB).
|| mDragLayer.getAlpha() < 1
// Maybe an ArrowPopup is closed.
|| mDragLayer.getChildCount() != origDragLayerChildCount)) {
onUiChangedWhileSleeping();
}
});
}
}
@Override
@ -938,35 +909,27 @@ public class Launcher extends BaseDraggingActivity implements LauncherExterns,
TraceHelper.INSTANCE.endSection(traceToken);
}
private void handleDeferredResume() {
if (hasBeenResumed() && !mStateManager.getState().hasFlag(FLAG_NON_INTERACTIVE)) {
logStopAndResume(Action.Command.RESUME);
getUserEventDispatcher().startSession();
@Override
@CallSuper
protected void onDeferredResumed() {
logStopAndResume(Action.Command.RESUME);
getUserEventDispatcher().startSession();
AppLaunchTracker.INSTANCE.get(this).onReturnedToHome();
AppLaunchTracker.INSTANCE.get(this).onReturnedToHome();
// Process any items that were added while Launcher was away.
InstallShortcutReceiver.disableAndFlushInstallQueue(
InstallShortcutReceiver.FLAG_ACTIVITY_PAUSED, this);
// Process any items that were added while Launcher was away.
InstallShortcutReceiver.disableAndFlushInstallQueue(
InstallShortcutReceiver.FLAG_ACTIVITY_PAUSED, this);
// Refresh shortcuts if the permission changed.
mModel.refreshShortcutsIfRequired();
// Refresh shortcuts if the permission changed.
mModel.refreshShortcutsIfRequired();
// Set the notification listener and fetch updated notifications when we resume
NotificationListener.setNotificationsChangedListener(mPopupDataProvider);
// Set the notification listener and fetch updated notifications when we resume
NotificationListener.setNotificationsChangedListener(mPopupDataProvider);
DiscoveryBounce.showForHomeIfNeeded(this);
onDeferredResumed();
addActivityFlags(ACTIVITY_STATE_DEFERRED_RESUMED);
mDeferredResumePending = false;
} else {
mDeferredResumePending = true;
}
DiscoveryBounce.showForHomeIfNeeded(this);
}
protected void onDeferredResumed() { }
private void logStopAndResume(int command) {
int containerType = mStateManager.getState().containerType;
@ -1015,10 +978,9 @@ public class Launcher extends BaseDraggingActivity implements LauncherExterns,
return mOverlayManager;
}
@Override
public void onStateSetStart(LauncherState state) {
if (mDeferredResumePending) {
handleDeferredResume();
}
super.onStateSetStart(state);
if (mDeferOverlayCallbacks) {
scheduleDeferredCheck();
}
@ -1041,7 +1003,9 @@ public class Launcher extends BaseDraggingActivity implements LauncherExterns,
mWorkspace.getPageIndicator().setShouldAutoHide(!state.hasFlag(FLAG_MULTI_PAGE));
}
@Override
public void onStateSetEnd(LauncherState state) {
super.onStateSetStart(state);
getAppWidgetHost().setResumed(state == LauncherState.NORMAL);
getWorkspace().setClipChildren(!state.hasFlag(FLAG_MULTI_PAGE));
@ -1067,9 +1031,6 @@ public class Launcher extends BaseDraggingActivity implements LauncherExterns,
TraceHelper.FLAG_UI_EVENT);
super.onResume();
mHandler.removeCallbacks(mHandleDeferredResume);
Utilities.postAsyncCallback(mHandler, mHandleDeferredResume);
if (!mOnResumeCallbacks.isEmpty()) {
final ArrayList<OnResumeCallback> resumeCallbacks = new ArrayList<>(mOnResumeCallbacks);
mOnResumeCallbacks.clear();
@ -1112,10 +1073,6 @@ public class Launcher extends BaseDraggingActivity implements LauncherExterns,
}
}
public boolean isInState(LauncherState state) {
return mStateManager.getState() == state;
}
/**
* Restores the previous state, if it exists.
*
@ -1354,8 +1311,6 @@ public class Launcher extends BaseDraggingActivity implements LauncherExterns,
}
};
protected void onUiChangedWhileSleeping() { }
private void updateNotificationDots(Predicate<PackageUserKey> updatedDots) {
mWorkspace.updateNotificationDots(updatedDots);
mAppsView.getAppsStore().updateNotificationDots(updatedDots);
@ -2720,7 +2675,7 @@ public class Launcher extends BaseDraggingActivity implements LauncherExterns,
return super.onKeyUp(keyCode, event);
}
protected StateHandler[] createStateHandlers() {
protected StateHandler<LauncherState>[] createStateHandlers() {
return new StateHandler[] { getAllAppsController(), getWorkspace() };
}

View File

@ -13,11 +13,8 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.launcher3;
import android.animation.Animator;
import android.app.ActivityOptions;
import android.content.Context;
import android.graphics.Rect;
@ -57,17 +54,6 @@ public class LauncherAppTransitionManager implements ResourceBasedOverride {
return false;
}
/**
* Number of animations which run on state properties.
*/
public int getStateElementAnimationsCount() {
return 0;
}
public Animator createStateElementAnimation(int index, float... values) {
throw new RuntimeException("Unknown gesture animation " + index);
}
/**
* Registers remote animations for certain system transitions.
*/

View File

@ -20,7 +20,6 @@ import static com.android.launcher3.config.FeatureFlags.MULTI_DB_GRID_MIRATION_A
import static com.android.launcher3.provider.LauncherDbUtils.copyTable;
import static com.android.launcher3.provider.LauncherDbUtils.dropTable;
import static com.android.launcher3.provider.LauncherDbUtils.tableExists;
import static com.android.launcher3.util.Executors.MODEL_EXECUTOR;
import android.annotation.TargetApi;
import android.app.backup.BackupManager;
@ -48,7 +47,6 @@ import android.net.Uri;
import android.os.Binder;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.Process;
import android.os.UserHandle;
import android.os.UserManager;
@ -85,6 +83,7 @@ import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Locale;
import java.util.concurrent.TimeUnit;
import java.util.function.Supplier;
public class LauncherProvider extends ContentProvider {
@ -92,8 +91,7 @@ public class LauncherProvider extends ContentProvider {
private static final boolean LOGD = false;
private static final String DOWNGRADE_SCHEMA_FILE = "downgrade_schema.json";
private static final String TOKEN_RESTORE_BACKUP_TABLE = "restore_backup_table";
private static final long RESTORE_BACKUP_TABLE_DELAY = 60000;
private static final long RESTORE_BACKUP_TABLE_DELAY = TimeUnit.SECONDS.toMillis(30);
/**
* Represents the schema of the database. Changes in scheme need not be backwards compatible.
@ -107,6 +105,8 @@ public class LauncherProvider extends ContentProvider {
protected DatabaseHelper mOpenHelper;
private long mLastRestoreTimestamp = 0L;
/**
* $ adb shell dumpsys activity provider com.android.launcher3
*/
@ -412,11 +412,12 @@ public class LauncherProvider extends ContentProvider {
return null;
}
case LauncherSettings.Settings.METHOD_RESTORE_BACKUP_TABLE: {
final Handler handler = MODEL_EXECUTOR.getHandler();
handler.removeCallbacksAndMessages(TOKEN_RESTORE_BACKUP_TABLE);
handler.postDelayed(() -> RestoreDbTask.restoreIfPossible(
getContext(), mOpenHelper, new BackupManager(getContext())),
TOKEN_RESTORE_BACKUP_TABLE, RESTORE_BACKUP_TABLE_DELAY);
final long ts = System.currentTimeMillis();
if (ts - mLastRestoreTimestamp > RESTORE_BACKUP_TABLE_DELAY) {
mLastRestoreTimestamp = ts;
RestoreDbTask.restoreIfPossible(
getContext(), mOpenHelper, new BackupManager(getContext()));
}
return null;
}
case LauncherSettings.Settings.METHOD_UPDATE_CURRENT_OPEN_HELPER: {

View File

@ -15,19 +15,7 @@
*/
package com.android.launcher3;
import static android.view.View.VISIBLE;
import static com.android.launcher3.anim.Interpolators.ACCEL;
import static com.android.launcher3.anim.Interpolators.ACCEL_2;
import static com.android.launcher3.anim.Interpolators.DEACCEL;
import static com.android.launcher3.anim.Interpolators.DEACCEL_1_7;
import static com.android.launcher3.anim.Interpolators.clampToProgress;
import static com.android.launcher3.config.FeatureFlags.ENABLE_OVERVIEW_ACTIONS;
import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_FADE;
import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_SCALE;
import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_TRANSLATE_X;
import static com.android.launcher3.states.StateAnimationConfig.ANIM_WORKSPACE_FADE;
import static com.android.launcher3.states.StateAnimationConfig.ANIM_WORKSPACE_SCALE;
import static com.android.launcher3.testing.TestProtocol.ALL_APPS_STATE_ORDINAL;
import static com.android.launcher3.testing.TestProtocol.BACKGROUND_APP_STATE_ORDINAL;
import static com.android.launcher3.testing.TestProtocol.HINT_STATE_ORDINAL;
@ -39,24 +27,22 @@ import static com.android.launcher3.testing.TestProtocol.QUICK_SWITCH_STATE_ORDI
import static com.android.launcher3.testing.TestProtocol.SPRING_LOADED_STATE_ORDINAL;
import android.content.Context;
import android.view.View;
import android.view.animation.Interpolator;
import com.android.launcher3.allapps.AllAppsContainerView;
import com.android.launcher3.statemanager.BaseState;
import com.android.launcher3.statemanager.StateManager;
import com.android.launcher3.states.HintState;
import com.android.launcher3.states.SpringLoadedState;
import com.android.launcher3.states.StateAnimationConfig;
import com.android.launcher3.uioverrides.states.AllAppsState;
import com.android.launcher3.uioverrides.states.OverviewState;
import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType;
import java.util.Arrays;
/**
* Base state for various states used for the Launcher
*/
public abstract class LauncherState {
public abstract class LauncherState implements BaseState<LauncherState> {
/**
* Set of elements indicating various workspace elements which change visibility across states
@ -76,25 +62,22 @@ public abstract class LauncherState {
HOTSEAT_SEARCH_BOX | ALL_APPS_HEADER | ALL_APPS_HEADER_EXTRA | ALL_APPS_CONTENT;
// Flag indicating workspace has multiple pages visible.
public static final int FLAG_MULTI_PAGE = 1 << 0;
public static final int FLAG_MULTI_PAGE = BaseState.getFlag(0);
// Flag indicating that workspace and its contents are not accessible
public static final int FLAG_WORKSPACE_INACCESSIBLE = 1 << 1;
public static final int FLAG_WORKSPACE_INACCESSIBLE = BaseState.getFlag(1);
public static final int FLAG_DISABLE_RESTORE = 1 << 2;
// Flag indicating the state allows workspace icons to be dragged.
public static final int FLAG_WORKSPACE_ICONS_CAN_BE_DRAGGED = 1 << 3;
public static final int FLAG_WORKSPACE_ICONS_CAN_BE_DRAGGED = BaseState.getFlag(2);
// Flag to indicate that workspace should draw page background
public static final int FLAG_WORKSPACE_HAS_BACKGROUNDS = 1 << 4;
// Flag to indicate that Launcher is non-interactive in this state
public static final int FLAG_NON_INTERACTIVE = 1 << 5;
public static final int FLAG_WORKSPACE_HAS_BACKGROUNDS = BaseState.getFlag(3);
// True if the back button should be hidden when in this state (assuming no floating views are
// open, launcher has window focus, etc).
public static final int FLAG_HIDE_BACK_BUTTON = 1 << 6;
public static final int FLAG_HIDE_BACK_BUTTON = BaseState.getFlag(4);
// Flag to indicate if the state would have scrim over sysui region: statu sbar and nav bar
public static final int FLAG_HAS_SYS_UI_SCRIM = 1 << 7;
public static final int FLAG_HAS_SYS_UI_SCRIM = BaseState.getFlag(5);
// Flag to inticate that all popups should be closed when this state is enabled.
public static final int FLAG_CLOSE_POPUPS = 1 << 8;
public static final int FLAG_OVERVIEW_UI = 1 << 9;
public static final int FLAG_CLOSE_POPUPS = BaseState.getFlag(6);
public static final int FLAG_OVERVIEW_UI = BaseState.getFlag(7);
public static final float NO_OFFSET = 0;
@ -167,26 +150,15 @@ public abstract class LauncherState {
/**
* Returns if the state has the provided flag
*/
@Override
public final boolean hasFlag(int mask) {
return (mFlags & mask) != 0;
}
/**
* @return true if the state can be persisted across activity restarts.
*/
public final boolean shouldDisableRestore() {
return hasFlag(FLAG_DISABLE_RESTORE);
}
public static LauncherState[] values() {
return Arrays.copyOf(sAllStates, sAllStates.length);
}
/**
* @return How long the animation to this state should take (or from this state to NORMAL).
*/
public abstract int getTransitionDuration(Context context);
public ScaleAndTranslation getWorkspaceScaleAndTranslation(Launcher launcher) {
return new ScaleAndTranslation(NO_SCALE, NO_OFFSET, NO_OFFSET);
}
@ -280,65 +252,22 @@ public abstract class LauncherState {
};
}
@Override
public LauncherState getHistoryForState(LauncherState previousState) {
// No history is supported
return NORMAL;
}
public void onBackPressed(Launcher launcher) {
if (this != NORMAL) {
LauncherStateManager lsm = launcher.getStateManager();
LauncherState lastState = lsm.getLastState();
lsm.goToState(lastState);
}
@Override
public String toString() {
return "Ordinal-" + ordinal;
}
/**
* Prepares for a non-user controlled animation from fromState to this state. Preparations
* include:
* - Setting interpolators for various animations included in the state transition.
* - Setting some start values (e.g. scale) for views that are hidden but about to be shown.
*/
public void prepareForAtomicAnimation(Launcher launcher, LauncherState fromState,
StateAnimationConfig config) {
if (this == NORMAL && fromState == OVERVIEW) {
config.setInterpolator(ANIM_WORKSPACE_SCALE, DEACCEL);
config.setInterpolator(ANIM_WORKSPACE_FADE, ACCEL);
config.setInterpolator(ANIM_OVERVIEW_SCALE, clampToProgress(ACCEL, 0, 0.9f));
config.setInterpolator(ANIM_OVERVIEW_TRANSLATE_X, ACCEL);
config.setInterpolator(ANIM_OVERVIEW_FADE, DEACCEL_1_7);
Workspace workspace = launcher.getWorkspace();
// Start from a higher workspace scale, but only if we're invisible so we don't jump.
boolean isWorkspaceVisible = workspace.getVisibility() == VISIBLE;
if (isWorkspaceVisible) {
CellLayout currentChild = (CellLayout) workspace.getChildAt(
workspace.getCurrentPage());
isWorkspaceVisible = currentChild.getVisibility() == VISIBLE
&& currentChild.getShortcutsAndWidgets().getAlpha() > 0;
}
if (!isWorkspaceVisible) {
workspace.setScaleX(0.92f);
workspace.setScaleY(0.92f);
}
Hotseat hotseat = launcher.getHotseat();
boolean isHotseatVisible = hotseat.getVisibility() == VISIBLE && hotseat.getAlpha() > 0;
if (!isHotseatVisible) {
hotseat.setScaleX(0.92f);
hotseat.setScaleY(0.92f);
if (ENABLE_OVERVIEW_ACTIONS.get()) {
AllAppsContainerView qsbContainer = launcher.getAppsView();
View qsb = qsbContainer.getSearchView();
boolean qsbVisible = qsb.getVisibility() == VISIBLE && qsb.getAlpha() > 0;
if (!qsbVisible) {
qsbContainer.setScaleX(0.92f);
qsbContainer.setScaleY(0.92f);
}
}
}
} else if (this == NORMAL && fromState == OVERVIEW_PEEK) {
// Keep fully visible until the very end (when overview is offscreen) to make invisible.
config.setInterpolator(ANIM_OVERVIEW_FADE, t -> t < 1 ? 0 : 1);
public void onBackPressed(Launcher launcher) {
if (this != NORMAL) {
StateManager<LauncherState> lsm = launcher.getStateManager();
LauncherState lastState = lsm.getLastState();
lsm.goToState(lastState);
}
}

View File

@ -7,6 +7,10 @@ import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_DESKTOP
import static com.android.launcher3.accessibility.LauncherAccessibilityDelegate.DISMISS_PREDICTION;
import static com.android.launcher3.accessibility.LauncherAccessibilityDelegate.RECONFIGURE;
import static com.android.launcher3.accessibility.LauncherAccessibilityDelegate.UNINSTALL;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_ITEM_DROPPED_ON_DONT_SUGGEST;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_ITEM_DROPPED_ON_UNINSTALL;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_ITEM_UNINSTALL_CANCELLED;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_ITEM_UNINSTALL_COMPLETED;
import static com.android.launcher3.model.data.ItemInfoWithIcon.FLAG_SYSTEM_MASK;
import static com.android.launcher3.model.data.ItemInfoWithIcon.FLAG_SYSTEM_NO;
@ -34,6 +38,7 @@ import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.dragndrop.DragOptions;
import com.android.launcher3.logging.FileLog;
import com.android.launcher3.logging.LoggerUtils;
import com.android.launcher3.logging.StatsLogManager;
import com.android.launcher3.model.AppLaunchTracker;
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.model.data.ItemInfoWithIcon;
@ -58,7 +63,7 @@ public class SecondaryDropTarget extends ButtonDropTarget implements OnAlarmList
private static final long CACHE_EXPIRE_TIMEOUT = 5000;
private final ArrayMap<UserHandle, Boolean> mUninstallDisabledCache = new ArrayMap<>(1);
private final StatsLogManager mStatsLogManager;
private final Alarm mCacheExpireAlarm;
private boolean mHadPendingAlarm;
@ -69,8 +74,8 @@ public class SecondaryDropTarget extends ButtonDropTarget implements OnAlarmList
public SecondaryDropTarget(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
mCacheExpireAlarm = new Alarm();
mStatsLogManager = StatsLogManager.newInstance(context);
}
@Override
@ -214,6 +219,11 @@ public class SecondaryDropTarget extends ButtonDropTarget implements OnAlarmList
// Defer onComplete
d.dragSource = new DeferredOnComplete(d.dragSource, getContext());
super.onDrop(d, options);
if (mCurrentAccessibilityAction == UNINSTALL) {
mStatsLogManager.log(LAUNCHER_ITEM_DROPPED_ON_UNINSTALL, d.logInstanceId);
} else if (mCurrentAccessibilityAction == DISMISS_PREDICTION) {
mStatsLogManager.log(LAUNCHER_ITEM_DROPPED_ON_DONT_SUGGEST, d.logInstanceId);
}
}
@Override
@ -338,8 +348,10 @@ public class SecondaryDropTarget extends ButtonDropTarget implements OnAlarmList
mDragObject.dragInfo.user, PackageManager.MATCH_UNINSTALLED_PACKAGES) == null) {
mDragObject.dragSource = mOriginal;
mOriginal.onDropCompleted(SecondaryDropTarget.this, mDragObject, true);
mStatsLogManager.log(LAUNCHER_ITEM_UNINSTALL_COMPLETED, mDragObject.logInstanceId);
} else {
sendFailure();
mStatsLogManager.log(LAUNCHER_ITEM_UNINSTALL_CANCELLED, mDragObject.logInstanceId);
}
}

View File

@ -89,6 +89,7 @@ import com.android.launcher3.model.data.LauncherAppWidgetInfo;
import com.android.launcher3.model.data.WorkspaceItemInfo;
import com.android.launcher3.pageindicators.WorkspacePageIndicator;
import com.android.launcher3.popup.PopupContainerWithArrow;
import com.android.launcher3.statemanager.StateManager.StateHandler;
import com.android.launcher3.states.StateAnimationConfig;
import com.android.launcher3.touch.WorkspaceTouchListener;
import com.android.launcher3.userevent.nano.LauncherLogProto.Action;
@ -119,7 +120,7 @@ import java.util.function.Predicate;
*/
public class Workspace extends PagedView<WorkspacePageIndicator>
implements DropTarget, DragSource, View.OnTouchListener,
DragController.DragListener, Insettable, LauncherStateManager.StateHandler,
DragController.DragListener, Insettable, StateHandler<LauncherState>,
WorkspaceLayoutManager {
/** The value that {@link #mTransitionProgress} must be greater than for
@ -416,8 +417,12 @@ public class Workspace extends PagedView<WorkspacePageIndicator>
mLauncher.getStateManager().goToState(SPRING_LOADED);
mStatsLogManager.log(
LauncherEvent.LAUNCHER_ITEM_DRAG_STARTED,
dragObject.mLogInstanceId,
dragObject.originalDragInfo.buildProto(null));
dragObject.logInstanceId,
dragObject.originalDragInfo.buildProto(
dragObject.dragSource instanceof Folder
? ((Folder) dragObject.dragSource).mInfo
: null)
);
}
public void deferRemoveExtraEmptyScreen() {
@ -1437,6 +1442,10 @@ public class Workspace extends PagedView<WorkspacePageIndicator>
mOutlineProvider = previewProvider;
if (draggableView == null && child instanceof DraggableView) {
draggableView = (DraggableView) child;
}
// The drag bitmap follows the touch point around on the screen
final Bitmap b = previewProvider.createDragBitmap();
int halfPadding = previewProvider.previewPadding / 2;
@ -1447,12 +1456,8 @@ public class Workspace extends PagedView<WorkspacePageIndicator>
Point dragVisualizeOffset = null;
Rect dragRect = new Rect();
if (draggableView == null && child instanceof DraggableView) {
draggableView = (DraggableView) child;
}
if (draggableView != null) {
draggableView.getVisualDragBounds(dragRect);
draggableView.getSourceVisualDragBounds(dragRect);
dragLayerY += dragRect.top;
dragVisualizeOffset = new Point(- halfPadding, halfPadding);
}
@ -1645,7 +1650,10 @@ public class Workspace extends PagedView<WorkspacePageIndicator>
Rect folderLocation = new Rect();
float scale = mLauncher.getDragLayer().getDescendantRectRelativeToSelf(v, folderLocation);
target.removeView(v);
mStatsLogManager.log(
LauncherEvent.LAUNCHER_ITEM_DROP_FOLDER_CREATED,
d.logInstanceId,
destInfo.buildProto(null));
FolderIcon fi = mLauncher.addFolder(target, container, screenId, targetCell[0],
targetCell[1]);
destInfo.cellX = -1;
@ -1683,6 +1691,10 @@ public class Workspace extends PagedView<WorkspacePageIndicator>
if (dropOverView instanceof FolderIcon) {
FolderIcon fi = (FolderIcon) dropOverView;
if (fi.acceptDrop(d.dragInfo)) {
mStatsLogManager.log(
LauncherEvent.LAUNCHER_ITEM_DROP_COMPLETED,
d.logInstanceId,
fi.mInfo.buildProto(null));
fi.onDrop(d, false /* itemReturnedOnFailedDrop */);
// if the drag started here, we need to remove it from the workspace
@ -1885,15 +1897,15 @@ public class Workspace extends PagedView<WorkspacePageIndicator>
mLauncher.getStateManager().goToState(
NORMAL, SPRING_LOADED_EXIT_DELAY, onCompleteRunnable);
mStatsLogManager.log(
LauncherEvent.LAUNCHER_ITEM_DROP_COMPLETED,
d.logInstanceId,
d.dragInfo.buildProto(null));
}
if (d.stateAnnouncer != null && !droppedOnOriginalCell) {
d.stateAnnouncer.completeAction(R.string.item_moved);
}
mStatsLogManager.log(
LauncherEvent.LAUNCHER_ITEM_DROP_COMPLETED,
d.mLogInstanceId,
d.dragInfo.buildProto(null));
}
public void onNoCellFound(View dropTargetLayout) {
@ -2515,6 +2527,10 @@ public class Workspace extends PagedView<WorkspacePageIndicator>
resetTransitionTransform();
}
}
mStatsLogManager.log(
LauncherEvent.LAUNCHER_ITEM_DROP_COMPLETED,
d.logInstanceId,
d.dragInfo.buildProto(null));
}
public Bitmap createWidgetBitmap(ItemInfo widgetInfo, View layout) {

View File

@ -66,7 +66,7 @@ public class WorkspaceStateTransitionAnimation {
}
/**
* @see com.android.launcher3.LauncherStateManager.StateHandler#setStateWithAnimation
* @see com.android.launcher3.statemanager.StateManager.StateHandler#setStateWithAnimation
*/
public void setStateWithAnimation(
LauncherState toState, StateAnimationConfig config, PendingAnimation animation) {

View File

@ -28,11 +28,11 @@ import com.android.launcher3.DeviceProfile;
import com.android.launcher3.DeviceProfile.OnDeviceProfileChangeListener;
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherState;
import com.android.launcher3.LauncherStateManager.StateHandler;
import com.android.launcher3.R;
import com.android.launcher3.anim.AnimationSuccessListener;
import com.android.launcher3.anim.PendingAnimation;
import com.android.launcher3.anim.PropertySetter;
import com.android.launcher3.statemanager.StateManager.StateHandler;
import com.android.launcher3.states.StateAnimationConfig;
import com.android.launcher3.uioverrides.plugins.PluginManagerWrapper;
import com.android.launcher3.util.Themes;
@ -50,8 +50,8 @@ import com.android.systemui.plugins.PluginListener;
* If release velocity < THRES1, snap according to either top or bottom depending on whether it's
* closer to top or closer to the page indicator.
*/
public class AllAppsTransitionController implements StateHandler, OnDeviceProfileChangeListener,
PluginListener<AllAppsSearchPlugin> {
public class AllAppsTransitionController implements StateHandler<LauncherState>,
OnDeviceProfileChangeListener, PluginListener<AllAppsSearchPlugin> {
public static final FloatProperty<AllAppsTransitionController> ALL_APPS_PROGRESS =
new FloatProperty<AllAppsTransitionController>("allAppsProgress") {

View File

@ -31,9 +31,9 @@ import android.view.MotionEvent;
import com.android.launcher3.AbstractFloatingView;
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherState;
import com.android.launcher3.LauncherStateManager.StateListener;
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
import com.android.launcher3.statemanager.StateManager.StateListener;
import com.android.launcher3.util.OnboardingPrefs;
/**
@ -46,7 +46,7 @@ public class DiscoveryBounce extends AbstractFloatingView {
private final Launcher mLauncher;
private final Animator mDiscoBounceAnimation;
private final StateListener mStateListener = new StateListener() {
private final StateListener<LauncherState> mStateListener = new StateListener<LauncherState>() {
@Override
public void onStateTransitionStart(LauncherState toState) {
handleClose(false);

View File

@ -22,7 +22,7 @@ import android.view.MotionEvent;
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherState;
import com.android.launcher3.LauncherStateManager;
import com.android.launcher3.statemanager.StateManager.StateListener;
import com.android.launcher3.views.WorkEduView;
/**
@ -32,7 +32,7 @@ public class LauncherAllAppsContainerView extends AllAppsContainerView {
private final Launcher mLauncher;
private LauncherStateManager.StateListener mWorkTabListener;
private StateListener<LauncherState> mWorkTabListener;
public LauncherAllAppsContainerView(Context context) {
this(context, null);

View File

@ -105,6 +105,13 @@ public class PendingAnimation implements PropertySetter {
add(anim);
}
public <T> void addFloat(T target, FloatProperty<T> property, float from, float to,
TimeInterpolator interpolator) {
Animator anim = ObjectAnimator.ofFloat(target, property, from, to);
anim.setDuration(mDuration).setInterpolator(interpolator);
add(anim);
}
@Override
public <T> void setInt(T target, IntProperty<T> property, int value,
TimeInterpolator interpolator) {

View File

@ -186,8 +186,7 @@ public class DragController implements DragDriver.EventListener, TouchController
mDragObject.dragSource = source;
mDragObject.dragInfo = dragInfo;
mDragObject.originalDragInfo = new ItemInfo();
mDragObject.originalDragInfo.copyFrom(dragInfo);
mDragObject.originalDragInfo = mDragObject.dragInfo.makeShallowCopy();
if (dragOffset != null) {
dragView.setDragVisualizeOffset(new Point(dragOffset));

View File

@ -274,19 +274,29 @@ public class DragLayer extends BaseDragLayer<Launcher> {
scale *= childScale;
int toX = Math.round(coord[0]);
int toY = Math.round(coord[1]);
float toScale = scale;
if (child instanceof DraggableView) {
// This code is fairly subtle. Please verify drag and drop is pixel-perfect in a number
// of scenarios before modifying (from all apps, from workspace, different grid-sizes,
// shortcuts from in and out of Launcher etc).
DraggableView d = (DraggableView) child;
d.getVisualDragBounds(dragViewBounds);
Rect destRect = new Rect();
d.getWorkspaceVisualDragBounds(destRect);
// In most cases this additional scale factor should be a no-op (1). It mainly accounts
// for alternate grids where the source and destination icon sizes are different
toScale *= ((1f * destRect.width())
/ (dragView.getMeasuredWidth() - dragView.getBlurSizeOutline()));
// This accounts for the offset of the DragView created by scaling it about its
// center as it animates into place.
float scaleShiftX = dragView.getMeasuredWidth() * (1 - scale) / 2;
float scaleShiftY = dragView.getMeasuredHeight() * (1 - scale) / 2;
float scaleShiftX = dragView.getMeasuredWidth() * (1 - toScale) / 2;
float scaleShiftY = dragView.getMeasuredHeight() * (1 - toScale) / 2;
toX += scale * (dragViewBounds.left - dragView.getBlurSizeOutline() / 2) - scaleShiftX;
toY += scale * (dragViewBounds.top - dragView.getBlurSizeOutline() / 2) - scaleShiftY;
toX += scale * destRect.left - toScale * dragView.getBlurSizeOutline() / 2 - scaleShiftX;
toY += scale * destRect.top - toScale * dragView.getBlurSizeOutline() / 2 - scaleShiftY;
}
child.setVisibility(INVISIBLE);

View File

@ -49,18 +49,18 @@ import com.android.launcher3.FirstFrameAnimatorHelper;
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherSettings;
import com.android.launcher3.LauncherState;
import com.android.launcher3.LauncherStateManager;
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
import com.android.launcher3.anim.Interpolators;
import com.android.launcher3.icons.LauncherIcons;
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.statemanager.StateManager.StateListener;
import com.android.launcher3.util.Themes;
import com.android.launcher3.util.Thunk;
import java.util.Arrays;
public class DragView extends View implements LauncherStateManager.StateListener {
public class DragView extends View implements StateListener<LauncherState> {
private static final ColorMatrix sTempMatrix1 = new ColorMatrix();
private static final ColorMatrix sTempMatrix2 = new ColorMatrix();

View File

@ -18,6 +18,10 @@ package com.android.launcher3.dragndrop;
import android.graphics.Rect;
import androidx.annotation.NonNull;
import com.android.launcher3.util.SafeCloseable;
/**
* Interface defining methods required for drawing and previewing DragViews, drag previews, and
* related animations
@ -42,9 +46,12 @@ public interface DraggableView {
int getViewType();
/**
* Before rendering as a DragView bitmap, some views need a preparation step.
* Before rendering as a DragView bitmap, some views need a preparation step. Returns a
* callback to clear any preparation work
*/
default void prepareDrawDragView() { }
@NonNull default SafeCloseable prepareDrawDragView() {
return () -> { };
}
/**
* If an actual View subclass, this method returns the rectangle (within the View's coordinates)
@ -53,5 +60,14 @@ public interface DraggableView {
*
* @param bounds Visual bounds in the views coordinates will be written here.
*/
default void getVisualDragBounds(Rect bounds) { }
default void getWorkspaceVisualDragBounds(Rect bounds) { }
/**
* Same as above, but accounts for differing icon sizes between source and destination
*
* @param bounds Visual bounds in the views coordinates will be written here.
*/
default void getSourceVisualDragBounds(Rect bounds) {
getWorkspaceVisualDragBounds(bounds);
}
}

View File

@ -87,6 +87,7 @@ import com.android.launcher3.dragndrop.DragController;
import com.android.launcher3.dragndrop.DragController.DragListener;
import com.android.launcher3.dragndrop.DragLayer;
import com.android.launcher3.dragndrop.DragOptions;
import com.android.launcher3.logging.StatsLogManager;
import com.android.launcher3.model.data.AppInfo;
import com.android.launcher3.model.data.FolderInfo;
import com.android.launcher3.model.data.FolderInfo.FolderListener;
@ -1346,6 +1347,10 @@ public class Folder extends AbstractFloatingView implements ClipPathView, DragSo
if (d.stateAnnouncer != null) {
d.stateAnnouncer.completeAction(R.string.item_moved);
}
StatsLogManager.newInstance(getContext())
.log(StatsLogManager.LauncherEvent.LAUNCHER_ITEM_DROP_COMPLETED,
d.logInstanceId,
d.dragInfo.buildProto(mInfo));
}
// This is used so the item doesn't immediately appear in the folder when added. In one case

View File

@ -53,6 +53,7 @@ import com.android.launcher3.R;
import com.android.launcher3.Reorderable;
import com.android.launcher3.Utilities;
import com.android.launcher3.Workspace;
import com.android.launcher3.allapps.AllAppsContainerView;
import com.android.launcher3.anim.Interpolators;
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.dot.FolderDotInfo;
@ -85,7 +86,7 @@ public class FolderIcon extends FrameLayout implements FolderListener, IconLabel
@Thunk ActivityContext mActivity;
@Thunk Folder mFolder;
private FolderInfo mInfo;
public FolderInfo mInfo;
private CheckLongPressHelper mLongPressHelper;
@ -385,6 +386,14 @@ public class FolderIcon extends FrameLayout implements FolderListener, IconLabel
float finalAlpha = index < MAX_NUM_ITEMS_IN_PREVIEW ? 0.5f : 0f;
float finalScale = scale * scaleRelativeToDragLayer;
// Account for potentially different icon sizes with non-default grid settings
if (d.dragSource instanceof AllAppsContainerView) {
DeviceProfile grid = mActivity.getDeviceProfile();
float containerScale = (1f * grid.iconSizePx / grid.allAppsIconSizePx);
finalScale *= containerScale;
}
dragLayer.animateView(animateView, from, to, finalAlpha,
1, 1, finalScale, finalScale, DROP_IN_ANIMATION_DURATION,
Interpolators.DEACCEL_2, Interpolators.ACCEL_2,
@ -758,7 +767,7 @@ public class FolderIcon extends FrameLayout implements FolderListener, IconLabel
}
@Override
public void getVisualDragBounds(Rect bounds) {
public void getWorkspaceVisualDragBounds(Rect bounds) {
getPreviewBounds(bounds);
}
}

Some files were not shown because too many files have changed in this diff Show More