Snap for 11545716 from 60101ae7fc to 24Q3-release

Change-Id: Iac01a4f2a68a4125548bc9a463701f7e07b172c6
This commit is contained in:
Android Build Coastguard Worker
2024-03-08 00:20:58 +00:00
19 changed files with 303 additions and 242 deletions
+13 -5
View File
@@ -23,15 +23,23 @@ filegroup {
}
filegroup {
name: "launcher3-quickstep-robolectric-src",
path: "robolectric_tests",
srcs: ["robolectric_tests/src/**/*.java"],
name: "launcher3-quickstep-robo-src",
path: "tests/multivalentTests",
srcs: [
"tests/multivalentTests/src/**/*.java",
"tests/multivalentTests/src/**/*.kt",
],
}
filegroup {
name: "launcher3-quickstep-tests-src",
path: "tests",
srcs: ["tests/src/**/*.java", "tests/src/**/*.kt"],
srcs: [
"tests/multivalentTests/src/**/*.java",
"tests/multivalentTests/src/**/*.kt",
"tests/src/**/*.java",
"tests/src/**/*.kt",
],
}
filegroup {
@@ -44,5 +52,5 @@ filegroup {
"tests/src/com/android/quickstep/TaplOverviewIconTest.java",
"tests/src/com/android/quickstep/TaplTestsQuickstep.java",
"tests/src/com/android/quickstep/TaplTestsSplitscreen.java",
]
],
}
+3 -2
View File
@@ -41,9 +41,10 @@
<com.android.launcher3.taskbar.bubbles.BubbleBarView
android:id="@+id/taskbar_bubbles"
android:layout_width="wrap_content"
android:layout_height="@dimen/bubblebar_size"
android:layout_height="@dimen/bubblebar_size_with_pointer"
android:layout_gravity="bottom|end"
android:layout_marginEnd="@dimen/transient_taskbar_bottom_margin"
android:layout_marginHorizontal="@dimen/transient_taskbar_bottom_margin"
android:paddingTop="@dimen/bubblebar_pointer_size"
android:paddingEnd="@dimen/taskbar_icon_spacing"
android:paddingStart="@dimen/taskbar_icon_spacing"
android:visibility="gone"
+2
View File
@@ -413,6 +413,8 @@
<dimen name="bubblebar_stashed_size">@dimen/transient_taskbar_stashed_height</dimen>
<dimen name="bubblebar_stashed_handle_height">@dimen/taskbar_stashed_handle_height</dimen>
<dimen name="bubblebar_pointer_size">8dp</dimen>
<!-- Container size with pointer included: bubblebar_size + bubblebar_pointer_size -->
<dimen name="bubblebar_size_with_pointer">80dp</dimen>
<dimen name="bubblebar_elevation">1dp</dimen>
<dimen name="bubblebar_hotseat_adjustment_threshold">90dp</dimen>
@@ -19,6 +19,7 @@ import android.graphics.Canvas
import android.graphics.Color
import android.graphics.ColorFilter
import android.graphics.Paint
import android.graphics.PixelFormat
import android.graphics.drawable.Drawable
import android.graphics.drawable.ShapeDrawable
import com.android.app.animation.Interpolators
@@ -122,14 +123,22 @@ class BubbleBarBackground(context: TaskbarActivityContext, private val backgroun
// Draw background.
val radius = backgroundHeight / 2f
val left = if (anchorLeft) 0f else canvas.width.toFloat() - width
val right = if (anchorLeft) width else canvas.width.toFloat()
canvas.drawRoundRect(left, 0f, right, canvas.height.toFloat(), radius, radius, paint)
val left = if (anchorLeft) 0f else bounds.width().toFloat() - width
val right = if (anchorLeft) width else bounds.width().toFloat()
canvas.drawRoundRect(
left,
pointerSize,
right,
bounds.height().toFloat(),
radius,
radius,
paint
)
if (showingArrow) {
// Draw arrow.
val transX = arrowPositionX - pointerSize / 2f
canvas.translate(transX, -pointerSize)
canvas.translate(transX, 0f)
arrowDrawable.draw(canvas)
}
@@ -137,11 +146,20 @@ class BubbleBarBackground(context: TaskbarActivityContext, private val backgroun
}
override fun getOpacity(): Int {
return paint.alpha
return when (paint.alpha) {
255 -> PixelFormat.OPAQUE
0 -> PixelFormat.TRANSPARENT
else -> PixelFormat.TRANSLUCENT
}
}
override fun setAlpha(alpha: Int) {
paint.alpha = alpha
arrowDrawable.paint.alpha = alpha
}
override fun getAlpha(): Int {
return paint.alpha
}
override fun setColorFilter(colorFilter: ColorFilter?) {
@@ -73,6 +73,7 @@ import com.android.launcher3.util.Executors.SimpleThreadFactory;
import com.android.quickstep.SystemUiProxy;
import com.android.wm.shell.Flags;
import com.android.wm.shell.bubbles.IBubblesListener;
import com.android.wm.shell.common.bubbles.BubbleBarLocation;
import com.android.wm.shell.common.bubbles.BubbleBarUpdate;
import com.android.wm.shell.common.bubbles.BubbleInfo;
import com.android.wm.shell.common.bubbles.RemovedBubble;
@@ -155,12 +156,14 @@ public class BubbleBarController extends IBubblesListener.Stub {
* {@link BubbleBarBubble}s so that it can be used to update the views.
*/
private static class BubbleBarViewUpdate {
final boolean initialState;
boolean expandedChanged;
boolean expanded;
boolean shouldShowEducation;
String selectedBubbleKey;
String suppressedBubbleKey;
String unsuppressedBubbleKey;
BubbleBarLocation bubbleBarLocation;
List<RemovedBubble> removedBubbles;
List<String> bubbleKeysInOrder;
@@ -170,12 +173,14 @@ public class BubbleBarController extends IBubblesListener.Stub {
List<BubbleBarBubble> currentBubbles;
BubbleBarViewUpdate(BubbleBarUpdate update) {
initialState = update.initialState;
expandedChanged = update.expandedChanged;
expanded = update.expanded;
shouldShowEducation = update.shouldShowEducation;
selectedBubbleKey = update.selectedBubbleKey;
suppressedBubbleKey = update.suppressedBubbleKey;
unsuppressedBubbleKey = update.unsupressedBubbleKey;
bubbleBarLocation = update.bubbleBarLocation;
removedBubbles = update.removedBubbles;
bubbleKeysInOrder = update.bubbleKeysInOrder;
}
@@ -400,6 +405,14 @@ public class BubbleBarController extends IBubblesListener.Stub {
Log.w(TAG, "expansion was changed but is the same");
}
}
if (update.bubbleBarLocation != null) {
if (update.bubbleBarLocation != mBubbleBarViewController.getBubbleBarLocation()) {
// Animate when receiving updates. Skip it if we received the initial state.
boolean animate = !update.initialState;
mBubbleBarViewController.setBubbleBarLocation(update.bubbleBarLocation, animate);
mBubbleStashController.setBubbleBarLocation(update.bubbleBarLocation);
}
}
}
/** Tells WMShell to show the currently selected bubble. */
@@ -593,7 +606,7 @@ public class BubbleBarController extends IBubblesListener.Stub {
Rect location = new Rect();
// currentBarBounds is only useful for distance from left or right edge.
// It contains the current bounds, calculate the expanded bounds.
if (mBarView.isOnLeft()) {
if (mBarView.getBubbleBarLocation().isOnLeft(mBarView.isLayoutRtl())) {
location.left = currentBarBounds.left;
location.right = (int) (currentBarBounds.left + mBarView.expandedWidth());
} else {
@@ -601,7 +614,7 @@ public class BubbleBarController extends IBubblesListener.Stub {
location.right = currentBarBounds.right;
}
final int translation = (int) abs(mBubbleStashController.getBubbleBarTranslationY());
location.top = displaySize.y - mBarView.getHeight() - translation;
location.top = displaySize.y - currentBarBounds.height() - translation;
location.bottom = displaySize.y - translation;
return location;
}
@@ -15,21 +15,33 @@
*/
package com.android.launcher3.taskbar.bubbles;
import static com.android.app.animation.Interpolators.EMPHASIZED_ACCELERATE;
import static com.android.launcher3.LauncherAnimUtils.VIEW_TRANSLATE_X;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
import android.annotation.Nullable;
import android.content.Context;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.util.LayoutDirection;
import android.util.Log;
import android.view.Gravity;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.FrameLayout;
import androidx.dynamicanimation.animation.SpringForce;
import com.android.launcher3.R;
import com.android.launcher3.anim.SpringAnimationBuilder;
import com.android.launcher3.taskbar.TaskbarActivityContext;
import com.android.launcher3.views.ActivityContext;
import com.android.wm.shell.common.bubbles.BubbleBarLocation;
import java.util.List;
import java.util.function.Consumer;
@@ -70,6 +82,18 @@ public class BubbleBarView extends FrameLayout {
private static final int ARROW_POSITION_ANIMATION_DURATION_MS = 200;
private static final int WIDTH_ANIMATION_DURATION_MS = 200;
private static final long FADE_OUT_ANIM_ALPHA_DURATION_MS = 50L;
private static final long FADE_OUT_ANIM_ALPHA_DELAY_MS = 50L;
private static final long FADE_OUT_ANIM_POSITION_DURATION_MS = 100L;
// During fade out animation we shift the bubble bar 1/80th of the screen width
private static final float FADE_OUT_ANIM_POSITION_SHIFT = 1 / 80f;
private static final long FADE_IN_ANIM_ALPHA_DURATION_MS = 100L;
// Use STIFFNESS_MEDIUMLOW which is not defined in the API constants
private static final float FADE_IN_ANIM_POSITION_SPRING_STIFFNESS = 400f;
// During fade in animation we shift the bubble bar 1/60th of the screen width
private static final float FADE_IN_ANIM_POSITION_SHIFT = 1 / 60f;
private final BubbleBarBackground mBubbleBarBackground;
/**
@@ -86,11 +110,13 @@ public class BubbleBarView extends FrameLayout {
private final float mIconSize;
// The elevation of the bubbles within the bar
private final float mBubbleElevation;
private final int mPointerSize;
// Whether the bar is expanded (i.e. the bubble activity is being displayed).
private boolean mIsBarExpanded = false;
// The currently selected bubble view.
private BubbleView mSelectedBubbleView;
private BubbleBarLocation mBubbleBarLocation = BubbleBarLocation.DEFAULT;
// The click listener when the bubble bar is collapsed.
private View.OnClickListener mOnClickListener;
@@ -102,6 +128,9 @@ public class BubbleBarView extends FrameLayout {
// collapsed state and 1 to the fully expanded state.
private final ValueAnimator mWidthAnimator = ValueAnimator.ofFloat(0, 1);
@Nullable
private Animator mBubbleBarLocationAnimator = null;
// We don't reorder the bubbles when they are expanded as it could be jarring for the user
// this runnable will be populated with any reordering of the bubbles that should be applied
// once they are collapsed.
@@ -114,6 +143,8 @@ public class BubbleBarView extends FrameLayout {
@Nullable
private BubbleView mDraggedBubbleView;
private int mPreviousLayoutDirection = LayoutDirection.UNDEFINED;
public BubbleBarView(Context context) {
this(context, null);
}
@@ -136,6 +167,8 @@ public class BubbleBarView extends FrameLayout {
mIconSpacing = getResources().getDimensionPixelSize(R.dimen.bubblebar_icon_spacing);
mIconSize = getResources().getDimensionPixelSize(R.dimen.bubblebar_icon_size);
mBubbleElevation = getResources().getDimensionPixelSize(R.dimen.bubblebar_icon_elevation);
mPointerSize = getResources().getDimensionPixelSize(R.dimen.bubblebar_pointer_size);
setClipToPadding(false);
mBubbleBarBackground = new BubbleBarBackground(activityContext,
@@ -184,7 +217,7 @@ public class BubbleBarView extends FrameLayout {
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
mBubbleBarBounds.left = left;
mBubbleBarBounds.top = top;
mBubbleBarBounds.top = top + mPointerSize;
mBubbleBarBounds.right = right;
mBubbleBarBounds.bottom = bottom;
@@ -199,24 +232,123 @@ public class BubbleBarView extends FrameLayout {
@Override
public void onRtlPropertiesChanged(int layoutDirection) {
// TODO(b/313661121): set this based on bubble bar position and not LTR or RTL
boolean onLeft = layoutDirection == LAYOUT_DIRECTION_RTL;
if (mBubbleBarLocation == BubbleBarLocation.DEFAULT
&& mPreviousLayoutDirection != layoutDirection) {
Log.d(TAG, "BubbleBar RTL properties changed, new layoutDirection=" + layoutDirection
+ " previous layoutDirection=" + mPreviousLayoutDirection);
mPreviousLayoutDirection = layoutDirection;
onBubbleBarLocationChanged();
}
}
private void onBubbleBarLocationChanged() {
final boolean onLeft = mBubbleBarLocation.isOnLeft(isLayoutRtl());
mBubbleBarBackground.setAnchorLeft(onLeft);
mRelativePivotX = onLeft ? 0f : 1f;
ViewGroup.LayoutParams layoutParams = getLayoutParams();
if (layoutParams instanceof LayoutParams lp) {
lp.gravity = Gravity.BOTTOM | (onLeft ? Gravity.LEFT : Gravity.RIGHT);
setLayoutParams(lp);
}
invalidate();
}
/**
* @return <code>true</code> when bar is pinned to the left edge of the screen
* @return current {@link BubbleBarLocation}
*/
public boolean isOnLeft() {
return getLayoutDirection() == LAYOUT_DIRECTION_RTL;
public BubbleBarLocation getBubbleBarLocation() {
return mBubbleBarLocation;
}
/**
* Update {@link BubbleBarLocation}
*/
public void setBubbleBarLocation(BubbleBarLocation bubbleBarLocation, boolean animate) {
if (animate) {
animateToBubbleBarLocation(bubbleBarLocation);
} else {
setBubbleBarLocationInternal(bubbleBarLocation);
}
}
private void setBubbleBarLocationInternal(BubbleBarLocation bubbleBarLocation) {
if (bubbleBarLocation != mBubbleBarLocation) {
mBubbleBarLocation = bubbleBarLocation;
onBubbleBarLocationChanged();
invalidate();
}
}
private void animateToBubbleBarLocation(BubbleBarLocation bubbleBarLocation) {
if (bubbleBarLocation == mBubbleBarLocation) {
// nothing to do, already at expected location
return;
}
if (mBubbleBarLocationAnimator != null && mBubbleBarLocationAnimator.isRunning()) {
mBubbleBarLocationAnimator.cancel();
}
// Location animation uses two separate animators.
// First animator hides the bar.
// After it completes, location update is sent to layout the bar in the new location.
// Second animator is started to show the bar.
mBubbleBarLocationAnimator = getLocationUpdateFadeOutAnimator();
mBubbleBarLocationAnimator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
// Bubble bar is not visible, update the location
setBubbleBarLocationInternal(bubbleBarLocation);
// Animate it in
mBubbleBarLocationAnimator = getLocationUpdateFadeInAnimator();
mBubbleBarLocationAnimator.start();
}
});
mBubbleBarLocationAnimator.start();
}
private AnimatorSet getLocationUpdateFadeOutAnimator() {
final float shift =
getResources().getDisplayMetrics().widthPixels * FADE_OUT_ANIM_POSITION_SHIFT;
final float tx = mBubbleBarLocation.isOnLeft(isLayoutRtl()) ? shift : -shift;
ObjectAnimator positionAnim = ObjectAnimator.ofFloat(this, TRANSLATION_X, tx)
.setDuration(FADE_OUT_ANIM_POSITION_DURATION_MS);
positionAnim.setInterpolator(EMPHASIZED_ACCELERATE);
ObjectAnimator alphaAnim = ObjectAnimator.ofFloat(this, ALPHA, 0f)
.setDuration(FADE_OUT_ANIM_ALPHA_DURATION_MS);
alphaAnim.setStartDelay(FADE_OUT_ANIM_ALPHA_DELAY_MS);
AnimatorSet animatorSet = new AnimatorSet();
animatorSet.playTogether(positionAnim, alphaAnim);
return animatorSet;
}
private Animator getLocationUpdateFadeInAnimator() {
final float shift =
getResources().getDisplayMetrics().widthPixels * FADE_IN_ANIM_POSITION_SHIFT;
final float startTx = mBubbleBarLocation.isOnLeft(isLayoutRtl()) ? shift : -shift;
ValueAnimator positionAnim = new SpringAnimationBuilder(getContext())
.setStartValue(startTx)
.setEndValue(0)
.setDampingRatio(SpringForce.DAMPING_RATIO_LOW_BOUNCY)
.setStiffness(FADE_IN_ANIM_POSITION_SPRING_STIFFNESS)
.build(this, VIEW_TRANSLATE_X);
ObjectAnimator alphaAnim = ObjectAnimator.ofFloat(this, ALPHA, 1f)
.setDuration(FADE_IN_ANIM_ALPHA_DURATION_MS);
AnimatorSet animatorSet = new AnimatorSet();
animatorSet.playTogether(positionAnim, alphaAnim);
return animatorSet;
}
/**
* Updates the bounds with translation that may have been applied and returns the result.
*/
public Rect getBubbleBarBounds() {
mBubbleBarBounds.top = getTop() + (int) getTranslationY();
mBubbleBarBounds.top = getTop() + (int) getTranslationY() + mPointerSize;
mBubbleBarBounds.bottom = getBottom() + (int) getTranslationY();
return mBubbleBarBounds;
}
@@ -290,7 +422,7 @@ public class BubbleBarView extends FrameLayout {
int bubbleCount = getChildCount();
final float ty = (mBubbleBarBounds.height() - mIconSize) / 2f;
final boolean animate = getVisibility() == VISIBLE;
final boolean onLeft = isOnLeft();
final boolean onLeft = mBubbleBarLocation.isOnLeft(isLayoutRtl());
for (int i = 0; i < bubbleCount; i++) {
BubbleView bv = (BubbleView) getChildAt(i);
bv.setTranslationY(ty);
@@ -453,7 +585,7 @@ public class BubbleBarView extends FrameLayout {
private float arrowPositionForSelectedWhenExpanded() {
final int index = indexOfChild(mSelectedBubbleView);
final int bubblePosition;
if (isOnLeft()) {
if (mBubbleBarLocation.isOnLeft(isLayoutRtl())) {
// Bubble positions are reversed. First bubble is on the right.
bubblePosition = getChildCount() - index - 1;
} else {
@@ -465,7 +597,7 @@ public class BubbleBarView extends FrameLayout {
private float arrowPositionForSelectedWhenCollapsed() {
final int index = indexOfChild(mSelectedBubbleView);
final int bubblePosition;
if (isOnLeft()) {
if (mBubbleBarLocation.isOnLeft(isLayoutRtl())) {
// Bubble positions are reversed. First bubble may be shifted, if there are more
// bubbles than the current bubble and overflow.
bubblePosition = index == 0 && getChildCount() > 2 ? 1 : 0;
@@ -37,6 +37,7 @@ import com.android.launcher3.taskbar.TaskbarStashController;
import com.android.launcher3.util.MultiPropertyFactory;
import com.android.launcher3.util.MultiValueAlpha;
import com.android.quickstep.SystemUiProxy;
import com.android.wm.shell.common.bubbles.BubbleBarLocation;
import java.util.List;
import java.util.Objects;
@@ -54,6 +55,7 @@ public class BubbleBarViewController {
private final TaskbarActivityContext mActivity;
private final BubbleBarView mBarView;
private final int mIconSize;
private final int mPointerSize;
// Initialized in init.
private BubbleStashController mBubbleStashController;
@@ -86,6 +88,8 @@ public class BubbleBarViewController {
mBubbleBarAlpha = new MultiValueAlpha(mBarView, 1 /* num alpha channels */);
mBubbleBarAlpha.setUpdateVisibility(true);
mIconSize = activity.getResources().getDimensionPixelSize(R.dimen.bubblebar_icon_size);
mPointerSize = activity.getResources().getDimensionPixelSize(
R.dimen.bubblebar_pointer_size);
}
public void init(TaskbarControllers controllers, BubbleControllers bubbleControllers) {
@@ -96,9 +100,11 @@ public class BubbleBarViewController {
mTaskbarInsetsController = controllers.taskbarInsetsController;
mActivity.addOnDeviceProfileChangeListener(dp ->
mBarView.getLayoutParams().height = mActivity.getDeviceProfile().taskbarHeight
mBarView.getLayoutParams().height =
mActivity.getDeviceProfile().taskbarHeight + mPointerSize
);
mBarView.getLayoutParams().height = mActivity.getDeviceProfile().taskbarHeight;
mBarView.getLayoutParams().height =
mActivity.getDeviceProfile().taskbarHeight + mPointerSize;
mBubbleBarScale.updateValue(1f);
mBubbleClickListener = v -> onBubbleClicked(v);
mBubbleBarClickListener = v -> onBubbleBarClicked();
@@ -168,6 +174,20 @@ public class BubbleBarViewController {
return mBubbleBarController.getSelectedBubbleKey() != null;
}
/**
* @return current {@link BubbleBarLocation}
*/
public BubbleBarLocation getBubbleBarLocation() {
return mBarView.getBubbleBarLocation();
}
/**
* Update bar {@link BubbleBarLocation}
*/
public void setBubbleBarLocation(BubbleBarLocation bubbleBarLocation, boolean animate) {
mBarView.setBubbleBarLocation(bubbleBarLocation, animate);
}
/**
* The bounds of the bubble bar.
*/
@@ -31,6 +31,7 @@ import com.android.launcher3.taskbar.TaskbarControllers;
import com.android.launcher3.taskbar.TaskbarInsetsController;
import com.android.launcher3.taskbar.TaskbarStashController;
import com.android.launcher3.util.MultiPropertyFactory;
import com.android.wm.shell.common.bubbles.BubbleBarLocation;
/**
* Coordinates between controllers such as BubbleBarView and BubbleHandleViewController to
@@ -356,4 +357,9 @@ public class BubbleStashController {
public boolean isEventOverStashHandle(MotionEvent ev) {
return mHandleViewController.isEventOverHandle(ev);
}
/** Set a bubble bar location */
public void setBubbleBarLocation(BubbleBarLocation bubbleBarLocation) {
mHandleViewController.setBubbleBarLocation(bubbleBarLocation);
}
}
@@ -16,7 +16,6 @@
package com.android.launcher3.taskbar.bubbles;
import static android.view.View.INVISIBLE;
import static android.view.View.LAYOUT_DIRECTION_RTL;
import static android.view.View.VISIBLE;
import android.animation.Animator;
@@ -39,6 +38,7 @@ import com.android.launcher3.util.Executors;
import com.android.launcher3.util.MultiPropertyFactory;
import com.android.launcher3.util.MultiValueAlpha;
import com.android.systemui.shared.navigationbar.RegionSamplingHelper;
import com.android.wm.shell.common.bubbles.BubbleBarLocation;
/**
* Handles properties/data collection, then passes the results to our stashed handle View to render.
@@ -119,14 +119,14 @@ public class BubbleStashedHandleViewController {
}, Executors.UI_HELPER_EXECUTOR);
mStashedHandleView.addOnLayoutChangeListener((view, i, i1, i2, i3, i4, i5, i6, i7) ->
updateBounds());
updateBounds(mBarViewController.getBubbleBarLocation()));
}
private void updateBounds() {
private void updateBounds(BubbleBarLocation bubbleBarLocation) {
// As more bubbles get added, the icon bounds become larger. To ensure a consistent
// handle bar position, we pin it to the edge of the screen.
final int stashedCenterY = mStashedHandleView.getHeight() - mStashedTaskbarHeight / 2;
if (isOnLeft()) {
if (bubbleBarLocation.isOnLeft(mStashedHandleView.isLayoutRtl())) {
final int left = mBarViewController.getHorizontalMargin();
mStashedHandleBounds.set(
left,
@@ -149,11 +149,6 @@ public class BubbleStashedHandleViewController {
mStashedHandleView.setPivotY(mStashedHandleView.getHeight() - mStashedTaskbarHeight / 2f);
}
private boolean isOnLeft() {
// TODO(b/313661121): set this based on bubble bar position and not LTR or RTL
return mStashedHandleView.getLayoutDirection() == LAYOUT_DIRECTION_RTL;
}
public void onDestroy() {
mRegionSamplingHelper.stopAndDestroy();
mRegionSamplingHelper = null;
@@ -301,4 +296,9 @@ public class BubbleStashedHandleViewController {
public boolean containsX(int x) {
return x >= mStashedHandleBounds.left && x <= mStashedHandleBounds.right;
}
/** Set a bubble bar location */
public void setBubbleBarLocation(BubbleBarLocation bubbleBarLocation) {
updateBounds(bubbleBarLocation);
}
}
@@ -45,6 +45,7 @@ import com.android.launcher3.R;
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.logging.StatsLogManager.LauncherEvent;
import com.android.launcher3.model.WellbeingModel;
import com.android.launcher3.model.data.ItemInfoWithIcon;
import com.android.launcher3.popup.SystemShortcut;
import com.android.launcher3.popup.SystemShortcut.AppInfo;
import com.android.launcher3.util.InstantAppResolver;
@@ -61,6 +62,7 @@ import com.android.systemui.shared.recents.view.AppTransitionAnimationSpecsFutur
import com.android.systemui.shared.recents.view.RecentsTransition;
import com.android.systemui.shared.system.ActivityManagerWrapper;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.function.Function;
@@ -319,13 +321,18 @@ public interface TaskShortcutFactory {
recentsView.isTaskInExpectedScrollPosition(recentsView.indexOfChild(taskView));
boolean shouldShowActionsButtonInstead =
isLargeTileFocusedTask && isInExpectedScrollPosition;
boolean hasUnpinnableApp = Arrays.stream(taskView.getTaskIdAttributeContainers())
.anyMatch(att -> att != null && att.getItemInfo() != null
&& ((att.getItemInfo().runtimeStatusFlags
& ItemInfoWithIcon.FLAG_NOT_PINNABLE) != 0));
// No "save app pair" menu item if:
// - app pairs feature is not enabled
// - the task in question is a single task
// - at least one app in app pair is unpinnable
// - the Overview Actions Button should be visible
if (!FeatureFlags.enableAppPairs() || !taskView.containsMultipleTasks()
|| shouldShowActionsButtonInstead) {
|| hasUnpinnableApp || shouldShowActionsButtonInstead) {
return null;
}
@@ -29,6 +29,7 @@ import static com.android.launcher3.LauncherState.BACKGROUND_APP;
import static com.android.launcher3.Utilities.getDescendantCoordRelativeToAncestor;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TASK_ICON_TAP_OR_LONGPRESS;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TASK_LAUNCH_TAP;
import static com.android.launcher3.model.data.ItemInfoWithIcon.FLAG_NOT_PINNABLE;
import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_BOTTOM_OR_RIGHT;
@@ -83,6 +84,7 @@ import com.android.launcher3.R;
import com.android.launcher3.Utilities;
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.model.data.WorkspaceItemInfo;
import com.android.launcher3.pm.UserCache;
import com.android.launcher3.popup.SystemShortcut;
import com.android.launcher3.statemanager.StatefulActivity;
import com.android.launcher3.testing.TestLogging;
@@ -501,6 +503,11 @@ public class TaskView extends FrameLayout implements Reusable {
if (getRecentsView() != null) {
stubInfo.screenId = getRecentsView().indexOfChild(this);
}
if (Flags.privateSpaceRestrictAccessibilityDrag()) {
if (UserCache.getInstance(getContext()).getUserInfo(componentKey.user).isPrivate()) {
stubInfo.runtimeStatusFlags |= FLAG_NOT_PINNABLE;
}
}
return stubInfo;
}
@@ -0,0 +1,31 @@
/*
* Copyright (C) 2024 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.quickstep
import androidx.test.ext.junit.runners.AndroidJUnit4
import com.google.common.truth.Truth.assertThat
import org.junit.Test
import org.junit.runner.RunWith
@RunWith(AndroidJUnit4::class)
class RobolectricTest {
@Test
fun test1() {
val actual = 1 + 1
assertThat(actual).isEqualTo(2)
}
}
+1
View File
@@ -0,0 +1 @@
./multivalentTests
+1
View File
@@ -0,0 +1 @@
./multivalentTests
-60
View File
@@ -1,60 +0,0 @@
/*
* Copyright (C) 2024 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
import android.graphics.Rect
/**
* Fit [this] into [targetRect] with letter boxing. After calling this method, [this] will be
* modified to be letter boxed.
*
* @param targetRect target [Rect] that [this] should be fitted into
*/
fun Rect.letterBox(targetRect: Rect) {
letterBox(targetRect, this)
}
/**
* Fit [this] into [targetRect] with letter boxing. After calling this method, [resultRect] will be
* modified to be letter boxed.
*
* @param targetRect target [Rect] that [this] should be fitted into
* @param resultRect the letter boxed [Rect]
*/
fun Rect.letterBox(targetRect: Rect, resultRect: Rect) {
val widthRatio: Float = 1f * targetRect.width() / width()
val heightRatio: Float = 1f * targetRect.height() / height()
if (widthRatio < heightRatio) {
val scaledHeight: Int = (widthRatio * height()).toInt()
val verticalPadding: Int = (targetRect.height() - scaledHeight) / 2
resultRect.set(
targetRect.left,
targetRect.top + verticalPadding,
targetRect.right,
targetRect.bottom - verticalPadding
)
} else {
val scaledWidth: Int = (heightRatio * width()).toInt()
val horizontalPadding: Int = (targetRect.width() - scaledWidth) / 2
resultRect.set(
targetRect.left + horizontalPadding,
targetRect.top,
targetRect.right - horizontalPadding,
targetRect.bottom
)
}
}
@@ -73,7 +73,7 @@ public class WorkProfileManager extends UserProfileManager
* Posts quite mode enable/disable call for work profile user
*/
public void setWorkProfileEnabled(boolean enabled) {
setCurrentState(STATE_TRANSITION);
updateCurrentState(STATE_TRANSITION);
setQuietMode(!enabled);
}
@@ -29,9 +29,11 @@ import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.PorterDuff;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
@@ -53,7 +55,6 @@ import com.android.launcher3.DeviceProfile;
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherAppState;
import com.android.launcher3.R;
import com.android.launcher3.RectUtilsKt;
import com.android.launcher3.icons.FastBitmapDrawable;
import com.android.launcher3.icons.IconCache.ItemInfoUpdateReceiver;
import com.android.launcher3.model.data.ItemInfoWithIcon;
@@ -77,9 +78,9 @@ public class PendingAppWidgetHostView extends LauncherAppWidgetHostView
private final Rect mRect = new Rect();
private final Rect mPreviewBitmapRect = new Rect();
private final Rect mCanvasRect = new Rect();
private final Rect mLetterBoxedPreviewBitmapRect = new Rect();
private final Matrix mMatrix = new Matrix();
private final RectF mPreviewBitmapRect = new RectF();
private final RectF mCanvasRect = new RectF();
private final LauncherWidgetHolder mWidgetHolder;
private final LauncherAppWidgetProviderInfo mAppwidget;
@@ -458,9 +459,8 @@ public class PendingAppWidgetHostView extends LauncherAppWidgetHostView
mPreviewBitmapRect.set(0, 0, mPreviewBitmap.getWidth(), mPreviewBitmap.getHeight());
mCanvasRect.set(0, 0, getWidth(), getHeight());
RectUtilsKt.letterBox(mPreviewBitmapRect, mCanvasRect, mLetterBoxedPreviewBitmapRect);
canvas.drawBitmap(mPreviewBitmap, mPreviewBitmapRect, mLetterBoxedPreviewBitmapRect,
mPreviewPaint);
mMatrix.setRectToRect(mPreviewBitmapRect, mCanvasRect, Matrix.ScaleToFit.CENTER);
canvas.drawBitmap(mPreviewBitmap, mMatrix, mPreviewPaint);
return;
}
if (mCenterDrawable == null) {
+12
View File
@@ -18,6 +18,15 @@
<option name="test-suite-tag" value="apct" />
<option name="test-suite-tag" value="apct-instrumentation" />
<option name="max-tmp-logcat-file" value="104857600" /> <!-- 100 * 1024 * 1024 -->
<logger class="com.android.tradefed.log.FileLogger">
<option name="max-log-size" value="20" />
</logger>
<!-- Disables the "Ramdump uploader to betterbug" -->
<option name="post-boot-command" value="am broadcast --async --user 0 -a com.google.gservices.intent.action.GSERVICES_OVERRIDE -e betterbug_enable_ramdump_uploader false" />
<target_preparer class="com.android.tradefed.targetprep.DeviceSetup">
<option name="set-test-harness" value="true" />
@@ -34,6 +43,9 @@
<option name="run-command" value="settings delete secure assistant" />
<option name="run-command" value="settings put global airplane_mode_on 1" />
<option name="run-command" value="am broadcast -a android.intent.action.AIRPLANE_MODE" />
<option name="run-command" value="settings put system pointer_location 1" />
<option name="run-command" value="settings put system show_touches 1" />
</target_preparer>
<target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
@@ -1,138 +0,0 @@
/*
* Copyright (C) 2024 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
import android.graphics.Rect
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.google.common.truth.Truth.assertThat
import org.junit.Test
import org.junit.runner.RunWith
@SmallTest
@RunWith(AndroidJUnit4::class)
class RectUtilsTest {
private val srcRect = Rect()
private val destRect = Rect()
private val letterBoxedRect = Rect()
@Test
fun letterBoxSelf_toSameRect_noScale() {
srcRect.set(0, 0, 100, 100)
destRect.set(0, 0, 100, 100)
srcRect.letterBox(destRect)
assertThat(srcRect).isEqualTo(Rect(0, 0, 100, 100))
}
@Test
fun letterBox_toSameRect_noScale() {
srcRect.set(0, 0, 100, 100)
destRect.set(0, 0, 100, 100)
srcRect.letterBox(destRect, letterBoxedRect)
assertThat(letterBoxedRect).isEqualTo(Rect(0, 0, 100, 100))
assertThat(srcRect).isEqualTo(Rect(0, 0, 100, 100))
}
@Test
fun letterBoxSelf_toSmallHeight_scaleDownHorizontally() {
srcRect.set(0, 0, 2893, 2114)
destRect.set(0, 0, 939, 520)
srcRect.letterBox(destRect)
assertThat(srcRect).isEqualTo(Rect(114, 0, 825, 520))
}
@Test
fun letterBoxRect_toSmallHeight_scaleDownHorizontally() {
srcRect.set(0, 0, 2893, 2114)
destRect.set(0, 0, 939, 520)
srcRect.letterBox(destRect, letterBoxedRect)
assertThat(letterBoxedRect).isEqualTo(Rect(114, 0, 825, 520))
assertThat(srcRect).isEqualTo(Rect(0, 0, 2893, 2114))
}
@Test
fun letterBoxSelf_toSmallHeightWithOffset_scaleDownHorizontally() {
srcRect.set(0, 0, 2893, 2114)
destRect.set(10, 20, 949, 540)
srcRect.letterBox(destRect)
assertThat(srcRect).isEqualTo(Rect(124, 20, 835, 540))
}
@Test
fun letterBoxRect_toSmallHeightWithOffset_scaleDownHorizontally() {
srcRect.set(0, 0, 2893, 2114)
destRect.set(10, 20, 949, 540)
srcRect.letterBox(destRect, letterBoxedRect)
assertThat(letterBoxedRect).isEqualTo(Rect(124, 20, 835, 540))
assertThat(srcRect).isEqualTo(Rect(0, 0, 2893, 2114))
}
@Test
fun letterBoxSelf_toSmallWidth_scaleDownVertically() {
srcRect.set(0, 0, 2893, 2114)
destRect.set(0, 0, 520, 939)
srcRect.letterBox(destRect)
assertThat(srcRect).isEqualTo(Rect(0, 280, 520, 659))
}
@Test
fun letterBoxRect_toSmallWidth_scaleDownVertically() {
srcRect.set(0, 0, 2893, 2114)
destRect.set(0, 0, 520, 939)
srcRect.letterBox(destRect, letterBoxedRect)
assertThat(letterBoxedRect).isEqualTo(Rect(0, 280, 520, 659))
assertThat(srcRect).isEqualTo(Rect(0, 0, 2893, 2114))
}
@Test
fun letterBoxSelf_toSmallWidthWithOffset_scaleDownVertically() {
srcRect.set(0, 0, 2893, 2114)
destRect.set(40, 60, 560, 999)
srcRect.letterBox(destRect)
assertThat(srcRect).isEqualTo(Rect(40, 340, 560, 719))
}
@Test
fun letterBoxRect_toSmallWidthWithOffset_scaleDownVertically() {
srcRect.set(0, 0, 2893, 2114)
destRect.set(40, 60, 560, 999)
srcRect.letterBox(destRect, letterBoxedRect)
assertThat(letterBoxedRect).isEqualTo(Rect(40, 340, 560, 719))
assertThat(srcRect).isEqualTo(Rect(0, 0, 2893, 2114))
}
}