Snap for 9564855 from 8353c38f92 to udc-release
Change-Id: I06aaf52e6e207086fbd5ab1b0227b31ba32f67d5
This commit is contained in:
@@ -32,12 +32,10 @@
|
||||
android:layout_width="@dimen/taskbar_edu_features_lottie_width"
|
||||
android:layout_height="@dimen/taskbar_edu_features_lottie_height"
|
||||
android:layout_marginTop="@dimen/taskbar_edu_tooltip_vertical_margin"
|
||||
android:scaleType="centerCrop"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/title"
|
||||
app:lottie_autoPlay="true"
|
||||
app:lottie_loop="true"
|
||||
app:lottie_rawRes="@raw/taskbar_edu_splitscreen" />
|
||||
app:lottie_loop="true" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/splitscreen_text"
|
||||
@@ -61,7 +59,6 @@
|
||||
android:layout_height="@dimen/taskbar_edu_features_lottie_height"
|
||||
android:layout_marginStart="@dimen/taskbar_edu_features_horizontal_spacing"
|
||||
android:layout_marginTop="@dimen/taskbar_edu_tooltip_vertical_margin"
|
||||
android:scaleType="centerCrop"
|
||||
app:layout_constraintStart_toEndOf="@id/splitscreen_animation"
|
||||
app:layout_constraintTop_toBottomOf="@id/title"
|
||||
app:lottie_autoPlay="true"
|
||||
@@ -84,13 +81,11 @@
|
||||
android:layout_height="@dimen/taskbar_edu_features_lottie_height"
|
||||
android:layout_marginStart="@dimen/taskbar_edu_features_horizontal_spacing"
|
||||
android:layout_marginTop="@dimen/taskbar_edu_tooltip_vertical_margin"
|
||||
android:scaleType="centerCrop"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toEndOf="@id/settings_animation"
|
||||
app:layout_constraintTop_toBottomOf="@id/title"
|
||||
app:lottie_autoPlay="true"
|
||||
app:lottie_loop="true"
|
||||
app:lottie_rawRes="@raw/taskbar_edu_suggestions" />
|
||||
app:lottie_loop="true" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/suggestions_text"
|
||||
|
||||
@@ -31,7 +31,6 @@
|
||||
android:layout_width="@dimen/taskbar_edu_swipe_lottie_width"
|
||||
android:layout_height="@dimen/taskbar_edu_swipe_lottie_height"
|
||||
android:layout_marginTop="@dimen/taskbar_edu_tooltip_vertical_margin"
|
||||
android:scaleType="centerCrop"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -110,11 +110,22 @@ class TaskbarEduTooltipController(val activityContext: TaskbarActivityContext) :
|
||||
tooltipStep = TOOLTIP_STEP_NONE
|
||||
inflateTooltip(R.layout.taskbar_edu_features)
|
||||
tooltip?.run {
|
||||
findViewById<LottieAnimationView>(R.id.splitscreen_animation).supportLightTheme()
|
||||
findViewById<LottieAnimationView>(R.id.suggestions_animation).supportLightTheme()
|
||||
findViewById<LottieAnimationView>(R.id.settings_animation).supportLightTheme()
|
||||
findViewById<View>(R.id.settings_edu).visibility =
|
||||
if (DisplayController.isTransientTaskbar(activityContext)) GONE else VISIBLE
|
||||
val splitscreenAnim = findViewById<LottieAnimationView>(R.id.splitscreen_animation)
|
||||
val suggestionsAnim = findViewById<LottieAnimationView>(R.id.suggestions_animation)
|
||||
val settingsAnim = findViewById<LottieAnimationView>(R.id.settings_animation)
|
||||
val settingsEdu = findViewById<View>(R.id.settings_edu)
|
||||
splitscreenAnim.supportLightTheme()
|
||||
suggestionsAnim.supportLightTheme()
|
||||
settingsAnim.supportLightTheme()
|
||||
if (DisplayController.isTransientTaskbar(activityContext)) {
|
||||
splitscreenAnim.setAnimation(R.raw.taskbar_edu_splitscreen_transient)
|
||||
suggestionsAnim.setAnimation(R.raw.taskbar_edu_suggestions_transient)
|
||||
settingsEdu.visibility = GONE
|
||||
} else {
|
||||
splitscreenAnim.setAnimation(R.raw.taskbar_edu_splitscreen_persistent)
|
||||
suggestionsAnim.setAnimation(R.raw.taskbar_edu_suggestions_persistent)
|
||||
settingsEdu.visibility = VISIBLE
|
||||
}
|
||||
|
||||
findViewById<View>(R.id.done_button)?.setOnClickListener { hide() }
|
||||
if (DisplayController.isTransientTaskbar(activityContext)) {
|
||||
|
||||
@@ -596,6 +596,10 @@ public class TaskbarStashController implements TaskbarControllers.LoggableTaskba
|
||||
}
|
||||
}
|
||||
|
||||
if (DisplayController.isTransientTaskbar(mActivity)) {
|
||||
fullLengthAnimatorSet.play(mControllers.taskbarViewController
|
||||
.createRevealAnimToIsStashed(isStashed));
|
||||
}
|
||||
fullLengthAnimatorSet.play(mControllers.stashedHandleViewController
|
||||
.createRevealAnimToIsStashed(isStashed));
|
||||
// Return the stashed handle to its default scale in case it was changed as part of the
|
||||
|
||||
@@ -27,6 +27,8 @@ import static com.android.launcher3.taskbar.TaskbarManager.isPhoneMode;
|
||||
import static com.android.launcher3.touch.SingleAxisSwipeDetector.DIRECTION_NEGATIVE;
|
||||
import static com.android.launcher3.touch.SingleAxisSwipeDetector.VERTICAL;
|
||||
|
||||
import android.animation.AnimatorSet;
|
||||
import android.animation.ValueAnimator;
|
||||
import android.annotation.NonNull;
|
||||
import android.graphics.Rect;
|
||||
import android.util.FloatProperty;
|
||||
@@ -49,6 +51,8 @@ import com.android.launcher3.anim.AnimatedFloat;
|
||||
import com.android.launcher3.anim.AnimatorPlaybackController;
|
||||
import com.android.launcher3.anim.Interpolators;
|
||||
import com.android.launcher3.anim.PendingAnimation;
|
||||
import com.android.launcher3.anim.RevealOutlineAnimation;
|
||||
import com.android.launcher3.anim.RoundedRectRevealOutlineProvider;
|
||||
import com.android.launcher3.config.FeatureFlags;
|
||||
import com.android.launcher3.folder.FolderIcon;
|
||||
import com.android.launcher3.icons.ThemedIconDrawable;
|
||||
@@ -95,6 +99,7 @@ public class TaskbarViewController implements TaskbarControllers.LoggableTaskbar
|
||||
private float mTaskbarIconTranslationYForSwipe;
|
||||
|
||||
private final int mTaskbarBottomMargin;
|
||||
private final int mStashedHandleHeight;
|
||||
|
||||
private final AnimatedFloat mThemeIconsBackground = new AnimatedFloat(
|
||||
this::updateIconsBackground);
|
||||
@@ -127,6 +132,8 @@ public class TaskbarViewController implements TaskbarControllers.LoggableTaskbar
|
||||
mTaskbarBottomMargin = DisplayController.isTransientTaskbar(activity)
|
||||
? activity.getResources().getDimensionPixelSize(R.dimen.transient_taskbar_margin)
|
||||
: 0;
|
||||
mStashedHandleHeight = activity.getResources()
|
||||
.getDimensionPixelSize(R.dimen.taskbar_stashed_handle_height);
|
||||
|
||||
if (DisplayController.isTransientTaskbar(mActivity)) {
|
||||
mSwipeDownDetector = new SingleAxisSwipeDetector(activity,
|
||||
@@ -280,6 +287,40 @@ public class TaskbarViewController implements TaskbarControllers.LoggableTaskbar
|
||||
));
|
||||
}
|
||||
|
||||
private ValueAnimator createRevealAnimForView(View view, boolean isStashed) {
|
||||
Rect viewBounds = new Rect(0, 0, view.getWidth(), view.getHeight());
|
||||
int centerY = viewBounds.centerY();
|
||||
int halfHandleHeight = mStashedHandleHeight / 2;
|
||||
|
||||
Rect stashedRect = new Rect(viewBounds.left,
|
||||
centerY - halfHandleHeight,
|
||||
viewBounds.right,
|
||||
centerY + halfHandleHeight);
|
||||
|
||||
float radius = 0;
|
||||
float stashedRadius = viewBounds.width() / 2f;
|
||||
|
||||
return new RoundedRectRevealOutlineProvider(radius, stashedRadius, viewBounds, stashedRect)
|
||||
.createRevealAnimator(view, !isStashed, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates and returns a {@link RevealOutlineAnimation} Animator that updates the icon shape
|
||||
* and size.
|
||||
* @param isStashed When true, the icon crops vertically to the size of the stashed handle.
|
||||
* When false, the reverse happens.
|
||||
*/
|
||||
public AnimatorSet createRevealAnimToIsStashed(boolean isStashed) {
|
||||
AnimatorSet as = new AnimatorSet();
|
||||
for (int i = mTaskbarView.getChildCount() - 1; i >= 0; i--) {
|
||||
View child = mTaskbarView.getChildAt(i);
|
||||
if (child instanceof BubbleTextView) {
|
||||
as.play(createRevealAnimForView(child, isStashed));
|
||||
}
|
||||
}
|
||||
return as;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the taskbar icon alignment relative to Launcher hotseat icons
|
||||
* @param alignmentRatio [0, 1]
|
||||
|
||||
@@ -1597,7 +1597,7 @@ public abstract class AbsSwipeUpHandler<T extends StatefulActivity<S>,
|
||||
final SwipePipToHomeAnimator.Builder builder = new SwipePipToHomeAnimator.Builder()
|
||||
.setContext(mContext)
|
||||
.setTaskId(runningTaskTarget.taskId)
|
||||
.setComponentName(taskInfo.topActivity)
|
||||
.setActivityInfo(taskInfo.topActivityInfo)
|
||||
.setLeash(runningTaskTarget.leash)
|
||||
.setSourceRectHint(
|
||||
runningTaskTarget.taskInfo.pictureInPictureParams.getSourceRectHint())
|
||||
|
||||
@@ -22,9 +22,11 @@ import android.animation.Animator;
|
||||
import android.animation.RectEvaluator;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.pm.ActivityInfo;
|
||||
import android.graphics.Matrix;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.RectF;
|
||||
import android.os.SystemProperties;
|
||||
import android.util.Log;
|
||||
import android.view.Surface;
|
||||
import android.view.SurfaceControl;
|
||||
@@ -50,7 +52,7 @@ public class SwipePipToHomeAnimator extends RectFSpringAnim {
|
||||
private static final float END_PROGRESS = 1.0f;
|
||||
|
||||
private final int mTaskId;
|
||||
private final ComponentName mComponentName;
|
||||
private final ActivityInfo mActivityInfo;
|
||||
private final SurfaceControl mLeash;
|
||||
private final Rect mSourceRectHint = new Rect();
|
||||
private final Rect mAppBounds = new Rect();
|
||||
@@ -80,15 +82,16 @@ public class SwipePipToHomeAnimator extends RectFSpringAnim {
|
||||
private boolean mHasAnimationEnded;
|
||||
|
||||
/**
|
||||
* An overlay used to mask changes in content when entering PiP for apps that aren't seamless.
|
||||
* Wrapper of {@link SurfaceControl} that is used when entering PiP without valid
|
||||
* source rect hint.
|
||||
*/
|
||||
@Nullable
|
||||
private SurfaceControl mContentOverlay;
|
||||
private PipContentOverlay mPipContentOverlay;
|
||||
|
||||
/**
|
||||
* @param context {@link Context} provides Launcher resources
|
||||
* @param taskId Task id associated with this animator, see also {@link #getTaskId()}
|
||||
* @param componentName Component associated with this animator,
|
||||
* @param activityInfo {@link ActivityInfo} associated with this animator,
|
||||
* see also {@link #getComponentName()}
|
||||
* @param leash {@link SurfaceControl} this animator operates on
|
||||
* @param sourceRectHint See the definition in {@link android.app.PictureInPictureParams}
|
||||
@@ -106,7 +109,7 @@ public class SwipePipToHomeAnimator extends RectFSpringAnim {
|
||||
*/
|
||||
private SwipePipToHomeAnimator(@NonNull Context context,
|
||||
int taskId,
|
||||
@NonNull ComponentName componentName,
|
||||
@NonNull ActivityInfo activityInfo,
|
||||
@NonNull SurfaceControl leash,
|
||||
@Nullable Rect sourceRectHint,
|
||||
@NonNull Rect appBounds,
|
||||
@@ -120,7 +123,7 @@ public class SwipePipToHomeAnimator extends RectFSpringAnim {
|
||||
@NonNull View view) {
|
||||
super(startBounds, new RectF(destinationBoundsTransformed), context, null);
|
||||
mTaskId = taskId;
|
||||
mComponentName = componentName;
|
||||
mActivityInfo = activityInfo;
|
||||
mLeash = leash;
|
||||
mAppBounds.set(appBounds);
|
||||
mHomeToWindowPositionMap.set(homeToWindowPositionMap);
|
||||
@@ -146,15 +149,15 @@ public class SwipePipToHomeAnimator extends RectFSpringAnim {
|
||||
// Create a new overlay layer. We do not call detach on this instance, it's propagated
|
||||
// to other classes like PipTaskOrganizer / RecentsAnimationController to complete
|
||||
// the cleanup.
|
||||
final PipContentOverlay.PipColorOverlay overlay =
|
||||
new PipContentOverlay.PipColorOverlay(view.getContext());
|
||||
if (SystemProperties.getBoolean(
|
||||
"persist.wm.debug.enable_pip_app_icon_overlay", false)) {
|
||||
mPipContentOverlay = new PipContentOverlay.PipAppIconOverlay(view.getContext(),
|
||||
mAppBounds, mActivityInfo);
|
||||
} else {
|
||||
mPipContentOverlay = new PipContentOverlay.PipColorOverlay(view.getContext());
|
||||
}
|
||||
final SurfaceControl.Transaction tx = new SurfaceControl.Transaction();
|
||||
mContentOverlay = overlay.getLeash();
|
||||
overlay.attach(tx, mLeash);
|
||||
addOnUpdateListener((currentRect, progress) -> {
|
||||
overlay.onAnimationUpdate(tx, progress);
|
||||
tx.apply();
|
||||
});
|
||||
mPipContentOverlay.attach(tx, mLeash);
|
||||
} else {
|
||||
mSourceRectHint.set(sourceRectHint);
|
||||
mSourceHintRectInsets = new Rect(sourceRectHint.left - appBounds.left,
|
||||
@@ -203,6 +206,9 @@ public class SwipePipToHomeAnimator extends RectFSpringAnim {
|
||||
private PictureInPictureSurfaceTransaction onAnimationUpdate(SurfaceControl.Transaction tx,
|
||||
RectF currentRect, float progress) {
|
||||
currentRect.round(mCurrentBounds);
|
||||
if (mPipContentOverlay != null) {
|
||||
mPipContentOverlay.onAnimationUpdate(tx, mCurrentBounds, progress);
|
||||
}
|
||||
final PictureInPictureSurfaceTransaction op;
|
||||
if (mSourceHintRectInsets == null) {
|
||||
// no source rect hint been set, directly scale the window down
|
||||
@@ -247,7 +253,7 @@ public class SwipePipToHomeAnimator extends RectFSpringAnim {
|
||||
}
|
||||
|
||||
public ComponentName getComponentName() {
|
||||
return mComponentName;
|
||||
return mActivityInfo.getComponentName();
|
||||
}
|
||||
|
||||
public Rect getDestinationBounds() {
|
||||
@@ -256,7 +262,7 @@ public class SwipePipToHomeAnimator extends RectFSpringAnim {
|
||||
|
||||
@Nullable
|
||||
public SurfaceControl getContentOverlay() {
|
||||
return mContentOverlay;
|
||||
return mPipContentOverlay == null ? null : mPipContentOverlay.getLeash();
|
||||
}
|
||||
|
||||
/** @return {@link PictureInPictureSurfaceTransaction} for the final leash transaction. */
|
||||
@@ -309,7 +315,7 @@ public class SwipePipToHomeAnimator extends RectFSpringAnim {
|
||||
public static class Builder {
|
||||
private Context mContext;
|
||||
private int mTaskId;
|
||||
private ComponentName mComponentName;
|
||||
private ActivityInfo mActivityInfo;
|
||||
private SurfaceControl mLeash;
|
||||
private Rect mSourceRectHint;
|
||||
private Rect mDisplayCutoutInsets;
|
||||
@@ -333,8 +339,8 @@ public class SwipePipToHomeAnimator extends RectFSpringAnim {
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setComponentName(ComponentName componentName) {
|
||||
mComponentName = componentName;
|
||||
public Builder setActivityInfo(ActivityInfo activityInfo) {
|
||||
mActivityInfo = activityInfo;
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -418,7 +424,7 @@ public class SwipePipToHomeAnimator extends RectFSpringAnim {
|
||||
mAppBounds.inset(mDisplayCutoutInsets);
|
||||
}
|
||||
}
|
||||
return new SwipePipToHomeAnimator(mContext, mTaskId, mComponentName, mLeash,
|
||||
return new SwipePipToHomeAnimator(mContext, mTaskId, mActivityInfo, mLeash,
|
||||
mSourceRectHint, mAppBounds,
|
||||
mHomeToWindowPositionMap, mStartBounds, mDestinationBounds,
|
||||
mFromRotation, mDestinationBoundsTransformed,
|
||||
|
||||
@@ -477,7 +477,7 @@ public class ActivityAllAppsContainerView<T extends Context & ActivityContext>
|
||||
}
|
||||
setupHeader();
|
||||
|
||||
if (FeatureFlags.ENABLE_FLOATING_SEARCH_BAR.get()) {
|
||||
if (isSearchBarOnBottom()) {
|
||||
// Keep the scroller above the search bar.
|
||||
RelativeLayout.LayoutParams scrollerLayoutParams =
|
||||
(LayoutParams) findViewById(R.id.fast_scroller).getLayoutParams();
|
||||
@@ -536,7 +536,7 @@ public class ActivityAllAppsContainerView<T extends Context & ActivityContext>
|
||||
removeCustomRules(getSearchRecyclerView());
|
||||
if (!isSearchSupported()) {
|
||||
layoutWithoutSearchContainer(rvContainer, showTabs);
|
||||
} else if (FeatureFlags.ENABLE_FLOATING_SEARCH_BAR.get()) {
|
||||
} else if (isSearchBarOnBottom()) {
|
||||
alignParentTop(rvContainer, showTabs);
|
||||
alignParentTop(getSearchRecyclerView(), /* tabs= */ false);
|
||||
layoutAboveSearchContainer(rvContainer);
|
||||
@@ -571,7 +571,7 @@ public class ActivityAllAppsContainerView<T extends Context & ActivityContext>
|
||||
removeCustomRules(mHeader);
|
||||
if (!isSearchSupported()) {
|
||||
layoutWithoutSearchContainer(mHeader, false /* includeTabsMargin */);
|
||||
} else if (FeatureFlags.ENABLE_FLOATING_SEARCH_BAR.get()) {
|
||||
} else if (isSearchBarOnBottom()) {
|
||||
alignParentTop(mHeader, false /* includeTabsMargin */);
|
||||
} else {
|
||||
layoutBelowSearchContainer(mHeader, false /* includeTabsMargin */);
|
||||
@@ -610,6 +610,13 @@ public class ActivityAllAppsContainerView<T extends Context & ActivityContext>
|
||||
(int) (mSearchContainer.getAlpha() * 255));
|
||||
}
|
||||
|
||||
/** @return true if the search bar is at the bottom of the container (as opposed to the top). */
|
||||
private boolean isSearchBarOnBottom() {
|
||||
return FeatureFlags.ENABLE_FLOATING_SEARCH_BAR.get()
|
||||
&& ((RelativeLayout.LayoutParams) mSearchContainer.getLayoutParams()).getRule(
|
||||
ALIGN_PARENT_BOTTOM) == RelativeLayout.TRUE;
|
||||
}
|
||||
|
||||
private void layoutBelowSearchContainer(View v, boolean includeTabsMargin) {
|
||||
if (!(v.getLayoutParams() instanceof RelativeLayout.LayoutParams)) {
|
||||
return;
|
||||
@@ -908,7 +915,7 @@ public class ActivityAllAppsContainerView<T extends Context & ActivityContext>
|
||||
setPadding(grid.workspacePadding.left, 0, grid.workspacePadding.right, 0);
|
||||
} else {
|
||||
int topPadding = grid.allAppsTopPadding;
|
||||
if (FeatureFlags.ENABLE_FLOATING_SEARCH_BAR.get() && !grid.isTablet) {
|
||||
if (isSearchBarOnBottom() && !grid.isTablet) {
|
||||
topPadding += getResources().getDimensionPixelSize(
|
||||
R.dimen.all_apps_additional_top_padding_floating_search);
|
||||
}
|
||||
@@ -1109,7 +1116,7 @@ public class ActivityAllAppsContainerView<T extends Context & ActivityContext>
|
||||
FloatingHeaderView headerView = getFloatingHeaderView();
|
||||
if (isTablet) {
|
||||
// Start adding header protection if search bar or tabs will attach to the top.
|
||||
if (!FeatureFlags.ENABLE_FLOATING_SEARCH_BAR.get() || mUsingTabs) {
|
||||
if (!isSearchBarOnBottom() || mUsingTabs) {
|
||||
View panel = (View) mBottomSheetBackground;
|
||||
float translationY = ((View) panel.getParent()).getTranslationY();
|
||||
mTmpRectF.set(panel.getLeft(), panel.getTop() + translationY, panel.getRight(),
|
||||
@@ -1151,7 +1158,7 @@ public class ActivityAllAppsContainerView<T extends Context & ActivityContext>
|
||||
/** Returns the position of the bottom edge of the header */
|
||||
public int getHeaderBottom() {
|
||||
int bottom = (int) getTranslationY() + mHeader.getClipTop();
|
||||
if (FeatureFlags.ENABLE_FLOATING_SEARCH_BAR.get()) {
|
||||
if (isSearchBarOnBottom()) {
|
||||
if (mActivityContext.getDeviceProfile().isTablet) {
|
||||
return bottom + mBottomSheetBackground.getTop();
|
||||
}
|
||||
|
||||
@@ -86,7 +86,7 @@ public final class FeatureFlags {
|
||||
"ENABLE_DEVICE_SEARCH", true, "Allows on device search in all apps");
|
||||
|
||||
public static final BooleanFlag ENABLE_FLOATING_SEARCH_BAR =
|
||||
getDebugFlag("ENABLE_FLOATING_SEARCH_BAR", false,
|
||||
new DeviceFlag("ENABLE_FLOATING_SEARCH_BAR", true,
|
||||
"Keep All Apps search bar at the bottom (but above keyboard if open)");
|
||||
|
||||
public static final BooleanFlag ENABLE_HIDE_HEADER = new DeviceFlag("ENABLE_HIDE_HEADER",
|
||||
@@ -309,9 +309,6 @@ public final class FeatureFlags {
|
||||
"FOLDABLE_WORKSPACE_REORDER", false,
|
||||
"In foldables, when reordering the icons and widgets, is now going to use both sides");
|
||||
|
||||
public static final BooleanFlag ENABLE_QUICK_LAUNCH_V3 = new DeviceFlag(
|
||||
"ENABLE_QUICK_LAUNCH_V3", false, "Quick Launch V3");
|
||||
|
||||
public static final BooleanFlag ENABLE_WIDGET_PICKER_DEPTH = new DeviceFlag(
|
||||
"ENABLE_WIDGET_PICKER_DEPTH", true, "Enable changing depth in widget picker.");
|
||||
|
||||
|
||||
@@ -232,6 +232,13 @@ public class TestInformationHandler implements ResourceBasedOverride {
|
||||
l -> l.getAppsView().getActiveRecyclerView().getClipBounds().top);
|
||||
}
|
||||
|
||||
case TestProtocol.REQUEST_ALL_APPS_BOTTOM_PADDING: {
|
||||
return getLauncherUIProperty(Bundle::putInt,
|
||||
l -> l.getAppsView().getBottom()
|
||||
- l.getAppsView().getActiveRecyclerView().getBottom()
|
||||
+ l.getAppsView().getActiveRecyclerView().getPaddingBottom());
|
||||
}
|
||||
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -120,6 +120,7 @@ public final class TestProtocol {
|
||||
public static final String REQUEST_TASKBAR_ALL_APPS_TOP_PADDING =
|
||||
"taskbar-all-apps-top-padding";
|
||||
public static final String REQUEST_ALL_APPS_TOP_PADDING = "all-apps-top-padding";
|
||||
public static final String REQUEST_ALL_APPS_BOTTOM_PADDING = "all-apps-bottom-padding";
|
||||
|
||||
public static final String REQUEST_WORKSPACE_CELL_LAYOUT_SIZE = "workspace-cell-layout-size";
|
||||
public static final String REQUEST_WORKSPACE_CELL_CENTER = "workspace-cell-center";
|
||||
|
||||
@@ -170,9 +170,9 @@ public class TaplTestsLauncher3 extends AbstractLauncherUiTest {
|
||||
flingBackwardY < flingForwardY));
|
||||
|
||||
// Test scrolling down to YouTube.
|
||||
assertNotNull("All apps: can't fine YouTube", allApps.getAppIcon("YouTube"));
|
||||
assertNotNull("All apps: can't find YouTube", allApps.getAppIcon("YouTube"));
|
||||
// Test scrolling up to Camera.
|
||||
assertNotNull("All apps: can't fine Camera", allApps.getAppIcon("Camera"));
|
||||
assertNotNull("All apps: can't find Camera", allApps.getAppIcon("Camera"));
|
||||
// Test failing to find a non-existing app.
|
||||
final AllApps allAppsFinal = allApps;
|
||||
expectFail("All apps: could find a non-existing app",
|
||||
@@ -264,8 +264,7 @@ public class TaplTestsLauncher3 extends AbstractLauncherUiTest {
|
||||
assertNotNull("AppIcon.launch returned null", app.launch(getAppPackageName()));
|
||||
test.executeOnLauncher(launcher -> assertTrue(
|
||||
"Launcher activity is the top activity; expecting another activity to be the "
|
||||
+ "top "
|
||||
+ "one",
|
||||
+ "top one",
|
||||
test.isInLaunchedApp(launcher)));
|
||||
} finally {
|
||||
allApps.unfreeze();
|
||||
|
||||
@@ -34,6 +34,9 @@ import androidx.test.uiautomator.UiObject2;
|
||||
|
||||
import com.android.launcher3.testing.shared.TestProtocol;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
@@ -102,10 +105,10 @@ public abstract class AllApps extends LauncherInstrumentation.VisibleContainer {
|
||||
iconCenter.x, iconCenter.y);
|
||||
}
|
||||
|
||||
private boolean iconCenterInRecyclerTopPadding(UiObject2 appListRecycler, UiObject2 icon) {
|
||||
private boolean iconCenterInRecyclerTopPadding(UiObject2 appsListRecycler, UiObject2 icon) {
|
||||
final Point iconCenter = icon.getVisibleCenter();
|
||||
|
||||
return iconCenter.y <= mLauncher.getVisibleBounds(appListRecycler).top
|
||||
return iconCenter.y <= mLauncher.getVisibleBounds(appsListRecycler).top
|
||||
+ getAppsListRecyclerTopPadding();
|
||||
}
|
||||
|
||||
@@ -137,15 +140,11 @@ public abstract class AllApps extends LauncherInstrumentation.VisibleContainer {
|
||||
bottomGestureStartOnScreen)) {
|
||||
mLauncher.scrollToLastVisibleRow(
|
||||
allAppsContainer,
|
||||
mLauncher.getObjectsInContainer(allAppsContainer, "icon")
|
||||
.stream()
|
||||
.filter(icon ->
|
||||
mLauncher.getVisibleBounds(icon).top
|
||||
< bottomGestureStartOnScreen)
|
||||
.collect(Collectors.toList()),
|
||||
getBottomVisibleIconBounds(allAppsContainer),
|
||||
mLauncher.getVisibleBounds(appListRecycler).top
|
||||
+ getAppsListRecyclerTopPadding()
|
||||
- mLauncher.getVisibleBounds(allAppsContainer).top);
|
||||
- mLauncher.getVisibleBounds(allAppsContainer).top,
|
||||
getAppsListRecyclerBottomPadding());
|
||||
verifyActiveContainer();
|
||||
final int newScroll = getAllAppsScroll();
|
||||
mLauncher.assertTrue(
|
||||
@@ -175,6 +174,28 @@ public abstract class AllApps extends LauncherInstrumentation.VisibleContainer {
|
||||
}
|
||||
}
|
||||
|
||||
/** @return visible bounds of the top-most visible icon in the container. */
|
||||
protected Rect getTopVisibleIconBounds(UiObject2 allAppsContainer) {
|
||||
return mLauncher.getVisibleBounds(Collections.min(getVisibleIcons(allAppsContainer),
|
||||
Comparator.comparingInt(i -> mLauncher.getVisibleBounds(i).top)));
|
||||
}
|
||||
|
||||
/** @return visible bounds of the bottom-most visible icon in the container. */
|
||||
protected Rect getBottomVisibleIconBounds(UiObject2 allAppsContainer) {
|
||||
return mLauncher.getVisibleBounds(Collections.max(getVisibleIcons(allAppsContainer),
|
||||
Comparator.comparingInt(i -> mLauncher.getVisibleBounds(i).top)));
|
||||
}
|
||||
|
||||
@NonNull
|
||||
private List<UiObject2> getVisibleIcons(UiObject2 allAppsContainer) {
|
||||
return mLauncher.getObjectsInContainer(allAppsContainer, "icon")
|
||||
.stream()
|
||||
.filter(icon ->
|
||||
mLauncher.getVisibleBounds(icon).top
|
||||
< mLauncher.getBottomGestureStartOnScreen())
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds an icon. Fails if the icon doesn't exist. Scrolls the app list when needed to make
|
||||
* sure the icon is visible.
|
||||
@@ -196,20 +217,23 @@ public abstract class AllApps extends LauncherInstrumentation.VisibleContainer {
|
||||
|
||||
protected abstract int getAppsListRecyclerTopPadding();
|
||||
|
||||
protected int getAppsListRecyclerBottomPadding() {
|
||||
return mLauncher.getTestInfo(TestProtocol.REQUEST_ALL_APPS_BOTTOM_PADDING)
|
||||
.getInt(TestProtocol.TEST_INFO_RESPONSE_FIELD);
|
||||
}
|
||||
|
||||
private void scrollBackToBeginning() {
|
||||
try (LauncherInstrumentation.Closable c = mLauncher.addContextLayer(
|
||||
"want to scroll back in all apps")) {
|
||||
LauncherInstrumentation.log("Scrolling to the beginning");
|
||||
final UiObject2 allAppsContainer = verifyActiveContainer();
|
||||
final UiObject2 appListRecycler = getAppListRecycler(allAppsContainer);
|
||||
|
||||
int attempts = 0;
|
||||
final Rect margins = new Rect(
|
||||
/* left= */ 0,
|
||||
mLauncher.getVisibleBounds(appListRecycler).top
|
||||
+ getAppsListRecyclerTopPadding() + 1,
|
||||
getTopVisibleIconBounds(allAppsContainer).bottom,
|
||||
/* right= */ 0,
|
||||
/* bottom= */ 5);
|
||||
/* bottom= */ getAppsListRecyclerBottomPadding());
|
||||
|
||||
for (int scroll = getAllAppsScroll();
|
||||
scroll != 0;
|
||||
@@ -240,7 +264,7 @@ public abstract class AllApps extends LauncherInstrumentation.VisibleContainer {
|
||||
.getInt(TestProtocol.TEST_INFO_RESPONSE_FIELD);
|
||||
}
|
||||
|
||||
private UiObject2 getAppListRecycler(UiObject2 allAppsContainer) {
|
||||
protected UiObject2 getAppListRecycler(UiObject2 allAppsContainer) {
|
||||
return mLauncher.waitForObjectInContainer(allAppsContainer, "apps_list_view");
|
||||
}
|
||||
|
||||
|
||||
@@ -17,15 +17,11 @@ package com.android.launcher3.tapl;
|
||||
|
||||
import static com.android.launcher3.testing.shared.TestProtocol.NORMAL_STATE_ORDINAL;
|
||||
|
||||
import android.graphics.Rect;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.test.uiautomator.UiObject2;
|
||||
|
||||
import com.android.launcher3.testing.shared.TestProtocol;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
public class HomeAllApps extends AllApps {
|
||||
private static final String BOTTOM_SHEET_RES_ID = "bottom_sheet_background";
|
||||
|
||||
@@ -45,10 +41,8 @@ public class HomeAllApps extends AllApps {
|
||||
mLauncher.addContextLayer("want to switch from all apps to workspace")) {
|
||||
UiObject2 allAppsContainer = verifyActiveContainer();
|
||||
|
||||
final Rect searchBoxBounds = Objects.requireNonNull(
|
||||
mLauncher.getVisibleBounds(getSearchBox(allAppsContainer)));
|
||||
final int startX = searchBoxBounds.centerX();
|
||||
final int startY = searchBoxBounds.bottom;
|
||||
final int startX = allAppsContainer.getVisibleCenter().x;
|
||||
final int startY = getTopVisibleIconBounds(allAppsContainer).centerY();
|
||||
final int endY = mLauncher.getDevice().getDisplayHeight();
|
||||
LauncherInstrumentation.log(
|
||||
"switchToWorkspace: startY = " + startY + ", endY = " + endY
|
||||
@@ -59,7 +53,7 @@ public class HomeAllApps extends AllApps {
|
||||
startY,
|
||||
startX,
|
||||
endY,
|
||||
12 /* steps */,
|
||||
5 /* steps */,
|
||||
NORMAL_STATE_ORDINAL, LauncherInstrumentation.GestureScope.INSIDE);
|
||||
|
||||
try (LauncherInstrumentation.Closable c1 = mLauncher.addContextLayer(
|
||||
|
||||
@@ -76,8 +76,6 @@ import java.io.IOException;
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Deque;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
@@ -1490,19 +1488,21 @@ public final class LauncherInstrumentation {
|
||||
}
|
||||
|
||||
void scrollToLastVisibleRow(
|
||||
UiObject2 container, Collection<UiObject2> items, int topPaddingInContainer) {
|
||||
final UiObject2 lowestItem = Collections.max(items, (i1, i2) ->
|
||||
Integer.compare(getVisibleBounds(i1).top, getVisibleBounds(i2).top));
|
||||
|
||||
final int itemRowCurrentTopOnScreen = getVisibleBounds(lowestItem).top;
|
||||
UiObject2 container, Rect bottomVisibleIconBounds, int topPaddingInContainer,
|
||||
int appsListBottomPadding) {
|
||||
final int itemRowCurrentTopOnScreen = bottomVisibleIconBounds.top;
|
||||
final Rect containerRect = getVisibleBounds(container);
|
||||
final int itemRowNewTopOnScreen = containerRect.top + topPaddingInContainer;
|
||||
final int distance = itemRowCurrentTopOnScreen - itemRowNewTopOnScreen + getTouchSlop();
|
||||
|
||||
scrollDownByDistance(container, distance);
|
||||
scrollDownByDistance(container, distance, appsListBottomPadding);
|
||||
}
|
||||
|
||||
void scrollDownByDistance(UiObject2 container, int distance) {
|
||||
scrollDownByDistance(container, distance, 0);
|
||||
}
|
||||
|
||||
void scrollDownByDistance(UiObject2 container, int distance, int bottomPadding) {
|
||||
final Rect containerRect = getVisibleBounds(container);
|
||||
final int bottomGestureMarginInContainer = getBottomGestureMarginInContainer(container);
|
||||
scroll(
|
||||
@@ -1512,7 +1512,7 @@ public final class LauncherInstrumentation {
|
||||
0,
|
||||
containerRect.height() - distance - bottomGestureMarginInContainer,
|
||||
0,
|
||||
bottomGestureMarginInContainer),
|
||||
bottomGestureMarginInContainer + bottomPadding),
|
||||
/* steps= */ 10,
|
||||
/* slowDown= */ true);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user