Merging ub-launcher3-qt-dev, build 5508646
Test: Manual
Bug:112934365 [STOP SHIP BUG] Sysui Navigation Bar Prototype Tracking Bug:114136250 Have a more spartan RecentsActivity on android go Bug:118758133 Add logging to track undo box usage Bug:119992316 Widget screen won't close when tapping back or home button Bug:128857973 With dark display and black accent device theme, App list header not visible on all apps screen. Bug:129279637 [Logging] Long press|tap on app icon from Task should be logged Bug:129497226 Remove setInteractionState from the contract Bug:129723135 Broken tests: swipe from killed launcher doesn't open overview Bug:129806241 [a11y][Qt] Remove an app icon in Home screen, the popup "Item removed" with UNDO doesn't follow the settings of Time to take action. Bug:129985827 [Fully Gestural Navigation] Delay Recents animation when swiping up Bug:130851537 Recents and notification shelf both became nonresponsive after I "palmed" the screen while it was on. Bug:131095241 Recents Go should support landscape app => landscape thumbnail transition Bug:131303610 Backedup shortcut icons are not badged Bug:131339235 Don't layout empty task views if we have the real content Bug:131364673 [Failing test] FallbackRecentsTest
Change-Id: I04018e14bd6d9ba77005e72fe20f4a3ede886abf
diff --git a/go/quickstep/res/drawable/default_thumbnail.xml b/go/quickstep/res/drawable/default_thumbnail.xml
index 0a2dbf0..ab22dcf 100644
--- a/go/quickstep/res/drawable/default_thumbnail.xml
+++ b/go/quickstep/res/drawable/default_thumbnail.xml
@@ -18,5 +18,5 @@
xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid android:color="@android:color/darker_gray"/>
- <corners android:radius="2dp"/>
+ <corners android:radius="@dimen/task_thumbnail_corner_radius"/>
</shape>
diff --git a/go/quickstep/res/values/dimens.xml b/go/quickstep/res/values/dimens.xml
new file mode 100644
index 0000000..ee154fc
--- /dev/null
+++ b/go/quickstep/res/values/dimens.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2019 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<resources>
+ <dimen name="task_thumbnail_corner_radius">3dp</dimen>
+</resources>
\ No newline at end of file
diff --git a/go/quickstep/src/com/android/quickstep/ContentFillItemAnimator.java b/go/quickstep/src/com/android/quickstep/ContentFillItemAnimator.java
index 1b6f2e3..9282345 100644
--- a/go/quickstep/src/com/android/quickstep/ContentFillItemAnimator.java
+++ b/go/quickstep/src/com/android/quickstep/ContentFillItemAnimator.java
@@ -161,6 +161,13 @@
private void animateChangeImpl(ViewHolder viewHolder, long startDelay) {
TaskItemView itemView = (TaskItemView) viewHolder.itemView;
+ if (itemView.getAlpha() == 0) {
+ // View is still not visible, so we can finish the change immediately.
+ CONTENT_TRANSITION_PROGRESS.set(itemView, 1.0f);
+ dispatchChangeFinished(viewHolder, true /* oldItem */);
+ dispatchFinishedWhenDone();
+ return;
+ }
final ObjectAnimator anim =
ObjectAnimator.ofFloat(itemView, CONTENT_TRANSITION_PROGRESS, 0.0f, 1.0f);
anim.setDuration(ITEM_CHANGE_DURATION).setStartDelay(startDelay);
diff --git a/go/quickstep/src/com/android/quickstep/ThumbnailDrawable.java b/go/quickstep/src/com/android/quickstep/ThumbnailDrawable.java
index 6ef9039..a8cc0a1 100644
--- a/go/quickstep/src/com/android/quickstep/ThumbnailDrawable.java
+++ b/go/quickstep/src/com/android/quickstep/ThumbnailDrawable.java
@@ -16,17 +16,23 @@
package com.android.quickstep;
+import static android.graphics.Shader.TileMode.CLAMP;
+
+import android.content.res.Resources;
import android.graphics.Bitmap;
+import android.graphics.BitmapShader;
import android.graphics.Canvas;
import android.graphics.ColorFilter;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.PixelFormat;
import android.graphics.Rect;
+import android.graphics.RectF;
import android.graphics.drawable.Drawable;
import androidx.annotation.NonNull;
+import com.android.launcher3.R;
import com.android.systemui.shared.recents.model.ThumbnailData;
/**
@@ -39,11 +45,18 @@
private final Paint mPaint = new Paint();
private final Matrix mMatrix = new Matrix();
private final ThumbnailData mThumbnailData;
+ private final BitmapShader mShader;
+ private final RectF mDestRect = new RectF();
+ private final int mCornerRadius;
private int mRequestedOrientation;
- public ThumbnailDrawable(@NonNull ThumbnailData thumbnailData, int requestedOrientation) {
+ public ThumbnailDrawable(Resources res, @NonNull ThumbnailData thumbnailData,
+ int requestedOrientation) {
mThumbnailData = thumbnailData;
mRequestedOrientation = requestedOrientation;
+ mCornerRadius = (int) res.getDimension(R.dimen.task_thumbnail_corner_radius);
+ mShader = new BitmapShader(mThumbnailData.thumbnail, CLAMP, CLAMP);
+ mPaint.setShader(mShader);
updateMatrix();
}
@@ -64,12 +77,13 @@
if (mThumbnailData.thumbnail == null) {
return;
}
- canvas.drawBitmap(mThumbnailData.thumbnail, mMatrix, mPaint);
+ canvas.drawRoundRect(mDestRect, mCornerRadius, mCornerRadius, mPaint);
}
@Override
protected void onBoundsChange(Rect bounds) {
super.onBoundsChange(bounds);
+ mDestRect.set(bounds);
updateMatrix();
}
@@ -125,5 +139,6 @@
}
// Scale to fill.
mMatrix.postScale(scaleX, scaleY);
+ mShader.setLocalMatrix(mMatrix);
}
}
diff --git a/go/quickstep/src/com/android/quickstep/views/TaskItemView.java b/go/quickstep/src/com/android/quickstep/views/TaskItemView.java
index 0b5ed56..9019205 100644
--- a/go/quickstep/src/com/android/quickstep/views/TaskItemView.java
+++ b/go/quickstep/src/com/android/quickstep/views/TaskItemView.java
@@ -177,7 +177,8 @@
return mDefaultThumbnail;
}
int orientation = getResources().getConfiguration().orientation;
- return new ThumbnailDrawable(thumbnailData, orientation /* requestedOrientation */);
+ return new ThumbnailDrawable(getResources(), thumbnailData,
+ orientation /* requestedOrientation */);
}
private @NonNull String getSafeLabel(@Nullable String label) {
diff --git a/go/quickstep/src/com/android/quickstep/views/TaskThumbnailIconView.java b/go/quickstep/src/com/android/quickstep/views/TaskThumbnailIconView.java
index b1c60dd..0bad77b 100644
--- a/go/quickstep/src/com/android/quickstep/views/TaskThumbnailIconView.java
+++ b/go/quickstep/src/com/android/quickstep/views/TaskThumbnailIconView.java
@@ -16,6 +16,9 @@
package com.android.quickstep.views;
+import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
+import static android.view.View.MeasureSpec.makeMeasureSpec;
+
import android.content.Context;
import android.graphics.Rect;
import android.util.AttributeSet;
@@ -53,15 +56,20 @@
int width = height;
setMeasuredDimension(width, height);
+
int subItemSize = (int) (SUBITEM_FRAME_RATIO * height);
if (mThumbnailView.getVisibility() != GONE) {
- int thumbnailHeightSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY);
- int thumbnailWidthSpec = MeasureSpec.makeMeasureSpec(subItemSize, MeasureSpec.EXACTLY);
+ boolean isPortrait =
+ (getResources().getConfiguration().orientation == ORIENTATION_PORTRAIT);
+ int thumbnailHeightSpec =
+ makeMeasureSpec(isPortrait ? height : subItemSize, MeasureSpec.EXACTLY);
+ int thumbnailWidthSpec =
+ makeMeasureSpec(isPortrait ? subItemSize : width, MeasureSpec.EXACTLY);
measureChild(mThumbnailView, thumbnailWidthSpec, thumbnailHeightSpec);
}
if (mIconView.getVisibility() != GONE) {
- int iconHeightSpec = MeasureSpec.makeMeasureSpec(subItemSize, MeasureSpec.EXACTLY);
- int iconWidthSpec = MeasureSpec.makeMeasureSpec(subItemSize, MeasureSpec.EXACTLY);
+ int iconHeightSpec = makeMeasureSpec(subItemSize, MeasureSpec.EXACTLY);
+ int iconWidthSpec = makeMeasureSpec(subItemSize, MeasureSpec.EXACTLY);
measureChild(mIconView, iconWidthSpec, iconHeightSpec);
}
}
diff --git a/protos/launcher_log.proto b/protos/launcher_log.proto
index 4974dcb..02c6b0f 100644
--- a/protos/launcher_log.proto
+++ b/protos/launcher_log.proto
@@ -71,6 +71,7 @@
NOTIFICATION = 8;
TASK = 9; // Each page of Recents UI (QuickStep)
WEB_APP = 10;
+ TASK_ICON = 11;
}
// Used to define what type of container a Target would represent.
@@ -115,6 +116,7 @@
REMOTE_ACTION_SHORTCUT = 17;
APP_USAGE_SETTINGS = 18;
BACK_GESTURE = 19;
+ UNDO = 20;
}
enum TipType {
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/AssistantTouchConsumer.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/AssistantTouchConsumer.java
index a76ecd5..5e7faf7 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/AssistantTouchConsumer.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/AssistantTouchConsumer.java
@@ -45,7 +45,7 @@
import com.android.launcher3.logging.UserEventDispatcher;
import com.android.systemui.shared.recents.ISystemUiProxy;
import com.android.systemui.shared.system.InputMonitorCompat;
-import com.android.systemui.shared.system.NavigationBarCompat;
+import com.android.systemui.shared.system.QuickStepContract;
/**
* Touch consumer for handling events to launch assistant from launcher
@@ -103,7 +103,7 @@
mDistThreshold = res.getDimension(R.dimen.gestures_assistant_drag_threshold);
mTimeThreshold = res.getInteger(R.integer.assistant_gesture_min_time_threshold);
mAngleThreshold = res.getInteger(R.integer.assistant_gesture_corner_deg_threshold);
- mSlop = NavigationBarCompat.getQuickStepDragSlopPx();
+ mSlop = QuickStepContract.getQuickStepDragSlopPx();
mInputMonitorCompat = inputMonitorCompat;
mActivityControlHelper = activityControlHelper;
mState = STATE_INACTIVE;
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherActivityControllerHelper.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherActivityControllerHelper.java
index 35783b5..a033402 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherActivityControllerHelper.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherActivityControllerHelper.java
@@ -16,14 +16,15 @@
package com.android.quickstep;
import static android.view.View.TRANSLATION_Y;
-
import static com.android.launcher3.LauncherAnimUtils.SCALE_PROPERTY;
import static com.android.launcher3.LauncherState.BACKGROUND_APP;
import static com.android.launcher3.LauncherState.NORMAL;
import static com.android.launcher3.LauncherState.OVERVIEW;
import static com.android.launcher3.allapps.AllAppsTransitionController.SPRING_DAMPING_RATIO;
import static com.android.launcher3.allapps.AllAppsTransitionController.SPRING_STIFFNESS;
+import static com.android.launcher3.anim.Interpolators.ACCEL_DEACCEL;
import static com.android.launcher3.anim.Interpolators.LINEAR;
+import static com.android.quickstep.WindowTransformSwipeHandler.RECENTS_ATTACH_DURATION;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
@@ -177,6 +178,8 @@
return new AnimationFactory() {
private Animator mShelfAnim;
private ShelfAnimState mShelfState;
+ private Animator mAttachToWindowAnim;
+ private boolean mIsAttachedToWindow;
@Override
public void createActivityController(long transitionLength) {
@@ -221,6 +224,28 @@
mShelfAnim.setDuration(duration);
mShelfAnim.start();
}
+
+ @Override
+ public void setRecentsAttachedToAppWindow(boolean attached, boolean animate) {
+ if (mIsAttachedToWindow == attached && animate) {
+ return;
+ }
+ mIsAttachedToWindow = attached;
+ if (mAttachToWindowAnim != null) {
+ mAttachToWindowAnim.cancel();
+ }
+ mAttachToWindowAnim = ObjectAnimator.ofFloat(activity.getOverviewPanel(),
+ RecentsView.CONTENT_ALPHA, attached ? 1 : 0);
+ mAttachToWindowAnim.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ mAttachToWindowAnim = null;
+ }
+ });
+ mAttachToWindowAnim.setInterpolator(ACCEL_DEACCEL);
+ mAttachToWindowAnim.setDuration(animate ? RECENTS_ATTACH_DURATION : 0);
+ mAttachToWindowAnim.start();
+ }
};
}
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/OtherActivityInputConsumer.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/OtherActivityInputConsumer.java
index 44ba515..5dc641f 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/OtherActivityInputConsumer.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/OtherActivityInputConsumer.java
@@ -60,7 +60,7 @@
import com.android.systemui.shared.system.BackgroundExecutor;
import com.android.systemui.shared.system.InputConsumerController;
import com.android.systemui.shared.system.InputMonitorCompat;
-import com.android.systemui.shared.system.NavigationBarCompat;
+import com.android.systemui.shared.system.QuickStepContract;
import com.android.systemui.shared.system.WindowManagerWrapper;
import java.util.function.Consumer;
@@ -152,8 +152,8 @@
mDisplayRotation = display.getRotation();
WindowManagerWrapper.getInstance().getStableInsets(mStableInsets);
- mDragSlop = NavigationBarCompat.getQuickStepDragSlopPx();
- mTouchSlop = NavigationBarCompat.getQuickStepTouchSlopPx();
+ mDragSlop = QuickStepContract.getQuickStepDragSlopPx();
+ mTouchSlop = QuickStepContract.getQuickStepTouchSlopPx();
mPassedTouchSlop = mPassedDragSlop = continuingPreviousGesture;
}
@@ -267,6 +267,7 @@
mMotionPauseDetector.setDisallowPause(upDist < mMotionPauseMinDisplacement
|| isLikelyToStartNewTask);
mMotionPauseDetector.addPosition(displacement, ev.getEventTime());
+ mInteractionHandler.setIsLikelyToStartNewTask(isLikelyToStartNewTask);
}
}
break;
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/WindowTransformSwipeHandler.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/WindowTransformSwipeHandler.java
index e1b38b3..afc4fcb 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/WindowTransformSwipeHandler.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/WindowTransformSwipeHandler.java
@@ -43,6 +43,7 @@
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.animation.TimeInterpolator;
+import android.animation.ValueAnimator;
import android.annotation.TargetApi;
import android.app.ActivityManager.RunningTaskInfo;
import android.content.Context;
@@ -111,6 +112,8 @@
implements SwipeAnimationListener, OnApplyWindowInsetsListener {
private static final String TAG = WindowTransformSwipeHandler.class.getSimpleName();
+ private static final Rect TEMP_RECT = new Rect();
+
private static final String[] STATE_NAMES = DEBUG_STATES ? new String[16] : null;
private static int getFlagForIndex(int index, String name) {
@@ -162,22 +165,23 @@
STATE_LAUNCHER_PRESENT | STATE_LAUNCHER_DRAWN | STATE_LAUNCHER_STARTED;
enum GestureEndTarget {
- HOME(1, STATE_SCALED_CONTROLLER_HOME, true, false, ContainerType.WORKSPACE),
+ HOME(1, STATE_SCALED_CONTROLLER_HOME, true, false, ContainerType.WORKSPACE, false),
RECENTS(1, STATE_SCALED_CONTROLLER_RECENTS | STATE_CAPTURE_SCREENSHOT
- | STATE_SCREENSHOT_VIEW_SHOWN, true, false, ContainerType.TASKSWITCHER),
+ | STATE_SCREENSHOT_VIEW_SHOWN, true, false, ContainerType.TASKSWITCHER, true),
- NEW_TASK(0, STATE_START_NEW_TASK, false, true, ContainerType.APP),
+ NEW_TASK(0, STATE_START_NEW_TASK, false, true, ContainerType.APP, true),
- LAST_TASK(0, STATE_RESUME_LAST_TASK, false, true, ContainerType.APP);
+ LAST_TASK(0, STATE_RESUME_LAST_TASK, false, true, ContainerType.APP, false);
GestureEndTarget(float endShift, int endState, boolean isLauncher, boolean canBeContinued,
- int containerType) {
+ int containerType, boolean recentsAttachedToAppWindow) {
this.endShift = endShift;
this.endState = endState;
this.isLauncher = isLauncher;
this.canBeContinued = canBeContinued;
this.containerType = containerType;
+ this.recentsAttachedToAppWindow = recentsAttachedToAppWindow;
}
/** 0 is app, 1 is overview */
@@ -190,6 +194,8 @@
public final boolean canBeContinued;
/** Used to log where the user ended up after the gesture ends */
public final int containerType;
+ /** Whether RecentsView should be attached to the window as we animate to this target */
+ public final boolean recentsAttachedToAppWindow;
}
public static final long MAX_SWIPE_DURATION = 350;
@@ -202,6 +208,7 @@
private static final String SCREENSHOT_CAPTURED_EVT = "ScreenshotCaptured";
private static final long SHELF_ANIM_DURATION = 120;
+ public static final long RECENTS_ATTACH_DURATION = 300;
/**
* Used as the page index for logging when we return to the last task at the end of the gesture.
@@ -254,6 +261,7 @@
private int mLogAction = Touch.SWIPE;
private int mLogDirection = Direction.UP;
private PointF mDownPos;
+ private boolean mIsLikelyToStartNewTask;
private final RecentsAnimationWrapper mRecentsAnimationWrapper;
@@ -277,6 +285,9 @@
mMode = SysUINavigationMode.getMode(context);
initStateCallbacks();
+
+ DeviceProfile dp = InvariantDeviceProfile.INSTANCE.get(mContext).getDeviceProfile(mContext);
+ initTransitionEndpoints(dp);
}
private void initStateCallbacks() {
@@ -434,6 +445,7 @@
mAnimationFactory = mActivityControlHelper.prepareRecentsUI(mActivity,
mWasLauncherAlreadyVisible, true,
this::onAnimatorPlaybackControllerCreated);
+ maybeUpdateRecentsAttachedState(false /* animate */);
};
if (mWasLauncherAlreadyVisible) {
// Launcher is visible, but might be about to stop. Thus, if we prepare recents
@@ -538,10 +550,65 @@
setShelfState(isPaused ? PEEK : HIDE, FAST_OUT_SLOW_IN, SHELF_ANIM_DURATION);
}
+ public void maybeUpdateRecentsAttachedState() {
+ maybeUpdateRecentsAttachedState(true /* animate */);
+ }
+
+ /**
+ * Determines whether to show or hide RecentsView. The window is always
+ * synchronized with its corresponding TaskView in RecentsView, so if
+ * RecentsView is shown, it will appear to be attached to the window.
+ *
+ * Note this method has no effect unless the navigation mode is NO_BUTTON.
+ */
+ private void maybeUpdateRecentsAttachedState(boolean animate) {
+ if (mMode != Mode.NO_BUTTON || mRecentsView == null) {
+ return;
+ }
+ RemoteAnimationTargetCompat runningTaskTarget = mRecentsAnimationWrapper.targetSet == null
+ ? null
+ : mRecentsAnimationWrapper.targetSet.findTask(mRunningTaskId);
+ final boolean recentsAttachedToAppWindow;
+ int runningTaskIndex = mRecentsView.getRunningTaskIndex();
+ if (mContinuingLastGesture) {
+ recentsAttachedToAppWindow = true;
+ animate = false;
+ } else if (runningTaskTarget != null && isNotInRecents(runningTaskTarget)) {
+ // The window is going away so make sure recents is always visible in this case.
+ recentsAttachedToAppWindow = true;
+ animate = false;
+ } else {
+ if (mGestureEndTarget != null) {
+ recentsAttachedToAppWindow = mGestureEndTarget.recentsAttachedToAppWindow;
+ } else {
+ recentsAttachedToAppWindow = mIsShelfPeeking || mIsLikelyToStartNewTask;
+ }
+ if (animate) {
+ // Only animate if an adjacent task view is visible on screen.
+ TaskView adjacentTask1 = mRecentsView.getTaskViewAt(runningTaskIndex + 1);
+ TaskView adjacentTask2 = mRecentsView.getTaskViewAt(runningTaskIndex - 1);
+ animate = (adjacentTask1 != null && adjacentTask1.getGlobalVisibleRect(TEMP_RECT))
+ || (adjacentTask2 != null && adjacentTask2.getGlobalVisibleRect(TEMP_RECT));
+ }
+ }
+ mAnimationFactory.setRecentsAttachedToAppWindow(recentsAttachedToAppWindow, animate);
+ }
+
+ public void setIsLikelyToStartNewTask(boolean isLikelyToStartNewTask) {
+ if (mIsLikelyToStartNewTask != isLikelyToStartNewTask) {
+ mIsLikelyToStartNewTask = isLikelyToStartNewTask;
+ maybeUpdateRecentsAttachedState();
+ }
+ }
+
@UiThread
public void setShelfState(ShelfAnimState shelfState, Interpolator interpolator, long duration) {
mAnimationFactory.setShelfState(shelfState, interpolator, duration);
+ boolean wasShelfPeeking = mIsShelfPeeking;
mIsShelfPeeking = shelfState == PEEK;
+ if (mIsShelfPeeking != wasShelfPeeking) {
+ maybeUpdateRecentsAttachedState();
+ }
if (mRecentsView != null && shelfState.shouldPreformHaptic) {
mRecentsView.performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY,
HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING);
@@ -869,6 +936,8 @@
Interpolator interpolator, GestureEndTarget target, PointF velocityPxPerMs) {
mGestureEndTarget = target;
+ maybeUpdateRecentsAttachedState();
+
if (mGestureEndTarget == HOME) {
HomeAnimationFactory homeAnimFactory;
if (mActivity != null) {
@@ -902,8 +971,15 @@
windowAnim.start(velocityPxPerMs);
mLauncherTransitionController = null;
} else {
- Animator windowAnim = mCurrentShift.animateToValue(start, end);
+ ValueAnimator windowAnim = mCurrentShift.animateToValue(start, end);
windowAnim.setDuration(duration).setInterpolator(interpolator);
+ windowAnim.addUpdateListener(valueAnimator -> {
+ if (mRecentsView != null && mRecentsView.getVisibility() != View.VISIBLE) {
+ // Views typically don't compute scroll when invisible as an optimization,
+ // but in our case we need to since the window offset depends on the scroll.
+ mRecentsView.computeScroll();
+ }
+ });
windowAnim.addListener(new AnimationSuccessListener() {
@Override
public void onAnimationSuccess(Animator animator) {
@@ -1177,10 +1253,14 @@
}
public static float getHiddenTargetAlpha(RemoteAnimationTargetCompat app, Float expectedAlpha) {
- if (!(app.isNotInRecents
- || app.activityType == RemoteAnimationTargetCompat.ACTIVITY_TYPE_HOME)) {
+ if (!isNotInRecents(app)) {
return 0;
}
return expectedAlpha;
}
+
+ private static boolean isNotInRecents(RemoteAnimationTargetCompat app) {
+ return app.isNotInRecents
+ || app.activityType == RemoteAnimationTargetCompat.ACTIVITY_TYPE_HOME;
+ }
}
diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/TaskView.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/TaskView.java
index 3ca8b18..2f739c8 100644
--- a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/TaskView.java
+++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/TaskView.java
@@ -48,6 +48,8 @@
import com.android.launcher3.R;
import com.android.launcher3.anim.AnimatorPlaybackController;
import com.android.launcher3.anim.Interpolators;
+import com.android.launcher3.logging.UserEventDispatcher;
+import com.android.launcher3.userevent.nano.LauncherLogProto;
import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Direction;
import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Touch;
import com.android.launcher3.util.PendingAnimation;
@@ -365,9 +367,11 @@
}
}
- private boolean showTaskMenu() {
+ private boolean showTaskMenu(int action) {
getRecentsView().snapToPage(getRecentsView().indexOfChild(this));
mMenuView = TaskMenuView.showForTask(this);
+ UserEventDispatcher.newInstance(getContext()).logActionOnItem(action, Direction.NONE,
+ LauncherLogProto.ItemType.TASK_ICON);
if (mMenuView != null) {
mMenuView.addOnAttachStateChangeListener(mTaskMenuStateListener);
}
@@ -377,10 +381,10 @@
private void setIcon(Drawable icon) {
if (icon != null) {
mIconView.setDrawable(icon);
- mIconView.setOnClickListener(v -> showTaskMenu());
+ mIconView.setOnClickListener(v -> showTaskMenu(Touch.TAP));
mIconView.setOnLongClickListener(v -> {
requestDisallowInterceptTouchEvent(true);
- return showTaskMenu();
+ return showTaskMenu(Touch.LONGPRESS);
});
} else {
mIconView.setDrawable(null);
diff --git a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/StatusBarTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/StatusBarTouchController.java
index 12e6f12..fee1820 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/StatusBarTouchController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/StatusBarTouchController.java
@@ -32,6 +32,8 @@
import com.android.quickstep.RecentsModel;
import com.android.systemui.shared.recents.ISystemUiProxy;
+import java.io.PrintWriter;
+
/**
* TouchController for handling touch events that get sent to the StatusBar. Once the
* Once the event delta y passes the touch slop, the events start getting forwarded.
@@ -45,6 +47,7 @@
protected final TouchEventTranslator mTranslator;
private final float mTouchSlop;
private ISystemUiProxy mSysUiProxy;
+ private int mLastAction;
/* If {@code false}, this controller should not handle the input {@link MotionEvent}.*/
private boolean mCanIntercept;
@@ -56,9 +59,18 @@
mTranslator = new TouchEventTranslator((MotionEvent ev)-> dispatchTouchEvent(ev));
}
+ @Override
+ public void dump(String prefix, PrintWriter writer) {
+ writer.println(prefix + "mCanIntercept:" + mCanIntercept);
+ writer.println(prefix + "mLastAction:" + MotionEvent.actionToString(mLastAction));
+ writer.println(prefix + "mSysUiProxy available:" + (mSysUiProxy != null));
+
+ }
+
private void dispatchTouchEvent(MotionEvent ev) {
try {
if (mSysUiProxy != null) {
+ mLastAction = ev.getActionMasked();
mSysUiProxy.onStatusBarMotionEvent(ev);
}
} catch (RemoteException e) {
diff --git a/quickstep/src/com/android/quickstep/ActivityControlHelper.java b/quickstep/src/com/android/quickstep/ActivityControlHelper.java
index a71b7bb..17f88c9 100644
--- a/quickstep/src/com/android/quickstep/ActivityControlHelper.java
+++ b/quickstep/src/com/android/quickstep/ActivityControlHelper.java
@@ -27,6 +27,10 @@
import android.view.View;
import android.view.animation.Interpolator;
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.annotation.UiThread;
+
import com.android.launcher3.BaseDraggingActivity;
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.anim.AnimatorPlaybackController;
@@ -37,10 +41,6 @@
import java.util.function.BiPredicate;
import java.util.function.Consumer;
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-import androidx.annotation.UiThread;
-
/**
* Utility class which abstracts out the logical differences between Launcher and RecentsActivity.
*/
@@ -122,6 +122,13 @@
default void setShelfState(ShelfAnimState animState, Interpolator interpolator,
long duration) { }
+
+ /**
+ * @param attached Whether to show RecentsView alongside the app window. If false, recents
+ * will be hidden by some property we can animate, e.g. alpha.
+ * @param animate Whether to animate recents to/from its new attached state.
+ */
+ default void setRecentsAttachedToAppWindow(boolean attached, boolean animate) { }
}
interface HomeAnimationFactory {
diff --git a/quickstep/src/com/android/quickstep/OverviewInteractionState.java b/quickstep/src/com/android/quickstep/OverviewInteractionState.java
index 286ddc0..79d922c 100644
--- a/quickstep/src/com/android/quickstep/OverviewInteractionState.java
+++ b/quickstep/src/com/android/quickstep/OverviewInteractionState.java
@@ -15,10 +15,6 @@
*/
package com.android.quickstep;
-import static com.android.systemui.shared.system.NavigationBarCompat.FLAG_DISABLE_QUICK_SCRUB;
-import static com.android.systemui.shared.system.NavigationBarCompat.FLAG_DISABLE_SWIPE_UP;
-import static com.android.systemui.shared.system.NavigationBarCompat.FLAG_SHOW_OVERVIEW_BUTTON;
-
import android.content.Context;
import android.os.Handler;
import android.os.Message;
@@ -34,13 +30,7 @@
import androidx.annotation.WorkerThread;
/**
- * Sets overview interaction flags, such as:
- *
- * - FLAG_DISABLE_QUICK_SCRUB
- * - FLAG_DISABLE_SWIPE_UP
- * - FLAG_SHOW_OVERVIEW_BUTTON
- *
- * @see com.android.systemui.shared.system.NavigationBarCompat.InteractionType and associated flags.
+ * Sets alpha for the back button
*/
public class OverviewInteractionState {
@@ -50,11 +40,10 @@
// We do not need any synchronization for this variable as its only written on UI thread.
public static final MainThreadInitializedObject<OverviewInteractionState> INSTANCE =
- new MainThreadInitializedObject<>((c) -> new OverviewInteractionState(c));
+ new MainThreadInitializedObject<>(OverviewInteractionState::new);
private static final int MSG_SET_PROXY = 200;
private static final int MSG_SET_BACK_BUTTON_ALPHA = 201;
- private static final int MSG_APPLY_FLAGS = 202;
private final Context mContext;
private final Handler mUiHandler;
@@ -62,7 +51,6 @@
// These are updated on the background thread
private ISystemUiProxy mISystemUiProxy;
- private boolean mSwipeUpEnabled;
private float mBackButtonAlpha = 1;
private OverviewInteractionState(Context context) {
@@ -83,7 +71,7 @@
}
public void setBackButtonAlpha(float alpha, boolean animate) {
- if (!mSwipeUpEnabled) {
+ if (!modeSupportsGestures()) {
alpha = 1;
}
mUiHandler.removeMessages(MSG_SET_BACK_BUTTON_ALPHA);
@@ -111,31 +99,11 @@
case MSG_SET_BACK_BUTTON_ALPHA:
applyBackButtonAlpha((float) msg.obj, msg.arg1 == 1);
return true;
- case MSG_APPLY_FLAGS:
- break;
}
- applyFlags();
return true;
}
@WorkerThread
- private void applyFlags() {
- if (mISystemUiProxy == null) {
- return;
- }
-
- int flags = FLAG_DISABLE_QUICK_SCRUB;
- if (!mSwipeUpEnabled) {
- flags = FLAG_DISABLE_SWIPE_UP | FLAG_DISABLE_QUICK_SCRUB | FLAG_SHOW_OVERVIEW_BUTTON;
- }
- try {
- mISystemUiProxy.setInteractionState(flags);
- } catch (RemoteException e) {
- Log.w(TAG, "Unable to update overview interaction flags", e);
- }
- }
-
- @WorkerThread
private void applyBackButtonAlpha(float alpha, boolean animate) {
if (mISystemUiProxy == null) {
return;
@@ -148,18 +116,20 @@
}
private void onNavigationModeChanged(SysUINavigationMode.Mode mode) {
- mSwipeUpEnabled = mode.hasGestures;
resetHomeBounceSeenOnQuickstepEnabledFirstTime();
- mBgHandler.obtainMessage(MSG_APPLY_FLAGS).sendToTarget();
}
private void resetHomeBounceSeenOnQuickstepEnabledFirstTime() {
- if (mSwipeUpEnabled && !Utilities.getPrefs(mContext).getBoolean(
+ if (modeSupportsGestures() && !Utilities.getPrefs(mContext).getBoolean(
HAS_ENABLED_QUICKSTEP_ONCE, true)) {
Utilities.getPrefs(mContext).edit()
- .putBoolean(HAS_ENABLED_QUICKSTEP_ONCE, true)
- .putBoolean(DiscoveryBounce.HOME_BOUNCE_SEEN, false)
- .apply();
+ .putBoolean(HAS_ENABLED_QUICKSTEP_ONCE, true)
+ .putBoolean(DiscoveryBounce.HOME_BOUNCE_SEEN, false)
+ .apply();
}
}
+
+ private boolean modeSupportsGestures() {
+ return SysUINavigationMode.getMode(mContext).hasGestures;
+ }
}
diff --git a/quickstep/tests/src/com/android/quickstep/DigitalWellBeingToastTest.java b/quickstep/tests/src/com/android/quickstep/DigitalWellBeingToastTest.java
index 8798157..70f9c90 100644
--- a/quickstep/tests/src/com/android/quickstep/DigitalWellBeingToastTest.java
+++ b/quickstep/tests/src/com/android/quickstep/DigitalWellBeingToastTest.java
@@ -12,21 +12,29 @@
import android.app.usage.UsageStatsManager;
import android.content.Intent;
+import androidx.test.filters.LargeTest;
+import androidx.test.runner.AndroidJUnit4;
+
import com.android.launcher3.Launcher;
import com.android.quickstep.views.DigitalWellBeingToast;
import com.android.quickstep.views.RecentsView;
import com.android.quickstep.views.TaskView;
import org.junit.Test;
+import org.junit.runner.RunWith;
import java.time.Duration;
+@LargeTest
+@RunWith(AndroidJUnit4.class)
public class DigitalWellBeingToastTest extends AbstractQuickStepTest {
private static final String CALCULATOR_PACKAGE =
resolveSystemApp(Intent.CATEGORY_APP_CALCULATOR);
@Test
public void testToast() throws Exception {
+ startAppFast(CALCULATOR_PACKAGE);
+
final UsageStatsManager usageStatsManager =
mTargetContext.getSystemService(UsageStatsManager.class);
final int observerId = 0;
diff --git a/quickstep/tests/src/com/android/quickstep/FallbackRecentsTest.java b/quickstep/tests/src/com/android/quickstep/FallbackRecentsTest.java
index f436831..20fdff2 100644
--- a/quickstep/tests/src/com/android/quickstep/FallbackRecentsTest.java
+++ b/quickstep/tests/src/com/android/quickstep/FallbackRecentsTest.java
@@ -32,6 +32,7 @@
import android.content.Context;
import android.content.Intent;
import android.content.pm.ActivityInfo;
+import android.os.RemoteException;
import androidx.test.filters.LargeTest;
import androidx.test.runner.AndroidJUnit4;
@@ -65,10 +66,11 @@
@Rule public final TestRule mSetLauncherCommand;
- public FallbackRecentsTest() {
+ public FallbackRecentsTest() throws RemoteException {
Instrumentation instrumentation = getInstrumentation();
Context context = instrumentation.getContext();
mDevice = UiDevice.getInstance(instrumentation);
+ mDevice.setOrientationNatural();
mLauncher = new LauncherInstrumentation(instrumentation);
mQuickstepOnOffExecutor = new NavigationModeSwitchRule(mLauncher);
diff --git a/quickstep/tests/src/com/android/quickstep/StartLauncherViaGestureTests.java b/quickstep/tests/src/com/android/quickstep/StartLauncherViaGestureTests.java
index a47c8e7..8bdb90d 100644
--- a/quickstep/tests/src/com/android/quickstep/StartLauncherViaGestureTests.java
+++ b/quickstep/tests/src/com/android/quickstep/StartLauncherViaGestureTests.java
@@ -88,7 +88,6 @@
}
@Test
- @Ignore // b/129723135
@NavigationModeSwitch
public void testStressSwipeToOverview() {
for (int i = 0; i < STRESS_REPEAT_COUNT; ++i) {
diff --git a/res/values/styles.xml b/res/values/styles.xml
index 9b84cc9..7932c6d 100644
--- a/res/values/styles.xml
+++ b/res/values/styles.xml
@@ -19,12 +19,13 @@
<resources>
<!-- Launcher theme -->
- <style name="BaseLauncherTheme" parent="@android:style/Theme.DeviceDefault.Light.NoActionBar">
- <item name="android:windowBackground">@android:color/transparent</item>
+ <style name="BaseLauncherTheme" parent="@android:style/Theme.DeviceDefault.DayNight">
<item name="android:colorBackgroundCacheHint">@null</item>
- <item name="android:windowShowWallpaper">true</item>
- <item name="android:windowNoTitle">true</item>
<item name="android:colorEdgeEffect">#FF757575</item>
+ <item name="android:windowActionBar">false</item>
+ <item name="android:windowBackground">@android:color/transparent</item>
+ <item name="android:windowNoTitle">true</item>
+ <item name="android:windowShowWallpaper">true</item>
</style>
<style name="LauncherTheme" parent="@style/BaseLauncherTheme">
diff --git a/src/com/android/launcher3/DeleteDropTarget.java b/src/com/android/launcher3/DeleteDropTarget.java
index 8cbad20..3347b2a 100644
--- a/src/com/android/launcher3/DeleteDropTarget.java
+++ b/src/com/android/launcher3/DeleteDropTarget.java
@@ -16,6 +16,9 @@
package com.android.launcher3;
+import static com.android.launcher3.userevent.nano.LauncherLogProto.Action.Touch.TAP;
+import static com.android.launcher3.userevent.nano.LauncherLogProto.ControlType.UNDO;
+
import android.content.Context;
import android.text.TextUtils;
import android.util.AttributeSet;
@@ -121,8 +124,12 @@
int itemPage = mLauncher.getWorkspace().getCurrentPage();
onAccessibilityDrop(null, item);
ModelWriter modelWriter = mLauncher.getModelWriter();
+ Runnable onUndoClicked = () -> {
+ modelWriter.abortDelete(itemPage);
+ mLauncher.getUserEventDispatcher().logActionOnControl(TAP, UNDO);
+ };
Snackbar.show(mLauncher, R.string.item_removed, R.string.undo,
- modelWriter::commitDelete, () -> modelWriter.abortDelete(itemPage));
+ modelWriter::commitDelete, onUndoClicked);
}
}
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index d790c04..fda674f 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -75,6 +75,8 @@
import android.view.animation.OvershootInterpolator;
import android.widget.Toast;
+import androidx.annotation.Nullable;
+
import com.android.launcher3.DropTarget.DragObject;
import com.android.launcher3.accessibility.LauncherAccessibilityDelegate;
import com.android.launcher3.allapps.AllAppsContainerView;
@@ -150,9 +152,6 @@
import java.util.List;
import java.util.function.Predicate;
-import androidx.annotation.IdRes;
-import androidx.annotation.Nullable;
-
/**
* Default launcher application.
*/
@@ -2198,7 +2197,9 @@
InstallShortcutReceiver.FLAG_LOADER_RUNNING, this);
// When undoing the removal of the last item on a page, return to that page.
- mWorkspace.setCurrentPage(pageBoundFirst);
+ // Since we are just resetting the current page without user interaction,
+ // override the previous page so we don't log the page switch.
+ mWorkspace.setCurrentPage(pageBoundFirst, pageBoundFirst /* overridePrevPage */);
TraceHelper.endSection("finishBindingItems");
}
@@ -2345,7 +2346,8 @@
writer.println(" mPendingActivityResult=" + mPendingActivityResult);
writer.println(" mRotationHelper: " + mRotationHelper);
// Extra logging for b/116853349
- mDragLayer.dumpAlpha(writer);
+ mDragLayer.dump(prefix, writer);
+ mStateManager.dump(prefix, writer);
dumpMisc(writer);
try {
diff --git a/src/com/android/launcher3/LauncherStateManager.java b/src/com/android/launcher3/LauncherStateManager.java
index 209578d..b24f660 100644
--- a/src/com/android/launcher3/LauncherStateManager.java
+++ b/src/com/android/launcher3/LauncherStateManager.java
@@ -50,6 +50,7 @@
import com.android.launcher3.anim.PropertySetter.AnimatedPropertySetter;
import com.android.launcher3.uioverrides.UiFactory;
+import java.io.PrintWriter;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
@@ -144,6 +145,15 @@
return mCurrentStableState;
}
+ public void dump(String prefix, PrintWriter writer) {
+ writer.println(prefix + "LauncherState");
+ writer.println(prefix + "\tmLastStableState:" + mLastStableState);
+ writer.println(prefix + "\tmCurrentStableState:" + mCurrentStableState);
+ writer.println(prefix + "\tmState:" + mState);
+ writer.println(prefix + "\tmRestState:" + mRestState);
+ writer.println(prefix + "\tisInTransition:" + (mConfig.mCurrentAnimation != null));
+ }
+
public StateHandler[] getStateHandlers() {
if (mStateHandlers == null) {
mStateHandlers = UiFactory.getStateHandler(mLauncher);
diff --git a/src/com/android/launcher3/PagedView.java b/src/com/android/launcher3/PagedView.java
index abb45e5..3a02b07 100644
--- a/src/com/android/launcher3/PagedView.java
+++ b/src/com/android/launcher3/PagedView.java
@@ -300,10 +300,14 @@
return page;
}
+ public void setCurrentPage(int currentPage) {
+ setCurrentPage(currentPage, INVALID_PAGE);
+ }
+
/**
* Sets the current page.
*/
- public void setCurrentPage(int currentPage) {
+ public void setCurrentPage(int currentPage, int overridePrevPage) {
if (!mScroller.isFinished()) {
abortScrollerAnimation(true);
}
@@ -312,7 +316,7 @@
if (getChildCount() == 0) {
return;
}
- int prevPage = mCurrentPage;
+ int prevPage = overridePrevPage != INVALID_PAGE ? overridePrevPage : mCurrentPage;
mCurrentPage = validateNewPage(currentPage);
updateCurrentPageScroll();
notifyPageSwitchListener(prevPage);
diff --git a/src/com/android/launcher3/compat/AccessibilityManagerCompat.java b/src/com/android/launcher3/compat/AccessibilityManagerCompat.java
index 51e914c..b4d0c54 100644
--- a/src/com/android/launcher3/compat/AccessibilityManagerCompat.java
+++ b/src/com/android/launcher3/compat/AccessibilityManagerCompat.java
@@ -106,4 +106,11 @@
}
return false;
}
+
+ public static int getRecommendedTimeoutMillis(Context context, int originalTimeout, int flags) {
+ if (Utilities.ATLEAST_Q) {
+ return getManager(context).getRecommendedTimeoutMillis(originalTimeout, flags);
+ }
+ return originalTimeout;
+ }
}
diff --git a/src/com/android/launcher3/dragndrop/DragController.java b/src/com/android/launcher3/dragndrop/DragController.java
index 4d45ba9..7210759 100644
--- a/src/com/android/launcher3/dragndrop/DragController.java
+++ b/src/com/android/launcher3/dragndrop/DragController.java
@@ -696,5 +696,4 @@
public void removeDropTarget(DropTarget target) {
mDropTargets.remove(target);
}
-
}
diff --git a/src/com/android/launcher3/model/ModelWriter.java b/src/com/android/launcher3/model/ModelWriter.java
index 40c914b..4ce2f4b 100644
--- a/src/com/android/launcher3/model/ModelWriter.java
+++ b/src/com/android/launcher3/model/ModelWriter.java
@@ -47,6 +47,7 @@
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.Executor;
+import java.util.function.Supplier;
/**
* Class for handling model updates.
@@ -151,15 +152,13 @@
public void moveItemInDatabase(final ItemInfo item,
int container, int screenId, int cellX, int cellY) {
updateItemInfoProps(item, container, screenId, cellX, cellY);
-
- final ContentWriter writer = new ContentWriter(mContext)
- .put(Favorites.CONTAINER, item.container)
- .put(Favorites.CELLX, item.cellX)
- .put(Favorites.CELLY, item.cellY)
- .put(Favorites.RANK, item.rank)
- .put(Favorites.SCREEN, item.screenId);
-
- enqueueDeleteRunnable(new UpdateItemRunnable(item, writer));
+ enqueueDeleteRunnable(new UpdateItemRunnable(item, () ->
+ new ContentWriter(mContext)
+ .put(Favorites.CONTAINER, item.container)
+ .put(Favorites.CELLX, item.cellX)
+ .put(Favorites.CELLY, item.cellY)
+ .put(Favorites.RANK, item.rank)
+ .put(Favorites.SCREEN, item.screenId)));
}
/**
@@ -195,25 +194,26 @@
item.spanX = spanX;
item.spanY = spanY;
- final ContentWriter writer = new ContentWriter(mContext)
- .put(Favorites.CONTAINER, item.container)
- .put(Favorites.CELLX, item.cellX)
- .put(Favorites.CELLY, item.cellY)
- .put(Favorites.RANK, item.rank)
- .put(Favorites.SPANX, item.spanX)
- .put(Favorites.SPANY, item.spanY)
- .put(Favorites.SCREEN, item.screenId);
-
- mWorkerExecutor.execute(new UpdateItemRunnable(item, writer));
+ mWorkerExecutor.execute(new UpdateItemRunnable(item, () ->
+ new ContentWriter(mContext)
+ .put(Favorites.CONTAINER, item.container)
+ .put(Favorites.CELLX, item.cellX)
+ .put(Favorites.CELLY, item.cellY)
+ .put(Favorites.RANK, item.rank)
+ .put(Favorites.SPANX, item.spanX)
+ .put(Favorites.SPANY, item.spanY)
+ .put(Favorites.SCREEN, item.screenId)));
}
/**
* Update an item to the database in a specified container.
*/
public void updateItemInDatabase(ItemInfo item) {
- ContentWriter writer = new ContentWriter(mContext);
- item.onAddToDatabase(writer);
- mWorkerExecutor.execute(new UpdateItemRunnable(item, writer));
+ mWorkerExecutor.execute(new UpdateItemRunnable(item, () -> {
+ ContentWriter writer = new ContentWriter(mContext);
+ item.onAddToDatabase(writer);
+ return writer;
+ }));
}
/**
@@ -224,17 +224,18 @@
int container, int screenId, int cellX, int cellY) {
updateItemInfoProps(item, container, screenId, cellX, cellY);
- final ContentWriter writer = new ContentWriter(mContext);
final ContentResolver cr = mContext.getContentResolver();
- item.onAddToDatabase(writer);
-
item.id = Settings.call(cr, Settings.METHOD_NEW_ITEM_ID).getInt(Settings.EXTRA_VALUE);
- writer.put(Favorites._ID, item.id);
ModelVerifier verifier = new ModelVerifier();
-
final StackTraceElement[] stackTrace = new Throwable().getStackTrace();
mWorkerExecutor.execute(() -> {
+ // Write the item on background thread, as some properties might have been updated in
+ // the background.
+ final ContentWriter writer = new ContentWriter(mContext);
+ item.onAddToDatabase(writer);
+ writer.put(Favorites._ID, item.id);
+
cr.insert(Favorites.CONTENT_URI, writer.getValues(mContext));
synchronized (mBgDataModel) {
@@ -354,10 +355,10 @@
private class UpdateItemRunnable extends UpdateItemBaseRunnable {
private final ItemInfo mItem;
- private final ContentWriter mWriter;
+ private final Supplier<ContentWriter> mWriter;
private final int mItemId;
- UpdateItemRunnable(ItemInfo item, ContentWriter writer) {
+ UpdateItemRunnable(ItemInfo item, Supplier<ContentWriter> writer) {
mItem = item;
mWriter = writer;
mItemId = item.id;
@@ -366,7 +367,8 @@
@Override
public void run() {
Uri uri = Favorites.getContentUri(mItemId);
- mContext.getContentResolver().update(uri, mWriter.getValues(mContext), null, null);
+ mContext.getContentResolver().update(uri, mWriter.get().getValues(mContext),
+ null, null);
updateItemArrays(mItem, mItemId);
}
}
diff --git a/src/com/android/launcher3/util/IOUtils.java b/src/com/android/launcher3/util/IOUtils.java
index 77c21fe..f95f74d 100644
--- a/src/com/android/launcher3/util/IOUtils.java
+++ b/src/com/android/launcher3/util/IOUtils.java
@@ -16,12 +16,18 @@
package com.android.launcher3.util;
+import android.content.Context;
+
+import com.android.launcher3.config.FeatureFlags;
+
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
+import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
+import java.util.UUID;
/**
* Supports various IO utility functions
@@ -52,4 +58,23 @@
}
return total;
}
+
+ /**
+ * Utility method to debug binary data
+ */
+ public static String createTempFile(Context context, byte[] data) {
+ if (!FeatureFlags.IS_DOGFOOD_BUILD) {
+ throw new IllegalStateException("Method only allowed in development mode");
+ }
+
+ String name = UUID.randomUUID().toString();
+ File file = new File(context.getCacheDir(), name);
+ try (FileOutputStream fo = new FileOutputStream(file)) {
+ fo.write(data);
+ fo.flush();
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ return file.getAbsolutePath();
+ }
}
diff --git a/src/com/android/launcher3/util/TouchController.java b/src/com/android/launcher3/util/TouchController.java
index 3cca215..fc1d819 100644
--- a/src/com/android/launcher3/util/TouchController.java
+++ b/src/com/android/launcher3/util/TouchController.java
@@ -18,6 +18,8 @@
import android.view.MotionEvent;
+import java.io.PrintWriter;
+
public interface TouchController {
/**
@@ -29,4 +31,6 @@
* Called when the draglayer receives a intercept touch event.
*/
boolean onControllerInterceptTouchEvent(MotionEvent ev);
+
+ default void dump(String prefix, PrintWriter writer) { }
}
diff --git a/src/com/android/launcher3/views/BaseDragLayer.java b/src/com/android/launcher3/views/BaseDragLayer.java
index ab72bbe..66cd536 100644
--- a/src/com/android/launcher3/views/BaseDragLayer.java
+++ b/src/com/android/launcher3/views/BaseDragLayer.java
@@ -383,8 +383,13 @@
return mMultiValueAlpha.getProperty(index);
}
- public void dumpAlpha(PrintWriter writer) {
- writer.println(" dragLayerAlpha : " + mMultiValueAlpha );
+ public void dump(String prefix, PrintWriter writer) {
+ writer.println(prefix + "DragLayer");
+ if (mActiveController != null) {
+ writer.println(prefix + "\tactiveController: " + mActiveController);
+ mActiveController.dump(prefix + "\t", writer);
+ }
+ writer.println(prefix + "\tdragLayerAlpha : " + mMultiValueAlpha );
}
public static class LayoutParams extends InsettableFrameLayout.LayoutParams {
diff --git a/src/com/android/launcher3/views/Snackbar.java b/src/com/android/launcher3/views/Snackbar.java
index 04b637b..dc0e2e0 100644
--- a/src/com/android/launcher3/views/Snackbar.java
+++ b/src/com/android/launcher3/views/Snackbar.java
@@ -16,6 +16,9 @@
package com.android.launcher3.views;
+import static android.view.accessibility.AccessibilityManager.FLAG_CONTENT_CONTROLS;
+import static android.view.accessibility.AccessibilityManager.FLAG_CONTENT_TEXT;
+
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Rect;
@@ -29,6 +32,7 @@
import com.android.launcher3.Launcher;
import com.android.launcher3.R;
import com.android.launcher3.anim.Interpolators;
+import com.android.launcher3.compat.AccessibilityManagerCompat;
import com.android.launcher3.dragndrop.DragLayer;
/**
@@ -38,7 +42,7 @@
private static final long SHOW_DURATION_MS = 180;
private static final long HIDE_DURATION_MS = 180;
- private static final long TIMEOUT_DURATION_MS = 4000;
+ private static final int TIMEOUT_DURATION_MS = 4000;
private final Launcher mLauncher;
private Runnable mOnDismissed;
@@ -131,7 +135,9 @@
.setDuration(SHOW_DURATION_MS)
.setInterpolator(Interpolators.ACCEL_DEACCEL)
.start();
- snackbar.postDelayed(() -> snackbar.close(true), TIMEOUT_DURATION_MS);
+ int timeout = AccessibilityManagerCompat.getRecommendedTimeoutMillis(launcher,
+ TIMEOUT_DURATION_MS, FLAG_CONTENT_TEXT | FLAG_CONTENT_CONTROLS);
+ snackbar.postDelayed(() -> snackbar.close(true), timeout);
}
@Override