Merging from ub-launcher3-rvc-qpr-dev @ build 6690853

Bug:150504032
Test: manual, presubmit on the source branch
x20/teams/android-launcher/merge/ub-launcher3-rvc-qpr-dev-rvc-qpr-dev_6690853.html

Change-Id: Ie86b0a2e0d82646a0c3d44a0214cbb985435320d
Merged-In: Ibff46b3ef7ff89accb459db323f31179adb4ef21
This commit is contained in:
Hyunyoung Song
2020-07-23 03:47:06 +00:00
102 changed files with 1499 additions and 1229 deletions
@@ -157,6 +157,12 @@ public abstract class BaseQuickstepLauncher extends Launcher
@Override
protected void onDeferredResumed() {
super.onDeferredResumed();
handlePendingActivityRequest();
}
@Override
protected void handlePendingActivityRequest() {
super.handlePendingActivityRequest();
if (mPendingActivityRequestCode != -1 && isInState(NORMAL)) {
// Remove any active ProxyActivityStarter task and send RESULT_CANCELED to Launcher.
onActivityResult(mPendingActivityRequestCode, RESULT_CANCELED, null);
@@ -16,8 +16,6 @@
package com.android.launcher3;
import static android.util.TypedValue.COMPLEX_UNIT_DIP;
import static com.android.launcher3.BaseActivity.INVISIBLE_ALL;
import static com.android.launcher3.BaseActivity.INVISIBLE_BY_APP_TRANSITIONS;
import static com.android.launcher3.BaseActivity.INVISIBLE_BY_PENDING_FLAGS;
@@ -62,7 +60,6 @@ import android.os.CancellationSignal;
import android.os.Handler;
import android.os.Looper;
import android.util.Pair;
import android.util.TypedValue;
import android.view.View;
import androidx.annotation.NonNull;
@@ -879,10 +876,8 @@ public abstract class QuickstepAppTransitionManagerImpl extends LauncherAppTrans
}
});
} else {
float velocityDpPerS = DynamicResource.provider(mLauncher)
float velocityPxPerS = DynamicResource.provider(mLauncher)
.getDimension(R.dimen.unlock_staggered_velocity_dp_per_s);
float velocityPxPerS = TypedValue.applyDimension(COMPLEX_UNIT_DIP,
velocityDpPerS, mLauncher.getResources().getDisplayMetrics());
anim.play(new StaggeredWorkspaceAnim(mLauncher, velocityPxPerS, false)
.getAnimators());
}
@@ -150,16 +150,9 @@ public abstract class BaseActivityInterface<STATE_TYPE extends BaseState<STATE_T
return deviceState.isInDeferredGestureRegion(ev);
}
public abstract void onExitOverview(RecentsAnimationDeviceState deviceState,
public abstract void onExitOverview(RotationTouchHelper deviceState,
Runnable exitRunnable);
/**
* Updates the prediction state to the overview state.
*/
public void updateOverviewPredictionState() {
// By public overview predictions are not supported
}
/**
* Used for containerType in {@link com.android.launcher3.logging.UserEventDispatcher}
*/
@@ -16,11 +16,9 @@
package com.android.quickstep;
import static android.content.Intent.ACTION_USER_UNLOCKED;
import static android.view.Surface.ROTATION_0;
import static com.android.launcher3.util.DefaultDisplay.CHANGE_ALL;
import static com.android.launcher3.util.DefaultDisplay.CHANGE_FRAME_DELAY;
import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
import static com.android.quickstep.SysUINavigationMode.Mode.NO_BUTTON;
import static com.android.quickstep.SysUINavigationMode.Mode.THREE_BUTTONS;
import static com.android.quickstep.SysUINavigationMode.Mode.TWO_BUTTONS;
@@ -49,23 +47,19 @@ import android.os.UserManager;
import android.provider.Settings;
import android.text.TextUtils;
import android.view.MotionEvent;
import android.view.OrientationEventListener;
import androidx.annotation.BinderThread;
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
import com.android.launcher3.testing.TestProtocol;
import com.android.launcher3.util.DefaultDisplay;
import com.android.launcher3.util.SecureSettingsObserver;
import com.android.quickstep.SysUINavigationMode.NavigationModeChangeListener;
import com.android.quickstep.util.NavBarPosition;
import com.android.quickstep.util.RecentsOrientedState;
import com.android.systemui.shared.system.ActivityManagerWrapper;
import com.android.systemui.shared.system.QuickStepContract;
import com.android.systemui.shared.system.QuickStepContract.SystemUiStateFlags;
import com.android.systemui.shared.system.SystemGestureExclusionListenerCompat;
import com.android.systemui.shared.system.TaskStackChangeListener;
import java.io.PrintWriter;
import java.util.ArrayList;
@@ -83,7 +77,7 @@ public class RecentsAnimationDeviceState implements
private final SysUINavigationMode mSysUiNavMode;
private final DefaultDisplay mDefaultDisplay;
private final int mDisplayId;
private int mDisplayRotation;
private final RotationTouchHelper mRotationTouchHelper;
private final ArrayList<Runnable> mOnDestroyActions = new ArrayList<>();
@@ -107,76 +101,10 @@ public class RecentsAnimationDeviceState implements
}
};
private TaskStackChangeListener mFrozenTaskListener = new TaskStackChangeListener() {
@Override
public void onRecentTaskListFrozenChanged(boolean frozen) {
mTaskListFrozen = frozen;
if (frozen || mInOverview) {
return;
}
enableMultipleRegions(false);
}
@Override
public void onActivityRotation(int displayId) {
super.onActivityRotation(displayId);
// This always gets called before onDisplayInfoChanged() so we know how to process
// the rotation in that method. This is done to avoid having a race condition between
// the sensor readings and onDisplayInfoChanged() call
if (displayId != mDisplayId) {
return;
}
mPrioritizeDeviceRotation = true;
if (mInOverview) {
// reset, launcher must be rotating
mExitOverviewRunnable.run();
}
}
};
private Runnable mExitOverviewRunnable = new Runnable() {
@Override
public void run() {
mInOverview = false;
enableMultipleRegions(false);
}
};
private OrientationTouchTransformer mOrientationTouchTransformer;
/**
* Used to listen for when the device rotates into the orientation of the current
* foreground app. For example, if a user quickswitches from a portrait to a fixed landscape
* app and then rotates rotates the device to match that orientation, this triggers calls to
* sysui to adjust the navbar.
*/
private OrientationEventListener mOrientationListener;
private int mSensorRotation = ROTATION_0;
/**
* This is the configuration of the foreground app or the app that will be in the foreground
* once a quickstep gesture finishes.
*/
private int mCurrentAppRotation = -1;
/**
* This flag is set to true when the device physically changes orientations. When true,
* we will always report the current rotation of the foreground app whenever the display
* changes, as it would indicate the user's intention to rotate the foreground app.
*/
private boolean mPrioritizeDeviceRotation = false;
private Region mExclusionRegion;
private SystemGestureExclusionListenerCompat mExclusionListener;
private final List<ComponentName> mGestureBlockedActivities;
private Runnable mOnDestroyFrozenTaskRunnable;
/**
* Set to true when user swipes to recents. In recents, we ignore the state of the recents
* task list being frozen or not to allow the user to keep interacting with nav bar rotation
* they went into recents with as opposed to defaulting to the default display rotation.
* TODO: (b/156984037) For when user rotates after entering overview
*/
private boolean mInOverview;
private boolean mTaskListFrozen;
private boolean mIsUserSetupComplete;
@@ -186,6 +114,8 @@ public class RecentsAnimationDeviceState implements
mDefaultDisplay = DefaultDisplay.INSTANCE.get(context);
mDisplayId = mDefaultDisplay.getInfo().id;
runOnDestroy(() -> mDefaultDisplay.removeChangeListener(this));
mRotationTouchHelper = RotationTouchHelper.INSTANCE.get(context);
runOnDestroy(mRotationTouchHelper::destroy);
// Register for user unlocked if necessary
mIsUserUnlocked = context.getSystemService(UserManager.class)
@@ -207,10 +137,6 @@ public class RecentsAnimationDeviceState implements
};
runOnDestroy(mExclusionListener::unregister);
Resources resources = mContext.getResources();
mOrientationTouchTransformer = new OrientationTouchTransformer(resources, mMode,
() -> QuickStepContract.getWindowCornerRadius(resources));
// Register for navigation mode changes
onNavigationModeChanged(mSysUiNavMode.addModeChangeListener(this));
runOnDestroy(() -> mSysUiNavMode.removeModeChangeListener(this));
@@ -241,38 +167,6 @@ public class RecentsAnimationDeviceState implements
userSetupObserver.register();
runOnDestroy(userSetupObserver::unregister);
}
mOrientationListener = new OrientationEventListener(context) {
@Override
public void onOrientationChanged(int degrees) {
int newRotation = RecentsOrientedState.getRotationForUserDegreesRotated(degrees,
mSensorRotation);
if (newRotation == mSensorRotation) {
return;
}
mSensorRotation = newRotation;
mPrioritizeDeviceRotation = true;
if (newRotation == mCurrentAppRotation) {
// When user rotates device to the orientation of the foreground app after
// quickstepping
toggleSecondaryNavBarsForRotation();
}
}
};
}
private void setupOrientationSwipeHandler() {
ActivityManagerWrapper.getInstance().registerTaskStackListener(mFrozenTaskListener);
mOnDestroyFrozenTaskRunnable = () -> ActivityManagerWrapper.getInstance()
.unregisterTaskStackListener(mFrozenTaskListener);
runOnDestroy(mOnDestroyFrozenTaskRunnable);
}
private void destroyOrientationSwipeHandlerCallback() {
ActivityManagerWrapper.getInstance().unregisterTaskStackListener(mFrozenTaskListener);
mOnDestroyActions.remove(mOnDestroyFrozenTaskRunnable);
}
private void runOnDestroy(Runnable action) {
@@ -311,13 +205,6 @@ public class RecentsAnimationDeviceState implements
mNavBarPosition = new NavBarPosition(newMode, mDefaultDisplay.getInfo());
mOrientationTouchTransformer.setNavigationMode(newMode, mDefaultDisplay.getInfo());
if (!mMode.hasGestures && newMode.hasGestures) {
setupOrientationSwipeHandler();
} else if (mMode.hasGestures && !newMode.hasGestures){
destroyOrientationSwipeHandlerCallback();
}
mMode = newMode;
}
@@ -328,28 +215,10 @@ public class RecentsAnimationDeviceState implements
return;
}
mDisplayRotation = info.rotation;
if (!mMode.hasGestures) {
return;
}
mNavBarPosition = new NavBarPosition(mMode, info);
updateGestureTouchRegions();
mOrientationTouchTransformer.createOrAddTouchRegion(info);
mCurrentAppRotation = mDisplayRotation;
/* Update nav bars on the following:
* a) if this is coming from an activity rotation OR
* aa) we launch an app in the orientation that user is already in
* b) We're not in overview, since overview will always be portrait (w/o home rotation)
* c) We're actively in quickswitch mode
*/
if ((mPrioritizeDeviceRotation
|| mCurrentAppRotation == mSensorRotation) // switch to an app of orientation user is in
&& !mInOverview
&& mTaskListFrozen) {
toggleSecondaryNavBarsForRotation();
}
}
/**
@@ -464,7 +333,7 @@ public class RecentsAnimationDeviceState implements
*/
public boolean canStartSystemGesture() {
boolean canStartWithNavHidden = (mSystemUiStateFlags & SYSUI_STATE_NAV_BAR_HIDDEN) == 0
|| mTaskListFrozen;
|| mRotationTouchHelper.isTaskListFrozen();
return canStartWithNavHidden
&& (mSystemUiStateFlags & SYSUI_STATE_NOTIFICATION_PANEL_EXPANDED) == 0
&& (mSystemUiStateFlags & SYSUI_STATE_QUICK_SETTINGS_EXPANDED) == 0
@@ -536,33 +405,6 @@ public class RecentsAnimationDeviceState implements
return (mSystemUiStateFlags & SYSUI_STATE_OVERVIEW_DISABLED) != 0;
}
/**
* Updates the regions for detecting the swipe up/quickswitch and assistant gestures.
*/
public void updateGestureTouchRegions() {
if (!mMode.hasGestures) {
return;
}
mOrientationTouchTransformer.createOrAddTouchRegion(mDefaultDisplay.getInfo());
}
/**
* @return whether the coordinates of the {@param event} is in the swipe up gesture region.
*/
public boolean isInSwipeUpTouchRegion(MotionEvent event) {
return mOrientationTouchTransformer.touchInValidSwipeRegions(event.getX(), event.getY());
}
/**
* @return whether the coordinates of the {@param event} with the given {@param pointerIndex}
* is in the swipe up gesture region.
*/
public boolean isInSwipeUpTouchRegion(MotionEvent event, int pointerIndex) {
return mOrientationTouchTransformer.touchInValidSwipeRegions(event.getX(pointerIndex),
event.getY(pointerIndex));
}
/**
* Sets the region in screen space where the gestures should be deferred (ie. due to specific
* nav bar ui).
@@ -620,101 +462,13 @@ public class RecentsAnimationDeviceState implements
public boolean canTriggerAssistantAction(MotionEvent ev, ActivityManager.RunningTaskInfo task) {
return mAssistantAvailable
&& !QuickStepContract.isAssistantGestureDisabled(mSystemUiStateFlags)
&& mOrientationTouchTransformer.touchInAssistantRegion(ev)
&& mRotationTouchHelper.touchInAssistantRegion(ev)
&& !isLockToAppActive()
&& !isGestureBlockedActivity(task);
}
/**
* *May* apply a transform on the motion event if it lies in the nav bar region for another
* orientation that is currently being tracked as a part of quickstep
*/
void setOrientationTransformIfNeeded(MotionEvent event) {
// negative coordinates bug b/143901881
if (event.getX() < 0 || event.getY() < 0) {
event.setLocation(Math.max(0, event.getX()), Math.max(0, event.getY()));
}
mOrientationTouchTransformer.transform(event);
}
private void enableMultipleRegions(boolean enable) {
mOrientationTouchTransformer.enableMultipleRegions(enable, mDefaultDisplay.getInfo());
notifySysuiOfCurrentRotation(mOrientationTouchTransformer.getQuickStepStartingRotation());
if (enable && !mInOverview && !TestProtocol.sDisableSensorRotation) {
// Clear any previous state from sensor manager
mSensorRotation = mCurrentAppRotation;
mOrientationListener.enable();
} else {
mOrientationListener.disable();
}
}
public void onStartGesture() {
if (mTaskListFrozen) {
// Prioritize whatever nav bar user touches once in quickstep
// This case is specifically when user changes what nav bar they are using mid
// quickswitch session before tasks list is unfrozen
notifySysuiOfCurrentRotation(mOrientationTouchTransformer.getCurrentActiveRotation());
}
}
void onEndTargetCalculated(GestureState.GestureEndTarget endTarget,
BaseActivityInterface activityInterface) {
if (endTarget == GestureState.GestureEndTarget.RECENTS) {
mInOverview = true;
if (!mTaskListFrozen) {
// If we're in landscape w/o ever quickswitching, show the navbar in landscape
enableMultipleRegions(true);
}
activityInterface.onExitOverview(this, mExitOverviewRunnable);
} else if (endTarget == GestureState.GestureEndTarget.HOME) {
enableMultipleRegions(false);
} else if (endTarget == GestureState.GestureEndTarget.NEW_TASK) {
if (mOrientationTouchTransformer.getQuickStepStartingRotation() == -1) {
// First gesture to start quickswitch
enableMultipleRegions(true);
} else {
notifySysuiOfCurrentRotation(
mOrientationTouchTransformer.getCurrentActiveRotation());
}
// A new gesture is starting, reset the current device rotation
// This is done under the assumption that the user won't rotate the phone and then
// quickswitch in the old orientation.
mPrioritizeDeviceRotation = false;
} else if (endTarget == GestureState.GestureEndTarget.LAST_TASK) {
if (!mTaskListFrozen) {
// touched nav bar but didn't go anywhere and not quickswitching, do nothing
return;
}
notifySysuiOfCurrentRotation(mOrientationTouchTransformer.getCurrentActiveRotation());
}
}
private void notifySysuiOfCurrentRotation(int rotation) {
UI_HELPER_EXECUTOR.execute(() -> SystemUiProxy.INSTANCE.get(mContext)
.onQuickSwitchToNewTask(rotation));
}
/**
* Disables/Enables multiple nav bars on {@link OrientationTouchTransformer} and then
* notifies system UI of the primary rotation the user is interacting with
*/
private void toggleSecondaryNavBarsForRotation() {
mOrientationTouchTransformer.setSingleActiveRegion(mDefaultDisplay.getInfo());
notifySysuiOfCurrentRotation(mOrientationTouchTransformer.getCurrentActiveRotation());
}
public int getCurrentActiveRotation() {
if (!mMode.hasGestures) {
// touch rotation should always match that of display for 3 button
return mDisplayRotation;
}
return mOrientationTouchTransformer.getCurrentActiveRotation();
}
public int getDisplayRotation() {
return mDisplayRotation;
public RotationTouchHelper getRotationTouchHelper() {
return mRotationTouchHelper;
}
public void dump(PrintWriter pw) {
@@ -726,9 +480,7 @@ public class RecentsAnimationDeviceState implements
pw.println(" assistantAvailable=" + mAssistantAvailable);
pw.println(" assistantDisabled="
+ QuickStepContract.isAssistantGestureDisabled(mSystemUiStateFlags));
pw.println(" currentActiveRotation=" + getCurrentActiveRotation());
pw.println(" displayRotation=" + getDisplayRotation());
pw.println(" isUserUnlocked=" + mIsUserUnlocked);
mOrientationTouchTransformer.dump(pw);
mRotationTouchHelper.dump(pw);
}
}
@@ -92,15 +92,6 @@ public class RecentsModel extends TaskStackChangeListener {
return mTaskList.getTasks(false /* loadKeysOnly */, callback);
}
/**
* @return The task id of the running task, or -1 if there is no current running task.
*/
public static int getRunningTaskId() {
ActivityManager.RunningTaskInfo runningTask =
ActivityManagerWrapper.getInstance().getRunningTask();
return runningTask != null ? runningTask.id : -1;
}
/**
* @return Whether the provided {@param changeId} is the latest recent tasks list id.
*/
@@ -140,7 +131,9 @@ public class RecentsModel extends TaskStackChangeListener {
}
// Keep the cache up to date with the latest thumbnails
int runningTaskId = RecentsModel.getRunningTaskId();
ActivityManager.RunningTaskInfo runningTask =
ActivityManagerWrapper.getInstance().getRunningTask();
int runningTaskId = runningTask != null ? runningTask.id : -1;
mTaskList.getTaskKeys(mThumbnailCache.getCacheSize(), tasks -> {
for (Task task : tasks) {
if (task.key.id == runningTaskId) {
@@ -0,0 +1,365 @@
/*
* Copyright (C) 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.quickstep;
import static android.view.Surface.ROTATION_0;
import static com.android.launcher3.util.DefaultDisplay.CHANGE_ALL;
import static com.android.launcher3.util.DefaultDisplay.CHANGE_FRAME_DELAY;
import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
import static com.android.quickstep.SysUINavigationMode.Mode.THREE_BUTTONS;
import android.content.Context;
import android.content.res.Resources;
import android.view.MotionEvent;
import android.view.OrientationEventListener;
import com.android.launcher3.testing.TestProtocol;
import com.android.launcher3.util.DefaultDisplay;
import com.android.launcher3.util.MainThreadInitializedObject;
import com.android.quickstep.util.RecentsOrientedState;
import com.android.systemui.shared.system.ActivityManagerWrapper;
import com.android.systemui.shared.system.QuickStepContract;
import com.android.systemui.shared.system.TaskStackChangeListener;
import java.io.PrintWriter;
import java.util.ArrayList;
public class RotationTouchHelper implements
SysUINavigationMode.NavigationModeChangeListener,
DefaultDisplay.DisplayInfoChangeListener {
public static final MainThreadInitializedObject<RotationTouchHelper> INSTANCE =
new MainThreadInitializedObject<>(RotationTouchHelper::new);
private final OrientationTouchTransformer mOrientationTouchTransformer;
private final DefaultDisplay mDefaultDisplay;
private final SysUINavigationMode mSysUiNavMode;
private final int mDisplayId;
private int mDisplayRotation;
private final ArrayList<Runnable> mOnDestroyActions = new ArrayList<>();
private SysUINavigationMode.Mode mMode = THREE_BUTTONS;
private TaskStackChangeListener mFrozenTaskListener = new TaskStackChangeListener() {
@Override
public void onRecentTaskListFrozenChanged(boolean frozen) {
mTaskListFrozen = frozen;
if (frozen || mInOverview) {
return;
}
enableMultipleRegions(false);
}
@Override
public void onActivityRotation(int displayId) {
super.onActivityRotation(displayId);
// This always gets called before onDisplayInfoChanged() so we know how to process
// the rotation in that method. This is done to avoid having a race condition between
// the sensor readings and onDisplayInfoChanged() call
if (displayId != mDisplayId) {
return;
}
mPrioritizeDeviceRotation = true;
if (mInOverview) {
// reset, launcher must be rotating
mExitOverviewRunnable.run();
}
}
};
private Runnable mExitOverviewRunnable = new Runnable() {
@Override
public void run() {
mInOverview = false;
enableMultipleRegions(false);
}
};
/**
* Used to listen for when the device rotates into the orientation of the current foreground
* app. For example, if a user quickswitches from a portrait to a fixed landscape app and then
* rotates rotates the device to match that orientation, this triggers calls to sysui to adjust
* the navbar.
*/
private OrientationEventListener mOrientationListener;
private int mSensorRotation = ROTATION_0;
/**
* This is the configuration of the foreground app or the app that will be in the foreground
* once a quickstep gesture finishes.
*/
private int mCurrentAppRotation = -1;
/**
* This flag is set to true when the device physically changes orientations. When true, we will
* always report the current rotation of the foreground app whenever the display changes, as it
* would indicate the user's intention to rotate the foreground app.
*/
private boolean mPrioritizeDeviceRotation = false;
private Runnable mOnDestroyFrozenTaskRunnable;
/**
* Set to true when user swipes to recents. In recents, we ignore the state of the recents
* task list being frozen or not to allow the user to keep interacting with nav bar rotation
* they went into recents with as opposed to defaulting to the default display rotation.
* TODO: (b/156984037) For when user rotates after entering overview
*/
private boolean mInOverview;
private boolean mTaskListFrozen;
private final Context mContext;
private RotationTouchHelper(Context context) {
mContext = context;
Resources resources = mContext.getResources();
mSysUiNavMode = SysUINavigationMode.INSTANCE.get(context);
mDefaultDisplay = DefaultDisplay.INSTANCE.get(context);
mDisplayId = mDefaultDisplay.getInfo().id;
mOrientationTouchTransformer = new OrientationTouchTransformer(resources, mMode,
() -> QuickStepContract.getWindowCornerRadius(resources));
// Register for navigation mode changes
onNavigationModeChanged(mSysUiNavMode.addModeChangeListener(this));
runOnDestroy(() -> mSysUiNavMode.removeModeChangeListener(this));
mOrientationListener = new OrientationEventListener(context) {
@Override
public void onOrientationChanged(int degrees) {
int newRotation = RecentsOrientedState.getRotationForUserDegreesRotated(degrees,
mSensorRotation);
if (newRotation == mSensorRotation) {
return;
}
mSensorRotation = newRotation;
mPrioritizeDeviceRotation = true;
if (newRotation == mCurrentAppRotation) {
// When user rotates device to the orientation of the foreground app after
// quickstepping
toggleSecondaryNavBarsForRotation();
}
}
};
}
private void setupOrientationSwipeHandler() {
ActivityManagerWrapper.getInstance().registerTaskStackListener(mFrozenTaskListener);
mOnDestroyFrozenTaskRunnable = () -> ActivityManagerWrapper.getInstance()
.unregisterTaskStackListener(mFrozenTaskListener);
runOnDestroy(mOnDestroyFrozenTaskRunnable);
}
private void destroyOrientationSwipeHandlerCallback() {
ActivityManagerWrapper.getInstance().unregisterTaskStackListener(mFrozenTaskListener);
mOnDestroyActions.remove(mOnDestroyFrozenTaskRunnable);
}
private void runOnDestroy(Runnable action) {
mOnDestroyActions.add(action);
}
/**
* Cleans up all the registered listeners and receivers.
*/
public void destroy() {
for (Runnable r : mOnDestroyActions) {
r.run();
}
}
public boolean isTaskListFrozen() {
return mTaskListFrozen;
}
public boolean touchInAssistantRegion(MotionEvent ev) {
return mOrientationTouchTransformer.touchInAssistantRegion(ev);
}
/**
* Updates the regions for detecting the swipe up/quickswitch and assistant gestures.
*/
public void updateGestureTouchRegions() {
if (!mMode.hasGestures) {
return;
}
mOrientationTouchTransformer.createOrAddTouchRegion(mDefaultDisplay.getInfo());
}
/**
* @return whether the coordinates of the {@param event} is in the swipe up gesture region.
*/
public boolean isInSwipeUpTouchRegion(MotionEvent event) {
return mOrientationTouchTransformer.touchInValidSwipeRegions(event.getX(), event.getY());
}
/**
* @return whether the coordinates of the {@param event} with the given {@param pointerIndex}
* is in the swipe up gesture region.
*/
public boolean isInSwipeUpTouchRegion(MotionEvent event, int pointerIndex) {
return mOrientationTouchTransformer.touchInValidSwipeRegions(event.getX(pointerIndex),
event.getY(pointerIndex));
}
@Override
public void onNavigationModeChanged(SysUINavigationMode.Mode newMode) {
mDefaultDisplay.removeChangeListener(this);
mDefaultDisplay.addChangeListener(this);
onDisplayInfoChanged(mDefaultDisplay.getInfo(), CHANGE_ALL);
mOrientationTouchTransformer.setNavigationMode(newMode, mDefaultDisplay.getInfo());
if (!mMode.hasGestures && newMode.hasGestures) {
setupOrientationSwipeHandler();
} else if (mMode.hasGestures && !newMode.hasGestures){
destroyOrientationSwipeHandlerCallback();
}
mMode = newMode;
}
public int getDisplayRotation() {
return mDisplayRotation;
}
@Override
public void onDisplayInfoChanged(DefaultDisplay.Info info, int flags) {
if (info.id != mDisplayId|| flags == CHANGE_FRAME_DELAY) {
// ignore displays that aren't running launcher and frame refresh rate changes
return;
}
mDisplayRotation = info.rotation;
if (!mMode.hasGestures) {
return;
}
updateGestureTouchRegions();
mOrientationTouchTransformer.createOrAddTouchRegion(info);
mCurrentAppRotation = mDisplayRotation;
/* Update nav bars on the following:
* a) if this is coming from an activity rotation OR
* aa) we launch an app in the orientation that user is already in
* b) We're not in overview, since overview will always be portrait (w/o home rotation)
* c) We're actively in quickswitch mode
*/
if ((mPrioritizeDeviceRotation
|| mCurrentAppRotation == mSensorRotation) // switch to an app of orientation user is in
&& !mInOverview
&& mTaskListFrozen) {
toggleSecondaryNavBarsForRotation();
}
}
/**
* *May* apply a transform on the motion event if it lies in the nav bar region for another
* orientation that is currently being tracked as a part of quickstep
*/
void setOrientationTransformIfNeeded(MotionEvent event) {
// negative coordinates bug b/143901881
if (event.getX() < 0 || event.getY() < 0) {
event.setLocation(Math.max(0, event.getX()), Math.max(0, event.getY()));
}
mOrientationTouchTransformer.transform(event);
}
private void enableMultipleRegions(boolean enable) {
mOrientationTouchTransformer.enableMultipleRegions(enable, mDefaultDisplay.getInfo());
notifySysuiOfCurrentRotation(mOrientationTouchTransformer.getQuickStepStartingRotation());
if (enable && !mInOverview && !TestProtocol.sDisableSensorRotation) {
// Clear any previous state from sensor manager
mSensorRotation = mCurrentAppRotation;
mOrientationListener.enable();
} else {
mOrientationListener.disable();
}
}
public void onStartGesture() {
if (mTaskListFrozen) {
// Prioritize whatever nav bar user touches once in quickstep
// This case is specifically when user changes what nav bar they are using mid
// quickswitch session before tasks list is unfrozen
notifySysuiOfCurrentRotation(mOrientationTouchTransformer.getCurrentActiveRotation());
}
}
void onEndTargetCalculated(GestureState.GestureEndTarget endTarget,
BaseActivityInterface activityInterface) {
if (endTarget == GestureState.GestureEndTarget.RECENTS) {
mInOverview = true;
if (!mTaskListFrozen) {
// If we're in landscape w/o ever quickswitching, show the navbar in landscape
enableMultipleRegions(true);
}
activityInterface.onExitOverview(this, mExitOverviewRunnable);
} else if (endTarget == GestureState.GestureEndTarget.HOME) {
enableMultipleRegions(false);
} else if (endTarget == GestureState.GestureEndTarget.NEW_TASK) {
if (mOrientationTouchTransformer.getQuickStepStartingRotation() == -1) {
// First gesture to start quickswitch
enableMultipleRegions(true);
} else {
notifySysuiOfCurrentRotation(
mOrientationTouchTransformer.getCurrentActiveRotation());
}
// A new gesture is starting, reset the current device rotation
// This is done under the assumption that the user won't rotate the phone and then
// quickswitch in the old orientation.
mPrioritizeDeviceRotation = false;
} else if (endTarget == GestureState.GestureEndTarget.LAST_TASK) {
if (!mTaskListFrozen) {
// touched nav bar but didn't go anywhere and not quickswitching, do nothing
return;
}
notifySysuiOfCurrentRotation(mOrientationTouchTransformer.getCurrentActiveRotation());
}
}
private void notifySysuiOfCurrentRotation(int rotation) {
UI_HELPER_EXECUTOR.execute(() -> SystemUiProxy.INSTANCE.get(mContext)
.onQuickSwitchToNewTask(rotation));
}
/**
* Disables/Enables multiple nav bars on {@link OrientationTouchTransformer} and then
* notifies system UI of the primary rotation the user is interacting with
*/
private void toggleSecondaryNavBarsForRotation() {
mOrientationTouchTransformer.setSingleActiveRegion(mDefaultDisplay.getInfo());
notifySysuiOfCurrentRotation(mOrientationTouchTransformer.getCurrentActiveRotation());
}
public int getCurrentActiveRotation() {
if (!mMode.hasGestures) {
// touch rotation should always match that of display for 3 button
return mDisplayRotation;
}
return mOrientationTouchTransformer.getCurrentActiveRotation();
}
public void dump(PrintWriter pw) {
pw.println("RotationTouchHelper:");
pw.println(" currentActiveRotation=" + getCurrentActiveRotation());
pw.println(" displayRotation=" + getDisplayRotation());
mOrientationTouchTransformer.dump(pw);
}
}
@@ -17,6 +17,7 @@ package com.android.quickstep.interaction;
import static com.android.launcher3.anim.Interpolators.ACCEL;
import static com.android.launcher3.util.DefaultDisplay.getSingleFrameMs;
import static com.android.launcher3.views.FloatingIconView.SHAPE_PROGRESS_DURATION;
import static com.android.quickstep.BaseSwipeUpHandlerV2.MAX_SWIPE_DURATION;
import static com.android.quickstep.interaction.TutorialController.TutorialType.HOME_NAVIGATION_COMPLETE;
import static com.android.quickstep.interaction.TutorialController.TutorialType.OVERVIEW_NAVIGATION_COMPLETE;
@@ -110,6 +111,7 @@ abstract class SwipeUpGestureTutorialController extends TutorialController {
AnimatorListenerAdapter resetTaskView = new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation, boolean isReverse) {
mFakeIconView.setVisibility(View.INVISIBLE);
mFakeTaskView.setVisibility(View.INVISIBLE);
mFakeTaskView.setAlpha(1);
mRunningWindowAnim = null;
@@ -131,6 +133,7 @@ abstract class SwipeUpGestureTutorialController extends TutorialController {
});
} else {
anim.setViewAlpha(mFakeTaskView, 0, ACCEL);
anim.setViewAlpha(mFakeIconView, 0, ACCEL);
anim.addListener(resetTaskView);
}
if (onEndRunnable != null) {
@@ -202,7 +205,7 @@ abstract class SwipeUpGestureTutorialController extends TutorialController {
// derivative of the scroll interpolator at zero, ie. 2.
long baseDuration = Math.round(Math.abs(distanceToTravel / velocityPxPerMs.y));
long duration = Math.min(MAX_SWIPE_DURATION, 2 * baseDuration);
HomeAnimationFactory homeAnimFactory = new HomeAnimationFactory(null) {
HomeAnimationFactory homeAnimFactory = new HomeAnimationFactory() {
@Override
public AnimatorPlaybackController createActivityAnimationToHome() {
return AnimatorPlaybackController.wrap(new AnimatorSet(), duration);
@@ -218,6 +221,24 @@ abstract class SwipeUpGestureTutorialController extends TutorialController {
fakeHomeIconLeft + fakeHomeIconSizePx,
fakeHomeIconTop + fakeHomeIconSizePx);
}
@Override
public void update(RectF rect, float progress, float radius) {
mFakeIconView.setVisibility(View.VISIBLE);
mFakeIconView.update(rect, progress,
1f - SHAPE_PROGRESS_DURATION /* shapeProgressStart */,
radius,
false, /* isOpening */
mFakeIconView, mDp,
false /* isVerticalBarLayout */);
mFakeIconView.setAlpha(1);
mFakeTaskView.setAlpha(getWindowAlpha(progress));
}
@Override
public void onCancel() {
mFakeIconView.setVisibility(View.INVISIBLE);
}
};
RectFSpringAnim windowAnim = createWindowAnimationToHome(startShift, homeAnimFactory);
windowAnim.start(mContext, velocityPxPerMs);
@@ -28,6 +28,7 @@ import androidx.annotation.CallSuper;
import androidx.annotation.Nullable;
import com.android.launcher3.R;
import com.android.launcher3.views.ClipIconView;
import com.android.quickstep.interaction.EdgeBackGestureHandler.BackGestureAttemptCallback;
import com.android.quickstep.interaction.NavBarGestureHandler.NavBarGestureAttemptCallback;
@@ -46,6 +47,7 @@ abstract class TutorialController implements BackGestureAttemptCallback,
final TextView mTitleTextView;
final TextView mSubtitleTextView;
final TextView mFeedbackView;
final ClipIconView mFakeIconView;
final View mFakeTaskView;
final View mRippleView;
final RippleDrawable mRippleDrawable;
@@ -66,6 +68,7 @@ abstract class TutorialController implements BackGestureAttemptCallback,
mTitleTextView = rootView.findViewById(R.id.gesture_tutorial_fragment_title_view);
mSubtitleTextView = rootView.findViewById(R.id.gesture_tutorial_fragment_subtitle_view);
mFeedbackView = rootView.findViewById(R.id.gesture_tutorial_fragment_feedback_view);
mFakeIconView = rootView.findViewById(R.id.gesture_tutorial_fake_icon_view);
mFakeTaskView = rootView.findViewById(R.id.gesture_tutorial_fake_task_view);
mRippleView = rootView.findViewById(R.id.gesture_tutorial_ripple_view);
mRippleDrawable = (RippleDrawable) mRippleView.getBackground();
@@ -27,7 +27,7 @@ import static com.android.systemui.shared.system.SysUiStatsLog.LAUNCHER_UICHANGE
import android.content.Context;
import android.util.Log;
import androidx.annotation.Nullable;
import androidx.annotation.WorkerThread;
import com.android.launcher3.LauncherAppState;
import com.android.launcher3.Utilities;
@@ -54,6 +54,7 @@ import com.android.systemui.shared.system.SysUiStatsLog;
import java.util.ArrayList;
import java.util.Optional;
import java.util.OptionalInt;
import java.util.concurrent.CopyOnWriteArrayList;
/**
* This class calls StatsLog compile time generated methods.
@@ -68,8 +69,6 @@ public class StatsLogCompatManager extends StatsLogManager {
private static final String TAG = "StatsLog";
private static final boolean IS_VERBOSE = Utilities.isPropertyEnabled(LogConfig.STATSLOG);
private static Context sContext;
private static final InstanceId DEFAULT_INSTANCE_ID = InstanceId.fakeInstanceId(0);
// LauncherAtom.ItemInfo.getDefaultInstance() should be used but until launcher proto migrates
// from nano to lite, bake constant to prevent robo test failure.
@@ -77,8 +76,13 @@ public class StatsLogCompatManager extends StatsLogManager {
private static final int FOLDER_HIERARCHY_OFFSET = 100;
private static final int SEARCH_RESULT_HIERARCHY_OFFSET = 200;
public static final CopyOnWriteArrayList<StatsLogConsumer> LOGS_CONSUMER =
new CopyOnWriteArrayList<>();
private final Context mContext;
public StatsLogCompatManager(Context context) {
sContext = context;
mContext = context;
}
@Override
@@ -86,25 +90,12 @@ public class StatsLogCompatManager extends StatsLogManager {
return new StatsCompatLogger();
}
/**
* Logs a ranking event and accompanying {@link InstanceId} and package name.
*/
@Override
public void log(EventEnum rankingEvent, InstanceId instanceId, @Nullable String packageName,
int position) {
SysUiStatsLog.write(SysUiStatsLog.RANKING_SELECTED,
rankingEvent.getId() /* event_id = 1; */,
packageName /* package_name = 2; */,
instanceId.getId() /* instance_id = 3; */,
position /* position_picked = 4; */);
}
/**
* Logs the workspace layout information on the model thread.
*/
@Override
public void logSnapshot() {
LauncherAppState.getInstance(sContext).getModel().enqueueModelUpdateTask(
LauncherAppState.getInstance(mContext).getModel().enqueueModelUpdateTask(
new SnapshotWorker());
}
@@ -175,6 +166,7 @@ public class StatsLogCompatManager extends StatsLogManager {
private static class StatsCompatLogger implements StatsLogger {
private static final ItemInfo DEFAULT_ITEM_INFO = new ItemInfo();
private ItemInfo mItemInfo = DEFAULT_ITEM_INFO;
private InstanceId mInstanceId = DEFAULT_INSTANCE_ID;
private OptionalInt mRank = OptionalInt.empty();
@@ -253,36 +245,35 @@ public class StatsLogCompatManager extends StatsLogManager {
return;
}
if (mItemInfo.container < 0) {
// Item is not within a folder. Write to StatsLog in same thread.
write(event, mInstanceId, applyOverwrites(mItemInfo.buildProto()), mSrcState,
mDstState);
LauncherAppState appState = LauncherAppState.getInstanceNoCreate();
if (mItemInfo.container < 0 || appState == null) {
// Write log on the model thread so that logs do not go out of order
// (for eg: drop comes after drag)
Executors.MODEL_EXECUTOR.execute(
() -> write(event, applyOverwrites(mItemInfo.buildProto())));
} else {
// Item is inside the folder, fetch folder info in a BG thread
// and then write to StatsLog.
LauncherAppState.getInstance(sContext).getModel().enqueueModelUpdateTask(
appState.getModel().enqueueModelUpdateTask(
new BaseModelUpdateTask() {
@Override
public void execute(LauncherAppState app, BgDataModel dataModel,
AllAppsList apps) {
FolderInfo folderInfo = dataModel.folders.get(mItemInfo.container);
write(event, mInstanceId,
applyOverwrites(mItemInfo.buildProto(folderInfo)),
mSrcState, mDstState);
write(event, applyOverwrites(mItemInfo.buildProto(folderInfo)));
}
});
}
}
private LauncherAtom.ItemInfo applyOverwrites(LauncherAtom.ItemInfo atomInfo) {
LauncherAtom.ItemInfo.Builder itemInfoBuilder =
(LauncherAtom.ItemInfo.Builder) atomInfo.toBuilder();
LauncherAtom.ItemInfo.Builder itemInfoBuilder = atomInfo.toBuilder();
mRank.ifPresent(itemInfoBuilder::setRank);
mContainerInfo.ifPresent(itemInfoBuilder::setContainerInfo);
if (mFromState.isPresent() || mToState.isPresent() || mEditText.isPresent()) {
FolderIcon.Builder folderIconBuilder = (FolderIcon.Builder) itemInfoBuilder
FolderIcon.Builder folderIconBuilder = itemInfoBuilder
.getFolderIcon()
.toBuilder();
mFromState.ifPresent(folderIconBuilder::setFromLabelState);
@@ -293,8 +284,11 @@ public class StatsLogCompatManager extends StatsLogManager {
return itemInfoBuilder.build();
}
private void write(EventEnum event, InstanceId instanceId, LauncherAtom.ItemInfo atomInfo,
int srcState, int dstState) {
@WorkerThread
private void write(EventEnum event, LauncherAtom.ItemInfo atomInfo) {
InstanceId instanceId = mInstanceId;
int srcState = mSrcState;
int dstState = mDstState;
if (IS_VERBOSE) {
String name = (event instanceof Enum) ? ((Enum) event).name() :
event.getId() + "";
@@ -307,6 +301,10 @@ public class StatsLogCompatManager extends StatsLogManager {
atomInfo));
}
for (StatsLogConsumer consumer : LOGS_CONSUMER) {
consumer.consume(event, atomInfo);
}
SysUiStatsLog.write(
SysUiStatsLog.LAUNCHER_EVENT,
SysUiStatsLog.LAUNCHER_UICHANGED__ACTION__DEFAULT_ACTION /* deprecated */,
@@ -446,7 +444,16 @@ public class StatsLogCompatManager extends StatsLogManager {
return "ALLAPPS";
default:
return "INVALID";
}
}
/**
* Interface to get stats log while it is dispatched to the system
*/
public interface StatsLogConsumer {
@WorkerThread
void consume(EventEnum event, LauncherAtom.ItemInfo atomInfo);
}
}
@@ -49,7 +49,7 @@ public class LayoutUtils {
Rect taskSize = new Rect();
LauncherActivityInterface.INSTANCE.calculateTaskSize(context, dp, taskSize,
orientationHandler);
return (dp.heightPx - taskSize.height()) / 2;
return orientationHandler.getDistanceToBottomOfRect(dp, taskSize);
}
int shelfHeight = dp.hotseatBarSizePx + dp.getInsets().bottom;
int spaceBetweenShelfAndRecents = (int) context.getResources().getDimension(