Merging ub-launcher3-qt-r1-dev, build 5736932

Test: Manual

Bug:111935715 P2 Incorrect parent type when logging drag and drop from All Apps
Bug:131315856 P1 [PO restore] No work profile launcher shortcuts restore ~50% of the time
Bug:132900132 P1 Apparently, tests start running while provisioning is still in progress
Bug:133009122 P2 Rare flake: dragged launchable to workspace, but the current state is not WORKSPACE; Can't find a launcher object; selector: BySelector [RES='\Qcom.google.android.apps.nexuslauncher:id/apps_view\E']
Bug:133765434 P1 [Flaky test] Launching task didn't open a new window
Bug:133867119 P2 Lab-only flake: want to switch from workspace to all apps; Swipe failed to receive an event for the swipe end
Bug:133891845 P2 TAPL: need clearer diags when a crash dialog is over Launcher or there is lock screeen
Bug:134532571 P1 Launcher flake: java.lang.AssertionError: http://go/tapl : want to switch from background to overview, but the current state is not BASE_OVERVIEW; Can't find a launcher object; selector: BySelector [RES='\Qcom.google.android.apps.nexuslauncher:id/overview_panel\E']
Bug:135165284 P2 [Q-Preview4] Gestural navigation animation glitch on RTL
Bug:135567630 P1 testBackground crashes in Landscape
Bug:135636137 P1 Workspace is clipped at the top when transitioning from app -> home
Bug:135687618 P4 Task shows between back and swiping up to overview
Bug:135952890 P1 Drag up on home indicator does not track finger if recently entered split screen
Bug:136033787 P0 Vzw DoU: sendexchangeemail wifi test fails with failed dismissal exception
Bug:136215685 P1 Flake: swiping up from Home to Overview in 2-button mode sometimes fails
Bug:137197916 P1 Add gesture support for 3p Launcher
Bug:137215697 P2 FloatingIcon and workspace icon visible at the same time when touch input during app to close animation
Bug:137290162 P1 Overview suggest chip showing on apps due to misconfigured flag
Bug:137316430 P1 Jank when swiping quickly back down to home when overview is peeking
Bug:64712476 P3 Import translations for dev branches
Change-Id: Ib228c0f291884050904fa069e25519755071c40a
This commit is contained in:
Winson Chung
2019-07-18 11:36:39 -07:00
74 changed files with 1655 additions and 1168 deletions
@@ -34,6 +34,8 @@ import android.view.MotionEvent;
import com.android.launcher3.Utilities;
import com.android.launcher3.compat.UserManagerCompat;
import com.android.launcher3.util.LooperExecutor;
import com.android.launcher3.util.UiThreadHelper;
import com.android.systemui.shared.recents.IOverviewProxy;
import com.android.systemui.shared.recents.ISystemUiProxy;
@@ -137,6 +139,9 @@ public class TouchInteractionService extends Service {
return sConnected;
}
public static final LooperExecutor BACKGROUND_EXECUTOR =
new LooperExecutor(UiThreadHelper.getBackgroundLooper());
private RecentsModel mRecentsModel;
private OverviewComponentObserver mOverviewComponentObserver;
private OverviewCommandHelper mOverviewCommandHelper;
@@ -180,4 +185,8 @@ public class TouchInteractionService extends Service {
}
return mMyBinder;
}
public static boolean isInputMonitorInitialized() {
return true;
}
}
+1
View File
@@ -23,6 +23,7 @@
package="com.android.launcher3" >
<uses-permission android:name="android.permission.CONTROL_REMOTE_APP_TRANSITION_ANIMATIONS" />
<uses-permission android:name="android.permission.VIBRATE" />
<application
android:backupAgent="com.android.launcher3.LauncherBackupAgent"
@@ -167,6 +167,21 @@ public class FlingAndHoldTouchController extends PortraitStatesTouchController {
mMotionPauseDetector.clear();
}
@Override
protected void goToTargetState(LauncherState targetState, int logAction) {
if (mPeekAnim != null && mPeekAnim.isStarted()) {
// Don't jump to the target state until overview is no longer peeking.
mPeekAnim.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
FlingAndHoldTouchController.super.goToTargetState(targetState, logAction);
}
});
} else {
super.goToTargetState(targetState, logAction);
}
}
@Override
protected void updateAnimatorBuilderOnReinit(AnimatorSetBuilder builder) {
if (handlingOverviewAnim()) {
@@ -0,0 +1,496 @@
/*
* Copyright (C) 2019 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.quickstep;
import static android.os.VibrationEffect.EFFECT_CLICK;
import static android.os.VibrationEffect.createPredefined;
import static com.android.launcher3.Utilities.postAsyncCallback;
import static com.android.launcher3.anim.Interpolators.ACCEL_1_5;
import static com.android.launcher3.anim.Interpolators.DEACCEL;
import static com.android.launcher3.config.FeatureFlags.ENABLE_QUICKSTEP_LIVE_TILE;
import static com.android.launcher3.views.FloatingIconView.SHAPE_PROGRESS_DURATION;
import static com.android.quickstep.TouchInteractionService.BACKGROUND_EXECUTOR;
import static com.android.quickstep.TouchInteractionService.MAIN_THREAD_EXECUTOR;
import static com.android.quickstep.TouchInteractionService.TOUCH_INTERACTION_LOG;
import android.animation.Animator;
import android.annotation.TargetApi;
import android.app.ActivityManager.RunningTaskInfo;
import android.content.Context;
import android.content.Intent;
import android.graphics.Point;
import android.graphics.PointF;
import android.graphics.Rect;
import android.graphics.RectF;
import android.os.Build;
import android.os.Handler;
import android.os.Looper;
import android.os.VibrationEffect;
import android.os.Vibrator;
import android.provider.Settings;
import android.view.MotionEvent;
import android.view.View;
import android.view.WindowManager;
import android.view.animation.Interpolator;
import com.android.launcher3.BaseDraggingActivity;
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.InvariantDeviceProfile;
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
import com.android.launcher3.anim.AnimationSuccessListener;
import com.android.launcher3.anim.AnimatorPlaybackController;
import com.android.launcher3.anim.Interpolators;
import com.android.launcher3.graphics.RotationMode;
import com.android.launcher3.views.FloatingIconView;
import com.android.quickstep.ActivityControlHelper.ActivityInitListener;
import com.android.quickstep.ActivityControlHelper.HomeAnimationFactory;
import com.android.quickstep.SysUINavigationMode.Mode;
import com.android.quickstep.inputconsumers.InputConsumer;
import com.android.quickstep.util.ClipAnimationHelper;
import com.android.quickstep.util.ClipAnimationHelper.TransformParams;
import com.android.quickstep.util.RectFSpringAnim;
import com.android.quickstep.util.RemoteAnimationTargetSet;
import com.android.quickstep.util.SwipeAnimationTargetSet;
import com.android.quickstep.util.SwipeAnimationTargetSet.SwipeAnimationListener;
import com.android.quickstep.views.RecentsView;
import com.android.quickstep.views.TaskView;
import com.android.systemui.shared.system.InputConsumerController;
import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
import com.android.systemui.shared.system.SyncRtSurfaceTransactionApplierCompat;
import java.util.function.Consumer;
import androidx.annotation.UiThread;
/**
* Base class for swipe up handler with some utility methods
*/
@TargetApi(Build.VERSION_CODES.Q)
public abstract class BaseSwipeUpHandler<T extends BaseDraggingActivity, Q extends RecentsView>
implements SwipeAnimationListener {
private static final String TAG = "BaseSwipeUpHandler";
protected static final Rect TEMP_RECT = new Rect();
// Start resisting when swiping past this factor of mTransitionDragLength.
private static final float DRAG_LENGTH_FACTOR_START_PULLBACK = 1.4f;
// This is how far down we can scale down, where 0f is full screen and 1f is recents.
private static final float DRAG_LENGTH_FACTOR_MAX_PULLBACK = 1.8f;
private static final Interpolator PULLBACK_INTERPOLATOR = DEACCEL;
// The distance needed to drag to reach the task size in recents.
protected int mTransitionDragLength;
// How much further we can drag past recents, as a factor of mTransitionDragLength.
protected float mDragLengthFactor = 1;
protected final Context mContext;
protected final OverviewComponentObserver mOverviewComponentObserver;
protected final ActivityControlHelper<T> mActivityControlHelper;
protected final RecentsModel mRecentsModel;
protected final int mRunningTaskId;
protected final ClipAnimationHelper mClipAnimationHelper;
protected final TransformParams mTransformParams = new TransformParams();
private final Vibrator mVibrator;
protected final Mode mMode;
// Shift in the range of [0, 1].
// 0 => preview snapShot is completely visible, and hotseat is completely translated down
// 1 => preview snapShot is completely aligned with the recents view and hotseat is completely
// visible.
protected final AnimatedFloat mCurrentShift = new AnimatedFloat(this::updateFinalShift);
protected final ActivityInitListener mActivityInitListener;
protected final RecentsAnimationWrapper mRecentsAnimationWrapper;
protected T mActivity;
protected Q mRecentsView;
protected DeviceProfile mDp;
private final int mPageSpacing;
protected Runnable mGestureEndCallback;
protected final Handler mMainThreadHandler = MAIN_THREAD_EXECUTOR.getHandler();
protected MultiStateCallback mStateCallback;
protected boolean mCanceled;
protected int mFinishingRecentsAnimationForNewTaskId = -1;
protected BaseSwipeUpHandler(Context context,
OverviewComponentObserver overviewComponentObserver,
RecentsModel recentsModel, InputConsumerController inputConsumer, int runningTaskId) {
mContext = context;
mOverviewComponentObserver = overviewComponentObserver;
mActivityControlHelper = overviewComponentObserver.getActivityControlHelper();
mRecentsModel = recentsModel;
mActivityInitListener =
mActivityControlHelper.createActivityInitListener(this::onActivityInit);
mRunningTaskId = runningTaskId;
mRecentsAnimationWrapper = new RecentsAnimationWrapper(inputConsumer,
this::createNewInputProxyHandler);
mMode = SysUINavigationMode.getMode(context);
mClipAnimationHelper = new ClipAnimationHelper(context);
mPageSpacing = context.getResources().getDimensionPixelSize(R.dimen.recents_page_spacing);
mVibrator = context.getSystemService(Vibrator.class);
initTransitionEndpoints(InvariantDeviceProfile.INSTANCE.get(mContext)
.getDeviceProfile(mContext));
}
protected void setStateOnUiThread(int stateFlag) {
if (Looper.myLooper() == mMainThreadHandler.getLooper()) {
mStateCallback.setState(stateFlag);
} else {
postAsyncCallback(mMainThreadHandler, () -> mStateCallback.setState(stateFlag));
}
}
protected void performHapticFeedback() {
if (!mVibrator.hasVibrator()) {
return;
}
if (Settings.System.getInt(
mContext.getContentResolver(), Settings.System.HAPTIC_FEEDBACK_ENABLED, 0) == 0) {
return;
}
VibrationEffect effect = createPredefined(EFFECT_CLICK);
if (effect == null) {
return;
}
BACKGROUND_EXECUTOR.execute(() -> mVibrator.vibrate(effect));
}
public Consumer<MotionEvent> getRecentsViewDispatcher(RotationMode rotationMode) {
return mRecentsView != null ? mRecentsView.getEventDispatcher(rotationMode) : null;
}
@UiThread
public void updateDisplacement(float displacement) {
// We are moving in the negative x/y direction
displacement = -displacement;
float shift;
if (displacement > mTransitionDragLength * mDragLengthFactor && mTransitionDragLength > 0) {
shift = mDragLengthFactor;
} else {
float translation = Math.max(displacement, 0);
shift = mTransitionDragLength == 0 ? 0 : translation / mTransitionDragLength;
if (shift > DRAG_LENGTH_FACTOR_START_PULLBACK) {
float pullbackProgress = Utilities.getProgress(shift,
DRAG_LENGTH_FACTOR_START_PULLBACK, mDragLengthFactor);
pullbackProgress = PULLBACK_INTERPOLATOR.getInterpolation(pullbackProgress);
shift = DRAG_LENGTH_FACTOR_START_PULLBACK + pullbackProgress
* (DRAG_LENGTH_FACTOR_MAX_PULLBACK - DRAG_LENGTH_FACTOR_START_PULLBACK);
}
}
mCurrentShift.updateValue(shift);
}
public void setGestureEndCallback(Runnable gestureEndCallback) {
mGestureEndCallback = gestureEndCallback;
}
public abstract Intent getLaunchIntent();
protected void linkRecentsViewScroll() {
SyncRtSurfaceTransactionApplierCompat.create(mRecentsView, applier -> {
mTransformParams.setSyncTransactionApplier(applier);
mRecentsAnimationWrapper.runOnInit(() ->
mRecentsAnimationWrapper.targetSet.addDependentTransactionApplier(applier));
});
mRecentsView.setOnScrollChangeListener((v, scrollX, scrollY, oldScrollX, oldScrollY) -> {
if (moveWindowWithRecentsScroll()) {
updateFinalShift();
}
});
mRecentsView.setRecentsAnimationWrapper(mRecentsAnimationWrapper);
mRecentsView.setClipAnimationHelper(mClipAnimationHelper);
}
protected void startNewTask(int successStateFlag, Consumer<Boolean> resultCallback) {
// Launch the task user scrolled to (mRecentsView.getNextPage()).
if (ENABLE_QUICKSTEP_LIVE_TILE.get()) {
// We finish recents animation inside launchTask() when live tile is enabled.
mRecentsView.getTaskViewAt(mRecentsView.getNextPage()).launchTask(false /* animate */,
true /* freezeTaskList */);
} else {
int taskId = mRecentsView.getTaskViewAt(mRecentsView.getNextPage()).getTask().key.id;
mFinishingRecentsAnimationForNewTaskId = taskId;
mRecentsAnimationWrapper.finish(true /* toRecents */, () -> {
if (!mCanceled) {
TaskView nextTask = mRecentsView.getTaskView(taskId);
if (nextTask != null) {
nextTask.launchTask(false /* animate */, true /* freezeTaskList */,
success -> {
resultCallback.accept(success);
if (!success) {
mActivityControlHelper.onLaunchTaskFailed(mActivity);
nextTask.notifyTaskLaunchFailed(TAG);
} else {
mActivityControlHelper.onLaunchTaskSuccess(mActivity);
}
}, mMainThreadHandler);
}
setStateOnUiThread(successStateFlag);
}
mCanceled = false;
mFinishingRecentsAnimationForNewTaskId = -1;
});
}
TOUCH_INTERACTION_LOG.addLog("finishRecentsAnimation", true);
}
@Override
public void onRecentsAnimationStart(SwipeAnimationTargetSet targetSet) {
DeviceProfile dp = InvariantDeviceProfile.INSTANCE.get(mContext).getDeviceProfile(mContext);
final Rect overviewStackBounds;
RemoteAnimationTargetCompat runningTaskTarget = targetSet.findTask(mRunningTaskId);
if (targetSet.minimizedHomeBounds != null && runningTaskTarget != null) {
overviewStackBounds = mActivityControlHelper
.getOverviewWindowBounds(targetSet.minimizedHomeBounds, runningTaskTarget);
dp = dp.getMultiWindowProfile(mContext, new Point(
overviewStackBounds.width(), overviewStackBounds.height()));
} else {
// If we are not in multi-window mode, home insets should be same as system insets.
dp = dp.copy(mContext);
overviewStackBounds = getStackBounds(dp);
}
dp.updateInsets(targetSet.homeContentInsets);
dp.updateIsSeascape(mContext.getSystemService(WindowManager.class));
if (runningTaskTarget != null) {
mClipAnimationHelper.updateSource(overviewStackBounds, runningTaskTarget);
}
mClipAnimationHelper.prepareAnimation(dp, false /* isOpening */);
initTransitionEndpoints(dp);
mRecentsAnimationWrapper.setController(targetSet);
}
private Rect getStackBounds(DeviceProfile dp) {
if (mActivity != null) {
int loc[] = new int[2];
View rootView = mActivity.getRootView();
rootView.getLocationOnScreen(loc);
return new Rect(loc[0], loc[1], loc[0] + rootView.getWidth(),
loc[1] + rootView.getHeight());
} else {
return new Rect(0, 0, dp.widthPx, dp.heightPx);
}
}
protected void initTransitionEndpoints(DeviceProfile dp) {
mDp = dp;
mTransitionDragLength = mActivityControlHelper.getSwipeUpDestinationAndLength(
dp, mContext, TEMP_RECT);
if (!dp.isMultiWindowMode) {
// When updating the target rect, also update the home bounds since the location on
// screen of the launcher window may be stale (position is not updated until first
// traversal after the window is resized). We only do this for non-multiwindow because
// we otherwise use the minimized home bounds provided by the system.
mClipAnimationHelper.updateHomeBounds(getStackBounds(dp));
}
mClipAnimationHelper.updateTargetRect(TEMP_RECT);
if (mMode == Mode.NO_BUTTON) {
// We can drag all the way to the top of the screen.
mDragLengthFactor = (float) dp.heightPx / mTransitionDragLength;
}
}
/**
* Return true if the window should be translated horizontally if the recents view scrolls
*/
protected abstract boolean moveWindowWithRecentsScroll();
protected abstract boolean onActivityInit(final T activity, Boolean alreadyOnHome);
/**
* Called to create a input proxy for the running task
*/
@UiThread
protected abstract InputConsumer createNewInputProxyHandler();
/**
* Called when the value of {@link #mCurrentShift} changes
*/
@UiThread
public abstract void updateFinalShift();
/**
* Called when motion pause is detected
*/
public abstract void onMotionPauseChanged(boolean isPaused);
@UiThread
public void onGestureStarted() { }
@UiThread
public abstract void onGestureCancelled();
@UiThread
public abstract void onGestureEnded(float endVelocity, PointF velocity, PointF downPos);
public abstract void onConsumerAboutToBeSwitched(SwipeSharedState sharedState);
public void setIsLikelyToStartNewTask(boolean isLikelyToStartNewTask) { }
public void initWhenReady() {
// Preload the plan
mRecentsModel.getTasks(null);
mActivityInitListener.register();
}
/**
* Applies the transform on the recents animation without any additional null checks
*/
protected void applyTransformUnchecked() {
float shift = mCurrentShift.value;
float offsetX = mRecentsView == null ? 0 : mRecentsView.getScrollOffset();
float offsetScale = getTaskCurveScaleForOffsetX(offsetX,
mClipAnimationHelper.getTargetRect().width());
mTransformParams.setProgress(shift).setOffsetX(offsetX).setOffsetScale(offsetScale);
mClipAnimationHelper.applyTransform(mRecentsAnimationWrapper.targetSet,
mTransformParams);
}
private float getTaskCurveScaleForOffsetX(float offsetX, float taskWidth) {
float distanceToReachEdge = mDp.widthPx / 2 + taskWidth / 2 + mPageSpacing;
float interpolation = Math.min(1, offsetX / distanceToReachEdge);
return TaskView.getCurveScaleForInterpolation(interpolation);
}
/**
* Creates an animation that transforms the current app window into the home app.
* @param startProgress The progress of {@link #mCurrentShift} to start the window from.
* @param homeAnimationFactory The home animation factory.
*/
protected RectFSpringAnim createWindowAnimationToHome(float startProgress,
HomeAnimationFactory homeAnimationFactory) {
final RemoteAnimationTargetSet targetSet = mRecentsAnimationWrapper.targetSet;
final RectF startRect = new RectF(mClipAnimationHelper.applyTransform(targetSet,
mTransformParams.setProgress(startProgress), false /* launcherOnTop */));
final RectF targetRect = homeAnimationFactory.getWindowTargetRect();
final View floatingView = homeAnimationFactory.getFloatingView();
final boolean isFloatingIconView = floatingView instanceof FloatingIconView;
RectFSpringAnim anim = new RectFSpringAnim(startRect, targetRect, mContext.getResources());
if (isFloatingIconView) {
FloatingIconView fiv = (FloatingIconView) floatingView;
anim.addAnimatorListener(fiv);
fiv.setOnTargetChangeListener(anim::onTargetPositionChanged);
}
AnimatorPlaybackController homeAnim = homeAnimationFactory.createActivityAnimationToHome();
// End on a "round-enough" radius so that the shape reveal doesn't have to do too much
// rounding at the end of the animation.
float startRadius = mClipAnimationHelper.getCurrentCornerRadius();
float endRadius = startRect.width() / 6f;
// We want the window alpha to be 0 once this threshold is met, so that the
// FolderIconView can be seen morphing into the icon shape.
final float windowAlphaThreshold = isFloatingIconView ? 1f - SHAPE_PROGRESS_DURATION : 1f;
anim.addOnUpdateListener(new RectFSpringAnim.OnUpdateListener() {
@Override
public void onUpdate(RectF currentRect, float progress) {
homeAnim.setPlayFraction(progress);
float alphaProgress = ACCEL_1_5.getInterpolation(progress);
float windowAlpha = Utilities.boundToRange(Utilities.mapToRange(alphaProgress, 0,
windowAlphaThreshold, 1.5f, 0f, Interpolators.LINEAR), 0, 1);
mTransformParams.setProgress(progress)
.setCurrentRectAndTargetAlpha(currentRect, windowAlpha);
if (isFloatingIconView) {
mTransformParams.setCornerRadius(endRadius * progress + startRadius
* (1f - progress));
}
mClipAnimationHelper.applyTransform(targetSet, mTransformParams,
false /* launcherOnTop */);
if (isFloatingIconView) {
((FloatingIconView) floatingView).update(currentRect, 1f, progress,
windowAlphaThreshold, mClipAnimationHelper.getCurrentCornerRadius(), false);
}
}
@Override
public void onCancel() {
if (isFloatingIconView) {
((FloatingIconView) floatingView).fastFinish();
}
}
});
anim.addAnimatorListener(new AnimationSuccessListener() {
@Override
public void onAnimationStart(Animator animation) {
homeAnim.dispatchOnStart();
}
@Override
public void onAnimationSuccess(Animator animator) {
homeAnim.getAnimationPlayer().end();
}
});
return anim;
}
public interface Factory {
BaseSwipeUpHandler newHandler(RunningTaskInfo runningTask,
long touchTimeMs, boolean continuingLastGesture, boolean isLikelyToStartNewTask);
}
protected interface RunningWindowAnim {
void end();
void cancel();
static RunningWindowAnim wrap(Animator animator) {
return new RunningWindowAnim() {
@Override
public void end() {
animator.end();
}
@Override
public void cancel() {
animator.cancel();
}
};
}
static RunningWindowAnim wrap(RectFSpringAnim rectFSpringAnim) {
return new RunningWindowAnim() {
@Override
public void end() {
rectFSpringAnim.end();
}
@Override
public void cancel() {
rectFSpringAnim.cancel();
}
};
}
}
}
@@ -151,16 +151,10 @@ public final class LauncherActivityControllerHelper implements ActivityControlHe
@NonNull
@Override
public RectF getWindowTargetRect() {
final int halfIconSize = dp.iconSizePx / 2;
final float targetCenterX = dp.availableWidthPx / 2f;
final float targetCenterY = dp.availableHeightPx - dp.hotseatBarSizePx;
if (canUseWorkspaceView) {
return iconLocation;
} else {
// Fallback to animate to center of screen.
return new RectF(targetCenterX - halfIconSize, targetCenterY - halfIconSize,
targetCenterX + halfIconSize, targetCenterY + halfIconSize);
return HomeAnimationFactory.getDefaultWindowTargetRect(dp);
}
}
@@ -194,9 +188,6 @@ public final class LauncherActivityControllerHelper implements ActivityControlHe
@Override
public AnimationFactory prepareRecentsUI(Launcher activity, boolean activityVisible,
boolean animateActivity, Consumer<AnimatorPlaybackController> callback) {
if (TestProtocol.sDebugTracing) {
Log.d(TestProtocol.NO_OVERVIEW_EVENT_TAG, "prepareRecentsUI");
}
final LauncherState startState = activity.getStateManager().getState();
LauncherState resetState = startState;
@@ -0,0 +1,83 @@
package com.android.quickstep;
import android.content.Context;
import android.os.Bundle;
import com.android.launcher3.MainThreadExecutor;
import com.android.launcher3.testing.TestInformationHandler;
import com.android.launcher3.testing.TestProtocol;
import com.android.launcher3.uioverrides.states.OverviewState;
import com.android.launcher3.uioverrides.touchcontrollers.PortraitStatesTouchController;
import com.android.quickstep.util.LayoutUtils;
import com.android.quickstep.views.RecentsView;
import java.util.concurrent.ExecutionException;
public class QuickstepTestInformationHandler extends TestInformationHandler {
public QuickstepTestInformationHandler(Context context) {
}
@Override
public Bundle call(String method) {
final Bundle response = new Bundle();
switch (method) {
case TestProtocol.REQUEST_HOME_TO_OVERVIEW_SWIPE_HEIGHT: {
final float swipeHeight =
OverviewState.getDefaultSwipeHeight(mDeviceProfile);
response.putInt(TestProtocol.TEST_INFO_RESPONSE_FIELD, (int) swipeHeight);
return response;
}
case TestProtocol.REQUEST_BACKGROUND_TO_OVERVIEW_SWIPE_HEIGHT: {
final float swipeHeight =
LayoutUtils.getShelfTrackingDistance(mContext, mDeviceProfile);
response.putInt(TestProtocol.TEST_INFO_RESPONSE_FIELD, (int) swipeHeight);
return response;
}
case TestProtocol.REQUEST_IS_LAUNCHER_INITIALIZED: {
response.putBoolean(TestProtocol.TEST_INFO_RESPONSE_FIELD,
TouchInteractionService.isInputMonitorInitialized());
return response;
}
case TestProtocol.REQUEST_HOTSEAT_TOP: {
if (mLauncher == null) return null;
response.putInt(TestProtocol.TEST_INFO_RESPONSE_FIELD,
PortraitStatesTouchController.getHotseatTop(mLauncher));
return response;
}
case TestProtocol.REQUEST_OVERVIEW_LEFT_GESTURE_MARGIN: {
try {
final int leftMargin = new MainThreadExecutor().submit(() ->
mLauncher.<RecentsView>getOverviewPanel().getLeftGestureMargin()).get();
response.putInt(TestProtocol.TEST_INFO_RESPONSE_FIELD, leftMargin);
} catch (ExecutionException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
return response;
}
case TestProtocol.REQUEST_OVERVIEW_RIGHT_GESTURE_MARGIN: {
try {
final int rightMargin = new MainThreadExecutor().submit(() ->
mLauncher.<RecentsView>getOverviewPanel().getRightGestureMargin()).
get();
response.putInt(TestProtocol.TEST_INFO_RESPONSE_FIELD, rightMargin);
} catch (ExecutionException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
return response;
}
}
return super.call(method);
}
}
@@ -28,8 +28,10 @@ import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
import android.app.ActivityOptions;
import android.content.Intent;
import android.content.res.Configuration;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
import android.view.View;
@@ -42,7 +44,9 @@ import com.android.launcher3.views.BaseDragLayer;
import com.android.quickstep.fallback.FallbackRecentsView;
import com.android.quickstep.fallback.RecentsRootView;
import com.android.quickstep.util.ClipAnimationHelper;
import com.android.quickstep.util.ObjectWrapper;
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;
@@ -54,6 +58,9 @@ import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
*/
public final class RecentsActivity extends BaseRecentsActivity {
public static final String EXTRA_THUMBNAIL = "thumbnailData";
public static final String EXTRA_TASK_ID = "taskID";
private Handler mUiHandler = new Handler(Looper.getMainLooper());
private RecentsRootView mRecentsRootView;
private FallbackRecentsView mFallbackRecentsView;
@@ -78,6 +85,22 @@ public final class RecentsActivity extends BaseRecentsActivity {
}
}
@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) {
ThumbnailData thumbnailData = ((ObjectWrapper<ThumbnailData>) thumbnail).get();
mFallbackRecentsView.showCurrentTask(taskID);
mFallbackRecentsView.updateThumbnail(taskID, thumbnailData);
}
}
intent.removeExtra(EXTRA_TASK_ID);
intent.removeExtra(EXTRA_THUMBNAIL);
super.onNewIntent(intent);
}
@Override
protected void onHandleConfigChanged() {
super.onHandleConfigChanged();
@@ -178,6 +201,12 @@ public final class RecentsActivity extends BaseRecentsActivity {
mFallbackRecentsView.resetTaskVisuals();
}
@Override
protected void onStop() {
super.onStop();
mFallbackRecentsView.reset();
}
public void onTaskLaunched() {
mFallbackRecentsView.resetTaskVisuals();
}
@@ -43,7 +43,6 @@ import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.ActivityInfo;
import android.content.res.Configuration;
import android.graphics.Point;
import android.graphics.RectF;
@@ -77,6 +76,7 @@ import com.android.launcher3.compat.UserManagerCompat;
import com.android.launcher3.logging.EventLogArray;
import com.android.launcher3.logging.UserEventDispatcher;
import com.android.launcher3.model.AppLaunchTracker;
import com.android.launcher3.provider.RestoreDbTask;
import com.android.launcher3.testing.TestProtocol;
import com.android.launcher3.util.LooperExecutor;
import com.android.launcher3.util.UiThreadHelper;
@@ -95,12 +95,12 @@ import com.android.quickstep.inputconsumers.ScreenPinnedInputConsumer;
import com.android.systemui.shared.recents.IOverviewProxy;
import com.android.systemui.shared.recents.ISystemUiProxy;
import com.android.systemui.shared.system.ActivityManagerWrapper;
import com.android.systemui.shared.system.BackgroundExecutor;
import com.android.systemui.shared.system.InputChannelCompat.InputEventReceiver;
import com.android.systemui.shared.system.InputConsumerController;
import com.android.systemui.shared.system.InputMonitorCompat;
import com.android.systemui.shared.system.QuickStepContract;
import com.android.systemui.shared.system.QuickStepContract.SystemUiStateFlags;
import com.android.systemui.shared.system.RecentsAnimationListener;
import com.android.systemui.shared.system.SystemGestureExclusionListenerCompat;
import java.io.FileDescriptor;
@@ -124,10 +124,6 @@ class ArgList extends LinkedList<String> {
public String nextArg() {
return pollFirst().toLowerCase();
}
public String nextArgExact() {
return pollFirst();
}
}
/**
@@ -231,12 +227,17 @@ public class TouchInteractionService extends Service implements
};
private static boolean sConnected = false;
private static boolean sInputMonitorInitialized = false;
private static final SwipeSharedState sSwipeSharedState = new SwipeSharedState();
public static boolean isConnected() {
return sConnected;
}
public static boolean isInputMonitorInitialized() {
return sInputMonitorInitialized;
}
public static SwipeSharedState getSwipeSharedState() {
return sSwipeSharedState;
}
@@ -244,6 +245,11 @@ public class TouchInteractionService extends Service implements
private final InputConsumer mResetGestureInputConsumer =
new ResetGestureInputConsumer(sSwipeSharedState);
private final BaseSwipeUpHandler.Factory mWindowTreansformFactory =
this::createWindowTransformSwipeHandler;
private final BaseSwipeUpHandler.Factory mFallbackNoButtonFactory =
this::createFallbackNoButtonSwipeHandler;
private ActivityManagerWrapper mAM;
private RecentsModel mRecentsModel;
private ISystemUiProxy mISystemUiProxy;
@@ -330,6 +336,7 @@ public class TouchInteractionService extends Service implements
mInputMonitorCompat.dispose();
mInputMonitorCompat = null;
}
sInputMonitorInitialized = false;
}
private void initInputMonitor() {
@@ -347,6 +354,7 @@ public class TouchInteractionService extends Service implements
Log.e(TAG, "Unable to create input monitor", e);
}
initTouchBounds();
sInputMonitorInitialized = true;
}
private int getNavbarSize(String resName) {
@@ -508,9 +516,6 @@ public class TouchInteractionService extends Service implements
}
private void onInputEvent(InputEvent ev) {
if (TestProtocol.sDebugTracing) {
Log.d(TestProtocol.EVENTS_TO_OVERVIEW_MISSING_TAG, "onInputEvent " + ev);
}
if (!(ev instanceof MotionEvent)) {
Log.e(TAG, "Unknown event " + ev);
return;
@@ -628,10 +633,6 @@ public class TouchInteractionService extends Service implements
} else if (mGestureBlockingActivity != null && runningTaskInfo != null
&& mGestureBlockingActivity.equals(runningTaskInfo.topActivity)) {
return mResetGestureInputConsumer;
} else if (mMode == Mode.NO_BUTTON && !mOverviewComponentObserver.isHomeAndOverviewSame()) {
return new FallbackNoButtonInputConsumer(this, activityControl,
mInputMonitorCompat, sSwipeSharedState, mSwipeTouchRegion,
mOverviewComponentObserver, disableHorizontalSwipe(event), runningTaskInfo);
} else {
return createOtherActivityInputConsumer(event, runningTaskInfo);
}
@@ -644,17 +645,25 @@ public class TouchInteractionService extends Service implements
&& exclusionRegion.contains((int) event.getX(), (int) event.getY());
}
private OtherActivityInputConsumer createOtherActivityInputConsumer(MotionEvent event,
private InputConsumer createOtherActivityInputConsumer(MotionEvent event,
RunningTaskInfo runningTaskInfo) {
final ActivityControlHelper activityControl =
mOverviewComponentObserver.getActivityControlHelper();
boolean shouldDefer = activityControl.deferStartingActivity(mActiveNavBarRegion, event);
return new OtherActivityInputConsumer(this, runningTaskInfo, mRecentsModel,
mOverviewComponentObserver.getOverviewIntent(), activityControl,
shouldDefer, mOverviewCallbacks, mInputConsumer, this::onConsumerInactive,
final boolean shouldDefer;
final BaseSwipeUpHandler.Factory factory;
if (mMode == Mode.NO_BUTTON && !mOverviewComponentObserver.isHomeAndOverviewSame()) {
shouldDefer = !sSwipeSharedState.recentsAnimationFinishInterrupted;
factory = mFallbackNoButtonFactory;
} else {
shouldDefer = mOverviewComponentObserver.getActivityControlHelper()
.deferStartingActivity(mActiveNavBarRegion, event);
factory = mWindowTreansformFactory;
}
return new OtherActivityInputConsumer(this, runningTaskInfo,
shouldDefer, mOverviewCallbacks, this::onConsumerInactive,
sSwipeSharedState, mInputMonitorCompat, mSwipeTouchRegion,
disableHorizontalSwipe(event));
disableHorizontalSwipe(event), factory);
}
private InputConsumer createDeviceLockedInputConsumer(RunningTaskInfo taskInfo) {
@@ -697,6 +706,16 @@ public class TouchInteractionService extends Service implements
if (!mIsUserUnlocked) {
return;
}
if (!mMode.hasGestures && !mOverviewComponentObserver.isHomeAndOverviewSame()) {
// Prevent the overview from being started before the real home on first boot.
return;
}
if (RestoreDbTask.isPending(this)) {
// Preloading while a restore is pending may cause launcher to start the restore
// too early.
return;
}
final ActivityControlHelper<BaseDraggingActivity> activityControl =
mOverviewComponentObserver.getActivityControlHelper();
@@ -714,11 +733,7 @@ public class TouchInteractionService extends Service implements
}
// Pass null animation handler to indicate this start is preload.
BackgroundExecutor.get().submit(
() -> ActivityManagerWrapper.getInstance().startRecentsActivity(
mOverviewComponentObserver.getOverviewIntentIgnoreSysUiState(),
null /* assistDataReceiver */, null /* animationHandler */,
null /* resultCallback */, null /* resultCallbackHandler */));
startRecentsActivityAsync(mOverviewComponentObserver.getOverviewIntentIgnoreSysUiState(), null);
}
@Override
@@ -796,4 +811,21 @@ public class TouchInteractionService extends Service implements
break;
}
}
private BaseSwipeUpHandler createWindowTransformSwipeHandler(RunningTaskInfo runningTask,
long touchTimeMs, boolean continuingLastGesture, boolean isLikelyToStartNewTask) {
return new WindowTransformSwipeHandler(runningTask, this, touchTimeMs,
mOverviewComponentObserver, continuingLastGesture, mInputConsumer, mRecentsModel);
}
private BaseSwipeUpHandler createFallbackNoButtonSwipeHandler(RunningTaskInfo runningTask,
long touchTimeMs, boolean continuingLastGesture, boolean isLikelyToStartNewTask) {
return new FallbackNoButtonInputConsumer(this, mOverviewComponentObserver, runningTask,
mRecentsModel, mInputConsumer, isLikelyToStartNewTask, continuingLastGesture);
}
public static void startRecentsActivityAsync(Intent intent, RecentsAnimationListener listener) {
BACKGROUND_EXECUTOR.execute(() -> ActivityManagerWrapper.getInstance()
.startRecentsActivity(intent, null, listener, null, null));
}
}
@@ -18,8 +18,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.Utilities.SINGLE_FRAME_MS;
import static com.android.launcher3.Utilities.postAsyncCallback;
import static com.android.launcher3.anim.Interpolators.ACCEL_1_5;
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;
@@ -28,11 +26,9 @@ import static com.android.launcher3.config.FeatureFlags.QUICKSTEP_SPRINGS;
import static com.android.launcher3.util.RaceConditionTracker.ENTER;
import static com.android.launcher3.util.RaceConditionTracker.EXIT;
import static com.android.launcher3.util.SystemUiController.UI_STATE_OVERVIEW;
import static com.android.launcher3.views.FloatingIconView.SHAPE_PROGRESS_DURATION;
import static com.android.quickstep.ActivityControlHelper.AnimationFactory.ShelfAnimState.HIDE;
import static com.android.quickstep.ActivityControlHelper.AnimationFactory.ShelfAnimState.PEEK;
import static com.android.quickstep.MultiStateCallback.DEBUG_STATES;
import static com.android.quickstep.TouchInteractionService.MAIN_THREAD_EXECUTOR;
import static com.android.quickstep.TouchInteractionService.TOUCH_INTERACTION_LOG;
import static com.android.quickstep.WindowTransformSwipeHandler.GestureEndTarget.HOME;
import static com.android.quickstep.WindowTransformSwipeHandler.GestureEndTarget.LAST_TASK;
@@ -43,65 +39,46 @@ import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_O
import android.animation.Animator;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.animation.TimeInterpolator;
import android.animation.ValueAnimator;
import android.annotation.TargetApi;
import android.app.ActivityManager.RunningTaskInfo;
import android.content.Context;
import android.content.Intent;
import android.graphics.Canvas;
import android.graphics.Point;
import android.graphics.PointF;
import android.graphics.Rect;
import android.graphics.RectF;
import android.os.Build;
import android.os.Handler;
import android.os.Looper;
import android.os.SystemClock;
import android.util.Log;
import android.view.HapticFeedbackConstants;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnApplyWindowInsetsListener;
import android.view.ViewTreeObserver.OnDrawListener;
import android.view.WindowInsets;
import android.view.WindowManager;
import android.view.animation.Interpolator;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.UiThread;
import com.android.launcher3.AbstractFloatingView;
import com.android.launcher3.BaseDraggingActivity;
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.InvariantDeviceProfile;
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
import com.android.launcher3.anim.AnimationSuccessListener;
import com.android.launcher3.anim.AnimatorPlaybackController;
import com.android.launcher3.anim.Interpolators;
import com.android.launcher3.graphics.RotationMode;
import com.android.launcher3.logging.UserEventDispatcher;
import com.android.launcher3.testing.TestProtocol;
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.RaceConditionTracker;
import com.android.launcher3.util.TraceHelper;
import com.android.launcher3.views.FloatingIconView;
import com.android.quickstep.ActivityControlHelper.ActivityInitListener;
import com.android.quickstep.ActivityControlHelper.AnimationFactory;
import com.android.quickstep.ActivityControlHelper.AnimationFactory.ShelfAnimState;
import com.android.quickstep.ActivityControlHelper.HomeAnimationFactory;
import com.android.quickstep.SysUINavigationMode.Mode;
import com.android.quickstep.inputconsumers.InputConsumer;
import com.android.quickstep.inputconsumers.OverviewInputConsumer;
import com.android.quickstep.util.ClipAnimationHelper;
import com.android.quickstep.util.ClipAnimationHelper.TargetAlphaProvider;
import com.android.quickstep.util.RectFSpringAnim;
import com.android.quickstep.util.RemoteAnimationTargetSet;
import com.android.quickstep.util.SwipeAnimationTargetSet;
import com.android.quickstep.util.SwipeAnimationTargetSet.SwipeAnimationListener;
import com.android.quickstep.views.LiveTileOverlay;
import com.android.quickstep.views.RecentsView;
import com.android.quickstep.views.TaskView;
@@ -109,19 +86,17 @@ import com.android.systemui.shared.recents.model.ThumbnailData;
import com.android.systemui.shared.system.InputConsumerController;
import com.android.systemui.shared.system.LatencyTrackerCompat;
import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
import com.android.systemui.shared.system.SyncRtSurfaceTransactionApplierCompat;
import com.android.systemui.shared.system.WindowCallbacksCompat;
import java.util.function.BiFunction;
import java.util.function.Consumer;
import androidx.annotation.NonNull;
import androidx.annotation.UiThread;
@TargetApi(Build.VERSION_CODES.O)
public class WindowTransformSwipeHandler<T extends BaseDraggingActivity>
implements SwipeAnimationListener, OnApplyWindowInsetsListener {
extends BaseSwipeUpHandler<T, RecentsView>
implements OnApplyWindowInsetsListener {
private static final String TAG = WindowTransformSwipeHandler.class.getSimpleName();
private static final Rect TEMP_RECT = new Rect();
private static final String[] STATE_NAMES = DEBUG_STATES ? new String[16] : null;
private static int getFlagForIndex(int index, String name) {
@@ -220,64 +195,30 @@ public class WindowTransformSwipeHandler<T extends BaseDraggingActivity>
private static final long SHELF_ANIM_DURATION = 240;
public static final long RECENTS_ATTACH_DURATION = 300;
// Start resisting when swiping past this factor of mTransitionDragLength.
private static final float DRAG_LENGTH_FACTOR_START_PULLBACK = 1.4f;
// This is how far down we can scale down, where 0f is full screen and 1f is recents.
private static final float DRAG_LENGTH_FACTOR_MAX_PULLBACK = 1.8f;
private static final Interpolator PULLBACK_INTERPOLATOR = DEACCEL;
/**
* Used as the page index for logging when we return to the last task at the end of the gesture.
*/
private static final int LOG_NO_OP_PAGE_INDEX = -1;
private final ClipAnimationHelper mClipAnimationHelper;
private final ClipAnimationHelper.TransformParams mTransformParams;
private Runnable mGestureEndCallback;
private GestureEndTarget mGestureEndTarget;
// Either RectFSpringAnim (if animating home) or ObjectAnimator (from mCurrentShift) otherwise
private RunningWindowAnim mRunningWindowAnim;
private boolean mIsShelfPeeking;
private DeviceProfile mDp;
// The distance needed to drag to reach the task size in recents.
private int mTransitionDragLength;
// How much further we can drag past recents, as a factor of mTransitionDragLength.
private float mDragLengthFactor = 1;
// Shift in the range of [0, 1].
// 0 => preview snapShot is completely visible, and hotseat is completely translated down
// 1 => preview snapShot is completely aligned with the recents view and hotseat is completely
// visible.
private final AnimatedFloat mCurrentShift = new AnimatedFloat(this::updateFinalShift);
private boolean mContinuingLastGesture;
// To avoid UI jump when gesture is started, we offset the animation by the threshold.
private float mShiftAtGestureStart = 0;
private final Handler mMainThreadHandler = MAIN_THREAD_EXECUTOR.getHandler();
private final Context mContext;
private final ActivityControlHelper<T> mActivityControlHelper;
private final ActivityInitListener mActivityInitListener;
private final SysUINavigationMode.Mode mMode;
private final int mRunningTaskId;
private ThumbnailData mTaskSnapshot;
private MultiStateCallback mStateCallback;
// Used to control launcher components throughout the swipe gesture.
private AnimatorPlaybackController mLauncherTransitionController;
private boolean mHasLauncherTransitionControllerStarted;
private T mActivity;
private RecentsView mRecentsView;
private AnimationFactory mAnimationFactory = (t) -> { };
private LiveTileOverlay mLiveTileOverlay = new LiveTileOverlay();
private boolean mCanceled;
private boolean mWasLauncherAlreadyVisible;
private int mFinishingRecentsAnimationForNewTaskId = -1;
private boolean mPassedOverviewThreshold;
private boolean mGestureStarted;
@@ -286,31 +227,17 @@ public class WindowTransformSwipeHandler<T extends BaseDraggingActivity>
private PointF mDownPos;
private boolean mIsLikelyToStartNewTask;
private final RecentsAnimationWrapper mRecentsAnimationWrapper;
private final long mTouchTimeMs;
private long mLauncherFrameDrawnTime;
public WindowTransformSwipeHandler(RunningTaskInfo runningTaskInfo, Context context,
long touchTimeMs, ActivityControlHelper<T> controller, boolean continuingLastGesture,
InputConsumerController inputConsumer) {
mContext = context;
mRunningTaskId = runningTaskInfo.id;
long touchTimeMs, OverviewComponentObserver overviewComponentObserver,
boolean continuingLastGesture,
InputConsumerController inputConsumer, RecentsModel recentsModel) {
super(context, overviewComponentObserver, recentsModel, inputConsumer, runningTaskInfo.id);
mTouchTimeMs = touchTimeMs;
mActivityControlHelper = controller;
mActivityInitListener = mActivityControlHelper
.createActivityInitListener(this::onActivityInit);
mContinuingLastGesture = continuingLastGesture;
mRecentsAnimationWrapper = new RecentsAnimationWrapper(inputConsumer,
this::createNewInputProxyHandler);
mClipAnimationHelper = new ClipAnimationHelper(context);
mTransformParams = new ClipAnimationHelper.TransformParams();
mMode = SysUINavigationMode.getMode(context);
initStateCallbacks();
DeviceProfile dp = InvariantDeviceProfile.INSTANCE.get(mContext).getDeviceProfile(mContext);
initTransitionEndpoints(dp);
}
private void initStateCallbacks() {
@@ -373,44 +300,8 @@ public class WindowTransformSwipeHandler<T extends BaseDraggingActivity>
}
}
private void setStateOnUiThread(int stateFlag) {
if (Looper.myLooper() == mMainThreadHandler.getLooper()) {
mStateCallback.setState(stateFlag);
} else {
postAsyncCallback(mMainThreadHandler, () -> mStateCallback.setState(stateFlag));
}
}
private void initTransitionEndpoints(DeviceProfile dp) {
mDp = dp;
Rect tempRect = new Rect();
mTransitionDragLength = mActivityControlHelper.getSwipeUpDestinationAndLength(
dp, mContext, tempRect);
mClipAnimationHelper.updateTargetRect(tempRect);
if (mMode == Mode.NO_BUTTON) {
// We can drag all the way to the top of the screen.
mDragLengthFactor = (float) dp.heightPx / mTransitionDragLength;
}
}
private long getFadeInDuration() {
if (mCurrentShift.getCurrentAnimation() != null) {
ObjectAnimator anim = mCurrentShift.getCurrentAnimation();
long theirDuration = anim.getDuration() - anim.getCurrentPlayTime();
// TODO: Find a better heuristic
return Math.min(MAX_SWIPE_DURATION, Math.max(theirDuration, MIN_SWIPE_DURATION));
} else {
return MAX_SWIPE_DURATION;
}
}
public void initWhenReady() {
mActivityInitListener.register();
}
private boolean onActivityInit(final T activity, Boolean alreadyOnHome) {
@Override
protected boolean onActivityInit(final T activity, Boolean alreadyOnHome) {
if (mActivity == activity) {
return true;
}
@@ -431,19 +322,7 @@ public class WindowTransformSwipeHandler<T extends BaseDraggingActivity>
}
mRecentsView = activity.getOverviewPanel();
SyncRtSurfaceTransactionApplierCompat.create(mRecentsView, applier -> {
mTransformParams.setSyncTransactionApplier(applier);
mRecentsAnimationWrapper.runOnInit(() ->
mRecentsAnimationWrapper.targetSet.addDependentTransactionApplier(applier));
});
mRecentsView.setOnScrollChangeListener((v, scrollX, scrollY, oldScrollX, oldScrollY) -> {
if (mGestureEndTarget != HOME) {
updateFinalShift();
}
});
mRecentsView.setRecentsAnimationWrapper(mRecentsAnimationWrapper);
mRecentsView.setClipAnimationHelper(mClipAnimationHelper);
linkRecentsViewScroll();
mRecentsView.setLiveTileOverlay(mLiveTileOverlay);
mActivity.getRootView().getOverlay().add(mLiveTileOverlay);
@@ -458,33 +337,23 @@ public class WindowTransformSwipeHandler<T extends BaseDraggingActivity>
return true;
}
@Override
protected boolean moveWindowWithRecentsScroll() {
return mGestureEndTarget != HOME;
}
private void onLauncherStart(final T activity) {
if (TestProtocol.sDebugTracing) {
Log.d(TestProtocol.NO_OVERVIEW_EVENT_TAG, "onLauncherStart");
}
if (mActivity != activity) {
return;
}
if (TestProtocol.sDebugTracing) {
Log.d(TestProtocol.NO_OVERVIEW_EVENT_TAG, "onLauncherStart 1");
}
if (mStateCallback.hasStates(STATE_HANDLER_INVALIDATED)) {
return;
}
if (TestProtocol.sDebugTracing) {
Log.d(TestProtocol.NO_OVERVIEW_EVENT_TAG, "onLauncherStart 2");
}
// If we've already ended the gesture and are going home, don't prepare recents UI,
// as that will set the state as BACKGROUND_APP, overriding the animation to NORMAL.
if (mGestureEndTarget != HOME) {
if (TestProtocol.sDebugTracing) {
Log.d(TestProtocol.NO_OVERVIEW_EVENT_TAG, "onLauncherStart 3");
}
Runnable initAnimFactory = () -> {
if (TestProtocol.sDebugTracing) {
Log.d(TestProtocol.NO_OVERVIEW_EVENT_TAG, "onLauncherStart 4");
}
mAnimationFactory = mActivityControlHelper.prepareRecentsUI(mActivity,
mWasLauncherAlreadyVisible, true,
this::onAnimatorPlaybackControllerCreated);
@@ -494,14 +363,8 @@ public class WindowTransformSwipeHandler<T extends BaseDraggingActivity>
// Launcher is visible, but might be about to stop. Thus, if we prepare recents
// now, it might get overridden by moveToRestState() in onStop(). To avoid this,
// wait until the next gesture (and possibly launcher) starts.
if (TestProtocol.sDebugTracing) {
Log.d(TestProtocol.NO_OVERVIEW_EVENT_TAG, "onLauncherStart 5");
}
mStateCallback.addCallback(STATE_GESTURE_STARTED, initAnimFactory);
} else {
if (TestProtocol.sDebugTracing) {
Log.d(TestProtocol.NO_OVERVIEW_EVENT_TAG, "onLauncherStart 6");
}
initAnimFactory.run();
}
}
@@ -577,30 +440,7 @@ public class WindowTransformSwipeHandler<T extends BaseDraggingActivity>
return TaskView.getCurveScaleForInterpolation(interpolation);
}
public Consumer<MotionEvent> getRecentsViewDispatcher(RotationMode rotationMode) {
return mRecentsView != null ? mRecentsView.getEventDispatcher(rotationMode) : null;
}
@UiThread
public void updateDisplacement(float displacement) {
// We are moving in the negative x/y direction
displacement = -displacement;
if (displacement > mTransitionDragLength * mDragLengthFactor && mTransitionDragLength > 0) {
mCurrentShift.updateValue(mDragLengthFactor);
} else {
float translation = Math.max(displacement, 0);
float shift = mTransitionDragLength == 0 ? 0 : translation / mTransitionDragLength;
if (shift > DRAG_LENGTH_FACTOR_START_PULLBACK) {
float pullbackProgress = Utilities.getProgress(shift,
DRAG_LENGTH_FACTOR_START_PULLBACK, mDragLengthFactor);
pullbackProgress = PULLBACK_INTERPOLATOR.getInterpolation(pullbackProgress);
shift = DRAG_LENGTH_FACTOR_START_PULLBACK + pullbackProgress
* (DRAG_LENGTH_FACTOR_MAX_PULLBACK - DRAG_LENGTH_FACTOR_START_PULLBACK);
}
mCurrentShift.updateValue(shift);
}
}
@Override
public void onMotionPauseChanged(boolean isPaused) {
setShelfState(isPaused ? PEEK : HIDE, OVERSHOOT_1_2, SHELF_ANIM_DURATION);
}
@@ -651,6 +491,7 @@ public class WindowTransformSwipeHandler<T extends BaseDraggingActivity>
mAnimationFactory.setRecentsAttachedToAppWindow(recentsAttachedToAppWindow, animate);
}
@Override
public void setIsLikelyToStartNewTask(boolean isLikelyToStartNewTask) {
if (mIsLikelyToStartNewTask != isLikelyToStartNewTask) {
mIsLikelyToStartNewTask = isLikelyToStartNewTask;
@@ -666,9 +507,8 @@ public class WindowTransformSwipeHandler<T extends BaseDraggingActivity>
if (mIsShelfPeeking != wasShelfPeeking) {
maybeUpdateRecentsAttachedState();
}
if (mRecentsView != null && shelfState.shouldPreformHaptic) {
mRecentsView.performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY,
HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING);
if (shelfState.shouldPreformHaptic) {
performHapticFeedback();
}
}
@@ -697,19 +537,18 @@ public class WindowTransformSwipeHandler<T extends BaseDraggingActivity>
updateLauncherTransitionProgress();
}
@UiThread
private void updateFinalShift() {
float shift = mCurrentShift.value;
@Override
public Intent getLaunchIntent() {
return mOverviewComponentObserver.getOverviewIntent();
}
@Override
public void updateFinalShift() {
SwipeAnimationTargetSet controller = mRecentsAnimationWrapper.getController();
if (controller != null) {
float offsetX = mRecentsView == null ? 0 : mRecentsView.getScrollOffset();
float offsetScale = getTaskCurveScaleForOffsetX(offsetX,
mClipAnimationHelper.getTargetRect().width());
mTransformParams.setProgress(shift).setOffsetX(offsetX).setOffsetScale(offsetScale);
mClipAnimationHelper.applyTransform(mRecentsAnimationWrapper.targetSet,
mTransformParams);
updateSysUiFlags(shift);
applyTransformUnchecked();
updateSysUiFlags(mCurrentShift.value);
}
if (ENABLE_QUICKSTEP_LIVE_TILE.get()) {
@@ -722,9 +561,8 @@ public class WindowTransformSwipeHandler<T extends BaseDraggingActivity>
final boolean passed = mCurrentShift.value >= MIN_PROGRESS_FOR_OVERVIEW;
if (passed != mPassedOverviewThreshold) {
mPassedOverviewThreshold = passed;
if (mRecentsView != null && mMode != Mode.NO_BUTTON) {
mRecentsView.performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY,
HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING);
if (mMode != Mode.NO_BUTTON) {
performHapticFeedback();
}
}
@@ -767,39 +605,7 @@ public class WindowTransformSwipeHandler<T extends BaseDraggingActivity>
@Override
public void onRecentsAnimationStart(SwipeAnimationTargetSet targetSet) {
DeviceProfile dp = InvariantDeviceProfile.INSTANCE.get(mContext).getDeviceProfile(mContext);
final Rect overviewStackBounds;
RemoteAnimationTargetCompat runningTaskTarget = targetSet.findTask(mRunningTaskId);
if (targetSet.minimizedHomeBounds != null && runningTaskTarget != null) {
overviewStackBounds = mActivityControlHelper
.getOverviewWindowBounds(targetSet.minimizedHomeBounds, runningTaskTarget);
dp = dp.getMultiWindowProfile(mContext, new Point(
targetSet.minimizedHomeBounds.width(), targetSet.minimizedHomeBounds.height()));
dp.updateInsets(targetSet.homeContentInsets);
} else {
if (mActivity != null) {
int loc[] = new int[2];
View rootView = mActivity.getRootView();
rootView.getLocationOnScreen(loc);
overviewStackBounds = new Rect(loc[0], loc[1], loc[0] + rootView.getWidth(),
loc[1] + rootView.getHeight());
} else {
overviewStackBounds = new Rect(0, 0, dp.widthPx, dp.heightPx);
}
// If we are not in multi-window mode, home insets should be same as system insets.
dp = dp.copy(mContext);
dp.updateInsets(targetSet.homeContentInsets);
}
dp.updateIsSeascape(mContext.getSystemService(WindowManager.class));
if (runningTaskTarget != null) {
mClipAnimationHelper.updateSource(overviewStackBounds, runningTaskTarget);
}
mClipAnimationHelper.prepareAnimation(dp, false /* isOpening */);
initTransitionEndpoints(dp);
mRecentsAnimationWrapper.setController(targetSet);
super.onRecentsAnimationStart(targetSet);
TOUCH_INTERACTION_LOG.addLog("startRecentsAnimationCallback", targetSet.apps.length);
setStateOnUiThread(STATE_APP_CONTROLLER_RECEIVED);
@@ -814,7 +620,7 @@ public class WindowTransformSwipeHandler<T extends BaseDraggingActivity>
TOUCH_INTERACTION_LOG.addLog("cancelRecentsAnimation");
}
@UiThread
@Override
public void onGestureStarted() {
notifyGestureStartedAsync();
mShiftAtGestureStart = mCurrentShift.value;
@@ -838,7 +644,7 @@ public class WindowTransformSwipeHandler<T extends BaseDraggingActivity>
/**
* Called as a result on ACTION_CANCEL to return the UI to the start state.
*/
@UiThread
@Override
public void onGestureCancelled() {
updateDisplacement(0);
setStateOnUiThread(STATE_GESTURE_COMPLETED);
@@ -851,7 +657,7 @@ public class WindowTransformSwipeHandler<T extends BaseDraggingActivity>
* @param velocity The x and y components of the velocity when the gesture ends.
* @param downPos The x and y value of where the gesture started.
*/
@UiThread
@Override
public void onGestureEnded(float endVelocity, PointF velocity, PointF downPos) {
float flingThreshold = mContext.getResources()
.getDimension(R.dimen.quickstep_fling_threshold_velocity);
@@ -869,9 +675,9 @@ public class WindowTransformSwipeHandler<T extends BaseDraggingActivity>
handleNormalGestureEnd(endVelocity, isFling, velocity, false /* isCancel */);
}
@UiThread
private InputConsumer createNewInputProxyHandler() {
endRunningWindowAnim();
@Override
protected InputConsumer createNewInputProxyHandler() {
endRunningWindowAnim(true /* cancel */);
endLauncherTransitionController();
if (!ENABLE_QUICKSTEP_LIVE_TILE.get()) {
// Hide the task view, if not already hidden
@@ -883,9 +689,13 @@ public class WindowTransformSwipeHandler<T extends BaseDraggingActivity>
? InputConsumer.NO_OP : new OverviewInputConsumer(activity, null, true);
}
private void endRunningWindowAnim() {
private void endRunningWindowAnim(boolean cancel) {
if (mRunningWindowAnim != null) {
mRunningWindowAnim.end();
if (cancel) {
mRunningWindowAnim.cancel();
} else {
mRunningWindowAnim.end();
}
}
}
@@ -976,7 +786,7 @@ public class WindowTransformSwipeHandler<T extends BaseDraggingActivity>
if (Math.abs(endVelocity) > minFlingVelocity && mTransitionDragLength > 0) {
if (endTarget == RECENTS && mMode != Mode.NO_BUTTON) {
Interpolators.OvershootParams overshoot = new Interpolators.OvershootParams(
startShift, endShift, endShift, velocityPxPerMs.y,
startShift, endShift, endShift, endVelocity / 1000,
mTransitionDragLength);
endShift = overshoot.end;
interpolator = overshoot.interpolator;
@@ -1152,57 +962,15 @@ public class WindowTransformSwipeHandler<T extends BaseDraggingActivity>
* @param startProgress The progress of {@link #mCurrentShift} to start the window from.
* @param homeAnimationFactory The home animation factory.
*/
private RectFSpringAnim createWindowAnimationToHome(float startProgress,
@Override
protected RectFSpringAnim createWindowAnimationToHome(float startProgress,
HomeAnimationFactory homeAnimationFactory) {
final RemoteAnimationTargetSet targetSet = mRecentsAnimationWrapper.targetSet;
final RectF startRect = new RectF(mClipAnimationHelper.applyTransform(targetSet,
mTransformParams.setProgress(startProgress), false /* launcherOnTop */));
final RectF targetRect = homeAnimationFactory.getWindowTargetRect();
final View floatingView = homeAnimationFactory.getFloatingView();
final boolean isFloatingIconView = floatingView instanceof FloatingIconView;
RectFSpringAnim anim = new RectFSpringAnim(startRect, targetRect, mActivity.getResources());
if (isFloatingIconView) {
FloatingIconView fiv = (FloatingIconView) floatingView;
anim.addAnimatorListener(fiv);
fiv.setOnTargetChangeListener(anim::onTargetPositionChanged);
}
AnimatorPlaybackController homeAnim = homeAnimationFactory.createActivityAnimationToHome();
// End on a "round-enough" radius so that the shape reveal doesn't have to do too much
// rounding at the end of the animation.
float startRadius = mClipAnimationHelper.getCurrentCornerRadius();
float endRadius = startRect.width() / 6f;
// We want the window alpha to be 0 once this threshold is met, so that the
// FolderIconView can be seen morphing into the icon shape.
final float windowAlphaThreshold = isFloatingIconView ? 1f - SHAPE_PROGRESS_DURATION : 1f;
anim.addOnUpdateListener((currentRect, progress) -> {
homeAnim.setPlayFraction(progress);
float alphaProgress = ACCEL_1_5.getInterpolation(progress);
float windowAlpha = Utilities.boundToRange(Utilities.mapToRange(alphaProgress, 0,
windowAlphaThreshold, 1.5f, 0f, Interpolators.LINEAR), 0, 1);
mTransformParams.setProgress(progress)
.setCurrentRectAndTargetAlpha(currentRect, windowAlpha);
if (isFloatingIconView) {
mTransformParams.setCornerRadius(endRadius * progress + startRadius
* (1f - progress));
}
mClipAnimationHelper.applyTransform(targetSet, mTransformParams,
false /* launcherOnTop */);
if (isFloatingIconView) {
((FloatingIconView) floatingView).update(currentRect, 1f, progress,
windowAlphaThreshold, mClipAnimationHelper.getCurrentCornerRadius(), false);
}
updateSysUiFlags(Math.max(progress, mCurrentShift.value));
});
RectFSpringAnim anim =
super.createWindowAnimationToHome(startProgress, homeAnimationFactory);
anim.addOnUpdateListener((r, p) -> updateSysUiFlags(Math.max(p, mCurrentShift.value)));
anim.addAnimatorListener(new AnimationSuccessListener() {
@Override
public void onAnimationStart(Animator animation) {
homeAnim.dispatchOnStart();
if (mActivity != null) {
mActivity.getRootView().getOverlay().remove(mLiveTileOverlay);
}
@@ -1210,7 +978,6 @@ public class WindowTransformSwipeHandler<T extends BaseDraggingActivity>
@Override
public void onAnimationSuccess(Animator animator) {
homeAnim.getAnimationPlayer().end();
if (mRecentsView != null) {
mRecentsView.post(mRecentsView::resetTaskVisuals);
}
@@ -1222,11 +989,18 @@ public class WindowTransformSwipeHandler<T extends BaseDraggingActivity>
return anim;
}
/**
* @return The GestureEndTarget if the gesture has ended, else null.
*/
public @Nullable GestureEndTarget getGestureEndTarget() {
return mGestureEndTarget;
@Override
public void onConsumerAboutToBeSwitched(SwipeSharedState sharedState) {
if (mGestureEndTarget != null) {
sharedState.canGestureBeContinued = mGestureEndTarget.canBeContinued;
sharedState.goingToLauncher = mGestureEndTarget.isLauncher;
}
if (sharedState.canGestureBeContinued) {
cancelCurrentAnimation(sharedState);
} else {
reset();
}
}
@UiThread
@@ -1239,43 +1013,18 @@ public class WindowTransformSwipeHandler<T extends BaseDraggingActivity>
@UiThread
private void startNewTask() {
// Launch the task user scrolled to (mRecentsView.getNextPage()).
if (ENABLE_QUICKSTEP_LIVE_TILE.get()) {
// We finish recents animation inside launchTask() when live tile is enabled.
mRecentsView.getTaskViewAt(mRecentsView.getNextPage()).launchTask(false /* animate */,
true /* freezeTaskList */);
} else {
int taskId = mRecentsView.getTaskViewAt(mRecentsView.getNextPage()).getTask().key.id;
mFinishingRecentsAnimationForNewTaskId = taskId;
mRecentsAnimationWrapper.finish(true /* toRecents */, () -> {
if (!mCanceled) {
TaskView nextTask = mRecentsView.getTaskView(taskId);
if (nextTask != null) {
nextTask.launchTask(false /* animate */, true /* freezeTaskList */,
success -> {
if (!success) {
// We couldn't launch the task, so take user to overview so they can
// decide what to do instead of staying in this broken state.
endLauncherTransitionController();
mActivityControlHelper.onLaunchTaskFailed(mActivity);
nextTask.notifyTaskLaunchFailed(TAG);
updateSysUiFlags(1 /* windowProgress == overview */);
} else {
mActivityControlHelper.onLaunchTaskSuccess(mActivity);
}
}, mMainThreadHandler);
doLogGesture(NEW_TASK);
}
reset();
}
mCanceled = false;
mFinishingRecentsAnimationForNewTaskId = -1;
});
}
TOUCH_INTERACTION_LOG.addLog("finishRecentsAnimation", true);
startNewTask(STATE_HANDLER_INVALIDATED, success -> {
if (!success) {
// We couldn't launch the task, so take user to overview so they can
// decide what to do instead of staying in this broken state.
endLauncherTransitionController();
updateSysUiFlags(1 /* windowProgress == overview */);
}
doLogGesture(NEW_TASK);
});
}
public void reset() {
private void reset() {
setStateOnUiThread(STATE_HANDLER_INVALIDATED);
}
@@ -1283,7 +1032,7 @@ public class WindowTransformSwipeHandler<T extends BaseDraggingActivity>
* Cancels any running animation so that the active target can be overriden by a new swipe
* handle (in case of quick switch).
*/
public void cancelCurrentAnimation(SwipeSharedState sharedState) {
private void cancelCurrentAnimation(SwipeSharedState sharedState) {
mCanceled = true;
mCurrentShift.cancelAnimation();
if (mLauncherTransitionController != null && mLauncherTransitionController
@@ -1306,7 +1055,7 @@ public class WindowTransformSwipeHandler<T extends BaseDraggingActivity>
}
private void invalidateHandler() {
endRunningWindowAnim();
endRunningWindowAnim(false /* cancel */);
if (mGestureEndCallback != null) {
mGestureEndCallback.run();
@@ -1446,17 +1195,12 @@ public class WindowTransformSwipeHandler<T extends BaseDraggingActivity>
reset();
}
public void setGestureEndCallback(Runnable gestureEndCallback) {
mGestureEndCallback = gestureEndCallback;
}
private void setTargetAlphaProvider(
BiFunction<RemoteAnimationTargetCompat, Float, Float> provider) {
private void setTargetAlphaProvider(TargetAlphaProvider provider) {
mClipAnimationHelper.setTaskAlphaCallback(provider);
updateFinalShift();
}
public static float getHiddenTargetAlpha(RemoteAnimationTargetCompat app, Float expectedAlpha) {
public static float getHiddenTargetAlpha(RemoteAnimationTargetCompat app, float expectedAlpha) {
if (!isNotInRecents(app)) {
return 0;
}
@@ -1467,16 +1211,4 @@ public class WindowTransformSwipeHandler<T extends BaseDraggingActivity>
return app.isNotInRecents
|| app.activityType == RemoteAnimationTargetCompat.ACTIVITY_TYPE_HOME;
}
private interface RunningWindowAnim {
void end();
static RunningWindowAnim wrap(Animator animator) {
return animator::end;
}
static RunningWindowAnim wrap(RectFSpringAnim rectFSpringAnim) {
return rectFSpringAnim::end;
}
}
}
@@ -17,6 +17,7 @@ package com.android.quickstep.fallback;
import static com.android.launcher3.LauncherAnimUtils.SCALE_PROPERTY;
import android.app.ActivityManager.RunningTaskInfo;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Rect;
@@ -31,6 +32,10 @@ import com.android.quickstep.RecentsActivity;
import com.android.quickstep.util.LayoutUtils;
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;
import java.util.ArrayList;
public class FallbackRecentsView extends RecentsView<RecentsActivity> {
@@ -54,6 +59,8 @@ public class FallbackRecentsView extends RecentsView<RecentsActivity> {
private float mZoomScale = 1f;
private float mZoomTranslationY = 0f;
private RunningTaskInfo mRunningTaskInfo;
public FallbackRecentsView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
@@ -87,6 +94,12 @@ public class FallbackRecentsView extends RecentsView<RecentsActivity> {
super.draw(canvas);
}
@Override
public void reset() {
super.reset();
resetViewUI();
}
@Override
protected void getTaskSize(DeviceProfile dp, Rect outRect) {
LayoutUtils.calculateFallbackTaskSize(getContext(), dp, outRect);
@@ -114,6 +127,12 @@ public class FallbackRecentsView extends RecentsView<RecentsActivity> {
}
}
@Override
public void resetTaskVisuals() {
super.resetTaskVisuals();
setFullscreenProgress(mFullscreenProgress);
}
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
@@ -139,4 +158,41 @@ public class FallbackRecentsView extends RecentsView<RecentsActivity> {
TRANSLATION_Y.set(this, Utilities.mapRange(mZoomInProgress, 0, mZoomTranslationY));
FULLSCREEN_PROGRESS.set(this, mZoomInProgress);
}
public void onGestureAnimationStart(RunningTaskInfo runningTaskInfo) {
mRunningTaskInfo = runningTaskInfo;
onGestureAnimationStart(runningTaskInfo == null ? -1 : runningTaskInfo.taskId);
}
@Override
public void setCurrentTask(int runningTaskId) {
super.setCurrentTask(runningTaskId);
if (mRunningTaskInfo != null && mRunningTaskInfo.taskId != runningTaskId) {
mRunningTaskInfo = null;
}
}
@Override
protected void applyLoadPlan(ArrayList<Task> tasks) {
// 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 it we are switching on any other app.
if (mRunningTaskInfo != null && mRunningTaskInfo.taskId == mRunningTaskId) {
// Check if the task list has running task
boolean found = false;
for (Task t : tasks) {
if (t.key.id == mRunningTaskId) {
found = true;
break;
}
}
if (!found) {
ArrayList<Task> newList = new ArrayList<>(tasks.size() + 1);
newList.addAll(tasks);
newList.add(Task.from(new TaskKey(mRunningTaskInfo), mRunningTaskInfo, false));
tasks = newList;
}
}
super.applyLoadPlan(tasks);
}
}
@@ -23,6 +23,7 @@ import static com.android.launcher3.Utilities.squaredHypot;
import static com.android.launcher3.Utilities.squaredTouchSlop;
import static com.android.quickstep.MultiStateCallback.DEBUG_STATES;
import static com.android.quickstep.WindowTransformSwipeHandler.MIN_PROGRESS_FOR_OVERVIEW;
import static com.android.quickstep.TouchInteractionService.startRecentsActivityAsync;
import android.content.ComponentName;
import android.content.Context;
@@ -44,8 +45,6 @@ import com.android.quickstep.SwipeSharedState;
import com.android.quickstep.util.ClipAnimationHelper;
import com.android.quickstep.util.RecentsAnimationListenerSet;
import com.android.quickstep.util.SwipeAnimationTargetSet;
import com.android.systemui.shared.system.ActivityManagerWrapper;
import com.android.systemui.shared.system.BackgroundExecutor;
import com.android.systemui.shared.system.InputMonitorCompat;
import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
@@ -209,9 +208,7 @@ public class DeviceLockedInputConsumer implements InputConsumer,
.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
mInputMonitorCompat.pilferPointers();
BackgroundExecutor.get().submit(
() -> ActivityManagerWrapper.getInstance().startRecentsActivity(
intent, null, newListenerSet, null, null));
startRecentsActivityAsync(intent, newListenerSet);
}
@Override
@@ -15,344 +15,441 @@
*/
package com.android.quickstep.inputconsumers;
import static android.view.MotionEvent.ACTION_CANCEL;
import static android.view.MotionEvent.ACTION_DOWN;
import static android.view.MotionEvent.ACTION_MOVE;
import static android.view.MotionEvent.ACTION_POINTER_DOWN;
import static android.view.MotionEvent.ACTION_POINTER_UP;
import static android.view.MotionEvent.ACTION_UP;
import static android.view.MotionEvent.INVALID_POINTER_ID;
import static com.android.quickstep.WindowTransformSwipeHandler.MAX_SWIPE_DURATION;
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.WindowTransformSwipeHandler.MIN_PROGRESS_FOR_OVERVIEW;
import static com.android.quickstep.WindowTransformSwipeHandler.MIN_SWIPE_DURATION;
import static com.android.quickstep.inputconsumers.OtherActivityInputConsumer.QUICKSTEP_TOUCH_SLOP_RATIO;
import static com.android.systemui.shared.system.ActivityManagerWrapper.CLOSE_SYSTEM_WINDOWS_REASON_RECENTS;
import static com.android.quickstep.inputconsumers.FallbackNoButtonInputConsumer.GestureEndTarget.HOME;
import static com.android.quickstep.inputconsumers.FallbackNoButtonInputConsumer.GestureEndTarget.LAST_TASK;
import static com.android.quickstep.inputconsumers.FallbackNoButtonInputConsumer.GestureEndTarget.NEW_TASK;
import static com.android.quickstep.inputconsumers.FallbackNoButtonInputConsumer.GestureEndTarget.RECENTS;
import static com.android.quickstep.views.RecentsView.UPDATE_SYSUI_FLAGS_THRESHOLD;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ValueAnimator;
import android.animation.AnimatorSet;
import android.app.ActivityManager.RunningTaskInfo;
import android.app.ActivityOptions;
import android.content.Context;
import android.content.Intent;
import android.graphics.PointF;
import android.graphics.Rect;
import android.graphics.RectF;
import android.view.MotionEvent;
import android.view.VelocityTracker;
import android.view.ViewConfiguration;
import android.view.WindowManager;
import android.os.Bundle;
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.InvariantDeviceProfile;
import com.android.launcher3.R;
import com.android.quickstep.ActivityControlHelper;
import com.android.launcher3.anim.AnimationSuccessListener;
import com.android.launcher3.anim.AnimatorPlaybackController;
import com.android.quickstep.ActivityControlHelper.HomeAnimationFactory;
import com.android.quickstep.AnimatedFloat;
import com.android.quickstep.BaseSwipeUpHandler;
import com.android.quickstep.MultiStateCallback;
import com.android.quickstep.OverviewComponentObserver;
import com.android.quickstep.RecentsActivity;
import com.android.quickstep.RecentsModel;
import com.android.quickstep.SwipeSharedState;
import com.android.quickstep.util.ClipAnimationHelper;
import com.android.quickstep.util.ClipAnimationHelper.TransformParams;
import com.android.quickstep.util.NavBarPosition;
import com.android.quickstep.util.RecentsAnimationListenerSet;
import com.android.quickstep.fallback.FallbackRecentsView;
import com.android.quickstep.util.ObjectWrapper;
import com.android.quickstep.util.RectFSpringAnim;
import com.android.quickstep.util.SwipeAnimationTargetSet;
import com.android.quickstep.util.SwipeAnimationTargetSet.SwipeAnimationListener;
import com.android.quickstep.views.TaskView;
import com.android.systemui.shared.recents.model.ThumbnailData;
import com.android.systemui.shared.system.ActivityManagerWrapper;
import com.android.systemui.shared.system.BackgroundExecutor;
import com.android.systemui.shared.system.InputMonitorCompat;
import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
import com.android.systemui.shared.system.ActivityOptionsCompat;
import com.android.systemui.shared.system.InputConsumerController;
public class FallbackNoButtonInputConsumer implements InputConsumer, SwipeAnimationListener {
public class FallbackNoButtonInputConsumer extends
BaseSwipeUpHandler<RecentsActivity, FallbackRecentsView> {
private static final int STATE_NOT_FINISHED = 0;
private static final int STATE_FINISHED_TO_HOME = 1;
private static final int STATE_FINISHED_TO_APP = 2;
private static final String[] STATE_NAMES = DEBUG_STATES ? new String[5] : null;
private static final float PROGRESS_TO_END_GESTURE = -2;
private static int getFlagForIndex(int index, String name) {
if (DEBUG_STATES) {
STATE_NAMES[index] = name;
}
return 1 << index;
}
private final ActivityControlHelper mActivityControlHelper;
private final InputMonitorCompat mInputMonitor;
private final Context mContext;
private final NavBarPosition mNavBarPosition;
private final SwipeSharedState mSwipeSharedState;
private final OverviewComponentObserver mOverviewComponentObserver;
private final int mRunningTaskId;
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 final ClipAnimationHelper mClipAnimationHelper;
private final TransformParams mTransformParams = new TransformParams();
private final float mTransitionDragLength;
private final DeviceProfile mDP;
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");
private final RectF mSwipeTouchRegion;
private final boolean mDisableHorizontalSwipe;
public enum GestureEndTarget {
HOME(3, 100, 1),
RECENTS(1, 300, 0),
LAST_TASK(0, 150, 1),
NEW_TASK(0, 150, 1);
private final PointF mDownPos = new PointF();
private final PointF mLastPos = new PointF();
private final float mEndProgress;
private final long mDurationMultiplier;
private final float mLauncherAlpha;
private int mActivePointerId = -1;
// Slop used to determine when we say that the gesture has started.
private boolean mPassedPilferInputSlop;
GestureEndTarget(float endProgress, long durationMultiplier, float launcherAlpha) {
mEndProgress = endProgress;
mDurationMultiplier = durationMultiplier;
mLauncherAlpha = launcherAlpha;
}
}
private VelocityTracker mVelocityTracker;
private final AnimatedFloat mLauncherAlpha = new AnimatedFloat(this::onLauncherAlphaChanged);
// Distance after which we start dragging the window.
private final float mTouchSlop;
private boolean mIsMotionPaused = false;
private GestureEndTarget mEndTarget;
// Might be displacement in X or Y, depending on the direction we are swiping from the nav bar.
private float mStartDisplacement;
private SwipeAnimationTargetSet mSwipeAnimationTargetSet;
private float mProgress;
private final boolean mInQuickSwitchMode;
private final boolean mContinuingLastGesture;
private final boolean mRunningOverHome;
private final boolean mSwipeUpOverHome;
private int mState = STATE_NOT_FINISHED;
private final RunningTaskInfo mRunningTaskInfo;
private final PointF mEndVelocityPxPerMs = new PointF(0, 0.5f);
private RunningWindowAnim mFinishAnimation;
public FallbackNoButtonInputConsumer(Context context,
ActivityControlHelper activityControlHelper, InputMonitorCompat inputMonitor,
SwipeSharedState swipeSharedState, RectF swipeTouchRegion,
OverviewComponentObserver overviewComponentObserver,
boolean disableHorizontalSwipe, RunningTaskInfo runningTaskInfo) {
mContext = context;
mActivityControlHelper = activityControlHelper;
mInputMonitor = inputMonitor;
mOverviewComponentObserver = overviewComponentObserver;
mRunningTaskId = runningTaskInfo.id;
RunningTaskInfo runningTaskInfo, RecentsModel recentsModel,
InputConsumerController inputConsumer,
boolean isLikelyToStartNewTask, boolean continuingLastGesture) {
super(context, overviewComponentObserver, recentsModel, inputConsumer, runningTaskInfo.id);
mLauncherAlpha.value = 1;
mSwipeSharedState = swipeSharedState;
mSwipeTouchRegion = swipeTouchRegion;
mDisableHorizontalSwipe = disableHorizontalSwipe;
mRunningTaskInfo = runningTaskInfo;
mInQuickSwitchMode = isLikelyToStartNewTask || continuingLastGesture;
mContinuingLastGesture = continuingLastGesture;
mRunningOverHome = ActivityManagerWrapper.isHomeTask(runningTaskInfo);
mSwipeUpOverHome = mRunningOverHome && !mInQuickSwitchMode;
mNavBarPosition = new NavBarPosition(context);
mVelocityTracker = VelocityTracker.obtain();
mTouchSlop = QUICKSTEP_TOUCH_SLOP_RATIO
* ViewConfiguration.get(context).getScaledTouchSlop();
mClipAnimationHelper = new ClipAnimationHelper(context);
mDP = InvariantDeviceProfile.INSTANCE.get(context).getDeviceProfile(context).copy(context);
Rect tempRect = new Rect();
mTransitionDragLength = mActivityControlHelper.getSwipeUpDestinationAndLength(
mDP, context, tempRect);
mClipAnimationHelper.updateTargetRect(tempRect);
}
@Override
public int getType() {
return TYPE_FALLBACK_NO_BUTTON;
}
@Override
public void onMotionEvent(MotionEvent ev) {
if (mVelocityTracker == null) {
return;
}
mVelocityTracker.addMovement(ev);
if (ev.getActionMasked() == ACTION_POINTER_UP) {
mVelocityTracker.clear();
}
switch (ev.getActionMasked()) {
case ACTION_DOWN: {
mActivePointerId = ev.getPointerId(0);
mDownPos.set(ev.getX(), ev.getY());
mLastPos.set(mDownPos);
break;
}
case ACTION_POINTER_DOWN: {
if (!mPassedPilferInputSlop) {
// Cancel interaction in case of multi-touch interaction
int ptrIdx = ev.getActionIndex();
if (!mSwipeTouchRegion.contains(ev.getX(ptrIdx), ev.getY(ptrIdx))) {
forceCancelGesture(ev);
}
}
break;
}
case ACTION_POINTER_UP: {
int ptrIdx = ev.getActionIndex();
int ptrId = ev.getPointerId(ptrIdx);
if (ptrId == mActivePointerId) {
final int newPointerIdx = ptrIdx == 0 ? 1 : 0;
mDownPos.set(
ev.getX(newPointerIdx) - (mLastPos.x - mDownPos.x),
ev.getY(newPointerIdx) - (mLastPos.y - mDownPos.y));
mLastPos.set(ev.getX(newPointerIdx), ev.getY(newPointerIdx));
mActivePointerId = ev.getPointerId(newPointerIdx);
}
break;
}
case ACTION_MOVE: {
int pointerIndex = ev.findPointerIndex(mActivePointerId);
if (pointerIndex == INVALID_POINTER_ID) {
break;
}
mLastPos.set(ev.getX(pointerIndex), ev.getY(pointerIndex));
float displacement = getDisplacement(ev);
if (!mPassedPilferInputSlop) {
if (mDisableHorizontalSwipe && Math.abs(mLastPos.x - mDownPos.x)
> Math.abs(mLastPos.y - mDownPos.y)) {
// Horizontal gesture is not allowed in this region
forceCancelGesture(ev);
break;
}
if (Math.abs(displacement) >= mTouchSlop) {
mPassedPilferInputSlop = true;
// Deferred gesture, start the animation and gesture tracking once
// we pass the actual touch slop
startTouchTrackingForWindowAnimation(displacement);
}
} else {
updateDisplacement(displacement - mStartDisplacement);
}
break;
}
case ACTION_CANCEL:
case ACTION_UP: {
finishTouchTracking(ev);
break;
}
}
}
private void startTouchTrackingForWindowAnimation(float displacement) {
mStartDisplacement = Math.min(displacement, -mTouchSlop);
RecentsAnimationListenerSet listenerSet =
mSwipeSharedState.newRecentsAnimationListenerSet();
listenerSet.addListener(this);
Intent homeIntent = mOverviewComponentObserver.getHomeIntent();
BackgroundExecutor.get().submit(
() -> ActivityManagerWrapper.getInstance().startRecentsActivity(
homeIntent, null, listenerSet, null, null));
ActivityManagerWrapper.getInstance().closeSystemWindows(
CLOSE_SYSTEM_WINDOWS_REASON_RECENTS);
mInputMonitor.pilferPointers();
}
private void updateDisplacement(float displacement) {
mProgress = displacement / mTransitionDragLength;
mTransformParams.setProgress(mProgress);
if (mSwipeAnimationTargetSet != null) {
mClipAnimationHelper.applyTransform(mSwipeAnimationTargetSet, mTransformParams);
}
}
private void forceCancelGesture(MotionEvent ev) {
int action = ev.getAction();
ev.setAction(ACTION_CANCEL);
finishTouchTracking(ev);
ev.setAction(action);
}
/**
* Called when the gesture has ended. Does not correlate to the completion of the interaction as
* the animation can still be running.
*/
private void finishTouchTracking(MotionEvent ev) {
if (ev.getAction() == ACTION_CANCEL) {
mState = STATE_FINISHED_TO_APP;
if (mSwipeUpOverHome) {
mClipAnimationHelper.setBaseAlphaCallback((t, a) -> 1 - mLauncherAlpha.value);
} else {
mClipAnimationHelper.setBaseAlphaCallback((t, a) -> mLauncherAlpha.value);
}
initStateCallbacks();
}
private void initStateCallbacks() {
mStateCallback = new MultiStateCallback(STATE_NAMES);
mStateCallback.addCallback(STATE_HANDLER_INVALIDATED,
this::onHandlerInvalidated);
mStateCallback.addCallback(STATE_RECENTS_PRESENT | STATE_HANDLER_INVALIDATED,
this::onHandlerInvalidatedWithRecents);
mStateCallback.addCallback(STATE_GESTURE_CANCELLED | STATE_APP_CONTROLLER_RECEIVED,
this::finishAnimationTargetSetAnimationComplete);
if (mInQuickSwitchMode) {
mStateCallback.addCallback(STATE_GESTURE_COMPLETED | STATE_APP_CONTROLLER_RECEIVED
| STATE_RECENTS_PRESENT,
this::finishAnimationTargetSet);
} else {
mStateCallback.addCallback(STATE_GESTURE_COMPLETED | STATE_APP_CONTROLLER_RECEIVED,
this::finishAnimationTargetSet);
}
}
private void onLauncherAlphaChanged() {
if (mRecentsAnimationWrapper.targetSet != null && mEndTarget == null) {
applyTransformUnchecked();
}
}
@Override
protected boolean onActivityInit(final RecentsActivity activity, Boolean alreadyOnHome) {
mActivity = activity;
mRecentsView = activity.getOverviewPanel();
linkRecentsViewScroll();
mRecentsView.setDisallowScrollToClearAll(true);
mRecentsView.getClearAllButton().setVisibilityAlpha(0);
mRecentsView.setZoomProgress(1);
if (!mContinuingLastGesture) {
if (mRunningOverHome) {
mRecentsView.onGestureAnimationStart(mRunningTaskInfo);
} else {
mRecentsView.onGestureAnimationStart(mRunningTaskId);
}
}
setStateOnUiThread(STATE_RECENTS_PRESENT);
return true;
}
@Override
protected boolean moveWindowWithRecentsScroll() {
return mInQuickSwitchMode;
}
@Override
public void initWhenReady() {
if (mInQuickSwitchMode) {
// Only init if we are in quickswitch mode
super.initWhenReady();
}
}
@Override
public void updateDisplacement(float displacement) {
if (!mInQuickSwitchMode) {
super.updateDisplacement(displacement);
}
}
@Override
protected InputConsumer createNewInputProxyHandler() {
// Just consume all input on the active task
return InputConsumer.NO_OP;
}
@Override
public void onMotionPauseChanged(boolean isPaused) {
if (!mInQuickSwitchMode) {
mIsMotionPaused = isPaused;
mLauncherAlpha.animateToValue(mLauncherAlpha.value, isPaused ? 0 : 1)
.setDuration(150).start();
performHapticFeedback();
}
}
@Override
public Intent getLaunchIntent() {
if (mInQuickSwitchMode || mSwipeUpOverHome) {
return mOverviewComponentObserver.getOverviewIntent();
} else {
return mOverviewComponentObserver.getHomeIntent();
}
}
@Override
public void updateFinalShift() {
mTransformParams.setProgress(mCurrentShift.value);
mRecentsAnimationWrapper.setWindowThresholdCrossed(!mInQuickSwitchMode
&& (mCurrentShift.value > 1 - UPDATE_SYSUI_FLAGS_THRESHOLD));
if (mRecentsAnimationWrapper.targetSet != null) {
applyTransformUnchecked();
}
}
@Override
public void onGestureCancelled() {
updateDisplacement(0);
mEndTarget = LAST_TASK;
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
mEndTarget = LAST_TASK;
} else {
mVelocityTracker.computeCurrentVelocity(1000,
ViewConfiguration.get(mContext).getScaledMaximumFlingVelocity());
float velocityX = mVelocityTracker.getXVelocity(mActivePointerId);
float velocityY = mVelocityTracker.getYVelocity(mActivePointerId);
float velocity = mNavBarPosition.isRightEdge() ? velocityX
: mNavBarPosition.isLeftEdge() ? -velocityX
: velocityY;
float flingThreshold = mContext.getResources()
.getDimension(R.dimen.quickstep_fling_threshold_velocity);
boolean isFling = Math.abs(velocity) > flingThreshold;
boolean isFling = Math.abs(endVelocity) > flingThreshold;
boolean goingHome;
if (!isFling) {
goingHome = -mProgress >= MIN_PROGRESS_FOR_OVERVIEW;
if (isFling) {
mEndTarget = endVelocity < 0 ? HOME : LAST_TASK;
} else if (mIsMotionPaused) {
mEndTarget = RECENTS;
} else {
goingHome = velocity < 0;
mEndTarget = mCurrentShift.value >= MIN_PROGRESS_FOR_OVERVIEW ? HOME : LAST_TASK;
}
}
setStateOnUiThread(STATE_GESTURE_COMPLETED);
}
@Override
public void onConsumerAboutToBeSwitched(SwipeSharedState sharedState) {
if (mInQuickSwitchMode && mEndTarget != null) {
sharedState.canGestureBeContinued = true;
sharedState.goingToLauncher = false;
mCanceled = true;
mCurrentShift.cancelAnimation();
if (mFinishAnimation != null) {
mFinishAnimation.cancel();
}
if (goingHome) {
mState = STATE_FINISHED_TO_HOME;
} else {
mState = STATE_FINISHED_TO_APP;
if (mRecentsView != null) {
if (mFinishingRecentsAnimationForNewTaskId != -1) {
TaskView newRunningTaskView = mRecentsView.getTaskView(
mFinishingRecentsAnimationForNewTaskId);
int newRunningTaskId = newRunningTaskView != null
? newRunningTaskView.getTask().key.id
: -1;
mRecentsView.setCurrentTask(newRunningTaskId);
sharedState.setRecentsAnimationFinishInterrupted(newRunningTaskId);
}
mRecentsView.setOnScrollChangeListener(null);
}
} else {
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 (mEndTarget) {
case HOME: {
if (mSwipeUpOverHome) {
mRecentsAnimationWrapper.finish(false, null, false);
// Send a home intent to clear the task stack
mContext.startActivity(mOverviewComponentObserver.getHomeIntent());
} else {
mRecentsAnimationWrapper.finish(true, null, true);
}
break;
}
case LAST_TASK:
mRecentsAnimationWrapper.finish(false, null, false);
break;
case RECENTS: {
if (mSwipeUpOverHome) {
mRecentsAnimationWrapper.finish(true, null, true);
break;
}
ThumbnailData thumbnail =
mRecentsAnimationWrapper.targetSet.controller.screenshotTask(mRunningTaskId);
mRecentsAnimationWrapper.setCancelWithDeferredScreenshot(true);
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, mRunningTaskId);
Intent intent = new Intent(mOverviewComponentObserver.getOverviewIntent())
.putExtras(extras);
mContext.startActivity(intent, options.toBundle());
mRecentsAnimationWrapper.targetSet.controller.cleanupScreenshot();
break;
}
case NEW_TASK: {
startNewTask(STATE_HANDLER_INVALIDATED, b -> {});
break;
}
}
if (mSwipeAnimationTargetSet != null) {
finishAnimationTargetSet();
}
setStateOnUiThread(STATE_HANDLER_INVALIDATED);
}
private void finishAnimationTargetSet() {
if (mState == STATE_FINISHED_TO_APP) {
mSwipeAnimationTargetSet.finishController(false, null, false);
} else {
if (mProgress < PROGRESS_TO_END_GESTURE) {
mSwipeAnimationTargetSet.finishController(true, null, true);
if (mInQuickSwitchMode) {
// Recalculate the end target, some views might have been initialized after
// gesture has ended.
if (mRecentsView == null || !mRecentsAnimationWrapper.hasTargets()) {
mEndTarget = LAST_TASK;
} else {
long duration = (long) (Math.min(mProgress - PROGRESS_TO_END_GESTURE, 1)
* MAX_SWIPE_DURATION / Math.abs(PROGRESS_TO_END_GESTURE));
if (duration < 0) {
duration = MIN_SWIPE_DURATION;
}
ValueAnimator anim = ValueAnimator.ofFloat(mProgress, PROGRESS_TO_END_GESTURE);
anim.addUpdateListener(a -> {
float p = (Float) anim.getAnimatedValue();
mTransformParams.setProgress(p);
mClipAnimationHelper.applyTransform(mSwipeAnimationTargetSet, mTransformParams);
});
anim.setDuration(duration);
anim.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
mSwipeAnimationTargetSet.finishController(true, null, true);
}
});
anim.start();
final int runningTaskIndex = mRecentsView.getRunningTaskIndex();
final int taskToLaunch = mRecentsView.getNextPage();
mEndTarget = (runningTaskIndex >= 0 && taskToLaunch != runningTaskIndex)
? NEW_TASK : LAST_TASK;
}
}
float endProgress = mEndTarget.mEndProgress;
long duration = (long) (mEndTarget.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) {
finishAnimationTargetSetAnimationComplete();
mFinishAnimation = null;
}
};
if (mEndTarget == HOME && !mRunningOverHome) {
RectFSpringAnim anim = createWindowAnimationToHome(mCurrentShift.value, duration);
anim.addAnimatorListener(endListener);
anim.start(mEndVelocityPxPerMs);
mFinishAnimation = RunningWindowAnim.wrap(anim);
} else {
AnimatorSet anim = new AnimatorSet();
anim.play(mLauncherAlpha.animateToValue(
mLauncherAlpha.value, mEndTarget.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(SwipeAnimationTargetSet targetSet) {
mSwipeAnimationTargetSet = targetSet;
Rect overviewStackBounds = new Rect(0, 0, mDP.widthPx, mDP.heightPx);
RemoteAnimationTargetCompat runningTaskTarget = targetSet.findTask(mRunningTaskId);
super.onRecentsAnimationStart(targetSet);
mRecentsAnimationWrapper.enableInputConsumer();
mDP.updateIsSeascape(mContext.getSystemService(WindowManager.class));
if (runningTaskTarget != null) {
mClipAnimationHelper.updateSource(overviewStackBounds, runningTaskTarget);
if (mRunningOverHome) {
mClipAnimationHelper.prepareAnimation(mDp, true);
}
mClipAnimationHelper.prepareAnimation(mDP, false /* isOpening */);
applyTransformUnchecked();
overviewStackBounds
.inset(-overviewStackBounds.width() / 5, -overviewStackBounds.height() / 5);
mClipAnimationHelper.updateTargetRect(overviewStackBounds);
mClipAnimationHelper.applyTransform(mSwipeAnimationTargetSet, mTransformParams);
if (mState != STATE_NOT_FINISHED) {
finishAnimationTargetSet();
}
setStateOnUiThread(STATE_APP_CONTROLLER_RECEIVED);
}
@Override
public void onRecentsAnimationCanceled() { }
private float getDisplacement(MotionEvent ev) {
if (mNavBarPosition.isRightEdge()) {
return ev.getX() - mDownPos.x;
} else if (mNavBarPosition.isLeftEdge()) {
return mDownPos.x - ev.getX();
} else {
return ev.getY() - mDownPos.y;
}
public void onRecentsAnimationCanceled() {
mRecentsAnimationWrapper.setController(null);
setStateOnUiThread(STATE_HANDLER_INVALIDATED);
}
@Override
public boolean allowInterceptByParent() {
return !mPassedPilferInputSlop;
/**
* Creates an animation that transforms the current app window into the home app.
* @param startProgress The progress of {@link #mCurrentShift} to start the window from.
*/
private RectFSpringAnim createWindowAnimationToHome(float startProgress, long duration) {
HomeAnimationFactory factory = new HomeAnimationFactory() {
@Override
public RectF getWindowTargetRect() {
return HomeAnimationFactory.getDefaultWindowTargetRect(mDp);
}
@Override
public AnimatorPlaybackController createActivityAnimationToHome() {
AnimatorSet anim = new AnimatorSet();
anim.play(mLauncherAlpha.animateToValue(mLauncherAlpha.value, 1));
anim.setDuration(duration);
return AnimatorPlaybackController.wrap(anim, duration);
}
};
return createWindowAnimationToHome(startProgress, factory);
}
}
@@ -33,7 +33,6 @@ public interface InputConsumer {
int TYPE_SCREEN_PINNED = 1 << 6;
int TYPE_OVERVIEW_WITHOUT_FOCUS = 1 << 7;
int TYPE_RESET_GESTURE = 1 << 8;
int TYPE_FALLBACK_NO_BUTTON = 1 << 9;
String[] NAMES = new String[] {
"TYPE_NO_OP", // 0
@@ -45,7 +44,6 @@ public interface InputConsumer {
"TYPE_SCREEN_PINNED", // 6
"TYPE_OVERVIEW_WITHOUT_FOCUS", // 7
"TYPE_RESET_GESTURE", // 8
"TYPE_FALLBACK_NO_BUTTON", // 9
};
InputConsumer NO_OP = () -> TYPE_NO_OP;
@@ -28,13 +28,13 @@ import static com.android.launcher3.Utilities.squaredHypot;
import static com.android.launcher3.util.RaceConditionTracker.ENTER;
import static com.android.launcher3.util.RaceConditionTracker.EXIT;
import static com.android.quickstep.TouchInteractionService.TOUCH_INTERACTION_LOG;
import static com.android.quickstep.TouchInteractionService.startRecentsActivityAsync;
import static com.android.systemui.shared.system.ActivityManagerWrapper.CLOSE_SYSTEM_WINDOWS_REASON_RECENTS;
import android.annotation.TargetApi;
import android.app.ActivityManager.RunningTaskInfo;
import android.content.Context;
import android.content.ContextWrapper;
import android.content.Intent;
import android.graphics.PointF;
import android.graphics.RectF;
import android.os.Build;
@@ -48,21 +48,16 @@ import com.android.launcher3.R;
import com.android.launcher3.util.Preconditions;
import com.android.launcher3.util.RaceConditionTracker;
import com.android.launcher3.util.TraceHelper;
import com.android.quickstep.ActivityControlHelper;
import com.android.quickstep.BaseSwipeUpHandler;
import com.android.quickstep.OverviewCallbacks;
import com.android.quickstep.RecentsModel;
import com.android.quickstep.SwipeSharedState;
import com.android.quickstep.SysUINavigationMode;
import com.android.quickstep.SysUINavigationMode.Mode;
import com.android.quickstep.WindowTransformSwipeHandler;
import com.android.quickstep.WindowTransformSwipeHandler.GestureEndTarget;
import com.android.quickstep.util.CachedEventDispatcher;
import com.android.quickstep.util.MotionPauseDetector;
import com.android.quickstep.util.NavBarPosition;
import com.android.quickstep.util.RecentsAnimationListenerSet;
import com.android.systemui.shared.system.ActivityManagerWrapper;
import com.android.systemui.shared.system.BackgroundExecutor;
import com.android.systemui.shared.system.InputConsumerController;
import com.android.systemui.shared.system.InputMonitorCompat;
import java.util.function.Consumer;
@@ -83,16 +78,14 @@ public class OtherActivityInputConsumer extends ContextWrapper implements InputC
private final CachedEventDispatcher mRecentsViewDispatcher = new CachedEventDispatcher();
private final RunningTaskInfo mRunningTask;
private final RecentsModel mRecentsModel;
private final Intent mHomeIntent;
private final ActivityControlHelper mActivityControlHelper;
private final OverviewCallbacks mOverviewCallbacks;
private final InputConsumerController mInputConsumer;
private final SwipeSharedState mSwipeSharedState;
private final InputMonitorCompat mInputMonitorCompat;
private final SysUINavigationMode.Mode mMode;
private final RectF mSwipeTouchRegion;
private final BaseSwipeUpHandler.Factory mHandlerFactory;
private final NavBarPosition mNavBarPosition;
private final Consumer<OtherActivityInputConsumer> mOnCompleteCallback;
@@ -100,7 +93,7 @@ public class OtherActivityInputConsumer extends ContextWrapper implements InputC
private final float mMotionPauseMinDisplacement;
private VelocityTracker mVelocityTracker;
private WindowTransformSwipeHandler mInteractionHandler;
private BaseSwipeUpHandler mInteractionHandler;
private final boolean mIsDeferredDownTarget;
private final PointF mDownPos = new PointF();
@@ -114,7 +107,7 @@ public class OtherActivityInputConsumer extends ContextWrapper implements InputC
private final boolean mDisableHorizontalSwipe;
// Slop used to check when we start moving window.
private boolean mPaddedWindowMoveSlop;
private boolean mPassedWindowMoveSlop;
// Slop used to determine when we say that the gesture has started.
private boolean mPassedPilferInputSlop;
@@ -128,20 +121,18 @@ public class OtherActivityInputConsumer extends ContextWrapper implements InputC
};
public OtherActivityInputConsumer(Context base, RunningTaskInfo runningTaskInfo,
RecentsModel recentsModel, Intent homeIntent, ActivityControlHelper activityControl,
boolean isDeferredDownTarget, OverviewCallbacks overviewCallbacks,
InputConsumerController inputConsumer,
Consumer<OtherActivityInputConsumer> onCompleteCallback,
SwipeSharedState swipeSharedState, InputMonitorCompat inputMonitorCompat,
RectF swipeTouchRegion, boolean disableHorizontalSwipe) {
RectF swipeTouchRegion, boolean disableHorizontalSwipe,
BaseSwipeUpHandler.Factory handlerFactory) {
super(base);
mMainThreadHandler = new Handler(Looper.getMainLooper());
mRunningTask = runningTaskInfo;
mRecentsModel = recentsModel;
mHomeIntent = homeIntent;
mMode = SysUINavigationMode.getMode(base);
mSwipeTouchRegion = swipeTouchRegion;
mHandlerFactory = handlerFactory;
mMotionPauseDetector = new MotionPauseDetector(base);
mMotionPauseMinDisplacement = base.getResources().getDimension(
@@ -150,11 +141,9 @@ public class OtherActivityInputConsumer extends ContextWrapper implements InputC
mVelocityTracker = VelocityTracker.obtain();
mInputMonitorCompat = inputMonitorCompat;
mActivityControlHelper = activityControl;
boolean continuingPreviousGesture = swipeSharedState.getActiveListener() != null;
mIsDeferredDownTarget = !continuingPreviousGesture && isDeferredDownTarget;
mOverviewCallbacks = overviewCallbacks;
mInputConsumer = inputConsumer;
mSwipeSharedState = swipeSharedState;
mNavBarPosition = new NavBarPosition(base);
@@ -163,7 +152,7 @@ public class OtherActivityInputConsumer extends ContextWrapper implements InputC
float slop = QUICKSTEP_TOUCH_SLOP_RATIO * mTouchSlop;
mSquaredTouchSlop = slop * slop;
mPassedPilferInputSlop = mPaddedWindowMoveSlop = continuingPreviousGesture;
mPassedPilferInputSlop = mPassedWindowMoveSlop = continuingPreviousGesture;
mDisableHorizontalSwipe = !mPassedPilferInputSlop && disableHorizontalSwipe;
}
@@ -186,7 +175,7 @@ public class OtherActivityInputConsumer extends ContextWrapper implements InputC
}
// Proxy events to recents view
if (mPaddedWindowMoveSlop && mInteractionHandler != null
if (mPassedWindowMoveSlop && mInteractionHandler != null
&& !mRecentsViewDispatcher.hasConsumer()) {
mRecentsViewDispatcher.setConsumer(mInteractionHandler.getRecentsViewDispatcher(
mNavBarPosition.getRotationMode()));
@@ -213,7 +202,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());
startTouchTrackingForWindowAnimation(ev.getEventTime(), false);
}
RaceConditionTracker.onEvent(DOWN_EVT, EXIT);
@@ -251,17 +240,21 @@ public class OtherActivityInputConsumer extends ContextWrapper implements InputC
float displacement = getDisplacement(ev);
float displacementX = mLastPos.x - mDownPos.x;
if (!mPaddedWindowMoveSlop) {
if (!mPassedWindowMoveSlop) {
if (!mIsDeferredDownTarget) {
// Normal gesture, ensure we pass the drag slop before we start tracking
// the gesture
if (Math.abs(displacement) > mTouchSlop) {
mPaddedWindowMoveSlop = true;
mPassedWindowMoveSlop = true;
mStartDisplacement = Math.min(displacement, -mTouchSlop);
}
}
}
float horizontalDist = Math.abs(displacementX);
float upDist = -displacement;
boolean isLikelyToStartNewTask = horizontalDist > upDist;
if (!mPassedPilferInputSlop) {
float displacementY = mLastPos.y - mDownPos.y;
if (squaredHypot(displacementX, displacementY) >= mSquaredTouchSlop) {
@@ -277,10 +270,11 @@ 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());
startTouchTrackingForWindowAnimation(
ev.getEventTime(), isLikelyToStartNewTask);
}
if (!mPaddedWindowMoveSlop) {
mPaddedWindowMoveSlop = true;
if (!mPassedWindowMoveSlop) {
mPassedWindowMoveSlop = true;
mStartDisplacement = Math.min(displacement, -mTouchSlop);
}
@@ -289,15 +283,12 @@ public class OtherActivityInputConsumer extends ContextWrapper implements InputC
}
if (mInteractionHandler != null) {
if (mPaddedWindowMoveSlop) {
if (mPassedWindowMoveSlop) {
// Move
mInteractionHandler.updateDisplacement(displacement - mStartDisplacement);
}
if (mMode == Mode.NO_BUTTON) {
float horizontalDist = Math.abs(displacementX);
float upDist = -displacement;
boolean isLikelyToStartNewTask = horizontalDist > upDist;
mMotionPauseDetector.setDisallowPause(upDist < mMotionPauseMinDisplacement
|| isLikelyToStartNewTask);
mMotionPauseDetector.addPosition(displacement, ev.getEventTime());
@@ -329,16 +320,14 @@ public class OtherActivityInputConsumer extends ContextWrapper implements InputC
mInteractionHandler.onGestureStarted();
}
private void startTouchTrackingForWindowAnimation(long touchTimeMs) {
private void startTouchTrackingForWindowAnimation(
long touchTimeMs, boolean isLikelyToStartNewTask) {
TOUCH_INTERACTION_LOG.addLog("startRecentsAnimation");
RecentsAnimationListenerSet listenerSet = mSwipeSharedState.getActiveListener();
final WindowTransformSwipeHandler handler = new WindowTransformSwipeHandler(
mRunningTask, this, touchTimeMs, mActivityControlHelper,
listenerSet != null, mInputConsumer);
final BaseSwipeUpHandler handler = mHandlerFactory.newHandler(mRunningTask, touchTimeMs,
listenerSet != null, isLikelyToStartNewTask);
// Preload the plan
mRecentsModel.getTasks(null);
mInteractionHandler = handler;
handler.setGestureEndCallback(this::onInteractionGestureFinished);
mMotionPauseDetector.setOnMotionPauseListener(handler::onMotionPauseChanged);
@@ -352,9 +341,7 @@ public class OtherActivityInputConsumer extends ContextWrapper implements InputC
RecentsAnimationListenerSet newListenerSet =
mSwipeSharedState.newRecentsAnimationListenerSet();
newListenerSet.addListener(handler);
BackgroundExecutor.get().submit(
() -> ActivityManagerWrapper.getInstance().startRecentsActivity(
mHomeIntent, null, newListenerSet, null, null));
startRecentsActivityAsync(handler.getLaunchIntent(), newListenerSet);
}
}
@@ -366,7 +353,7 @@ public class OtherActivityInputConsumer extends ContextWrapper implements InputC
RaceConditionTracker.onEvent(UP_EVT, ENTER);
TraceHelper.endSection("TouchInt");
if (mPaddedWindowMoveSlop && mInteractionHandler != null) {
if (mPassedWindowMoveSlop && mInteractionHandler != null) {
if (ev.getActionMasked() == ACTION_CANCEL) {
mInteractionHandler.onGestureCancelled();
} else {
@@ -409,14 +396,7 @@ public class OtherActivityInputConsumer extends ContextWrapper implements InputC
// The consumer is being switched while we are active. Set up the shared state to be
// used by the next animation
removeListener();
GestureEndTarget endTarget = mInteractionHandler.getGestureEndTarget();
mSwipeSharedState.canGestureBeContinued = endTarget != null && endTarget.canBeContinued;
mSwipeSharedState.goingToLauncher = endTarget != null && endTarget.isLauncher;
if (mSwipeSharedState.canGestureBeContinued) {
mInteractionHandler.cancelCurrentAnimation(mSwipeSharedState);
} else {
mInteractionHandler.reset();
}
mInteractionHandler.onConsumerAboutToBeSwitched(mSwipeSharedState);
}
}
@@ -82,9 +82,6 @@ public class OverviewInputConsumer<T extends BaseDraggingActivity>
@Override
public void onMotionEvent(MotionEvent ev) {
if (TestProtocol.sDebugTracing) {
Log.d(TestProtocol.EVENTS_TO_OVERVIEW_MISSING_TAG, "onMotionEvent " + ev);
}
if (!mProxyTouch) {
return;
}
@@ -99,8 +99,8 @@ public class ClipAnimationHelper {
// Whether to boost the opening animation target layers, or the closing
private int mBoostModeTargetLayers = -1;
private BiFunction<RemoteAnimationTargetCompat, Float, Float> mTaskAlphaCallback =
(t, a1) -> a1;
private TargetAlphaProvider mTaskAlphaCallback = (t, a) -> a;
private TargetAlphaProvider mBaseAlphaCallback = (t, a) -> 1;
public ClipAnimationHelper(Context context) {
mWindowCornerRadius = getWindowCornerRadius(context.getResources());
@@ -119,8 +119,12 @@ public class ClipAnimationHelper {
}
public void updateSource(Rect homeStackBounds, RemoteAnimationTargetCompat target) {
mHomeStackBounds.set(homeStackBounds);
updateSourceStack(target);
updateHomeBounds(homeStackBounds);
}
public void updateHomeBounds(Rect homeStackBounds) {
mHomeStackBounds.set(homeStackBounds);
}
public void updateTargetRect(Rect targetRect) {
@@ -187,12 +191,12 @@ public class ClipAnimationHelper {
Rect crop = mTmpRect;
crop.set(app.sourceContainerBounds);
crop.offsetTo(0, 0);
float alpha = 1f;
float alpha;
int layer = RemoteAnimationProvider.getLayer(app, mBoostModeTargetLayers);
float cornerRadius = 0f;
float scale = Math.max(params.currentRect.width(), mTargetRect.width()) / crop.width();
if (app.mode == targetSet.targetMode) {
alpha = mTaskAlphaCallback.apply(app, params.targetAlpha);
alpha = mTaskAlphaCallback.getAlpha(app, params.targetAlpha);
if (app.activityType != RemoteAnimationTargetCompat.ACTIVITY_TYPE_HOME) {
mTmpMatrix.setRectToRect(mSourceRect, params.currentRect, ScaleToFit.FILL);
mTmpMatrix.postTranslate(app.position.x, app.position.y);
@@ -214,9 +218,12 @@ public class ClipAnimationHelper {
// home target.
alpha = 1 - (progress * params.targetAlpha);
}
} else if (ENABLE_QUICKSTEP_LIVE_TILE.get() && launcherOnTop) {
crop = null;
layer = Integer.MAX_VALUE;
} else {
alpha = mBaseAlphaCallback.getAlpha(app, progress);
if (ENABLE_QUICKSTEP_LIVE_TILE.get() && launcherOnTop) {
crop = null;
layer = Integer.MAX_VALUE;
}
}
// Since radius is in Surface space, but we draw the rounded corners in screen space, we
@@ -247,11 +254,14 @@ public class ClipAnimationHelper {
}
}
public void setTaskAlphaCallback(
BiFunction<RemoteAnimationTargetCompat, Float, Float> callback) {
public void setTaskAlphaCallback(TargetAlphaProvider callback) {
mTaskAlphaCallback = callback;
}
public void setBaseAlphaCallback(TargetAlphaProvider callback) {
mBaseAlphaCallback = callback;
}
public void fromTaskThumbnailView(TaskThumbnailView ttv, RecentsView rv) {
fromTaskThumbnailView(ttv, rv, null);
}
@@ -357,6 +367,10 @@ public class ClipAnimationHelper {
return mCurrentCornerRadius;
}
public interface TargetAlphaProvider {
float getAlpha(RemoteAnimationTargetCompat target, float expectedAlpha);
}
public static class TransformParams {
float progress;
public float offsetX;
@@ -0,0 +1,41 @@
/*
* Copyright (C) 2019 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.quickstep.util;
import android.os.Binder;
import android.os.IBinder;
/**
* Utility class to pass non-parcealable objects within same process using parcealable payload.
*
* It wraps the object in a binder as binders are singleton within a process
*/
public class ObjectWrapper<T> extends Binder {
private final T mObject;
public ObjectWrapper(T object) {
mObject = object;
}
public T get() {
return mObject;
}
public static IBinder wrap(Object obj) {
return new ObjectWrapper<>(obj);
}
}
@@ -225,7 +225,18 @@ public class RectFSpringAnim {
}
}
public void cancel() {
if (mAnimsStarted) {
for (OnUpdateListener onUpdateListener : mOnUpdateListeners) {
onUpdateListener.onCancel();
}
}
end();
}
public interface OnUpdateListener {
void onUpdate(RectF currentRect, float progress);
default void onCancel() { }
}
}
@@ -16,6 +16,8 @@
package com.android.quickstep.util;
import android.animation.Animator;
import android.animation.Animator.AnimatorListener;
import android.animation.AnimatorListenerAdapter;
import android.animation.ObjectAnimator;
import android.view.View;
import android.view.ViewGroup;
@@ -29,6 +31,7 @@ import com.android.launcher3.LauncherState;
import com.android.launcher3.LauncherStateManager.AnimationConfig;
import com.android.launcher3.R;
import com.android.launcher3.ShortcutAndWidgetContainer;
import com.android.launcher3.Workspace;
import com.android.launcher3.anim.AnimatorSetBuilder;
import com.android.launcher3.anim.PropertySetter;
import com.android.launcher3.anim.SpringObjectAnimator;
@@ -79,9 +82,19 @@ public class StaggeredWorkspaceAnim {
.getDimensionPixelSize(R.dimen.swipe_up_max_workspace_trans_y);
DeviceProfile grid = launcher.getDeviceProfile();
ShortcutAndWidgetContainer currentPage = ((CellLayout) launcher.getWorkspace()
.getChildAt(launcher.getWorkspace().getCurrentPage()))
.getShortcutsAndWidgets();
Workspace workspace = launcher.getWorkspace();
CellLayout cellLayout = (CellLayout) workspace.getChildAt(workspace.getCurrentPage());
ShortcutAndWidgetContainer currentPage = cellLayout.getShortcutsAndWidgets();
boolean workspaceClipChildren = workspace.getClipChildren();
boolean workspaceClipToPadding = workspace.getClipToPadding();
boolean cellLayoutClipChildren = cellLayout.getClipChildren();
boolean cellLayoutClipToPadding = cellLayout.getClipToPadding();
workspace.setClipChildren(false);
workspace.setClipToPadding(false);
cellLayout.setClipChildren(false);
cellLayout.setClipToPadding(false);
// Hotseat and QSB takes up two additional rows.
int totalRows = grid.inv.numRows + (grid.isVerticalBarLayout() ? 0 : 2);
@@ -111,6 +124,27 @@ public class StaggeredWorkspaceAnim {
addWorkspaceScrimAnimationForState(launcher, BACKGROUND_APP, 0);
addWorkspaceScrimAnimationForState(launcher, NORMAL, ALPHA_DURATION_MS);
AnimatorListener resetClipListener = new AnimatorListenerAdapter() {
int numAnimations = mAnimators.size();
@Override
public void onAnimationEnd(Animator animation) {
numAnimations--;
if (numAnimations > 0) {
return;
}
workspace.setClipChildren(workspaceClipChildren);
workspace.setClipToPadding(workspaceClipToPadding);
cellLayout.setClipChildren(cellLayoutClipChildren);
cellLayout.setClipToPadding(cellLayoutClipToPadding);
}
};
for (Animator a : mAnimators) {
a.addListener(resetClipListener);
}
}
/**
@@ -134,10 +168,6 @@ public class StaggeredWorkspaceAnim {
* @param totalRows Total number of rows.
*/
private void addStaggeredAnimationForView(View v, int row, int totalRows) {
if (v == mViewToIgnore) {
return;
}
// Invert the rows, because we stagger starting from the bottom of the screen.
int invertedRow = totalRows - row;
// Add 1 to the inverted row so that the bottom most row has a start delay.
@@ -149,6 +179,10 @@ public class StaggeredWorkspaceAnim {
springTransY.setStartDelay(startDelay);
mAnimators.add(springTransY);
if (v == mViewToIgnore) {
return;
}
v.setAlpha(0);
ObjectAnimator alpha = ObjectAnimator.ofFloat(v, View.ALPHA, 0f, 1f);
alpha.setInterpolator(LINEAR);
@@ -37,6 +37,7 @@ import static com.android.launcher3.userevent.nano.LauncherLogProto.Action.Touch
import static com.android.launcher3.userevent.nano.LauncherLogProto.ControlType.CLEAR_ALL_BUTTON;
import static com.android.launcher3.util.SystemUiController.UI_STATE_OVERVIEW;
import static com.android.quickstep.TaskUtils.checkCurrentOrManagedUserId;
import static com.android.quickstep.TouchInteractionService.BACKGROUND_EXECUTOR;
import android.animation.Animator;
import android.animation.AnimatorSet;
@@ -72,6 +73,7 @@ import android.view.MotionEvent;
import android.view.View;
import android.view.ViewDebug;
import android.view.ViewGroup;
import android.view.WindowInsets;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityNodeInfo;
import android.widget.ListView;
@@ -108,7 +110,6 @@ import com.android.quickstep.util.ClipAnimationHelper;
import com.android.systemui.shared.recents.model.Task;
import com.android.systemui.shared.recents.model.ThumbnailData;
import com.android.systemui.shared.system.ActivityManagerWrapper;
import com.android.systemui.shared.system.BackgroundExecutor;
import com.android.systemui.shared.system.LauncherEventUtil;
import com.android.systemui.shared.system.PackageManagerWrapper;
import com.android.systemui.shared.system.SyncRtSurfaceTransactionApplierCompat;
@@ -226,7 +227,7 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl
return;
}
BackgroundExecutor.get().submit(() -> {
BACKGROUND_EXECUTOR.execute(() -> {
TaskView taskView = getTaskView(taskId);
if (taskView == null) {
return;
@@ -269,7 +270,7 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl
private int mTaskListChangeId = -1;
// Only valid until the launcher state changes to NORMAL
private int mRunningTaskId = -1;
protected int mRunningTaskId = -1;
private boolean mRunningTaskTileHidden;
private Task mTmpRunningTask;
@@ -289,7 +290,7 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl
@ViewDebug.ExportedProperty(category = "launcher")
private float mContentAlpha = 1;
@ViewDebug.ExportedProperty(category = "launcher")
private float mFullscreenProgress = 0;
protected float mFullscreenProgress = 0;
// Keeps track of task id whose visual state should not be reset
private int mIgnoreResetTaskId = -1;
@@ -532,7 +533,7 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl
return true;
}
private void applyLoadPlan(ArrayList<Task> tasks) {
protected void applyLoadPlan(ArrayList<Task> tasks) {
if (mPendingAnimation != null) {
mPendingAnimation.addEndListener((onEndListener) -> applyLoadPlan(tasks));
return;
@@ -604,6 +605,7 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl
TaskView taskView = (TaskView) getChildAt(i);
if (mIgnoreResetTaskId != taskView.getTask().key.id) {
taskView.resetVisualProperties();
taskView.setStableAlpha(mContentAlpha);
}
}
if (mRunningTaskTileHidden) {
@@ -854,12 +856,14 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl
* is called. Also scrolls the view to this task.
*/
public void showCurrentTask(int runningTaskId) {
if (getChildCount() == 0) {
if (getTaskView(runningTaskId) == null) {
boolean wasEmpty = getChildCount() == 0;
// Add an empty view for now until the task plan is loaded and applied
final TaskView taskView = mTaskViewPool.getView();
addView(taskView);
addView(mClearAllButton);
addView(taskView, 0);
if (wasEmpty) {
addView(mClearAllButton);
}
// The temporary running task is only used for the duration between the start of the
// gesture and the task list is loaded and applied
mTmpRunningTask = new Task(new Task.TaskKey(runningTaskId, 0, new Intent(),
@@ -1739,4 +1743,14 @@ public abstract class RecentsView<T extends BaseActivity> extends PagedView impl
updateEnabledOverlays();
}
}
public int getLeftGestureMargin() {
final WindowInsets insets = getRootWindowInsets();
return Math.max(insets.getSystemGestureInsets().left, insets.getSystemWindowInsetLeft());
}
public int getRightGestureMargin() {
final WindowInsets insets = getRootWindowInsets();
return Math.max(insets.getSystemGestureInsets().right, insets.getSystemWindowInsetRight());
}
}
@@ -192,9 +192,6 @@ public class TaskView extends FrameLayout implements PageCallbacks, Reusable {
super(context, attrs, defStyleAttr);
mActivity = BaseDraggingActivity.fromContext(context);
setOnClickListener((view) -> {
if (com.android.launcher3.testing.TestProtocol.sDebugTracing) {
android.util.Log.d(TestProtocol.NO_START_TASK_TAG, "TaskView onClick");
}
if (getTask() == null) {
return;
}
@@ -291,9 +288,6 @@ public class TaskView extends FrameLayout implements PageCallbacks, Reusable {
public void launchTask(boolean animate, boolean freezeTaskList, Consumer<Boolean> resultCallback,
Handler resultCallbackHandler) {
if (com.android.launcher3.testing.TestProtocol.sDebugTracing) {
android.util.Log.d(TestProtocol.NO_START_TASK_TAG, "launchTask");
}
if (ENABLE_QUICKSTEP_LIVE_TILE.get()) {
if (isRunningTask()) {
getRecentsView().finishRecentsAnimation(false /* toRecents */,
@@ -308,9 +302,6 @@ public class TaskView extends FrameLayout implements PageCallbacks, Reusable {
private void launchTaskInternal(boolean animate, boolean freezeTaskList,
Consumer<Boolean> resultCallback, Handler resultCallbackHandler) {
if (com.android.launcher3.testing.TestProtocol.sDebugTracing) {
android.util.Log.d(TestProtocol.NO_START_TASK_TAG, "launchTaskInternal");
}
if (mTask != null) {
final ActivityOptions opts;
if (animate) {
+1 -1
View File
@@ -33,5 +33,5 @@
<string name="time_left_for_app" msgid="3111996412933644358">"Encore <xliff:g id="TIME">%1$s</xliff:g> aujourd\'hui"</string>
<string name="title_app_suggestions" msgid="4185902664111965088">"Suggestions d\'applications"</string>
<string name="all_apps_label" msgid="8542784161730910663">"Toutes les applications"</string>
<string name="all_apps_prediction_tip" msgid="2672336544844936186">"Vos applications prévues"</string>
<string name="all_apps_prediction_tip" msgid="2672336544844936186">"Applications prévues pour vous"</string>
</resources>
+1 -1
View File
@@ -27,7 +27,7 @@
<string name="accessibility_close_task" msgid="5354563209433803643">"बंद करें"</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="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>
<string name="shorter_duration_less_than_one_minute" msgid="4722015666335015336">"&lt;1 मिनट"</string>
<string name="time_left_for_app" msgid="3111996412933644358">"आज <xliff:g id="TIME">%1$s</xliff:g> और चलेगा"</string>
+1 -1
View File
@@ -27,7 +27,7 @@
<string name="accessibility_close_task" msgid="5354563209433803643">"बंद"</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="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>
<string name="shorter_duration_less_than_one_minute" msgid="4722015666335015336">"१मिहून कमी"</string>
<string name="time_left_for_app" msgid="3111996412933644358">"आज <xliff:g id="TIME">%1$s</xliff:g>शिल्लक आहे"</string>
@@ -51,7 +51,6 @@ import com.android.quickstep.OverviewInteractionState;
import com.android.quickstep.RecentsModel;
import com.android.quickstep.TouchInteractionService;
import com.android.quickstep.util.LayoutUtils;
import com.android.systemui.shared.system.QuickStepContract;
/**
* Touch controller for handling various state transitions in portrait UI.
@@ -296,9 +295,13 @@ public class PortraitStatesTouchController extends AbstractStateChangeTouchContr
* @return true if the event is over the hotseat
*/
static boolean isTouchOverHotseat(Launcher launcher, MotionEvent ev) {
return (ev.getY() >= getHotseatTop(launcher));
}
public static int getHotseatTop(Launcher launcher) {
DeviceProfile dp = launcher.getDeviceProfile();
int hotseatHeight = dp.hotseatBarSizePx + dp.getInsets().bottom;
return (ev.getY() >= (launcher.getDragLayer().getHeight() - hotseatHeight));
return launcher.getDragLayer().getHeight() - hotseatHeight;
}
private static class InterpolatorWrapper implements Interpolator {
@@ -152,5 +152,15 @@ public interface ActivityControlHelper<T extends BaseDraggingActivity> {
default void playAtomicAnimation(float velocity) {
// No-op
}
static RectF getDefaultWindowTargetRect(DeviceProfile dp) {
final int halfIconSize = dp.iconSizePx / 2;
final float targetCenterX = dp.availableWidthPx / 2f;
final float targetCenterY = dp.availableHeightPx - dp.hotseatBarSizePx;
// Fallback to animate to center of screen.
return new RectF(targetCenterX - halfIconSize, targetCenterY - halfIconSize,
targetCenterX + halfIconSize, targetCenterY + halfIconSize);
}
}
}
@@ -1,36 +0,0 @@
package com.android.quickstep;
import android.content.Context;
import android.os.Bundle;
import com.android.launcher3.testing.TestInformationHandler;
import com.android.launcher3.testing.TestProtocol;
import com.android.launcher3.uioverrides.states.OverviewState;
import com.android.quickstep.util.LayoutUtils;
public class QuickstepTestInformationHandler extends TestInformationHandler {
public QuickstepTestInformationHandler(Context context) { }
@Override
public Bundle call(String method) {
final Bundle response = new Bundle();
switch (method) {
case TestProtocol.REQUEST_HOME_TO_OVERVIEW_SWIPE_HEIGHT: {
final float swipeHeight =
OverviewState.getDefaultSwipeHeight(mDeviceProfile);
response.putInt(TestProtocol.TEST_INFO_RESPONSE_FIELD, (int) swipeHeight);
return response;
}
case TestProtocol.REQUEST_BACKGROUND_TO_OVERVIEW_SWIPE_HEIGHT: {
final float swipeHeight =
LayoutUtils.getShelfTrackingDistance(mContext, mDeviceProfile);
response.putInt(TestProtocol.TEST_INFO_RESPONSE_FIELD, (int) swipeHeight);
return response;
}
}
return super.call(method);
}
}
@@ -16,6 +16,8 @@
package com.android.quickstep;
import static com.android.quickstep.TouchInteractionService.BACKGROUND_EXECUTOR;
import android.annotation.TargetApi;
import android.app.ActivityManager;
import android.content.Context;
@@ -25,10 +27,7 @@ import android.util.SparseBooleanArray;
import com.android.launcher3.MainThreadExecutor;
import com.android.systemui.shared.recents.model.Task;
import com.android.systemui.shared.system.ActivityManagerWrapper;
import com.android.systemui.shared.system.BackgroundExecutor;
import com.android.systemui.shared.system.KeyguardManagerCompat;
import com.android.systemui.shared.system.RecentTaskInfoCompat;
import com.android.systemui.shared.system.TaskDescriptionCompat;
import com.android.systemui.shared.system.TaskStackChangeListener;
import java.util.ArrayList;
import java.util.Collections;
@@ -43,7 +42,6 @@ public class RecentTasksList extends TaskStackChangeListener {
private final KeyguardManagerCompat mKeyguardManager;
private final MainThreadExecutor mMainThreadExecutor;
private final BackgroundExecutor mBgThreadExecutor;
// The list change id, increments as the task list changes in the system
private int mChangeId;
@@ -56,7 +54,6 @@ public class RecentTasksList extends TaskStackChangeListener {
public RecentTasksList(Context context) {
mMainThreadExecutor = new MainThreadExecutor();
mBgThreadExecutor = BackgroundExecutor.get();
mKeyguardManager = new KeyguardManagerCompat(context);
mChangeId = 1;
ActivityManagerWrapper.getInstance().registerTaskStackListener(this);
@@ -67,7 +64,7 @@ public class RecentTasksList extends TaskStackChangeListener {
*/
public void getTaskKeys(int numTasks, Consumer<ArrayList<Task>> callback) {
// Kick off task loading in the background
mBgThreadExecutor.submit(() -> {
BACKGROUND_EXECUTOR.execute(() -> {
ArrayList<Task> tasks = loadTasksInBackground(numTasks, true /* loadKeysOnly */);
mMainThreadExecutor.execute(() -> callback.accept(tasks));
});
@@ -87,13 +84,14 @@ public class RecentTasksList extends TaskStackChangeListener {
: () -> callback.accept(copyOf(mTasks));
if (mLastLoadedId == mChangeId && (!mLastLoadHadKeysOnly || loadKeysOnly)) {
// The list is up to date, callback with the same list
mMainThreadExecutor.execute(resultCallback);
// The list is up to date, send the callback on the next frame,
// so that requestID can be returned first.
mMainThreadExecutor.getHandler().post(resultCallback);
return requestLoadId;
}
// Kick off task loading in the background
mBgThreadExecutor.submit(() -> {
BACKGROUND_EXECUTOR.execute(() -> {
ArrayList<Task> tasks = loadTasksInBackground(Integer.MAX_VALUE, loadKeysOnly);
mMainThreadExecutor.execute(() -> {
@@ -121,12 +119,7 @@ public class RecentTasksList extends TaskStackChangeListener {
@Override
public void onTaskRemoved(int taskId) {
for (int i = mTasks.size() - 1; i >= 0; i--) {
if (mTasks.get(i).key.id == taskId) {
mTasks.remove(i);
return;
}
}
mTasks = loadTasksInBackground(Integer.MAX_VALUE, false);
}
@Override
@@ -166,15 +159,11 @@ public class RecentTasksList extends TaskStackChangeListener {
int taskCount = rawTasks.size();
for (int i = 0; i < taskCount; i++) {
ActivityManager.RecentTaskInfo rawTask = rawTasks.get(i);
RecentTaskInfoCompat t = new RecentTaskInfoCompat(rawTask);
Task.TaskKey taskKey = new Task.TaskKey(rawTask);
Task task;
if (!loadKeysOnly) {
ActivityManager.TaskDescription rawTd = t.getTaskDescription();
TaskDescriptionCompat td = new TaskDescriptionCompat(rawTd);
boolean isLocked = tmpLockedUsers.get(t.getUserId());
task = new Task(taskKey, td.getPrimaryColor(), td.getBackgroundColor(),
t.supportsSplitScreenMultiWindow(), isLocked, rawTd, t.getTopActivity());
boolean isLocked = tmpLockedUsers.get(taskKey.userId);
task = Task.from(taskKey, rawTask, isLocked);
} else {
task = new Task(taskKey);
}
@@ -88,7 +88,7 @@ public class AppPredictionsUITests extends AbstractQuickStepTest {
*/
@Test
public void testPredictionExistsInAllApps() {
mActivityMonitor.startLauncher();
mDevice.pressHome();
mLauncher.pressHome().switchToAllApps();
// Dispatch an update
@@ -103,7 +103,7 @@ public class AppPredictionsUITests extends AbstractQuickStepTest {
*/
@Test
public void testPredictionsDeferredUntilHome() {
mActivityMonitor.startLauncher();
mDevice.pressHome();
sendPredictionUpdate(mSampleApp1, mSampleApp2);
mLauncher.pressHome().switchToAllApps();
waitForLauncherCondition("Predictions were not updated in loading state",
@@ -120,7 +120,7 @@ public class AppPredictionsUITests extends AbstractQuickStepTest {
@Test
public void testPredictionsDisabled() {
mActivityMonitor.startLauncher();
mDevice.pressHome();
sendPredictionUpdate();
mLauncher.pressHome().switchToAllApps();
@@ -17,7 +17,6 @@
package com.android.quickstep;
import static com.android.launcher3.ui.TaplTestsLauncher3.getAppPackageName;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
@@ -208,7 +207,7 @@ public class TaplTestsQuickstep extends AbstractQuickStepTest {
@Test
@NavigationModeSwitch
// @PortraitLandscape
@PortraitLandscape
public void testBackground() throws Exception {
startAppFast(resolveSystemApp(Intent.CATEGORY_APP_CALCULATOR));
final Background background = mLauncher.getBackground();
+1 -1
View File
@@ -88,7 +88,7 @@
<string name="notification_dots_title" msgid="9062440428204120317">"Punts de notificació"</string>
<string name="notification_dots_desc_on" msgid="1679848116452218908">"Activats"</string>
<string name="notification_dots_desc_off" msgid="1760796511504341095">"Desactivats"</string>
<string name="title_missing_notification_access" msgid="7503287056163941064">"Cal que tingui accés a les notificacions"</string>
<string name="title_missing_notification_access" msgid="7503287056163941064">"Cal accés a les notificacions"</string>
<string name="msg_missing_notification_access" msgid="281113995110910548">"Per veure els punts de notificació, activa les notificacions de l\'aplicació <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="title_change_settings" msgid="1376365968844349552">"Canvia la configuració"</string>
<string name="notification_dots_service_title" msgid="4284221181793592871">"Mostra els punts de notificació"</string>
+6 -6
View File
@@ -30,10 +30,10 @@
<string name="home_screen" msgid="806512411299847073">"Layar utama"</string>
<string name="custom_actions" msgid="3747508247759093328">"Tindakan khusus"</string>
<string name="long_press_widget_to_add" msgid="7699152356777458215">"Sentuh lama untuk memilih widget."</string>
<string name="long_accessible_way_to_add" msgid="4289502106628154155">"Tap dua kalip &amp; tahan untuk mengambil widget atau menggunakan tindakan khusus."</string>
<string name="long_accessible_way_to_add" msgid="4289502106628154155">"Ketuk dua kali &amp; tahan untuk mengambil widget atau menggunakan tindakan khusus."</string>
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
<string name="widget_accessible_dims_format" msgid="3640149169885301790">"lebar %1$d x tinggi %2$d"</string>
<string name="add_item_request_drag_hint" msgid="5899764264480397019">"Tap lama untuk menempatkan secara manual"</string>
<string name="add_item_request_drag_hint" msgid="5899764264480397019">"Sentuh lama untuk menempatkan secara manual"</string>
<string name="place_automatically" msgid="8064208734425456485">"Tambahkan otomatis"</string>
<string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Telusuri aplikasi"</string>
<string name="all_apps_loading_message" msgid="5813968043155271636">"Memuat aplikasi…"</string>
@@ -41,8 +41,8 @@
<string name="all_apps_search_market_message" msgid="1366263386197059176">"Telusuri aplikasi lainnya"</string>
<string name="label_application" msgid="8531721983832654978">"Aplikasi"</string>
<string name="notifications_header" msgid="1404149926117359025">"Notifikasi"</string>
<string name="long_press_shortcut_to_add" msgid="4524750017792716791">"Tap lama untuk memilih pintasan."</string>
<string name="long_accessible_way_to_add_shortcut" msgid="3327314059613154633">"Tap dua kali &amp; tahan untuk memilih pintasan atau menggunakan tindakan khusus."</string>
<string name="long_press_shortcut_to_add" msgid="4524750017792716791">"Sentuh lama untuk memilih pintasan."</string>
<string name="long_accessible_way_to_add_shortcut" msgid="3327314059613154633">"Ketuk dua kali &amp; tahan untuk memilih pintasan atau menggunakan tindakan khusus."</string>
<string name="out_of_space" msgid="4691004494942118364">"Tidak ada ruang lagi pada layar Utama ini."</string>
<string name="hotseat_out_of_space" msgid="7448809638125333693">"Tidak ada ruang tersisa di baki Favorit"</string>
<string name="all_apps_button_label" msgid="8130441508702294465">"Daftar aplikasi"</string>
@@ -73,8 +73,8 @@
<string name="workspace_scroll_format" msgid="8458889198184077399">"Layar utama %1$d dari %2$d"</string>
<string name="workspace_new_page" msgid="257366611030256142">"Halaman layar utama baru"</string>
<string name="folder_opened" msgid="94695026776264709">"Folder dibuka, <xliff:g id="WIDTH">%1$d</xliff:g> x <xliff:g id="HEIGHT">%2$d</xliff:g>"</string>
<string name="folder_tap_to_close" msgid="4625795376335528256">"Tap untuk menutup folder"</string>
<string name="folder_tap_to_rename" msgid="4017685068016979677">"Tap untuk menyimpan ganti nama"</string>
<string name="folder_tap_to_close" msgid="4625795376335528256">"Ketuk untuk menutup folder"</string>
<string name="folder_tap_to_rename" msgid="4017685068016979677">"Ketuk untuk menyimpan ganti nama"</string>
<string name="folder_closed" msgid="4100806530910930934">"Folder ditutup"</string>
<string name="folder_renamed" msgid="1794088362165669656">"Folder diganti namanya menjadi <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="folder_name_format" msgid="6629239338071103179">"Folder: <xliff:g id="NAME">%1$s</xliff:g>"</string>
+7 -7
View File
@@ -35,18 +35,18 @@
<string name="widget_accessible_dims_format" msgid="3640149169885301790">"%1$d रूंद बाय %2$d उंच"</string>
<string name="add_item_request_drag_hint" msgid="5899764264480397019">"स्वतः ठेवण्यासाठी स्पर्श करा आणि धरून ठेवा"</string>
<string name="place_automatically" msgid="8064208734425456485">"आपोआप जोडा"</string>
<string name="all_apps_search_bar_hint" msgid="1390553134053255246">"अॅप्स शोधा"</string>
<string name="all_apps_loading_message" msgid="5813968043155271636">"अॅप्स लोड करत आहे…"</string>
<string name="all_apps_no_search_results" msgid="3200346862396363786">"\"<xliff:g id="QUERY">%1$s</xliff:g>\" शी जुळणारे कोणतेही अॅप्स आढळले नाहीत"</string>
<string name="all_apps_search_market_message" msgid="1366263386197059176">"अधिक अॅप्स शोधा"</string>
<string name="all_apps_search_bar_hint" msgid="1390553134053255246">"अॅप्स शोधा"</string>
<string name="all_apps_loading_message" msgid="5813968043155271636">"अॅप्स लोड करत आहे…"</string>
<string name="all_apps_no_search_results" msgid="3200346862396363786">"\"<xliff:g id="QUERY">%1$s</xliff:g>\" शी जुळणारे कोणतेही अॅप्स आढळले नाहीत"</string>
<string name="all_apps_search_market_message" msgid="1366263386197059176">"अधिक अॅप्स शोधा"</string>
<string name="label_application" msgid="8531721983832654978">"ॲप"</string>
<string name="notifications_header" msgid="1404149926117359025">"सूचना"</string>
<string name="long_press_shortcut_to_add" msgid="4524750017792716791">"शॉर्टकट निवडण्यासाठी स्पर्श करा आणि धरून ठेवा."</string>
<string name="long_accessible_way_to_add_shortcut" msgid="3327314059613154633">"शॉर्टकट निवडण्यासाठी किंवा कस्टम क्रिया वापरण्यासाठी दोनदा टॅप करा आणि धरून ठेवा."</string>
<string name="out_of_space" msgid="4691004494942118364">"या मुख्य स्क्रीनवर आणखी जागा नाही."</string>
<string name="hotseat_out_of_space" msgid="7448809638125333693">"आवडीच्या ट्रे मध्ये आणखी जागा नाही"</string>
<string name="all_apps_button_label" msgid="8130441508702294465">"अॅप्स सूची"</string>
<string name="all_apps_button_personal_label" msgid="1315764287305224468">"वैयक्तिक अॅप्स सूची"</string>
<string name="all_apps_button_label" msgid="8130441508702294465">"अॅप्स सूची"</string>
<string name="all_apps_button_personal_label" msgid="1315764287305224468">"वैयक्तिक अॅप्स सूची"</string>
<string name="all_apps_button_work_label" msgid="7270707118948892488">"कामाच्या ठिकाणी वापरली जाणाऱ्या अॅप्सची सूची"</string>
<string name="all_apps_home_button_label" msgid="252062713717058851">"होम"</string>
<string name="remove_drop_target_label" msgid="7812859488053230776">"काढा"</string>
@@ -136,7 +136,7 @@
<string name="bottom_work_tab_user_education_title" msgid="5785851780786322825">"कामाची अ‍ॅप्स येथे मिळवा"</string>
<string name="bottom_work_tab_user_education_body" msgid="2818107472360579152">"प्रत्येक कार्य अ‍ॅपला एक बॅज असतो आणि तो तुमच्या संस्थेकडून सुरक्षित ठेवला जातो. अधिक सहज अ‍ॅक्सेससाठी अ‍ॅप्स तुमच्या होम स्क्रीनवर हलवा."</string>
<string name="work_mode_on_label" msgid="4781128097185272916">"तुमच्या संस्थेकडून व्यवस्थापित"</string>
<string name="work_mode_off_label" msgid="3194894777601421047">"सूचना आणि अॅप्स बंद आहेत"</string>
<string name="work_mode_off_label" msgid="3194894777601421047">"सूचना आणि अॅप्स बंद आहेत"</string>
<string name="bottom_work_tab_user_education_close_button" msgid="4224492243977802135">"बंद करा"</string>
<string name="bottom_work_tab_user_education_closed" msgid="1098340939861869465">"बंद केले"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"हे करता आले नाही: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
+1 -1
View File
@@ -90,7 +90,7 @@
<string name="notification_dots_title" msgid="9062440428204120317">"Значки уведомлений"</string>
<string name="notification_dots_desc_on" msgid="1679848116452218908">"Включены"</string>
<string name="notification_dots_desc_off" msgid="1760796511504341095">"Отключены"</string>
<string name="title_missing_notification_access" msgid="7503287056163941064">"Нет доступа к уведомлениям"</string>
<string name="title_missing_notification_access" msgid="7503287056163941064">"Нужен доступ к уведомлениям"</string>
<string name="msg_missing_notification_access" msgid="281113995110910548">"Чтобы показывать значки уведомлений, включите уведомления в приложении \"<xliff:g id="NAME">%1$s</xliff:g>\""</string>
<string name="title_change_settings" msgid="1376365968844349552">"Изменить настройки"</string>
<string name="notification_dots_service_title" msgid="4284221181793592871">"Показывать значки уведомлений"</string>
@@ -135,10 +135,6 @@ public abstract class BaseDraggingActivity extends BaseActivity
public boolean startActivitySafely(View v, Intent intent, @Nullable ItemInfo item,
@Nullable String sourceContainer) {
if (TestProtocol.sDebugTracing) {
android.util.Log.d(TestProtocol.NO_START_TAG,
"startActivitySafely 1");
}
if (mIsSafeModeEnabled && !Utilities.isSystemApp(this, intent)) {
Toast.makeText(this, R.string.safemode_shortcut_error, Toast.LENGTH_SHORT).show();
return false;
@@ -162,10 +158,6 @@ public abstract class BaseDraggingActivity extends BaseActivity
startShortcutIntentSafely(intent, optsBundle, item, sourceContainer);
} else if (user == null || user.equals(Process.myUserHandle())) {
// Could be launching some bookkeeping activity
if (TestProtocol.sDebugTracing) {
android.util.Log.d(TestProtocol.NO_START_TAG,
"startActivitySafely 2");
}
startActivity(intent, optsBundle);
AppLaunchTracker.INSTANCE.get(this).onStartApp(intent.getComponent(),
Process.myUserHandle(), sourceContainer);
@@ -319,9 +319,6 @@ public class BubbleTextView extends TextView implements ItemInfoUpdateReceiver,
@Override
public boolean onTouchEvent(MotionEvent event) {
if (TestProtocol.sDebugTracing) {
Log.d(TestProtocol.NO_START_TAG, "BubbleTextView.onTouchEvent " + event);
}
// Call the superclass onTouchEvent first, because sometimes it changes the state to
// isPressed() on an ACTION_UP
boolean result = super.onTouchEvent(event);
-8
View File
@@ -890,9 +890,6 @@ public class Launcher extends BaseDraggingActivity implements LauncherExterns,
@Override
protected void onStart() {
if (TestProtocol.sDebugTracing) {
Log.d(TestProtocol.NO_OVERVIEW_EVENT_TAG, "Launcher.onStart");
}
RaceConditionTracker.onEvent(ON_START_EVT, ENTER);
super.onStart();
if (mLauncherCallbacks != null) {
@@ -1809,11 +1806,6 @@ public class Launcher extends BaseDraggingActivity implements LauncherExterns,
public boolean startActivitySafely(View v, Intent intent, ItemInfo item,
@Nullable String sourceContainer) {
if (TestProtocol.sDebugTracing) {
android.util.Log.d(TestProtocol.NO_START_TAG,
"startActivitySafely outer");
}
if (!hasBeenResumed()) {
// Workaround an issue where the WM launch animation is clobbered when finishing the
// recents animation into launcher. Defer launching the activity until Launcher is
@@ -403,10 +403,6 @@ public class LauncherStateManager {
}
private void onStateTransitionStart(LauncherState state) {
if (TestProtocol.sDebugTracing) {
android.util.Log.d(TestProtocol.NO_DRAG_TAG,
"onStateTransitionStart");
}
if (mState != state) {
mState.onStateDisabled(mLauncher);
}
@@ -429,11 +425,6 @@ public class LauncherStateManager {
// Only change the stable states after the transitions have finished
if (state != mCurrentStableState) {
mLastStableState = state.getHistoryForState(mCurrentStableState);
if (TestProtocol.sDebugTracing) {
Log.d(TestProtocol.NO_ALLAPPS_EVENT_TAG,
"mCurrentStableState = " + state.getClass().getSimpleName() + " @ " +
android.util.Log.getStackTraceString(new Throwable()));
}
mCurrentStableState = state;
}
@@ -580,10 +571,6 @@ public class LauncherStateManager {
private final AnimatorSet mAnim;
public StartAnimRunnable(AnimatorSet anim) {
if (TestProtocol.sDebugTracing) {
android.util.Log.d(TestProtocol.NO_DRAG_TAG,
"StartAnimRunnable");
}
mAnim = anim;
}
+2
View File
@@ -47,6 +47,7 @@ import android.view.animation.Interpolator;
import android.widget.ScrollView;
import com.android.launcher3.anim.Interpolators;
import com.android.launcher3.compat.AccessibilityManagerCompat;
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.pageindicators.PageIndicator;
import com.android.launcher3.touch.OverScroll;
@@ -367,6 +368,7 @@ public abstract class PagedView<T extends View & PageIndicator> extends ViewGrou
*/
protected void onPageEndTransition() {
mWasInOverscroll = false;
AccessibilityManagerCompat.sendScrollFinishedEventToTest(getContext());
}
protected int getUnboundedScrollX() {
-8
View File
@@ -370,10 +370,6 @@ public class Workspace extends PagedView<WorkspacePageIndicator>
@Override
public void onDragStart(DropTarget.DragObject dragObject, DragOptions options) {
if (TestProtocol.sDebugTracing) {
android.util.Log.d(TestProtocol.NO_DRAG_TAG,
"onDragStart 1");
}
if (ENFORCE_DRAG_EVENT_ORDER) {
enforceDragParity("onDragStart", 0, 0);
}
@@ -424,10 +420,6 @@ public class Workspace extends PagedView<WorkspacePageIndicator>
}
// Always enter the spring loaded mode
if (TestProtocol.sDebugTracing) {
android.util.Log.d(TestProtocol.NO_DRAG_TAG,
"onDragStart 2");
}
mLauncher.getStateManager().goToState(SPRING_LOADED);
}
@@ -50,6 +50,7 @@ import com.android.launcher3.Utilities;
import com.android.launcher3.compat.AccessibilityManagerCompat;
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.keyboard.FocusedItemDecorator;
import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType;
import com.android.launcher3.userevent.nano.LauncherLogProto.Target;
import com.android.launcher3.util.ItemInfoMatcher;
import com.android.launcher3.util.MultiValueAlpha;
@@ -297,7 +298,11 @@ public class AllAppsContainerView extends SpringRelativeLayout implements DragSo
@Override
public void fillInLogContainerData(View v, ItemInfo info, Target target, Target targetParent) {
// This is filled in {@link AllAppsRecyclerView}
if (getApps().hasFilter()) {
targetParent.containerType = ContainerType.SEARCHRESULT;
} else {
targetParent.containerType = ContainerType.ALLAPPS;
}
}
@Override
@@ -626,9 +631,6 @@ public class AllAppsContainerView extends SpringRelativeLayout implements DragSo
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
if (TestProtocol.sDebugTracing) {
Log.d(TestProtocol.NO_START_TAG, "AllAppsContainerView.dispatchTouchEvent " + ev);
}
final boolean result = super.dispatchTouchEvent(ev);
switch (ev.getActionMasked()) {
case MotionEvent.ACTION_DOWN:
@@ -168,10 +168,6 @@ public class AllAppsTransitionController implements StateHandler, OnDeviceProfil
@Override
public void setStateWithAnimation(LauncherState toState,
AnimatorSetBuilder builder, AnimationConfig config) {
if (TestProtocol.sDebugTracing) {
Log.d(TestProtocol.NO_ALLAPPS_EVENT_TAG,
"setStateWithAnimation " + toState.getClass().getSimpleName());
}
float targetProgress = toState.getVerticalProgress(mLauncher);
if (Float.compare(mProgress, targetProgress) == 0) {
setAlphas(toState, config, builder);
@@ -301,11 +301,6 @@ public class AlphabeticalAppsList implements AllAppsStore.OnUpdateListener {
}
private void refreshRecyclerView() {
if (TestProtocol.sDebugTracing) {
android.util.Log.d(TestProtocol.NO_START_TAG,
"refreshRecyclerView @ " + android.util.Log.getStackTraceString(
new Throwable()));
}
if (mAdapter != null) {
mAdapter.notifyDataSetChanged();
}
@@ -144,7 +144,8 @@ public class Interpolators {
public static Interpolator clampToProgress(Interpolator interpolator, float lowerBound,
float upperBound) {
if (upperBound <= lowerBound) {
throw new IllegalArgumentException("lowerBound must be less than upperBound");
throw new IllegalArgumentException(String.format(
"lowerBound (%f) must be less than upperBound (%f)", lowerBound, upperBound));
}
return t -> {
if (t < lowerBound) {
@@ -96,7 +96,10 @@ public class SpringObjectAnimator<T> extends ValueAnimator {
}
});
mSpring.addUpdateListener((animation, value, velocity) -> mSpringEnded = false);
mSpring.addUpdateListener((animation, value, velocity) -> {
mSpringEnded = false;
mEnded = false;
});
mSpring.addEndListener((animation, canceled, value, velocity) -> {
mSpringEnded = true;
tryEnding();
@@ -53,9 +53,6 @@ public class AccessibilityManagerCompat {
}
public static void sendStateEventToTest(Context context, int stateOrdinal) {
if (com.android.launcher3.testing.TestProtocol.sDebugTracing) {
android.util.Log.e(TestProtocol.NO_ALLAPPS_EVENT_TAG, "sendStateEventToTest");
}
final AccessibilityManager accessibilityManager = getAccessibilityManagerForTest(context);
if (accessibilityManager == null) return;
@@ -137,9 +137,6 @@ public abstract class BaseItemDragListener extends InternalStateHandler implemen
@Override
public boolean shouldStartDrag(double distanceDragged) {
if (TestProtocol.sDebugTracing) {
Log.d(TestProtocol.NO_DRAG_TAG, "BIDL.shouldStartDrag");
}
// Stay in pre-drag mode, if workspace is locked.
return !mLauncher.isWorkspaceLocked();
}
@@ -474,10 +474,6 @@ public class DragController implements DragDriver.EventListener, TouchController
}
private void handleMoveEvent(int x, int y) {
if (TestProtocol.sDebugTracing) {
android.util.Log.d(TestProtocol.NO_DRAG_TAG,
"handleMoveEvent 1");
}
mDragObject.dragView.move(x, y);
// Drop on someone?
@@ -492,22 +488,8 @@ public class DragController implements DragDriver.EventListener, TouchController
mLastTouch[0] = x;
mLastTouch[1] = y;
if (TestProtocol.sDebugTracing) {
Log.d(TestProtocol.NO_DRAG_TAG,
"handleMoveEvent Conditions " +
mIsInPreDrag + ", " +
(mIsInPreDrag && mOptions.preDragCondition != null) + ", " +
(mIsInPreDrag && mOptions.preDragCondition != null
&& mOptions.preDragCondition.shouldStartDrag(
mDistanceSinceScroll)));
}
if (mIsInPreDrag && mOptions.preDragCondition != null
&& mOptions.preDragCondition.shouldStartDrag(mDistanceSinceScroll)) {
if (TestProtocol.sDebugTracing) {
android.util.Log.d(TestProtocol.NO_DRAG_TAG,
"handleMoveEvent 2");
}
callOnDragStart();
}
}
@@ -545,10 +527,6 @@ public class DragController implements DragDriver.EventListener, TouchController
* Call this from a drag source view.
*/
public boolean onControllerTouchEvent(MotionEvent ev) {
if (TestProtocol.sDebugTracing) {
android.util.Log.d(TestProtocol.NO_DRAG_TAG,
"onControllerTouchEvent");
}
if (mDragDriver == null || mOptions == null || mOptions.isAccessibleDrag) {
return false;
}
@@ -449,11 +449,6 @@ public class PopupContainerWithArrow extends ArrowPopup implements DragSource,
@Override
public boolean shouldStartDrag(double distanceDragged) {
if (TestProtocol.sDebugTracing) {
Log.d(TestProtocol.NO_DRAG_TAG,
"createPreDragCondition().shouldStartDrag " + distanceDragged + ", "
+ mStartDragThreshold);
}
return distanceDragged > mStartDragThreshold;
}
@@ -74,6 +74,11 @@ public class TestInformationHandler implements ResourceBasedOverride {
break;
}
case TestProtocol.REQUEST_IS_LAUNCHER_INITIALIZED: {
response.putBoolean(TestProtocol.TEST_INFO_RESPONSE_FIELD, true);
break;
}
case TestProtocol.REQUEST_ENABLE_DEBUG_TRACING:
TestProtocol.sDebugTracing = true;
break;
@@ -66,17 +66,15 @@ public final class TestProtocol {
"all-apps-to-overview-swipe-height";
public static final String REQUEST_HOME_TO_ALL_APPS_SWIPE_HEIGHT =
"home-to-all-apps-swipe-height";
public static final String REQUEST_HOTSEAT_TOP = "hotseat-top";
public static final String REQUEST_IS_LAUNCHER_INITIALIZED = "is-launcher-initialized";
public static final String REQUEST_FREEZE_APP_LIST = "freeze-app-list";
public static final String REQUEST_UNFREEZE_APP_LIST = "unfreeze-app-list";
public static final String REQUEST_APP_LIST_FREEZE_FLAGS = "app-list-freeze-flags";
public static final String REQUEST_OVERVIEW_LEFT_GESTURE_MARGIN = "overview-left-margin";
public static final String REQUEST_OVERVIEW_RIGHT_GESTURE_MARGIN = "overview-right-margin";
public static boolean sDebugTracing = false;
public static final String REQUEST_ENABLE_DEBUG_TRACING = "enable-debug-tracing";
public static final String REQUEST_DISABLE_DEBUG_TRACING = "disable-debug-tracing";
public static final String NO_ALLAPPS_EVENT_TAG = "b/133867119";
public static final String NO_DRAG_TAG = "b/133009122";
public static final String NO_START_TAG = "b/132900132";
public static final String NO_START_TASK_TAG = "b/133765434";
public static final String NO_OVERVIEW_EVENT_TAG = "b/134532571";
public static final String EVENTS_TO_OVERVIEW_MISSING_TAG = "b/133867119";
}
@@ -31,7 +31,6 @@ import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
import android.animation.ValueAnimator;
import android.os.SystemClock;
import android.util.Log;
import android.view.HapticFeedbackConstants;
import android.view.MotionEvent;
@@ -43,7 +42,6 @@ import com.android.launcher3.Utilities;
import com.android.launcher3.anim.AnimationSuccessListener;
import com.android.launcher3.anim.AnimatorPlaybackController;
import com.android.launcher3.anim.AnimatorSetBuilder;
import com.android.launcher3.testing.TestProtocol;
import com.android.launcher3.userevent.nano.LauncherLogProto;
import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Direction;
import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Touch;
@@ -118,9 +116,6 @@ public abstract class AbstractStateChangeTouchController
@Override
public final boolean onControllerInterceptTouchEvent(MotionEvent ev) {
if (TestProtocol.sDebugTracing) {
Log.d(TestProtocol.NO_ALLAPPS_EVENT_TAG, "onControllerInterceptTouchEvent 1 " + ev);
}
if (ev.getAction() == MotionEvent.ACTION_DOWN) {
mNoIntercept = !canInterceptTouch(ev);
if (mNoIntercept) {
@@ -150,9 +145,6 @@ public abstract class AbstractStateChangeTouchController
return false;
}
if (TestProtocol.sDebugTracing) {
Log.d(TestProtocol.NO_ALLAPPS_EVENT_TAG, "onControllerInterceptTouchEvent 2 ");
}
onControllerTouchEvent(ev);
return mDetector.isDraggingOrSettling();
}
@@ -240,9 +232,6 @@ public abstract class AbstractStateChangeTouchController
@Override
public void onDragStart(boolean start) {
if (TestProtocol.sDebugTracing) {
Log.d(TestProtocol.NO_ALLAPPS_EVENT_TAG, "onDragStart 1 " + start);
}
mStartState = mLauncher.getStateManager().getState();
if (mStartState == ALL_APPS) {
mStartContainerType = LauncherLogProto.ContainerType.ALLAPPS;
@@ -252,9 +241,6 @@ public abstract class AbstractStateChangeTouchController
mStartContainerType = LauncherLogProto.ContainerType.TASKSWITCHER;
}
if (mCurrentAnimation == null) {
if (TestProtocol.sDebugTracing) {
Log.d(TestProtocol.NO_ALLAPPS_EVENT_TAG, "onDragStart 2");
}
mFromState = mStartState;
mToState = null;
cancelAnimationControllers();
@@ -376,9 +362,6 @@ public abstract class AbstractStateChangeTouchController
@Override
public void onDragEnd(float velocity, boolean fling) {
if (com.android.launcher3.testing.TestProtocol.sDebugTracing) {
android.util.Log.e(TestProtocol.NO_ALLAPPS_EVENT_TAG, "onDragEnd");
}
final int logAction = fling ? Touch.FLING : Touch.SWIPE;
boolean blockedFling = fling && mFlingBlockCheck.isBlocked();
@@ -515,9 +498,6 @@ public abstract class AbstractStateChangeTouchController
}
protected void onSwipeInteractionCompleted(LauncherState targetState, int logAction) {
if (com.android.launcher3.testing.TestProtocol.sDebugTracing) {
android.util.Log.e(TestProtocol.NO_ALLAPPS_EVENT_TAG, "onSwipeInteractionCompleted 1");
}
if (mAtomicComponentsController != null) {
mAtomicComponentsController.getAnimationPlayer().end();
mAtomicComponentsController = null;
@@ -531,18 +511,17 @@ public abstract class AbstractStateChangeTouchController
shouldGoToTargetState = !reachedTarget;
}
if (shouldGoToTargetState) {
if (targetState != mStartState) {
logReachedState(logAction, targetState);
}
mLauncher.getStateManager().goToState(targetState, false /* animated */);
if (com.android.launcher3.testing.TestProtocol.sDebugTracing) {
android.util.Log.e(
TestProtocol.NO_ALLAPPS_EVENT_TAG, "onSwipeInteractionCompleted 2");
}
goToTargetState(targetState, logAction);
}
}
protected void goToTargetState(LauncherState targetState, int logAction) {
if (targetState != mStartState) {
logReachedState(logAction, targetState);
}
mLauncher.getStateManager().goToState(targetState, false /* animated */);
}
private void logReachedState(int logAction, LauncherState targetState) {
// Transition complete. log the action
mLauncher.getUserEventDispatcher().logStateChangeAction(logAction,
@@ -563,9 +542,6 @@ public abstract class AbstractStateChangeTouchController
}
private void cancelAnimationControllers() {
if (TestProtocol.sDebugTracing) {
Log.d(TestProtocol.NO_ALLAPPS_EVENT_TAG, "cancelAnimationControllers");
}
mCurrentAnimation = null;
cancelAtomicComponentsController();
mDetector.finishedScrolling();
@@ -68,28 +68,12 @@ public class ItemClickHandler {
}
private static void onClick(View v, String sourceContainer) {
if (TestProtocol.sDebugTracing) {
android.util.Log.d(TestProtocol.NO_START_TAG,
"onClick 1");
}
// Make sure that rogue clicks don't get through while allapps is launching, or after the
// view has detached (it's possible for this to happen if the view is removed mid touch).
if (v.getWindowToken() == null) {
if (TestProtocol.sDebugTracing) {
android.util.Log.d(TestProtocol.NO_START_TAG,
"onClick 2");
}
return;
}
if (v.getWindowToken() == null) return;
Launcher launcher = Launcher.getLauncher(v.getContext());
if (!launcher.getWorkspace().isFinishedSwitchingState()) {
if (TestProtocol.sDebugTracing) {
android.util.Log.d(TestProtocol.NO_START_TAG,
"onClick 3");
}
return;
}
if (!launcher.getWorkspace().isFinishedSwitchingState()) return;
Object tag = v.getTag();
if (tag instanceof WorkspaceItemInfo) {
@@ -99,10 +83,6 @@ public class ItemClickHandler {
onClickFolderIcon(v);
}
} else if (tag instanceof AppInfo) {
if (TestProtocol.sDebugTracing) {
android.util.Log.d(TestProtocol.NO_START_TAG,
"onClick 4");
}
startAppShortcutOrInfoActivity(v, (AppInfo) tag, launcher,
sourceContainer == null ? CONTAINER_ALL_APPS: sourceContainer);
} else if (tag instanceof LauncherAppWidgetInfo) {
@@ -234,10 +214,6 @@ public class ItemClickHandler {
private static void startAppShortcutOrInfoActivity(View v, ItemInfo item, Launcher launcher,
@Nullable String sourceContainer) {
if (TestProtocol.sDebugTracing) {
android.util.Log.d(TestProtocol.NO_START_TAG,
"startAppShortcutOrInfoActivity");
}
Intent intent;
if (item instanceof PromiseAppInfo) {
PromiseAppInfo promiseAppInfo = (PromiseAppInfo) item;
@@ -158,9 +158,6 @@ public class SwipeDetector {
// SETTLING -> (View settled) -> IDLE
private void setState(ScrollState newState) {
if (TestProtocol.sDebugTracing) {
Log.d(TestProtocol.NO_ALLAPPS_EVENT_TAG, "setState -- start: " + newState);
}
if (DBG) {
Log.d(TAG, "setState:" + mState + "->" + newState);
}
@@ -168,9 +165,6 @@ public class SwipeDetector {
if (newState == ScrollState.DRAGGING) {
initializeDragging();
if (mState == ScrollState.IDLE) {
if (TestProtocol.sDebugTracing) {
Log.d(TestProtocol.NO_ALLAPPS_EVENT_TAG, "setState -- 1: " + newState);
}
reportDragStart(false /* recatch */);
} else if (mState == ScrollState.SETTLING) {
reportDragStart(true /* recatch */);
@@ -181,11 +175,6 @@ public class SwipeDetector {
}
mState = newState;
if (com.android.launcher3.testing.TestProtocol.sDebugTracing) {
android.util.Log.e(TestProtocol.NO_ALLAPPS_EVENT_TAG,
"setState: " + newState + " @ " + android.util.Log.getStackTraceString(
new Throwable()));
}
}
public boolean isDraggingOrSettling() {
@@ -324,15 +313,9 @@ public class SwipeDetector {
break;
}
mDisplacement = mDir.getDisplacement(ev, pointerIndex, mDownPos, mIsRtl);
if (TestProtocol.sDebugTracing) {
Log.d(TestProtocol.NO_ALLAPPS_EVENT_TAG, "onTouchEvent 1");
}
// handle state and listener calls.
if (mState != ScrollState.DRAGGING && shouldScrollStart(ev, pointerIndex)) {
if (TestProtocol.sDebugTracing) {
Log.d(TestProtocol.NO_ALLAPPS_EVENT_TAG, "onTouchEvent 2");
}
setState(ScrollState.DRAGGING);
}
if (mState == ScrollState.DRAGGING) {
@@ -152,9 +152,6 @@ public abstract class BaseDragLayer<T extends Context & ActivityContext>
}
private TouchController findControllerToHandleTouch(MotionEvent ev) {
if (TestProtocol.sDebugTracing) {
Log.d(TestProtocol.EVENTS_TO_OVERVIEW_MISSING_TAG, "findControllerToHandleTouch " + ev);
}
if (shouldDisableGestures(ev)) return null;
AbstractFloatingView topView = AbstractFloatingView.getTopOpenView(mActivity);
@@ -233,10 +230,6 @@ public abstract class BaseDragLayer<T extends Context & ActivityContext>
@Override
public boolean onTouchEvent(MotionEvent ev) {
if (TestProtocol.sDebugTracing) {
android.util.Log.d(TestProtocol.NO_DRAG_TAG,
"onTouchEvent " + ev);
}
int action = ev.getAction();
if (action == ACTION_UP || action == ACTION_CANCEL) {
if (mTouchCompleteListener != null) {
@@ -246,10 +239,6 @@ public abstract class BaseDragLayer<T extends Context & ActivityContext>
}
if (mActiveController != null) {
if (TestProtocol.sDebugTracing) {
android.util.Log.d(TestProtocol.NO_DRAG_TAG,
"onTouchEvent 1");
}
return mActiveController.onControllerTouchEvent(ev);
} else {
// In case no child view handled the touch event, we may not get onIntercept anymore
@@ -259,9 +248,6 @@ public abstract class BaseDragLayer<T extends Context & ActivityContext>
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
if (TestProtocol.sDebugTracing) {
Log.d(TestProtocol.NO_START_TAG, "BaseDragLayer.dispatchTouchEvent " + ev);
}
switch (ev.getAction()) {
case ACTION_DOWN: {
float x = ev.getX();
@@ -315,9 +301,6 @@ public abstract class BaseDragLayer<T extends Context & ActivityContext>
* Proxies the touch events to the gesture handlers
*/
public boolean proxyTouchEvent(MotionEvent ev) {
if (TestProtocol.sDebugTracing) {
Log.d(TestProtocol.EVENTS_TO_OVERVIEW_MISSING_TAG, "proxyTouchEvent " + ev);
}
boolean handled;
if (mProxyTouchController != null) {
handled = mProxyTouchController.onControllerTouchEvent(ev);
@@ -18,6 +18,7 @@ package com.android.launcher3.views;
import static com.android.launcher3.LauncherAnimUtils.DRAWABLE_ALPHA;
import static com.android.launcher3.Utilities.getBadge;
import static com.android.launcher3.Utilities.getFullDrawable;
import static com.android.launcher3.Utilities.isRtl;
import static com.android.launcher3.Utilities.mapToRange;
import static com.android.launcher3.anim.Interpolators.LINEAR;
import static com.android.launcher3.config.FeatureFlags.ADAPTIVE_ICON_WINDOW_ANIM;
@@ -129,6 +130,7 @@ public class FloatingIconView extends View implements
private final Launcher mLauncher;
private final int mBlurSizeOutline;
private final boolean mIsRtl;
private boolean mIsVerticalBarLayout = false;
private boolean mIsAdaptiveIcon = false;
@@ -174,6 +176,7 @@ public class FloatingIconView extends View implements
mLauncher = Launcher.getLauncher(context);
mBlurSizeOutline = getResources().getDimensionPixelSize(
R.dimen.blur_size_medium_outline);
mIsRtl = Utilities.isRtl(getResources());
mListenerView = new ListenerView(context, attrs);
mFgSpringX = new SpringAnimation(this, mFgTransXProperty)
@@ -213,7 +216,10 @@ public class FloatingIconView extends View implements
setAlpha(alpha);
LayoutParams lp = (LayoutParams) getLayoutParams();
float dX = rect.left - lp.leftMargin;
float dX = mIsRtl
? rect.left
- (mLauncher.getDeviceProfile().widthPx - lp.getMarginStart() - lp.width)
: rect.left - lp.getMarginStart();
float dY = rect.top - lp.topMargin;
setTranslationX(dX);
setTranslationY(dY);
@@ -323,14 +329,18 @@ public class FloatingIconView extends View implements
mPositionOut.set(position);
lp.ignoreInsets = true;
// Position the floating view exactly on top of the original
lp.leftMargin = Math.round(position.left);
lp.topMargin = Math.round(position.top);
if (mIsRtl) {
lp.setMarginStart(Math.round(mLauncher.getDeviceProfile().widthPx - position.right));
} else {
lp.setMarginStart(Math.round(position.left));
}
// Set the properties here already to make sure they are available when running the first
// animation frame.
layout(lp.leftMargin, lp.topMargin, lp.leftMargin + lp.width, lp.topMargin
+ lp.height);
int left = mIsRtl
? mLauncher.getDeviceProfile().widthPx - lp.getMarginStart() - lp.width
: lp.leftMargin;
layout(left, lp.topMargin, left + lp.width, lp.topMargin + lp.height);
}
/**
@@ -514,8 +524,11 @@ public class FloatingIconView extends View implements
} else {
lp.height = (int) Math.max(lp.height, lp.width * aspectRatio);
}
layout(lp.leftMargin, lp.topMargin, lp.leftMargin + lp.width, lp.topMargin
+ lp.height);
int left = mIsRtl
? mLauncher.getDeviceProfile().widthPx - lp.getMarginStart() - lp.width
: lp.leftMargin;
layout(left, lp.topMargin, left + lp.width, lp.topMargin + lp.height);
float scale = Math.max((float) lp.height / originalHeight,
(float) lp.width / originalWidth);
@@ -656,8 +669,7 @@ public class FloatingIconView extends View implements
canvas.restoreToCount(count);
}
public void onListenerViewClosed() {
// Fast finish here.
public void fastFinish() {
if (mEndRunnable != null) {
mEndRunnable.run();
mEndRunnable = null;
@@ -757,7 +769,7 @@ public class FloatingIconView extends View implements
view.setVisibility(INVISIBLE);
parent.addView(view);
dragLayer.addView(view.mListenerView);
view.mListenerView.setListener(view::onListenerViewClosed);
view.mListenerView.setListener(view::fastFinish);
view.mEndRunnable = () -> {
view.mEndRunnable = null;
@@ -32,13 +32,14 @@ import android.os.Bundle;
import android.os.ParcelFileDescriptor;
import android.util.Base64;
import androidx.test.InstrumentationRegistry;
import com.android.launcher3.tapl.TestHelpers;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import androidx.test.InstrumentationRegistry;
/**
* Content provider to receive commands from tests
*/
@@ -47,6 +48,7 @@ public class TestCommandReceiver extends ContentProvider {
public static final String ENABLE_TEST_LAUNCHER = "enable-test-launcher";
public static final String DISABLE_TEST_LAUNCHER = "disable-test-launcher";
public static final String KILL_PROCESS = "kill-process";
public static final String GET_SYSTEM_HEALTH_MESSAGE = "get-system-health-message";
@Override
public boolean onCreate() {
@@ -99,6 +101,12 @@ public class TestCommandReceiver extends ContentProvider {
killBackgroundProcesses(arg);
return null;
}
case GET_SYSTEM_HEALTH_MESSAGE: {
final Bundle response = new Bundle();
response.putString("result", TestHelpers.getSystemHealthMessage(getContext()));
return response;
}
}
return super.call(method, arg, extras);
}
@@ -122,7 +130,8 @@ public class TestCommandReceiver extends ContentProvider {
// Create an empty file so that we can pass its descriptor
try {
file.createNewFile();
} catch (IOException e) { }
} catch (IOException e) {
}
}
return ParcelFileDescriptor.open(file, MODE_READ_WRITE);
@@ -51,6 +51,7 @@ import com.android.launcher3.compat.LauncherAppsCompat;
import com.android.launcher3.model.AppLaunchTracker;
import com.android.launcher3.tapl.LauncherInstrumentation;
import com.android.launcher3.tapl.TestHelpers;
import com.android.launcher3.testcomponent.TestCommandReceiver;
import com.android.launcher3.util.PackageManagerHelper;
import com.android.launcher3.util.Wait;
import com.android.launcher3.util.rule.FailureWatcher;
@@ -98,7 +99,11 @@ public abstract class AbstractLauncherUiTest {
} catch (RemoteException e) {
throw new RuntimeException(e);
}
if (TestHelpers.isInLauncherProcess()) Utilities.enableRunningInTestHarnessForTests();
if (TestHelpers.isInLauncherProcess()) {
Utilities.enableRunningInTestHarnessForTests();
mLauncher.setSystemHealthSupplier(() -> TestCommandReceiver.callCommand(
TestCommandReceiver.GET_SYSTEM_HEALTH_MESSAGE).getString("result"));
}
}
protected final LauncherActivityRule mActivityMonitor = new LauncherActivityRule();
@@ -72,7 +72,7 @@ public class DefaultLayoutProviderTest extends AbstractLauncherUiTest {
writeLayout(new LauncherLayoutBuilder().atHotseat(0).putApp(SETTINGS_APP, SETTINGS_APP));
// Launch the home activity
mActivityMonitor.startLauncher();
mDevice.pressHome();
waitForModelLoaded();
mLauncher.getWorkspace().getHotseatAppIcon(getSettingsApp().getLabel().toString());
@@ -88,7 +88,7 @@ public class DefaultLayoutProviderTest extends AbstractLauncherUiTest {
info.getComponent().getClassName(), 2, 2));
// Launch the home activity
mActivityMonitor.startLauncher();
mDevice.pressHome();
waitForModelLoaded();
// Verify widget present
@@ -105,7 +105,7 @@ public class DefaultLayoutProviderTest extends AbstractLauncherUiTest {
.build());
// Launch the home activity
mActivityMonitor.startLauncher();
mDevice.pressHome();
waitForModelLoaded();
mLauncher.getWorkspace().getHotseatFolder("Folder: Copy");
@@ -53,8 +53,8 @@ public class WorkTabTest extends AbstractLauncherUiTest {
@Test
public void workTabExists() {
mActivityMonitor.startLauncher();
mDevice.pressHome();
waitForLauncherCondition("Launcher didn't start", launcher -> launcher != null);
executeOnLauncher(launcher -> launcher.getStateManager().goToState(ALL_APPS));
/*
@@ -98,7 +98,7 @@ public class AddConfigWidgetTest extends AbstractLauncherUiTest {
lockRotation(true);
clearHomescreen();
mActivityMonitor.startLauncher();
mDevice.pressHome();
final Widgets widgets = mLauncher.getWorkspace().openAllWidgets();
@@ -55,7 +55,7 @@ public class AddWidgetTest extends AbstractLauncherUiTest {
private void performTest() throws Throwable {
clearHomescreen();
mActivityMonitor.startLauncher();
mDevice.pressHome();
final LauncherAppWidgetProviderInfo widgetInfo =
TestViewHelpers.findWidgetProvider(this, false /* hasConfigureScreen */);
@@ -267,7 +267,7 @@ public class BindWidgetTest extends AbstractLauncherUiTest {
resetLoaderState();
// Launch the home activity
mActivityMonitor.startLauncher();
mDevice.pressHome();
waitForModelLoaded();
}
@@ -131,7 +131,7 @@ public class RequestPinItemTest extends AbstractLauncherUiTest {
lockRotation(true);
clearHomescreen();
mActivityMonitor.startLauncher();
mDevice.pressHome();
// Open Pin item activity
BlockingBroadcastReceiver openMonitor = new BlockingBroadcastReceiver(
@@ -15,11 +15,6 @@
*/
package com.android.launcher3.util.rule;
import static com.android.launcher3.tapl.TestHelpers.getHomeIntentInPackage;
import static androidx.test.InstrumentationRegistry.getInstrumentation;
import static androidx.test.InstrumentationRegistry.getTargetContext;
import android.app.Activity;
import android.app.Application;
import android.app.Application.ActivityLifecycleCallbacks;
@@ -52,26 +47,15 @@ public class LauncherActivityRule implements TestRule {
}
public Callable<Boolean> itemExists(final ItemOperator op) {
return new Callable<Boolean>() {
@Override
public Boolean call() throws Exception {
Launcher launcher = getActivity();
if (launcher == null) {
return false;
}
return launcher.getWorkspace().getFirstMatch(op) != null;
return () -> {
Launcher launcher = getActivity();
if (launcher == null) {
return false;
}
return launcher.getWorkspace().getFirstMatch(op) != null;
};
}
/**
* Starts the launcher activity in the target package.
*/
public void startLauncher() {
getInstrumentation().startActivitySync(getHomeIntentInPackage(getTargetContext()));
}
private class MyStatement extends Statement implements ActivityLifecycleCallbacks {
private final Statement mBase;
@@ -181,7 +181,6 @@ public class AllApps extends LauncherInstrumentation.VisibleContainer {
* Flings backward (up) and waits the fling's end.
*/
public void flingBackward() {
mLauncher.getTestInfo(TestProtocol.REQUEST_ENABLE_DEBUG_TRACING);
try (LauncherInstrumentation.Closable c =
mLauncher.addContextLayer("want to fling backward in all apps")) {
final UiObject2 allAppsContainer = verifyActiveContainer();
@@ -190,7 +189,6 @@ public class AllApps extends LauncherInstrumentation.VisibleContainer {
allAppsContainer, Direction.UP, 1, new Rect(0, mHeight / 2, 0, 0), 10);
verifyActiveContainer();
}
mLauncher.getTestInfo(TestProtocol.REQUEST_DISABLE_DEBUG_TRACING);
}
/**
@@ -59,7 +59,6 @@ public class Background extends LauncherInstrumentation.VisibleContainer {
}
protected void goToOverviewUnchecked(int expectedState) {
mLauncher.getTestInfo(TestProtocol.REQUEST_ENABLE_DEBUG_TRACING);
switch (mLauncher.getNavigationModel()) {
case ZERO_BUTTON: {
final int centerX = mLauncher.getDevice().getDisplayWidth() / 2;
@@ -112,7 +111,6 @@ public class Background extends LauncherInstrumentation.VisibleContainer {
mLauncher.waitForSystemUiObject("recent_apps").click();
break;
}
mLauncher.getTestInfo(TestProtocol.REQUEST_DISABLE_DEBUG_TRACING);
}
protected String getSwipeHeightRequestName() {
@@ -16,11 +16,15 @@
package com.android.launcher3.tapl;
import android.graphics.Rect;
import androidx.annotation.NonNull;
import androidx.test.uiautomator.BySelector;
import androidx.test.uiautomator.Direction;
import androidx.test.uiautomator.UiObject2;
import com.android.launcher3.testing.TestProtocol;
import java.util.Collections;
import java.util.List;
@@ -28,7 +32,6 @@ import java.util.List;
* Common overview pane for both Launcher and fallback recents
*/
public class BaseOverview extends LauncherInstrumentation.VisibleContainer {
private static final int FLING_SPEED = LauncherInstrumentation.isAvd() ? 500 : 1500;
private static final int FLINGS_FOR_DISMISS_LIMIT = 40;
BaseOverview(LauncherInstrumentation launcher) {
@@ -49,9 +52,10 @@ public class BaseOverview extends LauncherInstrumentation.VisibleContainer {
mLauncher.addContextLayer("want to fling forward in overview")) {
LauncherInstrumentation.log("Overview.flingForward before fling");
final UiObject2 overview = verifyActiveContainer();
overview.setGestureMargins(mLauncher.getEdgeSensitivityWidth(), 0, 0, 0);
overview.fling(Direction.LEFT, (int) (FLING_SPEED * mLauncher.getDisplayDensity()));
mLauncher.waitForIdle();
final int leftMargin = mLauncher.getTestInfo(
TestProtocol.REQUEST_OVERVIEW_LEFT_GESTURE_MARGIN).
getInt(TestProtocol.TEST_INFO_RESPONSE_FIELD);
mLauncher.scroll(overview, Direction.LEFT, 1, new Rect(leftMargin, 0, 0, 0), 20);
verifyActiveContainer();
}
}
@@ -86,9 +90,10 @@ public class BaseOverview extends LauncherInstrumentation.VisibleContainer {
mLauncher.addContextLayer("want to fling backward in overview")) {
LauncherInstrumentation.log("Overview.flingBackward before fling");
final UiObject2 overview = verifyActiveContainer();
overview.setGestureMargins(0, 0, mLauncher.getEdgeSensitivityWidth(), 0);
overview.fling(Direction.RIGHT, (int) (FLING_SPEED * mLauncher.getDisplayDensity()));
mLauncher.waitForIdle();
final int rightMargin = mLauncher.getTestInfo(
TestProtocol.REQUEST_OVERVIEW_RIGHT_GESTURE_MARGIN).
getInt(TestProtocol.TEST_INFO_RESPONSE_FIELD);
mLauncher.scroll(overview, Direction.RIGHT, 1, new Rect(0, 0, rightMargin, 0), 20);
verifyActiveContainer();
}
}
@@ -53,11 +53,9 @@ abstract class Launchable {
private Background launch(BySelector selector) {
LauncherInstrumentation.log("Launchable.launch before click " +
mObject.getVisibleCenter() + " in " + mObject.getVisibleBounds());
mLauncher.getTestInfo(TestProtocol.REQUEST_ENABLE_DEBUG_TRACING);
mLauncher.assertTrue(
"Launching an app didn't open a new window: " + mObject.getText(),
mObject.clickAndWait(Until.newWindow(), WAIT_TIME_MS));
mLauncher.getTestInfo(TestProtocol.REQUEST_DISABLE_DEBUG_TRACING);
mLauncher.assertTrue(
"App didn't start: " + selector,
mLauncher.getDevice().wait(Until.hasObject(selector),
@@ -39,7 +39,6 @@ import android.graphics.Rect;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.DropBoxManager;
import android.os.Parcelable;
import android.os.SystemClock;
import android.text.TextUtils;
@@ -73,6 +72,7 @@ import java.util.Deque;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.TimeoutException;
import java.util.function.Supplier;
/**
* The main tapl object. The only object that can be explicitly constructed by the using code. It
@@ -133,6 +133,7 @@ public final class LauncherInstrumentation {
private int mExpectedRotation = Surface.ROTATION_0;
private final Uri mTestProviderUri;
private final Deque<String> mDiagnosticContext = new LinkedList<>();
private Supplier<String> mSystemHealthSupplier;
/**
* Constructs the root of TAPL hierarchy. You get all other objects from it.
@@ -207,7 +208,7 @@ public final class LauncherInstrumentation {
try {
// Workaround, use constructed context because both the instrumentation context and the
// app context are not constructed with resources that take overlays into account
final Context ctx = baseContext.createPackageContext("android", 0);
final Context ctx = baseContext.createPackageContext(getLauncherPackageName(), 0);
for (int i = 0; i < 100; ++i) {
final int currentInteractionMode = getCurrentInteractionMode(ctx);
final NavigationModel model = getNavigationModel(currentInteractionMode);
@@ -265,11 +266,17 @@ public final class LauncherInstrumentation {
}
private String getAnomalyMessage() {
final UiObject2 object = mDevice.findObject(By.res("android", "alertTitle"));
UiObject2 object = mDevice.findObject(By.res("android", "alertTitle"));
if (object != null) {
return "System alert popup is visible: " + object.getText();
}
object = mDevice.findObject(By.res("android", "message"));
if (object != null) {
return "Message popup by " + object.getApplicationPackage() + " is visible: "
+ object.getText();
}
if (hasSystemUiObject("keyguard_status_view")) return "Phone is locked";
if (!mDevice.hasObject(By.textStartsWith(""))) return "Screen is empty";
@@ -285,79 +292,24 @@ public final class LauncherInstrumentation {
return "Background";
}
private static String truncateCrash(String text, int maxLines) {
String[] lines = text.split("\\r?\\n");
StringBuilder ret = new StringBuilder();
for (int i = 0; i < maxLines && i < lines.length; i++) {
ret.append(lines[i]);
ret.append('\n');
}
if (lines.length > maxLines) {
ret.append("... ");
ret.append(lines.length - maxLines);
ret.append(" more lines truncated ...\n");
}
return ret.toString();
}
private String checkCrash(String label) {
DropBoxManager dropbox = (DropBoxManager) getContext().getSystemService(
Context.DROPBOX_SERVICE);
Assert.assertNotNull("Unable access the DropBoxManager service", dropbox);
long timestamp = 0;
DropBoxManager.Entry entry;
int crashCount = 0;
StringBuilder errorDetails = new StringBuilder();
while (null != (entry = dropbox.getNextEntry(label, timestamp))) {
String dropboxSnippet;
try {
dropboxSnippet = entry.getText(4096);
} finally {
entry.close();
}
crashCount++;
errorDetails.append(label);
errorDetails.append(": ");
errorDetails.append(truncateCrash(dropboxSnippet, 40));
errorDetails.append(" ...\n");
timestamp = entry.getTimeMillis();
}
Assert.assertEquals(errorDetails.toString(), 0, crashCount);
return crashCount > 0 ? errorDetails.toString() : null;
public void setSystemHealthSupplier(Supplier<String> supplier) {
this.mSystemHealthSupplier = supplier;
}
private String getSystemHealthMessage() {
final String testPackage = getContext().getPackageName();
try {
StringBuilder errors = new StringBuilder();
final String testPackage = getContext().getPackageName();
try {
mDevice.executeShellCommand("pm grant " + testPackage +
" android.permission.READ_LOGS");
mDevice.executeShellCommand("pm grant " + testPackage +
" android.permission.PACKAGE_USAGE_STATS");
} catch (IOException e) {
e.printStackTrace();
}
final String[] labels = {
"system_server_crash",
"system_server_native_crash",
"system_server_anr",
};
for (String label : labels) {
final String crash = checkCrash(label);
if (crash != null) errors.append(crash);
}
return errors.length() != 0 ? errors.toString() : null;
} catch (Exception e) {
return null;
mDevice.executeShellCommand("pm grant " + testPackage +
" android.permission.READ_LOGS");
mDevice.executeShellCommand("pm grant " + testPackage +
" android.permission.PACKAGE_USAGE_STATS");
} catch (IOException e) {
e.printStackTrace();
}
return mSystemHealthSupplier != null
? mSystemHealthSupplier.get()
: TestHelpers.getSystemHealthMessage(getContext());
}
private void fail(String message) {
@@ -444,6 +396,8 @@ public final class LauncherInstrumentation {
}
private UiObject2 verifyContainerType(ContainerType containerType) {
//waitForTouchInteractionService();
assertEquals("Unexpected display rotation",
mExpectedRotation, mDevice.getDisplayRotation());
@@ -514,6 +468,18 @@ public final class LauncherInstrumentation {
}
}
private void waitForTouchInteractionService() {
for (int i = 0; i < 100; ++i) {
if (getTestInfo(
TestProtocol.REQUEST_IS_LAUNCHER_INITIALIZED).
getBoolean(TestProtocol.TEST_INFO_RESPONSE_FIELD)) {
return;
}
SystemClock.sleep(100);
}
fail("TouchInteractionService didn't connect");
}
Parcelable executeAndWaitForEvent(Runnable command,
UiAutomation.AccessibilityEventFilter eventFilter, String message) {
try {
@@ -816,10 +782,26 @@ public final class LauncherInstrumentation {
startX = endX = rect.centerX();
final int vertCenter = rect.centerY();
final float halfGestureHeight = rect.height() * percent / 2.0f;
startY = (int) (vertCenter + halfGestureHeight);
startY = (int) (vertCenter + halfGestureHeight) - 1;
endY = (int) (vertCenter - halfGestureHeight);
}
break;
case LEFT: {
startY = endY = rect.centerY();
final int horizCenter = rect.centerX();
final float halfGestureWidth = rect.width() * percent / 2.0f;
startX = (int) (horizCenter - halfGestureWidth);
endX = (int) (horizCenter + halfGestureWidth);
}
break;
case RIGHT: {
startY = endY = rect.centerY();
final int horizCenter = rect.centerX();
final float halfGestureWidth = rect.width() * percent / 2.0f;
startX = (int) (horizCenter + halfGestureWidth) - 1;
endX = (int) (horizCenter - halfGestureWidth);
}
break;
default:
fail("Unsupported direction");
return;
@@ -936,7 +918,7 @@ public final class LauncherInstrumentation {
int getEdgeSensitivityWidth() {
try {
final Context context = mInstrumentation.getTargetContext().createPackageContext(
"android", 0);
getLauncherPackageName(), 0);
return context.getResources().getDimensionPixelSize(
getSystemDimensionResId(context, "config_backGestureInset")) + 1;
} catch (PackageManager.NameNotFoundException e) {
@@ -19,9 +19,9 @@ package com.android.launcher3.tapl;
import static com.android.launcher3.testing.TestProtocol.ALL_APPS_STATE_ORDINAL;
import androidx.annotation.NonNull;
import androidx.test.uiautomator.UiObject2;
import com.android.launcher3.tapl.LauncherInstrumentation.ContainerType;
import com.android.launcher3.testing.TestProtocol;
/**
* Overview pane.
@@ -51,11 +51,15 @@ public final class Overview extends BaseOverview {
// Swipe from an app icon to the top.
LauncherInstrumentation.log("Overview.switchToAllApps before swipe");
final UiObject2 allApps = mLauncher.waitForLauncherObject("apps_view");
mLauncher.swipeToState(mLauncher.getDevice().getDisplayWidth() / 2,
allApps.getVisibleBounds().top,
mLauncher.swipeToState(
mLauncher.getDevice().getDisplayWidth() / 2,
0, 50, ALL_APPS_STATE_ORDINAL);
mLauncher.getTestInfo(
TestProtocol.REQUEST_HOTSEAT_TOP).
getInt(TestProtocol.TEST_INFO_RESPONSE_FIELD),
mLauncher.getDevice().getDisplayWidth() / 2,
0,
50,
ALL_APPS_STATE_ORDINAL);
try (LauncherInstrumentation.Closable c1 = mLauncher.addContextLayer(
"swiped all way up from overview")) {
@@ -64,14 +64,12 @@ public final class OverviewTask {
*/
public Background open() {
verifyActiveContainer();
mLauncher.getTestInfo(TestProtocol.REQUEST_ENABLE_DEBUG_TRACING);
try (LauncherInstrumentation.Closable c = mLauncher.addContextLayer(
"clicking an overview task")) {
mLauncher.assertTrue("Launching task didn't open a new window: " +
mTask.getParent().getContentDescription(),
mTask.clickAndWait(Until.newWindow(), WAIT_TIME_MS));
}
mLauncher.getTestInfo(TestProtocol.REQUEST_DISABLE_DEBUG_TRACING);
return new Background(mLauncher);
}
}
@@ -26,6 +26,9 @@ import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.content.pm.ResolveInfo;
import android.content.res.Resources;
import android.os.DropBoxManager;
import org.junit.Assert;
import java.util.List;
@@ -81,4 +84,69 @@ public class TestHelpers {
}
return "com.android.systemui";
}
private static String truncateCrash(String text, int maxLines) {
String[] lines = text.split("\\r?\\n");
StringBuilder ret = new StringBuilder();
for (int i = 0; i < maxLines && i < lines.length; i++) {
ret.append(lines[i]);
ret.append('\n');
}
if (lines.length > maxLines) {
ret.append("... ");
ret.append(lines.length - maxLines);
ret.append(" more lines truncated ...\n");
}
return ret.toString();
}
private static String checkCrash(Context context, String label) {
DropBoxManager dropbox = (DropBoxManager) context.getSystemService(Context.DROPBOX_SERVICE);
Assert.assertNotNull("Unable access the DropBoxManager service", dropbox);
long timestamp = 0;
DropBoxManager.Entry entry;
int crashCount = 0;
StringBuilder errorDetails = new StringBuilder();
while (null != (entry = dropbox.getNextEntry(label, timestamp))) {
String dropboxSnippet;
try {
dropboxSnippet = entry.getText(4096);
} finally {
entry.close();
}
crashCount++;
errorDetails.append(label);
errorDetails.append(": ");
errorDetails.append(truncateCrash(dropboxSnippet, 40));
errorDetails.append(" ...\n");
timestamp = entry.getTimeMillis();
}
Assert.assertEquals(errorDetails.toString(), 0, crashCount);
return crashCount > 0 ? errorDetails.toString() : null;
}
public static String getSystemHealthMessage(Context context) {
try {
StringBuilder errors = new StringBuilder();
final String[] labels = {
"system_server_crash",
"system_server_native_crash",
"system_server_anr",
};
for (String label : labels) {
final String crash = checkCrash(context, label);
if (crash != null) errors.append(crash);
}
return errors.length() != 0 ? errors.toString() : null;
} catch (Exception e) {
return "Failed to get system health diags, maybe build your test via .bp instead of "
+ ".mk? " + android.util.Log.getStackTraceString(e);
}
}
}
@@ -67,7 +67,6 @@ public final class Workspace extends Home {
"switchToAllApps: swipeHeight = " + swipeHeight + ", slop = "
+ mLauncher.getTouchSlop());
mLauncher.getTestInfo(TestProtocol.REQUEST_ENABLE_DEBUG_TRACING);
mLauncher.swipeToState(
start.x,
start.y,
@@ -75,7 +74,6 @@ public final class Workspace extends Home {
start.y - swipeHeight - mLauncher.getTouchSlop(),
60,
ALL_APPS_STATE_ORDINAL);
mLauncher.getTestInfo(TestProtocol.REQUEST_DISABLE_DEBUG_TRACING);
try (LauncherInstrumentation.Closable c1 = mLauncher.addContextLayer(
"swiped to all apps")) {
@@ -157,7 +155,6 @@ public final class Workspace extends Home {
static void dragIconToWorkspace(
LauncherInstrumentation launcher, Launchable launchable, Point dest,
String longPressIndicator) {
launcher.getTestInfo(TestProtocol.REQUEST_ENABLE_DEBUG_TRACING);
LauncherInstrumentation.log("dragIconToWorkspace: begin");
final Point launchableCenter = launchable.getObject().getVisibleCenter();
final long downTime = SystemClock.uptimeMillis();
@@ -172,7 +169,6 @@ public final class Workspace extends Home {
downTime, SystemClock.uptimeMillis(), MotionEvent.ACTION_UP, dest);
LauncherInstrumentation.log("dragIconToWorkspace: end");
launcher.waitUntilGone("drop_target_bar");
launcher.getTestInfo(TestProtocol.REQUEST_DISABLE_DEBUG_TRACING);
}
/**