Merge "Ensure that the Hotseat respects the margins of the QSB." into tm-dev
diff --git a/quickstep/src/com/android/launcher3/uioverrides/states/AllAppsState.java b/quickstep/src/com/android/launcher3/uioverrides/states/AllAppsState.java
index 4583fc3..cd14b3f 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/states/AllAppsState.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/states/AllAppsState.java
@@ -38,7 +38,7 @@
@Override
public int getTransitionDuration(Context context) {
- return 320;
+ return 150;
}
@Override
diff --git a/quickstep/src/com/android/quickstep/RecentsAnimationController.java b/quickstep/src/com/android/quickstep/RecentsAnimationController.java
index f343485..c120b32 100644
--- a/quickstep/src/com/android/quickstep/RecentsAnimationController.java
+++ b/quickstep/src/com/android/quickstep/RecentsAnimationController.java
@@ -17,9 +17,13 @@
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 android.os.RemoteException;
+import android.util.Log;
import android.view.IRecentsAnimationController;
import android.view.SurfaceControl;
+import android.view.WindowManagerGlobal;
import android.window.PictureInPictureSurfaceTransaction;
import androidx.annotation.NonNull;
@@ -39,6 +43,7 @@
*/
public class RecentsAnimationController {
+ private static final String TAG = "RecentsAnimationController";
private final RecentsAnimationControllerCompat mController;
private final Consumer<RecentsAnimationController> mOnFinishedListener;
private final boolean mAllowMinimizeSplitScreen;
@@ -74,7 +79,16 @@
if (mUseLauncherSysBarFlags != useLauncherSysBarFlags) {
mUseLauncherSysBarFlags = useLauncherSysBarFlags;
UI_HELPER_EXECUTOR.execute(() -> {
- mController.setAnimationTargetsBehindSystemBars(!useLauncherSysBarFlags);
+ if (!ENABLE_SHELL_TRANSITIONS) {
+ mController.setAnimationTargetsBehindSystemBars(!useLauncherSysBarFlags);
+ } else {
+ try {
+ WindowManagerGlobal.getWindowManagerService().setRecentsAppBehindSystemBars(
+ useLauncherSysBarFlags);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Unable to reach window manager", e);
+ }
+ }
});
}
}
diff --git a/quickstep/src/com/android/quickstep/TouchInteractionService.java b/quickstep/src/com/android/quickstep/TouchInteractionService.java
index 2ed75b5..fc5f34d 100644
--- a/quickstep/src/com/android/quickstep/TouchInteractionService.java
+++ b/quickstep/src/com/android/quickstep/TouchInteractionService.java
@@ -959,6 +959,9 @@
pw.println("ProtoTrace:");
pw.println(" file=" + ProtoTracer.INSTANCE.get(this).getTraceFile());
mTaskbarManager.dumpLogs("", pw);
+ if (createdOverviewActivity != null) {
+ createdOverviewActivity.getDeviceProfile().dump("", pw);
+ }
}
}
diff --git a/quickstep/src/com/android/quickstep/views/FloatingTaskThumbnailView.java b/quickstep/src/com/android/quickstep/views/FloatingTaskThumbnailView.java
new file mode 100644
index 0000000..cfb0056
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/views/FloatingTaskThumbnailView.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright 2022 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.views;
+
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.graphics.BitmapShader;
+import android.graphics.Canvas;
+import android.graphics.Matrix;
+import android.graphics.Paint;
+import android.graphics.Shader;
+import android.util.AttributeSet;
+import android.view.View;
+
+import androidx.annotation.Nullable;
+
+/**
+ * A child view of {@link com.android.quickstep.views.FloatingTaskView} to draw the thumbnail in a
+ * rounded corner frame. While the purpose of this class sounds similar to
+ * {@link TaskThumbnailView}, it doesn't need a lot of complex logic in {@link TaskThumbnailView}
+ * in relation to moving with {@link RecentsView}.
+ */
+public class FloatingTaskThumbnailView extends View {
+
+ private final Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
+ private final Matrix mMatrix = new Matrix();
+
+ private @Nullable BitmapShader mBitmapShader;
+ private @Nullable Bitmap mBitmap;
+
+ private FloatingTaskView.FullscreenDrawParams mFullscreenParams;
+
+ public FloatingTaskThumbnailView(Context context) {
+ this(context, null);
+ }
+
+ public FloatingTaskThumbnailView(Context context, AttributeSet attrs) {
+ this(context, attrs, 0);
+ }
+
+ public FloatingTaskThumbnailView(Context context, AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ }
+
+ @Override
+ protected void onDraw(Canvas canvas) {
+ if (mFullscreenParams == null || mBitmap == null) {
+ return;
+ }
+
+ // Scale down the bitmap to fix x, and crop in y.
+ float scale = 1.0f * getMeasuredWidth() / mBitmap.getWidth();
+ mMatrix.postScale(scale, scale);
+ mBitmapShader.setLocalMatrix(mMatrix);
+
+ canvas.drawRoundRect(0, 0, getMeasuredWidth(), getMeasuredHeight(),
+ mFullscreenParams.mCurrentDrawnCornerRadius / mFullscreenParams.mScaleX,
+ mFullscreenParams.mCurrentDrawnCornerRadius / mFullscreenParams.mScaleY, mPaint);
+ }
+
+ public void setThumbnail(Bitmap bitmap) {
+ mBitmap = bitmap;
+ if (bitmap != null) {
+ mBitmapShader = new BitmapShader(bitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
+ mPaint.setShader(mBitmapShader);
+ }
+ }
+
+ public void setFullscreenParams(FloatingTaskView.FullscreenDrawParams fullscreenParams) {
+ mFullscreenParams = fullscreenParams;
+ }
+}
diff --git a/quickstep/src/com/android/quickstep/views/FloatingTaskView.java b/quickstep/src/com/android/quickstep/views/FloatingTaskView.java
index f2f1c3f..c59dc18 100644
--- a/quickstep/src/com/android/quickstep/views/FloatingTaskView.java
+++ b/quickstep/src/com/android/quickstep/views/FloatingTaskView.java
@@ -15,7 +15,6 @@
import android.view.View;
import android.view.ViewGroup;
import android.widget.FrameLayout;
-import android.widget.ImageView;
import androidx.annotation.Nullable;
@@ -29,6 +28,8 @@
import com.android.launcher3.touch.PagedOrientationHandler;
import com.android.launcher3.views.BaseDragLayer;
import com.android.quickstep.util.MultiValueUpdateListener;
+import com.android.quickstep.util.TaskCornerRadius;
+import com.android.systemui.shared.system.QuickStepContract;
import java.util.function.Consumer;
@@ -50,9 +51,9 @@
private RectF mStartingPosition;
private final StatefulActivity mActivity;
private final boolean mIsRtl;
- private final Rect mOutline = new Rect();
+ private final FullscreenDrawParams mCurrentFullscreenParams;
private PagedOrientationHandler mOrientationHandler;
- private ImageView mImageView;
+ private FloatingTaskThumbnailView mThumbnailView;
public FloatingTaskView(Context context) {
this(context, null);
@@ -66,16 +67,17 @@
super(context, attrs, defStyleAttr);
mActivity = BaseActivity.fromContext(context);
mIsRtl = Utilities.isRtl(getResources());
+ mCurrentFullscreenParams = new FullscreenDrawParams(context);
}
@Override
protected void onFinishInflate() {
super.onFinishInflate();
- mImageView = findViewById(R.id.thumbnail);
- mImageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
- mImageView.setLayerType(LAYER_TYPE_HARDWARE, null);
+ mThumbnailView = findViewById(R.id.thumbnail);
+ mThumbnailView.setFullscreenParams(mCurrentFullscreenParams);
mSplitPlaceholderView = findViewById(R.id.split_placeholder);
mSplitPlaceholderView.setAlpha(0);
+ mSplitPlaceholderView.setFullscreenParams(mCurrentFullscreenParams);
}
private void init(StatefulActivity launcher, View originalView, @Nullable Bitmap thumbnail,
@@ -86,13 +88,11 @@
(InsettableFrameLayout.LayoutParams) getLayoutParams();
mSplitPlaceholderView.setLayoutParams(new FrameLayout.LayoutParams(lp.width, lp.height));
- positionOut.round(mOutline);
setPivotX(0);
setPivotY(0);
// Copy bounds of exiting thumbnail into ImageView
- mImageView.setImageBitmap(thumbnail);
- mImageView.setVisibility(VISIBLE);
+ mThumbnailView.setThumbnail(thumbnail);
RecentsView recentsView = launcher.getOverviewPanel();
mOrientationHandler = recentsView.getPagedOrientationHandler();
@@ -133,27 +133,24 @@
setLayoutParams(lp);
}
- // TODO(194414938) set correct corner radii
- public void update(RectF position, float progress, float windowRadius) {
+ public void update(RectF position, float progress) {
MarginLayoutParams lp = (MarginLayoutParams) getLayoutParams();
float dX = position.left - mStartingPosition.left;
float dY = position.top - lp.topMargin;
+ float scaleX = position.width() / lp.width;
+ float scaleY = position.height() / lp.height;
+
+ mCurrentFullscreenParams.updateParams(position, progress, scaleX, scaleY);
setTranslationX(dX);
setTranslationY(dY);
-
- float scaleX = position.width() / lp.width;
- float scaleY = position.height() / lp.height;
setScaleX(scaleX);
setScaleY(scaleY);
+ mSplitPlaceholderView.invalidate();
+
float childScaleX = 1f / scaleX;
float childScaleY = 1f / scaleY;
-
- invalidate();
- // TODO(194414938) seems like this scale value could be fine tuned, some stretchiness
- mImageView.setScaleX(1f / scaleX + scaleX * progress);
- mImageView.setScaleY(1f / scaleY + scaleY * progress);
mOrientationHandler.setPrimaryScale(mSplitPlaceholderView.getIconView(), childScaleX);
mOrientationHandler.setSecondaryScale(mSplitPlaceholderView.getIconView(), childScaleY);
}
@@ -181,7 +178,8 @@
}
public void addAnimation(PendingAnimation animation, RectF startingBounds, Rect endBounds,
- boolean fadeWithThumbnail) {
+ boolean fadeWithThumbnail, boolean isInitialSplit) {
+ mCurrentFullscreenParams.setIsInitialSplit(isInitialSplit);
final BaseDragLayer dragLayer = mActivity.getDragLayer();
int[] dragLayerBounds = new int[2];
dragLayer.getLocationOnScreen(dragLayerBounds);
@@ -191,22 +189,16 @@
ValueAnimator transitionAnimator = ValueAnimator.ofFloat(0, 1);
animation.add(transitionAnimator);
long animDuration = animation.getDuration();
- Rect crop = new Rect();
RectF floatingTaskViewBounds = new RectF();
- final float initialWindowRadius = supportsRoundedCornersOnWindows(getResources())
- ? Math.max(crop.width(), crop.height()) / 2f
- : 0f;
if (fadeWithThumbnail) {
animation.addFloat(mSplitPlaceholderView, SplitPlaceholderView.ALPHA_FLOAT,
0, 1, ACCEL);
- animation.addFloat(mImageView, LauncherAnimUtils.VIEW_ALPHA,
+ animation.addFloat(mThumbnailView, LauncherAnimUtils.VIEW_ALPHA,
1, 0, DEACCEL_3);
}
MultiValueUpdateListener listener = new MultiValueUpdateListener() {
- final FloatProp mWindowRadius = new FloatProp(initialWindowRadius,
- initialWindowRadius, 0, animDuration, LINEAR);
final FloatProp mDx = new FloatProp(0, prop.dX, 0, animDuration, LINEAR);
final FloatProp mDy = new FloatProp(0, prop.dY, 0, animDuration, LINEAR);
final FloatProp mTaskViewScaleX = new FloatProp(1f, prop.finalTaskViewScaleX, 0,
@@ -221,7 +213,7 @@
Utilities.scaleRectFAboutCenter(floatingTaskViewBounds, mTaskViewScaleX.value,
mTaskViewScaleY.value);
- update(floatingTaskViewBounds, percent, mWindowRadius.value * 1);
+ update(floatingTaskViewBounds, percent);
}
};
transitionAnimator.addUpdateListener(listener);
@@ -250,4 +242,36 @@
dY = centerY - startTaskViewBounds.centerY();
}
}
+
+ public static class FullscreenDrawParams {
+
+ private final float mCornerRadius;
+ private final float mWindowCornerRadius;
+
+ public boolean mIsInitialSplit = true;
+ public final RectF mFloatingTaskViewBounds = new RectF();
+ public float mCurrentDrawnCornerRadius;
+ public float mScaleX = 1;
+ public float mScaleY = 1;
+
+ public FullscreenDrawParams(Context context) {
+ mCornerRadius = TaskCornerRadius.get(context);
+ mWindowCornerRadius = QuickStepContract.getWindowCornerRadius(context);
+
+ mCurrentDrawnCornerRadius = mCornerRadius;
+ }
+
+ public void updateParams(RectF floatingTaskViewBounds, float progress, float scaleX,
+ float scaleY) {
+ mFloatingTaskViewBounds.set(floatingTaskViewBounds);
+ mScaleX = scaleX;
+ mScaleY = scaleY;
+ mCurrentDrawnCornerRadius = mIsInitialSplit ? 0 :
+ Utilities.mapRange(progress, mCornerRadius, mWindowCornerRadius);
+ }
+
+ public void setIsInitialSplit(boolean isInitialSplit) {
+ mIsInitialSplit = isInitialSplit;
+ }
+ }
}
diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java
index cb7e08a..5e331e2 100644
--- a/quickstep/src/com/android/quickstep/views/RecentsView.java
+++ b/quickstep/src/com/android/quickstep/views/RecentsView.java
@@ -2732,7 +2732,7 @@
mSplitHiddenTaskView.getIconView().getDrawable(), startingTaskRect);
mFirstFloatingTaskView.setAlpha(1);
mFirstFloatingTaskView.addAnimation(anim, startingTaskRect,
- mTempRect, true /*fadeWithThumbnail*/);
+ mTempRect, true /* fadeWithThumbnail */, true /* isInitialSplit */);
} else {
mSplitSelectSource.view.setVisibility(INVISIBLE);
mFirstFloatingTaskView = FloatingTaskView.getFloatingTaskView(mActivity,
@@ -2740,7 +2740,7 @@
mSplitSelectSource.drawable, startingTaskRect);
mFirstFloatingTaskView.setAlpha(1);
mFirstFloatingTaskView.addAnimation(anim, startingTaskRect,
- mTempRect, true /*fadeWithThumbnail*/);
+ mTempRect, true /* fadeWithThumbnail */, true /* isInitialSplit */);
}
anim.addEndListener(success -> {
if (success) {
@@ -4030,14 +4030,14 @@
mFirstFloatingTaskView.getBoundsOnScreen(firstTaskStartingBounds);
mFirstFloatingTaskView.addAnimation(pendingAnimation,
new RectF(firstTaskStartingBounds), firstTaskEndingBounds,
- false /*fadeWithThumbnail*/);
+ false /* fadeWithThumbnail */, false /* isInitialSplit */);
mSecondFloatingTaskView = FloatingTaskView.getFloatingTaskView(mActivity,
thumbnailView, thumbnailView.getThumbnail(),
iconView.getDrawable(), secondTaskStartingBounds);
mSecondFloatingTaskView.setAlpha(1);
mSecondFloatingTaskView.addAnimation(pendingAnimation, secondTaskStartingBounds,
- secondTaskEndingBounds, true /* fadeWithThumbnail */);
+ secondTaskEndingBounds, true /* fadeWithThumbnail */, false /* isInitialSplit */);
pendingAnimation.addEndListener(aBoolean ->
mSplitSelectStateController.setSecondTaskId(task.key.id,
aBoolean1 -> RecentsView.this.resetFromSplitSelectionState()));
@@ -4110,7 +4110,7 @@
mTempRectF.set(mTempRect);
// TODO(194414938) set correct corner radius
mFirstFloatingTaskView.updateOrientationHandler(mOrientationHandler);
- mFirstFloatingTaskView.update(mTempRectF, /*progress=*/1f, /*windowRadius=*/0f);
+ mFirstFloatingTaskView.update(mTempRectF, /*progress=*/1f);
PagedOrientationHandler orientationHandler = getPagedOrientationHandler();
Pair<FloatProperty, FloatProperty> taskViewsFloat =
diff --git a/quickstep/src/com/android/quickstep/views/SplitPlaceholderView.java b/quickstep/src/com/android/quickstep/views/SplitPlaceholderView.java
index cfa482f..d37dfbf 100644
--- a/quickstep/src/com/android/quickstep/views/SplitPlaceholderView.java
+++ b/quickstep/src/com/android/quickstep/views/SplitPlaceholderView.java
@@ -17,9 +17,12 @@
package com.android.quickstep.views;
import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Paint;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.util.FloatProperty;
+import android.util.TypedValue;
import android.view.Gravity;
import android.widget.FrameLayout;
@@ -27,6 +30,10 @@
public class SplitPlaceholderView extends FrameLayout {
+ private final Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
+
+ private FloatingTaskView.FullscreenDrawParams mFullscreenParams;
+
public static final FloatProperty<SplitPlaceholderView> ALPHA_FLOAT =
new FloatProperty<SplitPlaceholderView>("SplitViewAlpha") {
@Override
@@ -46,6 +53,17 @@
public SplitPlaceholderView(Context context, AttributeSet attrs) {
super(context, attrs);
+
+ mPaint.setColor(getThemePrimaryColor(context));
+ setWillNotDraw(false);
+ }
+
+ @Override
+ protected void dispatchDraw(Canvas canvas) {
+ // Call this before super call to draw below the children.
+ drawBackground(canvas);
+
+ super.dispatchDraw(canvas);
}
@Nullable
@@ -53,6 +71,10 @@
return mIconView;
}
+ public void setFullscreenParams(FloatingTaskView.FullscreenDrawParams fullscreenParams) {
+ mFullscreenParams = fullscreenParams;
+ }
+
public void setIcon(Drawable drawable, int iconSize) {
if (mIconView == null) {
mIconView = new IconView(getContext());
@@ -64,4 +86,20 @@
params.gravity = Gravity.CENTER;
mIconView.setLayoutParams(params);
}
+
+ private void drawBackground(Canvas canvas) {
+ if (mFullscreenParams == null) {
+ return;
+ }
+
+ canvas.drawRoundRect(0, 0, getMeasuredWidth(), getMeasuredHeight(),
+ mFullscreenParams.mCurrentDrawnCornerRadius / mFullscreenParams.mScaleX,
+ mFullscreenParams.mCurrentDrawnCornerRadius / mFullscreenParams.mScaleY, mPaint);
+ }
+
+ private static int getThemePrimaryColor(Context context) {
+ final TypedValue value = new TypedValue();
+ context.getTheme().resolveAttribute(android.R.attr.colorPrimary, value, true);
+ return value.data;
+ }
}
diff --git a/quickstep/src/com/android/quickstep/views/TaskView.java b/quickstep/src/com/android/quickstep/views/TaskView.java
index f716965..984b0ef 100644
--- a/quickstep/src/com/android/quickstep/views/TaskView.java
+++ b/quickstep/src/com/android/quickstep/views/TaskView.java
@@ -912,31 +912,31 @@
public void setOrientationState(RecentsOrientedState orientationState) {
PagedOrientationHandler orientationHandler = orientationState.getOrientationHandler();
boolean isRtl = getLayoutDirection() == LAYOUT_DIRECTION_RTL;
- LayoutParams snapshotParams = (LayoutParams) mSnapshotView.getLayoutParams();
DeviceProfile deviceProfile = mActivity.getDeviceProfile();
- snapshotParams.topMargin = deviceProfile.overviewTaskThumbnailTopMarginPx;
+
boolean isGridTask = isGridTask();
+ LayoutParams iconParams = (LayoutParams) mIconView.getLayoutParams();
+
+ int thumbnailTopMargin = deviceProfile.overviewTaskThumbnailTopMarginPx;
int taskIconHeight = deviceProfile.overviewTaskIconSizePx;
int taskMargin = isGridTask ? deviceProfile.overviewTaskMarginGridPx
: deviceProfile.overviewTaskMarginPx;
- int taskIconMargin = snapshotParams.topMargin - taskIconHeight - taskMargin;
- LayoutParams iconParams = (LayoutParams) mIconView.getLayoutParams();
- orientationHandler.setIconAndSnapshotParams(mIconView, taskIconMargin, taskIconHeight,
- snapshotParams, isRtl);
- updateDwbPlacement();
- mSnapshotView.setLayoutParams(snapshotParams);
+ int taskIconMargin = thumbnailTopMargin - taskIconHeight - taskMargin;
+ orientationHandler.setTaskIconParams(iconParams, taskIconMargin, taskIconHeight,
+ thumbnailTopMargin, isRtl);
iconParams.width = iconParams.height = taskIconHeight;
mIconView.setLayoutParams(iconParams);
+
mIconView.setRotation(orientationHandler.getDegreesRotated());
int iconDrawableSize = isGridTask ? deviceProfile.overviewTaskIconDrawableSizeGridPx
: deviceProfile.overviewTaskIconDrawableSizePx;
mIconView.setDrawableSize(iconDrawableSize, iconDrawableSize);
- snapshotParams.topMargin = deviceProfile.overviewTaskThumbnailTopMarginPx;
- mSnapshotView.setLayoutParams(snapshotParams);
- mSnapshotView.getTaskOverlay().updateOrientationState(orientationState);
- }
- private void updateDwbPlacement() {
+ LayoutParams snapshotParams = (LayoutParams) mSnapshotView.getLayoutParams();
+ snapshotParams.topMargin = thumbnailTopMargin;
+ mSnapshotView.setLayoutParams(snapshotParams);
+
+ mSnapshotView.getTaskOverlay().updateOrientationState(orientationState);
mDigitalWellBeingToast.initialize(mTask);
}
diff --git a/res/layout/floating_split_select_view.xml b/res/layout/floating_split_select_view.xml
index 8d47f4e..e4ca52e 100644
--- a/res/layout/floating_split_select_view.xml
+++ b/res/layout/floating_split_select_view.xml
@@ -4,7 +4,7 @@
android:layout_width="match_parent"
android:layout_height="match_parent">
- <ImageView
+ <com.android.quickstep.views.FloatingTaskThumbnailView
android:id="@+id/thumbnail"
android:layout_width="match_parent"
android:layout_height="match_parent"
@@ -14,7 +14,6 @@
android:id="@+id/split_placeholder"
android:layout_width="match_parent"
android:layout_height="@dimen/split_placeholder_size"
- android:background="?android:colorPrimary"
android:visibility="gone" />
</com.android.quickstep.views.FloatingTaskView>
\ No newline at end of file
diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java
index b3f5c03..df97d2f 100644
--- a/src/com/android/launcher3/Workspace.java
+++ b/src/com/android/launcher3/Workspace.java
@@ -2484,21 +2484,27 @@
}
}
+ // Note, centerX represents the center of the object that is being dragged, visually. d.x
+ // represents the location of the finger within the dragged item.
+ float touchX;
+ float touchY = d.y;
+
+ // Go through the pages and check if the dragged item is inside one of them. This block
+ // is responsible for determining whether we need to snap to a different screen.
int nextPage = getNextPage();
- IntSet pageIndexesToVerify = IntSet.wrap(nextPage - 1, nextPage + 1);
- if (isTwoPanelEnabled()) {
- // If two panel is enabled, users can also drag items to nextPage + 2
- pageIndexesToVerify.add(nextPage + 2);
- }
-
- int touchX = (int) Math.min(centerX, d.x);
- int touchY = d.y;
-
- // Go through the pages and check if the dragged item is inside one of them
+ IntSet pageIndexesToVerify = IntSet.wrap(nextPage - 1, nextPage
+ + (isTwoPanelEnabled() ? 2 : 1));
for (int pageIndex : pageIndexesToVerify) {
if (layout != null || isPageInTransition()) {
break;
}
+
+ // When deciding whether to perform a page switch, we need to consider the most extreme
+ // X coordinate between the finger location and the center of the object being dragged.
+ // This is either the max or the min of the two depending on whether dragging to the
+ // left / right, respectively.
+ touchX = ((((pageIndex < nextPage) && !mIsRtl) || pageIndex > nextPage && mIsRtl)
+ ? Math.min(d.x, centerX) : Math.max(d.x, centerX));
layout = verifyInsidePage(pageIndex, touchX, touchY);
}
@@ -2507,12 +2513,16 @@
// on one panel just choose the current page.
if (layout == null && nextPage >= 0 && nextPage < getPageCount()) {
if (isTwoPanelEnabled()) {
+ // When determining which panel to use within a single screen, we always use
+ // the centroid of the object rather than the finger.
+ touchX = centerX;
nextPage = getScreenCenter(getScrollX()) > touchX
? (mIsRtl ? nextPage + 1 : nextPage) // left side
: (mIsRtl ? nextPage : nextPage + 1); // right side
}
layout = (CellLayout) getChildAt(nextPage);
}
+
if (layout != mDragTargetLayout) {
setCurrentDropLayout(layout);
setCurrentDragOverlappingLayout(layout);
diff --git a/src/com/android/launcher3/config/FeatureFlags.java b/src/com/android/launcher3/config/FeatureFlags.java
index 8b2184d..993431e 100644
--- a/src/com/android/launcher3/config/FeatureFlags.java
+++ b/src/com/android/launcher3/config/FeatureFlags.java
@@ -246,6 +246,10 @@
"ENABLE_ALL_APPS_IN_TASKBAR", true,
"Enables accessing All Apps from the system Taskbar.");
+ public static final BooleanFlag ENABLE_ALL_APPS_ONE_SEARCH_IN_TASKBAR = getDebugFlag(
+ "ENABLE_ALL_APPS_ONE_SEARCH_IN_TASKBAR", false,
+ "Enables One Search box in Taskbar All Apps.");
+
public static final BooleanFlag ENABLE_SPLIT_FROM_WORKSPACE = getDebugFlag(
"ENABLE_SPLIT_FROM_WORKSPACE", true,
"Enable initiating split screen from workspace.");
diff --git a/src/com/android/launcher3/touch/LandscapePagedViewHandler.java b/src/com/android/launcher3/touch/LandscapePagedViewHandler.java
index 4a55d2e..2609e54 100644
--- a/src/com/android/launcher3/touch/LandscapePagedViewHandler.java
+++ b/src/com/android/launcher3/touch/LandscapePagedViewHandler.java
@@ -178,18 +178,6 @@
}
@Override
- public int getSplitTaskViewDismissDirection(@StagePosition int stagePosition,
- DeviceProfile dp) {
- // Don't use device profile here because we know we're in fake landscape, only split option
- // available is top/left
- if (stagePosition == STAGE_POSITION_TOP_OR_LEFT) {
- // Top (visually left) side
- return SPLIT_TRANSLATE_PRIMARY_NEGATIVE;
- }
- throw new IllegalStateException("Invalid split stage position: " + stagePosition);
- }
-
- @Override
public int getPrimaryScroll(View view) {
return view.getScrollY();
}
@@ -469,14 +457,12 @@
}
@Override
- public void setIconAndSnapshotParams(View iconView, int taskIconMargin, int taskIconHeight,
- FrameLayout.LayoutParams snapshotParams, boolean isRtl) {
- FrameLayout.LayoutParams iconParams =
- (FrameLayout.LayoutParams) iconView.getLayoutParams();
+ public void setTaskIconParams(FrameLayout.LayoutParams iconParams, int taskIconMargin,
+ int taskIconHeight, int thumbnailTopMargin, boolean isRtl) {
iconParams.gravity = (isRtl ? START : END) | CENTER_VERTICAL;
iconParams.rightMargin = -taskIconHeight - taskIconMargin / 2;
iconParams.leftMargin = 0;
- iconParams.topMargin = snapshotParams.topMargin / 2;
+ iconParams.topMargin = thumbnailTopMargin / 2;
}
@Override
diff --git a/src/com/android/launcher3/touch/PagedOrientationHandler.java b/src/com/android/launcher3/touch/PagedOrientationHandler.java
index 923dcc6..6e594e9 100644
--- a/src/com/android/launcher3/touch/PagedOrientationHandler.java
+++ b/src/com/android/launcher3/touch/PagedOrientationHandler.java
@@ -47,10 +47,6 @@
*/
public interface PagedOrientationHandler {
- int SPLIT_TRANSLATE_PRIMARY_POSITIVE = 0;
- int SPLIT_TRANSLATE_PRIMARY_NEGATIVE = 1;
- int SPLIT_TRANSLATE_SECONDARY_NEGATIVE = 2;
-
PagedOrientationHandler PORTRAIT = new PortraitPagedViewHandler();
PagedOrientationHandler LANDSCAPE = new LandscapePagedViewHandler();
PagedOrientationHandler SEASCAPE = new SeascapePagedViewHandler();
@@ -82,12 +78,6 @@
FloatProperty<View> getPrimaryViewTranslate();
FloatProperty<View> getSecondaryViewTranslate();
- /**
- * @param stagePosition The position where the view to be split will go
- * @return {@link #SPLIT_TRANSLATE_*} constants to indicate which direction the
- * dismissal should happen
- */
- int getSplitTaskViewDismissDirection(@StagePosition int stagePosition, DeviceProfile dp);
int getPrimaryScroll(View view);
float getPrimaryScale(View view);
int getChildStart(View view);
@@ -152,8 +142,8 @@
StagedSplitBounds splitBoundsConfig, DeviceProfile dp);
// Overview TaskMenuView methods
- void setIconAndSnapshotParams(View iconView, int taskIconMargin, int taskIconHeight,
- FrameLayout.LayoutParams snapshotParams, boolean isRtl);
+ void setTaskIconParams(FrameLayout.LayoutParams iconParams,
+ int taskIconMargin, int taskIconHeight, int thumbnailTopMargin, boolean isRtl);
void setSplitIconParams(View primaryIconView, View secondaryIconView,
int taskIconHeight, int primarySnapshotWidth, int primarySnapshotHeight,
boolean isRtl, DeviceProfile deviceProfile, StagedSplitBounds splitConfig);
diff --git a/src/com/android/launcher3/touch/PortraitPagedViewHandler.java b/src/com/android/launcher3/touch/PortraitPagedViewHandler.java
index 0d92e25..2c9afd6 100644
--- a/src/com/android/launcher3/touch/PortraitPagedViewHandler.java
+++ b/src/com/android/launcher3/touch/PortraitPagedViewHandler.java
@@ -180,24 +180,6 @@
}
@Override
- public int getSplitTaskViewDismissDirection(@StagePosition int stagePosition,
- DeviceProfile dp) {
- if (stagePosition == STAGE_POSITION_TOP_OR_LEFT) {
- if (dp.isLandscape) {
- // Left side
- return SPLIT_TRANSLATE_PRIMARY_NEGATIVE;
- } else {
- // Top side
- return SPLIT_TRANSLATE_SECONDARY_NEGATIVE;
- }
- } else if (stagePosition == STAGE_POSITION_BOTTOM_OR_RIGHT) {
- // We don't have a bottom option, so should be right
- return SPLIT_TRANSLATE_PRIMARY_POSITIVE;
- }
- throw new IllegalStateException("Invalid split stage position: " + stagePosition);
- }
-
- @Override
public int getPrimaryScroll(View view) {
return view.getScrollX();
}
@@ -567,10 +549,8 @@
}
@Override
- public void setIconAndSnapshotParams(View iconView, int taskIconMargin, int taskIconHeight,
- FrameLayout.LayoutParams snapshotParams, boolean isRtl) {
- FrameLayout.LayoutParams iconParams =
- (FrameLayout.LayoutParams) iconView.getLayoutParams();
+ public void setTaskIconParams(FrameLayout.LayoutParams iconParams, int taskIconMargin,
+ int taskIconHeight, int thumbnailTopMargin, boolean isRtl) {
iconParams.gravity = TOP | CENTER_HORIZONTAL;
iconParams.leftMargin = iconParams.rightMargin = 0;
iconParams.topMargin = taskIconMargin;
diff --git a/src/com/android/launcher3/touch/SeascapePagedViewHandler.java b/src/com/android/launcher3/touch/SeascapePagedViewHandler.java
index 69e19f4..9151796 100644
--- a/src/com/android/launcher3/touch/SeascapePagedViewHandler.java
+++ b/src/com/android/launcher3/touch/SeascapePagedViewHandler.java
@@ -23,7 +23,6 @@
import static com.android.launcher3.touch.SingleAxisSwipeDetector.HORIZONTAL;
import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_BOTTOM_OR_RIGHT;
-import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_TOP_OR_LEFT;
import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_TYPE_MAIN;
import android.content.res.Resources;
@@ -168,14 +167,12 @@
}
@Override
- public void setIconAndSnapshotParams(View mIconView, int taskIconMargin, int taskIconHeight,
- FrameLayout.LayoutParams snapshotParams, boolean isRtl) {
- FrameLayout.LayoutParams iconParams =
- (FrameLayout.LayoutParams) mIconView.getLayoutParams();
+ public void setTaskIconParams(FrameLayout.LayoutParams iconParams,
+ int taskIconMargin, int taskIconHeight, int thumbnailTopMargin, boolean isRtl) {
iconParams.gravity = (isRtl ? END : START) | CENTER_VERTICAL;
iconParams.leftMargin = -taskIconHeight - taskIconMargin / 2;
iconParams.rightMargin = 0;
- iconParams.topMargin = snapshotParams.topMargin / 2;
+ iconParams.topMargin = thumbnailTopMargin / 2;
}
@Override
diff --git a/tests/AndroidManifest-common.xml b/tests/AndroidManifest-common.xml
index e44c172..b4cd773 100644
--- a/tests/AndroidManifest-common.xml
+++ b/tests/AndroidManifest-common.xml
@@ -267,6 +267,15 @@
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity-alias>
+ <activity-alias android:name="Activity15" android:exported="true"
+ android:label="ThemeIconTestActivity"
+ android:icon="@drawable/test_theme_icon"
+ android:targetActivity="com.android.launcher3.testcomponent.OtherBaseTestingActivity">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity-alias>
<!-- [b/197780098] Disable eager initialization of Jetpack libraries. -->
<provider
diff --git a/tests/res/drawable/test_theme_icon.xml b/tests/res/drawable/test_theme_icon.xml
new file mode 100644
index 0000000..be5c4d9
--- /dev/null
+++ b/tests/res/drawable/test_theme_icon.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+Copyright (C) 2021 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.
+-->
+<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
+ <background android:drawable="@android:color/white"/>
+ <foreground>
+ <color android:color="#FFFF0000" />
+ </foreground>
+ <monochrome>
+ <vector android:width="48dp" android:height="48dp" android:viewportWidth="48.0" android:viewportHeight="48.0">
+ <path
+ android:fillColor="#FF000000"
+ android:pathData="M0,24L48,24 48,48, 0,48 Z"/>
+ </vector>
+ </monochrome>
+</adaptive-icon>
diff --git a/tests/src/com/android/launcher3/ui/workspace/ThemeIconsTest.java b/tests/src/com/android/launcher3/ui/workspace/ThemeIconsTest.java
new file mode 100644
index 0000000..e66810c
--- /dev/null
+++ b/tests/src/com/android/launcher3/ui/workspace/ThemeIconsTest.java
@@ -0,0 +1,128 @@
+/*
+ * Copyright (C) 2022 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.launcher3.ui.workspace;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import android.content.ContentProviderClient;
+import android.content.ContentResolver;
+import android.content.ContentValues;
+import android.net.Uri;
+import android.view.View;
+import android.view.ViewGroup;
+
+import androidx.test.filters.LargeTest;
+
+import com.android.launcher3.BubbleTextView;
+import com.android.launcher3.icons.ThemedIconDrawable;
+import com.android.launcher3.tapl.HomeAllApps;
+import com.android.launcher3.tapl.HomeAppIcon;
+import com.android.launcher3.ui.AbstractLauncherUiTest;
+import com.android.launcher3.ui.TaplTestsLauncher3;
+
+import org.junit.Test;
+
+import java.util.ArrayDeque;
+import java.util.Queue;
+
+/**
+ * Tests for theme icon support in Launcher
+ *
+ * Note running these tests will clear the workspace on the device.
+ */
+@LargeTest
+public class ThemeIconsTest extends AbstractLauncherUiTest {
+
+ private static final String APP_NAME = "ThemeIconTestActivity";
+
+ @Test
+ public void testIconWithoutTheme() throws Exception {
+ setThemeEnabled(false);
+ TaplTestsLauncher3.initialize(this);
+
+ HomeAllApps allApps = mLauncher.getWorkspace().switchToAllApps();
+ allApps.freeze();
+
+ try {
+ HomeAppIcon icon = allApps.getAppIcon(APP_NAME);
+ executeOnLauncher(l -> verifyIconTheme(l.getAppsView(), false));
+ icon.dragToWorkspace(false, false);
+ executeOnLauncher(l -> verifyIconTheme(l.getWorkspace(), false));
+ } finally {
+ allApps.unfreeze();
+ }
+ }
+
+ @Test
+ public void testIconWithTheme() throws Exception {
+ setThemeEnabled(true);
+ TaplTestsLauncher3.initialize(this);
+
+ HomeAllApps allApps = mLauncher.getWorkspace().switchToAllApps();
+ allApps.freeze();
+
+ try {
+ HomeAppIcon icon = allApps.getAppIcon(APP_NAME);
+ executeOnLauncher(l -> verifyIconTheme(l.getAppsView(), false));
+ icon.dragToWorkspace(false, false);
+ executeOnLauncher(l -> verifyIconTheme(l.getWorkspace(), true));
+ } finally {
+ allApps.unfreeze();
+ }
+ }
+
+ private void verifyIconTheme(ViewGroup parent, boolean isThemed) {
+ // Find the app icon
+ Queue<View> viewQueue = new ArrayDeque<>();
+ viewQueue.add(parent);
+ BubbleTextView icon = null;
+ while (!viewQueue.isEmpty()) {
+ View view = viewQueue.poll();
+ if (view instanceof ViewGroup) {
+ parent = (ViewGroup) view;
+ for (int i = parent.getChildCount() - 1; i >= 0; i--) {
+ viewQueue.add(parent.getChildAt(i));
+ }
+ } else if (view instanceof BubbleTextView) {
+ BubbleTextView btv = (BubbleTextView) view;
+ if (APP_NAME.equals(btv.getText())) {
+ icon = btv;
+ break;
+ }
+ }
+ }
+
+ assertNotNull(icon.getIcon());
+ assertEquals(isThemed, icon.getIcon() instanceof ThemedIconDrawable);
+ }
+
+ private void setThemeEnabled(boolean isEnabled) throws Exception {
+ Uri uri = new Uri.Builder()
+ .scheme(ContentResolver.SCHEME_CONTENT)
+ .authority(mTargetPackage + ".grid_control")
+ .appendPath("set_icon_themed")
+ .build();
+ ContentValues values = new ContentValues();
+ values.put("boolean_value", isEnabled);
+ try (ContentProviderClient client = mTargetContext.getContentResolver()
+ .acquireContentProviderClient(uri)) {
+ int result = client.update(uri, values, null);
+ assertTrue(result > 0);
+ }
+ }
+}