Merging from ub-launcher3-rvc-dev @ build 6538292 am: d67be77066

Change-Id: I478bf64e645d189e29086a3f13af7eec60dbc194
This commit is contained in:
Tracy Zhou
2020-05-29 17:20:48 +00:00
committed by Automerger Merge Worker
234 changed files with 1832 additions and 1876 deletions
+11
View File
@@ -49,15 +49,26 @@ message ContainerInfo {
FolderContainer folder = 3;
AllAppsContainer all_apps_container = 4;
WidgetsContainer widgets_container = 5;
PredictionContainer prediction_container = 6;
SearchResultContainer search_result_container = 7;
}
}
// Represents the apps list sorted alphabetically inside the all-apps view.
message AllAppsContainer {
}
message WidgetsContainer {
}
// Represents the predicted apps row(top row) in the all-apps view.
message PredictionContainer {
}
// Represents the apps container within search results.
message SearchResultContainer {
}
enum Origin {
UNKNOWN = 0;
DEFAULT_LAYOUT = 1; // icon automatically placed in workspace, folder, hotseat
@@ -18,6 +18,7 @@
android:id="@+id/drag_layer"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clipChildren="false"
android:fitsSystemWindows="true">
<com.android.quickstep.fallback.FallbackRecentsView
@@ -19,8 +19,8 @@ package com.android.launcher3;
import static com.android.launcher3.LauncherState.NORMAL;
import static com.android.launcher3.anim.Interpolators.AGGRESSIVE_EASE;
import static com.android.launcher3.anim.Interpolators.LINEAR;
import static com.android.quickstep.TaskViewUtils.createRecentsWindowAnimator;
import static com.android.quickstep.TaskViewUtils.findTaskViewToLaunch;
import static com.android.quickstep.TaskViewUtils.getRecentsWindowAnimator;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
@@ -34,6 +34,7 @@ import androidx.annotation.Nullable;
import com.android.launcher3.anim.AnimatorPlaybackController;
import com.android.launcher3.anim.Interpolators;
import com.android.launcher3.anim.PendingAnimation;
import com.android.quickstep.views.RecentsView;
import com.android.quickstep.views.TaskView;
import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
@@ -63,9 +64,10 @@ public final class LauncherAppTransitionManagerImpl extends QuickstepAppTransiti
boolean skipLauncherChanges = !launcherClosing;
TaskView taskView = findTaskViewToLaunch(mLauncher, v, appTargets);
Animator recentsAnimator = getRecentsWindowAnimator(taskView, skipLauncherChanges,
appTargets, wallpaperTargets, mLauncher.getDepthController());
anim.play(recentsAnimator.setDuration(RECENTS_LAUNCH_DURATION));
PendingAnimation pa = new PendingAnimation(RECENTS_LAUNCH_DURATION);
createRecentsWindowAnimator(taskView, skipLauncherChanges, appTargets, wallpaperTargets,
mLauncher.getDepthController(), pa);
anim.play(pa.buildAnim());
Animator childStateAnimation = null;
// Found a visible recents task that matches the opening app, lets launch the app from there
@@ -15,6 +15,7 @@
*/
package com.android.launcher3.hybridhotseat;
import static com.android.launcher3.InvariantDeviceProfile.CHANGE_FLAG_GRID;
import static com.android.launcher3.LauncherAnimUtils.SCALE_PROPERTY;
import android.animation.Animator;
@@ -571,8 +572,10 @@ public class HotseatPredictionController implements DragController.DragListener,
@Override
public void onIdpChanged(int changeFlags, InvariantDeviceProfile profile) {
this.mHotSeatItemsCount = profile.numHotseatIcons;
createPredictor();
if ((changeFlags & CHANGE_FLAG_GRID) != 0) {
this.mHotSeatItemsCount = profile.numHotseatIcons;
createPredictor();
}
}
@Override
@@ -94,6 +94,7 @@ public class QuickstepLauncher extends BaseQuickstepLauncher {
super.onCreate(savedInstanceState);
if (FeatureFlags.ENABLE_HYBRID_HOTSEAT.get()) {
mHotseatPredictionController = new HotseatPredictionController(this);
mHotseatPredictionController.createPredictor();
}
}
@@ -177,14 +178,6 @@ public class QuickstepLauncher extends BaseQuickstepLauncher {
}
}
@Override
public void finishBindingItems(int pageBoundFirst) {
super.finishBindingItems(pageBoundFirst);
if (mHotseatPredictionController != null) {
mHotseatPredictionController.createPredictor();
}
}
@Override
public void bindPredictedItems(List<AppInfo> appInfos, IntArray ranks) {
super.bindPredictedItems(appInfos, ranks);
@@ -45,8 +45,10 @@ public class BackgroundAppState extends OverviewState {
if (launcher.getDeviceProfile().isVerticalBarLayout()) {
return super.getVerticalProgress(launcher);
}
RecentsView recentsView = launcher.getOverviewPanel();
int transitionLength = LayoutUtils.getShelfTrackingDistance(launcher,
launcher.getDeviceProfile());
launcher.getDeviceProfile(),
recentsView.getPagedOrientationHandler());
AllAppsTransitionController controller = launcher.getAllAppsController();
float scrollRange = Math.max(controller.getShiftRange(), 1);
float progressDelta = (transitionLength / scrollRange);
@@ -73,9 +75,11 @@ public class BackgroundAppState extends OverviewState {
public ScaleAndTranslation getHotseatScaleAndTranslation(Launcher launcher) {
if ((getVisibleElements(launcher) & HOTSEAT_ICONS) != 0) {
// Translate hotseat offscreen if we show it in overview.
RecentsView recentsView = launcher.getOverviewPanel();
ScaleAndTranslation scaleAndTranslation = super.getHotseatScaleAndTranslation(launcher);
scaleAndTranslation.translationY += LayoutUtils.getShelfTrackingDistance(launcher,
launcher.getDeviceProfile());
launcher.getDeviceProfile(),
recentsView.getPagedOrientationHandler());
return scaleAndTranslation;
}
return super.getHotseatScaleAndTranslation(launcher);
@@ -19,8 +19,7 @@ import static com.android.launcher3.anim.Interpolators.DEACCEL_2;
import static com.android.launcher3.config.FeatureFlags.ENABLE_OVERVIEW_ACTIONS;
import static com.android.launcher3.logging.LoggerUtils.newContainerTarget;
import static com.android.quickstep.SysUINavigationMode.Mode.NO_BUTTON;
import static com.android.quickstep.SysUINavigationMode.Mode.TWO_BUTTONS;
import static com.android.quickstep.SysUINavigationMode.getMode;
import static com.android.quickstep.SysUINavigationMode.hideShelfInTwoButtonLandscape;
import static com.android.quickstep.SysUINavigationMode.removeShelfFromOverview;
import android.content.Context;
@@ -130,10 +129,8 @@ public class OverviewState extends LauncherState {
@Override
public int getVisibleElements(Launcher launcher) {
RecentsView recentsView = launcher.getOverviewPanel();
boolean hideShelfTwoButtonLandscape = getMode(launcher) == TWO_BUTTONS &&
!recentsView.getPagedOrientationHandler().isLayoutNaturalToLauncher();
if (ENABLE_OVERVIEW_ACTIONS.get() && removeShelfFromOverview(launcher) ||
hideShelfTwoButtonLandscape) {
hideShelfInTwoButtonLandscape(launcher, recentsView.getPagedOrientationHandler())) {
return OVERVIEW_BUTTONS;
} else if (launcher.getDeviceProfile().isVerticalBarLayout()) {
return VERTICAL_SWIPE_INDICATOR | OVERVIEW_BUTTONS;
@@ -49,64 +49,62 @@ import static com.android.launcher3.states.StateAnimationConfig.ANIM_WORKSPACE_S
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.Launcher;
import com.android.launcher3.LauncherState;
import com.android.launcher3.LauncherState.ScaleAndTranslation;
import com.android.launcher3.Workspace;
import com.android.launcher3.allapps.AllAppsContainerView;
import com.android.launcher3.allapps.AllAppsTransitionController;
import com.android.launcher3.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.util.RecentsAtomicAnimationFactory;
import com.android.quickstep.views.RecentsView;
/**
* Animation factory for quickstep specific transitions
*/
public class QuickstepAtomicAnimationFactory extends AtomicAnimationFactory<LauncherState> {
public class QuickstepAtomicAnimationFactory extends
RecentsAtomicAnimationFactory<Launcher, 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 int INDEX_SHELF_ANIM = RecentsAtomicAnimationFactory.NEXT_INDEX + 0;
public static final int INDEX_PAUSE_TO_OVERVIEW_ANIM =
RecentsAtomicAnimationFactory.NEXT_INDEX + 1;
private static final int MY_ANIM_COUNT = 2;
protected static final int NEXT_INDEX = RecentsAtomicAnimationFactory.NEXT_INDEX
+ MY_ANIM_COUNT;
public static final long ATOMIC_DURATION_FROM_PAUSED_TO_OVERVIEW = 300;
private final QuickstepLauncher mLauncher;
public QuickstepAtomicAnimationFactory(QuickstepLauncher launcher) {
super(ANIM_COUNT);
mLauncher = launcher;
public QuickstepAtomicAnimationFactory(QuickstepLauncher activity) {
super(activity, MY_ANIM_COUNT);
}
@Override
public Animator createStateElementAnimation(int index, float... values) {
switch (index) {
case INDEX_SHELF_ANIM: {
AllAppsTransitionController aatc = mLauncher.getAllAppsController();
AllAppsTransitionController aatc = mActivity.getAllAppsController();
Animator springAnim = aatc.createSpringAnimation(values);
if ((OVERVIEW.getVisibleElements(mLauncher) & HOTSEAT_ICONS) != 0) {
if ((OVERVIEW.getVisibleElements(mActivity) & HOTSEAT_ICONS) != 0) {
// Translate hotseat with the shelf until reaching overview.
float overviewProgress = OVERVIEW.getVerticalProgress(mLauncher);
ScaleAndTranslation sat = OVERVIEW.getHotseatScaleAndTranslation(mLauncher);
float overviewProgress = OVERVIEW.getVerticalProgress(mActivity);
ScaleAndTranslation sat = OVERVIEW.getHotseatScaleAndTranslation(mActivity);
float shiftRange = aatc.getShiftRange();
if (values.length == 1) {
values = new float[] {aatc.getProgress(), values[0]};
@@ -114,9 +112,9 @@ public class QuickstepAtomicAnimationFactory extends AtomicAnimationFactory<Laun
ValueAnimator hotseatAnim = ValueAnimator.ofFloat(values);
hotseatAnim.addUpdateListener(anim -> {
float progress = (Float) anim.getAnimatedValue();
if (progress >= overviewProgress || mLauncher.isInState(BACKGROUND_APP)) {
if (progress >= overviewProgress || mActivity.isInState(BACKGROUND_APP)) {
float hotseatShift = (progress - overviewProgress) * shiftRange;
mLauncher.getHotseat().setTranslationY(hotseatShift + sat.translationY);
mActivity.getHotseat().setTranslationY(hotseatShift + sat.translationY);
}
});
hotseatAnim.setInterpolator(LINEAR);
@@ -130,34 +128,21 @@ public class QuickstepAtomicAnimationFactory extends AtomicAnimationFactory<Laun
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) {
if ((OVERVIEW.getVisibleElements(mActivity) & HOTSEAT_ICONS) != 0) {
config.setInterpolator(ANIM_HOTSEAT_SCALE, OVERSHOOT_1_2);
config.setInterpolator(ANIM_HOTSEAT_TRANSLATE, OVERSHOOT_1_2);
}
StateManager<LauncherState> stateManager = mLauncher.getStateManager();
StateManager<LauncherState> stateManager = mActivity.getStateManager();
return stateManager.createAtomicAnimation(
stateManager.getCurrentStableState(), OVERVIEW, config);
}
default:
return super.createStateElementAnimation(index, values);
}
@@ -172,7 +157,7 @@ public class QuickstepAtomicAnimationFactory extends AtomicAnimationFactory<Laun
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();
Workspace workspace = mActivity.getWorkspace();
// Start from a higher workspace scale, but only if we're invisible so we don't jump.
boolean isWorkspaceVisible = workspace.getVisibility() == VISIBLE;
@@ -186,13 +171,13 @@ public class QuickstepAtomicAnimationFactory extends AtomicAnimationFactory<Laun
workspace.setScaleX(0.92f);
workspace.setScaleY(0.92f);
}
Hotseat hotseat = mLauncher.getHotseat();
Hotseat hotseat = mActivity.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();
AllAppsContainerView qsbContainer = mActivity.getAppsView();
View qsb = qsbContainer.getSearchView();
boolean qsbVisible = qsb.getVisibility() == VISIBLE && qsb.getAlpha() > 0;
if (!qsbVisible) {
@@ -209,7 +194,7 @@ public class QuickstepAtomicAnimationFactory extends AtomicAnimationFactory<Laun
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) {
if (SysUINavigationMode.getMode(mActivity) == NO_BUTTON) {
config.setInterpolator(ANIM_WORKSPACE_SCALE,
fromState == NORMAL ? ACCEL : OVERSHOOT_1_2);
config.setInterpolator(ANIM_WORKSPACE_TRANSLATE, ACCEL);
@@ -217,7 +202,7 @@ public class QuickstepAtomicAnimationFactory extends AtomicAnimationFactory<Laun
config.setInterpolator(ANIM_WORKSPACE_SCALE, OVERSHOOT_1_2);
// Scale up the recents, if it is not coming from the side
RecentsView overview = mLauncher.getOverviewPanel();
RecentsView overview = mActivity.getOverviewPanel();
if (overview.getVisibility() != VISIBLE || overview.getContentAlpha() == 0) {
SCALE_PROPERTY.set(overview, RECENTS_PREPARE_SCALE);
}
@@ -225,7 +210,7 @@ public class QuickstepAtomicAnimationFactory extends AtomicAnimationFactory<Laun
config.setInterpolator(ANIM_WORKSPACE_FADE, OVERSHOOT_1_2);
config.setInterpolator(ANIM_OVERVIEW_SCALE, OVERSHOOT_1_2);
Interpolator translationInterpolator = ENABLE_OVERVIEW_ACTIONS.get()
&& removeShelfFromOverview(mLauncher)
&& removeShelfFromOverview(mActivity)
? OVERSHOOT_1_2
: OVERSHOOT_1_7;
config.setInterpolator(ANIM_OVERVIEW_TRANSLATE_X, translationInterpolator);
@@ -116,7 +116,7 @@ public class NoButtonQuickSwitchTouchController implements TouchController,
mRecentsView = mLauncher.getOverviewPanel();
mXRange = mLauncher.getDeviceProfile().widthPx / 2f;
mYRange = LayoutUtils.getShelfTrackingDistance(
mLauncher, mLauncher.getDeviceProfile());
mLauncher, mLauncher.getDeviceProfile(), mRecentsView.getPagedOrientationHandler());
mMotionPauseDetector = new MotionPauseDetector(mLauncher);
mMotionPauseMinDisplacement = mLauncher.getResources().getDimension(
R.dimen.motion_pause_detector_min_displacement_from_app);
@@ -77,7 +77,6 @@ final class AppToOverviewAnimationProvider<T extends StatefulActivity<?>> extend
controller.dispatchOnStart();
controller.getAnimationPlayer().end();
});
factory.onRemoteAnimationReceived(null);
factory.createActivityInterface(RECENTS_LAUNCH_DURATION);
factory.setRecentsAttachedToAppWindow(true, false);
mActivity = activity;
@@ -137,10 +136,13 @@ final class AppToOverviewAnimationProvider<T extends StatefulActivity<?>> extend
new SyncRtSurfaceTransactionApplierCompat(mActivity.getRootView()));
AnimatedFloat recentsAlpha = new AnimatedFloat(() -> { });
params.setBaseAlphaCallback((t, a) -> recentsAlpha.value);
params.setBaseBuilderProxy((builder, app, p)
-> builder.withAlpha(recentsAlpha.value));
Interpolator taskInterpolator;
if (targets.isAnimatingHome()) {
params.setHomeBuilderProxy((builder, app, p) -> builder.withAlpha(1 - p.getProgress()));
taskInterpolator = TOUCH_RESPONSE_INTERPOLATOR;
pa.addFloat(recentsAlpha, AnimatedFloat.VALUE, 0, 1, TOUCH_RESPONSE_INTERPOLATOR);
} else {
@@ -55,7 +55,6 @@ import com.android.launcher3.views.FloatingIconView;
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.RectFSpringAnim;
import com.android.quickstep.util.TaskViewSimulator;
import com.android.quickstep.util.TransformParams;
@@ -234,7 +233,6 @@ public abstract class BaseSwipeUpHandler<T extends StatefulActivity<?>, Q extend
}
mCanceled = false;
}
ActiveGestureLog.INSTANCE.addLog("finishRecentsAnimation", true);
}
/**
@@ -247,7 +245,9 @@ public abstract class BaseSwipeUpHandler<T extends StatefulActivity<?>, Q extend
protected void onRestartLastAppearedTask() {
// Finish the controller here, since we won't get onTaskAppeared() for a task that already
// appeared.
mRecentsAnimationController.finish(false, null);
if (mRecentsAnimationController != null) {
mRecentsAnimationController.finish(false, null);
}
}
/**
@@ -329,6 +329,7 @@ public abstract class BaseSwipeUpHandler<T extends StatefulActivity<?>, Q extend
mRecentsAnimationController.finish(false /* toRecents */,
null /* onFinishComplete */);
mActivityInterface.onLaunchTaskSuccess();
ActiveGestureLog.INSTANCE.addLog("finishRecentsAnimation", false);
}
}
}
@@ -357,12 +358,13 @@ public abstract class BaseSwipeUpHandler<T extends StatefulActivity<?>, Q extend
protected void initTransitionEndpoints(DeviceProfile dp) {
mDp = dp;
mTransitionDragLength = mActivityInterface.getSwipeUpDestinationAndLength(
dp, mContext, TEMP_RECT);
mTaskViewSimulator.setDp(dp);
mTaskViewSimulator.setLayoutRotation(
mDeviceState.getCurrentActiveRotation(),
mDeviceState.getDisplayRotation());
mTransitionDragLength = mActivityInterface.getSwipeUpDestinationAndLength(
dp, mContext, TEMP_RECT,
mTaskViewSimulator.getOrientationState().getOrientationHandler());
if (mDeviceState.isFullyGesturalNavMode()) {
// We can drag all the way to the top of the screen.
@@ -510,8 +512,8 @@ public abstract class BaseSwipeUpHandler<T extends StatefulActivity<?>, Q extend
public interface Factory {
BaseSwipeUpHandler newHandler(GestureState gestureState, long touchTimeMs,
boolean continuingLastGesture, boolean isLikelyToStartNewTask);
BaseSwipeUpHandler newHandler(
GestureState gestureState, long touchTimeMs, boolean continuingLastGesture);
}
protected interface RunningWindowAnim {
@@ -17,7 +17,6 @@ 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.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;
@@ -38,29 +37,24 @@ import static com.android.quickstep.util.ShelfPeekAnim.ShelfAnimState.PEEK;
import static com.android.quickstep.views.RecentsView.UPDATE_SYSUI_FLAGS_THRESHOLD;
import android.animation.Animator;
import android.animation.AnimatorSet;
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.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;
import android.view.WindowInsets;
import android.view.animation.Interpolator;
import androidx.annotation.NonNull;
import androidx.annotation.UiThread;
import com.android.launcher3.AbstractFloatingView;
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;
@@ -72,7 +66,6 @@ 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.GestureState.GestureEndTarget;
import com.android.quickstep.inputconsumers.OverviewInputConsumer;
@@ -80,8 +73,6 @@ import com.android.quickstep.util.ActiveGestureLog;
import com.android.quickstep.util.RectFSpringAnim;
import com.android.quickstep.util.ShelfPeekAnim;
import com.android.quickstep.util.ShelfPeekAnim.ShelfAnimState;
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;
@@ -92,11 +83,12 @@ import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
/**
* Handles the navigation gestures when Launcher is the default home activity.
* TODO: Merge this with BaseSwipeUpHandler
*/
@TargetApi(Build.VERSION_CODES.O)
public class LauncherSwipeHandler extends BaseSwipeUpHandler<Launcher, RecentsView>
implements OnApplyWindowInsetsListener {
private static final String TAG = LauncherSwipeHandler.class.getSimpleName();
public abstract class BaseSwipeUpHandlerV2<T extends StatefulActivity<?>, Q extends RecentsView>
extends BaseSwipeUpHandler<T, Q> implements OnApplyWindowInsetsListener {
private static final String TAG = BaseSwipeUpHandlerV2.class.getSimpleName();
private static final String[] STATE_NAMES = DEBUG_STATES ? new String[16] : null;
@@ -108,9 +100,11 @@ public class LauncherSwipeHandler extends BaseSwipeUpHandler<Launcher, RecentsVi
}
// Launcher UI related states
private static final int STATE_LAUNCHER_PRESENT = getFlagForIndex(0, "STATE_LAUNCHER_PRESENT");
private static final int STATE_LAUNCHER_STARTED = getFlagForIndex(1, "STATE_LAUNCHER_STARTED");
private static final int STATE_LAUNCHER_DRAWN = getFlagForIndex(2, "STATE_LAUNCHER_DRAWN");
protected static final int STATE_LAUNCHER_PRESENT =
getFlagForIndex(0, "STATE_LAUNCHER_PRESENT");
protected static final int STATE_LAUNCHER_STARTED =
getFlagForIndex(1, "STATE_LAUNCHER_STARTED");
protected static final int STATE_LAUNCHER_DRAWN = getFlagForIndex(2, "STATE_LAUNCHER_DRAWN");
// Internal initialization states
private static final int STATE_APP_CONTROLLER_RECEIVED =
@@ -122,7 +116,7 @@ public class LauncherSwipeHandler extends BaseSwipeUpHandler<Launcher, RecentsVi
private static final int STATE_SCALED_CONTROLLER_RECENTS =
getFlagForIndex(5, "STATE_SCALED_CONTROLLER_RECENTS");
private static final int STATE_HANDLER_INVALIDATED =
protected static final int STATE_HANDLER_INVALIDATED =
getFlagForIndex(6, "STATE_HANDLER_INVALIDATED");
private static final int STATE_GESTURE_STARTED =
getFlagForIndex(7, "STATE_GESTURE_STARTED");
@@ -163,7 +157,7 @@ public class LauncherSwipeHandler extends BaseSwipeUpHandler<Launcher, RecentsVi
*/
private static final int LOG_NO_OP_PAGE_INDEX = -1;
private final TaskAnimationManager mTaskAnimationManager;
protected final TaskAnimationManager mTaskAnimationManager;
// Either RectFSpringAnim (if animating home) or ObjectAnimator (from mCurrentShift) otherwise
private RunningWindowAnim mRunningWindowAnim;
@@ -193,7 +187,7 @@ public class LauncherSwipeHandler extends BaseSwipeUpHandler<Launcher, RecentsVi
private final Runnable mOnDeferredActivityLaunch = this::onDeferredActivityLaunch;
public LauncherSwipeHandler(Context context, RecentsAnimationDeviceState deviceState,
public BaseSwipeUpHandlerV2(Context context, RecentsAnimationDeviceState deviceState,
TaskAnimationManager taskAnimationManager, GestureState gestureState,
long touchTimeMs, boolean continuingLastGesture,
InputConsumerController inputConsumer) {
@@ -222,9 +216,6 @@ public class LauncherSwipeHandler extends BaseSwipeUpHandler<Launcher, RecentsVi
| STATE_GESTURE_CANCELLED,
this::resetStateForAnimationCancel);
mStateCallback.runOnceAtState(STATE_LAUNCHER_STARTED | STATE_APP_CONTROLLER_RECEIVED,
this::sendRemoteAnimationsToAnimationFactory);
mStateCallback.runOnceAtState(STATE_RESUME_LAST_TASK | STATE_APP_CONTROLLER_RECEIVED,
this::resumeLastTask);
mStateCallback.runOnceAtState(STATE_START_NEW_TASK | STATE_SCREENSHOT_CAPTURED,
@@ -272,7 +263,7 @@ public class LauncherSwipeHandler extends BaseSwipeUpHandler<Launcher, RecentsVi
@Override
protected boolean onActivityInit(Boolean alreadyOnHome) {
super.onActivityInit(alreadyOnHome);
final Launcher activity = mActivityInterface.getCreatedActivity();
final T activity = mActivityInterface.getCreatedActivity();
if (mActivity == activity) {
return true;
}
@@ -323,7 +314,7 @@ public class LauncherSwipeHandler extends BaseSwipeUpHandler<Launcher, RecentsVi
}
private void onLauncherStart() {
final Launcher activity = mActivityInterface.getCreatedActivity();
final T activity = mActivityInterface.getCreatedActivity();
if (mActivity != activity) {
return;
}
@@ -411,6 +402,10 @@ public class LauncherSwipeHandler extends BaseSwipeUpHandler<Launcher, RecentsVi
updateSysUiFlags(mCurrentShift.value);
return;
}
notifyGestureAnimationStartToRecents();
}
protected void notifyGestureAnimationStartToRecents() {
mRecentsView.onGestureAnimationStart(mGestureState.getRunningTaskId());
}
@@ -418,10 +413,6 @@ public class LauncherSwipeHandler extends BaseSwipeUpHandler<Launcher, RecentsVi
mLauncherFrameDrawnTime = SystemClock.uptimeMillis();
}
private void sendRemoteAnimationsToAnimationFactory() {
mAnimationFactory.onRemoteAnimationReceived(mRecentsAnimationTargets);
}
private void initializeLauncherAnimationController() {
buildAnimationController();
@@ -633,7 +624,7 @@ public class LauncherSwipeHandler extends BaseSwipeUpHandler<Launcher, RecentsVi
*/
@UiThread
private void notifyGestureStartedAsync() {
final Launcher curActivity = mActivity;
final T 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
@@ -679,10 +670,6 @@ public class LauncherSwipeHandler extends BaseSwipeUpHandler<Launcher, RecentsVi
protected InputConsumer createNewInputProxyHandler() {
endRunningWindowAnim(mGestureState.getEndTarget() == HOME /* cancel */);
endLauncherTransitionController();
if (!ENABLE_QUICKSTEP_LIVE_TILE.get()) {
// Hide the task view, if not already hidden
setTargetAlphaProvider(LauncherSwipeHandler::getHiddenTargetAlpha);
}
StatefulActivity activity = mActivityInterface.getCreatedActivity();
return activity == null ? InputConsumer.NO_OP
@@ -717,6 +704,7 @@ public class LauncherSwipeHandler extends BaseSwipeUpHandler<Launcher, RecentsVi
mStateCallback.setState(STATE_RESUME_LAST_TASK);
break;
}
ActiveGestureLog.INSTANCE.addLog("onSettledOnEndTarget " + mGestureState.getEndTarget());
}
@Override
@@ -787,12 +775,6 @@ public class LauncherSwipeHandler extends BaseSwipeUpHandler<Launcher, RecentsVi
}
}
if (endTarget == RECENTS || endTarget == HOME) {
// Since we're now done quickStepping, we want to only listen for touch events
// for the main orientation's nav bar, instead of multiple
mDeviceState.enableMultipleRegions(false);
}
if (mDeviceState.isOverviewDisabled() && (endTarget == RECENTS || endTarget == LAST_TASK)) {
return LAST_TASK;
}
@@ -911,6 +893,8 @@ public class LauncherSwipeHandler extends BaseSwipeUpHandler<Launcher, RecentsVi
interpolator, target, velocityPxPerMs));
}
protected abstract HomeAnimationFactory createHomeAnimationFactory(long duration);
@UiThread
private void animateToProgressInternal(float start, float end, long duration,
Interpolator interpolator, GestureEndTarget target, PointF velocityPxPerMs) {
@@ -919,67 +903,7 @@ public class LauncherSwipeHandler extends BaseSwipeUpHandler<Launcher, RecentsVi
maybeUpdateRecentsAttachedState();
if (mGestureState.getEndTarget() == HOME) {
HomeAnimationFactory homeAnimFactory;
if (mActivity != null) {
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);
mActivityInterface.setHintUserWillBeActive();
homeAnimFactory = new HomeAnimationFactory(floatingIconView) {
@Override
public RectF getWindowTargetRect() {
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);
}
};
mStateCallback.addChangeListener(STATE_LAUNCHER_PRESENT | STATE_HANDLER_INVALIDATED,
isPresent -> mRecentsView.startHome());
}
HomeAnimationFactory homeAnimFactory = createHomeAnimationFactory(duration);
RectFSpringAnim windowAnim = createWindowAnimationToHome(start, homeAnimFactory);
windowAnim.addAnimatorListener(new AnimationSuccessListener() {
@Override
@@ -1303,14 +1227,16 @@ public class LauncherSwipeHandler extends BaseSwipeUpHandler<Launcher, RecentsVi
// If there are no targets or the animation not started, then there is nothing to finish
mStateCallback.setStateOnUiThread(STATE_CURRENT_TASK_FINISHED);
} else {
mRecentsAnimationController.finish(true /* toRecents */,
() -> mStateCallback.setStateOnUiThread(STATE_CURRENT_TASK_FINISHED),
true /* sendUserLeaveHint */);
finishRecentsControllerToHome(
() -> mStateCallback.setStateOnUiThread(STATE_CURRENT_TASK_FINISHED));
}
ActiveGestureLog.INSTANCE.addLog("finishRecentsAnimation", true);
doLogGesture(HOME);
mDeviceState.enableMultipleRegions(false);
}
protected abstract void finishRecentsControllerToHome(Runnable callback);
private void setupLauncherUiAfterSwipeUpToRecentsAnimation() {
endLauncherTransitionController();
mActivityInterface.onSwipeUpToRecentsComplete();
@@ -1322,14 +1248,10 @@ public class LauncherSwipeHandler extends BaseSwipeUpHandler<Launcher, RecentsVi
SystemUiProxy.INSTANCE.get(mContext).onOverviewShown(false, TAG);
doLogGesture(RECENTS);
mDeviceState.onSwipeUpToOverview(mActivityInterface);
reset();
}
private void setTargetAlphaProvider(TargetAlphaProvider provider) {
mTransformParams.setTaskAlphaCallback(provider);
updateFinalShift();
}
private void addLiveTileOverlay() {
if (LiveTileOverlay.INSTANCE.attach(mActivity.getRootView().getOverlay())) {
mRecentsView.setLiveTileOverlayAttached(true);
@@ -1341,13 +1263,6 @@ public class LauncherSwipeHandler extends BaseSwipeUpHandler<Launcher, RecentsVi
mRecentsView.setLiveTileOverlayAttached(false);
}
public static float getHiddenTargetAlpha(RemoteAnimationTargetCompat app, float expectedAlpha) {
if (!isNotInRecents(app)) {
return 0;
}
return expectedAlpha;
}
private static boolean isNotInRecents(RemoteAnimationTargetCompat app) {
return app.isNotInRecents
|| app.activityType == RemoteAnimationTargetCompat.ACTIVITY_TYPE_HOME;
@@ -15,26 +15,21 @@
*/
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.RecentsState.BACKGROUND_APP;
import static com.android.quickstep.fallback.RecentsState.DEFAULT;
import static com.android.quickstep.views.RecentsView.CONTENT_ALPHA;
import static com.android.quickstep.views.RecentsView.FULLSCREEN_PROGRESS;
import android.content.Context;
import android.graphics.PointF;
import android.graphics.Rect;
import android.view.MotionEvent;
import androidx.annotation.Nullable;
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.R;
import com.android.launcher3.anim.AnimatorPlaybackController;
import com.android.launcher3.anim.PendingAnimation;
import com.android.launcher3.touch.PagedOrientationHandler;
import com.android.launcher3.userevent.nano.LauncherLogProto;
import com.android.quickstep.fallback.FallbackRecentsView;
import com.android.quickstep.fallback.RecentsState;
import com.android.quickstep.util.ActivityInitListener;
import com.android.quickstep.views.RecentsView;
@@ -54,12 +49,14 @@ public final class FallbackActivityInterface extends
public static final FallbackActivityInterface INSTANCE = new FallbackActivityInterface();
private FallbackActivityInterface() {
super(false);
super(false, DEFAULT, BACKGROUND_APP);
}
/** 2 */
@Override
public int getSwipeUpDestinationAndLength(DeviceProfile dp, Context context, Rect outRect) {
calculateTaskSize(context, dp, outRect);
public int getSwipeUpDestinationAndLength(DeviceProfile dp, Context context, Rect outRect,
PagedOrientationHandler orientationHandler) {
calculateTaskSize(context, dp, outRect, orientationHandler);
if (dp.isVerticalBarLayout()
&& SysUINavigationMode.INSTANCE.get(context).getMode() != NO_BUTTON) {
Rect targetInsets = dp.getInsets();
@@ -70,6 +67,13 @@ public final class FallbackActivityInterface extends
}
}
/** 4 */
@Override
public void onSwipeUpToHomeComplete() {
onSwipeUpToRecentsComplete();
}
/** 5 */
@Override
public void onAssistantVisibilityChanged(float visibility) {
// This class becomes active when the screen is locked.
@@ -77,50 +81,13 @@ public final class FallbackActivityInterface extends
// set to zero prior to this class becoming active.
}
/** 6 */
@Override
public AnimationFactory prepareRecentsUI(
boolean activityVisible, Consumer<AnimatorPlaybackController> callback) {
RecentsActivity activity = getCreatedActivity();
if (activity == null) {
return (transitionLength) -> { };
}
activity.getStateManager().goToState(BACKGROUND_APP);
FallbackRecentsView rv = activity.getOverviewPanel();
rv.setContentAlpha(0);
return new AnimationFactory() {
boolean isAnimatingToRecents = false;
@Override
public void onRemoteAnimationReceived(RemoteAnimationTargets targets) {
isAnimatingToRecents = targets != null && targets.isAnimatingHome();
if (!isAnimatingToRecents) {
rv.setContentAlpha(1);
}
createActivityInterface(getSwipeUpDestinationAndLength(
activity.getDeviceProfile(), activity, new Rect()));
}
@Override
public void createActivityInterface(long transitionLength) {
PendingAnimation pa = new PendingAnimation(transitionLength * 2);
if (isAnimatingToRecents) {
pa.addFloat(rv, CONTENT_ALPHA, 0, 1, LINEAR);
}
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(() -> activity.getStateManager().goToState(
controller.getInterpolatedProgress() > 0.5 ? DEFAULT : BACKGROUND_APP));
callback.accept(controller);
}
};
DefaultAnimationFactory factory = new DefaultAnimationFactory(callback);
factory.initUI();
return factory;
}
@Override
@@ -163,6 +130,20 @@ public final class FallbackActivityInterface extends
return false;
}
@Override
public boolean deferStartingActivity(RecentsAnimationDeviceState deviceState, MotionEvent ev) {
// In non-gesture mode, user might be clicking on the home button which would directly
// start the home activity instead of going through recents. In that case, defer starting
// recents until we are sure it is a gesture.
return !deviceState.isFullyGesturalNavMode()
|| super.deferStartingActivity(deviceState, ev);
}
@Override
public void onExitOverview(RecentsAnimationDeviceState deviceState, Runnable exitRunnable) {
// no-op, fake landscape not supported for 3P
}
@Override
public int getContainerType() {
RecentsActivity activity = getCreatedActivity();
@@ -188,12 +169,8 @@ public final class FallbackActivityInterface extends
}
@Override
public void getMultiWindowSize(Context context, DeviceProfile dp, PointF out) {
out.set(dp.widthPx, dp.heightPx);
}
@Override
protected float getExtraSpace(Context context, DeviceProfile dp) {
protected float getExtraSpace(Context context, DeviceProfile dp,
PagedOrientationHandler orientationHandler) {
return showOverviewActions(context)
? context.getResources().getDimensionPixelSize(R.dimen.overview_actions_height)
: 0;
@@ -15,537 +15,198 @@
*/
package com.android.quickstep;
import static com.android.launcher3.anim.Interpolators.ACCEL_1_5;
import static com.android.launcher3.anim.Interpolators.ACCEL_2;
import static com.android.quickstep.GestureState.GestureEndTarget.HOME;
import static com.android.quickstep.GestureState.GestureEndTarget.LAST_TASK;
import static com.android.quickstep.GestureState.GestureEndTarget.NEW_TASK;
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.views.RecentsView.UPDATE_SYSUI_FLAGS_THRESHOLD;
import static com.android.launcher3.anim.Interpolators.ACCEL;
import static com.android.systemui.shared.system.RemoteAnimationTargetCompat.ACTIVITY_TYPE_HOME;
import android.animation.Animator;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.app.ActivityOptions;
import android.content.Context;
import android.content.Intent;
import android.graphics.PointF;
import android.os.Bundle;
import android.util.ArrayMap;
import android.view.MotionEvent;
import android.graphics.Matrix;
import androidx.annotation.NonNull;
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.R;
import com.android.launcher3.anim.AnimationSuccessListener;
import com.android.launcher3.Utilities;
import com.android.launcher3.anim.AnimatorPlaybackController;
import com.android.launcher3.util.ObjectWrapper;
import com.android.quickstep.BaseActivityInterface.AnimationFactory;
import com.android.quickstep.GestureState.GestureEndTarget;
import com.android.launcher3.anim.PendingAnimation;
import com.android.launcher3.anim.SpringAnimationBuilder;
import com.android.quickstep.fallback.FallbackRecentsView;
import com.android.quickstep.util.RectFSpringAnim;
import com.android.systemui.shared.recents.model.ThumbnailData;
import com.android.quickstep.util.TransformParams;
import com.android.quickstep.util.TransformParams.BuilderProxy;
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;
import com.android.systemui.shared.system.SyncRtSurfaceTransactionApplierCompat.SurfaceParams;
/**
* Handles the navigation gestures when a 3rd party launcher is the default home activity.
*/
public class FallbackSwipeHandler extends BaseSwipeUpHandler<RecentsActivity, FallbackRecentsView> {
public class FallbackSwipeHandler extends
BaseSwipeUpHandlerV2<RecentsActivity, FallbackRecentsView> {
private static final String[] STATE_NAMES = DEBUG_STATES ? new String[5] : null;
private static int getFlagForIndex(int index, String name) {
if (DEBUG_STATES) {
STATE_NAMES[index] = name;
}
return 1 << index;
}
private static final int STATE_RECENTS_PRESENT =
getFlagForIndex(0, "STATE_RECENTS_PRESENT");
private static final int STATE_HANDLER_INVALIDATED =
getFlagForIndex(1, "STATE_HANDLER_INVALIDATED");
private static final int STATE_GESTURE_CANCELLED =
getFlagForIndex(2, "STATE_GESTURE_CANCELLED");
private static final int STATE_GESTURE_COMPLETED =
getFlagForIndex(3, "STATE_GESTURE_COMPLETED");
private static final int STATE_APP_CONTROLLER_RECEIVED =
getFlagForIndex(4, "STATE_APP_CONTROLLER_RECEIVED");
public static class EndTargetAnimationParams {
private final float mEndProgress;
private final long mDurationMultiplier;
private final float mLauncherAlpha;
EndTargetAnimationParams(float endProgress, long durationMultiplier, float launcherAlpha) {
mEndProgress = endProgress;
mDurationMultiplier = durationMultiplier;
mLauncherAlpha = launcherAlpha;
}
}
private final ArrayMap<GestureEndTarget, EndTargetAnimationParams>
mEndTargetAnimationParams = new ArrayMap();
private final AnimatedFloat mLauncherAlpha = new AnimatedFloat(this::onLauncherAlphaChanged);
private boolean mOverviewThresholdPassed = false;
private final boolean mInQuickSwitchMode;
private final boolean mContinuingLastGesture;
private FallbackHomeAnimationFactory mActiveAnimationFactory;
private final boolean mRunningOverHome;
private final boolean mSwipeUpOverHome;
private boolean mTouchedHomeDuringTransition;
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) -> { };
private final Matrix mTmpMatrix = new Matrix();
private float mMaxLauncherScale = 1;
public FallbackSwipeHandler(Context context, RecentsAnimationDeviceState deviceState,
GestureState gestureState, InputConsumerController inputConsumer,
boolean isLikelyToStartNewTask, boolean continuingLastGesture) {
super(context, deviceState, gestureState, inputConsumer);
TaskAnimationManager taskAnimationManager, GestureState gestureState, long touchTimeMs,
boolean continuingLastGesture, InputConsumerController inputConsumer) {
super(context, deviceState, taskAnimationManager, gestureState, touchTimeMs,
continuingLastGesture, inputConsumer);
mInQuickSwitchMode = isLikelyToStartNewTask || continuingLastGesture;
mContinuingLastGesture = continuingLastGesture;
mRunningOverHome = ActivityManagerWrapper.isHomeTask(mGestureState.getRunningTask());
mSwipeUpOverHome = mRunningOverHome && !mInQuickSwitchMode;
// Keep the home launcher invisible until we decide to land there.
mLauncherAlpha.value = mRunningOverHome ? 1 : 0;
if (mSwipeUpOverHome) {
mTransformParams.setBaseAlphaCallback((t, a) -> 1 - mLauncherAlpha.value);
} else {
mTransformParams.setBaseAlphaCallback((t, a) -> mLauncherAlpha.value);
if (mRunningOverHome) {
mTransformParams.setHomeBuilderProxy(this::updateHomeActivityTransformDuringSwipeUp);
}
// Going home has an extra long progress to ensure that it animates into the screen
mEndTargetAnimationParams.put(HOME, new EndTargetAnimationParams(3, 100, 1));
mEndTargetAnimationParams.put(RECENTS, new EndTargetAnimationParams(1, 300, 0));
mEndTargetAnimationParams.put(LAST_TASK, new EndTargetAnimationParams(0, 150, 1));
mEndTargetAnimationParams.put(NEW_TASK, new EndTargetAnimationParams(0, 150, 1));
initAfterSubclassConstructor();
initStateCallbacks();
}
private void initStateCallbacks() {
mStateCallback = new MultiStateCallback(STATE_NAMES);
mStateCallback.runOnceAtState(STATE_HANDLER_INVALIDATED,
this::onHandlerInvalidated);
mStateCallback.runOnceAtState(STATE_RECENTS_PRESENT | STATE_HANDLER_INVALIDATED,
this::onHandlerInvalidatedWithRecents);
mStateCallback.runOnceAtState(STATE_GESTURE_CANCELLED | STATE_APP_CONTROLLER_RECEIVED,
this::finishAnimationTargetSetAnimationComplete);
if (mInQuickSwitchMode) {
mStateCallback.runOnceAtState(STATE_GESTURE_COMPLETED | STATE_APP_CONTROLLER_RECEIVED
| STATE_RECENTS_PRESENT,
this::finishAnimationTargetSet);
} else {
mStateCallback.runOnceAtState(STATE_GESTURE_COMPLETED | STATE_APP_CONTROLLER_RECEIVED,
this::finishAnimationTargetSet);
}
}
private void onLauncherAlphaChanged() {
if (mRecentsAnimationTargets != null && mGestureState.getEndTarget() == null) {
applyWindowTransform();
}
}
@Override
protected boolean onActivityInit(Boolean alreadyOnHome) {
super.onActivityInit(alreadyOnHome);
mActivity = mActivityInterface.getCreatedActivity();
mRecentsView = mActivity.getOverviewPanel();
mRecentsView.setOnPageTransitionEndCallback(null);
linkRecentsViewScroll();
if (!mContinuingLastGesture) {
if (mRunningOverHome) {
mRecentsView.onGestureAnimationStart(mGestureState.getRunningTask());
} else {
mRecentsView.onGestureAnimationStart(mGestureState.getRunningTaskId());
}
}
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);
if (mRunningOverHome) {
mMaxLauncherScale = 1 / mTaskViewSimulator.getFullScreenScale();
}
}
private void onAnimatorPlaybackControllerCreated(AnimatorPlaybackController anim) {
mLauncherTransitionController = anim;
mLauncherTransitionController.dispatchSetInterpolator(t -> t * mDragLengthFactor);
mLauncherTransitionController.dispatchOnStart();
updateLauncherTransitionProgress();
private void updateHomeActivityTransformDuringSwipeUp(SurfaceParams.Builder builder,
RemoteAnimationTargetCompat app, TransformParams params) {
setHomeScaleAndAlpha(builder, app, mCurrentShift.value,
Utilities.boundToRange(1 - mCurrentShift.value, 0, 1));
}
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;
private void setHomeScaleAndAlpha(SurfaceParams.Builder builder,
RemoteAnimationTargetCompat app, float verticalShift, float alpha) {
float scale = Utilities.mapRange(verticalShift, 1, mMaxLauncherScale);
mTmpMatrix.setScale(scale, scale,
app.localBounds.exactCenterX(), app.localBounds.exactCenterY());
builder.withMatrix(mTmpMatrix).withAlpha(alpha);
}
@Override
protected boolean moveWindowWithRecentsScroll() {
return mInQuickSwitchMode;
}
@Override
public void initWhenReady(Intent intent) {
if (mInQuickSwitchMode) {
// Only init if we are in quickswitch mode
super.initWhenReady(intent);
}
}
@Override
public void updateDisplacement(float displacement) {
if (!mInQuickSwitchMode) {
super.updateDisplacement(displacement);
}
}
@Override
protected InputConsumer createNewInputProxyHandler() {
// Just consume all input on the active task
return new InputConsumer() {
@Override
public int getType() {
return InputConsumer.TYPE_NO_OP;
}
@Override
public void onMotionEvent(MotionEvent ev) {
mTouchedHomeDuringTransition = true;
}
};
}
@Override
public void onMotionPauseChanged(boolean isPaused) {
if (!mInQuickSwitchMode && mDeviceState.isFullyGesturalNavMode()) {
updateOverviewThresholdPassed(isPaused);
}
}
private void updateOverviewThresholdPassed(boolean passed) {
if (passed != mOverviewThresholdPassed) {
mOverviewThresholdPassed = passed;
if (mSwipeUpOverHome) {
mLauncherAlpha.animateToValue(mLauncherAlpha.value, passed ? 0 : 1)
.setDuration(150).start();
}
performHapticFeedback();
}
}
@Override
public Intent getLaunchIntent() {
if (mInQuickSwitchMode || mSwipeUpOverHome || !mDeviceState.isFullyGesturalNavMode()) {
return mGestureState.getOverviewIntent();
} else {
return mGestureState.getHomeIntent();
}
}
@Override
public void updateFinalShift() {
mTransformParams.setProgress(mCurrentShift.value);
if (mRecentsAnimationController != null) {
boolean swipeUpThresholdPassed = mCurrentShift.value > 1 - UPDATE_SYSUI_FLAGS_THRESHOLD;
mRecentsAnimationController.setUseLauncherSystemBarFlags(mInQuickSwitchMode
|| swipeUpThresholdPassed);
mRecentsAnimationController.setSplitScreenMinimized(!mInQuickSwitchMode
&& swipeUpThresholdPassed);
}
if (!mInQuickSwitchMode && !mDeviceState.isFullyGesturalNavMode()) {
updateOverviewThresholdPassed(mCurrentShift.value >= MIN_PROGRESS_FOR_OVERVIEW);
}
applyWindowTransform();
updateLauncherTransitionProgress();
}
@Override
public void onGestureCancelled() {
updateDisplacement(0);
mGestureState.setEndTarget(LAST_TASK);
mStateCallback.setStateOnUiThread(STATE_GESTURE_CANCELLED);
}
@Override
public void onGestureEnded(float endVelocity, PointF velocity, PointF downPos) {
mEndVelocityPxPerMs.set(0, velocity.y / 1000);
if (mInQuickSwitchMode) {
// For now set it to non-null, it will be reset before starting the animation
mGestureState.setEndTarget(LAST_TASK);
} else {
float flingThreshold = mContext.getResources()
.getDimension(R.dimen.quickstep_fling_threshold_velocity);
boolean isFling = Math.abs(endVelocity) > flingThreshold;
if (mDeviceState.isFullyGesturalNavMode()) {
if (isFling) {
mGestureState.setEndTarget(endVelocity < 0 ? HOME : LAST_TASK);
} else if (mOverviewThresholdPassed) {
mGestureState.setEndTarget(RECENTS);
} else {
mGestureState.setEndTarget(mCurrentShift.value >= MIN_PROGRESS_FOR_OVERVIEW
? HOME
: LAST_TASK);
}
} else {
GestureEndTarget startState = mSwipeUpOverHome ? HOME : LAST_TASK;
if (isFling) {
mGestureState.setEndTarget(endVelocity < 0 ? RECENTS : startState);
} else {
mGestureState.setEndTarget(mCurrentShift.value >= MIN_PROGRESS_FOR_OVERVIEW
? RECENTS
: startState);
}
}
}
mStateCallback.setStateOnUiThread(STATE_GESTURE_COMPLETED);
}
@Override
public void onConsumerAboutToBeSwitched() {
if (mInQuickSwitchMode && mGestureState.getEndTarget() != null) {
mGestureState.setEndTarget(NEW_TASK);
mCanceled = true;
mCurrentShift.cancelAnimation();
if (mFinishAnimation != null) {
mFinishAnimation.cancel();
}
if (mRecentsView != null) {
mRecentsView.setOnScrollChangeListener(null);
}
} else {
mStateCallback.setStateOnUiThread(STATE_HANDLER_INVALIDATED);
}
}
private void onHandlerInvalidated() {
mActivityInitListener.unregister();
if (mGestureEndCallback != null) {
mGestureEndCallback.run();
}
if (mFinishAnimation != null) {
mFinishAnimation.end();
}
}
private void onHandlerInvalidatedWithRecents() {
mRecentsView.onGestureAnimationEnd();
mRecentsView.setDisallowScrollToClearAll(false);
mRecentsView.getClearAllButton().setVisibilityAlpha(1);
}
private void finishAnimationTargetSetAnimationComplete() {
switch (mGestureState.getEndTarget()) {
case HOME: {
if (mSwipeUpOverHome) {
mRecentsAnimationController.finish(false, null, false);
// Send a home intent to clear the task stack
mContext.startActivity(mGestureState.getHomeIntent());
} else {
// Notify swipe-to-home (recents animation) is finished
SystemUiProxy.INSTANCE.get(mContext).notifySwipeToHomeFinished();
mRecentsAnimationController.finish(true, () -> {
if (!mTouchedHomeDuringTransition) {
// If the user hasn't interacted with the screen during the transition,
// send a home intent so launcher can go to the default home screen.
// (If they are trying to touch something, we don't want to interfere.)
mContext.startActivity(mGestureState.getHomeIntent());
}
}, true);
}
break;
}
case LAST_TASK:
mRecentsAnimationController.finish(false, null, false);
break;
case RECENTS: {
if (mSwipeUpOverHome || !mDeviceState.isFullyGesturalNavMode()) {
mRecentsAnimationController.finish(true, null, true);
break;
}
final int runningTaskId = mGestureState.getRunningTaskId();
ThumbnailData thumbnail = mRecentsAnimationController.screenshotTask(runningTaskId);
mRecentsAnimationController.setDeferCancelUntilNextTransition(true /* defer */,
false /* screenshot */);
ActivityOptions options = ActivityOptions.makeCustomAnimation(mContext, 0, 0);
ActivityOptionsCompat.setFreezeRecentTasksList(options);
Bundle extras = new Bundle();
extras.putBinder(EXTRA_THUMBNAIL, new ObjectWrapper<>(thumbnail));
extras.putInt(EXTRA_TASK_ID, runningTaskId);
Intent intent = new Intent(mGestureState.getOverviewIntent())
.putExtras(extras);
mContext.startActivity(intent, options.toBundle());
mRecentsAnimationController.cleanupScreenshot();
break;
}
case NEW_TASK: {
startNewTask(success -> { });
break;
}
}
mStateCallback.setStateOnUiThread(STATE_HANDLER_INVALIDATED);
}
private void finishAnimationTargetSet() {
if (mInQuickSwitchMode) {
// Recalculate the end target, some views might have been initialized after
// gesture has ended.
if (mRecentsView == null || !hasTargets()) {
mGestureState.setEndTarget(LAST_TASK);
} else {
final int runningTaskIndex = getLastAppearedTaskIndex();
final int taskToLaunch = mRecentsView.getNextPage();
mGestureState.setEndTarget(
(runningTaskIndex >= 0 && taskToLaunch != runningTaskIndex)
? NEW_TASK
: LAST_TASK);
}
}
EndTargetAnimationParams params = mEndTargetAnimationParams.get(mGestureState.getEndTarget());
float endProgress = params.mEndProgress;
long duration = (long) (params.mDurationMultiplier *
Math.abs(endProgress - mCurrentShift.value));
if (mRecentsView != null) {
duration = Math.max(duration, mRecentsView.getScroller().getDuration());
}
if (mCurrentShift.value != endProgress || mInQuickSwitchMode) {
AnimationSuccessListener endListener = new AnimationSuccessListener() {
@Override
public void onAnimationSuccess(Animator animator) {
if (mRecentsView != null) {
mRecentsView.setOnPageTransitionEndCallback(FallbackSwipeHandler.this
::finishAnimationTargetSetAnimationComplete);
} else {
finishAnimationTargetSetAnimationComplete();
}
mFinishAnimation = null;
}
};
if (mGestureState.getEndTarget() == HOME && !mRunningOverHome) {
mRecentsAnimationController.enableInputProxy(mInputConsumer,
this::createNewInputProxyHandler);
RectFSpringAnim anim = createWindowAnimationToHome(mCurrentShift.value, duration);
anim.addAnimatorListener(endListener);
anim.start(mContext, mEndVelocityPxPerMs);
mFinishAnimation = RunningWindowAnim.wrap(anim);
} else {
AnimatorSet anim = new AnimatorSet();
anim.play(mLauncherAlpha.animateToValue(
mLauncherAlpha.value, params.mLauncherAlpha));
anim.play(mCurrentShift.animateToValue(mCurrentShift.value, endProgress));
anim.setDuration(duration);
anim.addListener(endListener);
anim.start();
mFinishAnimation = RunningWindowAnim.wrap(anim);
}
} else {
finishAnimationTargetSetAnimationComplete();
}
}
@Override
public void onRecentsAnimationStart(RecentsAnimationController controller,
RecentsAnimationTargets targets) {
super.onRecentsAnimationStart(controller, targets);
mRecentsAnimationController.enableInputConsumer();
applyWindowTransform();
mStateCallback.setStateOnUiThread(STATE_APP_CONTROLLER_RECEIVED);
}
@Override
public void onRecentsAnimationCanceled(ThumbnailData thumbnailData) {
mStateCallback.setStateOnUiThread(STATE_HANDLER_INVALIDATED);
// Defer clearing the controller and the targets until after we've updated the state
super.onRecentsAnimationCanceled(thumbnailData);
protected HomeAnimationFactory createHomeAnimationFactory(long duration) {
mActiveAnimationFactory = new FallbackHomeAnimationFactory(duration);
ActivityOptions options = ActivityOptions.makeCustomAnimation(mContext, 0, 0);
mContext.startActivity(new Intent(mGestureState.getHomeIntent()), options.toBundle());
return mActiveAnimationFactory;
}
@Override
protected boolean handleTaskAppeared(RemoteAnimationTargetCompat appearedTaskTarget) {
return true;
}
if (mActiveAnimationFactory != null
&& mActiveAnimationFactory.handleHomeTaskAppeared(appearedTaskTarget)) {
mActiveAnimationFactory = null;
return false;
}
/**
* 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(null) {
@Override
public AnimatorPlaybackController createActivityAnimationToHome() {
AnimatorSet anim = new AnimatorSet();
Animator fadeInLauncher = mLauncherAlpha.animateToValue(mLauncherAlpha.value, 1);
fadeInLauncher.setInterpolator(ACCEL_2);
anim.play(fadeInLauncher);
anim.setDuration(duration);
return AnimatorPlaybackController.wrap(anim, duration);
}
};
return createWindowAnimationToHome(startProgress, factory);
return super.handleTaskAppeared(appearedTaskTarget);
}
@Override
protected float getWindowAlpha(float progress) {
return 1 - ACCEL_1_5.getInterpolation(progress);
protected void finishRecentsControllerToHome(Runnable callback) {
mRecentsAnimationController.finish(
false /* toRecents */, callback, true /* sendUserLeaveHint */);
}
@Override
protected void notifyGestureAnimationStartToRecents() {
if (mRunningOverHome) {
mRecentsView.onGestureAnimationStartOnHome(mGestureState.getRunningTask());
} else {
super.notifyGestureAnimationStartToRecents();
}
}
private class FallbackHomeAnimationFactory extends HomeAnimationFactory {
private final TransformParams mHomeAlphaParams = new TransformParams();
private final AnimatedFloat mHomeAlpha;
private final AnimatedFloat mVerticalShiftForScale = new AnimatedFloat();
private final AnimatedFloat mRecentsAlpha = new AnimatedFloat();
private final long mDuration;
FallbackHomeAnimationFactory(long duration) {
super(null);
mDuration = duration;
if (mRunningOverHome) {
mHomeAlpha = new AnimatedFloat();
mHomeAlpha.value = Utilities.boundToRange(1 - mCurrentShift.value, 0, 1);
mVerticalShiftForScale.value = mCurrentShift.value;
mTransformParams.setHomeBuilderProxy(
this::updateHomeActivityTransformDuringHomeAnim);
} else {
mHomeAlpha = new AnimatedFloat(this::updateHomeAlpha);
mHomeAlpha.value = 0;
mHomeAlphaParams.setHomeBuilderProxy(
this::updateHomeActivityTransformDuringHomeAnim);
}
mRecentsAlpha.value = 1;
mTransformParams.setBaseBuilderProxy(
this::updateRecentsActivityTransformDuringHomeAnim);
}
private void updateRecentsActivityTransformDuringHomeAnim(SurfaceParams.Builder builder,
RemoteAnimationTargetCompat app, TransformParams params) {
builder.withAlpha(mRecentsAlpha.value);
}
private void updateHomeActivityTransformDuringHomeAnim(SurfaceParams.Builder builder,
RemoteAnimationTargetCompat app, TransformParams params) {
setHomeScaleAndAlpha(builder, app, mVerticalShiftForScale.value, mHomeAlpha.value);
}
@NonNull
@Override
public AnimatorPlaybackController createActivityAnimationToHome() {
PendingAnimation pa = new PendingAnimation(mDuration);
pa.setFloat(mRecentsAlpha, AnimatedFloat.VALUE, 0, ACCEL);
return pa.createPlaybackController();
}
private void updateHomeAlpha() {
if (mHomeAlphaParams.getTargetSet() != null) {
mHomeAlphaParams.applySurfaceParams(
mHomeAlphaParams.createSurfaceParams(BuilderProxy.NO_OP));
}
}
public boolean handleHomeTaskAppeared(RemoteAnimationTargetCompat appearedTaskTarget) {
if (appearedTaskTarget.activityType == ACTIVITY_TYPE_HOME) {
RemoteAnimationTargets targets = new RemoteAnimationTargets(
new RemoteAnimationTargetCompat[] {appearedTaskTarget},
new RemoteAnimationTargetCompat[0], appearedTaskTarget.mode);
mHomeAlphaParams.setTargetSet(targets);
updateHomeAlpha();
return true;
}
return false;
}
@Override
public void playAtomicAnimation(float velocity) {
ObjectAnimator alphaAnim = mHomeAlpha.animateToValue(mHomeAlpha.value, 1);
alphaAnim.setDuration(mDuration).setInterpolator(ACCEL);
alphaAnim.start();
if (mRunningOverHome) {
// Spring back launcher scale
new SpringAnimationBuilder(mContext)
.setStartValue(mVerticalShiftForScale.value)
.setEndValue(0)
.setStartVelocity(-velocity / mTransitionDragLength)
.setMinimumVisibleChange(1f / mDp.heightPx)
.setDampingRatio(0.6f)
.setStiffness(800)
.build(mVerticalShiftForScale, AnimatedFloat.VALUE)
.start();
}
}
}
}
@@ -15,30 +15,18 @@
*/
package com.android.quickstep;
import static com.android.launcher3.LauncherAnimUtils.SCALE_PROPERTY;
import static com.android.launcher3.LauncherState.BACKGROUND_APP;
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.config.FeatureFlags.ENABLE_OVERVIEW_ACTIONS;
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.SysUINavigationMode.getMode;
import static com.android.quickstep.SysUINavigationMode.removeShelfFromOverview;
import static com.android.quickstep.SysUINavigationMode.hideShelfInTwoButtonLandscape;
import static com.android.quickstep.util.LayoutUtils.getDefaultSwipeHeight;
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.content.Context;
import android.content.res.Resources;
import android.graphics.PointF;
import android.graphics.Rect;
import android.util.Log;
import android.view.MotionEvent;
import android.view.animation.Interpolator;
import androidx.annotation.Nullable;
@@ -56,14 +44,14 @@ 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.statemanager.StateManager;
import com.android.launcher3.testing.TestProtocol;
import com.android.launcher3.touch.PagedOrientationHandler;
import com.android.launcher3.userevent.nano.LauncherLogProto;
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.views.LauncherRecentsView;
import com.android.quickstep.views.RecentsView;
import com.android.systemui.plugins.shared.LauncherOverlayManager;
import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
@@ -75,23 +63,24 @@ import java.util.function.Predicate;
* {@link BaseActivityInterface} for the in-launcher recents.
*/
public final class LauncherActivityInterface extends
BaseActivityInterface<LauncherState, Launcher> {
BaseActivityInterface<LauncherState, BaseQuickstepLauncher> {
public static final LauncherActivityInterface INSTANCE = new LauncherActivityInterface();
private LauncherActivityInterface() {
super(true);
super(true, OVERVIEW, BACKGROUND_APP);
}
@Override
public int getSwipeUpDestinationAndLength(DeviceProfile dp, Context context, Rect outRect) {
calculateTaskSize(context, dp, outRect);
public int getSwipeUpDestinationAndLength(DeviceProfile dp, Context context, Rect outRect,
PagedOrientationHandler orientationHandler) {
calculateTaskSize(context, dp, outRect, orientationHandler);
if (dp.isVerticalBarLayout() && SysUINavigationMode.getMode(context) != Mode.NO_BUTTON) {
Rect targetInsets = dp.getInsets();
int hotseatInset = dp.isSeascape() ? targetInsets.left : targetInsets.right;
return dp.hotseatBarSizePx + hotseatInset;
} else {
return LayoutUtils.getShelfTrackingDistance(context, dp);
return LayoutUtils.getShelfTrackingDistance(context, dp, orientationHandler);
}
}
@@ -130,119 +119,43 @@ public final class LauncherActivityInterface extends
@Override
public AnimationFactory prepareRecentsUI(
boolean activityVisible, Consumer<AnimatorPlaybackController> callback) {
BaseQuickstepLauncher launcher = getCreatedActivity();
final LauncherState startState = launcher.getStateManager().getState();
LauncherState resetState = startState;
if (startState.shouldDisableRestore()) {
resetState = launcher.getStateManager().getRestState();
}
launcher.getStateManager().setRestState(resetState);
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 */);
return new AnimationFactory() {
private final ShelfPeekAnim mShelfAnim = launcher.getShelfPeekAnim();
private boolean mIsAttachedToWindow;
@Override
public void createActivityInterface(long transitionLength) {
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.
if (SysUINavigationMode.getMode(launcher) == Mode.NO_BUTTON) {
setRecentsAttachedToAppWindow(mIsAttachedToWindow, false);
}
}
@Override
public void onTransitionCancelled() {
launcher.getStateManager().goToState(startState, false /* animate */);
}
DefaultAnimationFactory factory = new DefaultAnimationFactory(callback) {
@Override
public void setShelfState(ShelfAnimState shelfState, Interpolator interpolator,
long duration) {
mShelfAnim.setShelfState(shelfState, interpolator, duration);
mActivity.getShelfPeekAnim().setShelfState(shelfState, interpolator, duration);
}
@Override
public void setRecentsAttachedToAppWindow(boolean attached, boolean animate) {
if (mIsAttachedToWindow == attached && animate) {
return;
}
mIsAttachedToWindow = attached;
LauncherRecentsView recentsView = launcher.getOverviewPanel();
Animator fadeAnim = launcher.getStateManager()
.createStateElementAnimation(
INDEX_RECENTS_FADE_ANIM, attached ? 1 : 0);
protected void createBackgroundToOverviewAnim(BaseQuickstepLauncher activity,
PendingAnimation pa) {
super.createBackgroundToOverviewAnim(activity, pa);
float fromTranslation = attached ? 1 : 0;
float toTranslation = attached ? 0 : 1;
launcher.getStateManager()
.cancelStateElementAnimation(INDEX_RECENTS_TRANSLATE_X_ANIM);
if (!recentsView.isShown() && animate) {
ADJACENT_PAGE_OFFSET.set(recentsView, fromTranslation);
} else {
fromTranslation = ADJACENT_PAGE_OFFSET.get(recentsView);
}
if (!animate) {
ADJACENT_PAGE_OFFSET.set(recentsView, toTranslation);
} else {
launcher.getStateManager().createStateElementAnimation(
INDEX_RECENTS_TRANSLATE_X_ANIM,
fromTranslation, toTranslation).start();
if (!activity.getDeviceProfile().isVerticalBarLayout()
&& SysUINavigationMode.getMode(activity) != Mode.NO_BUTTON) {
// Don't animate the shelf when the mode is NO_BUTTON, because we
// update it atomically.
pa.add(activity.getStateManager().createStateElementAnimation(
INDEX_SHELF_ANIM,
BACKGROUND_APP.getVerticalProgress(activity),
OVERVIEW.getVerticalProgress(activity)));
}
fadeAnim.setInterpolator(attached ? INSTANT : ACCEL_2);
fadeAnim.setDuration(animate ? RECENTS_ATTACH_DURATION : 0).start();
// Animate the blur and wallpaper zoom
float fromDepthRatio = BACKGROUND_APP.getDepth(activity);
float toDepthRatio = OVERVIEW.getDepth(activity);
pa.addFloat(getDepthController(),
new ClampedDepthProperty(fromDepthRatio, toDepthRatio),
fromDepthRatio, toDepthRatio, LINEAR);
}
};
}
private AnimatorPlaybackController createBackgroundToOverviewAnim(
Launcher activity, long transitionLength) {
PendingAnimation pa = new PendingAnimation(transitionLength * 2);
if (!activity.getDeviceProfile().isVerticalBarLayout()
&& SysUINavigationMode.getMode(activity) != Mode.NO_BUTTON) {
// Don't animate the shelf when the mode is NO_BUTTON, because we update it atomically.
pa.add(activity.getStateManager().createStateElementAnimation(
INDEX_SHELF_ANIM,
BACKGROUND_APP.getVerticalProgress(activity),
OVERVIEW.getVerticalProgress(activity)));
}
// Animate the blur and wallpaper zoom
float fromDepthRatio = BACKGROUND_APP.getDepth(activity);
float toDepthRatio = OVERVIEW.getDepth(activity);
pa.addFloat(getDepthController(), new ClampedDepthProperty(fromDepthRatio, toDepthRatio),
fromDepthRatio, toDepthRatio, LINEAR);
// 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 ? OVERVIEW : BACKGROUND_APP, false));
return controller;
BaseQuickstepLauncher launcher = factory.initUI();
// 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 */);
return factory;
}
@Override
@@ -251,6 +164,15 @@ public final class LauncherActivityInterface extends
onInitListener.test(alreadyOnHome));
}
@Override
public void setOnDeferredActivityLaunchCallback(Runnable r) {
Launcher launcher = getCreatedActivity();
if (launcher == null) {
return;
}
launcher.setOnDeferredActivityLaunchCallback(r);
}
@Nullable
@Override
public BaseQuickstepLauncher getCreatedActivity() {
@@ -258,11 +180,13 @@ public final class LauncherActivityInterface extends
}
@Nullable
@UiThread
private Launcher getVisibleLauncher() {
Launcher launcher = getCreatedActivity();
return (launcher != null) && launcher.isStarted() && launcher.hasWindowFocus() ?
launcher : null;
@Override
public DepthController getDepthController() {
BaseQuickstepLauncher launcher = getCreatedActivity();
if (launcher == null) {
return null;
}
return launcher.getDepthController();
}
@Nullable
@@ -273,6 +197,14 @@ public final class LauncherActivityInterface extends
? launcher.getOverviewPanel() : null;
}
@Nullable
@UiThread
private Launcher getVisibleLauncher() {
Launcher launcher = getCreatedActivity();
return (launcher != null) && launcher.isStarted() && launcher.hasWindowFocus()
? launcher : null;
}
@Override
public boolean switchToRecentsIfVisible(Runnable onCompleteCallback) {
if (TestProtocol.sDebugTracing) {
@@ -292,14 +224,26 @@ public final class LauncherActivityInterface extends
return true;
}
@Override
public void setHintUserWillBeActive() {
getCreatedActivity().setHintUserWillBeActive();
}
@Override
public boolean deferStartingActivity(RecentsAnimationDeviceState deviceState, MotionEvent ev) {
return deviceState.isInDeferredGestureRegion(ev);
public void onExitOverview(RecentsAnimationDeviceState deviceState, Runnable exitRunnable) {
final StateManager<LauncherState> stateManager = getCreatedActivity().getStateManager();
stateManager.addStateListener(
new StateManager.StateListener<LauncherState>() {
@Override
public void onStateTransitionComplete(LauncherState toState) {
// Are we going from Recents to Workspace?
if (toState == LauncherState.NORMAL) {
exitRunnable.run();
// reset layout on swipe to home
RecentsView recentsView = getCreatedActivity().getOverviewPanel();
recentsView.setLayoutRotation(deviceState.getCurrentActiveRotation(),
deviceState.getDisplayRotation());
stateManager.removeStateListener(this);
}
}
});
}
@Override
@@ -312,6 +256,16 @@ public final class LauncherActivityInterface extends
return true;
}
@Override
public void updateOverviewPredictionState() {
Launcher launcher = getCreatedActivity();
if (launcher == null) {
return;
}
PredictionUiStateManager.INSTANCE.get(launcher).switchClient(
PredictionUiStateManager.Client.OVERVIEW);
}
@Override
public int getContainerType() {
final Launcher launcher = getVisibleLauncher();
@@ -350,54 +304,11 @@ public final class LauncherActivityInterface extends
}
@Override
public void setOnDeferredActivityLaunchCallback(Runnable r) {
Launcher launcher = getCreatedActivity();
if (launcher == null) {
return;
}
launcher.setOnDeferredActivityLaunchCallback(r);
}
@Override
public void updateOverviewPredictionState() {
Launcher launcher = getCreatedActivity();
if (launcher == null) {
return;
}
PredictionUiStateManager.INSTANCE.get(launcher).switchClient(
PredictionUiStateManager.Client.OVERVIEW);
}
@Nullable
@Override
public DepthController getDepthController() {
BaseQuickstepLauncher launcher = getCreatedActivity();
if (launcher == null) {
return null;
}
return launcher.getDepthController();
}
@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
protected float getExtraSpace(Context context, DeviceProfile dp) {
if (dp.isVerticalBarLayout()) {
return 0;
protected float getExtraSpace(Context context, DeviceProfile dp,
PagedOrientationHandler orientationHandler) {
if (dp.isVerticalBarLayout() ||
hideShelfInTwoButtonLandscape(context, orientationHandler)) {
return 0;
} else {
Resources res = context.getResources();
if (showOverviewActions(context)) {
@@ -423,4 +334,5 @@ public final class LauncherActivityInterface extends
}
}
}
}
@@ -0,0 +1,121 @@
/*
* 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.LauncherState.NORMAL;
import android.animation.AnimatorSet;
import android.content.Context;
import android.graphics.RectF;
import android.os.UserHandle;
import android.view.View;
import androidx.annotation.NonNull;
import com.android.launcher3.BaseQuickstepLauncher;
import com.android.launcher3.anim.AnimatorPlaybackController;
import com.android.launcher3.views.FloatingIconView;
import com.android.quickstep.util.StaggeredWorkspaceAnim;
import com.android.quickstep.views.RecentsView;
import com.android.quickstep.views.TaskView;
import com.android.systemui.shared.system.InputConsumerController;
/**
* Temporary class to allow easier refactoring
*/
public class LauncherSwipeHandlerV2 extends
BaseSwipeUpHandlerV2<BaseQuickstepLauncher, RecentsView> {
public LauncherSwipeHandlerV2(Context context, RecentsAnimationDeviceState deviceState,
TaskAnimationManager taskAnimationManager, GestureState gestureState, long touchTimeMs,
boolean continuingLastGesture, InputConsumerController inputConsumer) {
super(context, deviceState, taskAnimationManager, gestureState, touchTimeMs,
continuingLastGesture, inputConsumer);
}
@Override
protected HomeAnimationFactory createHomeAnimationFactory(long duration) {
HomeAnimationFactory homeAnimFactory;
if (mActivity != null) {
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);
mActivity.setHintUserWillBeActive();
homeAnimFactory = new HomeAnimationFactory(floatingIconView) {
@Override
public RectF getWindowTargetRect() {
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);
}
};
mStateCallback.addChangeListener(STATE_LAUNCHER_PRESENT | STATE_HANDLER_INVALIDATED,
isPresent -> mRecentsView.startHome());
}
return homeAnimFactory;
}
@Override
protected void finishRecentsControllerToHome(Runnable callback) {
mRecentsAnimationController.finish(
true /* toRecents */, callback, true /* sendUserLeaveHint */);
}
}
@@ -7,6 +7,7 @@ import android.os.Bundle;
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.testing.TestInformationHandler;
import com.android.launcher3.testing.TestProtocol;
import com.android.launcher3.touch.PagedOrientationHandler;
import com.android.launcher3.uioverrides.touchcontrollers.PortraitStatesTouchController;
import com.android.quickstep.util.LayoutUtils;
import com.android.systemui.shared.recents.model.Task;
@@ -35,7 +36,8 @@ public class QuickstepTestInformationHandler extends TestInformationHandler {
case TestProtocol.REQUEST_BACKGROUND_TO_OVERVIEW_SWIPE_HEIGHT: {
final float swipeHeight =
LayoutUtils.getShelfTrackingDistance(mContext, mDeviceProfile);
LayoutUtils.getShelfTrackingDistance(mContext, mDeviceProfile,
PagedOrientationHandler.HOME_ROTATED);
response.putInt(TestProtocol.TEST_INFO_RESPONSE_FIELD, (int) swipeHeight);
return response;
}
@@ -23,7 +23,7 @@ import static com.android.launcher3.QuickstepAppTransitionManagerImpl.STATUS_BAR
import static com.android.launcher3.QuickstepAppTransitionManagerImpl.STATUS_BAR_TRANSITION_PRE_DELAY;
import static com.android.launcher3.testing.TestProtocol.OVERVIEW_STATE_ORDINAL;
import static com.android.quickstep.TaskUtils.taskIsATargetWithMode;
import static com.android.quickstep.TaskViewUtils.getRecentsWindowAnimator;
import static com.android.quickstep.TaskViewUtils.createRecentsWindowAnimator;
import static com.android.systemui.shared.system.RemoteAnimationTargetCompat.MODE_CLOSING;
import android.animation.Animator;
@@ -34,7 +34,6 @@ 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;
@@ -44,12 +43,13 @@ 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.anim.PendingAnimation;
import com.android.launcher3.compat.AccessibilityManagerCompat;
import com.android.launcher3.statemanager.StateManager;
import com.android.launcher3.statemanager.StateManager.AtomicAnimationFactory;
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;
@@ -57,9 +57,9 @@ 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.util.RecentsAtomicAnimationFactory;
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;
import com.android.systemui.shared.system.RemoteAnimationAdapterCompat;
import com.android.systemui.shared.system.RemoteAnimationRunnerCompat;
@@ -74,8 +74,6 @@ import java.io.PrintWriter;
*/
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<>();
@@ -115,21 +113,6 @@ public final class RecentsActivity extends StatefulActivity<RecentsState> {
@Override
protected void onNewIntent(Intent intent) {
if (intent.getExtras() != null) {
int taskID = intent.getIntExtra(EXTRA_TASK_ID, 0);
IBinder thumbnail = intent.getExtras().getBinder(EXTRA_THUMBNAIL);
if (taskID != 0 && thumbnail instanceof ObjectWrapper) {
ObjectWrapper<ThumbnailData> obj = (ObjectWrapper<ThumbnailData>) thumbnail;
ThumbnailData thumbnailData = obj.get();
mFallbackRecentsView.showCurrentTask(taskID);
mFallbackRecentsView.updateThumbnail(taskID, thumbnailData);
// Clear the ref since any reference to the extras on the system side will still
// hold a reference to the wrapper
obj.clear();
}
}
intent.removeExtra(EXTRA_TASK_ID);
intent.removeExtra(EXTRA_THUMBNAIL);
super.onNewIntent(intent);
ACTIVITY_TRACKER.handleNewIntent(this, intent);
}
@@ -223,9 +206,10 @@ public final class RecentsActivity extends StatefulActivity<RecentsState> {
RemoteAnimationTargetCompat[] wallpaperTargets) {
AnimatorSet target = new AnimatorSet();
boolean activityClosing = taskIsATargetWithMode(appTargets, getTaskId(), MODE_CLOSING);
Animator recentsAnimator = getRecentsWindowAnimator(taskView, !activityClosing, appTargets,
wallpaperTargets, null /* depthController */);
target.play(recentsAnimator.setDuration(RECENTS_LAUNCH_DURATION));
PendingAnimation pa = new PendingAnimation(RECENTS_LAUNCH_DURATION);
createRecentsWindowAnimator(taskView, !activityClosing, appTargets,
wallpaperTargets, null /* depthController */, pa);
target.play(pa.buildAnim());
// Found a visible recents task that matches the opening app, lets launch the app from there
if (activityClosing) {
@@ -345,6 +329,11 @@ public final class RecentsActivity extends StatefulActivity<RecentsState> {
dumpMisc(prefix + "\t", writer);
}
@Override
public AtomicAnimationFactory<RecentsState> createAtomicAnimationFactory() {
return new RecentsAtomicAnimationFactory<>(this, 0);
}
private AnimatorListenerAdapter resetStateListener() {
return new AnimatorListenerAdapter() {
@Override
@@ -15,44 +15,46 @@
*/
package com.android.quickstep;
import static com.android.launcher3.LauncherAnimUtils.VIEW_ALPHA;
import static com.android.launcher3.LauncherState.BACKGROUND_APP;
import static com.android.launcher3.Utilities.getDescendantCoordRelativeToAncestor;
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.anim.Interpolators.clampToProgress;
import static com.android.launcher3.statehandlers.DepthController.DEPTH;
import static com.android.systemui.shared.system.RemoteAnimationTargetCompat.MODE_OPENING;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
import android.annotation.TargetApi;
import android.content.ComponentName;
import android.content.Context;
import android.graphics.Matrix;
import android.graphics.Matrix.ScaleToFit;
import android.graphics.RectF;
import android.os.Build;
import android.view.View;
import com.android.launcher3.BaseActivity;
import com.android.launcher3.BaseDraggingActivity;
import com.android.launcher3.Utilities;
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.anim.PendingAnimation;
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.launcher3.util.DefaultDisplay;
import com.android.quickstep.util.TaskViewSimulator;
import com.android.quickstep.util.TransformParams;
import com.android.quickstep.views.RecentsView;
import com.android.quickstep.views.TaskThumbnailView;
import com.android.quickstep.views.TaskView;
import com.android.systemui.shared.recents.model.Task;
import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
import com.android.systemui.shared.system.SyncRtSurfaceTransactionApplierCompat;
import com.android.systemui.shared.system.SyncRtSurfaceTransactionApplierCompat.SurfaceParams;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/**
* Utility class for helpful methods related to {@link TaskView} objects and their tasks.
*/
@TargetApi(Build.VERSION_CODES.R)
public final class TaskViewUtils {
private TaskViewUtils() {}
@@ -118,97 +120,111 @@ public final class TaskViewUtils {
}
/**
* @return Animator that controls the window of the opening targets for the recents launch
* Creates an animation that controls the window of the opening targets for the recents launch
* animation.
*/
public static Animator getRecentsWindowAnimator(TaskView v, boolean skipViewChanges,
public static void createRecentsWindowAnimator(TaskView v, boolean skipViewChanges,
RemoteAnimationTargetCompat[] appTargets,
RemoteAnimationTargetCompat[] wallpaperTargets,
DepthController depthController) {
AppWindowAnimationHelper inOutHelper = new AppWindowAnimationHelper(
v.getRecentsView().getPagedViewOrientedState(), v.getContext());
RemoteAnimationTargetCompat[] wallpaperTargets, DepthController depthController,
PendingAnimation out) {
SyncRtSurfaceTransactionApplierCompat applier =
new SyncRtSurfaceTransactionApplierCompat(v);
final RemoteAnimationTargets targets =
new RemoteAnimationTargets(appTargets, wallpaperTargets, MODE_OPENING);
targets.addDependentTransactionApplier(applier);
TransformParams params =
new TransformParams()
TransformParams params = new TransformParams()
.setSyncTransactionApplier(applier)
.setTargetSet(targets);
AnimatorSet animatorSet = new AnimatorSet();
final RecentsView recentsView = v.getRecentsView();
final ValueAnimator appAnimator = ValueAnimator.ofFloat(0, 1);
appAnimator.setInterpolator(TOUCH_RESPONSE_INTERPOLATOR);
appAnimator.addUpdateListener(new MultiValueUpdateListener() {
int taskIndex = recentsView.indexOfChild(v);
boolean parallaxCenterAndAdjacentTask = taskIndex != recentsView.getCurrentPage();
int startScroll = recentsView.getScrollOffset(taskIndex);
// Defer fading out the view until after the app window gets faded in
final FloatProp mViewAlpha = new FloatProp(1f, 0f, 75, 75, LINEAR);
final FloatProp mTaskAlpha = new FloatProp(0f, 1f, 0, 75, LINEAR);
final RectF mThumbnailRect;
Context context = v.getContext();
DeviceProfile dp = BaseActivity.fromContext(context).getDeviceProfile();
// RecentsView never updates the display rotation until swipe-up so the value may be stale.
// Use the display value instead.
int displayRotation = DefaultDisplay.INSTANCE.get(context).getInfo().rotation;
{
params.setTaskAlphaCallback((t, alpha) -> mTaskAlpha.value);
inOutHelper.prepareAnimation(
BaseActivity.fromContext(v.getContext()).getDeviceProfile());
inOutHelper.fromTaskThumbnailView(v.getThumbnail(), (RecentsView) v.getParent(),
targets.apps.length == 0 ? null : targets.apps[0]);
TaskViewSimulator topMostSimulator = null;
if (targets.apps.length > 0) {
TaskViewSimulator tsv = new TaskViewSimulator(context, recentsView.getSizeStrategy());
tsv.setDp(dp);
tsv.setLayoutRotation(displayRotation, displayRotation);
tsv.setPreview(targets.apps[targets.apps.length - 1]);
tsv.fullScreenProgress.value = 0;
tsv.recentsViewScale.value = 1;
tsv.setScroll(startScroll);
mThumbnailRect = new RectF(inOutHelper.getTargetRect());
mThumbnailRect.offset(-v.getTranslationX(), -v.getTranslationY());
Utilities.scaleRectFAboutCenter(mThumbnailRect, 1 / v.getScaleX());
}
out.setFloat(tsv.fullScreenProgress,
AnimatedFloat.VALUE, 1, TOUCH_RESPONSE_INTERPOLATOR);
out.setFloat(tsv.recentsViewScale,
AnimatedFloat.VALUE, tsv.getFullScreenScale(), TOUCH_RESPONSE_INTERPOLATOR);
out.setInt(tsv, TaskViewSimulator.SCROLL, 0, TOUCH_RESPONSE_INTERPOLATOR);
@Override
public void onUpdate(float percent) {
// TODO: Take into account the current fullscreen progress for animating the insets
params.setProgress(1 - percent);
RectF taskBounds;
if (ENABLE_QUICKSTEP_LIVE_TILE.get()) {
List<SurfaceParams> surfaceParamsList = new ArrayList<>();
// Append the surface transform params for the app that's being opened.
Collections.addAll(surfaceParamsList, inOutHelper.computeSurfaceParams(params));
out.addOnFrameCallback(() -> tsv.apply(params));
topMostSimulator = tsv;
}
AppWindowAnimationHelper liveTileAnimationHelper =
v.getRecentsView().getClipAnimationHelper();
if (liveTileAnimationHelper != null) {
// Append the surface transform params for the live tile app.
TransformParams liveTileParams =
v.getRecentsView().getLiveTileParams(true /* mightNeedToRefill */);
if (liveTileParams != null) {
SurfaceParams[] liveTileSurfaceParams =
liveTileAnimationHelper.computeSurfaceParams(liveTileParams);
if (liveTileSurfaceParams != null) {
Collections.addAll(surfaceParamsList, liveTileSurfaceParams);
}
}
}
// Apply surface transform using the surface params list.
params.applySurfaceParams(
surfaceParamsList.toArray(new SurfaceParams[surfaceParamsList.size()]));
// Get the task bounds for the app that's being opened after surface transform
// update.
taskBounds = inOutHelper.updateCurrentRect(params);
} else {
taskBounds = inOutHelper.applyTransform(params);
// Fade in the task during the initial 20% of the animation
out.addFloat(params, TransformParams.TARGET_ALPHA, 0, 1, clampToProgress(LINEAR, 0, 0.2f));
if (!skipViewChanges && parallaxCenterAndAdjacentTask && topMostSimulator != null) {
out.addFloat(v, VIEW_ALPHA, 1, 0, clampToProgress(LINEAR, 0.2f, 0.4f));
TaskViewSimulator simulatorToCopy = topMostSimulator;
simulatorToCopy.apply(params);
// Mt represents the overall transformation on the thumbnailView relative to the
// Launcher's rootView
// K(t) represents transformation on the running window by the taskViewSimulator at
// any time t.
// at t = 0, we know that the simulator matches the thumbnailView. So if we apply K(0)`
// on the Launcher's rootView, the thumbnailView would match the full running task
// window. If we apply "K(0)` K(t)" thumbnailView will match the final transformed
// window at any time t. This gives the overall matrix on thumbnailView to be:
// Mt K(0)` K(t)
// During animation we apply transformation on the thumbnailView (and not the rootView)
// to follow the TaskViewSimulator. So the final matrix applied on the thumbnailView is:
// Mt K(0)` K(t) Mt`
TaskThumbnailView ttv = v.getThumbnail();
RectF tvBounds = new RectF(0, 0, ttv.getWidth(), ttv.getHeight());
float[] tvBoundsMapped = new float[]{0, 0, ttv.getWidth(), ttv.getHeight()};
getDescendantCoordRelativeToAncestor(ttv, ttv.getRootView(), tvBoundsMapped, false);
RectF tvBoundsInRoot = new RectF(
tvBoundsMapped[0], tvBoundsMapped[1],
tvBoundsMapped[2], tvBoundsMapped[3]);
Matrix mt = new Matrix();
mt.setRectToRect(tvBounds, tvBoundsInRoot, ScaleToFit.FILL);
Matrix mti = new Matrix();
mt.invert(mti);
Matrix k0i = new Matrix();
simulatorToCopy.getCurrentMatrix().invert(k0i);
Matrix animationMatrix = new Matrix();
out.addOnFrameCallback(() -> {
animationMatrix.set(mt);
animationMatrix.postConcat(k0i);
animationMatrix.postConcat(simulatorToCopy.getCurrentMatrix());
animationMatrix.postConcat(mti);
ttv.setAnimationMatrix(animationMatrix);
});
out.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
ttv.setAnimationMatrix(null);
}
});
}
int taskIndex = recentsView.indexOfChild(v);
int centerTaskIndex = recentsView.getCurrentPage();
boolean parallaxCenterAndAdjacentTask = taskIndex != centerTaskIndex;
if (!skipViewChanges && parallaxCenterAndAdjacentTask) {
float scale = taskBounds.width() / mThumbnailRect.width();
v.setScaleX(scale);
v.setScaleY(scale);
v.setTranslationX(taskBounds.centerX() - mThumbnailRect.centerX());
v.setTranslationY(taskBounds.centerY() - mThumbnailRect.centerY());
v.setAlpha(mViewAlpha.value);
}
}
});
appAnimator.addListener(new AnimatorListenerAdapter() {
out.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
targets.release();
@@ -216,12 +232,8 @@ public final class TaskViewUtils {
});
if (depthController != null) {
ObjectAnimator backgroundRadiusAnim = ObjectAnimator.ofFloat(depthController,
DEPTH, BACKGROUND_APP.getDepth(v.getContext()));
animatorSet.playTogether(appAnimator, backgroundRadiusAnim);
} else {
animatorSet.play(appAnimator);
out.setFloat(depthController, DEPTH, BACKGROUND_APP.getDepth(context),
TOUCH_RESPONSE_INTERPOLATOR);
}
return animatorSet;
}
}
@@ -85,7 +85,6 @@ 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;
import com.android.systemui.shared.recents.IOverviewProxy;
@@ -555,7 +554,6 @@ public class TouchInteractionService extends Service implements PluginListener<O
|| previousGestureState.isRecentsAnimationRunning()
? newBaseConsumer(previousGestureState, newGestureState, event)
: mResetGestureInputConsumer;
// TODO(b/149880412): 2 button landscape mode is wrecked. Fixit!
if (mDeviceState.isGesturalNavMode()) {
handleOrientationSetup(base);
}
@@ -612,7 +610,7 @@ public class TouchInteractionService extends Service implements PluginListener<O
if (TestProtocol.sDebugTracing) {
Log.d(TestProtocol.PAUSE_NOT_DETECTED, "handleOrientationSetup.1");
}
if (!isFixedRotationTransformEnabled(this)) {
if (!isFixedRotationTransformEnabled()) {
return;
}
mDeviceState.enableMultipleRegions(baseInputConsumer instanceof OtherActivityInputConsumer);
@@ -833,16 +831,16 @@ public class TouchInteractionService extends Service implements PluginListener<O
}
}
private BaseSwipeUpHandler createLauncherSwipeHandler(GestureState gestureState,
long touchTimeMs, boolean continuingLastGesture, boolean isLikelyToStartNewTask) {
return new LauncherSwipeHandler(this, mDeviceState, mTaskAnimationManager,
private BaseSwipeUpHandler createLauncherSwipeHandler(
GestureState gestureState, long touchTimeMs, boolean continuingLastGesture) {
return new LauncherSwipeHandlerV2(this, mDeviceState, mTaskAnimationManager,
gestureState, touchTimeMs, continuingLastGesture, mInputConsumer);
}
private BaseSwipeUpHandler createFallbackSwipeHandler(GestureState gestureState,
long touchTimeMs, boolean continuingLastGesture, boolean isLikelyToStartNewTask) {
return new FallbackSwipeHandler(this, mDeviceState, gestureState,
mInputConsumer, isLikelyToStartNewTask, continuingLastGesture);
private BaseSwipeUpHandler createFallbackSwipeHandler(
GestureState gestureState, long touchTimeMs, boolean continuingLastGesture) {
return new FallbackSwipeHandler(this, mDeviceState, mTaskAnimationManager,
gestureState, touchTimeMs, continuingLastGesture, mInputConsumer);
}
protected boolean shouldNotifyBackGesture() {
@@ -24,11 +24,13 @@ import android.content.Context;
import android.os.Build;
import android.util.AttributeSet;
import com.android.launcher3.anim.PendingAnimation;
import com.android.launcher3.statemanager.StateManager.StateListener;
import com.android.quickstep.FallbackActivityInterface;
import com.android.quickstep.RecentsActivity;
import com.android.quickstep.views.OverviewActionsView;
import com.android.quickstep.views.RecentsView;
import com.android.quickstep.views.TaskView;
import com.android.systemui.shared.recents.model.Task;
import com.android.systemui.shared.recents.model.Task.TaskKey;
@@ -38,7 +40,7 @@ import java.util.ArrayList;
public class FallbackRecentsView extends RecentsView<RecentsActivity>
implements StateListener<RecentsState> {
private RunningTaskInfo mRunningTaskInfo;
private RunningTaskInfo mHomeTaskInfo;
public FallbackRecentsView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
@@ -67,16 +69,40 @@ public class FallbackRecentsView extends RecentsView<RecentsActivity>
return false;
}
public void onGestureAnimationStart(RunningTaskInfo runningTaskInfo) {
mRunningTaskInfo = runningTaskInfo;
onGestureAnimationStart(runningTaskInfo == null ? -1 : runningTaskInfo.taskId);
/**
* When starting gesture interaction from home, we add a temporary invisible tile corresponding
* to the home task. This allows us to handle quick-switch similarly to a quick-switching
* from a foreground task.
*/
public void onGestureAnimationStartOnHome(RunningTaskInfo homeTaskInfo) {
mHomeTaskInfo = homeTaskInfo;
onGestureAnimationStart(homeTaskInfo == null ? -1 : homeTaskInfo.taskId);
}
/**
* When the gesture ends and recents view become interactive, we also remove the temporary
* invisible tile added for the home task. This also pushes the remaining tiles back
* to the center.
*/
@Override
public void onGestureAnimationEnd() {
super.onGestureAnimationEnd();
if (mHomeTaskInfo != null) {
TaskView tv = getTaskView(mHomeTaskInfo.taskId);
if (tv != null) {
PendingAnimation pa = createTaskDismissAnimation(tv, true, false, 150);
pa.addEndListener(e -> setCurrentTask(-1));
runDismissAnimation(pa);
}
}
}
@Override
public void setCurrentTask(int runningTaskId) {
super.setCurrentTask(runningTaskId);
if (mRunningTaskInfo != null && mRunningTaskInfo.taskId != runningTaskId) {
mRunningTaskInfo = null;
if (mHomeTaskInfo != null && mHomeTaskInfo.taskId != runningTaskId) {
mHomeTaskInfo = null;
setRunningTaskHidden(false);
}
}
@@ -85,7 +111,7 @@ public class FallbackRecentsView extends RecentsView<RecentsActivity>
// When quick-switching on 3p-launcher, we add a "dummy" tile corresponding to Launcher
// as well. This tile is never shown as we have setCurrentTaskHidden, but allows use to
// track the index of the next task appropriately, as if we are switching on any other app.
if (mRunningTaskInfo != null && mRunningTaskInfo.taskId == mRunningTaskId) {
if (mHomeTaskInfo != null && mHomeTaskInfo.taskId == mRunningTaskId) {
// Check if the task list has running task
boolean found = false;
for (Task t : tasks) {
@@ -97,13 +123,22 @@ public class FallbackRecentsView extends RecentsView<RecentsActivity>
if (!found) {
ArrayList<Task> newList = new ArrayList<>(tasks.size() + 1);
newList.addAll(tasks);
newList.add(Task.from(new TaskKey(mRunningTaskInfo), mRunningTaskInfo, false));
newList.add(Task.from(new TaskKey(mHomeTaskInfo), mHomeTaskInfo, false));
tasks = newList;
}
}
super.applyLoadPlan(tasks);
}
@Override
public void setRunningTaskHidden(boolean isHidden) {
if (mHomeTaskInfo != null) {
// Always keep the home task hidden
isHidden = true;
}
super.setRunningTaskHidden(isHidden);
}
@Override
public void setModalStateEnabled(boolean isModalState) {
super.setModalStateEnabled(isModalState);
@@ -21,7 +21,7 @@ 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.LauncherSwipeHandler.MIN_PROGRESS_FOR_OVERVIEW;
import static com.android.quickstep.BaseSwipeUpHandlerV2.MIN_PROGRESS_FOR_OVERVIEW;
import static com.android.quickstep.MultiStateCallback.DEBUG_STATES;
import static com.android.quickstep.util.ActiveGestureLog.INTENT_EXTRA_LOG_TRACE_ID;
@@ -112,6 +112,9 @@ public class OtherActivityInputConsumer extends ContextWrapper implements InputC
private boolean mPassedWindowMoveSlop;
// Slop used to determine when we say that the gesture has started.
private boolean mPassedPilferInputSlop;
// Same as mPassedPilferInputSlop, except when continuing a gesture mPassedPilferInputSlop is
// initially true while this one is false.
private boolean mPassedSlopOnThisGesture;
// Might be displacement in X or Y, depending on the direction we are swiping from the nav bar.
private float mStartDisplacement;
@@ -207,7 +210,7 @@ public class OtherActivityInputConsumer extends ContextWrapper implements InputC
// Start the window animation on down to give more time for launcher to draw if the
// user didn't start the gesture over the back button
if (!mIsDeferredDownTarget) {
startTouchTrackingForWindowAnimation(ev.getEventTime(), false);
startTouchTrackingForWindowAnimation(ev.getEventTime());
}
TraceHelper.INSTANCE.endSection(traceToken);
@@ -244,6 +247,7 @@ public class OtherActivityInputConsumer extends ContextWrapper implements InputC
mLastPos.set(ev.getX(pointerIndex), ev.getY(pointerIndex));
float displacement = getDisplacement(ev);
float displacementX = mLastPos.x - mDownPos.x;
float displacementY = mLastPos.y - mDownPos.y;
if (!mPassedWindowMoveSlop) {
if (!mIsDeferredDownTarget) {
@@ -258,11 +262,18 @@ public class OtherActivityInputConsumer extends ContextWrapper implements InputC
float horizontalDist = Math.abs(displacementX);
float upDist = -displacement;
boolean isLikelyToStartNewTask = horizontalDist > upDist;
boolean passedSlop = squaredHypot(displacementX, displacementY)
>= mSquaredTouchSlop;
if (!mPassedSlopOnThisGesture && passedSlop) {
mPassedSlopOnThisGesture = true;
}
// Until passing slop, we don't know what direction we're going, so assume we might
// be quick switching to avoid translating recents away when continuing the gesture.
boolean isLikelyToStartNewTask = !mPassedSlopOnThisGesture
|| horizontalDist > upDist;
if (!mPassedPilferInputSlop) {
float displacementY = mLastPos.y - mDownPos.y;
if (squaredHypot(displacementX, displacementY) >= mSquaredTouchSlop) {
if (passedSlop) {
if (mDisableHorizontalSwipe
&& Math.abs(displacementX) > Math.abs(displacementY)) {
// Horizontal gesture is not allowed in this region
@@ -275,8 +286,7 @@ public class OtherActivityInputConsumer extends ContextWrapper implements InputC
if (mIsDeferredDownTarget) {
// Deferred gesture, start the animation and gesture tracking once
// we pass the actual touch slop
startTouchTrackingForWindowAnimation(
ev.getEventTime(), isLikelyToStartNewTask);
startTouchTrackingForWindowAnimation(ev.getEventTime());
}
if (!mPassedWindowMoveSlop) {
mPassedWindowMoveSlop = true;
@@ -326,12 +336,11 @@ public class OtherActivityInputConsumer extends ContextWrapper implements InputC
mInteractionHandler.onGestureStarted();
}
private void startTouchTrackingForWindowAnimation(
long touchTimeMs, boolean isLikelyToStartNewTask) {
private void startTouchTrackingForWindowAnimation(long touchTimeMs) {
ActiveGestureLog.INSTANCE.addLog("startRecentsAnimation");
mInteractionHandler = mHandlerFactory.newHandler(mGestureState, touchTimeMs,
mTaskAnimationManager.isRecentsAnimationRunning(), isLikelyToStartNewTask);
mTaskAnimationManager.isRecentsAnimationRunning());
mInteractionHandler.setGestureEndCallback(this::onInteractionGestureFinished);
mMotionPauseDetector.setOnMotionPauseListener(mInteractionHandler::onMotionPauseChanged);
Intent intent = new Intent(mInteractionHandler.getLaunchIntent());
@@ -341,6 +350,7 @@ public class OtherActivityInputConsumer extends ContextWrapper implements InputC
mActiveCallbacks = mTaskAnimationManager.continueRecentsAnimation(mGestureState);
mActiveCallbacks.addListener(mInteractionHandler);
mTaskAnimationManager.notifyRecentsAnimationState(mInteractionHandler);
mInteractionHandler.setIsLikelyToStartNewTask(true);
notifyGestureStarted();
} else {
intent.putExtra(INTENT_EXTRA_LOG_TRACE_ID, mGestureState.getGestureId());
@@ -1,294 +0,0 @@
/*
* Copyright (C) 2018 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.quickstep.util;
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 android.annotation.TargetApi;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Matrix;
import android.graphics.Matrix.ScaleToFit;
import android.graphics.Rect;
import android.graphics.RectF;
import android.os.Build;
import androidx.annotation.Nullable;
import com.android.launcher3.BaseDraggingActivity;
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
import com.android.launcher3.views.BaseDragLayer;
import com.android.quickstep.SystemUiProxy;
import com.android.quickstep.views.RecentsView;
import com.android.quickstep.views.TaskThumbnailView;
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.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 implements TransformParams.BuilderProxy {
// The bounds of the source app in device coordinates
private final RectF mSourceStackBounds = new RectF();
// The insets of the source app
private final Rect mSourceInsets = new Rect();
// The source app bounds with the source insets applied, in the device coordinates
private final RectF mSourceRect = new RectF();
// The bounds of the task view in device coordinates
private final RectF mTargetRect = new RectF();
// The bounds of the app window (between mSourceRect and mTargetRect) in device coordinates
private final RectF mCurrentRect = new RectF();
// The insets to be used for clipping the app window, which can be larger than mSourceInsets
// if the aspect ratio of the target is smaller than the aspect ratio of the source rect. In
// app window coordinates.
private final RectF mSourceWindowClipInsets = new RectF();
// The clip rect in source app window coordinates. The app window surface will only be drawn
// within these bounds. This clip rect starts at the full mSourceStackBounds, and insets by
// mSourceWindowClipInsets as the transform progress goes to 1.
private final RectF mCurrentClipRectF = new RectF();
// The bounds of launcher (not including insets) in device coordinates
public final Rect mHomeStackBounds = new Rect();
private final RectFEvaluator mRectFEvaluator = new RectFEvaluator();
private final Matrix mTmpMatrix = new Matrix();
private final Rect mTmpRect = new Rect();
private final RectF mTmpRectF = new RectF();
private RecentsOrientedState mOrientedState;
// Corner radius of windows, in pixels
private final float mWindowCornerRadius;
// Corner radius of windows when they're in overview mode.
private final float mTaskCornerRadius;
// If windows can have real time rounded corners.
private final boolean mSupportsRoundedCornersOnWindows;
// Whether or not to actually use the rounded cornders on windows
private boolean mUseRoundedCornersOnWindows;
public AppWindowAnimationHelper(RecentsOrientedState orientedState, Context context) {
Resources res = context.getResources();
mOrientedState = orientedState;
mWindowCornerRadius = getWindowCornerRadius(res);
mSupportsRoundedCornersOnWindows = supportsRoundedCornersOnWindows(res);
mTaskCornerRadius = TaskCornerRadius.get(context);
mUseRoundedCornersOnWindows = mSupportsRoundedCornersOnWindows;
}
private void updateSourceStack(RemoteAnimationTargetCompat target) {
mSourceInsets.set(target.contentInsets);
mSourceStackBounds.set(target.screenSpaceBounds);
}
public void updateTargetRect(Rect targetRect) {
mSourceRect.set(mSourceInsets.left, mSourceInsets.top,
mSourceStackBounds.width() - mSourceInsets.right,
mSourceStackBounds.height() - mSourceInsets.bottom);
mTargetRect.set(targetRect);
mTargetRect.offset(mHomeStackBounds.left - mSourceStackBounds.left,
mHomeStackBounds.top - mSourceStackBounds.top);
// Calculate the clip based on the target rect (since the content insets and the
// launcher insets may differ, so the aspect ratio of the target rect can differ
// from the source rect. The difference between the target rect (scaled to the
// source rect) is the amount to clip on each edge.
RectF scaledTargetRect = new RectF(mTargetRect);
float scale = getSrcToTargetScale();
Utilities.scaleRectFAboutCenter(scaledTargetRect, scale);
scaledTargetRect.offsetTo(mSourceRect.left, mSourceRect.top);
mSourceWindowClipInsets.set(
Math.max(scaledTargetRect.left, 0),
Math.max(scaledTargetRect.top, 0),
Math.max(mSourceStackBounds.width() - scaledTargetRect.right, 0),
Math.max(mSourceStackBounds.height() - scaledTargetRect.bottom, 0));
mSourceRect.set(scaledTargetRect);
}
public float getSrcToTargetScale() {
return LayoutUtils.getTaskScale(mOrientedState,
mSourceRect.width(), mSourceRect.height(),
mTargetRect.width(), mTargetRect.height());
}
public void prepareAnimation(DeviceProfile dp) {
mUseRoundedCornersOnWindows = mSupportsRoundedCornersOnWindows && !dp.isMultiWindowMode;
}
public RectF applyTransform(TransformParams params) {
SurfaceParams[] surfaceParams = computeSurfaceParams(params);
if (surfaceParams == null) {
return null;
}
params.applySurfaceParams(surfaceParams);
return mCurrentRect;
}
/**
* Updates this AppWindowAnimationHelper's state based on the given TransformParams, and returns
* the SurfaceParams to apply via {@link SyncRtSurfaceTransactionApplierCompat#applyParams}.
*/
public SurfaceParams[] computeSurfaceParams(TransformParams params) {
if (params.getTargetSet() == null) {
return null;
}
updateCurrentRect(params);
return params.createSurfaceParams(this);
}
@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();
mTmpMatrix.setTranslate(0, 0);
if (app.activityType == RemoteAnimationTargetCompat.ACTIVITY_TYPE_HOME) {
mTmpMatrix.setTranslate(app.localBounds.left, app.localBounds.top);
}
if (app.mode == targetMode
&& app.activityType != RemoteAnimationTargetCompat.ACTIVITY_TYPE_HOME) {
mTmpMatrix.setRectToRect(mSourceRect, mCurrentRect, ScaleToFit.FILL);
mTmpMatrix.postTranslate(app.localBounds.left, app.localBounds.top);
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);
}
}
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);
}
}
public RectF updateCurrentRect(TransformParams params) {
if (params.getCurrentRect() != null) {
mCurrentRect.set(params.getCurrentRect());
} else {
mTmpRectF.set(mTargetRect);
mCurrentRect.set(mRectFEvaluator.evaluate(
params.getProgress(), mSourceRect, mTmpRectF));
}
updateClipRect(params);
return mCurrentRect;
}
private void updateClipRect(TransformParams params) {
// Don't clip past progress > 1.
float progress = Math.min(1, params.getProgress());
mCurrentClipRectF.left = mSourceWindowClipInsets.left * progress;
mCurrentClipRectF.top = mSourceWindowClipInsets.top * progress;
mCurrentClipRectF.right =
mSourceStackBounds.width() - (mSourceWindowClipInsets.right * progress);
mCurrentClipRectF.bottom =
mSourceStackBounds.height() - (mSourceWindowClipInsets.bottom * progress);
}
public void fromTaskThumbnailView(TaskThumbnailView ttv, RecentsView rv,
@Nullable RemoteAnimationTargetCompat target) {
BaseDraggingActivity activity = BaseDraggingActivity.fromContext(ttv.getContext());
BaseDragLayer dl = activity.getDragLayer();
int[] pos = new int[2];
dl.getLocationOnScreen(pos);
mHomeStackBounds.set(0, 0, dl.getWidth(), dl.getHeight());
mHomeStackBounds.offset(pos[0], pos[1]);
if (target != null) {
updateSourceStack(target);
} else if (rv.shouldUseMultiWindowTaskSizeStrategy()) {
updateStackBoundsToMultiWindowTaskSize(activity);
} else {
mSourceStackBounds.set(mHomeStackBounds);
Rect fallback = dl.getInsets();
mSourceInsets.set(ttv.getInsets(fallback));
}
Rect targetRect = new Rect();
dl.getDescendantRectRelativeToSelf(ttv, targetRect);
updateTargetRect(targetRect);
if (target == null) {
// Transform the clip relative to the target rect. Only do this in the case where we
// aren't applying the insets to the app windows (where the clip should be in target app
// space)
float scale = mTargetRect.width() / mSourceRect.width();
mSourceWindowClipInsets.left = mSourceWindowClipInsets.left * scale;
mSourceWindowClipInsets.top = mSourceWindowClipInsets.top * scale;
mSourceWindowClipInsets.right = mSourceWindowClipInsets.right * scale;
mSourceWindowClipInsets.bottom = mSourceWindowClipInsets.bottom * scale;
}
}
private void updateStackBoundsToMultiWindowTaskSize(BaseDraggingActivity activity) {
SystemUiProxy proxy = SystemUiProxy.INSTANCE.get(activity);
if (proxy.isActive()) {
mSourceStackBounds.set(proxy.getNonMinimizedSplitScreenSecondaryBounds());
return;
}
// Assume that the task size is half screen size (minus the insets and the divider size)
DeviceProfile fullDp = activity.getDeviceProfile().getFullScreenProfile();
// Use availableWidthPx and availableHeightPx instead of widthPx and heightPx to
// account for system insets
int taskWidth = fullDp.availableWidthPx;
int taskHeight = fullDp.availableHeightPx;
int halfDividerSize = activity.getResources()
.getDimensionPixelSize(R.dimen.multi_window_task_divider_size) / 2;
Rect insets = new Rect();
WindowManagerWrapper.getInstance().getStableInsets(insets);
if (fullDp.isLandscape) {
taskWidth = taskWidth / 2 - halfDividerSize;
} else {
taskHeight = taskHeight / 2 - halfDividerSize;
}
// Align the task to bottom left/right edge (closer to nav bar).
int left = activity.getDeviceProfile().isSeascape() ? insets.left
: (insets.left + fullDp.availableWidthPx - taskWidth);
mSourceStackBounds.set(0, 0, taskWidth, taskHeight);
mSourceStackBounds.offset(left, insets.top + fullDp.availableHeightPx - taskHeight);
}
public RectF getTargetRect() {
return mTargetRect;
}
}
@@ -0,0 +1,67 @@
/*
* 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 com.android.quickstep.views.RecentsView.ADJACENT_PAGE_OFFSET;
import android.animation.Animator;
import android.animation.ObjectAnimator;
import com.android.launcher3.anim.SpringAnimationBuilder;
import com.android.launcher3.statemanager.StateManager.AtomicAnimationFactory;
import com.android.launcher3.statemanager.StatefulActivity;
import com.android.quickstep.views.RecentsView;
public class RecentsAtomicAnimationFactory<ACTIVITY_TYPE extends StatefulActivity, STATE_TYPE>
extends AtomicAnimationFactory<STATE_TYPE> {
public static final int INDEX_RECENTS_FADE_ANIM = AtomicAnimationFactory.NEXT_INDEX + 0;
public static final int INDEX_RECENTS_TRANSLATE_X_ANIM = AtomicAnimationFactory.NEXT_INDEX + 1;
private static final int MY_ANIM_COUNT = 2;
protected static final int NEXT_INDEX = AtomicAnimationFactory.NEXT_INDEX + MY_ANIM_COUNT;
protected final ACTIVITY_TYPE mActivity;
/**
* @param extraAnims number of animations supported by the subclass. This should not include
* the 2 animations supported by this class.
*/
public RecentsAtomicAnimationFactory(ACTIVITY_TYPE activity, int extraAnims) {
super(MY_ANIM_COUNT + extraAnims);
mActivity = activity;
}
@Override
public Animator createStateElementAnimation(int index, float... values) {
switch (index) {
case INDEX_RECENTS_FADE_ANIM:
return ObjectAnimator.ofFloat(mActivity.getOverviewPanel(),
RecentsView.CONTENT_ALPHA, values);
case INDEX_RECENTS_TRANSLATE_X_ANIM: {
RecentsView rv = mActivity.getOverviewPanel();
return new SpringAnimationBuilder(mActivity)
.setMinimumVisibleChange(1f / rv.getPageOffsetScale())
.setDampingRatio(0.8f)
.setStiffness(250)
.setValues(values)
.build(rv, ADJACENT_PAGE_OFFSET);
}
default:
return super.createStateElementAnimation(index, values);
}
}
}
@@ -26,6 +26,7 @@ import android.graphics.Matrix;
import android.graphics.PointF;
import android.graphics.Rect;
import android.graphics.RectF;
import android.util.IntProperty;
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.R;
@@ -47,6 +48,19 @@ import com.android.systemui.shared.system.SyncRtSurfaceTransactionApplierCompat.
*/
public class TaskViewSimulator implements TransformParams.BuilderProxy {
public static final IntProperty<TaskViewSimulator> SCROLL =
new IntProperty<TaskViewSimulator>("scroll") {
@Override
public void setValue(TaskViewSimulator simulator, int i) {
simulator.setScroll(i);
}
@Override
public Integer get(TaskViewSimulator simulator) {
return simulator.mScrollState.scroll;
}
};
private final Rect mTmpCropRect = new Rect();
private final RectF mTempRectF = new RectF();
private final float[] mTempPoint = new float[2];
@@ -73,8 +87,8 @@ public class TaskViewSimulator implements TransformParams.BuilderProxy {
private float mCurveScale = 1;
// RecentsView properties
public final AnimatedFloat recentsViewScale = new AnimatedFloat(() -> { });
public final AnimatedFloat fullScreenProgress = new AnimatedFloat(() -> { });
public final AnimatedFloat recentsViewScale = new AnimatedFloat();
public final AnimatedFloat fullScreenProgress = new AnimatedFloat();
private final ScrollState mScrollState = new ScrollState();
private final int mPageSpacing;
@@ -116,7 +130,8 @@ public class TaskViewSimulator implements TransformParams.BuilderProxy {
if (mDp == null) {
return 1;
}
mSizeStrategy.calculateTaskSize(mContext, mDp, mTaskRect);
mSizeStrategy.calculateTaskSize(mContext, mDp, mTaskRect,
mOrientationState.getOrientationHandler());
return mOrientationState.getFullScreenScaleAndPivot(mTaskRect, mDp, mPivot);
}
@@ -278,4 +293,5 @@ public class TaskViewSimulator implements TransformParams.BuilderProxy {
// Ideally we should use square-root. This is an optimization as one of the dimension is 0.
return Math.max(Math.abs(mTempPoint[0]), Math.abs(mTempPoint[1]));
}
}
@@ -15,11 +15,8 @@
*/
package com.android.quickstep.util;
import android.graphics.RectF;
import android.util.FloatProperty;
import androidx.annotation.Nullable;
import com.android.launcher3.Utilities;
import com.android.launcher3.anim.Interpolators;
import com.android.quickstep.RemoteAnimationTargets;
@@ -43,19 +40,30 @@ public class TransformParams {
}
};
public static FloatProperty<TransformParams> TARGET_ALPHA =
new FloatProperty<TransformParams>("targetAlpha") {
@Override
public void setValue(TransformParams params, float v) {
params.setTargetAlpha(v);
}
@Override
public Float get(TransformParams params) {
return params.getTargetAlpha();
}
};
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;
private BuilderProxy mHomeBuilderProxy = BuilderProxy.ALWAYS_VISIBLE;
private BuilderProxy mBaseBuilderProxy = BuilderProxy.ALWAYS_VISIBLE;
public TransformParams() {
mProgress = 0;
mCurrentRect = null;
mTargetAlpha = 1;
mCornerRadius = -1;
}
@@ -80,17 +88,6 @@ public class TransformParams {
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.
*/
@@ -121,18 +118,20 @@ public class TransformParams {
}
/**
* Sets an alternate function which can be used to control the alpha of target app
* Sets an alternate function to control transform for non-target apps. The default
* implementation keeps the targets visible with alpha=1
*/
public TransformParams setTaskAlphaCallback(TargetAlphaProvider callback) {
mTaskAlphaCallback = callback;
public TransformParams setBaseBuilderProxy(BuilderProxy proxy) {
mBaseBuilderProxy = proxy;
return this;
}
/**
* Sets an alternate function which can be used to control the alpha of non-target app
* Sets an alternate function to control transform for home target. The default
* implementation keeps the targets visible with alpha=1
*/
public TransformParams setBaseAlphaCallback(TargetAlphaProvider callback) {
mBaseAlphaCallback = callback;
public TransformParams setHomeBuilderProxy(BuilderProxy proxy) {
mHomeBuilderProxy = proxy;
return this;
}
@@ -143,25 +142,24 @@ public class TransformParams {
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) {
if (app.activityType == RemoteAnimationTargetCompat.ACTIVITY_TYPE_HOME) {
mHomeBuilderProxy.onBuildTargetParams(builder, app, this);
} else {
// Fade out Assistant overlay.
if (app.activityType == RemoteAnimationTargetCompat.ACTIVITY_TYPE_ASSISTANT
&& app.isNotInRecents) {
alpha = 1 - Interpolators.DEACCEL_2_5.getInterpolation(progress);
float progress = Utilities.boundToRange(getProgress(), 0, 1);
builder.withAlpha(1 - Interpolators.DEACCEL_2_5.getInterpolation(progress));
} else {
builder.withAlpha(getTargetAlpha());
}
} else if (targets.hasRecents) {
// If home has a different target then recents, reverse anim the
// home target.
alpha = 1 - (progress * getTargetAlpha());
proxy.onBuildTargetParams(builder, app, this);
}
} else {
alpha = mBaseAlphaCallback.getAlpha(app, progress);
mBaseBuilderProxy.onBuildTargetParams(builder, app, this);
}
proxy.onBuildParams(builder.withAlpha(alpha), app, targets.targetMode, this);
surfaceParams[i] = builder.build();
}
return surfaceParams;
@@ -173,11 +171,6 @@ public class TransformParams {
return mProgress;
}
@Nullable
public RectF getCurrentRect() {
return mCurrentRect;
}
public float getTargetAlpha() {
return mTargetAlpha;
}
@@ -203,21 +196,13 @@ public class TransformParams {
}
}
public interface TargetAlphaProvider {
float getAlpha(RemoteAnimationTargetCompat target, float expectedAlpha);
}
@FunctionalInterface
public interface BuilderProxy {
default void onBuildParams(SurfaceParams.Builder builder,
RemoteAnimationTargetCompat app, int targetMode, TransformParams params) {
if (app.mode == targetMode
&& app.activityType != RemoteAnimationTargetCompat.ACTIVITY_TYPE_HOME) {
onBuildTargetParams(builder, app, params);
}
}
BuilderProxy NO_OP = (builder, app, params) -> { };
BuilderProxy ALWAYS_VISIBLE = (builder, app, params) ->builder.withAlpha(1);
default void onBuildTargetParams(SurfaceParams.Builder builder,
RemoteAnimationTargetCompat app, TransformParams params) { }
void onBuildTargetParams(SurfaceParams.Builder builder,
RemoteAnimationTargetCompat app, TransformParams params);
}
}
@@ -47,24 +47,21 @@ public class ClearAllButton extends Button implements PageCallbacks {
private boolean mIsRtl;
private int mScrollOffset;
private RecentsView mParent;
public ClearAllButton(Context context, AttributeSet attrs) {
super(context, attrs);
mIsRtl = getLayoutDirection() == LAYOUT_DIRECTION_RTL;
}
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
PagedOrientationHandler orientationHandler = mParent.getPagedOrientationHandler();
mScrollOffset = orientationHandler.getClearAllScrollOffset(mParent, mIsRtl);
PagedOrientationHandler orientationHandler = getRecentsView().getPagedOrientationHandler();
mScrollOffset = orientationHandler.getClearAllScrollOffset(getRecentsView(), mIsRtl);
}
@Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
mParent = (RecentsView) getParent();
mIsRtl = getLayoutDirection() == LAYOUT_DIRECTION_RTL;
private RecentsView getRecentsView() {
return (RecentsView) getParent();
}
@Override
@@ -94,7 +91,7 @@ public class ClearAllButton extends Button implements PageCallbacks {
@Override
public void onPageScroll(ScrollState scrollState) {
PagedOrientationHandler orientationHandler = mParent.getPagedOrientationHandler();
PagedOrientationHandler orientationHandler = getRecentsView().getPagedOrientationHandler();
float orientationSize = orientationHandler.getPrimaryValue(getWidth(), getHeight());
if (orientationSize == 0) {
return;
@@ -157,9 +157,8 @@ public class LauncherRecentsView extends RecentsView<BaseQuickstepLauncher>
if (ENABLE_QUICKSTEP_LIVE_TILE.get()) {
if (tv.isRunningTask()) {
mTransformParams.setProgress(1 - progress)
.setCurrentRect(null)
.setSyncTransactionApplier(mSyncTransactionApplier);
mAppWindowAnimationHelper.applyTransform(mTransformParams);
// TODO: Revisit live tiles
} else {
redrawLiveTile(true);
}
@@ -190,19 +189,11 @@ public class LauncherRecentsView extends RecentsView<BaseQuickstepLauncher>
}
}
@Override
public void redrawLiveTile(boolean mightNeedToRefill) {
TransformParams transformParams = getLiveTileParams(mightNeedToRefill);
if (transformParams != null) {
mAppWindowAnimationHelper.applyTransform(transformParams);
}
}
@Override
public TransformParams getLiveTileParams(
boolean mightNeedToRefill) {
if (!mEnableDrawingLiveTile || mRecentsAnimationController == null
|| mRecentsAnimationTargets == null || mAppWindowAnimationHelper == null) {
|| mRecentsAnimationTargets == null) {
return null;
}
TaskView taskView = getRunningTaskView();
@@ -222,9 +213,7 @@ public class LauncherRecentsView extends RecentsView<BaseQuickstepLauncher>
if (mightNeedToRefill && offsetY > 0) {
mTempRect.top -= offsetY;
}
mTempRectF.set(mTempRect);
mTransformParams.setProgress(1f)
.setCurrentRect(mTempRectF)
.setTargetAlpha(taskView.getAlpha())
.setSyncTransactionApplier(mSyncTransactionApplier)
.setTargetSet(mRecentsAnimationTargets);
@@ -17,10 +17,12 @@
package com.android.quickstep.views;
import static com.android.launcher3.config.FeatureFlags.ENABLE_OVERVIEW_ACTIONS;
import static com.android.launcher3.config.FeatureFlags.ENABLE_OVERVIEW_SHARE;
import static com.android.quickstep.SysUINavigationMode.removeShelfFromOverview;
import android.content.Context;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.FrameLayout;
@@ -91,8 +93,13 @@ public class OverviewActionsView<T extends OverlayUICallbacks> extends FrameLayo
@Override
protected void onFinishInflate() {
super.onFinishInflate();
findViewById(R.id.action_share).setOnClickListener(this);
View share = findViewById(R.id.action_share);
share.setOnClickListener(this);
findViewById(R.id.action_screenshot).setOnClickListener(this);
if (ENABLE_OVERVIEW_SHARE.get()) {
share.setVisibility(VISIBLE);
findViewById(R.id.share_space).setVisibility(VISIBLE);
}
}
/**
@@ -107,6 +114,7 @@ public class OverviewActionsView<T extends OverlayUICallbacks> extends FrameLayo
@Override
public void onClick(View view) {
if (mCallbacks == null) {
Log.d("OverviewActionsView", "Callbacks null onClick");
return;
}
int id = view.getId();
@@ -17,6 +17,8 @@
package com.android.quickstep.views;
import static android.view.Surface.ROTATION_0;
import static android.view.View.MeasureSpec.EXACTLY;
import static android.view.View.MeasureSpec.makeMeasureSpec;
import static com.android.launcher3.BaseActivity.STATE_HANDLER_INVISIBILITY_FLAGS;
import static com.android.launcher3.InvariantDeviceProfile.CHANGE_FLAG_ICON_PARAMS;
@@ -61,7 +63,6 @@ import android.graphics.Canvas;
import android.graphics.Point;
import android.graphics.PointF;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.Typeface;
import android.graphics.drawable.Drawable;
import android.os.Build;
@@ -124,7 +125,6 @@ import com.android.quickstep.SystemUiProxy;
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;
@@ -212,15 +212,12 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl
protected final BaseActivityInterface mSizeStrategy;
protected RecentsAnimationController mRecentsAnimationController;
protected RecentsAnimationTargets mRecentsAnimationTargets;
protected AppWindowAnimationHelper mAppWindowAnimationHelper;
protected SyncRtSurfaceTransactionApplierCompat mSyncTransactionApplier;
protected int mTaskWidth;
protected int mTaskHeight;
protected boolean mEnableDrawingLiveTile = false;
protected final Rect mTempRect = new Rect();
protected final RectF mTempRectF = new RectF();
private final PointF mTempPointF = new PointF();
private final float[] mTempFloatPoint = new float[2];
private static final int DISMISS_TASK_DURATION = 300;
private static final int ADDITION_TASK_DURATION = 200;
@@ -827,6 +824,10 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl
@Override
public void setInsets(Rect insets) {
mInsets.set(insets);
resetPaddingFromTaskSize();
}
private void resetPaddingFromTaskSize() {
DeviceProfile dp = mActivity.getDeviceProfile();
mOrientationState.setMultiWindowMode(dp.isMultiWindowMode);
getTaskSize(mTempRect);
@@ -840,7 +841,8 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl
}
public void getTaskSize(Rect outRect) {
mSizeStrategy.calculateTaskSize(mActivity, mActivity.getDeviceProfile(), outRect);
mSizeStrategy.calculateTaskSize(mActivity, mActivity.getDeviceProfile(), outRect,
mOrientationHandler);
}
/** Gets the task size for modal state. */
@@ -973,7 +975,6 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl
mRecentsAnimationController = null;
mRecentsAnimationTargets = null;
mAppWindowAnimationHelper = null;
unloadVisibleTaskData();
setCurrentPage(0);
@@ -1075,9 +1076,9 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl
* Called when a gesture from an app has finished.
*/
public void onGestureAnimationEnd() {
setOnScrollChangeListener(null);
setEnableFreeScroll(true);
setEnableDrawingLiveTile(true);
setOnScrollChangeListener(null);
if (!ENABLE_QUICKSTEP_LIVE_TILE.get()) {
setRunningTaskViewShowScreenshot(true);
}
@@ -1108,6 +1109,12 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl
false, true, false, false, new ActivityManager.TaskDescription(), 0,
new ComponentName("", ""), false);
taskView.bind(mTmpRunningTask, mOrientationState);
// Measure and layout immediately so that the scroll values is updated instantly
// as the user might be quick-switching
measure(makeMeasureSpec(getMeasuredWidth(), EXACTLY),
makeMeasureSpec(getMeasuredHeight(), EXACTLY));
layout(getLeft(), getTop(), getRight(), getBottom());
}
boolean runningTaskTileHidden = mRunningTaskTileHidden;
@@ -1484,7 +1491,7 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl
return true;
}
private void runDismissAnimation(PendingAnimation pendingAnim) {
protected void runDismissAnimation(PendingAnimation pendingAnim) {
AnimatorPlaybackController controller = pendingAnim.createPlaybackController();
controller.dispatchOnStart();
controller.setEndAction(() -> pendingAnim.finish(true, Touch.SWIPE));
@@ -1618,6 +1625,7 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl
mActivity.getDragLayer().recreateControllers();
mActionsView.updateHiddenFlags(HIDDEN_NON_ZERO_ROTATION,
touchRotation != 0 || mOrientationState.getLauncherRotation() != ROTATION_0);
resetPaddingFromTaskSize();
requestLayout();
}
}
@@ -1995,11 +2003,6 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl
mRecentsAnimationTargets = recentsAnimationTargets;
}
// TODO: To be removed in a follow up CL
public void setAppWindowAnimationHelper(AppWindowAnimationHelper appWindowAnimationHelper) {
mAppWindowAnimationHelper = appWindowAnimationHelper;
}
public void setLiveTileOverlayAttached(boolean liveTileOverlayAttached) {
mLiveTileOverlayAttached = liveTileOverlayAttached;
}
@@ -2082,13 +2085,20 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl
/**
* @return How many pixels the running task is offset on the x-axis due to the current scrollX.
* @return How many pixels the running task is offset on the currently laid out dominant axis.
*/
public int getScrollOffset() {
if (getRunningTaskIndex() == -1) {
return getScrollOffset(getRunningTaskIndex());
}
/**
* @return How many pixels the page is offset on the currently laid out dominant axis.
*/
public int getScrollOffset(int pageIndex) {
if (pageIndex == -1) {
return 0;
}
return getScrollForPage(getRunningTaskIndex()) - mOrientationHandler.getPrimaryScroll(this);
return getScrollForPage(pageIndex) - mOrientationHandler.getPrimaryScroll(this);
}
public Consumer<MotionEvent> getEventDispatcher(float navbarRotation) {
@@ -2120,10 +2130,6 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl
};
}
public AppWindowAnimationHelper getClipAnimationHelper() {
return mAppWindowAnimationHelper;
}
public TransformParams getLiveTileParams(
boolean mightNeedToRefill) {
return null;
@@ -444,7 +444,6 @@ public class TaskThumbnailView extends View implements PluginListener<OverviewSc
int thumbnailRotation = thumbnailData.rotation;
int deltaRotate = getRotationDelta(currentRotation, thumbnailRotation);
Rect deviceInsets = dp.getInsets();
// Landscape vs portrait change
boolean windowingModeSupportsRotation = !dp.isMultiWindowMode
&& thumbnailData.windowingMode == WINDOWING_MODE_FULLSCREEN;
@@ -463,9 +462,16 @@ public class TaskThumbnailView extends View implements PluginListener<OverviewSc
: canvasWidth / thumbnailWidth;
}
Rect splitScreenInsets = dp.getInsets();
if (!isRotated) {
// No Rotation
mClippedInsets.offsetTo(deviceInsets.left * scale, deviceInsets.top * scale);
if (dp.isMultiWindowMode) {
mClippedInsets.offsetTo(splitScreenInsets.left * scale,
splitScreenInsets.top * scale);
} else {
mClippedInsets.offsetTo(thumbnailInsets.left * scale,
thumbnailInsets.top * scale);
}
mMatrix.setTranslate(
-thumbnailInsets.left * scale,
-thumbnailInsets.top * scale);
@@ -486,8 +492,8 @@ public class TaskThumbnailView extends View implements PluginListener<OverviewSc
mClippedInsets.top *= thumbnailScale;
if (dp.isMultiWindowMode) {
mClippedInsets.right = deviceInsets.right * scale * thumbnailScale;
mClippedInsets.bottom = deviceInsets.bottom * scale * thumbnailScale;
mClippedInsets.right = splitScreenInsets.right * scale * thumbnailScale;
mClippedInsets.bottom = splitScreenInsets.bottom * scale * thumbnailScale;
} else {
mClippedInsets.right = Math.max(0,
widthWithInsets - mClippedInsets.left - canvasWidth);
@@ -14,13 +14,12 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
<com.android.quickstep.views.OverviewActionsView
xmlns:android="http://schemas.android.com/apk/res/android"
<com.android.quickstep.views.OverviewActionsView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="@dimen/overview_actions_height"
android:layout_gravity="center_horizontal|bottom"
android:layout_marginLeft="@dimen/overview_actions_horizontal_margin"
android:layout_marginRight="@dimen/overview_actions_horizontal_margin" >
android:layout_marginRight="@dimen/overview_actions_horizontal_margin">
<LinearLayout
android:id="@+id/action_buttons"
@@ -28,38 +27,42 @@
android:layout_height="wrap_content"
android:layout_gravity="center"
android:orientation="horizontal">
<Space
android:layout_width="0dp"
android:layout_height="1dp"
android:layout_weight="1" >
</Space>
android:layout_weight="1" />
<Button
android:id="@+id/action_screenshot"
android:theme="@style/ThemeControlHighlightWorkspaceColor"
style="@style/OverviewActionButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:drawableTop="@drawable/ic_screenshot"
android:text="@string/action_screenshot" />
android:text="@string/action_screenshot"
android:theme="@style/ThemeControlHighlightWorkspaceColor" />
<Space
android:layout_width="0dp"
android:layout_height="1dp"
android:layout_weight="1" >
</Space>
android:layout_weight="1" />
<Button
android:id="@+id/action_share"
android:theme="@style/ThemeControlHighlightWorkspaceColor"
style="@style/OverviewActionButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:drawableTop="@drawable/ic_share"
android:text="@string/action_share" />
android:text="@string/action_share"
android:theme="@style/ThemeControlHighlightWorkspaceColor"
android:visibility="gone" />
<Space
android:id="@+id/share_space"
android:layout_width="0dp"
android:layout_height="1dp"
android:layout_weight="1" >
</Space>
android:layout_weight="1"
android:visibility="gone" />
</LinearLayout>
</com.android.quickstep.views.OverviewActionsView>
+1
View File
@@ -46,4 +46,5 @@
<string name="hotseat_prediction_content_description" msgid="4582028296938078419">"Voorspelde program: <xliff:g id="TITLE">%1$s</xliff:g>"</string>
<string name="action_share" msgid="2648470652637092375">"Deel"</string>
<string name="action_screenshot" msgid="8171125848358142917">"Skermkiekie"</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"Jou organisasie laat nie hierdie program toe nie"</string>
</resources>
+1
View File
@@ -46,4 +46,5 @@
<string name="hotseat_prediction_content_description" msgid="4582028296938078419">"የተገመተው መተግበሪያ፦ <xliff:g id="TITLE">%1$s</xliff:g>"</string>
<string name="action_share" msgid="2648470652637092375">"አጋራ"</string>
<string name="action_screenshot" msgid="8171125848358142917">"ቅጽበታዊ ገጽ እይታ"</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"ይህ ድርጊት በመተግበሪያው ወይም በእርስዎ ድርጅት አይፈቀድም"</string>
</resources>
+1
View File
@@ -46,4 +46,5 @@
<string name="hotseat_prediction_content_description" msgid="4582028296938078419">"التطبيق المتوقع: <xliff:g id="TITLE">%1$s</xliff:g>"</string>
<string name="action_share" msgid="2648470652637092375">"مشاركة"</string>
<string name="action_screenshot" msgid="8171125848358142917">"لقطة شاشة"</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"لا يسمح التطبيق أو لا تسمح مؤسستك بهذا الإجراء."</string>
</resources>
+1
View File
@@ -46,4 +46,5 @@
<string name="hotseat_prediction_content_description" msgid="4582028296938078419">"পূৰ্বানুমান কৰা এপ্: <xliff:g id="TITLE">%1$s</xliff:g>"</string>
<string name="action_share" msgid="2648470652637092375">"শ্বেয়াৰ কৰক"</string>
<string name="action_screenshot" msgid="8171125848358142917">"স্ক্ৰীনশ্বট"</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"এপ্‌টোৱে অথবা আপোনাৰ প্ৰতিষ্ঠানে এই কাৰ্যটোৰ অনুমতি নিদিয়ে"</string>
</resources>
+1
View File
@@ -46,4 +46,5 @@
<string name="hotseat_prediction_content_description" msgid="4582028296938078419">"Proqnozlaşdırılan tətbiq: <xliff:g id="TITLE">%1$s</xliff:g>"</string>
<string name="action_share" msgid="2648470652637092375">"Paylaşın"</string>
<string name="action_screenshot" msgid="8171125848358142917">"Ekran şəkli"</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"Bu əməliyyata tətbiq və ya təşkilatınız tərəfindən icazə verilmir"</string>
</resources>
+2 -1
View File
@@ -45,5 +45,6 @@
<string name="hotseat_tip_gaps_filled" msgid="3035673010274223538">"Predlozi aplikacija se dodaju na prazno mesto"</string>
<string name="hotseat_prediction_content_description" msgid="4582028296938078419">"Predviđamo aplikaciju: <xliff:g id="TITLE">%1$s</xliff:g>"</string>
<string name="action_share" msgid="2648470652637092375">"Deli"</string>
<string name="action_screenshot" msgid="8171125848358142917">"Napravi snimak ekrana"</string>
<string name="action_screenshot" msgid="8171125848358142917">"Snimak ekrana"</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"Aplikacija ili organizacija ne dozvoljavaju ovu radnju"</string>
</resources>
+1
View File
@@ -46,4 +46,5 @@
<string name="hotseat_prediction_content_description" msgid="4582028296938078419">"Праграма з падказкі: <xliff:g id="TITLE">%1$s</xliff:g>"</string>
<string name="action_share" msgid="2648470652637092375">"Абагуліць"</string>
<string name="action_screenshot" msgid="8171125848358142917">"Здымак экрана"</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"Гэта дзеянне не дазволена праграмай ці вашай арганізацыяй"</string>
</resources>
+2 -1
View File
@@ -32,7 +32,7 @@
<string name="title_app_suggestions" msgid="4185902664111965088">"Предложения за приложения"</string>
<string name="all_apps_label" msgid="8542784161730910663">"Всички приложения"</string>
<string name="all_apps_prediction_tip" msgid="2672336544844936186">"Предвидени приложения"</string>
<string name="hotseat_edu_prompt_title" msgid="5595771595144175752">"Лесен достъп до най-използваните от вас приложения"</string>
<string name="hotseat_edu_prompt_title" msgid="5595771595144175752">"Лесен достъп до най-използваните прилож."</string>
<string name="hotseat_edu_prompt_content" msgid="5709176001504149521">"Pixel предвижда кои приложения ще са ви нужни в следващия момент и ви ги показва директно на началния екран. Докоснете, за да настроите."</string>
<string name="hotseat_edu_title_migrate" msgid="306578144424489980">"Получавайте предложения за приложения на най-долния ред на началния си екран"</string>
<string name="hotseat_edu_message_migrate" msgid="8927179260533775320">"Осъществявайте лесен достъп до най-използваните от вас приложения директно от началния екран. Предложенията ще се променят въз основа на поредиците ви. Приложенията на най-долния ред ще се преместят на началния ви екран."</string>
@@ -46,4 +46,5 @@
<string name="hotseat_prediction_content_description" msgid="4582028296938078419">"Предвидено приложение: <xliff:g id="TITLE">%1$s</xliff:g>"</string>
<string name="action_share" msgid="2648470652637092375">"Споделяне"</string>
<string name="action_screenshot" msgid="8171125848358142917">"Екранна снимка"</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"Това действие не е разрешено от приложението или организацията ви"</string>
</resources>
+1
View File
@@ -46,4 +46,5 @@
<string name="hotseat_prediction_content_description" msgid="4582028296938078419">"আপনার প্রয়োজন হতে পারে এমন অ্যাপ: <xliff:g id="TITLE">%1$s</xliff:g>"</string>
<string name="action_share" msgid="2648470652637092375">"শেয়ার করুন"</string>
<string name="action_screenshot" msgid="8171125848358142917">"স্ক্রিনশট"</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"এই অ্যাপ বা আপনার প্রতিষ্ঠান এই অ্যাকশনটি পারফর্ম করার অনুমতি দেয়নি"</string>
</resources>
+1
View File
@@ -46,4 +46,5 @@
<string name="hotseat_prediction_content_description" msgid="4582028296938078419">"Predviđena aplikacija: <xliff:g id="TITLE">%1$s</xliff:g>"</string>
<string name="action_share" msgid="2648470652637092375">"Dijeli"</string>
<string name="action_screenshot" msgid="8171125848358142917">"Snimak ekrana"</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"Ovu radnju ne dozvoljava aplikacija ili vaša organizacija"</string>
</resources>
+1
View File
@@ -46,4 +46,5 @@
<string name="hotseat_prediction_content_description" msgid="4582028296938078419">"Predicció d\'aplicació: <xliff:g id="TITLE">%1$s</xliff:g>"</string>
<string name="action_share" msgid="2648470652637092375">"Comparteix"</string>
<string name="action_screenshot" msgid="8171125848358142917">"Captura de pantalla"</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"L\'aplicació o la teva organització no permeten aquesta acció"</string>
</resources>
+1
View File
@@ -46,4 +46,5 @@
<string name="hotseat_prediction_content_description" msgid="4582028296938078419">"Předpokládaná aplikace: <xliff:g id="TITLE">%1$s</xliff:g>"</string>
<string name="action_share" msgid="2648470652637092375">"Sdílet"</string>
<string name="action_screenshot" msgid="8171125848358142917">"Snímek obrazovky"</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"Aplikace nebo organizace zakazuje tuto akci"</string>
</resources>
+1
View File
@@ -46,4 +46,5 @@
<string name="hotseat_prediction_content_description" msgid="4582028296938078419">"App, du forventes at skulle bruge: <xliff:g id="TITLE">%1$s</xliff:g>"</string>
<string name="action_share" msgid="2648470652637092375">"Del"</string>
<string name="action_screenshot" msgid="8171125848358142917">"Screenshot"</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"Appen eller din organisation tillader ikke denne handling"</string>
</resources>
+2 -1
View File
@@ -33,7 +33,7 @@
<string name="all_apps_label" msgid="8542784161730910663">"Alle Apps"</string>
<string name="all_apps_prediction_tip" msgid="2672336544844936186">"App-Vorschläge für dich"</string>
<string name="hotseat_edu_prompt_title" msgid="5595771595144175752">"Einfacher Zugriff auf deine meistverwendeten Apps"</string>
<string name="hotseat_edu_prompt_content" msgid="5709176001504149521">"Das Pixel prognostiziert, welche Apps du als nächste brauchst, und setzt diese direkt auf den Startbildschirm. Zum Einrichten tippen."</string>
<string name="hotseat_edu_prompt_content" msgid="5709176001504149521">"Pixel prognostiziert, welche Apps du als nächste brauchst, und setzt diese direkt auf den Startbildschirm. Zum Einrichten tippen."</string>
<string name="hotseat_edu_title_migrate" msgid="306578144424489980">"Lass dir in der unteren Reihe auf deinem Startbildschirm Vorschläge für Apps anzeigen"</string>
<string name="hotseat_edu_message_migrate" msgid="8927179260533775320">"Schneller Zugriff auf deine meistverwendeten Apps direkt über den Startbildschirm. Die Vorschläge richten sich nach deiner gewöhnlichen Nutzung. Apps in der unteren Reihe werden nach oben auf den Startbildschirm verschoben."</string>
<string name="hotseat_edu_message_migrate_alt" msgid="3042360119039646356">"Schneller Zugriff auf deine meistverwendeten Apps direkt über den Startbildschirm. Die Vorschläge richten sich nach deiner gewöhnlichen Nutzung. Apps in der unteren Reihe werden in einen neuen Ordner verschoben."</string>
@@ -46,4 +46,5 @@
<string name="hotseat_prediction_content_description" msgid="4582028296938078419">"App-Vorhersage: <xliff:g id="TITLE">%1$s</xliff:g>"</string>
<string name="action_share" msgid="2648470652637092375">"Teilen"</string>
<string name="action_screenshot" msgid="8171125848358142917">"Screenshot"</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"Die App oder deine Organisation lässt diese Aktion nicht zu"</string>
</resources>
+1
View File
@@ -46,4 +46,5 @@
<string name="hotseat_prediction_content_description" msgid="4582028296938078419">"Εφαρμογή από πρόβλεψη: <xliff:g id="TITLE">%1$s</xliff:g>"</string>
<string name="action_share" msgid="2648470652637092375">"Κοινοποίηση"</string>
<string name="action_screenshot" msgid="8171125848358142917">"Στιγμιότυπο οθόνης"</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"Αυτή η ενέργεια δεν επιτρέπεται από την εφαρμογή ή τον οργανισμό σας."</string>
</resources>
+2 -1
View File
@@ -33,7 +33,7 @@
<string name="all_apps_label" msgid="8542784161730910663">"All apps"</string>
<string name="all_apps_prediction_tip" msgid="2672336544844936186">"Your predicted apps"</string>
<string name="hotseat_edu_prompt_title" msgid="5595771595144175752">"Easily access your most-used apps"</string>
<string name="hotseat_edu_prompt_content" msgid="5709176001504149521">"Pixel predicts apps that you\'ll need next directly from your home screen. Tap to set up."</string>
<string name="hotseat_edu_prompt_content" msgid="5709176001504149521">"Pixel predicts apps you\'ll need next, right on your Home screen. Tap to set up."</string>
<string name="hotseat_edu_title_migrate" msgid="306578144424489980">"Get app suggestions on the bottom row of your home screen"</string>
<string name="hotseat_edu_message_migrate" msgid="8927179260533775320">"Easily access your most-used apps directly from the home screen. Suggestions will change based on your routines. Apps on the bottom row will move up to your home screen."</string>
<string name="hotseat_edu_message_migrate_alt" msgid="3042360119039646356">"Easily access your most-used apps directly from the home screen. Suggestions will change based on your routines. Apps on the bottom row will be moved to a new folder."</string>
@@ -46,4 +46,5 @@
<string name="hotseat_prediction_content_description" msgid="4582028296938078419">"Predicted app: <xliff:g id="TITLE">%1$s</xliff:g>"</string>
<string name="action_share" msgid="2648470652637092375">"Share"</string>
<string name="action_screenshot" msgid="8171125848358142917">"Screenshot"</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"This action isn\'t allowed by the app or your organisation"</string>
</resources>
+2 -1
View File
@@ -33,7 +33,7 @@
<string name="all_apps_label" msgid="8542784161730910663">"All apps"</string>
<string name="all_apps_prediction_tip" msgid="2672336544844936186">"Your predicted apps"</string>
<string name="hotseat_edu_prompt_title" msgid="5595771595144175752">"Easily access your most-used apps"</string>
<string name="hotseat_edu_prompt_content" msgid="5709176001504149521">"Pixel predicts apps that you\'ll need next directly from your home screen. Tap to set up."</string>
<string name="hotseat_edu_prompt_content" msgid="5709176001504149521">"Pixel predicts apps you\'ll need next, right on your Home screen. Tap to set up."</string>
<string name="hotseat_edu_title_migrate" msgid="306578144424489980">"Get app suggestions on the bottom row of your home screen"</string>
<string name="hotseat_edu_message_migrate" msgid="8927179260533775320">"Easily access your most-used apps directly from the home screen. Suggestions will change based on your routines. Apps on the bottom row will move up to your home screen."</string>
<string name="hotseat_edu_message_migrate_alt" msgid="3042360119039646356">"Easily access your most-used apps directly from the home screen. Suggestions will change based on your routines. Apps on the bottom row will be moved to a new folder."</string>
@@ -46,4 +46,5 @@
<string name="hotseat_prediction_content_description" msgid="4582028296938078419">"Predicted app: <xliff:g id="TITLE">%1$s</xliff:g>"</string>
<string name="action_share" msgid="2648470652637092375">"Share"</string>
<string name="action_screenshot" msgid="8171125848358142917">"Screenshot"</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"This action isn\'t allowed by the app or your organisation"</string>
</resources>
+2 -1
View File
@@ -33,7 +33,7 @@
<string name="all_apps_label" msgid="8542784161730910663">"All apps"</string>
<string name="all_apps_prediction_tip" msgid="2672336544844936186">"Your predicted apps"</string>
<string name="hotseat_edu_prompt_title" msgid="5595771595144175752">"Easily access your most-used apps"</string>
<string name="hotseat_edu_prompt_content" msgid="5709176001504149521">"Pixel predicts apps that you\'ll need next directly from your home screen. Tap to set up."</string>
<string name="hotseat_edu_prompt_content" msgid="5709176001504149521">"Pixel predicts apps you\'ll need next, right on your Home screen. Tap to set up."</string>
<string name="hotseat_edu_title_migrate" msgid="306578144424489980">"Get app suggestions on the bottom row of your home screen"</string>
<string name="hotseat_edu_message_migrate" msgid="8927179260533775320">"Easily access your most-used apps directly from the home screen. Suggestions will change based on your routines. Apps on the bottom row will move up to your home screen."</string>
<string name="hotseat_edu_message_migrate_alt" msgid="3042360119039646356">"Easily access your most-used apps directly from the home screen. Suggestions will change based on your routines. Apps on the bottom row will be moved to a new folder."</string>
@@ -46,4 +46,5 @@
<string name="hotseat_prediction_content_description" msgid="4582028296938078419">"Predicted app: <xliff:g id="TITLE">%1$s</xliff:g>"</string>
<string name="action_share" msgid="2648470652637092375">"Share"</string>
<string name="action_screenshot" msgid="8171125848358142917">"Screenshot"</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"This action isn\'t allowed by the app or your organisation"</string>
</resources>
+2 -1
View File
@@ -33,7 +33,7 @@
<string name="all_apps_label" msgid="8542784161730910663">"All apps"</string>
<string name="all_apps_prediction_tip" msgid="2672336544844936186">"Your predicted apps"</string>
<string name="hotseat_edu_prompt_title" msgid="5595771595144175752">"Easily access your most-used apps"</string>
<string name="hotseat_edu_prompt_content" msgid="5709176001504149521">"Pixel predicts apps that you\'ll need next directly from your home screen. Tap to set up."</string>
<string name="hotseat_edu_prompt_content" msgid="5709176001504149521">"Pixel predicts apps you\'ll need next, right on your Home screen. Tap to set up."</string>
<string name="hotseat_edu_title_migrate" msgid="306578144424489980">"Get app suggestions on the bottom row of your home screen"</string>
<string name="hotseat_edu_message_migrate" msgid="8927179260533775320">"Easily access your most-used apps directly from the home screen. Suggestions will change based on your routines. Apps on the bottom row will move up to your home screen."</string>
<string name="hotseat_edu_message_migrate_alt" msgid="3042360119039646356">"Easily access your most-used apps directly from the home screen. Suggestions will change based on your routines. Apps on the bottom row will be moved to a new folder."</string>
@@ -46,4 +46,5 @@
<string name="hotseat_prediction_content_description" msgid="4582028296938078419">"Predicted app: <xliff:g id="TITLE">%1$s</xliff:g>"</string>
<string name="action_share" msgid="2648470652637092375">"Share"</string>
<string name="action_screenshot" msgid="8171125848358142917">"Screenshot"</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"This action isn\'t allowed by the app or your organisation"</string>
</resources>
+1
View File
@@ -46,4 +46,5 @@
<string name="hotseat_prediction_content_description" msgid="4582028296938078419">"Predicted app: <xliff:g id="TITLE">%1$s</xliff:g>"</string>
<string name="action_share" msgid="2648470652637092375">"Share"</string>
<string name="action_screenshot" msgid="8171125848358142917">"Screenshot"</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"This action isn\'t allowed by the app or your organization"</string>
</resources>
+1
View File
@@ -46,4 +46,5 @@
<string name="hotseat_prediction_content_description" msgid="4582028296938078419">"Predicción de app: <xliff:g id="TITLE">%1$s</xliff:g>"</string>
<string name="action_share" msgid="2648470652637092375">"Compartir"</string>
<string name="action_screenshot" msgid="8171125848358142917">"Captura de pantalla"</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"La app o tu organización no permiten realizar esta acción"</string>
</resources>
+1
View File
@@ -46,4 +46,5 @@
<string name="hotseat_prediction_content_description" msgid="4582028296938078419">"Aplicación sugerida: <xliff:g id="TITLE">%1$s</xliff:g>"</string>
<string name="action_share" msgid="2648470652637092375">"Compartir"</string>
<string name="action_screenshot" msgid="8171125848358142917">"Hacer captura"</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"No puedes hacerlo porque la aplicación o tu organización no lo permiten"</string>
</resources>
+1
View File
@@ -46,4 +46,5 @@
<string name="hotseat_prediction_content_description" msgid="4582028296938078419">"Ennustatud rakendus: <xliff:g id="TITLE">%1$s</xliff:g>"</string>
<string name="action_share" msgid="2648470652637092375">"Jaga"</string>
<string name="action_screenshot" msgid="8171125848358142917">"Ekraanipilt"</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"Rakendus või teie organisatsioon on selle toimingu keelanud"</string>
</resources>
+1
View File
@@ -46,4 +46,5 @@
<string name="hotseat_prediction_content_description" msgid="4582028296938078419">"Iragarritako aplikazioa: <xliff:g id="TITLE">%1$s</xliff:g>"</string>
<string name="action_share" msgid="2648470652637092375">"Partekatu"</string>
<string name="action_screenshot" msgid="8171125848358142917">"Atera pantaila-argazki bat"</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"Aplikazioak edo erakundeak ez du eman ekintza hori gauzatzeko baimena"</string>
</resources>
+1
View File
@@ -46,4 +46,5 @@
<string name="hotseat_prediction_content_description" msgid="4582028296938078419">"برنامه پیش‌بینی‌شده: <xliff:g id="TITLE">%1$s</xliff:g>"</string>
<string name="action_share" msgid="2648470652637092375">"هم‌رسانی"</string>
<string name="action_screenshot" msgid="8171125848358142917">"نماگرفت"</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"برنامه یا سازمان شما اجازه نمی‌دهد این کنش انجام شود."</string>
</resources>
+1
View File
@@ -46,4 +46,5 @@
<string name="hotseat_prediction_content_description" msgid="4582028296938078419">"Ennakoitu sovellus: <xliff:g id="TITLE">%1$s</xliff:g>"</string>
<string name="action_share" msgid="2648470652637092375">"Jaa"</string>
<string name="action_screenshot" msgid="8171125848358142917">"Kuvakaappaus"</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"Sovellus tai organisaatio ei salli tätä toimintoa"</string>
</resources>
+1
View File
@@ -46,4 +46,5 @@
<string name="hotseat_prediction_content_description" msgid="4582028296938078419">"Application prédite : <xliff:g id="TITLE">%1$s</xliff:g>"</string>
<string name="action_share" msgid="2648470652637092375">"Partager"</string>
<string name="action_screenshot" msgid="8171125848358142917">"Capture d\'écran"</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"L\'application ou votre organisation n\'autorise pas cette action"</string>
</resources>
+8 -7
View File
@@ -34,16 +34,17 @@
<string name="all_apps_prediction_tip" msgid="2672336544844936186">"Applications prévues pour vous"</string>
<string name="hotseat_edu_prompt_title" msgid="5595771595144175752">"Accédez facilement à vos applications les plus utilisées"</string>
<string name="hotseat_edu_prompt_content" msgid="5709176001504149521">"Pixel prédit les applications dont vous pourriez avoir besoin par la suite et les affiche sur votre écran d\'accueil. Appuyez ici pour configurer ce paramètre."</string>
<string name="hotseat_edu_title_migrate" msgid="306578144424489980">"Retrouvez vos applications suggérées dans la rangée du bas de votre écran d\'accueil"</string>
<string name="hotseat_edu_message_migrate" msgid="8927179260533775320">"Accédez facilement aux applications dont vous vous servez le plus, directement depuis l\'écran d\'accueil. Ces suggestions peuvent varier en fonction de vos habitudes d\'utilisation. Les applications de la rangée du bas seront transférées sur votre écran d\'accueil."</string>
<string name="hotseat_edu_message_migrate_alt" msgid="3042360119039646356">"Accédez facilement aux applications dont vous vous servez le plus, directement depuis l\'écran d\'accueil. Ces suggestions peuvent varier en fonction de vos habitudes d\'utilisation. Les applications de la rangée du bas seront transférées dans un nouveau dossier."</string>
<string name="hotseat_edu_accept" msgid="1611544083278999837">"Activer les applications suggérées"</string>
<string name="hotseat_edu_title_migrate" msgid="306578144424489980">"Retrouvez vos applications favorites au bas de votre écran d\'accueil"</string>
<string name="hotseat_edu_message_migrate" msgid="8927179260533775320">"Les suggestions d\'applications permettent d\'afficher vos applications favorites au bas de votre écran d\'accueil. Elles s\'adaptent à vos habitudes d\'utilisation. Les icônes auparavant affichées au bas de l\'écran seront déplacées vers le haut."</string>
<string name="hotseat_edu_message_migrate_alt" msgid="3042360119039646356">"Les suggestions d\'applications permettent d\'afficher vos applications favorites au bas de votre écran d\'accueil. Elles s\'adaptent à vos habitudes d\'utilisation. Les icônes auparavant affichées au bas de l\'écran seront placées dans un nouveau dossier."</string>
<string name="hotseat_edu_accept" msgid="1611544083278999837">"Activer les suggestions"</string>
<string name="hotseat_edu_dismiss" msgid="2781161822780201689">"Non, merci"</string>
<string name="hotseat_turn_off" msgid="7808360330229368470">"Paramètres"</string>
<string name="hotseat_auto_enrolled" msgid="522100018967146807">"Les applications dont vous vous servez le plus s\'affichent ici (ces suggestions peuvent varier en fonction de vos habitudes d\'utilisation)"</string>
<string name="hotseat_tip_no_empty_slots" msgid="1325212677738179185">"Faites glisser des applications hors de la rangée du bas pour obtenir des applications suggérées"</string>
<string name="hotseat_tip_gaps_filled" msgid="3035673010274223538">"Vos applications suggérées ont été ajoutées là où il y avait de la place"</string>
<string name="hotseat_tip_no_empty_slots" msgid="1325212677738179185">"Faites glisser des applications hors de la rangée du bas pour obtenir des suggestions d\'applications"</string>
<string name="hotseat_tip_gaps_filled" msgid="3035673010274223538">"Des suggestions d\'applications ont été ajoutées à un emplacement vide"</string>
<string name="hotseat_prediction_content_description" msgid="4582028296938078419">"Application prédite : <xliff:g id="TITLE">%1$s</xliff:g>"</string>
<string name="action_share" msgid="2648470652637092375">"Partager"</string>
<string name="action_screenshot" msgid="8171125848358142917">"Faire une capture d\'écran"</string>
<string name="action_screenshot" msgid="8171125848358142917">"Capture d\'écran"</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"Cette action n\'est pas autorisée par l\'application ou par votre organisation"</string>
</resources>
+2 -1
View File
@@ -45,5 +45,6 @@
<string name="hotseat_tip_gaps_filled" msgid="3035673010274223538">"Engadíronse suxestións de aplicacións ao espazo baleiro"</string>
<string name="hotseat_prediction_content_description" msgid="4582028296938078419">"Aplicación predita: <xliff:g id="TITLE">%1$s</xliff:g>"</string>
<string name="action_share" msgid="2648470652637092375">"Compartir"</string>
<string name="action_screenshot" msgid="8171125848358142917">"Crear captura"</string>
<string name="action_screenshot" msgid="8171125848358142917">"Facer captura"</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"A aplicación ou a túa organización non permite realizar esta acción"</string>
</resources>
+1
View File
@@ -46,4 +46,5 @@
<string name="hotseat_prediction_content_description" msgid="4582028296938078419">"પૂર્વાનુમાનિત ઍપ: <xliff:g id="TITLE">%1$s</xliff:g>"</string>
<string name="action_share" msgid="2648470652637092375">"શેર કરો"</string>
<string name="action_screenshot" msgid="8171125848358142917">"સ્ક્રીનશૉટ"</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"ઍપ કે તમારી સંસ્થા દ્વારા આ ક્રિયા કરવાની મંજૂરી નથી"</string>
</resources>
+1
View File
@@ -46,4 +46,5 @@
<string name="hotseat_prediction_content_description" msgid="4582028296938078419">"सुझाया गया ऐप्लिकेशन: <xliff:g id="TITLE">%1$s</xliff:g>"</string>
<string name="action_share" msgid="2648470652637092375">"शेयर करें"</string>
<string name="action_screenshot" msgid="8171125848358142917">"स्क्रीनशॉट"</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"ऐप्लिकेशन या आपका संगठन इस कार्रवाई की अनुमति नहीं देता"</string>
</resources>
+1
View File
@@ -46,4 +46,5 @@
<string name="hotseat_prediction_content_description" msgid="4582028296938078419">"Predviđena aplikacija: <xliff:g id="TITLE">%1$s</xliff:g>"</string>
<string name="action_share" msgid="2648470652637092375">"Udio"</string>
<string name="action_screenshot" msgid="8171125848358142917">"Snimka zaslona"</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"Aplikacija ili vaša organizacija ne dopuštaju ovu radnju"</string>
</resources>
+1
View File
@@ -46,4 +46,5 @@
<string name="hotseat_prediction_content_description" msgid="4582028296938078419">"Várható alkalmazás: <xliff:g id="TITLE">%1$s</xliff:g>"</string>
<string name="action_share" msgid="2648470652637092375">"Megosztás"</string>
<string name="action_screenshot" msgid="8171125848358142917">"Képernyőkép"</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"Az alkalmazás vagy az Ön szervezete nem engedélyezi ezt a műveletet"</string>
</resources>
+1
View File
@@ -46,4 +46,5 @@
<string name="hotseat_prediction_content_description" msgid="4582028296938078419">"Առաջարկվող հավելված՝ <xliff:g id="TITLE">%1$s</xliff:g>"</string>
<string name="action_share" msgid="2648470652637092375">"Կիսվել"</string>
<string name="action_screenshot" msgid="8171125848358142917">"Սքրինշոթ անել"</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"Այս գործողությունն արգելված է հավելվածի կամ ձեր կազմակերպության կողմից"</string>
</resources>
+1
View File
@@ -46,4 +46,5 @@
<string name="hotseat_prediction_content_description" msgid="4582028296938078419">"Aplikasi yang diprediksi: <xliff:g id="TITLE">%1$s</xliff:g>"</string>
<string name="action_share" msgid="2648470652637092375">"Bagikan"</string>
<string name="action_screenshot" msgid="8171125848358142917">"Screenshot"</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"Tindakan ini tidak diizinkan oleh aplikasi atau organisasi Anda"</string>
</resources>
+1
View File
@@ -46,4 +46,5 @@
<string name="hotseat_prediction_content_description" msgid="4582028296938078419">"Tillaga að forriti: <xliff:g id="TITLE">%1$s</xliff:g>"</string>
<string name="action_share" msgid="2648470652637092375">"Deila"</string>
<string name="action_screenshot" msgid="8171125848358142917">"Skjámynd"</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"Forritið eða fyrirtækið leyfir ekki þessa aðgerð"</string>
</resources>
+1
View File
@@ -46,4 +46,5 @@
<string name="hotseat_prediction_content_description" msgid="4582028296938078419">"App prevista: <xliff:g id="TITLE">%1$s</xliff:g>"</string>
<string name="action_share" msgid="2648470652637092375">"Condividi"</string>
<string name="action_screenshot" msgid="8171125848358142917">"Screenshot"</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"Questa azione non è consentita dall\'app o dall\'organizzazione"</string>
</resources>
+1
View File
@@ -46,4 +46,5 @@
<string name="hotseat_prediction_content_description" msgid="4582028296938078419">"האפליקציות החזויות: <xliff:g id="TITLE">%1$s</xliff:g>"</string>
<string name="action_share" msgid="2648470652637092375">"שיתוף"</string>
<string name="action_screenshot" msgid="8171125848358142917">"צילום מסך"</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"האפליקציה או הארגון שלך אינם מתירים את הפעולה הזאת"</string>
</resources>
+1
View File
@@ -46,4 +46,5 @@
<string name="hotseat_prediction_content_description" msgid="4582028296938078419">"予測されたアプリ: <xliff:g id="TITLE">%1$s</xliff:g>"</string>
<string name="action_share" msgid="2648470652637092375">"共有"</string>
<string name="action_screenshot" msgid="8171125848358142917">"スクリーンショット"</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"この操作はアプリまたは組織で許可されていません"</string>
</resources>
+1
View File
@@ -46,4 +46,5 @@
<string name="hotseat_prediction_content_description" msgid="4582028296938078419">"ნაწინასწარმეტყველები აპი: <xliff:g id="TITLE">%1$s</xliff:g>"</string>
<string name="action_share" msgid="2648470652637092375">"გაზიარება"</string>
<string name="action_screenshot" msgid="8171125848358142917">"ეკრანის ანაბეჭდი"</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"ეს მოქმედება არ არის დაშვებული აპის ან თქვენი ორგანიზაციის მიერ"</string>
</resources>
+1
View File
@@ -46,4 +46,5 @@
<string name="hotseat_prediction_content_description" msgid="4582028296938078419">"Болжалды қолданба: <xliff:g id="TITLE">%1$s</xliff:g>"</string>
<string name="action_share" msgid="2648470652637092375">"Бөлісу"</string>
<string name="action_screenshot" msgid="8171125848358142917">"Скриншот"</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"Бұл әрекетке қолданба не ұйым рұқсат етпейді."</string>
</resources>
+1
View File
@@ -46,4 +46,5 @@
<string name="hotseat_prediction_content_description" msgid="4582028296938078419">"កម្មវិធី​ដែលបាន​ព្យាករ៖ <xliff:g id="TITLE">%1$s</xliff:g>"</string>
<string name="action_share" msgid="2648470652637092375">"ចែករំលែក"</string>
<string name="action_screenshot" msgid="8171125848358142917">"រូបថតអេក្រង់"</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"សកម្មភាពនេះ​មិនត្រូវបានអនុញ្ញាតដោយកម្មវិធី​ ឬ​ស្ថាប័ន​របស់អ្នកទេ"</string>
</resources>
+1
View File
@@ -46,4 +46,5 @@
<string name="hotseat_prediction_content_description" msgid="4582028296938078419">"ಶಿಫಾರಸು ಮಾಡಿದ ಆ್ಯಪ್: <xliff:g id="TITLE">%1$s</xliff:g>"</string>
<string name="action_share" msgid="2648470652637092375">"ಹಂಚಿಕೊಳ್ಳಿ"</string>
<string name="action_screenshot" msgid="8171125848358142917">"ಸ್ಕ್ರೀನ್‌ಶಾಟ್"</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"ಆ್ಯಪ್ ಅಥವಾ ನಿಮ್ಮ ಸಂಸ್ಥೆಯು ಈ ಕ್ರಿಯೆಯನ್ನು ಅನುಮತಿಸುವುದಿಲ್ಲ"</string>
</resources>
+1
View File
@@ -46,4 +46,5 @@
<string name="hotseat_prediction_content_description" msgid="4582028296938078419">"예상 앱: <xliff:g id="TITLE">%1$s</xliff:g>"</string>
<string name="action_share" msgid="2648470652637092375">"공유"</string>
<string name="action_screenshot" msgid="8171125848358142917">"스크린샷"</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"이 작업은 앱 또는 조직에서 허용되지 않습니다."</string>
</resources>
+5 -4
View File
@@ -32,11 +32,11 @@
<string name="title_app_suggestions" msgid="4185902664111965088">"Сунушталган колдонмолор"</string>
<string name="all_apps_label" msgid="8542784161730910663">"Бардык колдонмолор"</string>
<string name="all_apps_prediction_tip" msgid="2672336544844936186">"Божомолдонгон колдонмолоруңуз"</string>
<string name="hotseat_edu_prompt_title" msgid="5595771595144175752">"Көп иштетилген колдонмолорго оңой кириңиз"</string>
<string name="hotseat_edu_prompt_content" msgid="5709176001504149521">"Pixel кийинки керектелүүчү колдонмолорду Башкы экраныңызда божомолдоп, сунуштап турат. Жөндөө үчүн таптап коюңуз."</string>
<string name="hotseat_edu_prompt_title" msgid="5595771595144175752">"Көп колдонулган колдонмолорго оңой кириңиз"</string>
<string name="hotseat_edu_prompt_content" msgid="5709176001504149521">"Pixel жакын арада кайсы колдонмолорду колдоно турганыңызды божомолдоп, Башкы экраныңызда сунуштап турат. Жөндөө үчүн, таптап коюңуз."</string>
<string name="hotseat_edu_title_migrate" msgid="306578144424489980">"Сунушталган колдонмолорду Башкы экрандын ылдый жагында жайгашкан тилкесинде көрүңүз"</string>
<string name="hotseat_edu_message_migrate" msgid="8927179260533775320">"Көп иштетилген колдонмолорго Башкы экрандан оңой кириңиз. Сунуштар тартиптин негизинде өзгөрөт. Төмөндө жайгашкан тилкедеги колдонмолор Башкы экраныңызга көтөрүлөт."</string>
<string name="hotseat_edu_message_migrate_alt" msgid="3042360119039646356">"Көп иштетилген колдонмолорго Башкы экрандан оңой кириңиз. Сунуштар тартиптин негизинде өзгөрөт. Ылдый жакта жайгашкан тилкедеги колдонмолор жаңы папкага жылдырылат."</string>
<string name="hotseat_edu_message_migrate" msgid="8927179260533775320">"Көп колдонулган колдонмолорго Башкы экрандан оңой кириңиз. Сунуштар тартиптин негизинде өзгөрөт. Төмөндө жайгашкан тилкедеги колдонмолор Башкы экраныңызга көтөрүлөт."</string>
<string name="hotseat_edu_message_migrate_alt" msgid="3042360119039646356">"Көп колдонулган колдонмолорго Башкы экрандан оңой кириңиз. Сунуштар тартиптин негизинде өзгөрөт. Ылдый жакта жайгашкан тилкедеги колдонмолор жаңы папкага жылдырылат."</string>
<string name="hotseat_edu_accept" msgid="1611544083278999837">"Сунушталган колдонолорду алуу"</string>
<string name="hotseat_edu_dismiss" msgid="2781161822780201689">"Жок, рахмат"</string>
<string name="hotseat_turn_off" msgid="7808360330229368470">"Жөндөөлөр"</string>
@@ -46,4 +46,5 @@
<string name="hotseat_prediction_content_description" msgid="4582028296938078419">"Божомолдонгон колдонмо: <xliff:g id="TITLE">%1$s</xliff:g>"</string>
<string name="action_share" msgid="2648470652637092375">"Бөлүшүү"</string>
<string name="action_screenshot" msgid="8171125848358142917">"Скриншот"</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"Бул аракетти аткарууга колдонмо же ишканаңыз тыюу салган"</string>
</resources>
+1
View File
@@ -46,4 +46,5 @@
<string name="hotseat_prediction_content_description" msgid="4582028296938078419">"ແອັບທີ່ຄາດເດົາໄວ້: <xliff:g id="TITLE">%1$s</xliff:g>"</string>
<string name="action_share" msgid="2648470652637092375">"ແບ່ງປັນ"</string>
<string name="action_screenshot" msgid="8171125848358142917">"ຮູບໜ້າຈໍ"</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"ແອັບ ຫຼື ອົງການຂອງທ່ານບໍ່ອະນຸຍາດໃຫ້ໃຊ້ຄຳສັ່ງນີ້"</string>
</resources>
+1
View File
@@ -46,4 +46,5 @@
<string name="hotseat_prediction_content_description" msgid="4582028296938078419">"Numatoma programa: <xliff:g id="TITLE">%1$s</xliff:g>"</string>
<string name="action_share" msgid="2648470652637092375">"Bendrinti"</string>
<string name="action_screenshot" msgid="8171125848358142917">"Ekrano kopija"</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"Jūsų organizacijoje arba naudojant šią programą neleidžiama atlikti šio veiksmo"</string>
</resources>
+1
View File
@@ -46,4 +46,5 @@
<string name="hotseat_prediction_content_description" msgid="4582028296938078419">"Prognozētā lietotne: <xliff:g id="TITLE">%1$s</xliff:g>"</string>
<string name="action_share" msgid="2648470652637092375">"Kopīgot"</string>
<string name="action_screenshot" msgid="8171125848358142917">"Izveidot ekrānuzņēmumu"</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"Lietotne vai jūsu organizācija neatļauj veikt šo darbību."</string>
</resources>
+1
View File
@@ -46,4 +46,5 @@
<string name="hotseat_prediction_content_description" msgid="4582028296938078419">"Предвидена апликација: <xliff:g id="TITLE">%1$s</xliff:g>"</string>
<string name="action_share" msgid="2648470652637092375">"Сподели"</string>
<string name="action_screenshot" msgid="8171125848358142917">"Слика од екранот"</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"Апликацијата или вашата организација не го дозволува дејствово"</string>
</resources>
+1
View File
@@ -46,4 +46,5 @@
<string name="hotseat_prediction_content_description" msgid="4582028296938078419">"പ്രവചിച്ച ആപ്പ്: <xliff:g id="TITLE">%1$s</xliff:g>"</string>
<string name="action_share" msgid="2648470652637092375">"പങ്കിടുക"</string>
<string name="action_screenshot" msgid="8171125848358142917">"സ്ക്രീൻഷോട്ട്"</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"ഈ നടപടി എടുക്കുന്നത് ആപ്പോ നിങ്ങളുടെ സ്ഥാപനമോ അനുവദിക്കുന്നില്ല"</string>
</resources>
+1
View File
@@ -46,4 +46,5 @@
<string name="hotseat_prediction_content_description" msgid="4582028296938078419">"Таамаглаж буй апп: <xliff:g id="TITLE">%1$s</xliff:g>"</string>
<string name="action_share" msgid="2648470652637092375">"Хуваалцах"</string>
<string name="action_screenshot" msgid="8171125848358142917">"Дэлгэцийн агшин дарах"</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"Энэ үйлдлийг апп эсвэл танай байгууллага зөвшөөрдөггүй"</string>
</resources>
+1
View File
@@ -46,4 +46,5 @@
<string name="hotseat_prediction_content_description" msgid="4582028296938078419">"पूर्वानुमान केलेले अ‍ॅप: <xliff:g id="TITLE">%1$s</xliff:g>"</string>
<string name="action_share" msgid="2648470652637092375">"शेअर करा"</string>
<string name="action_screenshot" msgid="8171125848358142917">"स्क्रीनशॉट"</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"अ‍ॅप किंवा तुमच्या संस्थेद्वारे ही क्रिया करण्याची अनुमती नाही"</string>
</resources>
+1
View File
@@ -46,4 +46,5 @@
<string name="hotseat_prediction_content_description" msgid="4582028296938078419">"Apl yang diramalkan: <xliff:g id="TITLE">%1$s</xliff:g>"</string>
<string name="action_share" msgid="2648470652637092375">"Kongsi"</string>
<string name="action_screenshot" msgid="8171125848358142917">"Tangkapan skrin"</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"Tindakan ini tidak dibenarkan oleh apl atau organisasi anda"</string>
</resources>
+2 -1
View File
@@ -33,7 +33,7 @@
<string name="all_apps_label" msgid="8542784161730910663">"အက်ပ်အားလုံး"</string>
<string name="all_apps_prediction_tip" msgid="2672336544844936186">"သင်၏ ခန့်မှန်းအက်ပ်များ"</string>
<string name="hotseat_edu_prompt_title" msgid="5595771595144175752">"အသုံးအများဆုံးအက်ပ်များကို အလွယ်တကူ သုံးခြင်း"</string>
<string name="hotseat_edu_prompt_content" msgid="5709176001504149521">"Pixel က သင်၏ \'ပင်မစာမျက်နှာ\' တွင် နောင်တွင်သင်လိုအပ်မည့် အက်ပ်များကို ကြိုတင်မှန်းဆပါသည်။ စနစ်ထည့်သွင်းရန် တို့ပါ။"</string>
<string name="hotseat_edu_prompt_content" msgid="5709176001504149521">"Pixel က သင်၏ \'ပင်မစာမျက်နှာ\' တွင် သင်လိုအပ်မည့် အက်ပ်များကို ကြိုတင်မှန်းဆပါသည်။ စနစ်ထည့်သွင်းရန် တို့ပါ။"</string>
<string name="hotseat_edu_title_migrate" msgid="306578144424489980">"သင်၏ \'ပင်မစာမျက်နှာ\' အောက်ခြေအတန်းတွင် အက်ပ်အကြံပြုချက်များ ရယူခြင်း"</string>
<string name="hotseat_edu_message_migrate" msgid="8927179260533775320">"အသုံးအများဆုံးအက်ပ်များကို \'ပင်မစာမျက်နှာ\' တွင် အလွယ်တကူ သုံးနိုင်သည်။ သင်၏ ပုံမှန်အစီအစဉ်များပေါ် အခြေခံ၍ အကြံပြုချက်များ ပြောင်းလဲပါမည်။ အောက်ခြေအတန်းရှိ အက်ပ်များကို သင်၏ \'ပင်မစာမျက်နှာ\' သို့ရွှေ့လိုက်မည်။"</string>
<string name="hotseat_edu_message_migrate_alt" msgid="3042360119039646356">"အသုံးအများဆုံးအက်ပ်များကို \'ပင်မစာမျက်နှာ\' တွင် အလွယ်တကူ သုံးနိုင်သည်။ သင်၏ ပုံမှန်အစီအစဉ်များပေါ် အခြေခံ၍ အကြံပြုချက်များ ပြောင်းလဲပါမည်။ အောက်ခြေအတန်းရှိ အက်ပ်များကို ဖိုင်တွဲအသစ်သို့ ရွှေ့လိုက်မည်။"</string>
@@ -46,4 +46,5 @@
<string name="hotseat_prediction_content_description" msgid="4582028296938078419">"ကြိုတင်မှန်းဆထားသော အက်ပ်− <xliff:g id="TITLE">%1$s</xliff:g>"</string>
<string name="action_share" msgid="2648470652637092375">"မျှဝေရန်"</string>
<string name="action_screenshot" msgid="8171125848358142917">"ဖန်သားပြင်ဓာတ်ပုံ"</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"ဤလုပ်ဆောင်ချက်ကို အက်ပ် သို့မဟုတ် သင်၏အဖွဲ့အစည်းက ခွင့်မပြုပါ"</string>
</resources>
+1
View File
@@ -46,4 +46,5 @@
<string name="hotseat_prediction_content_description" msgid="4582028296938078419">"Foreslått app: <xliff:g id="TITLE">%1$s</xliff:g>"</string>
<string name="action_share" msgid="2648470652637092375">"Del"</string>
<string name="action_screenshot" msgid="8171125848358142917">"Skjermdump"</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"Appen eller organisasjonen din tillater ikke denne handlingen"</string>
</resources>
+2 -1
View File
@@ -23,7 +23,7 @@
<string name="recent_task_option_pin" msgid="7929860679018978258">"पिन गर्नुहोस्"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"फ्रिफर्म"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"हालसालैको कुनै पनि वस्तु छैन"</string>
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"अनुप्रयोगको उपयोगका सेटिङहरू"</string>
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"एपको उपयोगका सेटिङहरू"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"सबै खाली गर्नुहोस्"</string>
<string name="accessibility_recent_apps" msgid="4058661986695117371">"हालसालैका एपहरू"</string>
<string name="task_contents_description_with_remaining_time" msgid="4479688746574672685">"<xliff:g id="TASK_DESCRIPTION">%1$s</xliff:g>, <xliff:g id="REMAINING_TIME">%2$s</xliff:g>"</string>
@@ -46,4 +46,5 @@
<string name="hotseat_prediction_content_description" msgid="4582028296938078419">"पूर्वानुमान गरिएको एप: <xliff:g id="TITLE">%1$s</xliff:g>"</string>
<string name="action_share" msgid="2648470652637092375">"सेयर गर्नुहोस्"</string>
<string name="action_screenshot" msgid="8171125848358142917">"स्क्रिनसट"</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"यो एप वा तपाईंको सङ्गठनले यो कारबाही गर्ने अनुमति दिँदैन"</string>
</resources>
+1
View File
@@ -46,4 +46,5 @@
<string name="hotseat_prediction_content_description" msgid="4582028296938078419">"Voorspelde app: <xliff:g id="TITLE">%1$s</xliff:g>"</string>
<string name="action_share" msgid="2648470652637092375">"Delen"</string>
<string name="action_screenshot" msgid="8171125848358142917">"Screenshot"</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"Deze actie wordt niet toegestaan door de app of je organisatie"</string>
</resources>
+1
View File
@@ -46,4 +46,5 @@
<string name="hotseat_prediction_content_description" msgid="4582028296938078419">"ପୂର୍ବାନୁମାନ କରାଯାଇଥିବା ଆପ୍: <xliff:g id="TITLE">%1$s</xliff:g>"</string>
<string name="action_share" msgid="2648470652637092375">"ସେୟାର୍ କରନ୍ତୁ"</string>
<string name="action_screenshot" msgid="8171125848358142917">"ସ୍କ୍ରିନସଟ୍"</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"ଆପ୍ କିମ୍ବା ଆପଣଙ୍କ ସଂସ୍ଥା ଦ୍ୱାରା ଏହି କାର୍ଯ୍ୟକୁ ଅନୁମତି ଦିଆଯାଇ ନାହିଁ"</string>
</resources>
+1
View File
@@ -46,4 +46,5 @@
<string name="hotseat_prediction_content_description" msgid="4582028296938078419">"ਪੂਰਵ ਅਨੁਮਾਨਿਤ ਐਪ: <xliff:g id="TITLE">%1$s</xliff:g>"</string>
<string name="action_share" msgid="2648470652637092375">"ਸਾਂਝਾ ਕਰੋ"</string>
<string name="action_screenshot" msgid="8171125848358142917">"ਸਕ੍ਰੀਨਸ਼ਾਟ"</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"ਐਪ ਜਾਂ ਤੁਹਾਡੀ ਸੰਸਥਾ ਵੱਲੋਂ ਇਸ ਕਾਰਵਾਈ ਦੀ ਇਜਾਜ਼ਤ ਨਹੀਂ ਹੈ"</string>
</resources>
+2 -1
View File
@@ -32,7 +32,7 @@
<string name="title_app_suggestions" msgid="4185902664111965088">"Sugestie aplikacji"</string>
<string name="all_apps_label" msgid="8542784161730910663">"Wszystkie aplikacje"</string>
<string name="all_apps_prediction_tip" msgid="2672336544844936186">"Przewidywane aplikacje"</string>
<string name="hotseat_edu_prompt_title" msgid="5595771595144175752">"Korzystaj z najczęściej używanych przez siebie aplikacji w łatwy sposób"</string>
<string name="hotseat_edu_prompt_title" msgid="5595771595144175752">"Łatwy dostęp do najczęstszych aplikacji"</string>
<string name="hotseat_edu_prompt_content" msgid="5709176001504149521">"Pixel przewiduje, których aplikacji będziesz potrzebować w następnej kolejności, bezpośrednio na ekranie głównym. Kliknij, by skonfigurować."</string>
<string name="hotseat_edu_title_migrate" msgid="306578144424489980">"Otrzymuj sugestie aplikacji w dolnym wierszu ekranu głównego"</string>
<string name="hotseat_edu_message_migrate" msgid="8927179260533775320">"Korzystaj z najczęściej używanych aplikacji na ekranie głównym w łatwy sposób. Sugestie będą się zmieniać na podstawie Twojej rutyny. Aplikacje z dolnych wierszy będą się przenosić w górę do ekranu głównego."</string>
@@ -46,4 +46,5 @@
<string name="hotseat_prediction_content_description" msgid="4582028296938078419">"Przewidywana aplikacja: <xliff:g id="TITLE">%1$s</xliff:g>"</string>
<string name="action_share" msgid="2648470652637092375">"Udostępnij"</string>
<string name="action_screenshot" msgid="8171125848358142917">"Zrzut ekranu"</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"Nie możesz wykonać tego działania, bo nie zezwala na to aplikacja lub Twoja organizacja"</string>
</resources>
+1
View File
@@ -46,4 +46,5 @@
<string name="hotseat_prediction_content_description" msgid="4582028296938078419">"App prevista: <xliff:g id="TITLE">%1$s</xliff:g>"</string>
<string name="action_share" msgid="2648470652637092375">"Partilhar"</string>
<string name="action_screenshot" msgid="8171125848358142917">"Tirar captura de ecrã"</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"Esta ação não é permitida pela app ou a sua entidade."</string>
</resources>
+1
View File
@@ -46,4 +46,5 @@
<string name="hotseat_prediction_content_description" msgid="4582028296938078419">"App previsto: <xliff:g id="TITLE">%1$s</xliff:g>"</string>
<string name="action_share" msgid="2648470652637092375">"Compartilhar"</string>
<string name="action_screenshot" msgid="8171125848358142917">"Capturar tela"</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"Essa ação não é permitida pelo app ou pela organização"</string>
</resources>
+1
View File
@@ -46,4 +46,5 @@
<string name="hotseat_prediction_content_description" msgid="4582028296938078419">"Aplicația estimată: <xliff:g id="TITLE">%1$s</xliff:g>"</string>
<string name="action_share" msgid="2648470652637092375">"Distribuiți"</string>
<string name="action_screenshot" msgid="8171125848358142917">"Captură de ecran"</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"Această acțiune nu este permisă de aplicație sau de organizația dvs."</string>
</resources>
+1
View File
@@ -46,4 +46,5 @@
<string name="hotseat_prediction_content_description" msgid="4582028296938078419">"Рекомендуемое приложение: <xliff:g id="TITLE">%1$s</xliff:g>"</string>
<string name="action_share" msgid="2648470652637092375">"Поделиться"</string>
<string name="action_screenshot" msgid="8171125848358142917">"Скриншот"</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"Это действие заблокировано приложением или организацией."</string>
</resources>
+1
View File
@@ -46,4 +46,5 @@
<string name="hotseat_prediction_content_description" msgid="4582028296938078419">"පුරෝකථනය කළ යෙදුම: <xliff:g id="TITLE">%1$s</xliff:g>"</string>
<string name="action_share" msgid="2648470652637092375">"බෙදා ගන්න"</string>
<string name="action_screenshot" msgid="8171125848358142917">"තිර රුව"</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"මෙම ක්‍රියාව යෙදුම හෝ ඔබේ සංවිධානය මගින් ඉඩ නොදේ"</string>
</resources>
+1
View File
@@ -46,4 +46,5 @@
<string name="hotseat_prediction_content_description" msgid="4582028296938078419">"Predpovedaná aplikácia: <xliff:g id="TITLE">%1$s</xliff:g>"</string>
<string name="action_share" msgid="2648470652637092375">"Zdieľať"</string>
<string name="action_screenshot" msgid="8171125848358142917">"Snímka obrazovky"</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"Aplikácia alebo vaša organizácia túto akciu nepovoľuje"</string>
</resources>
+1
View File
@@ -46,4 +46,5 @@
<string name="hotseat_prediction_content_description" msgid="4582028296938078419">"Predvidena aplikacija: <xliff:g id="TITLE">%1$s</xliff:g>"</string>
<string name="action_share" msgid="2648470652637092375">"Deli"</string>
<string name="action_screenshot" msgid="8171125848358142917">"Posnetek zaslona"</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"Aplikacija ali vaša organizacija ne dovoljuje tega dejanja"</string>
</resources>

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