Merge "Fixing some dimentions in AllSet activity" into sc-dev
diff --git a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
index 524cd53..ea4b08d 100644
--- a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
+++ b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
@@ -61,6 +61,7 @@
import android.graphics.Matrix;
import android.graphics.PointF;
import android.graphics.Rect;
+import android.graphics.RectF;
import android.os.Build;
import android.os.IBinder;
import android.os.SystemClock;
@@ -383,10 +384,10 @@
// Set up a entire animation lifecycle callback to notify the current recents view when
// the animation is canceled
mGestureState.runOnceAtState(STATE_RECENTS_ANIMATION_CANCELED, () -> {
- ThumbnailData snapshot = mGestureState.getRecentsAnimationCanceledSnapshot();
+ ThumbnailData snapshot = mGestureState.consumeRecentsAnimationCanceledSnapshot();
if (snapshot != null) {
- RecentsModel.INSTANCE.get(mContext).onTaskSnapshotChanged(
- mRecentsView.getRunningTaskId(), snapshot);
+ mRecentsView.switchToScreenshot(snapshot,
+ () -> mRecentsAnimationController.cleanupScreenshot());
mRecentsView.onRecentsAnimationComplete();
}
});
@@ -1233,30 +1234,40 @@
final RecentsOrientedState orientationState = mTaskViewSimulator.getOrientationState();
final int windowRotation = orientationState.getDisplayRotation();
final int homeRotation = orientationState.getRecentsActivityRotation();
+
+ final Matrix homeToWindowPositionMap = new Matrix();
+ final RectF startRect = updateProgressForStartRect(homeToWindowPositionMap, startProgress);
+ // Move the startRect to Launcher space as floatingIconView runs in Launcher
+ final Matrix windowToHomePositionMap = new Matrix();
+ homeToWindowPositionMap.invert(windowToHomePositionMap);
+ windowToHomePositionMap.mapRect(startRect);
+
final Rect destinationBounds = SystemUiProxy.INSTANCE.get(mContext)
.startSwipePipToHome(taskInfo.topActivity,
TaskInfoCompat.getTopActivityInfo(taskInfo),
runningTaskTarget.taskInfo.pictureInPictureParams,
homeRotation,
mDp.hotseatBarSizePx);
- final SwipePipToHomeAnimator swipePipToHomeAnimator = new SwipePipToHomeAnimator(
- mContext,
- runningTaskTarget.taskId,
- taskInfo.topActivity,
- runningTaskTarget.leash.getSurfaceControl(),
- TaskInfoCompat.getPipSourceRectHint(
- runningTaskTarget.taskInfo.pictureInPictureParams),
- TaskInfoCompat.getWindowConfigurationBounds(taskInfo),
- updateProgressForStartRect(new Matrix(), startProgress),
- destinationBounds,
- mRecentsView.getPipCornerRadius(),
- mRecentsView);
+ final SwipePipToHomeAnimator.Builder builder = new SwipePipToHomeAnimator.Builder()
+ .setContext(mContext)
+ .setTaskId(runningTaskTarget.taskId)
+ .setComponentName(taskInfo.topActivity)
+ .setLeash(runningTaskTarget.leash.getSurfaceControl())
+ .setSourceRectHint(TaskInfoCompat.getPipSourceRectHint(
+ runningTaskTarget.taskInfo.pictureInPictureParams))
+ .setAppBounds(TaskInfoCompat.getWindowConfigurationBounds(taskInfo))
+ .setHomeToWindowPositionMap(homeToWindowPositionMap)
+ .setStartBounds(startRect)
+ .setDestinationBounds(destinationBounds)
+ .setCornerRadius(mRecentsView.getPipCornerRadius())
+ .setAttachedView(mRecentsView);
// We would assume home and app window always in the same rotation While homeRotation
// is not ROTATION_0 (which implies the rotation is turned on in launcher settings).
if (homeRotation == ROTATION_0
&& (windowRotation == ROTATION_90 || windowRotation == ROTATION_270)) {
- swipePipToHomeAnimator.setFromRotation(mTaskViewSimulator, windowRotation);
+ builder.setFromRotation(mTaskViewSimulator, windowRotation);
}
+ final SwipePipToHomeAnimator swipePipToHomeAnimator = builder.build();
AnimatorPlaybackController activityAnimationToHome =
homeAnimFactory.createActivityAnimationToHome();
swipePipToHomeAnimator.addAnimatorListener(new AnimatorListenerAdapter() {
@@ -1283,6 +1294,7 @@
mGestureState.setState(STATE_END_TARGET_ANIMATION_FINISHED);
}
});
+ setupWindowAnimation(swipePipToHomeAnimator);
return swipePipToHomeAnimator;
}
@@ -1313,6 +1325,11 @@
HomeAnimationFactory homeAnimationFactory) {
RectFSpringAnim anim =
super.createWindowAnimationToHome(startProgress, homeAnimationFactory);
+ setupWindowAnimation(anim);
+ return anim;
+ }
+
+ private void setupWindowAnimation(RectFSpringAnim anim) {
anim.addOnUpdateListener((v, r, p) -> {
updateSysUiFlags(Math.max(p, mCurrentShift.value));
});
@@ -1330,7 +1347,6 @@
if (mRecentsAnimationTargets != null) {
mRecentsAnimationTargets.addReleaseCheck(anim);
}
- return anim;
}
public void onConsumerAboutToBeSwitched() {
diff --git a/quickstep/src/com/android/quickstep/GestureState.java b/quickstep/src/com/android/quickstep/GestureState.java
index a302a07..015002f 100644
--- a/quickstep/src/com/android/quickstep/GestureState.java
+++ b/quickstep/src/com/android/quickstep/GestureState.java
@@ -376,11 +376,14 @@
}
/**
- * Returns the canceled animation thumbnail data. This call only returns a value while
- * STATE_RECENTS_ANIMATION_CANCELED state is being set.
+ * Returns and clears the canceled animation thumbnail data. This call only returns a value
+ * while STATE_RECENTS_ANIMATION_CANCELED state is being set, and the caller is responsible for
+ * calling {@link RecentsAnimationController#cleanupScreenshot()}.
*/
- ThumbnailData getRecentsAnimationCanceledSnapshot() {
- return mRecentsAnimationCanceledSnapshot;
+ ThumbnailData consumeRecentsAnimationCanceledSnapshot() {
+ ThumbnailData data = mRecentsAnimationCanceledSnapshot;
+ mRecentsAnimationCanceledSnapshot = null;
+ return data;
}
void setSwipeUpStartTimeMs(long uptimeMs) {
diff --git a/quickstep/src/com/android/quickstep/util/SwipePipToHomeAnimator.java b/quickstep/src/com/android/quickstep/util/SwipePipToHomeAnimator.java
index 67a635b..7488649 100644
--- a/quickstep/src/com/android/quickstep/util/SwipePipToHomeAnimator.java
+++ b/quickstep/src/com/android/quickstep/util/SwipePipToHomeAnimator.java
@@ -56,7 +56,9 @@
private final ComponentName mComponentName;
private final SurfaceControl mLeash;
private final Rect mAppBounds = new Rect();
+ private final Matrix mHomeToWindowPositionMap = new Matrix();
private final Rect mStartBounds = new Rect();
+ private final RectF mCurrentBoundsF = new RectF();
private final Rect mCurrentBounds = new Rect();
private final Rect mDestinationBounds = new Rect();
private final PipSurfaceTransactionHelper mSurfaceTransactionHelper;
@@ -66,10 +68,9 @@
private final Rect mSourceHintRectInsets;
private final Rect mSourceInsets = new Rect();
- /** for rotation via {@link #setFromRotation(TaskViewSimulator, int)} */
- private @RecentsOrientedState.SurfaceRotation int mFromRotation = Surface.ROTATION_0;
+ /** for rotation calculations */
+ private final @RecentsOrientedState.SurfaceRotation int mFromRotation;
private final Rect mDestinationBoundsTransformed = new Rect();
- private final Rect mDestinationBoundsAnimation = new Rect();
/**
* Flag to avoid the double-end problem since the leash would have been released
@@ -91,31 +92,39 @@
* @param leash {@link SurfaceControl} this animator operates on
* @param sourceRectHint See the definition in {@link android.app.PictureInPictureParams}
* @param appBounds Bounds of the application, sourceRectHint is based on this bounds
+ * @param homeToWindowPositionMap {@link Matrix} to map a Rect from home to window space
* @param startBounds Bounds of the application when this animator starts. This can be
* different from the appBounds if user has swiped a certain distance and
* Launcher has performed transform on the leash.
* @param destinationBounds Bounds of the destination this animator ends to
+ * @param fromRotation From rotation if different from final rotation, ROTATION_0 otherwise
+ * @param destinationBoundsTransformed Destination bounds in window space
* @param cornerRadius Corner radius in pixel value for PiP window
+ * @param view Attached view for logging purpose
*/
- public SwipePipToHomeAnimator(@NonNull Context context,
+ private SwipePipToHomeAnimator(@NonNull Context context,
int taskId,
@NonNull ComponentName componentName,
@NonNull SurfaceControl leash,
@Nullable Rect sourceRectHint,
@NonNull Rect appBounds,
+ @NonNull Matrix homeToWindowPositionMap,
@NonNull RectF startBounds,
@NonNull Rect destinationBounds,
+ @RecentsOrientedState.SurfaceRotation int fromRotation,
+ @NonNull Rect destinationBoundsTransformed,
int cornerRadius,
@NonNull View view) {
- super(startBounds, new RectF(destinationBounds), context);
+ super(startBounds, new RectF(destinationBoundsTransformed), context);
mTaskId = taskId;
mComponentName = componentName;
mLeash = leash;
mAppBounds.set(appBounds);
+ mHomeToWindowPositionMap.set(homeToWindowPositionMap);
startBounds.round(mStartBounds);
mDestinationBounds.set(destinationBounds);
- mDestinationBoundsTransformed.set(mDestinationBounds);
- mDestinationBoundsAnimation.set(mDestinationBounds);
+ mFromRotation = fromRotation;
+ mDestinationBoundsTransformed.set(destinationBoundsTransformed);
mSurfaceTransactionHelper = new PipSurfaceTransactionHelper(cornerRadius);
if (sourceRectHint != null && (sourceRectHint.width() < destinationBounds.width()
@@ -191,37 +200,13 @@
addOnUpdateListener(this::onAnimationUpdate);
}
- /** sets the from rotation if it's different from the target rotation. */
- public void setFromRotation(TaskViewSimulator taskViewSimulator,
- @RecentsOrientedState.SurfaceRotation int fromRotation) {
- if (fromRotation != Surface.ROTATION_90 && fromRotation != Surface.ROTATION_270) {
- Log.wtf(TAG, "Not a supported rotation, rotation=" + fromRotation);
- return;
- }
- mFromRotation = fromRotation;
- final Matrix matrix = new Matrix();
- taskViewSimulator.applyWindowToHomeRotation(matrix);
-
- // map the destination bounds into window space. mDestinationBounds is always calculated
- // in the final home space and the animation runs in original window space.
- final RectF transformed = new RectF(mDestinationBounds);
- matrix.mapRect(transformed, new RectF(mDestinationBounds));
- transformed.round(mDestinationBoundsTransformed);
-
- // set the animation destination bounds for RectEvaluator calculation.
- // bounds and insets are calculated as if the transition is from mAppBounds to
- // mDestinationBoundsAnimation, separated from rotate / scale / position.
- mDestinationBoundsAnimation.set(mAppBounds.left, mAppBounds.top,
- mAppBounds.left + mDestinationBounds.width(),
- mAppBounds.top + mDestinationBounds.height());
- }
-
private void onAnimationUpdate(@Nullable AppCloseConfig values, RectF currentRect,
float progress) {
if (mHasAnimationEnded) return;
final SurfaceControl.Transaction tx =
PipSurfaceTransactionHelper.newSurfaceControlTransaction();
- onAnimationUpdate(tx, currentRect, progress);
+ mHomeToWindowPositionMap.mapRect(mCurrentBoundsF, currentRect);
+ onAnimationUpdate(tx, mCurrentBoundsF, progress);
tx.apply();
}
@@ -309,6 +294,108 @@
return new RotatedPosition(degree, positionX, positionY);
}
+ /** Builder class for {@link SwipePipToHomeAnimator} */
+ public static class Builder {
+ private Context mContext;
+ private int mTaskId;
+ private ComponentName mComponentName;
+ private SurfaceControl mLeash;
+ private Rect mSourceRectHint;
+ private Rect mAppBounds;
+ private Matrix mHomeToWindowPositionMap;
+ private RectF mStartBounds;
+ private Rect mDestinationBounds;
+ private int mCornerRadius;
+ private View mAttachedView;
+ private @RecentsOrientedState.SurfaceRotation int mFromRotation = Surface.ROTATION_0;
+ private final Rect mDestinationBoundsTransformed = new Rect();
+
+ public Builder setContext(Context context) {
+ mContext = context;
+ return this;
+ }
+
+ public Builder setTaskId(int taskId) {
+ mTaskId = taskId;
+ return this;
+ }
+
+ public Builder setComponentName(ComponentName componentName) {
+ mComponentName = componentName;
+ return this;
+ }
+
+ public Builder setLeash(SurfaceControl leash) {
+ mLeash = leash;
+ return this;
+ }
+
+ public Builder setSourceRectHint(Rect sourceRectHint) {
+ mSourceRectHint = new Rect(sourceRectHint);
+ return this;
+ }
+
+ public Builder setAppBounds(Rect appBounds) {
+ mAppBounds = new Rect(appBounds);
+ return this;
+ }
+
+ public Builder setHomeToWindowPositionMap(Matrix homeToWindowPositionMap) {
+ mHomeToWindowPositionMap = new Matrix(homeToWindowPositionMap);
+ return this;
+ }
+
+ public Builder setStartBounds(RectF startBounds) {
+ mStartBounds = new RectF(startBounds);
+ return this;
+ }
+
+ public Builder setDestinationBounds(Rect destinationBounds) {
+ mDestinationBounds = new Rect(destinationBounds);
+ return this;
+ }
+
+ public Builder setCornerRadius(int cornerRadius) {
+ mCornerRadius = cornerRadius;
+ return this;
+ }
+
+ public Builder setAttachedView(View attachedView) {
+ mAttachedView = attachedView;
+ return this;
+ }
+
+ public Builder setFromRotation(TaskViewSimulator taskViewSimulator,
+ @RecentsOrientedState.SurfaceRotation int fromRotation) {
+ if (fromRotation != Surface.ROTATION_90 && fromRotation != Surface.ROTATION_270) {
+ Log.wtf(TAG, "Not a supported rotation, rotation=" + fromRotation);
+ return this;
+ }
+ final Matrix matrix = new Matrix();
+ taskViewSimulator.applyWindowToHomeRotation(matrix);
+
+ // map the destination bounds into window space. mDestinationBounds is always calculated
+ // in the final home space and the animation runs in original window space.
+ final RectF transformed = new RectF(mDestinationBounds);
+ matrix.mapRect(transformed, new RectF(mDestinationBounds));
+ transformed.round(mDestinationBoundsTransformed);
+
+ mFromRotation = fromRotation;
+ return this;
+ }
+
+ public SwipePipToHomeAnimator build() {
+ if (mDestinationBoundsTransformed.isEmpty()) {
+ mDestinationBoundsTransformed.set(mDestinationBounds);
+ }
+ return new SwipePipToHomeAnimator(mContext, mTaskId, mComponentName, mLeash,
+ mSourceRectHint, mAppBounds,
+ mHomeToWindowPositionMap, mStartBounds, mDestinationBounds,
+ mFromRotation, mDestinationBoundsTransformed,
+ mCornerRadius, mAttachedView);
+ }
+ }
+
private static class RotatedPosition {
private final float degree;
private final float positionX;
diff --git a/res/drawable/work_card.xml b/res/drawable/work_card.xml
index 0e4b054..7048955 100644
--- a/res/drawable/work_card.xml
+++ b/res/drawable/work_card.xml
@@ -20,8 +20,5 @@
android:shape="rectangle">
<solid android:color="?androidprv:attr/colorSurface" />
<corners android:radius="@dimen/work_edu_card_margin" />
- <padding
- android:left="@dimen/work_fab_radius"
- android:right="@dimen/work_fab_radius" />
</shape>
diff --git a/res/layout/launcher_preview_layout.xml b/res/layout/launcher_preview_layout.xml
index 1691680..cf2f2c7 100644
--- a/res/layout/launcher_preview_layout.xml
+++ b/res/layout/launcher_preview_layout.xml
@@ -13,7 +13,7 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<com.android.launcher3.InsettableFrameLayout
+<view class="com.android.launcher3.graphics.LauncherPreviewRenderer$LauncherPreviewLayout"
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:launcher="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
@@ -33,4 +33,4 @@
android:id="@+id/hotseat"
layout="@layout/hotseat" />
-</com.android.launcher3.InsettableFrameLayout>
\ No newline at end of file
+</view>
\ No newline at end of file
diff --git a/res/layout/work_apps_edu.xml b/res/layout/work_apps_edu.xml
index 919f1b2..84fdfdf 100644
--- a/res/layout/work_apps_edu.xml
+++ b/res/layout/work_apps_edu.xml
@@ -22,7 +22,8 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
- android:padding="@dimen/work_edu_card_margin"
+ android:paddingHorizontal="@dimen/work_card_padding_horizontal"
+ android:paddingVertical="@dimen/work_card_padding_vertical"
android:background="@drawable/work_card"
android:layout_gravity="center_horizontal"
android:gravity="center"
@@ -34,8 +35,7 @@
android:id="@+id/work_apps_paused_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:layout_marginTop="8dp"
- android:layout_marginBottom="8dp"
+ android:layout_marginBottom="@dimen/work_card_padding_vertical"
android:text="@string/work_profile_edu_work_apps"
android:textAlignment="center"
android:textSize="20sp" />
diff --git a/res/layout/work_apps_paused.xml b/res/layout/work_apps_paused.xml
index 02a50ca..841734c 100644
--- a/res/layout/work_apps_paused.xml
+++ b/res/layout/work_apps_paused.xml
@@ -28,18 +28,18 @@
android:layout_marginTop="40dp"
android:text="@string/work_apps_paused_title"
android:textAlignment="center"
- android:textSize="20sp" />
+ android:textSize="22sp" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/work_apps_paused_content"
- android:textColor="?attr/workProfileOverlayTextColor"
+ android:textColor="?android:attr/textColorSecondary"
android:text="@string/work_apps_paused_body"
android:textAlignment="center"
android:layout_marginTop="16dp"
android:layout_marginBottom="24dp"
- android:textSize="16sp" />
+ android:textSize="14sp" />
<Button
android:layout_width="wrap_content"
@@ -49,5 +49,7 @@
android:text="@string/work_apps_enable_btn_text"
android:textAlignment="center"
android:background="@drawable/rounded_action_button"
+ android:paddingStart="8dp"
+ android:paddingEnd="8dp"
android:textSize="14sp" />
</com.android.launcher3.allapps.WorkPausedCard>
\ No newline at end of file
diff --git a/res/layout/work_mode_fab.xml b/res/layout/work_mode_fab.xml
index 7183817..04faa15 100644
--- a/res/layout/work_mode_fab.xml
+++ b/res/layout/work_mode_fab.xml
@@ -25,7 +25,7 @@
android:textColor="@color/all_apps_tab_text"
android:textSize="14sp"
android:background="@drawable/work_apps_toggle_background"
- android:drawablePadding="16dp"
+ android:drawablePadding="8dp"
android:drawableStart="@drawable/ic_corp_off"
android:layout_marginBottom="@dimen/work_fab_margin"
android:layout_marginEnd="@dimen/work_fab_margin"
diff --git a/res/values-sw340dp/dimens.xml b/res/values-sw340dp/dimens.xml
index c9f2981..33b06f5 100644
--- a/res/values-sw340dp/dimens.xml
+++ b/res/values-sw340dp/dimens.xml
@@ -19,6 +19,5 @@
<!-- Drag padding to add to the bottom of drop targets -->
<dimen name="drop_target_drag_padding">20dp</dimen>
- <dimen name="drop_target_text_size">16sp</dimen>
</resources>
\ No newline at end of file
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index 270c92e..ee2304c 100644
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -121,6 +121,8 @@
<!-- Floating action button inside work tab to toggle work profile -->
<dimen name="work_fab_height">48dp</dimen>
<dimen name="work_fab_radius">24dp</dimen>
+ <dimen name="work_card_padding_horizontal">24dp</dimen>
+ <dimen name="work_card_padding_vertical">32dp</dimen>
<dimen name="work_fab_margin">16dp</dimen>
<dimen name="work_profile_footer_padding">20dp</dimen>
<dimen name="work_profile_footer_text_size">16sp</dimen>
@@ -189,8 +191,9 @@
<!-- Dragging -->
<!-- Drag padding to add to the bottom of drop targets -->
<dimen name="drop_target_drag_padding">14dp</dimen>
- <dimen name="drop_target_text_size">20sp</dimen>
+ <dimen name="drop_target_text_size">16sp</dimen>
<dimen name="drop_target_shadow_elevation">2dp</dimen>
+ <dimen name="drop_target_bar_margin_horizontal">4dp</dimen>
<!-- the distance an icon must be dragged before button drop targets accept it -->
<dimen name="drag_distanceThreshold">30dp</dimen>
diff --git a/res/values/styles.xml b/res/values/styles.xml
index 416c711..24851f2 100644
--- a/res/values/styles.xml
+++ b/res/values/styles.xml
@@ -258,7 +258,7 @@
<!-- Drop targets -->
<style name="DropTargetButtonBase" parent="@android:style/TextAppearance.DeviceDefault">
<item name="android:drawablePadding">8dp</item>
- <item name="android:padding">16dp</item>
+ <item name="android:padding">14dp</item>
<item name="android:textColor">@color/drop_target_text</item>
<item name="android:textSize">@dimen/drop_target_text_size</item>
<item name="android:singleLine">true</item>
diff --git a/src/com/android/launcher3/ButtonDropTarget.java b/src/com/android/launcher3/ButtonDropTarget.java
index 23dd3bb..61b5564 100644
--- a/src/com/android/launcher3/ButtonDropTarget.java
+++ b/src/com/android/launcher3/ButtonDropTarget.java
@@ -20,15 +20,12 @@
import static com.android.launcher3.LauncherState.NORMAL;
-import android.animation.AnimatorSet;
import android.content.Context;
-import android.content.res.ColorStateList;
import android.content.res.Resources;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.text.TextUtils;
import android.util.AttributeSet;
-import android.util.Property;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
@@ -40,6 +37,7 @@
import com.android.launcher3.dragndrop.DragController;
import com.android.launcher3.dragndrop.DragLayer;
import com.android.launcher3.dragndrop.DragOptions;
+import com.android.launcher3.dragndrop.DragView;
import com.android.launcher3.model.data.ItemInfo;
/**
@@ -212,18 +210,23 @@
return;
}
final DragLayer dragLayer = mLauncher.getDragLayer();
+ final DragView dragView = d.dragView;
final Rect from = new Rect();
dragLayer.getViewRectRelativeToSelf(d.dragView, from);
final Rect to = getIconRect(d);
final float scale = (float) to.width() / from.width();
- d.dragView.detachContentView(/* reattachToPreviousParent= */ true);
+ dragView.disableColorExtraction();
+ dragView.detachContentView(/* reattachToPreviousParent= */ true);
mDropTargetBar.deferOnDragEnd();
Runnable onAnimationEndRunnable = () -> {
completeDrop(d);
mDropTargetBar.onDragEnd();
mLauncher.getStateManager().goToState(NORMAL);
+ // Only re-enable updates once the workspace is back to normal, which will be after the
+ // current frame.
+ post(dragView::resumeColorExtraction);
};
dragLayer.animateView(d.dragView, from, to, scale, 1f, 1f, 0.1f, 0.1f,
diff --git a/src/com/android/launcher3/DropTargetBar.java b/src/com/android/launcher3/DropTargetBar.java
index 4a1b084..88f6c49 100644
--- a/src/com/android/launcher3/DropTargetBar.java
+++ b/src/com/android/launcher3/DropTargetBar.java
@@ -105,7 +105,8 @@
/ (2 * (grid.inv.numColumns + 1)))
+ grid.edgeMarginPx;
} else {
- gap = grid.desiredWorkspaceLeftRightMarginPx - grid.inv.defaultWidgetPadding.right;
+ gap = getContext().getResources()
+ .getDimensionPixelSize(R.dimen.drop_target_bar_margin_horizontal);
}
lp.width = grid.availableWidthPx - 2 * gap;
diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java
index f28f54a..5bdc402 100644
--- a/src/com/android/launcher3/Workspace.java
+++ b/src/com/android/launcher3/Workspace.java
@@ -1786,8 +1786,11 @@
onDropExternal(touchXY, dropTargetLayout, d);
} else {
final View cell = mDragInfo.cell;
+ final DragView dragView = d.dragView;
boolean droppedOnOriginalCellDuringTransition = false;
- Runnable onCompleteRunnable = null;
+ Runnable onCompleteRunnable = dragView::resumeColorExtraction;
+
+ dragView.disableColorExtraction();
if (dropTargetLayout != null && !d.cancelled) {
// Move internally
@@ -1898,7 +1901,9 @@
AppWidgetProviderInfo pInfo = hostView.getAppWidgetInfo();
if (pInfo != null && pInfo.resizeMode != AppWidgetProviderInfo.RESIZE_NONE
&& !options.isAccessibleDrag) {
+ final Runnable previousRunnable = onCompleteRunnable;
onCompleteRunnable = () -> {
+ previousRunnable.run();
if (!isPageInTransition()) {
AppWidgetResizeFrame.showForWidget(hostView, cellLayout);
}
@@ -1967,7 +1972,7 @@
parent.onDropChild(cell);
mLauncher.getStateManager().goToState(NORMAL, SPRING_LOADED_EXIT_DELAY,
- onCompleteRunnable == null ? null : forSuccessCallback(onCompleteRunnable));
+ forSuccessCallback(onCompleteRunnable));
mStatsLogManager.logger().withItemInfo(d.dragInfo).withInstanceId(d.logInstanceId)
.log(LauncherEvent.LAUNCHER_ITEM_DROP_COMPLETED);
}
diff --git a/src/com/android/launcher3/dragndrop/DragView.java b/src/com/android/launcher3/dragndrop/DragView.java
index 1664980..3fdb256 100644
--- a/src/com/android/launcher3/dragndrop/DragView.java
+++ b/src/com/android/launcher3/dragndrop/DragView.java
@@ -66,6 +66,7 @@
import com.android.launcher3.util.RunnableList;
import com.android.launcher3.util.Thunk;
import com.android.launcher3.views.BaseDragLayer;
+import com.android.launcher3.widget.LauncherAppWidgetHostView;
/** A custom view for rendering an icon, folder, shortcut or widget during drag-n-drop. */
public class DragView extends FrameLayout implements StateListener<LauncherState> {
@@ -471,12 +472,12 @@
mContent.draw(picture.beginRecording(mWidth, mHeight));
picture.endRecording();
View view = new View(mLauncher);
- view.setClipToOutline(mContent.getClipToOutline());
- view.setOutlineProvider(mContent.getOutlineProvider());
view.setBackground(new PictureDrawable(picture));
view.measure(makeMeasureSpec(mWidth, EXACTLY), makeMeasureSpec(mHeight, EXACTLY));
view.layout(mContent.getLeft(), mContent.getTop(),
mContent.getRight(), mContent.getBottom());
+ setClipToOutline(mContent.getClipToOutline());
+ setOutlineProvider(mContent.getOutlineProvider());
addViewInLayout(view, indexOfChild(mContent), mContent.getLayoutParams(), true);
removeViewInLayout(mContent);
@@ -491,6 +492,24 @@
}
/**
+ * If the drag view uses color extraction, block it.
+ */
+ public void disableColorExtraction() {
+ if (mContent instanceof LauncherAppWidgetHostView) {
+ ((LauncherAppWidgetHostView) mContent).disableColorExtraction();
+ }
+ }
+
+ /**
+ * If the drag view uses color extraction, restores it.
+ */
+ public void resumeColorExtraction() {
+ if (mContent instanceof LauncherAppWidgetHostView) {
+ ((LauncherAppWidgetHostView) mContent).enableColorExtraction(/* updateColors= */ false);
+ }
+ }
+
+ /**
* Removes this view from the {@link DragLayer}.
*
* <p>If the drag content is a {@link #mContent}, this call doesn't reattach the
diff --git a/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java b/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java
index 2a1aec8..cf3da4b 100644
--- a/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java
+++ b/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java
@@ -43,6 +43,7 @@
import android.util.AttributeSet;
import android.view.ContextThemeWrapper;
import android.view.LayoutInflater;
+import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowInsets;
@@ -467,4 +468,16 @@
view.measure(makeMeasureSpec(width, EXACTLY), makeMeasureSpec(height, EXACTLY));
view.layout(0, 0, width, height);
}
+
+ /** Root layout for launcher preview that intercepts all touch events. */
+ public static class LauncherPreviewLayout extends InsettableFrameLayout {
+ public LauncherPreviewLayout(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ @Override
+ public boolean onInterceptTouchEvent(MotionEvent ev) {
+ return true;
+ }
+ }
}
diff --git a/src/com/android/launcher3/widget/LauncherAppWidgetHostView.java b/src/com/android/launcher3/widget/LauncherAppWidgetHostView.java
index ea08a25..63bc416 100644
--- a/src/com/android/launcher3/widget/LauncherAppWidgetHostView.java
+++ b/src/com/android/launcher3/widget/LauncherAppWidgetHostView.java
@@ -57,7 +57,6 @@
import com.android.launcher3.widget.dragndrop.AppWidgetHostViewDragListener;
import java.util.List;
-import java.util.Optional;
/**
* {@inheritDoc}
@@ -118,7 +117,9 @@
private final ViewGroupFocusHelper mDragLayerRelativeCoordinateHelper;
private long mDeferUpdatesUntilMillis = 0;
private RemoteViews mDeferredRemoteViews;
- private Optional<SparseIntArray> mDeferredColorChange = Optional.empty();
+ private boolean mHasDeferredColorChange = false;
+ private @Nullable SparseIntArray mDeferredColorChange = null;
+ private boolean mEnableColorExtraction = true;
public LauncherAppWidgetHostView(Context context) {
super(context);
@@ -243,18 +244,23 @@
*/
public void endDeferringUpdates() {
RemoteViews remoteViews;
- Optional<SparseIntArray> deferredColors;
+ SparseIntArray deferredColors;
+ boolean hasDeferredColors;
synchronized (mUpdateLock) {
mDeferUpdatesUntilMillis = 0;
remoteViews = mDeferredRemoteViews;
mDeferredRemoteViews = null;
deferredColors = mDeferredColorChange;
- mDeferredColorChange = Optional.empty();
+ hasDeferredColors = mHasDeferredColorChange;
+ mDeferredColorChange = null;
+ mHasDeferredColorChange = false;
}
if (remoteViews != null) {
updateAppWidget(remoteViews);
}
- deferredColors.ifPresent(colors -> onColorsChanged(null /* rectF */, colors));
+ if (hasDeferredColors) {
+ onColorsChanged(null /* rectF */, deferredColors);
+ }
}
public boolean onInterceptTouchEvent(MotionEvent ev) {
@@ -342,13 +348,7 @@
}
mIsScrollable = checkScrollableRecursively(this);
- if (!mIsInDragMode && getTag() instanceof LauncherAppWidgetInfo) {
-
- LauncherAppWidgetInfo info = (LauncherAppWidgetInfo) getTag();
- mDragLayerRelativeCoordinateHelper.viewToRect(this, mCurrentWidgetSize);
- updateColorExtraction(mCurrentWidgetSize,
- mWorkspace.getPageIndexForScreenId(info.screenId));
- }
+ updateColorExtraction();
enforceRoundedCorners();
}
@@ -377,6 +377,7 @@
* @param pageId The workspace page the widget is on.
*/
private void updateColorExtraction(Rect rectInDragLayer, int pageId) {
+ if (!mEnableColorExtraction) return;
mColorExtractor.getExtractedRectForViewRect(mLauncher, pageId, rectInDragLayer, mTempRectF);
if (mTempRectF.isEmpty()) {
@@ -391,6 +392,38 @@
}
}
+ /**
+ * Update the color extraction, using the current position of the app widget.
+ */
+ private void updateColorExtraction() {
+ if (!mIsInDragMode && getTag() instanceof LauncherAppWidgetInfo) {
+ LauncherAppWidgetInfo info = (LauncherAppWidgetInfo) getTag();
+ mDragLayerRelativeCoordinateHelper.viewToRect(this, mCurrentWidgetSize);
+ updateColorExtraction(mCurrentWidgetSize,
+ mWorkspace.getPageIndexForScreenId(info.screenId));
+ }
+ }
+
+ /**
+ * Enables the local color extraction.
+ *
+ * @param updateColors If true, this will update the color extraction using the current location
+ * of the App Widget.
+ */
+ public void enableColorExtraction(boolean updateColors) {
+ mEnableColorExtraction = true;
+ if (updateColors) {
+ updateColorExtraction();
+ }
+ }
+
+ /**
+ * Disables the local color extraction.
+ */
+ public void disableColorExtraction() {
+ mEnableColorExtraction = false;
+ }
+
// Compare two location rectangles. Locations are always in the [0;1] range.
private static boolean isSameLocation(@NonNull RectF rect1, @Nullable RectF rect2,
float epsilon) {
@@ -409,10 +442,12 @@
public void onColorsChanged(RectF rectF, SparseIntArray colors) {
synchronized (mUpdateLock) {
if (isDeferringUpdates()) {
- mDeferredColorChange = Optional.ofNullable(colors);
+ mDeferredColorChange = colors;
+ mHasDeferredColorChange = true;
return;
}
- mDeferredColorChange = Optional.empty();
+ mDeferredColorChange = null;
+ mHasDeferredColorChange = false;
}
// setColorResources will reapply the view, which must happen in the UI thread.
diff --git a/tests/src/com/android/launcher3/util/rule/ShellCommandRule.java b/tests/src/com/android/launcher3/util/rule/ShellCommandRule.java
index 0ec0f02..2b2fef4 100644
--- a/tests/src/com/android/launcher3/util/rule/ShellCommandRule.java
+++ b/tests/src/com/android/launcher3/util/rule/ShellCommandRule.java
@@ -15,21 +15,27 @@
*/
package com.android.launcher3.util.rule;
-import static com.android.launcher3.tapl.TestHelpers.getLauncherInMyProcess;
-
import static androidx.test.InstrumentationRegistry.getInstrumentation;
+import static com.android.launcher3.tapl.TestHelpers.getLauncherInMyProcess;
+
import android.content.ComponentName;
import android.content.pm.ActivityInfo;
-
-import org.junit.rules.TestRule;
-import org.junit.runner.Description;
-import org.junit.runners.model.Statement;
+import android.util.Log;
import androidx.annotation.Nullable;
import androidx.test.InstrumentationRegistry;
import androidx.test.uiautomator.UiDevice;
+import com.android.systemui.shared.system.PackageManagerWrapper;
+
+import org.junit.Assert;
+import org.junit.rules.TestRule;
+import org.junit.runner.Description;
+import org.junit.runners.model.Statement;
+
+import java.util.ArrayList;
+
/**
* Test rule which executes a shell command at the start of the test.
*/
@@ -37,10 +43,19 @@
private final String mCmd;
private final String mRevertCommand;
+ private final boolean mCheckSuccess;
+ private final Runnable mAdditionalChecks;
- public ShellCommandRule(String cmd, @Nullable String revertCommand) {
+ public ShellCommandRule(String cmd, @Nullable String revertCommand, boolean checkSuccess,
+ Runnable additionalChecks) {
mCmd = cmd;
mRevertCommand = revertCommand;
+ mCheckSuccess = checkSuccess;
+ mAdditionalChecks = additionalChecks;
+ }
+
+ public ShellCommandRule(String cmd, @Nullable String revertCommand) {
+ this(cmd, revertCommand, false, null);
}
@Override
@@ -48,12 +63,27 @@
return new Statement() {
@Override
public void evaluate() throws Throwable {
- UiDevice.getInstance(getInstrumentation()).executeShellCommand(mCmd);
+ final String result =
+ UiDevice.getInstance(getInstrumentation()).executeShellCommand(mCmd);
+ if (mCheckSuccess) {
+ Assert.assertTrue(
+ "Failed command: " + mCmd + ", result: " + result,
+ "Success".equals(result.replaceAll("\\s", "")));
+ }
+ if (mAdditionalChecks != null) mAdditionalChecks.run();
try {
base.evaluate();
} finally {
if (mRevertCommand != null) {
- UiDevice.getInstance(getInstrumentation()).executeShellCommand(mRevertCommand);
+ final String revertResult = UiDevice.getInstance(
+ getInstrumentation()).executeShellCommand(
+ mRevertCommand);
+ if (mCheckSuccess) {
+ Assert.assertTrue(
+ "Failed command: " + mRevertCommand
+ + ", result: " + revertResult,
+ "Success".equals(result.replaceAll("\\s", "")));
+ }
}
}
}
@@ -72,7 +102,15 @@
* Sets the target launcher as default launcher.
*/
public static ShellCommandRule setDefaultLauncher() {
- return new ShellCommandRule(getLauncherCommand(getLauncherInMyProcess()), null);
+ final ActivityInfo launcher = getLauncherInMyProcess();
+ Log.d("b/187080582", "Launcher: " + new ComponentName(launcher.packageName, launcher.name)
+ .flattenToString());
+ return new ShellCommandRule(getLauncherCommand(launcher), null, true, () ->
+ Assert.assertEquals("Setting default launcher failed",
+ new ComponentName(launcher.packageName, launcher.name)
+ .flattenToString(),
+ PackageManagerWrapper.getInstance().getHomeActivities(new ArrayList<>())
+ .flattenToString()));
}
public static String getLauncherCommand(ActivityInfo launcher) {
diff --git a/tests/tapl/com/android/launcher3/tapl/LogEventChecker.java b/tests/tapl/com/android/launcher3/tapl/LogEventChecker.java
index a809e2e..710e3cd 100644
--- a/tests/tapl/com/android/launcher3/tapl/LogEventChecker.java
+++ b/tests/tapl/com/android/launcher3/tapl/LogEventChecker.java
@@ -15,6 +15,10 @@
*/
package com.android.launcher3.tapl;
+import static com.android.launcher3.testing.TestProtocol.SEQUENCE_MAIN;
+import static com.android.launcher3.testing.TestProtocol.SEQUENCE_PILFER;
+import static com.android.launcher3.testing.TestProtocol.SEQUENCE_TIS;
+
import android.os.SystemClock;
import com.android.launcher3.testing.TestProtocol;
@@ -87,6 +91,24 @@
final ListMap<String> actualEvents = finishSync(waitForExpectedCountMs);
if (actualEvents == null) return "null event sequences because launcher likely died";
+ final String lowLevelDiags = lowLevelMismatchDiagnostics(actualEvents);
+ // If we have a sequence mismatch for a successful gesture, we want to provide all low-level
+ // details.
+ if (successfulGesture) {
+ return lowLevelDiags;
+ }
+
+ final String sequenceMismatchInEnglish = highLevelMismatchDiagnostics(actualEvents);
+
+ if (sequenceMismatchInEnglish != null) {
+ LauncherInstrumentation.log(lowLevelDiags);
+ return "Hint: " + sequenceMismatchInEnglish;
+ } else {
+ return lowLevelDiags;
+ }
+ }
+
+ private String lowLevelMismatchDiagnostics(ListMap<String> actualEvents) {
final StringBuilder sb = new StringBuilder();
boolean hasMismatches = false;
for (Map.Entry<String, List<Pattern>> expectedEvents : mExpectedEvents.entrySet()) {
@@ -118,6 +140,42 @@
return hasMismatches ? "Mismatching events: " + sb.toString() : null;
}
+ private String highLevelMismatchDiagnostics(ListMap<String> actualEvents) {
+ if (!mExpectedEvents.getNonNull(SEQUENCE_TIS).isEmpty()
+ && actualEvents.getNonNull(SEQUENCE_TIS).isEmpty()) {
+ return "TouchInteractionService didn't receive any of the touch events sent by the "
+ + "test";
+ }
+ if (getMismatchPosition(mExpectedEvents.getNonNull(SEQUENCE_TIS),
+ actualEvents.getNonNull(SEQUENCE_TIS)) != -1) {
+ // If TIS has a mismatch that we can't convert to high-level diags, don't convert
+ // other sequences either.
+ return null;
+ }
+
+ if (mExpectedEvents.getNonNull(SEQUENCE_PILFER).size() == 1
+ && actualEvents.getNonNull(SEQUENCE_PILFER).isEmpty()) {
+ return "Launcher didn't detect the navigation gesture sent by the test";
+ }
+ if (mExpectedEvents.getNonNull(SEQUENCE_PILFER).isEmpty()
+ && actualEvents.getNonNull(SEQUENCE_PILFER).size() == 1) {
+ return "Launcher detected a navigation gesture, but the test didn't send one";
+ }
+ if (getMismatchPosition(mExpectedEvents.getNonNull(SEQUENCE_PILFER),
+ actualEvents.getNonNull(SEQUENCE_PILFER)) != -1) {
+ // If Pilfer has a mismatch that we can't convert to high-level diags, don't analyze
+ // other sequences.
+ return null;
+ }
+
+ if (!mExpectedEvents.getNonNull(SEQUENCE_MAIN).isEmpty()
+ && actualEvents.getNonNull(SEQUENCE_MAIN).isEmpty()) {
+ return "None of the touch or keyboard events sent by the test was received by "
+ + "Launcher's main thread";
+ }
+ return null;
+ }
+
// If the list of actual events matches the list of expected events, returns -1, otherwise
// the position of the mismatch.
private static int getMismatchPosition(List<Pattern> expected, List<String> actual) {