Snap for 9257771 from 345ef9ffba to tm-qpr2-release
Change-Id: Ied2a41807a640fe6325f0dbce7e5362828f39018
This commit is contained in:
@@ -17,6 +17,7 @@
|
||||
package com.android.launcher3.testing;
|
||||
|
||||
import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
|
||||
import static com.android.launcher3.util.Executors.MODEL_EXECUTOR;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.Application;
|
||||
@@ -248,6 +249,9 @@ public class DebugTestInformationHandler extends TestInformationHandler {
|
||||
return response;
|
||||
}
|
||||
|
||||
case TestProtocol.REQUEST_MODEL_QUEUE_CLEARED:
|
||||
return getFromExecutorSync(MODEL_EXECUTOR, Bundle::new);
|
||||
|
||||
default:
|
||||
return super.call(method, arg, extras);
|
||||
}
|
||||
|
||||
@@ -288,6 +288,8 @@
|
||||
<dimen name="transient_taskbar_margin">24dp</dimen>
|
||||
<dimen name="transient_taskbar_shadow_blur">40dp</dimen>
|
||||
<dimen name="transient_taskbar_key_shadow_distance">10dp</dimen>
|
||||
<dimen name="transient_taskbar_stashed_size">32dp</dimen>
|
||||
<dimen name="transient_taskbar_icon_spacing">10dp</dimen>
|
||||
<!-- Taskbar swipe up thresholds -->
|
||||
<dimen name="taskbar_app_window_threshold">150dp</dimen>
|
||||
<dimen name="taskbar_home_overview_threshold">225dp</dimen>
|
||||
|
||||
@@ -355,6 +355,11 @@ public class LauncherTaskbarUIController extends TaskbarUIController {
|
||||
mTaskbarLauncherStateController.applyState();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isIconAlignedWithHotseat() {
|
||||
return mTaskbarLauncherStateController.isIconAlignedWithHotseat();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dumpLogs(String prefix, PrintWriter pw) {
|
||||
super.dumpLogs(prefix, pw);
|
||||
|
||||
@@ -38,9 +38,8 @@ import com.android.launcher3.Utilities;
|
||||
import com.android.launcher3.anim.AnimatorListeners;
|
||||
import com.android.launcher3.statemanager.StateManager;
|
||||
import com.android.launcher3.uioverrides.QuickstepLauncher;
|
||||
import com.android.launcher3.util.MultiPropertyFactory.MultiProperty;
|
||||
import com.android.launcher3.uioverrides.states.OverviewState;
|
||||
import com.android.launcher3.util.MultiValueAlpha;
|
||||
import com.android.launcher3.util.MultiPropertyFactory.MultiProperty;
|
||||
import com.android.quickstep.AnimatedFloat;
|
||||
import com.android.quickstep.RecentsAnimationCallbacks;
|
||||
import com.android.quickstep.RecentsAnimationController;
|
||||
@@ -251,17 +250,7 @@ import java.util.StringJoiner;
|
||||
|
||||
private Animator onStateChangeApplied(int changedFlags, long duration, boolean start) {
|
||||
boolean goingToLauncher = isInLauncher();
|
||||
final float toAlignment;
|
||||
if (goingToLauncher) {
|
||||
boolean isInStashedState = mLauncherState.isTaskbarStashed(mLauncher);
|
||||
boolean willStashVisually = isInStashedState
|
||||
&& mControllers.taskbarStashController.supportsVisualStashing();
|
||||
boolean isTaskbarAlignedWithHotseat =
|
||||
mLauncherState.isTaskbarAlignedWithHotseat(mLauncher);
|
||||
toAlignment = isTaskbarAlignedWithHotseat && !willStashVisually ? 1 : 0;
|
||||
} else {
|
||||
toAlignment = 0;
|
||||
}
|
||||
final float toAlignment = isIconAlignedWithHotseat() ? 1 : 0;
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, "onStateChangeApplied - mState: " + getStateString(mState)
|
||||
+ ", changedFlags: " + getStateString(changedFlags)
|
||||
@@ -357,6 +346,22 @@ import java.util.StringJoiner;
|
||||
return mLauncherState.isTaskbarAlignedWithHotseat(mLauncher);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns if icons should be aligned to hotseat in the current transition
|
||||
*/
|
||||
public boolean isIconAlignedWithHotseat() {
|
||||
if (isInLauncher()) {
|
||||
boolean isInStashedState = mLauncherState.isTaskbarStashed(mLauncher);
|
||||
boolean willStashVisually = isInStashedState
|
||||
&& mControllers.taskbarStashController.supportsVisualStashing();
|
||||
boolean isTaskbarAlignedWithHotseat =
|
||||
mLauncherState.isTaskbarAlignedWithHotseat(mLauncher);
|
||||
return isTaskbarAlignedWithHotseat && !willStashVisually;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private void playStateTransitionAnim(AnimatorSet animatorSet, long duration,
|
||||
boolean committed) {
|
||||
boolean isInStashedState = mLauncherState.isTaskbarStashed(mLauncher);
|
||||
@@ -395,7 +400,7 @@ import java.util.StringJoiner;
|
||||
|| (!taskbarWillBeVisible && Float.compare(currentValue, 0) != 0);
|
||||
|
||||
mControllers.taskbarViewController.setLauncherIconAlignment(
|
||||
mIconAlignment.value, mIconAlignment.getEndValue(), mLauncher.getDeviceProfile());
|
||||
mIconAlignment.value, mLauncher.getDeviceProfile());
|
||||
mControllers.navbarButtonsViewController.updateTaskbarAlignment(mIconAlignment.value);
|
||||
// Switch taskbar and hotseat in last frame
|
||||
updateIconAlphaForHome(taskbarWillBeVisible ? 1 : 0);
|
||||
|
||||
@@ -190,8 +190,13 @@ public class TaskbarStashController implements TaskbarControllers.LoggableTaskba
|
||||
if (isPhoneMode()) {
|
||||
// DeviceProfile's taskbar vars aren't initialized w/ the flag off
|
||||
Resources resources = mActivity.getResources();
|
||||
mUnstashedHeight = resources.getDimensionPixelSize(R.dimen.taskbar_size);
|
||||
mStashedHeight = resources.getDimensionPixelOffset(R.dimen.taskbar_stashed_size);
|
||||
boolean isTransientTaskbar = DisplayController.isTransientTaskbar(mActivity);
|
||||
mUnstashedHeight = resources.getDimensionPixelSize(isTransientTaskbar
|
||||
? R.dimen.transient_taskbar_size
|
||||
: R.dimen.taskbar_size);
|
||||
mStashedHeight = resources.getDimensionPixelSize(isTransientTaskbar
|
||||
? R.dimen.transient_taskbar_stashed_size
|
||||
: R.dimen.taskbar_stashed_size);
|
||||
} else {
|
||||
mUnstashedHeight = mActivity.getDeviceProfile().taskbarSize;
|
||||
mStashedHeight = mActivity.getDeviceProfile().stashedTaskbarSize;
|
||||
@@ -344,7 +349,8 @@ public class TaskbarStashController implements TaskbarControllers.LoggableTaskba
|
||||
* @see WindowInsets.Type#systemBars()
|
||||
*/
|
||||
public int getContentHeightToReportToApps() {
|
||||
if (isPhoneMode() && !mActivity.isThreeButtonNav()) {
|
||||
if ((isPhoneMode() && !mActivity.isThreeButtonNav())
|
||||
|| DisplayController.isTransientTaskbar(mActivity)) {
|
||||
return getStashedHeight();
|
||||
}
|
||||
|
||||
|
||||
@@ -114,6 +114,13 @@ public class TaskbarUIController {
|
||||
|| mControllers.navbarButtonsViewController.isEventOverAnyItem(ev);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if icons should be aligned to hotseat in the current transition.
|
||||
*/
|
||||
public boolean isIconAlignedWithHotseat() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@CallSuper
|
||||
protected void dumpLogs(String prefix, PrintWriter pw) {
|
||||
pw.println(String.format(
|
||||
|
||||
@@ -280,10 +280,9 @@ public class TaskbarViewController implements TaskbarControllers.LoggableTaskbar
|
||||
* 0 => not aligned
|
||||
* 1 => fully aligned
|
||||
*/
|
||||
public void setLauncherIconAlignment(float alignmentRatio, Float endAlignment,
|
||||
DeviceProfile launcherDp) {
|
||||
public void setLauncherIconAlignment(float alignmentRatio, DeviceProfile launcherDp) {
|
||||
if (mIconAlignControllerLazy == null) {
|
||||
mIconAlignControllerLazy = createIconAlignmentController(launcherDp, endAlignment);
|
||||
mIconAlignControllerLazy = createIconAlignmentController(launcherDp);
|
||||
}
|
||||
mIconAlignControllerLazy.setPlayFraction(alignmentRatio);
|
||||
if (alignmentRatio <= 0 || alignmentRatio >= 1) {
|
||||
@@ -295,8 +294,7 @@ public class TaskbarViewController implements TaskbarControllers.LoggableTaskbar
|
||||
/**
|
||||
* Creates an animation for aligning the taskbar icons with the provided Launcher device profile
|
||||
*/
|
||||
private AnimatorPlaybackController createIconAlignmentController(DeviceProfile launcherDp,
|
||||
Float endAlignment) {
|
||||
private AnimatorPlaybackController createIconAlignmentController(DeviceProfile launcherDp) {
|
||||
mOnControllerPreCreateCallback.run();
|
||||
PendingAnimation setter = new PendingAnimation(100);
|
||||
DeviceProfile taskbarDp = mActivity.getDeviceProfile();
|
||||
@@ -322,7 +320,7 @@ public class TaskbarViewController implements TaskbarControllers.LoggableTaskbar
|
||||
setter.addOnFrameListener(anim -> mActivity.setTaskbarWindowHeight(
|
||||
anim.getAnimatedFraction() > 0 ? expandedHeight : collapsedHeight));
|
||||
|
||||
boolean isToHome = endAlignment != null && endAlignment == 1;
|
||||
boolean isToHome = mControllers.uiController.isIconAlignedWithHotseat();
|
||||
for (int i = 0; i < mTaskbarView.getChildCount(); i++) {
|
||||
View child = mTaskbarView.getChildAt(i);
|
||||
int positionInHotseat;
|
||||
|
||||
@@ -219,6 +219,8 @@ public class QuickstepLauncher extends Launcher {
|
||||
|
||||
mEnableWidgetDepth = ENABLE_WIDGET_PICKER_DEPTH.get()
|
||||
&& SystemProperties.getBoolean("ro.launcher.depth.widget", true);
|
||||
getWorkspace().addOverlayCallback(progress ->
|
||||
onTaskbarInAppDisplayProgressUpdate(progress, MINUS_ONE_PAGE_PROGRESS_INDEX));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -594,17 +596,6 @@ public class QuickstepLauncher extends Launcher {
|
||||
recentsView.finishRecentsAnimation(true /* toRecents */, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@code LauncherOverlayCallbacks} scroll amount.
|
||||
* Indicates transition progress to -1 screen.
|
||||
* @param progress From 0 to 1.
|
||||
*/
|
||||
@Override
|
||||
public void onScrollChanged(float progress) {
|
||||
super.onScrollChanged(progress);
|
||||
onTaskbarInAppDisplayProgressUpdate(progress, MINUS_ONE_PAGE_PROGRESS_INDEX);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAllAppsTransition(float progress) {
|
||||
super.onAllAppsTransition(progress);
|
||||
|
||||
@@ -48,7 +48,7 @@ import static com.android.quickstep.GestureState.STATE_RECENTS_ANIMATION_CANCELE
|
||||
import static com.android.quickstep.GestureState.STATE_RECENTS_SCROLLING_FINISHED;
|
||||
import static com.android.quickstep.MultiStateCallback.DEBUG_STATES;
|
||||
import static com.android.quickstep.util.ActiveGestureErrorDetector.GestureEvent.CANCEL_RECENTS_ANIMATION;
|
||||
import static com.android.quickstep.util.ActiveGestureErrorDetector.GestureEvent.FINISH_RECENTS_ANIMATION;
|
||||
import static com.android.quickstep.util.ActiveGestureErrorDetector.GestureEvent.EXPECTING_TASK_APPEARED;
|
||||
import static com.android.quickstep.util.ActiveGestureErrorDetector.GestureEvent.ON_SETTLED_ON_END_TARGET;
|
||||
import static com.android.quickstep.util.VibratorWrapper.OVERVIEW_HAPTIC;
|
||||
import static com.android.quickstep.views.RecentsView.UPDATE_SYSUI_FLAGS_THRESHOLD;
|
||||
@@ -1704,10 +1704,6 @@ public abstract class AbsSwipeUpHandler<T extends StatefulActivity<S>,
|
||||
private void resumeLastTask() {
|
||||
if (mRecentsAnimationController != null) {
|
||||
mRecentsAnimationController.finish(false /* toRecents */, null);
|
||||
ActiveGestureLog.INSTANCE.addLog(
|
||||
/* event= */ "finishRecentsAnimation",
|
||||
/* extras= */ false,
|
||||
/* gestureEvent= */ FINISH_RECENTS_ANIMATION);
|
||||
}
|
||||
doLogGesture(LAST_TASK, null);
|
||||
reset();
|
||||
@@ -1916,10 +1912,6 @@ public abstract class AbsSwipeUpHandler<T extends StatefulActivity<S>,
|
||||
mRecentsAnimationController.detachNavigationBarFromApp(true);
|
||||
}
|
||||
}
|
||||
ActiveGestureLog.INSTANCE.addLog(
|
||||
/* event= */ "finishRecentsAnimation",
|
||||
/* extras= */ true,
|
||||
/* gestureEvent= */ FINISH_RECENTS_ANIMATION);
|
||||
}
|
||||
|
||||
private void finishCurrentTransitionToHome() {
|
||||
@@ -1931,10 +1923,6 @@ public abstract class AbsSwipeUpHandler<T extends StatefulActivity<S>,
|
||||
finishRecentsControllerToHome(
|
||||
() -> mStateCallback.setStateOnUiThread(STATE_CURRENT_TASK_FINISHED));
|
||||
}
|
||||
ActiveGestureLog.INSTANCE.addLog(
|
||||
/* event= */ "finishRecentsAnimation",
|
||||
/* extras= */ true,
|
||||
/* gestureEvent= */ FINISH_RECENTS_ANIMATION);
|
||||
doLogGesture(HOME, mRecentsView == null ? null : mRecentsView.getCurrentPageTaskView());
|
||||
}
|
||||
|
||||
@@ -2045,6 +2033,9 @@ public abstract class AbsSwipeUpHandler<T extends StatefulActivity<S>,
|
||||
mGestureState.updateLastStartedTaskId(taskId);
|
||||
boolean hasTaskPreviouslyAppeared = mGestureState.getPreviouslyAppearedTaskIds()
|
||||
.contains(taskId);
|
||||
if (!hasTaskPreviouslyAppeared) {
|
||||
ActiveGestureLog.INSTANCE.trackEvent(EXPECTING_TASK_APPEARED);
|
||||
}
|
||||
nextTask.launchTask(success -> {
|
||||
resultCallback.accept(success);
|
||||
if (success) {
|
||||
|
||||
@@ -98,15 +98,6 @@ public class AnimatedFloat {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts the animation.
|
||||
*/
|
||||
public void startAnimation() {
|
||||
if (mValueAnimator != null) {
|
||||
mValueAnimator.start();
|
||||
}
|
||||
}
|
||||
|
||||
public void cancelAnimation() {
|
||||
if (mValueAnimator != null) {
|
||||
mValueAnimator.cancel();
|
||||
@@ -119,10 +110,6 @@ public class AnimatedFloat {
|
||||
}
|
||||
}
|
||||
|
||||
public ObjectAnimator getCurrentAnimation() {
|
||||
return mValueAnimator;
|
||||
}
|
||||
|
||||
public boolean isAnimating() {
|
||||
return mValueAnimator != null;
|
||||
}
|
||||
@@ -140,11 +127,4 @@ public class AnimatedFloat {
|
||||
public boolean isSettledOnValue(float endValue) {
|
||||
return !isAnimating() && value == endValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value we are animating to, or {@code null} if we are not currently animating.
|
||||
*/
|
||||
public Float getEndValue() {
|
||||
return mEndValue;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,7 +21,6 @@ import static com.android.launcher3.logging.StatsLogManager.LAUNCHER_STATE_OVERV
|
||||
import static com.android.quickstep.MultiStateCallback.DEBUG_STATES;
|
||||
import static com.android.quickstep.util.ActiveGestureErrorDetector.GestureEvent.SET_END_TARGET;
|
||||
import static com.android.quickstep.util.ActiveGestureErrorDetector.GestureEvent.SET_END_TARGET_HOME;
|
||||
import static com.android.quickstep.util.ActiveGestureErrorDetector.GestureEvent.SET_END_TARGET_LAST_TASK;
|
||||
import static com.android.quickstep.util.ActiveGestureErrorDetector.GestureEvent.SET_END_TARGET_NEW_TASK;
|
||||
|
||||
import android.annotation.Nullable;
|
||||
@@ -341,8 +340,6 @@ public class GestureState implements RecentsAnimationCallbacks.RecentsAnimationL
|
||||
ActiveGestureLog.INSTANCE.trackEvent(SET_END_TARGET_NEW_TASK);
|
||||
break;
|
||||
case LAST_TASK:
|
||||
ActiveGestureLog.INSTANCE.trackEvent(SET_END_TARGET_LAST_TASK);
|
||||
break;
|
||||
case RECENTS:
|
||||
default:
|
||||
// No-Op
|
||||
|
||||
@@ -23,6 +23,8 @@ import static com.android.wm.shell.util.GroupedRecentTaskInfo.TYPE_FREEFORM;
|
||||
import android.annotation.TargetApi;
|
||||
import android.app.ActivityManager;
|
||||
import android.app.KeyguardManager;
|
||||
import android.app.TaskInfo;
|
||||
import android.content.ComponentName;
|
||||
import android.os.Build;
|
||||
import android.os.Process;
|
||||
import android.os.RemoteException;
|
||||
@@ -324,8 +326,14 @@ public class RecentTasksList {
|
||||
writer.println(prefix + " mChangeId=" + mChangeId);
|
||||
writer.println(prefix + " mResultsUi=[id=" + mResultsUi.mRequestId + ", tasks=");
|
||||
for (GroupTask task : mResultsUi) {
|
||||
writer.println(prefix + " t1=" + task.task1.key.id
|
||||
+ " t2=" + (task.hasMultipleTasks() ? task.task2.key.id : "-1"));
|
||||
Task task1 = task.task1;
|
||||
Task task2 = task.task2;
|
||||
ComponentName cn1 = task1.getTopComponent();
|
||||
ComponentName cn2 = task2 != null ? task2.getTopComponent() : null;
|
||||
writer.println(prefix + " t1: (id=" + task1.key.id
|
||||
+ "; package=" + (cn1 != null ? cn1.getPackageName() + ")" : "no package)")
|
||||
+ " t2: (id=" + (task2 != null ? task2.key.id : "-1")
|
||||
+ "; package=" + (cn2 != null ? cn2.getPackageName() + ")" : "no package)"));
|
||||
}
|
||||
writer.println(prefix + " ]");
|
||||
int currentUserId = Process.myUserHandle().getIdentifier();
|
||||
@@ -333,8 +341,14 @@ public class RecentTasksList {
|
||||
mSysUiProxy.getRecentTasks(Integer.MAX_VALUE, currentUserId);
|
||||
writer.println(prefix + " rawTasks=[");
|
||||
for (GroupedRecentTaskInfo task : rawTasks) {
|
||||
writer.println(prefix + " t1=" + task.getTaskInfo1().taskId
|
||||
+ " t2=" + (task.getTaskInfo2() != null ? task.getTaskInfo2().taskId : "-1"));
|
||||
TaskInfo taskInfo1 = task.getTaskInfo1();
|
||||
TaskInfo taskInfo2 = task.getTaskInfo2();
|
||||
ComponentName cn1 = taskInfo1.topActivity;
|
||||
ComponentName cn2 = taskInfo2 != null ? taskInfo2.topActivity : null;
|
||||
writer.println(prefix + " t1: (id=" + taskInfo1.taskId
|
||||
+ "; package=" + (cn1 != null ? cn1.getPackageName() + ")" : "no package)")
|
||||
+ " t2: (id=" + (taskInfo2 != null ? taskInfo2.taskId : "-1")
|
||||
+ "; package=" + (cn2 != null ? cn2.getPackageName() + ")" : "no package)"));
|
||||
}
|
||||
writer.println(prefix + " ]");
|
||||
}
|
||||
|
||||
@@ -130,7 +130,7 @@ public class RecentsAnimationCallbacks implements
|
||||
public final void onAnimationCanceled(HashMap<Integer, ThumbnailData> thumbnailDatas) {
|
||||
Utilities.postAsyncCallback(MAIN_EXECUTOR.getHandler(), () -> {
|
||||
ActiveGestureLog.INSTANCE.addLog(
|
||||
/* event= */ "onRecentsAnimationCancelled",
|
||||
/* event= */ "RecentsAnimationCallbacks.onAnimationCanceled",
|
||||
/* gestureEvent= */ CANCEL_RECENTS_ANIMATION);
|
||||
for (RecentsAnimationListener listener : getListeners()) {
|
||||
listener.onRecentsAnimationCanceled(thumbnailDatas);
|
||||
@@ -142,7 +142,7 @@ public class RecentsAnimationCallbacks implements
|
||||
@Override
|
||||
public void onTasksAppeared(RemoteAnimationTarget[] apps) {
|
||||
Utilities.postAsyncCallback(MAIN_EXECUTOR.getHandler(), () -> {
|
||||
ActiveGestureLog.INSTANCE.addLog("onTasksAppeared",
|
||||
ActiveGestureLog.INSTANCE.addLog("RecentsAnimationCallbacks.onTasksAppeared",
|
||||
ActiveGestureErrorDetector.GestureEvent.TASK_APPEARED);
|
||||
for (RecentsAnimationListener listener : getListeners()) {
|
||||
listener.onTasksAppeared(apps);
|
||||
@@ -164,6 +164,8 @@ public class RecentsAnimationCallbacks implements
|
||||
|
||||
private final void onAnimationFinished(RecentsAnimationController controller) {
|
||||
Utilities.postAsyncCallback(MAIN_EXECUTOR.getHandler(), () -> {
|
||||
ActiveGestureLog.INSTANCE.addLog(
|
||||
/* event= */ "RecentsAnimationCallbacks.onAnimationFinished");
|
||||
for (RecentsAnimationListener listener : getListeners()) {
|
||||
listener.onRecentsAnimationFinished(controller);
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@ package com.android.quickstep;
|
||||
import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
|
||||
import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
|
||||
import static com.android.quickstep.TaskAnimationManager.ENABLE_SHELL_TRANSITIONS;
|
||||
import static com.android.quickstep.util.ActiveGestureErrorDetector.GestureEvent.FINISH_RECENTS_ANIMATION;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.RemoteException;
|
||||
@@ -155,6 +156,10 @@ public class RecentsAnimationController {
|
||||
mPendingFinishCallbacks.add(callback);
|
||||
return;
|
||||
}
|
||||
ActiveGestureLog.INSTANCE.addLog(
|
||||
/* event= */ "finishRecentsAnimation",
|
||||
/* extras= */ toRecents,
|
||||
/* gestureEvent= */ FINISH_RECENTS_ANIMATION);
|
||||
|
||||
// Finish not yet requested
|
||||
mFinishRequested = true;
|
||||
|
||||
@@ -21,6 +21,7 @@ import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
|
||||
import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
|
||||
import static com.android.quickstep.GestureState.STATE_RECENTS_ANIMATION_INITIALIZED;
|
||||
import static com.android.quickstep.GestureState.STATE_RECENTS_ANIMATION_STARTED;
|
||||
import static com.android.quickstep.util.ActiveGestureErrorDetector.GestureEvent.START_RECENTS_ANIMATION;
|
||||
import static com.android.systemui.shared.system.RemoteTransitionCompat.newRemoteTransition;
|
||||
|
||||
import android.app.ActivityManager;
|
||||
@@ -38,6 +39,7 @@ import androidx.annotation.UiThread;
|
||||
import com.android.launcher3.Utilities;
|
||||
import com.android.launcher3.config.FeatureFlags;
|
||||
import com.android.quickstep.TopTaskTracker.CachedTaskInfo;
|
||||
import com.android.quickstep.util.ActiveGestureLog;
|
||||
import com.android.quickstep.views.RecentsView;
|
||||
import com.android.systemui.shared.recents.model.ThumbnailData;
|
||||
import com.android.systemui.shared.system.ActivityManagerWrapper;
|
||||
@@ -101,6 +103,9 @@ public class TaskAnimationManager implements RecentsAnimationCallbacks.RecentsAn
|
||||
@UiThread
|
||||
public RecentsAnimationCallbacks startRecentsAnimation(GestureState gestureState,
|
||||
Intent intent, RecentsAnimationCallbacks.RecentsAnimationListener listener) {
|
||||
ActiveGestureLog.INSTANCE.addLog(
|
||||
/* event= */ "startRecentsAnimation",
|
||||
/* gestureEvent= */ START_RECENTS_ANIMATION);
|
||||
// Notify if recents animation is still running
|
||||
if (mController != null) {
|
||||
String msg = "New recents animation started before old animation completed";
|
||||
@@ -250,6 +255,7 @@ public class TaskAnimationManager implements RecentsAnimationCallbacks.RecentsAn
|
||||
* Continues the existing running recents animation for a new gesture.
|
||||
*/
|
||||
public RecentsAnimationCallbacks continueRecentsAnimation(GestureState gestureState) {
|
||||
ActiveGestureLog.INSTANCE.addLog(/* event= */ "continueRecentsAnimation");
|
||||
mCallbacks.removeListener(mLastGestureState);
|
||||
mLastGestureState = gestureState;
|
||||
mCallbacks.addListener(gestureState);
|
||||
@@ -288,6 +294,8 @@ public class TaskAnimationManager implements RecentsAnimationCallbacks.RecentsAn
|
||||
*/
|
||||
public void finishRunningRecentsAnimation(boolean toHome) {
|
||||
if (mController != null) {
|
||||
ActiveGestureLog.INSTANCE.addLog(
|
||||
/* event= */ "finishRunningRecentsAnimation", toHome);
|
||||
mCallbacks.notifyAnimationCanceled();
|
||||
Utilities.postAsyncCallback(MAIN_EXECUTOR.getHandler(), toHome
|
||||
? mController::finishAnimationToHome
|
||||
@@ -320,6 +328,7 @@ public class TaskAnimationManager implements RecentsAnimationCallbacks.RecentsAn
|
||||
* Cleans up the recents animation entirely.
|
||||
*/
|
||||
private void cleanUpRecentsAnimation() {
|
||||
ActiveGestureLog.INSTANCE.addLog(/* event= */ "cleanUpRecentsAnimation");
|
||||
if (mLiveTileCleanUpHandler != null) {
|
||||
mLiveTileCleanUpHandler.run();
|
||||
mLiveTileCleanUpHandler = null;
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
*/
|
||||
package com.android.quickstep;
|
||||
|
||||
import static android.accessibilityservice.AccessibilityService.GLOBAL_ACTION_ACCESSIBILITY_ALL_APPS;
|
||||
import static android.view.MotionEvent.ACTION_CANCEL;
|
||||
import static android.view.MotionEvent.ACTION_DOWN;
|
||||
import static android.view.MotionEvent.ACTION_UP;
|
||||
@@ -22,6 +23,7 @@ import static android.view.MotionEvent.ACTION_UP;
|
||||
import static com.android.launcher3.config.FeatureFlags.ASSISTANT_GIVES_LAUNCHER_FOCUS;
|
||||
import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
|
||||
import static com.android.quickstep.GestureState.DEFAULT_STATE;
|
||||
import static com.android.quickstep.util.ActiveGestureErrorDetector.GestureEvent.FLAG_USING_OTHER_ACTIVITY_INPUT_CONSUMER;
|
||||
import static com.android.quickstep.util.ActiveGestureErrorDetector.GestureEvent.MOTION_DOWN;
|
||||
import static com.android.quickstep.util.ActiveGestureErrorDetector.GestureEvent.MOTION_UP;
|
||||
import static com.android.systemui.shared.system.ActivityManagerWrapper.CLOSE_SYSTEM_WINDOWS_REASON_RECENTS;
|
||||
@@ -46,7 +48,6 @@ import android.app.Service;
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.content.res.Configuration;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.Region;
|
||||
import android.graphics.drawable.Icon;
|
||||
import android.os.Build;
|
||||
@@ -54,7 +55,6 @@ import android.os.Bundle;
|
||||
import android.os.IBinder;
|
||||
import android.os.Looper;
|
||||
import android.os.SystemClock;
|
||||
import android.os.SystemProperties;
|
||||
import android.util.Log;
|
||||
import android.view.Choreographer;
|
||||
import android.view.InputEvent;
|
||||
@@ -86,7 +86,6 @@ import com.android.launcher3.uioverrides.plugins.PluginManagerWrapper;
|
||||
import com.android.launcher3.util.DisplayController;
|
||||
import com.android.launcher3.util.OnboardingPrefs;
|
||||
import com.android.launcher3.util.TraceHelper;
|
||||
import com.android.launcher3.util.WindowBounds;
|
||||
import com.android.quickstep.inputconsumers.AccessibilityInputConsumer;
|
||||
import com.android.quickstep.inputconsumers.AssistantInputConsumer;
|
||||
import com.android.quickstep.inputconsumers.DeviceLockedInputConsumer;
|
||||
@@ -103,7 +102,6 @@ import com.android.quickstep.util.ActiveGestureLog;
|
||||
import com.android.quickstep.util.ActiveGestureLog.CompoundString;
|
||||
import com.android.quickstep.util.ProtoTracer;
|
||||
import com.android.quickstep.util.ProxyScreenStatusProvider;
|
||||
import com.android.quickstep.util.SplitScreenBounds;
|
||||
import com.android.systemui.shared.recents.IOverviewProxy;
|
||||
import com.android.systemui.shared.recents.ISystemUiProxy;
|
||||
import com.android.systemui.shared.system.ActivityManagerWrapper;
|
||||
@@ -139,21 +137,7 @@ public class TouchInteractionService extends Service
|
||||
|
||||
private static final String TAG = "TouchInteractionService";
|
||||
|
||||
private static final boolean BUBBLES_HOME_GESTURE_ENABLED =
|
||||
SystemProperties.getBoolean("persist.wm.debug.bubbles_home_gesture", true);
|
||||
|
||||
private static final String KEY_BACK_NOTIFICATION_COUNT = "backNotificationCount";
|
||||
private static final String NOTIFY_ACTION_BACK = "com.android.quickstep.action.BACK_GESTURE";
|
||||
private static final String HAS_ENABLED_QUICKSTEP_ONCE = "launcher.has_enabled_quickstep_once";
|
||||
private static final int MAX_BACK_NOTIFICATION_COUNT = 3;
|
||||
|
||||
/**
|
||||
* System Action ID to show all apps.
|
||||
* TODO: Use AccessibilityService's corresponding global action constant in S
|
||||
*/
|
||||
private static final int SYSTEM_ACTION_ID_ALL_APPS = 14;
|
||||
|
||||
private int mBackGestureNotificationCounter = -1;
|
||||
|
||||
private final TISBinder mTISBinder = new TISBinder();
|
||||
|
||||
@@ -264,12 +248,6 @@ public class TouchInteractionService extends Service
|
||||
MAIN_EXECUTOR.execute(() -> mDeviceState.setDeferredGestureRegion(region));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSplitScreenSecondaryBoundsChanged(Rect bounds, Rect insets) {
|
||||
WindowBounds wb = new WindowBounds(bounds, insets);
|
||||
MAIN_EXECUTOR.execute(() -> SplitScreenBounds.INSTANCE.setSecondaryWindowBounds(wb));
|
||||
}
|
||||
|
||||
@BinderThread
|
||||
@Override
|
||||
public void onScreenTurnedOn() {
|
||||
@@ -483,8 +461,6 @@ public class TouchInteractionService extends Service
|
||||
|
||||
// Temporarily disable model preload
|
||||
// new ModelPreload().start(this);
|
||||
mBackGestureNotificationCounter = Math.max(0, Utilities.getDevicePrefs(this)
|
||||
.getInt(KEY_BACK_NOTIFICATION_COUNT, MAX_BACK_NOTIFICATION_COUNT));
|
||||
resetHomeBounceSeenOnQuickstepEnabledFirstTime();
|
||||
|
||||
mOverviewComponentObserver.setOverviewChangeListener(this::onOverviewTargetChange);
|
||||
@@ -522,11 +498,11 @@ public class TouchInteractionService extends Service
|
||||
Icon.createWithResource(this, R.drawable.ic_apps),
|
||||
getString(R.string.all_apps_label),
|
||||
getString(R.string.all_apps_label),
|
||||
PendingIntent.getActivity(this, SYSTEM_ACTION_ID_ALL_APPS, intent,
|
||||
PendingIntent.getActivity(this, GLOBAL_ACTION_ACCESSIBILITY_ALL_APPS, intent,
|
||||
PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE));
|
||||
am.registerSystemAction(allAppsAction, SYSTEM_ACTION_ID_ALL_APPS);
|
||||
am.registerSystemAction(allAppsAction, GLOBAL_ACTION_ACCESSIBILITY_ALL_APPS);
|
||||
} else {
|
||||
am.unregisterSystemAction(SYSTEM_ACTION_ID_ALL_APPS);
|
||||
am.unregisterSystemAction(GLOBAL_ACTION_ACCESSIBILITY_ALL_APPS);
|
||||
}
|
||||
|
||||
StatefulActivity newOverviewActivity = mOverviewComponentObserver.getActivityInterface()
|
||||
@@ -604,7 +580,7 @@ public class TouchInteractionService extends Service
|
||||
ProtoTracer.INSTANCE.get(this).remove(this);
|
||||
|
||||
getSystemService(AccessibilityManager.class)
|
||||
.unregisterSystemAction(SYSTEM_ACTION_ID_ALL_APPS);
|
||||
.unregisterSystemAction(GLOBAL_ACTION_ACCESSIBILITY_ALL_APPS);
|
||||
|
||||
mTaskbarManager.destroy();
|
||||
sConnected = false;
|
||||
@@ -829,27 +805,9 @@ public class TouchInteractionService extends Service
|
||||
if (mDeviceState.isBubblesExpanded()) {
|
||||
reasonString = newCompoundString(reasonPrefix)
|
||||
.append(SUBSTRING_PREFIX)
|
||||
.append("bubbles expanded");
|
||||
if (BUBBLES_HOME_GESTURE_ENABLED) {
|
||||
reasonString.append(SUBSTRING_PREFIX)
|
||||
.append("bubbles can handle the home gesture")
|
||||
.append(", trying to use default input consumer");
|
||||
// Bubbles can handle home gesture itself.
|
||||
base = getDefaultInputConsumer(reasonString);
|
||||
} else {
|
||||
// If Bubbles is expanded, use the overlay input consumer, which will close
|
||||
// Bubbles instead of going all the way home when a swipe up is detected.
|
||||
// Notification panel can be expanded on top of expanded bubbles. Bubbles remain
|
||||
// expanded in the back. Make sure swipe up is not passed to bubbles in this
|
||||
// case.
|
||||
if (!mDeviceState.isNotificationPanelExpanded()) {
|
||||
reasonString = newCompoundString(reasonPrefix)
|
||||
.append(SUBSTRING_PREFIX)
|
||||
.append("using SysUiOverlayInputConsumer");
|
||||
base = new SysUiOverlayInputConsumer(
|
||||
getBaseContext(), mDeviceState, mInputMonitorCompat);
|
||||
}
|
||||
}
|
||||
.append("bubbles expanded, trying to use default input consumer");
|
||||
// Bubbles can handle home gesture itself.
|
||||
base = getDefaultInputConsumer(reasonString);
|
||||
}
|
||||
|
||||
if (mDeviceState.isSystemUiDialogShowing()) {
|
||||
@@ -927,6 +885,9 @@ public class TouchInteractionService extends Service
|
||||
.append(consumer.getName())
|
||||
.append(". reason(s):")
|
||||
.append(reasonString));
|
||||
if ((consumer.getType() & InputConsumer.TYPE_OTHER_ACTIVITY) != 0) {
|
||||
ActiveGestureLog.INSTANCE.trackEvent(FLAG_USING_OTHER_ACTIVITY_INPUT_CONSUMER);
|
||||
}
|
||||
}
|
||||
|
||||
private void handleOrientationSetup(InputConsumer baseInputConsumer) {
|
||||
@@ -1251,12 +1212,22 @@ public class TouchInteractionService extends Service
|
||||
}
|
||||
|
||||
private void onCommand(PrintWriter pw, LinkedList<String> args) {
|
||||
switch (args.pollFirst()) {
|
||||
String cmd = args.pollFirst();
|
||||
if (cmd == null) {
|
||||
pw.println("Command missing");
|
||||
printAvailableCommands(pw);
|
||||
return;
|
||||
}
|
||||
switch (cmd) {
|
||||
case "clear-touch-log":
|
||||
ActiveGestureLog.INSTANCE.clear();
|
||||
break;
|
||||
case "print-gesture-log":
|
||||
ActiveGestureLog.INSTANCE.dump("", pw);
|
||||
break;
|
||||
default:
|
||||
pw.println("Command does not exist: " + cmd);
|
||||
printAvailableCommands(pw);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -30,7 +30,6 @@ import static com.android.launcher3.Utilities.squaredHypot;
|
||||
import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
|
||||
import static com.android.launcher3.util.TraceHelper.FLAG_CHECK_FOR_RACE_CONDITIONS;
|
||||
import static com.android.launcher3.util.VelocityUtils.PX_PER_MS;
|
||||
import static com.android.quickstep.util.ActiveGestureErrorDetector.GestureEvent.START_RECENTS_ANIMATION;
|
||||
import static com.android.quickstep.util.ActiveGestureLog.INTENT_EXTRA_LOG_TRACE_ID;
|
||||
|
||||
import android.annotation.TargetApi;
|
||||
@@ -67,7 +66,6 @@ import com.android.quickstep.RecentsAnimationDeviceState;
|
||||
import com.android.quickstep.RecentsAnimationTargets;
|
||||
import com.android.quickstep.RotationTouchHelper;
|
||||
import com.android.quickstep.TaskAnimationManager;
|
||||
import com.android.quickstep.util.ActiveGestureLog;
|
||||
import com.android.quickstep.util.CachedEventDispatcher;
|
||||
import com.android.quickstep.util.MotionPauseDetector;
|
||||
import com.android.quickstep.util.NavBarPosition;
|
||||
@@ -387,10 +385,6 @@ public class OtherActivityInputConsumer extends ContextWrapper implements InputC
|
||||
}
|
||||
|
||||
private void startTouchTrackingForWindowAnimation(long touchTimeMs) {
|
||||
ActiveGestureLog.INSTANCE.addLog(
|
||||
/* event= */ "startRecentsAnimation",
|
||||
/* gestureEvent= */ START_RECENTS_ANIMATION);
|
||||
|
||||
mInteractionHandler = mHandlerFactory.newHandler(mGestureState, touchTimeMs);
|
||||
mInteractionHandler.setGestureEndCallback(this::onInteractionGestureFinished);
|
||||
mMotionPauseDetector.setOnMotionPauseListener(mInteractionHandler.getMotionPauseListener());
|
||||
|
||||
+1
-13
@@ -28,8 +28,6 @@ import android.content.Intent;
|
||||
import android.graphics.Point;
|
||||
import android.view.MotionEvent;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.android.launcher3.anim.AnimatorListeners;
|
||||
import com.android.launcher3.testing.TestLogging;
|
||||
import com.android.launcher3.testing.shared.TestProtocol;
|
||||
@@ -43,7 +41,6 @@ import com.android.quickstep.RecentsAnimationCallbacks;
|
||||
import com.android.quickstep.RecentsAnimationController;
|
||||
import com.android.quickstep.RecentsAnimationTargets;
|
||||
import com.android.quickstep.TaskAnimationManager;
|
||||
import com.android.quickstep.util.ActiveGestureErrorDetector;
|
||||
import com.android.systemui.shared.recents.model.ThumbnailData;
|
||||
import com.android.systemui.shared.system.InputMonitorCompat;
|
||||
|
||||
@@ -102,8 +99,7 @@ public class ProgressDelegateInputConsumer implements InputConsumer,
|
||||
mDisplaySize = DisplayController.INSTANCE.get(context).getInfo().currentSize;
|
||||
|
||||
// Init states
|
||||
mStateCallback = new MultiStateCallback(
|
||||
STATE_NAMES, ProgressDelegateInputConsumer::getTrackedEventForState);
|
||||
mStateCallback = new MultiStateCallback(STATE_NAMES);
|
||||
mStateCallback.runOnceAtState(STATE_TARGET_RECEIVED | STATE_HANDLER_INVALIDATED,
|
||||
this::endRemoteAnimation);
|
||||
mStateCallback.runOnceAtState(STATE_TARGET_RECEIVED | STATE_FLING_FINISHED,
|
||||
@@ -113,14 +109,6 @@ public class ProgressDelegateInputConsumer implements InputConsumer,
|
||||
mSwipeDetector.setDetectableScrollConditions(DIRECTION_POSITIVE, false);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static ActiveGestureErrorDetector.GestureEvent getTrackedEventForState(int stateFlag) {
|
||||
if (stateFlag == STATE_HANDLER_INVALIDATED) {
|
||||
return ActiveGestureErrorDetector.GestureEvent.STATE_HANDLER_INVALIDATED;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getType() {
|
||||
return TYPE_PROGRESS_DELEGATE;
|
||||
|
||||
@@ -135,7 +135,6 @@ public class AllSetActivity extends Activity {
|
||||
} catch (URISyntaxException e) {
|
||||
Log.e(LOG_TAG, "Failed to parse system nav settings intent", e);
|
||||
}
|
||||
finish();
|
||||
});
|
||||
|
||||
findViewById(R.id.hint).setAccessibilityDelegate(new SkipButtonAccessibilityDelegate());
|
||||
|
||||
@@ -33,10 +33,11 @@ public class ActiveGestureErrorDetector {
|
||||
* Enums associated to gesture navigation events.
|
||||
*/
|
||||
public enum GestureEvent {
|
||||
MOTION_DOWN, MOTION_UP, SET_END_TARGET, SET_END_TARGET_HOME, SET_END_TARGET_LAST_TASK,
|
||||
SET_END_TARGET_NEW_TASK, ON_SETTLED_ON_END_TARGET, START_RECENTS_ANIMATION,
|
||||
FINISH_RECENTS_ANIMATION, CANCEL_RECENTS_ANIMATION, SET_ON_PAGE_TRANSITION_END_CALLBACK,
|
||||
CANCEL_CURRENT_ANIMATION, CLEANUP_SCREENSHOT, SCROLLER_ANIMATION_ABORTED, TASK_APPEARED,
|
||||
MOTION_DOWN, MOTION_UP, SET_END_TARGET, SET_END_TARGET_HOME, SET_END_TARGET_NEW_TASK,
|
||||
ON_SETTLED_ON_END_TARGET, START_RECENTS_ANIMATION, FINISH_RECENTS_ANIMATION,
|
||||
CANCEL_RECENTS_ANIMATION, SET_ON_PAGE_TRANSITION_END_CALLBACK, CANCEL_CURRENT_ANIMATION,
|
||||
CLEANUP_SCREENSHOT, SCROLLER_ANIMATION_ABORTED, TASK_APPEARED, EXPECTING_TASK_APPEARED,
|
||||
FLAG_USING_OTHER_ACTIVITY_INPUT_CONSUMER,
|
||||
|
||||
/**
|
||||
* These GestureEvents are specifically associated to state flags that get set in
|
||||
@@ -91,35 +92,40 @@ public class ActiveGestureErrorDetector {
|
||||
case MOTION_UP:
|
||||
errorDetected |= printErrorIfTrue(
|
||||
!encounteredEvents.contains(GestureEvent.MOTION_DOWN),
|
||||
/* errorMessage= */ prefix + "\t\tMotion up detected before/without"
|
||||
prefix,
|
||||
/* errorMessage= */ "Motion up detected before/without"
|
||||
+ " motion down.",
|
||||
writer);
|
||||
break;
|
||||
case ON_SETTLED_ON_END_TARGET:
|
||||
errorDetected |= printErrorIfTrue(
|
||||
!encounteredEvents.contains(GestureEvent.SET_END_TARGET),
|
||||
/* errorMessage= */ prefix + "\t\tonSettledOnEndTarget called "
|
||||
prefix,
|
||||
/* errorMessage= */ "onSettledOnEndTarget called "
|
||||
+ "before/without setEndTarget.",
|
||||
writer);
|
||||
break;
|
||||
case FINISH_RECENTS_ANIMATION:
|
||||
errorDetected |= printErrorIfTrue(
|
||||
!encounteredEvents.contains(GestureEvent.START_RECENTS_ANIMATION),
|
||||
/* errorMessage= */ prefix + "\t\tfinishRecentsAnimation called "
|
||||
prefix,
|
||||
/* errorMessage= */ "finishRecentsAnimation called "
|
||||
+ "before/without startRecentsAnimation.",
|
||||
writer);
|
||||
break;
|
||||
case CANCEL_RECENTS_ANIMATION:
|
||||
errorDetected |= printErrorIfTrue(
|
||||
!encounteredEvents.contains(GestureEvent.START_RECENTS_ANIMATION),
|
||||
/* errorMessage= */ prefix + "\t\tcancelRecentsAnimation called "
|
||||
prefix,
|
||||
/* errorMessage= */ "cancelRecentsAnimation called "
|
||||
+ "before/without startRecentsAnimation.",
|
||||
writer);
|
||||
break;
|
||||
case CLEANUP_SCREENSHOT:
|
||||
errorDetected |= printErrorIfTrue(
|
||||
!encounteredEvents.contains(GestureEvent.STATE_SCREENSHOT_CAPTURED),
|
||||
/* errorMessage= */ prefix + "\t\trecents activity screenshot was "
|
||||
prefix,
|
||||
/* errorMessage= */ "recents activity screenshot was "
|
||||
+ "cleaned up before/without STATE_SCREENSHOT_CAPTURED "
|
||||
+ "being set.",
|
||||
writer);
|
||||
@@ -129,48 +135,66 @@ public class ActiveGestureErrorDetector {
|
||||
encounteredEvents.contains(GestureEvent.SET_END_TARGET_HOME)
|
||||
&& !encounteredEvents.contains(
|
||||
GestureEvent.ON_SETTLED_ON_END_TARGET),
|
||||
/* errorMessage= */ prefix + "\t\trecents view scroller animation "
|
||||
prefix,
|
||||
/* errorMessage= */ "recents view scroller animation "
|
||||
+ "aborted after setting end target HOME, but before"
|
||||
+ " settling on end target.",
|
||||
writer);
|
||||
break;
|
||||
case TASK_APPEARED:
|
||||
errorDetected |= printErrorIfTrue(
|
||||
!encounteredEvents.contains(GestureEvent.SET_END_TARGET_LAST_TASK)
|
||||
&& !encounteredEvents.contains(
|
||||
GestureEvent.SET_END_TARGET_NEW_TASK),
|
||||
/* errorMessage= */ prefix + "\t\tonTasksAppeared called "
|
||||
+ "before/without setting end target to last or new task",
|
||||
!encounteredEvents.contains(GestureEvent.SET_END_TARGET_NEW_TASK),
|
||||
prefix,
|
||||
/* errorMessage= */ "onTasksAppeared called "
|
||||
+ "before/without setting end target to new task",
|
||||
writer);
|
||||
errorDetected |= printErrorIfTrue(
|
||||
!encounteredEvents.contains(GestureEvent.EXPECTING_TASK_APPEARED),
|
||||
prefix,
|
||||
/* errorMessage= */ "onTasksAppeared was not expected to be called",
|
||||
writer);
|
||||
break;
|
||||
case EXPECTING_TASK_APPEARED:
|
||||
errorDetected |= printErrorIfTrue(
|
||||
!encounteredEvents.contains(GestureEvent.SET_END_TARGET_NEW_TASK),
|
||||
prefix,
|
||||
/* errorMessage= */ "expecting onTasksAppeared to be called "
|
||||
+ "before/without setting end target to new task",
|
||||
writer);
|
||||
break;
|
||||
case STATE_GESTURE_COMPLETED:
|
||||
errorDetected |= printErrorIfTrue(
|
||||
!encounteredEvents.contains(GestureEvent.MOTION_UP),
|
||||
/* errorMessage= */ prefix + "\t\tSTATE_GESTURE_COMPLETED set "
|
||||
prefix,
|
||||
/* errorMessage= */ "STATE_GESTURE_COMPLETED set "
|
||||
+ "before/without motion up.",
|
||||
writer);
|
||||
errorDetected |= printErrorIfTrue(
|
||||
!encounteredEvents.contains(GestureEvent.STATE_GESTURE_STARTED),
|
||||
/* errorMessage= */ prefix + "\t\tSTATE_GESTURE_COMPLETED set "
|
||||
prefix,
|
||||
/* errorMessage= */ "STATE_GESTURE_COMPLETED set "
|
||||
+ "before/without STATE_GESTURE_STARTED.",
|
||||
writer);
|
||||
break;
|
||||
case STATE_GESTURE_CANCELLED:
|
||||
errorDetected |= printErrorIfTrue(
|
||||
!encounteredEvents.contains(GestureEvent.MOTION_UP),
|
||||
/* errorMessage= */ prefix + "\t\tSTATE_GESTURE_CANCELLED set "
|
||||
prefix,
|
||||
/* errorMessage= */ "STATE_GESTURE_CANCELLED set "
|
||||
+ "before/without motion up.",
|
||||
writer);
|
||||
errorDetected |= printErrorIfTrue(
|
||||
!encounteredEvents.contains(GestureEvent.STATE_GESTURE_STARTED),
|
||||
/* errorMessage= */ prefix + "\t\tSTATE_GESTURE_CANCELLED set "
|
||||
prefix,
|
||||
/* errorMessage= */ "STATE_GESTURE_CANCELLED set "
|
||||
+ "before/without STATE_GESTURE_STARTED.",
|
||||
writer);
|
||||
break;
|
||||
case STATE_SCREENSHOT_CAPTURED:
|
||||
errorDetected |= printErrorIfTrue(
|
||||
!encounteredEvents.contains(GestureEvent.STATE_CAPTURE_SCREENSHOT),
|
||||
/* errorMessage= */ prefix + "\t\tSTATE_SCREENSHOT_CAPTURED set "
|
||||
prefix,
|
||||
/* errorMessage= */ "STATE_SCREENSHOT_CAPTURED set "
|
||||
+ "before/without STATE_CAPTURE_SCREENSHOT.",
|
||||
writer);
|
||||
break;
|
||||
@@ -178,7 +202,8 @@ public class ActiveGestureErrorDetector {
|
||||
errorDetected |= printErrorIfTrue(
|
||||
!encounteredEvents.contains(
|
||||
GestureEvent.SET_ON_PAGE_TRANSITION_END_CALLBACK),
|
||||
/* errorMessage= */ prefix + "\t\tSTATE_RECENTS_SCROLLING_FINISHED "
|
||||
prefix,
|
||||
/* errorMessage= */ "STATE_RECENTS_SCROLLING_FINISHED "
|
||||
+ "set before/without calling "
|
||||
+ "setOnPageTransitionEndCallback.",
|
||||
writer);
|
||||
@@ -187,16 +212,19 @@ public class ActiveGestureErrorDetector {
|
||||
errorDetected |= printErrorIfTrue(
|
||||
!encounteredEvents.contains(
|
||||
GestureEvent.START_RECENTS_ANIMATION),
|
||||
/* errorMessage= */ prefix + "\t\tSTATE_RECENTS_ANIMATION_CANCELED "
|
||||
prefix,
|
||||
/* errorMessage= */ "STATE_RECENTS_ANIMATION_CANCELED "
|
||||
+ "set before/without startRecentsAnimation.",
|
||||
writer);
|
||||
break;
|
||||
case MOTION_DOWN:
|
||||
case SET_END_TARGET:
|
||||
case SET_END_TARGET_HOME:
|
||||
case SET_END_TARGET_NEW_TASK:
|
||||
case START_RECENTS_ANIMATION:
|
||||
case SET_ON_PAGE_TRANSITION_END_CALLBACK:
|
||||
case CANCEL_CURRENT_ANIMATION:
|
||||
case FLAG_USING_OTHER_ACTIVITY_INPUT_CONSUMER:
|
||||
case STATE_GESTURE_STARTED:
|
||||
case STATE_END_TARGET_ANIMATION_FINISHED:
|
||||
case STATE_CAPTURE_SCREENSHOT:
|
||||
@@ -210,31 +238,36 @@ public class ActiveGestureErrorDetector {
|
||||
// Check that all required events were found.
|
||||
errorDetected |= printErrorIfTrue(
|
||||
!encounteredEvents.contains(GestureEvent.MOTION_DOWN),
|
||||
/* errorMessage= */ prefix + "\t\tMotion down never detected.",
|
||||
prefix,
|
||||
/* errorMessage= */ "Motion down never detected.",
|
||||
writer);
|
||||
errorDetected |= printErrorIfTrue(
|
||||
!encounteredEvents.contains(GestureEvent.MOTION_UP),
|
||||
/* errorMessage= */ prefix + "\t\tMotion up never detected.",
|
||||
prefix,
|
||||
/* errorMessage= */ "Motion up never detected.",
|
||||
writer);
|
||||
|
||||
errorDetected |= printErrorIfTrue(
|
||||
/* condition= */ encounteredEvents.contains(GestureEvent.SET_END_TARGET)
|
||||
&& !encounteredEvents.contains(GestureEvent.ON_SETTLED_ON_END_TARGET),
|
||||
/* errorMessage= */ prefix + "\t\tsetEndTarget was called, but "
|
||||
prefix,
|
||||
/* errorMessage= */ "setEndTarget was called, but "
|
||||
+ "onSettledOnEndTarget wasn't.",
|
||||
writer);
|
||||
errorDetected |= printErrorIfTrue(
|
||||
/* condition= */ encounteredEvents.contains(GestureEvent.SET_END_TARGET)
|
||||
&& !encounteredEvents.contains(
|
||||
GestureEvent.STATE_END_TARGET_ANIMATION_FINISHED),
|
||||
/* errorMessage= */ prefix + "\t\tsetEndTarget was called, but "
|
||||
prefix,
|
||||
/* errorMessage= */ "setEndTarget was called, but "
|
||||
+ "STATE_END_TARGET_ANIMATION_FINISHED was never set.",
|
||||
writer);
|
||||
errorDetected |= printErrorIfTrue(
|
||||
/* condition= */ encounteredEvents.contains(GestureEvent.SET_END_TARGET)
|
||||
&& !encounteredEvents.contains(
|
||||
GestureEvent.STATE_RECENTS_SCROLLING_FINISHED),
|
||||
/* errorMessage= */ prefix + "\t\tsetEndTarget was called, but "
|
||||
prefix,
|
||||
/* errorMessage= */ "setEndTarget was called, but "
|
||||
+ "STATE_RECENTS_SCROLLING_FINISHED was never set.",
|
||||
writer);
|
||||
errorDetected |= printErrorIfTrue(
|
||||
@@ -243,7 +276,8 @@ public class ActiveGestureErrorDetector {
|
||||
&& encounteredEvents.contains(
|
||||
GestureEvent.STATE_RECENTS_SCROLLING_FINISHED)
|
||||
&& !encounteredEvents.contains(GestureEvent.ON_SETTLED_ON_END_TARGET),
|
||||
/* errorMessage= */ prefix + "\t\tSTATE_END_TARGET_ANIMATION_FINISHED and "
|
||||
prefix,
|
||||
/* errorMessage= */ "STATE_END_TARGET_ANIMATION_FINISHED and "
|
||||
+ "STATE_RECENTS_SCROLLING_FINISHED were set, but onSettledOnEndTarget "
|
||||
+ "wasn't called.",
|
||||
writer);
|
||||
@@ -253,7 +287,8 @@ public class ActiveGestureErrorDetector {
|
||||
GestureEvent.START_RECENTS_ANIMATION)
|
||||
&& !encounteredEvents.contains(GestureEvent.FINISH_RECENTS_ANIMATION)
|
||||
&& !encounteredEvents.contains(GestureEvent.CANCEL_RECENTS_ANIMATION),
|
||||
/* errorMessage= */ prefix + "\t\tstartRecentsAnimation was called, but "
|
||||
prefix,
|
||||
/* errorMessage= */ "startRecentsAnimation was called, but "
|
||||
+ "finishRecentsAnimation and cancelRecentsAnimation weren't.",
|
||||
writer);
|
||||
|
||||
@@ -261,7 +296,8 @@ public class ActiveGestureErrorDetector {
|
||||
/* condition= */ encounteredEvents.contains(GestureEvent.STATE_GESTURE_STARTED)
|
||||
&& !encounteredEvents.contains(GestureEvent.STATE_GESTURE_COMPLETED)
|
||||
&& !encounteredEvents.contains(GestureEvent.STATE_GESTURE_CANCELLED),
|
||||
/* errorMessage= */ prefix + "\t\tSTATE_GESTURE_STARTED was set, but "
|
||||
prefix,
|
||||
/* errorMessage= */ "STATE_GESTURE_STARTED was set, but "
|
||||
+ "STATE_GESTURE_COMPLETED and STATE_GESTURE_CANCELLED weren't.",
|
||||
writer);
|
||||
|
||||
@@ -269,7 +305,8 @@ public class ActiveGestureErrorDetector {
|
||||
/* condition= */ encounteredEvents.contains(
|
||||
GestureEvent.STATE_CAPTURE_SCREENSHOT)
|
||||
&& !encounteredEvents.contains(GestureEvent.STATE_SCREENSHOT_CAPTURED),
|
||||
/* errorMessage= */ prefix + "\t\tSTATE_CAPTURE_SCREENSHOT was set, but "
|
||||
prefix,
|
||||
/* errorMessage= */ "STATE_CAPTURE_SCREENSHOT was set, but "
|
||||
+ "STATE_SCREENSHOT_CAPTURED wasn't.",
|
||||
writer);
|
||||
|
||||
@@ -278,15 +315,18 @@ public class ActiveGestureErrorDetector {
|
||||
GestureEvent.SET_ON_PAGE_TRANSITION_END_CALLBACK)
|
||||
&& !encounteredEvents.contains(
|
||||
GestureEvent.STATE_RECENTS_SCROLLING_FINISHED),
|
||||
/* errorMessage= */ prefix + "\t\tsetOnPageTransitionEndCallback called, but "
|
||||
prefix,
|
||||
/* errorMessage= */ "setOnPageTransitionEndCallback called, but "
|
||||
+ "STATE_RECENTS_SCROLLING_FINISHED wasn't set.",
|
||||
writer);
|
||||
|
||||
errorDetected |= printErrorIfTrue(
|
||||
/* condition= */ !encounteredEvents.contains(
|
||||
GestureEvent.CANCEL_CURRENT_ANIMATION)
|
||||
/* condition= */ encounteredEvents.contains(
|
||||
GestureEvent.FLAG_USING_OTHER_ACTIVITY_INPUT_CONSUMER)
|
||||
&& !encounteredEvents.contains(GestureEvent.CANCEL_CURRENT_ANIMATION)
|
||||
&& !encounteredEvents.contains(GestureEvent.STATE_HANDLER_INVALIDATED),
|
||||
/* errorMessage= */ prefix + "\t\tAbsSwipeUpHandler.cancelCurrentAnimation "
|
||||
prefix,
|
||||
/* errorMessage= */ "AbsSwipeUpHandler.cancelCurrentAnimation "
|
||||
+ "wasn't called and STATE_HANDLER_INVALIDATED wasn't set.",
|
||||
writer);
|
||||
|
||||
@@ -294,23 +334,17 @@ public class ActiveGestureErrorDetector {
|
||||
/* condition= */ encounteredEvents.contains(
|
||||
GestureEvent.STATE_RECENTS_ANIMATION_CANCELED)
|
||||
&& !encounteredEvents.contains(GestureEvent.CLEANUP_SCREENSHOT),
|
||||
/* errorMessage= */ prefix + "\t\tSTATE_RECENTS_ANIMATION_CANCELED was set but "
|
||||
prefix,
|
||||
/* errorMessage= */ "STATE_RECENTS_ANIMATION_CANCELED was set but "
|
||||
+ "the task screenshot wasn't cleaned up.",
|
||||
writer);
|
||||
|
||||
errorDetected |= printErrorIfTrue(
|
||||
/* condition= */ encounteredEvents.contains(
|
||||
GestureEvent.SET_END_TARGET_LAST_TASK)
|
||||
GestureEvent.EXPECTING_TASK_APPEARED)
|
||||
&& !encounteredEvents.contains(GestureEvent.TASK_APPEARED),
|
||||
/* errorMessage= */ prefix + "\t\tend target set to last task, but "
|
||||
+ "onTaskAppeared wasn't called.",
|
||||
writer);
|
||||
errorDetected |= printErrorIfTrue(
|
||||
/* condition= */ encounteredEvents.contains(
|
||||
GestureEvent.SET_END_TARGET_NEW_TASK)
|
||||
&& !encounteredEvents.contains(GestureEvent.TASK_APPEARED),
|
||||
/* errorMessage= */ prefix + "\t\tend target set to new task, but "
|
||||
+ "onTaskAppeared wasn't called.",
|
||||
prefix,
|
||||
/* errorMessage= */ "onTaskAppeared was expected to be called but wasn't.",
|
||||
writer);
|
||||
|
||||
if (!errorDetected) {
|
||||
@@ -320,11 +354,11 @@ public class ActiveGestureErrorDetector {
|
||||
}
|
||||
|
||||
private static boolean printErrorIfTrue(
|
||||
boolean condition, String errorMessage, PrintWriter writer) {
|
||||
boolean condition, String prefix, String errorMessage, PrintWriter writer) {
|
||||
if (!condition) {
|
||||
return false;
|
||||
}
|
||||
writer.println(errorMessage);
|
||||
writer.println(prefix + "\t\t- " + errorMessage);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,107 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2020 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.android.quickstep.util;
|
||||
|
||||
import static android.view.Surface.ROTATION_0;
|
||||
import static android.view.Surface.ROTATION_180;
|
||||
|
||||
import android.annotation.TargetApi;
|
||||
import android.content.Context;
|
||||
import android.os.Build;
|
||||
import android.view.WindowManager;
|
||||
import android.view.WindowMetrics;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.annotation.UiThread;
|
||||
|
||||
import com.android.launcher3.R;
|
||||
import com.android.launcher3.util.DisplayController;
|
||||
import com.android.launcher3.util.WindowBounds;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
/**
|
||||
* Utility class to hold the information abound a window bounds for split screen
|
||||
*/
|
||||
@TargetApi(Build.VERSION_CODES.R)
|
||||
public class SplitScreenBounds {
|
||||
|
||||
public static final SplitScreenBounds INSTANCE = new SplitScreenBounds();
|
||||
private final ArrayList<OnChangeListener> mListeners = new ArrayList<>();
|
||||
|
||||
@Nullable
|
||||
private WindowBounds mBounds;
|
||||
|
||||
private SplitScreenBounds() { }
|
||||
|
||||
@UiThread
|
||||
public void setSecondaryWindowBounds(@NonNull WindowBounds bounds) {
|
||||
if (!bounds.equals(mBounds)) {
|
||||
mBounds = bounds;
|
||||
for (OnChangeListener listener : mListeners) {
|
||||
listener.onSecondaryWindowBoundsChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public @NonNull WindowBounds getSecondaryWindowBounds(Context context) {
|
||||
if (mBounds == null) {
|
||||
mBounds = createDefaultWindowBounds(context);
|
||||
}
|
||||
return mBounds;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates window bounds as 50% of device size
|
||||
*/
|
||||
private static WindowBounds createDefaultWindowBounds(Context context) {
|
||||
WindowMetrics wm = context.getSystemService(WindowManager.class).getMaximumWindowMetrics();
|
||||
WindowBounds bounds = WindowBounds.fromWindowMetrics(wm);
|
||||
|
||||
int rotation = DisplayController.INSTANCE.get(context).getInfo().rotation;
|
||||
int halfDividerSize = context.getResources()
|
||||
.getDimensionPixelSize(R.dimen.multi_window_task_divider_size) / 2;
|
||||
|
||||
if (rotation == ROTATION_0 || rotation == ROTATION_180) {
|
||||
bounds.bounds.top = bounds.insets.top + bounds.availableSize.y / 2 + halfDividerSize;
|
||||
bounds.insets.top = 0;
|
||||
} else {
|
||||
bounds.bounds.left = bounds.insets.left + bounds.availableSize.x / 2 + halfDividerSize;
|
||||
bounds.insets.left = 0;
|
||||
}
|
||||
return new WindowBounds(bounds.bounds, bounds.insets);
|
||||
}
|
||||
|
||||
public void addOnChangeListener(OnChangeListener listener) {
|
||||
mListeners.add(listener);
|
||||
}
|
||||
|
||||
public void removeOnChangeListener(OnChangeListener listener) {
|
||||
mListeners.remove(listener);
|
||||
}
|
||||
|
||||
/**
|
||||
* Interface to receive window bounds changes
|
||||
*/
|
||||
public interface OnChangeListener {
|
||||
|
||||
/**
|
||||
* Called when window bounds for secondary window changes
|
||||
*/
|
||||
void onSecondaryWindowBoundsChanged();
|
||||
}
|
||||
}
|
||||
@@ -178,7 +178,6 @@ import com.android.quickstep.util.GroupTask;
|
||||
import com.android.quickstep.util.LayoutUtils;
|
||||
import com.android.quickstep.util.RecentsOrientedState;
|
||||
import com.android.quickstep.util.SplitAnimationTimings;
|
||||
import com.android.quickstep.util.SplitScreenBounds;
|
||||
import com.android.quickstep.util.SplitSelectStateController;
|
||||
import com.android.quickstep.util.SurfaceTransaction;
|
||||
import com.android.quickstep.util.SurfaceTransactionApplier;
|
||||
@@ -210,7 +209,7 @@ import java.util.function.Consumer;
|
||||
public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_TYPE>,
|
||||
STATE_TYPE extends BaseState<STATE_TYPE>> extends PagedView implements Insettable,
|
||||
TaskThumbnailCache.HighResLoadingState.HighResLoadingStateChangedCallback,
|
||||
TaskVisualsChangeListener, SplitScreenBounds.OnChangeListener {
|
||||
TaskVisualsChangeListener {
|
||||
|
||||
private static final String TAG = "RecentsView";
|
||||
private static final boolean DEBUG = false;
|
||||
@@ -948,7 +947,6 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T
|
||||
SystemUiProxy.INSTANCE.get(getContext()).setPipAnimationListener(
|
||||
mIPipAnimationListener);
|
||||
mOrientationState.initListeners();
|
||||
SplitScreenBounds.INSTANCE.addOnChangeListener(this);
|
||||
mTaskOverlayFactory.initListeners();
|
||||
}
|
||||
|
||||
@@ -965,7 +963,6 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T
|
||||
executeSideTaskLaunchCallback();
|
||||
RecentsModel.INSTANCE.get(getContext()).removeThumbnailChangeListener(this);
|
||||
SystemUiProxy.INSTANCE.get(getContext()).setPipAnimationListener(null);
|
||||
SplitScreenBounds.INSTANCE.removeOnChangeListener(this);
|
||||
mIPipAnimationListener.setActivityAndRecentsView(null, null);
|
||||
mOrientationState.destroyListeners();
|
||||
mTaskOverlayFactory.removeListeners();
|
||||
@@ -2900,6 +2897,19 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T
|
||||
|
||||
InteractionJankMonitorWrapper.begin(this,
|
||||
InteractionJankMonitorWrapper.CUJ_SPLIT_SCREEN_ENTER, "First tile selected");
|
||||
anim.addListener(new AnimatorListenerAdapter() {
|
||||
@Override
|
||||
public void onAnimationStart(Animator animation) {
|
||||
if (mSplitHiddenTaskView == getRunningTaskView()) {
|
||||
finishRecentsAnimation(true /* toRecents */, false /* shouldPip */,
|
||||
null /* onFinishComplete */);
|
||||
} else {
|
||||
switchToScreenshot(
|
||||
() -> finishRecentsAnimation(true /* toRecents */,
|
||||
false /* shouldPip */, null /* onFinishComplete */));
|
||||
}
|
||||
}
|
||||
});
|
||||
anim.addEndListener(success -> {
|
||||
if (success) {
|
||||
InteractionJankMonitorWrapper.end(
|
||||
@@ -4190,8 +4200,6 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T
|
||||
mSplitSelectStateController.setInitialTaskSelect(taskView.getTask(),
|
||||
stagePosition, splitEvent, taskView.getItemInfo());
|
||||
mSplitHiddenTaskViewIndex = indexOfChild(taskView);
|
||||
finishRecentsAnimation(true /* toRecents */, false /* shouldPip */,
|
||||
null /* onFinishComplete */);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -5198,12 +5206,6 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSecondaryWindowBoundsChanged() {
|
||||
// Invalidate the task view size
|
||||
setInsets(mInsets);
|
||||
}
|
||||
|
||||
/** Enables or disables modal state for RecentsView */
|
||||
public abstract void setModalStateEnabled(boolean isModalState, boolean animate);
|
||||
|
||||
|
||||
@@ -367,7 +367,9 @@
|
||||
<dimen name="transient_taskbar_margin">0dp</dimen>
|
||||
<dimen name="transient_taskbar_shadow_blur">0dp</dimen>
|
||||
<dimen name="transient_taskbar_key_shadow_distance">0dp</dimen>
|
||||
<dimen name="transient_taskbar_icon_spacing">10dp</dimen>
|
||||
<dimen name="transient_taskbar_stashed_size">0dp</dimen>
|
||||
<!-- Note that this applies to both sides of all icons, so visible space is double this. -->
|
||||
<dimen name="transient_taskbar_icon_spacing">0dp</dimen>
|
||||
<!-- Note that this applies to both sides of all icons, so visible space is double this. -->
|
||||
<dimen name="taskbar_icon_spacing">8dp</dimen>
|
||||
<dimen name="taskbar_nav_buttons_size">0dp</dimen>
|
||||
|
||||
@@ -402,7 +402,6 @@ public class CellLayout extends ViewGroup {
|
||||
mCountY = y;
|
||||
mOccupied = new GridOccupancy(mCountX, mCountY);
|
||||
mTmpOccupied = new GridOccupancy(mCountX, mCountY);
|
||||
mTempRectStack.clear();
|
||||
mShortcutsAndWidgets.setCellDimensions(mCellWidth, mCellHeight, mCountX, mCountY,
|
||||
mBorderSpace);
|
||||
requestLayout();
|
||||
@@ -1247,21 +1246,6 @@ public class CellLayout extends ViewGroup {
|
||||
result, resultSpan);
|
||||
}
|
||||
|
||||
private final Stack<Rect> mTempRectStack = new Stack<>();
|
||||
private void lazyInitTempRectStack() {
|
||||
if (mTempRectStack.isEmpty()) {
|
||||
for (int i = 0; i < mCountX * mCountY; i++) {
|
||||
mTempRectStack.push(new Rect());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void recycleTempRects(Stack<Rect> used) {
|
||||
while (!used.isEmpty()) {
|
||||
mTempRectStack.push(used.pop());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Find a vacant area that will fit the given bounds nearest the requested
|
||||
* cell location. Uses Euclidean distance to score multiple vacant areas.
|
||||
@@ -1281,8 +1265,6 @@ public class CellLayout extends ViewGroup {
|
||||
*/
|
||||
private int[] findNearestArea(int relativeXPos, int relativeYPos, int minSpanX, int minSpanY,
|
||||
int spanX, int spanY, boolean ignoreOccupied, int[] result, int[] resultSpan) {
|
||||
lazyInitTempRectStack();
|
||||
|
||||
// For items with a spanX / spanY > 1, the passed in point (relativeXPos, relativeYPos)
|
||||
// corresponds to the center of the item, but we are searching based on the top-left cell,
|
||||
// so we translate the point over to correspond to the top-left.
|
||||
@@ -1352,9 +1334,6 @@ public class CellLayout extends ViewGroup {
|
||||
hitMaxY |= ySize >= spanY;
|
||||
incX = !incX;
|
||||
}
|
||||
incX = true;
|
||||
hitMaxX = xSize >= spanX;
|
||||
hitMaxY = ySize >= spanY;
|
||||
}
|
||||
final int[] cellXY = mTmpPoint;
|
||||
cellToCenterPoint(x, y, cellXY);
|
||||
@@ -1362,8 +1341,7 @@ public class CellLayout extends ViewGroup {
|
||||
// We verify that the current rect is not a sub-rect of any of our previous
|
||||
// candidates. In this case, the current rect is disqualified in favour of the
|
||||
// containing rect.
|
||||
Rect currentRect = mTempRectStack.pop();
|
||||
currentRect.set(x, y, x + xSize, y + ySize);
|
||||
Rect currentRect = new Rect(x, y, x + xSize, y + ySize);
|
||||
boolean contained = false;
|
||||
for (Rect r : validRegions) {
|
||||
if (r.contains(currentRect)) {
|
||||
@@ -1393,7 +1371,6 @@ public class CellLayout extends ViewGroup {
|
||||
bestXY[0] = -1;
|
||||
bestXY[1] = -1;
|
||||
}
|
||||
recycleTempRects(validRegions);
|
||||
return bestXY;
|
||||
}
|
||||
|
||||
@@ -2544,21 +2521,21 @@ public class CellLayout extends ViewGroup {
|
||||
if (result == null) {
|
||||
result = new int[]{-1, -1};
|
||||
}
|
||||
ItemConfiguration finalSolution;
|
||||
// When we are checking drop validity or actually dropping, we don't recompute the
|
||||
// direction vector, since we want the solution to match the preview, and it's possible
|
||||
// that the exact position of the item has changed to result in a new reordering outcome.
|
||||
if ((mode == MODE_ON_DROP || mode == MODE_ON_DROP_EXTERNAL || mode == MODE_ACCEPT_DROP)
|
||||
&& mPreviousSolution != null) {
|
||||
|
||||
ItemConfiguration finalSolution = null;
|
||||
// We want the solution to match the animation of the preview and to match the drop so we
|
||||
// only recalculate in mode MODE_SHOW_REORDER_HINT because that the first one to run in the
|
||||
// reorder cycle.
|
||||
if (mode == MODE_SHOW_REORDER_HINT || mPreviousSolution == null) {
|
||||
finalSolution = calculateReorder(pixelX, pixelY, minSpanX, minSpanY, spanX, spanY,
|
||||
dragView);
|
||||
mPreviousSolution = finalSolution;
|
||||
} else {
|
||||
finalSolution = mPreviousSolution;
|
||||
// We reset this vector after drop
|
||||
if (mode == MODE_ON_DROP || mode == MODE_ON_DROP_EXTERNAL) {
|
||||
mPreviousSolution = null;
|
||||
}
|
||||
} else {
|
||||
finalSolution = calculateReorder(pixelX, pixelY, minSpanX, minSpanY, spanX, spanY,
|
||||
dragView);
|
||||
mPreviousSolution = finalSolution;
|
||||
}
|
||||
|
||||
if (finalSolution == null || !finalSolution.isSolution) {
|
||||
|
||||
@@ -312,10 +312,14 @@ public class DeviceProfile {
|
||||
}
|
||||
|
||||
if (isTaskbarPresent) {
|
||||
taskbarSize = DisplayController.isTransientTaskbar(context)
|
||||
? res.getDimensionPixelSize(R.dimen.transient_taskbar_size)
|
||||
: res.getDimensionPixelSize(R.dimen.taskbar_size);
|
||||
stashedTaskbarSize = res.getDimensionPixelSize(R.dimen.taskbar_stashed_size);
|
||||
if (DisplayController.isTransientTaskbar(context)) {
|
||||
taskbarSize = res.getDimensionPixelSize(R.dimen.transient_taskbar_size);
|
||||
stashedTaskbarSize =
|
||||
res.getDimensionPixelSize(R.dimen.transient_taskbar_stashed_size);
|
||||
} else {
|
||||
taskbarSize = res.getDimensionPixelSize(R.dimen.taskbar_size);
|
||||
stashedTaskbarSize = res.getDimensionPixelSize(R.dimen.taskbar_stashed_size);
|
||||
}
|
||||
}
|
||||
|
||||
edgeMarginPx = res.getDimensionPixelSize(R.dimen.dynamic_grid_edge_margin);
|
||||
|
||||
@@ -53,6 +53,8 @@ import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCH
|
||||
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_ALLAPPS_EXIT;
|
||||
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_ONRESUME;
|
||||
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_ONSTOP;
|
||||
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_SWIPELEFT;
|
||||
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_SWIPERIGHT;
|
||||
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_WIDGET_RECONFIGURED;
|
||||
import static com.android.launcher3.model.ItemInstallQueue.FLAG_ACTIVITY_PAUSED;
|
||||
import static com.android.launcher3.model.ItemInstallQueue.FLAG_DRAG_AND_DROP;
|
||||
@@ -183,7 +185,6 @@ import com.android.launcher3.states.RotationHelper;
|
||||
import com.android.launcher3.testing.TestLogging;
|
||||
import com.android.launcher3.testing.shared.TestProtocol;
|
||||
import com.android.launcher3.touch.AllAppsSwipeController;
|
||||
import com.android.launcher3.touch.ItemClickHandler;
|
||||
import com.android.launcher3.uioverrides.plugins.PluginManagerWrapper;
|
||||
import com.android.launcher3.util.ActivityResultInfo;
|
||||
import com.android.launcher3.util.ActivityTracker;
|
||||
@@ -222,7 +223,6 @@ import com.android.systemui.plugins.PluginListener;
|
||||
import com.android.systemui.plugins.shared.LauncherExterns;
|
||||
import com.android.systemui.plugins.shared.LauncherOverlayManager;
|
||||
import com.android.systemui.plugins.shared.LauncherOverlayManager.LauncherOverlay;
|
||||
import com.android.systemui.plugins.shared.LauncherOverlayManager.LauncherOverlayCallbacks;
|
||||
|
||||
import java.io.FileDescriptor;
|
||||
import java.io.PrintWriter;
|
||||
@@ -242,7 +242,7 @@ import java.util.stream.Stream;
|
||||
*/
|
||||
public class Launcher extends StatefulActivity<LauncherState>
|
||||
implements LauncherExterns, Callbacks, InvariantDeviceProfile.OnIDPChangeListener,
|
||||
PluginListener<LauncherOverlayPlugin>, LauncherOverlayCallbacks {
|
||||
PluginListener<LauncherOverlayPlugin> {
|
||||
public static final String TAG = "Launcher";
|
||||
|
||||
public static final ActivityTracker<Launcher> ACTIVITY_TRACKER = new ActivityTracker<>();
|
||||
@@ -696,17 +696,9 @@ public class Launcher extends StatefulActivity<LauncherState>
|
||||
*/
|
||||
@Override
|
||||
public void setLauncherOverlay(LauncherOverlay overlay) {
|
||||
if (overlay != null) {
|
||||
overlay.setOverlayCallbacks(this);
|
||||
}
|
||||
mWorkspace.setLauncherOverlay(overlay);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void runOnOverlayHidden(Runnable runnable) {
|
||||
getWorkspace().runOnOverlayHidden(runnable);
|
||||
}
|
||||
|
||||
public boolean setLauncherCallbacks(LauncherCallbacks callbacks) {
|
||||
mLauncherCallbacks = callbacks;
|
||||
return true;
|
||||
@@ -1213,18 +1205,6 @@ public class Launcher extends StatefulActivity<LauncherState>
|
||||
mAppWidgetHolder.setActivityResumed(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@code LauncherOverlayCallbacks} scroll amount.
|
||||
* Indicates transition progress to -1 screen.
|
||||
* @param progress From 0 to 1.
|
||||
*/
|
||||
@Override
|
||||
public void onScrollChanged(float progress) {
|
||||
if (mWorkspace != null) {
|
||||
mWorkspace.onOverlayScrollChanged(progress);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Restores the previous state, if it exists.
|
||||
*
|
||||
@@ -2895,7 +2875,16 @@ public class Launcher extends StatefulActivity<LauncherState>
|
||||
/**
|
||||
* Informs us that the overlay (-1 screen, typically), has either become visible or invisible.
|
||||
*/
|
||||
public void onOverlayVisibilityChanged(boolean visible) {}
|
||||
public void onOverlayVisibilityChanged(boolean visible) {
|
||||
getStatsLogManager().logger()
|
||||
.withSrcState(LAUNCHER_STATE_HOME)
|
||||
.withDstState(LAUNCHER_STATE_HOME)
|
||||
.withContainerInfo(LauncherAtom.ContainerInfo.newBuilder()
|
||||
.setWorkspace(WorkspaceContainer.newBuilder()
|
||||
.setPageIndex(visible ? 0 : -1))
|
||||
.build())
|
||||
.log(visible ? LAUNCHER_SWIPELEFT : LAUNCHER_SWIPERIGHT);
|
||||
}
|
||||
|
||||
/**
|
||||
* Informs us that the page transition has ended, so that we can react to the newly selected
|
||||
|
||||
@@ -26,7 +26,6 @@ import static com.android.launcher3.LauncherState.HINT_STATE;
|
||||
import static com.android.launcher3.LauncherState.NORMAL;
|
||||
import static com.android.launcher3.LauncherState.SPRING_LOADED;
|
||||
import static com.android.launcher3.anim.AnimatorListeners.forSuccessCallback;
|
||||
import static com.android.launcher3.dragndrop.DragLayer.ALPHA_INDEX_OVERLAY;
|
||||
import static com.android.launcher3.logging.StatsLogManager.LAUNCHER_STATE_HOME;
|
||||
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_SWIPELEFT;
|
||||
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_SWIPERIGHT;
|
||||
@@ -58,7 +57,6 @@ import android.view.LayoutInflater;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.ViewTreeObserver;
|
||||
import android.view.accessibility.AccessibilityNodeInfo;
|
||||
import android.widget.FrameLayout;
|
||||
import android.widget.Toast;
|
||||
@@ -119,6 +117,7 @@ import com.android.launcher3.widget.WidgetManagerHelper;
|
||||
import com.android.launcher3.widget.dragndrop.AppWidgetHostViewDragListener;
|
||||
import com.android.launcher3.widget.util.WidgetSizes;
|
||||
import com.android.systemui.plugins.shared.LauncherOverlayManager.LauncherOverlay;
|
||||
import com.android.systemui.plugins.shared.LauncherOverlayManager.LauncherOverlayCallbacks;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
@@ -136,7 +135,7 @@ import java.util.stream.Collectors;
|
||||
public class Workspace<T extends View & PageIndicator> extends PagedView<T>
|
||||
implements DropTarget, DragSource, View.OnTouchListener,
|
||||
DragController.DragListener, Insettable, StateHandler<LauncherState>,
|
||||
WorkspaceLayoutManager, LauncherBindableItemsContainer {
|
||||
WorkspaceLayoutManager, LauncherBindableItemsContainer, LauncherOverlayCallbacks {
|
||||
|
||||
/** The value that {@link #mTransitionProgress} must be greater than for
|
||||
* {@link #transitionStateShouldAllowDrop()} to return true. */
|
||||
@@ -254,14 +253,12 @@ public class Workspace<T extends View & PageIndicator> extends PagedView<T>
|
||||
|
||||
// State related to Launcher Overlay
|
||||
private OverlayEdgeEffect mOverlayEdgeEffect;
|
||||
boolean mOverlayShown = false;
|
||||
private Runnable mOnOverlayHiddenCallback;
|
||||
private boolean mOverlayShown = false;
|
||||
private float mOverlayProgress; // 1 -> overlay completely visible, 0 -> home visible
|
||||
private final List<LauncherOverlayCallbacks> mOverlayCallbacks = new ArrayList<>();
|
||||
|
||||
private boolean mForceDrawAdjacentPages = false;
|
||||
|
||||
// Total over scrollX in the overlay direction.
|
||||
private float mOverlayTranslation;
|
||||
|
||||
// Handles workspace state transitions
|
||||
private final WorkspaceStateTransitionAnimation mStateTransitionAnimation;
|
||||
|
||||
@@ -1151,9 +1148,15 @@ public class Workspace<T extends View & PageIndicator> extends PagedView<T>
|
||||
}
|
||||
|
||||
public void setLauncherOverlay(LauncherOverlay overlay) {
|
||||
mOverlayEdgeEffect = overlay == null ? null : new OverlayEdgeEffect(getContext(), overlay);
|
||||
EdgeEffectCompat newEffect = overlay == null
|
||||
? new EdgeEffectCompat(getContext()) : mOverlayEdgeEffect;
|
||||
final EdgeEffectCompat newEffect;
|
||||
if (overlay == null) {
|
||||
newEffect = new EdgeEffectCompat(getContext());
|
||||
mOverlayEdgeEffect = null;
|
||||
} else {
|
||||
newEffect = mOverlayEdgeEffect = new OverlayEdgeEffect(getContext(), overlay);
|
||||
overlay.setOverlayCallbacks(this);
|
||||
}
|
||||
|
||||
if (mIsRtl) {
|
||||
mEdgeGlowRight = newEffect;
|
||||
} else {
|
||||
@@ -1203,132 +1206,46 @@ public class Workspace<T extends View & PageIndicator> extends PagedView<T>
|
||||
@Override
|
||||
protected boolean shouldFlingForVelocity(int velocityX) {
|
||||
// When the overlay is moving, the fling or settle transition is controlled by the overlay.
|
||||
return Float.compare(Math.abs(mOverlayTranslation), 0) == 0 &&
|
||||
super.shouldFlingForVelocity(velocityX);
|
||||
return Float.compare(Math.abs(mOverlayProgress), 0) == 0
|
||||
&& super.shouldFlingForVelocity(velocityX);
|
||||
}
|
||||
|
||||
/**
|
||||
* The overlay scroll is being controlled locally, just update our overlay effect
|
||||
*/
|
||||
@Override
|
||||
public void onOverlayScrollChanged(float scroll) {
|
||||
if (Float.compare(scroll, 1f) == 0) {
|
||||
mOverlayProgress = Utilities.boundToRange(scroll, 0, 1);
|
||||
if (Float.compare(mOverlayProgress, 1f) == 0) {
|
||||
if (!mOverlayShown) {
|
||||
mLauncher.getStatsLogManager().logger()
|
||||
.withSrcState(LAUNCHER_STATE_HOME)
|
||||
.withDstState(LAUNCHER_STATE_HOME)
|
||||
.withContainerInfo(LauncherAtom.ContainerInfo.newBuilder()
|
||||
.setWorkspace(
|
||||
LauncherAtom.WorkspaceContainer.newBuilder()
|
||||
.setPageIndex(0))
|
||||
.build())
|
||||
.log(LAUNCHER_SWIPELEFT);
|
||||
mOverlayShown = true;
|
||||
mLauncher.onOverlayVisibilityChanged(true);
|
||||
}
|
||||
mOverlayShown = true;
|
||||
|
||||
// Let the Launcher activity know that the overlay is now visible.
|
||||
mLauncher.onOverlayVisibilityChanged(mOverlayShown);
|
||||
|
||||
// Not announcing the overlay page for accessibility since it announces itself.
|
||||
} else if (Float.compare(scroll, 0f) == 0) {
|
||||
} else if (Float.compare(mOverlayProgress, 0f) == 0) {
|
||||
if (mOverlayShown) {
|
||||
// TODO: this is logged unnecessarily on home gesture.
|
||||
mLauncher.getStatsLogManager().logger()
|
||||
.withSrcState(LAUNCHER_STATE_HOME)
|
||||
.withDstState(LAUNCHER_STATE_HOME)
|
||||
.withContainerInfo(LauncherAtom.ContainerInfo.newBuilder()
|
||||
.setWorkspace(
|
||||
LauncherAtom.WorkspaceContainer.newBuilder()
|
||||
.setPageIndex(-1))
|
||||
.build())
|
||||
.log(LAUNCHER_SWIPERIGHT);
|
||||
} else if (Float.compare(mOverlayTranslation, 0f) != 0) {
|
||||
// When arriving to 0 overscroll from non-zero overscroll, announce page for
|
||||
// accessibility since default announcements were disabled while in overscroll
|
||||
// state.
|
||||
// Not doing this if mOverlayShown because in that case the accessibility service
|
||||
// will announce the launcher window description upon regaining focus after
|
||||
// switching from the overlay screen.
|
||||
announcePageForAccessibility();
|
||||
mOverlayShown = false;
|
||||
mLauncher.onOverlayVisibilityChanged(false);
|
||||
}
|
||||
mOverlayShown = false;
|
||||
|
||||
// Let the Launcher activity know that the overlay is no longer visible.
|
||||
mLauncher.onOverlayVisibilityChanged(mOverlayShown);
|
||||
|
||||
tryRunOverlayCallback();
|
||||
}
|
||||
|
||||
float offset = 0f;
|
||||
|
||||
scroll = Math.max(scroll - offset, 0);
|
||||
scroll = Math.min(1, scroll / (1 - offset));
|
||||
|
||||
float alpha = 1 - Interpolators.DEACCEL_3.getInterpolation(scroll);
|
||||
float transX = mLauncher.getDragLayer().getMeasuredWidth() * scroll;
|
||||
|
||||
if (mIsRtl) {
|
||||
transX = -transX;
|
||||
int count = mOverlayCallbacks.size();
|
||||
for (int i = 0; i < count; i++) {
|
||||
mOverlayCallbacks.get(i).onOverlayScrollChanged(mOverlayProgress);
|
||||
}
|
||||
mOverlayTranslation = transX;
|
||||
|
||||
// TODO(adamcohen): figure out a final effect here. We may need to recommend
|
||||
// different effects based on device performance. On at least one relatively high-end
|
||||
// device I've tried, translating the launcher causes things to get quite laggy.
|
||||
mLauncher.getDragLayer().setTranslationX(transX);
|
||||
mLauncher.getDragLayer().getAlphaProperty(ALPHA_INDEX_OVERLAY).setValue(alpha);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return false if the callback is still pending
|
||||
* Adds a callback for receiving overlay progress
|
||||
*/
|
||||
private boolean tryRunOverlayCallback() {
|
||||
if (mOnOverlayHiddenCallback == null) {
|
||||
// Return true as no callback is pending. This is used by OnWindowFocusChangeListener
|
||||
// to remove itself if multiple focus handles were added.
|
||||
return true;
|
||||
}
|
||||
if (mOverlayShown || !hasWindowFocus()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
mOnOverlayHiddenCallback.run();
|
||||
mOnOverlayHiddenCallback = null;
|
||||
return true;
|
||||
public void addOverlayCallback(LauncherOverlayCallbacks callback) {
|
||||
mOverlayCallbacks.add(callback);
|
||||
callback.onOverlayScrollChanged(mOverlayProgress);
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs the given callback when the minus one overlay is hidden. Specifically, it is run
|
||||
* when launcher's window has focus and the overlay is no longer being shown. If a callback
|
||||
* is already present, the new callback will chain off it so both are run.
|
||||
*
|
||||
* @return Whether the callback was deferred.
|
||||
* Removes a previously added overlay progress callback
|
||||
*/
|
||||
public boolean runOnOverlayHidden(Runnable callback) {
|
||||
if (mOnOverlayHiddenCallback == null) {
|
||||
mOnOverlayHiddenCallback = callback;
|
||||
} else {
|
||||
// Chain the new callback onto the previous callback(s).
|
||||
Runnable oldCallback = mOnOverlayHiddenCallback;
|
||||
mOnOverlayHiddenCallback = () -> {
|
||||
oldCallback.run();
|
||||
callback.run();
|
||||
};
|
||||
}
|
||||
if (!tryRunOverlayCallback()) {
|
||||
ViewTreeObserver observer = getViewTreeObserver();
|
||||
if (observer != null && observer.isAlive()) {
|
||||
observer.addOnWindowFocusChangeListener(
|
||||
new ViewTreeObserver.OnWindowFocusChangeListener() {
|
||||
@Override
|
||||
public void onWindowFocusChanged(boolean hasFocus) {
|
||||
if (tryRunOverlayCallback() && observer.isAlive()) {
|
||||
observer.removeOnWindowFocusChangeListener(this);
|
||||
}
|
||||
}});
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
public void removeOverlayCallback(LauncherOverlayCallbacks callback) {
|
||||
mOverlayCallbacks.remove(callback);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -2467,23 +2384,20 @@ public class Workspace<T extends View & PageIndicator> extends PagedView<T>
|
||||
final View child = (mDragInfo == null) ? null : mDragInfo.cell;
|
||||
int reorderX = mTargetCell[0];
|
||||
int reorderY = mTargetCell[1];
|
||||
if (!nearestDropOccupied) {
|
||||
mDragTargetLayout.performReorder((int) mDragViewVisualCenter[0],
|
||||
(int) mDragViewVisualCenter[1], minSpanX, minSpanY, item.spanX, item.spanY,
|
||||
child, mTargetCell, new int[2], CellLayout.MODE_SHOW_REORDER_HINT);
|
||||
mDragTargetLayout.visualizeDropLocation(mTargetCell[0], mTargetCell[1],
|
||||
item.spanX, item.spanY, d);
|
||||
} else if ((mDragMode == DRAG_MODE_NONE || mDragMode == DRAG_MODE_REORDER)
|
||||
&& !mReorderAlarm.alarmPending()
|
||||
if ((mDragMode == DRAG_MODE_NONE || mDragMode == DRAG_MODE_REORDER)
|
||||
&& (mLastReorderX != reorderX || mLastReorderY != reorderY)
|
||||
&& targetCellDistance < mDragTargetLayout.getReorderRadius(mTargetCell, item.spanX,
|
||||
item.spanY)) {
|
||||
|
||||
int[] resultSpan = new int[2];
|
||||
mDragTargetLayout.performReorder((int) mDragViewVisualCenter[0],
|
||||
(int) mDragViewVisualCenter[1], minSpanX, minSpanY, item.spanX, item.spanY,
|
||||
child, mTargetCell, resultSpan, CellLayout.MODE_SHOW_REORDER_HINT);
|
||||
child, mTargetCell, new int[2], CellLayout.MODE_SHOW_REORDER_HINT);
|
||||
}
|
||||
|
||||
if (!nearestDropOccupied) {
|
||||
mDragTargetLayout.visualizeDropLocation(mTargetCell[0], mTargetCell[1],
|
||||
item.spanX, item.spanY, d);
|
||||
} else if ((mDragMode == DRAG_MODE_NONE || mDragMode == DRAG_MODE_REORDER)
|
||||
&& !mReorderAlarm.alarmPending()) {
|
||||
// Otherwise, if we aren't adding to or creating a folder and there's no pending
|
||||
// reorder, then we schedule a reorder
|
||||
ReorderAlarmListener listener = new ReorderAlarmListener(mDragViewVisualCenter,
|
||||
@@ -3470,7 +3384,7 @@ public class Workspace<T extends View & PageIndicator> extends PagedView<T>
|
||||
protected boolean canAnnouncePageDescription() {
|
||||
// Disable announcements while overscrolling potentially to overlay screen because if we end
|
||||
// up on the overlay screen, it will take care of announcing itself.
|
||||
return Float.compare(mOverlayTranslation, 0f) == 0;
|
||||
return Float.compare(mOverlayProgress, 0f) == 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -107,8 +107,7 @@ public abstract class BaseAllAppsContainerView<T extends Context & ActivityConte
|
||||
new RecyclerView.OnScrollListener() {
|
||||
@Override
|
||||
public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) {
|
||||
updateHeaderScroll(
|
||||
((AllAppsRecyclerView) recyclerView).computeVerticalScrollOffset());
|
||||
updateHeaderScroll(recyclerView.computeVerticalScrollOffset());
|
||||
}
|
||||
};
|
||||
|
||||
@@ -192,7 +191,6 @@ public abstract class BaseAllAppsContainerView<T extends Context & ActivityConte
|
||||
reset(true);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -815,6 +813,10 @@ public abstract class BaseAllAppsContainerView<T extends Context & ActivityConte
|
||||
}
|
||||
}
|
||||
|
||||
protected void onInitializeRecyclerView(RecyclerView rv) {
|
||||
rv.addOnScrollListener(mScrollListener);
|
||||
}
|
||||
|
||||
/** Holds a {@link BaseAllAppsAdapter} and related fields. */
|
||||
public class AdapterHolder {
|
||||
public static final int MAIN = 0;
|
||||
@@ -851,7 +853,7 @@ public abstract class BaseAllAppsContainerView<T extends Context & ActivityConte
|
||||
mRecyclerView.setHasFixedSize(true);
|
||||
// No animations will occur when changes occur to the items in this RecyclerView.
|
||||
mRecyclerView.setItemAnimator(null);
|
||||
mRecyclerView.addOnScrollListener(mScrollListener);
|
||||
onInitializeRecyclerView(mRecyclerView);
|
||||
FocusedItemDecorator focusedItemDecorator = new FocusedItemDecorator(mRecyclerView);
|
||||
mRecyclerView.addItemDecoration(focusedItemDecorator);
|
||||
mAdapter.setIconFocusListener(focusedItemDecorator.getFocusListener());
|
||||
|
||||
@@ -25,4 +25,11 @@ public class BaseSearchConfig {
|
||||
public boolean isKeyboardSyncEnabled() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether IME is enabled on swipe up.
|
||||
*/
|
||||
public boolean isImeEnabledOnSwipeUp() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,19 +16,50 @@
|
||||
package com.android.launcher3.allapps;
|
||||
|
||||
import android.content.Context;
|
||||
import android.text.TextUtils;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.WindowInsets;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import com.android.launcher3.ExtendedEditText;
|
||||
import com.android.launcher3.Launcher;
|
||||
import com.android.launcher3.LauncherState;
|
||||
import com.android.launcher3.Utilities;
|
||||
import com.android.launcher3.config.FeatureFlags;
|
||||
|
||||
/**
|
||||
* AllAppsContainerView with launcher specific callbacks
|
||||
*/
|
||||
public class LauncherAllAppsContainerView extends ActivityAllAppsContainerView<Launcher> {
|
||||
|
||||
private final RecyclerView.OnScrollListener mActivityScrollListener =
|
||||
new RecyclerView.OnScrollListener() {
|
||||
@Override
|
||||
public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) {
|
||||
int scrolledOffset = recyclerView.computeVerticalScrollOffset();
|
||||
ExtendedEditText input = mSearchUiManager.getEditText();
|
||||
// Scroll up and scroll to top
|
||||
if (dy < 0 && scrolledOffset == 0 && input != null) {
|
||||
boolean isImeEnabledOnSwipeUp = Launcher.getLauncher(mActivityContext)
|
||||
.getSearchConfig().isImeEnabledOnSwipeUp();
|
||||
if (isImeEnabledOnSwipeUp || !TextUtils.isEmpty(input.getText())) {
|
||||
input.showKeyboard();
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@Override
|
||||
protected void onInitializeRecyclerView(RecyclerView rv) {
|
||||
super.onInitializeRecyclerView(rv);
|
||||
if (FeatureFlags.SCROLL_TOP_TO_RESET.get()) {
|
||||
rv.addOnScrollListener(mActivityScrollListener);
|
||||
}
|
||||
}
|
||||
|
||||
public LauncherAllAppsContainerView(Context context) {
|
||||
this(context, null);
|
||||
}
|
||||
|
||||
@@ -96,6 +96,10 @@ public final class FeatureFlags {
|
||||
"ENABLE_QUICK_LAUNCH_V2", false, "Use quick launch v2 "
|
||||
+ "behavior. Quick search and quick launch v1 would be unavailable if this is enabled");
|
||||
|
||||
public static final BooleanFlag GBOARD_UPDATE_ENTER_KEY = new DeviceFlag(
|
||||
"GBOARD_UPDATE_ENTER_KEY", false, "Update gBoard enter key "
|
||||
+ "icon dynamically based on top search content for Quick Launch V2");
|
||||
|
||||
public static final BooleanFlag ENABLE_HIDE_HEADER = new DeviceFlag("ENABLE_HIDE_HEADER",
|
||||
true, "Hide header on keyboard before typing in all apps");
|
||||
|
||||
@@ -290,6 +294,10 @@ public final class FeatureFlags {
|
||||
public static final BooleanFlag ENABLE_WIDGET_PICKER_DEPTH = new DeviceFlag(
|
||||
"ENABLE_WIDGET_PICKER_DEPTH", true, "Enable changing depth in widget picker.");
|
||||
|
||||
public static final BooleanFlag SCROLL_TOP_TO_RESET = new DeviceFlag(
|
||||
"SCROLL_TOP_TO_RESET", false, "Bring up IME and focus on "
|
||||
+ "input when scroll to top if 'Always show keyboard' is enabled or in prefix state");
|
||||
|
||||
public static final BooleanFlag SHOW_DELIGHTFUL_PAGINATION = getDebugFlag(
|
||||
"SHOW_DELIGHTFUL_PAGINATION", false,
|
||||
"Enable showing the new 'delightful pagination' which is a brand"
|
||||
|
||||
@@ -47,7 +47,9 @@ import com.android.launcher3.DropTargetBar;
|
||||
import com.android.launcher3.Launcher;
|
||||
import com.android.launcher3.R;
|
||||
import com.android.launcher3.ShortcutAndWidgetContainer;
|
||||
import com.android.launcher3.Utilities;
|
||||
import com.android.launcher3.Workspace;
|
||||
import com.android.launcher3.anim.Interpolators;
|
||||
import com.android.launcher3.anim.PendingAnimation;
|
||||
import com.android.launcher3.anim.SpringProperty;
|
||||
import com.android.launcher3.celllayout.CellLayoutLayoutParams;
|
||||
@@ -56,13 +58,14 @@ import com.android.launcher3.graphics.Scrim;
|
||||
import com.android.launcher3.keyboard.ViewGroupFocusHelper;
|
||||
import com.android.launcher3.util.TouchController;
|
||||
import com.android.launcher3.views.BaseDragLayer;
|
||||
import com.android.systemui.plugins.shared.LauncherOverlayManager.LauncherOverlayCallbacks;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
/**
|
||||
* A ViewGroup that coordinates dragging across its descendants
|
||||
*/
|
||||
public class DragLayer extends BaseDragLayer<Launcher> {
|
||||
public class DragLayer extends BaseDragLayer<Launcher> implements LauncherOverlayCallbacks {
|
||||
|
||||
public static final int ALPHA_INDEX_OVERLAY = 0;
|
||||
private static final int ALPHA_CHANNEL_COUNT = 1;
|
||||
@@ -70,6 +73,8 @@ public class DragLayer extends BaseDragLayer<Launcher> {
|
||||
public static final int ANIMATION_END_DISAPPEAR = 0;
|
||||
public static final int ANIMATION_END_REMAIN_VISIBLE = 2;
|
||||
|
||||
private final boolean mIsRtl;
|
||||
|
||||
private DragController mDragController;
|
||||
|
||||
// Variables relating to animation of views after drop
|
||||
@@ -100,6 +105,7 @@ public class DragLayer extends BaseDragLayer<Launcher> {
|
||||
setChildrenDrawingOrderEnabled(true);
|
||||
|
||||
mFocusIndicatorHelper = new ViewGroupFocusHelper(this);
|
||||
mIsRtl = Utilities.isRtl(getResources());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -109,6 +115,7 @@ public class DragLayer extends BaseDragLayer<Launcher> {
|
||||
mDragController = dragController;
|
||||
recreateControllers();
|
||||
mWorkspaceDragScrim = new Scrim(this);
|
||||
workspace.addOverlayCallback(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -476,4 +483,16 @@ public class DragLayer extends BaseDragLayer<Launcher> {
|
||||
controller.onOneHandedModeStateChanged(activated);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onOverlayScrollChanged(float progress) {
|
||||
float alpha = 1 - Interpolators.DEACCEL_3.getInterpolation(progress);
|
||||
float transX = getMeasuredWidth() * progress;
|
||||
|
||||
if (mIsRtl) {
|
||||
transX = -transX;
|
||||
}
|
||||
setTranslationX(transX);
|
||||
getAlphaProperty(ALPHA_INDEX_OVERLAY).setValue(alpha);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -47,7 +47,9 @@ import com.android.launcher3.testing.shared.WorkspaceCellCenterRequest;
|
||||
import com.android.launcher3.util.ResourceBasedOverride;
|
||||
import com.android.launcher3.widget.picker.WidgetsFullSheet;
|
||||
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
@@ -214,8 +216,7 @@ public class TestInformationHandler implements ResourceBasedOverride {
|
||||
}
|
||||
|
||||
case TestProtocol.REQUEST_HAS_TIS: {
|
||||
response.putBoolean(
|
||||
TestProtocol.REQUEST_HAS_TIS, false);
|
||||
response.putBoolean(TestProtocol.REQUEST_HAS_TIS, false);
|
||||
return response;
|
||||
}
|
||||
|
||||
@@ -266,17 +267,24 @@ public class TestInformationHandler implements ResourceBasedOverride {
|
||||
*/
|
||||
private static <S, T> Bundle getUIProperty(
|
||||
BundleSetter<T> bundleSetter, Function<S, T> provider, Supplier<S> targetSupplier) {
|
||||
return getFromExecutorSync(MAIN_EXECUTOR, () -> {
|
||||
S target = targetSupplier.get();
|
||||
if (target == null) {
|
||||
return null;
|
||||
}
|
||||
T value = provider.apply(target);
|
||||
Bundle response = new Bundle();
|
||||
bundleSetter.set(response, TestProtocol.TEST_INFO_RESPONSE_FIELD, value);
|
||||
return response;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes the callback on the executor and waits for the result
|
||||
*/
|
||||
protected static <T> T getFromExecutorSync(ExecutorService executor, Callable<T> callback) {
|
||||
try {
|
||||
return MAIN_EXECUTOR.submit(() -> {
|
||||
S target = targetSupplier.get();
|
||||
if (target == null) {
|
||||
return null;
|
||||
}
|
||||
T value = provider.apply(target);
|
||||
Bundle response = new Bundle();
|
||||
bundleSetter.set(response, TestProtocol.TEST_INFO_RESPONSE_FIELD, value);
|
||||
return response;
|
||||
}).get();
|
||||
return executor.submit(callback).get();
|
||||
} catch (ExecutionException | InterruptedException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
@@ -128,6 +128,7 @@ public final class TestProtocol {
|
||||
public static final String REQUEST_GET_OVERVIEW_PAGE_SPACING = "get-overview-page-spacing";
|
||||
public static final String REQUEST_ENABLE_ROTATION = "enable_rotation";
|
||||
public static final String REQUEST_ENABLE_SUGGESTION = "enable-suggestion";
|
||||
public static final String REQUEST_MODEL_QUEUE_CLEARED = "model-queue-cleared";
|
||||
|
||||
public static boolean sDebugTracing = false;
|
||||
public static final String REQUEST_ENABLE_DEBUG_TRACING = "enable-debug-tracing";
|
||||
|
||||
@@ -40,10 +40,4 @@ public interface LauncherExterns {
|
||||
* Sets the overlay on the target activity
|
||||
*/
|
||||
void setLauncherOverlay(LauncherOverlay overlay);
|
||||
|
||||
/**
|
||||
* Executes the command, next time the overlay is hidden
|
||||
*/
|
||||
void runOnOverlayHidden(Runnable runnable);
|
||||
|
||||
}
|
||||
|
||||
@@ -93,6 +93,6 @@ public interface LauncherOverlayManager extends Application.ActivityLifecycleCal
|
||||
|
||||
interface LauncherOverlayCallbacks {
|
||||
|
||||
void onScrollChanged(float progress);
|
||||
void onOverlayScrollChanged(float progress);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
<uses-permission android:name="android.permission.PACKAGE_USAGE_STATS"/>
|
||||
<uses-permission android:name="android.permission.READ_LOGS"/>
|
||||
<uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS"/>
|
||||
<uses-permission android:name="android.permission.QUERY_ALL_PACKAGES" />
|
||||
|
||||
<application android:debuggable="true" android:extractNativeLibs="true">
|
||||
<uses-library android:name="android.test.runner"/>
|
||||
|
||||
@@ -29,7 +29,6 @@ import static org.junit.Assume.assumeTrue;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.graphics.Point;
|
||||
import android.os.SystemClock;
|
||||
import android.platform.test.annotations.IwTest;
|
||||
|
||||
import androidx.test.filters.LargeTest;
|
||||
@@ -479,7 +478,7 @@ public class TaplTestsLauncher3 extends AbstractLauncherUiTest {
|
||||
@Test
|
||||
@PortraitLandscape
|
||||
public void testUninstallFromWorkspace() throws Exception {
|
||||
TestUtil.installDummyApp();
|
||||
installDummyAppAndWaitForUIUpdate();
|
||||
try {
|
||||
verifyAppUninstalledFromAllApps(
|
||||
createShortcutInCenterIfNotExist(DUMMY_APP_NAME).uninstall(), DUMMY_APP_NAME);
|
||||
@@ -492,10 +491,8 @@ public class TaplTestsLauncher3 extends AbstractLauncherUiTest {
|
||||
@PortraitLandscape
|
||||
@ScreenRecord // (b/256659409)
|
||||
public void testUninstallFromAllApps() throws Exception {
|
||||
TestUtil.installDummyApp();
|
||||
installDummyAppAndWaitForUIUpdate();
|
||||
try {
|
||||
// b/256659409
|
||||
SystemClock.sleep(5000);
|
||||
Workspace workspace = mLauncher.getWorkspace();
|
||||
final HomeAllApps allApps = workspace.switchToAllApps();
|
||||
allApps.freeze();
|
||||
@@ -539,7 +536,7 @@ public class TaplTestsLauncher3 extends AbstractLauncherUiTest {
|
||||
Point[] gridPositions = getCornersAndCenterPositions();
|
||||
createShortcutIfNotExist(STORE_APP_NAME, gridPositions[0]);
|
||||
createShortcutIfNotExist(MAPS_APP_NAME, gridPositions[1]);
|
||||
TestUtil.installDummyApp();
|
||||
installDummyAppAndWaitForUIUpdate();
|
||||
try {
|
||||
createShortcutIfNotExist(DUMMY_APP_NAME, gridPositions[2]);
|
||||
Map<String, Point> initialPositions =
|
||||
@@ -590,6 +587,17 @@ public class TaplTestsLauncher3 extends AbstractLauncherUiTest {
|
||||
mLauncher.getWorkspace().getHotseatAppIcon(APP_NAME));
|
||||
}
|
||||
|
||||
private void installDummyAppAndWaitForUIUpdate() throws IOException {
|
||||
TestUtil.installDummyApp();
|
||||
// Wait for model thread completion as it may be processing
|
||||
// the install event from the SystemService
|
||||
mLauncher.waitForModelQueueCleared();
|
||||
// Wait for Launcher UI thread completion, as it may be processing updating the UI in
|
||||
// response to the model update. Not that `waitForLauncherInitialized` is just a proxy
|
||||
// method, we can use any method which touches Launcher UI thread,
|
||||
mLauncher.waitForLauncherInitialized();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return List of workspace grid coordinates. Those are not pixels. See {@link
|
||||
* Workspace#getIconGridDimensions()}
|
||||
|
||||
@@ -17,8 +17,13 @@ package com.android.launcher3.util;
|
||||
|
||||
import static androidx.test.InstrumentationRegistry.getContext;
|
||||
import static androidx.test.InstrumentationRegistry.getInstrumentation;
|
||||
import static androidx.test.InstrumentationRegistry.getTargetContext;
|
||||
|
||||
import android.content.pm.LauncherApps;
|
||||
import android.content.res.Resources;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import android.os.UserHandle;
|
||||
|
||||
import androidx.test.uiautomator.UiDevice;
|
||||
|
||||
@@ -27,6 +32,7 @@ import org.junit.Assert;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
|
||||
public class TestUtil {
|
||||
public static final String DUMMY_PACKAGE = "com.example.android.aardwolf";
|
||||
@@ -40,24 +46,77 @@ public class TestUtil {
|
||||
final String apkFilename = getInstrumentation().getTargetContext().
|
||||
getFilesDir().getPath() + "/dummy_app.apk";
|
||||
|
||||
final FileOutputStream out = new FileOutputStream(apkFilename);
|
||||
byte[] buff = new byte[1024];
|
||||
int read;
|
||||
try (PackageInstallCheck pic = new PackageInstallCheck()) {
|
||||
final FileOutputStream out = new FileOutputStream(apkFilename);
|
||||
byte[] buff = new byte[1024];
|
||||
int read;
|
||||
|
||||
while ((read = in.read(buff)) > 0) {
|
||||
out.write(buff, 0, read);
|
||||
while ((read = in.read(buff)) > 0) {
|
||||
out.write(buff, 0, read);
|
||||
}
|
||||
in.close();
|
||||
out.close();
|
||||
|
||||
final String result = UiDevice.getInstance(getInstrumentation())
|
||||
.executeShellCommand("pm install " + apkFilename);
|
||||
Assert.assertTrue(
|
||||
"Failed to install wellbeing test apk; make sure the device is rooted",
|
||||
"Success".equals(result.replaceAll("\\s+", "")));
|
||||
pic.mAddWait.await();
|
||||
} catch (InterruptedException e) {
|
||||
throw new IOException(e);
|
||||
}
|
||||
in.close();
|
||||
out.close();
|
||||
|
||||
final String result = UiDevice.getInstance(getInstrumentation())
|
||||
.executeShellCommand("pm install " + apkFilename);
|
||||
Assert.assertTrue("Failed to install wellbeing test apk; make sure the device is rooted",
|
||||
"Success".equals(result.replaceAll("\\s+", "")));
|
||||
}
|
||||
|
||||
public static void uninstallDummyApp() throws IOException {
|
||||
UiDevice.getInstance(getInstrumentation()).executeShellCommand(
|
||||
"pm uninstall " + DUMMY_PACKAGE);
|
||||
}
|
||||
|
||||
private static class PackageInstallCheck extends LauncherApps.Callback
|
||||
implements AutoCloseable {
|
||||
|
||||
final CountDownLatch mAddWait = new CountDownLatch(1);
|
||||
final LauncherApps mLauncherApps;
|
||||
|
||||
PackageInstallCheck() {
|
||||
mLauncherApps = getTargetContext().getSystemService(LauncherApps.class);
|
||||
mLauncherApps.registerCallback(this, new Handler(Looper.getMainLooper()));
|
||||
}
|
||||
|
||||
private void verifyPackage(String packageName) {
|
||||
if (DUMMY_PACKAGE.equals(packageName)) {
|
||||
mAddWait.countDown();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPackageAdded(String packageName, UserHandle user) {
|
||||
verifyPackage(packageName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPackageChanged(String packageName, UserHandle user) {
|
||||
verifyPackage(packageName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPackageRemoved(String packageName, UserHandle user) { }
|
||||
|
||||
@Override
|
||||
public void onPackagesAvailable(String[] packageNames, UserHandle user, boolean replacing) {
|
||||
for (String packageName : packageNames) {
|
||||
verifyPackage(packageName);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPackagesUnavailable(String[] packageNames, UserHandle user,
|
||||
boolean replacing) { }
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
mLauncherApps.unregisterCallback(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -848,6 +848,10 @@ public final class LauncherInstrumentation {
|
||||
}
|
||||
}
|
||||
|
||||
public void waitForModelQueueCleared() {
|
||||
getTestInfo(TestProtocol.REQUEST_MODEL_QUEUE_CLEARED);
|
||||
}
|
||||
|
||||
public void waitForLauncherInitialized() {
|
||||
for (int i = 0; i < 100; ++i) {
|
||||
if (getTestInfo(
|
||||
|
||||
Reference in New Issue
Block a user