diff options
46 files changed, 493 insertions, 237 deletions
diff --git a/go/quickstep/src/com/android/launcher3/uioverrides/states/OverviewState.java b/go/quickstep/src/com/android/launcher3/uioverrides/states/OverviewState.java index d0cfcf97a..212ce9bef 100644 --- a/go/quickstep/src/com/android/launcher3/uioverrides/states/OverviewState.java +++ b/go/quickstep/src/com/android/launcher3/uioverrides/states/OverviewState.java @@ -32,6 +32,7 @@ import static com.android.launcher3.anim.Interpolators.OVERSHOOT_1_2; import static com.android.launcher3.anim.Interpolators.OVERSHOOT_1_7; import static com.android.launcher3.states.RotationHelper.REQUEST_ROTATE; +import android.content.Context; import android.view.View; import com.android.launcher3.DeviceProfile; @@ -115,10 +116,10 @@ public class OverviewState extends LauncherState { } public static float getDefaultSwipeHeight(Launcher launcher) { - return getDefaultSwipeHeight(launcher.getDeviceProfile()); + return getDefaultSwipeHeight(launcher, launcher.getDeviceProfile()); } - public static float getDefaultSwipeHeight(DeviceProfile dp) { + public static float getDefaultSwipeHeight(Context context, DeviceProfile dp) { return dp.allAppsCellHeightPx - dp.allAppsIconTextSizePx; } diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/states/OverviewState.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/states/OverviewState.java index 151ceb834..93d4de17d 100644 --- a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/states/OverviewState.java +++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/states/OverviewState.java @@ -32,6 +32,7 @@ import static com.android.launcher3.anim.Interpolators.OVERSHOOT_1_7; import static com.android.launcher3.logging.LoggerUtils.newContainerTarget; import static com.android.launcher3.states.RotationHelper.REQUEST_ROTATE; +import android.content.Context; import android.graphics.Rect; import android.view.View; @@ -159,11 +160,15 @@ public class OverviewState extends LauncherState { } public static float getDefaultSwipeHeight(Launcher launcher) { - return getDefaultSwipeHeight(launcher.getDeviceProfile()); + return getDefaultSwipeHeight(launcher, launcher.getDeviceProfile()); } - public static float getDefaultSwipeHeight(DeviceProfile dp) { - return dp.allAppsCellHeightPx - dp.allAppsIconTextSizePx; + public static float getDefaultSwipeHeight(Context context, DeviceProfile dp) { + float swipeHeight = dp.allAppsCellHeightPx - dp.allAppsIconTextSizePx; + if (SysUINavigationMode.getMode(context) == SysUINavigationMode.Mode.NO_BUTTON) { + swipeHeight -= dp.getInsets().bottom; + } + return swipeHeight; } @Override diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherActivityControllerHelper.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherActivityControllerHelper.java index 4f971809f..25cc33df0 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherActivityControllerHelper.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherActivityControllerHelper.java @@ -172,8 +172,6 @@ public final class LauncherActivityControllerHelper implements ActivityControlHe AnimatorSetBuilder builder = new AnimatorSetBuilder(); // setRecentsAttachedToAppWindow() will animate recents out. builder.addFlag(AnimatorSetBuilder.FLAG_DONT_ANIMATE_OVERVIEW); - // We want to keep all apps content as GONE to avoid relayout during home animation. - builder.addFlag(AnimatorSetBuilder.FLAG_DONT_UPDATE_ALL_APPS_VISIBILITY); stateManager.createAtomicAnimation(BACKGROUND_APP, NORMAL, builder, ANIM_ALL, 0); builder.build().start(); @@ -202,9 +200,6 @@ public final class LauncherActivityControllerHelper implements ActivityControlHe // This ensures then the next swipe up to all-apps starts from scroll 0. activity.getAppsView().reset(false /* animate */); - // Optimization, hide the all apps view to prevent layout while initializing - activity.getAppsView().getContentView().setVisibility(View.GONE); - return new AnimationFactory() { private ShelfAnimState mShelfState; private boolean mIsAttachedToWindow; diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/QuickstepTestInformationHandler.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/QuickstepTestInformationHandler.java index 4eb9df2cb..da4642636 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/QuickstepTestInformationHandler.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/QuickstepTestInformationHandler.java @@ -24,7 +24,7 @@ public class QuickstepTestInformationHandler extends TestInformationHandler { switch (method) { case TestProtocol.REQUEST_HOME_TO_OVERVIEW_SWIPE_HEIGHT: { final float swipeHeight = - OverviewState.getDefaultSwipeHeight(mDeviceProfile); + OverviewState.getDefaultSwipeHeight(mContext, mDeviceProfile); response.putInt(TestProtocol.TEST_INFO_RESPONSE_FIELD, (int) swipeHeight); return response; } diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/AssistantTouchConsumer.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/AssistantTouchConsumer.java index 38b5a137c..346969e59 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/AssistantTouchConsumer.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/AssistantTouchConsumer.java @@ -1,3 +1,4 @@ + /* * Copyright (C) 2019 The Android Open Source Project * @@ -82,7 +83,8 @@ public class AssistantTouchConsumer extends DelegateInputConsumer { private int mDirection; private ActivityControlHelper mActivityControlHelper; - private final float mDistThreshold; + private final float mDragDistThreshold; + private final float mFlingDistThreshold; private final long mTimeThreshold; private final int mAngleThreshold; private final float mSquaredSlop; @@ -97,7 +99,8 @@ public class AssistantTouchConsumer extends DelegateInputConsumer { final Resources res = context.getResources(); mContext = context; mSysUiProxy = systemUiProxy; - mDistThreshold = res.getDimension(R.dimen.gestures_assistant_drag_threshold); + mDragDistThreshold = res.getDimension(R.dimen.gestures_assistant_drag_threshold); + mFlingDistThreshold = res.getDimension(R.dimen.gestures_assistant_fling_threshold); mTimeThreshold = res.getInteger(R.integer.assistant_gesture_min_time_threshold); mAngleThreshold = res.getInteger(R.integer.assistant_gesture_corner_deg_threshold); @@ -117,8 +120,6 @@ public class AssistantTouchConsumer extends DelegateInputConsumer { @Override public void onMotionEvent(MotionEvent ev) { // TODO add logging - mGestureDetector.onTouchEvent(ev); - switch (ev.getActionMasked()) { case ACTION_DOWN: { mActivePointerId = ev.getPointerId(0); @@ -213,6 +214,8 @@ public class AssistantTouchConsumer extends DelegateInputConsumer { break; } + mGestureDetector.onTouchEvent(ev); + if (mState != STATE_ACTIVE) { mDelegate.onMotionEvent(ev); } @@ -220,9 +223,9 @@ public class AssistantTouchConsumer extends DelegateInputConsumer { private void updateAssistantProgress() { if (!mLaunchedAssistant) { - mLastProgress = Math.min(mDistance * 1f / mDistThreshold, 1) * mTimeFraction; + mLastProgress = Math.min(mDistance * 1f / mDragDistThreshold, 1) * mTimeFraction; try { - if (mDistance >= mDistThreshold && mTimeFraction >= 1) { + if (mDistance >= mDragDistThreshold && mTimeFraction >= 1) { mSysUiProxy.onAssistantGestureCompletion(0); startAssistantInternal(SWIPE); @@ -271,7 +274,9 @@ public class AssistantTouchConsumer extends DelegateInputConsumer { @Override public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) { if (isValidAssistantGestureAngle(velocityX, -velocityY) - && !mLaunchedAssistant && mState != STATE_DELEGATE_ACTIVE) { + && mDistance >= mFlingDistThreshold + && !mLaunchedAssistant + && mState != STATE_DELEGATE_ACTIVE) { mLastProgress = 1; try { mSysUiProxy.onAssistantGestureCompletion( diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/util/StaggeredWorkspaceAnim.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/util/StaggeredWorkspaceAnim.java index 1069bed59..1aa5365fd 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/util/StaggeredWorkspaceAnim.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/util/StaggeredWorkspaceAnim.java @@ -29,6 +29,7 @@ import android.view.ViewGroup; import androidx.annotation.Nullable; +import com.android.launcher3.BubbleTextView; import com.android.launcher3.CellLayout; import com.android.launcher3.DeviceProfile; import com.android.launcher3.Launcher; @@ -40,7 +41,9 @@ import com.android.launcher3.Workspace; import com.android.launcher3.anim.AnimatorSetBuilder; import com.android.launcher3.anim.PropertySetter; import com.android.launcher3.anim.SpringObjectAnimator; +import com.android.launcher3.folder.FolderIcon; import com.android.launcher3.graphics.OverviewScrim; +import com.android.launcher3.views.IconLabelDotView; import java.util.ArrayList; import java.util.List; @@ -62,7 +65,9 @@ public class StaggeredWorkspaceAnim { private final float mVelocity; private final float mSpringTransY; - private final View mViewToIgnore; + + // The original view of the {@link FloatingIconView}. + private final View mOriginalView; private final List<Animator> mAnimators = new ArrayList<>(); @@ -72,9 +77,7 @@ public class StaggeredWorkspaceAnim { public StaggeredWorkspaceAnim(Launcher launcher, @Nullable View floatingViewOriginalView, float velocity) { mVelocity = velocity; - // We ignore this view since it's visibility and position is controlled by - // the FloatingIconView. - mViewToIgnore = floatingViewOriginalView; + mOriginalView = floatingViewOriginalView; // Scale the translationY based on the initial velocity to better sync the workspace items // with the floating view. @@ -86,16 +89,21 @@ public class StaggeredWorkspaceAnim { Workspace workspace = launcher.getWorkspace(); CellLayout cellLayout = (CellLayout) workspace.getChildAt(workspace.getCurrentPage()); ShortcutAndWidgetContainer currentPage = cellLayout.getShortcutsAndWidgets(); + ViewGroup hotseat = launcher.getHotseat(); boolean workspaceClipChildren = workspace.getClipChildren(); boolean workspaceClipToPadding = workspace.getClipToPadding(); boolean cellLayoutClipChildren = cellLayout.getClipChildren(); boolean cellLayoutClipToPadding = cellLayout.getClipToPadding(); + boolean hotseatClipChildren = hotseat.getClipChildren(); + boolean hotseatClipToPadding = hotseat.getClipToPadding(); workspace.setClipChildren(false); workspace.setClipToPadding(false); cellLayout.setClipChildren(false); cellLayout.setClipToPadding(false); + hotseat.setClipChildren(false); + hotseat.setClipToPadding(false); // Hotseat and QSB takes up two additional rows. int totalRows = grid.inv.numRows + (grid.isVerticalBarLayout() ? 0 : 2); @@ -108,16 +116,18 @@ public class StaggeredWorkspaceAnim { } // Set up springs for the hotseat and qsb. + ViewGroup hotseatChild = (ViewGroup) hotseat.getChildAt(0); if (grid.isVerticalBarLayout()) { - ViewGroup hotseat = (ViewGroup) launcher.getHotseat().getChildAt(0); - for (int i = hotseat.getChildCount() - 1; i >= 0; i--) { - View child = hotseat.getChildAt(i); + for (int i = hotseatChild.getChildCount() - 1; i >= 0; i--) { + View child = hotseatChild.getChildAt(i); CellLayout.LayoutParams lp = ((CellLayout.LayoutParams) child.getLayoutParams()); addStaggeredAnimationForView(child, lp.cellY + 1, totalRows); } } else { - View hotseat = launcher.getHotseat().getChildAt(0); - addStaggeredAnimationForView(hotseat, grid.inv.numRows + 1, totalRows); + for (int i = hotseatChild.getChildCount() - 1; i >= 0; i--) { + View child = hotseatChild.getChildAt(i); + addStaggeredAnimationForView(child, grid.inv.numRows + 1, totalRows); + } View qsb = launcher.findViewById(R.id.search_container_all_apps); addStaggeredAnimationForView(qsb, grid.inv.numRows + 2, totalRows); @@ -140,6 +150,8 @@ public class StaggeredWorkspaceAnim { workspace.setClipToPadding(workspaceClipToPadding); cellLayout.setClipChildren(cellLayoutClipChildren); cellLayout.setClipToPadding(cellLayoutClipToPadding); + hotseat.setClipChildren(hotseatClipChildren); + hotseat.setClipToPadding(hotseatClipToPadding); } }; @@ -180,16 +192,35 @@ public class StaggeredWorkspaceAnim { springTransY.setStartDelay(startDelay); mAnimators.add(springTransY); - if (v == mViewToIgnore) { - return; + ObjectAnimator alpha = getAlphaAnimator(v, startDelay); + if (v == mOriginalView) { + // For IconLabelDotViews, we just want the label to fade in. + // Icon, badge, and dots will animate in separately (controlled via FloatingIconView) + if (v instanceof IconLabelDotView) { + alpha.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationStart(Animator animation) { + IconLabelDotView view = (IconLabelDotView) v; + view.setIconVisible(false); + view.setForceHideDot(true); + } + }); + } else { + return; + } } v.setAlpha(0); + mAnimators.add(alpha); + } + + private ObjectAnimator getAlphaAnimator(View v, long startDelay) { ObjectAnimator alpha = ObjectAnimator.ofFloat(v, View.ALPHA, 0f, 1f); alpha.setInterpolator(LINEAR); alpha.setDuration(ALPHA_DURATION_MS); alpha.setStartDelay(startDelay); - mAnimators.add(alpha); + return alpha; + } private void addScrimAnimationForState(Launcher launcher, LauncherState state, long duration) { diff --git a/quickstep/res/values/dimens.xml b/quickstep/res/values/dimens.xml index b0968f94c..78424ca51 100644 --- a/quickstep/res/values/dimens.xml +++ b/quickstep/res/values/dimens.xml @@ -69,6 +69,7 @@ <!-- Distance from the vertical edges of the screen in which assist gestures are recognized --> <dimen name="gestures_assistant_width">48dp</dimen> <dimen name="gestures_assistant_drag_threshold">55dp</dimen> + <dimen name="gestures_assistant_fling_threshold">55dp</dimen> <!-- Distance to move elements when swiping up to go home from launcher --> <dimen name="home_pullback_distance">28dp</dimen> diff --git a/quickstep/src/com/android/launcher3/uioverrides/TogglableFlag.java b/quickstep/src/com/android/launcher3/uioverrides/TogglableFlag.java index e42508814..853a1c6ac 100644 --- a/quickstep/src/com/android/launcher3/uioverrides/TogglableFlag.java +++ b/quickstep/src/com/android/launcher3/uioverrides/TogglableFlag.java @@ -16,17 +16,34 @@ package com.android.launcher3.uioverrides; +import android.content.Context; import android.provider.DeviceConfig; import com.android.launcher3.config.BaseFlags.BaseTogglableFlag; public class TogglableFlag extends BaseTogglableFlag { + public static final String NAMESPACE_LAUNCHER = "launcher"; + public static final String TAG = "TogglableFlag"; public TogglableFlag(String key, boolean defaultValue, String description) { super(key, defaultValue, description); } @Override - public boolean getInitialValue(boolean value) { - return DeviceConfig.getBoolean("launcher", getKey(), value); + public boolean getOverridenDefaultValue(boolean value) { + return DeviceConfig.getBoolean(NAMESPACE_LAUNCHER, getKey(), value); + } + + @Override + public void addChangeListener(Context context, Runnable r) { + DeviceConfig.addOnPropertiesChangedListener( + NAMESPACE_LAUNCHER, + context.getMainExecutor(), + (properties) -> { + if (!NAMESPACE_LAUNCHER.equals(properties.getNamespace())) { + return; + } + initialize(context); + r.run(); + }); } } diff --git a/quickstep/src/com/android/quickstep/views/ShelfScrimView.java b/quickstep/src/com/android/quickstep/views/ShelfScrimView.java index 3747f9a8b..dc6b56eec 100644 --- a/quickstep/src/com/android/quickstep/views/ShelfScrimView.java +++ b/quickstep/src/com/android/quickstep/views/ShelfScrimView.java @@ -156,12 +156,14 @@ public class ShelfScrimView extends ScrimView implements NavigationModeChangeLis mDragHandleProgress = 1; mMidAlpha = 0; } else { - mMidAlpha = Themes.getAttrInteger(getContext(), R.attr.allAppsInterimScrimAlpha); + Context context = getContext(); + mMidAlpha = Themes.getAttrInteger(context, R.attr.allAppsInterimScrimAlpha); mMidProgress = OVERVIEW.getVerticalProgress(mLauncher); Rect hotseatPadding = dp.getHotseatLayoutPadding(); int hotseatSize = dp.hotseatBarSizePx + dp.getInsets().bottom - hotseatPadding.bottom - hotseatPadding.top; - float dragHandleTop = Math.min(hotseatSize, OverviewState.getDefaultSwipeHeight(dp)); + float dragHandleTop = + Math.min(hotseatSize, OverviewState.getDefaultSwipeHeight(context, dp)); mDragHandleProgress = 1 - (dragHandleTop / mShiftRange); } mTopOffset = dp.getInsets().top - mShelfOffset; diff --git a/quickstep/tests/src/com/android/quickstep/DigitalWellBeingToastTest.java b/quickstep/tests/src/com/android/quickstep/DigitalWellBeingToastTest.java index ec3d49afa..a7c33a954 100644 --- a/quickstep/tests/src/com/android/quickstep/DigitalWellBeingToastTest.java +++ b/quickstep/tests/src/com/android/quickstep/DigitalWellBeingToastTest.java @@ -69,10 +69,9 @@ public class DigitalWellBeingToastTest extends AbstractQuickStepTest { private DigitalWellBeingToast getToast() { executeOnLauncher(launcher -> launcher.getStateManager().goToState(OVERVIEW)); waitForState("Launcher internal state didn't switch to Overview", OVERVIEW); - waitForLauncherCondition("No latest task", launcher -> getLatestTask(launcher) != null); + final TaskView task = getOnceNotNull("No latest task", launcher -> getLatestTask(launcher)); return getFromLauncher(launcher -> { - final TaskView task = getLatestTask(launcher); assertTrue("Latest task is not Calculator", CALCULATOR_PACKAGE.equals(task.getTask().getTopComponent().getPackageName())); return task.getDigitalWellBeingToast(); diff --git a/quickstep/tests/src/com/android/quickstep/NavigationModeSwitchRule.java b/quickstep/tests/src/com/android/quickstep/NavigationModeSwitchRule.java index edd5011f2..e29552713 100644 --- a/quickstep/tests/src/com/android/quickstep/NavigationModeSwitchRule.java +++ b/quickstep/tests/src/com/android/quickstep/NavigationModeSwitchRule.java @@ -118,7 +118,6 @@ public class NavigationModeSwitchRule implements TestRule { assertTrue("Couldn't set overlay", setActiveOverlay(prevOverlayPkg, originalMode)); } - mLauncher.disableDebugTracing(); } private void evaluateWithThreeButtons() throws Throwable { diff --git a/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java b/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java index be8506d83..885fdbf42 100644 --- a/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java +++ b/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java @@ -97,7 +97,6 @@ public class TaplTestsQuickstep extends AbstractQuickStepTest { @Test @PortraitLandscape public void testOverview() throws Exception { - mLauncher.enableDebugTracing(); startTestApps(); Overview overview = mLauncher.pressHome().switchToOverview(); assertTrue("Launcher internal state didn't switch to Overview", @@ -177,7 +176,6 @@ public class TaplTestsQuickstep extends AbstractQuickStepTest { executeOnLauncher( launcher -> assertEquals("Still have tasks after dismissing all", 0, getTaskCount(launcher))); - mLauncher.disableDebugTracing(); } private int getCurrentOverviewPage(Launcher launcher) { diff --git a/src/com/android/launcher3/BaseRecyclerView.java b/src/com/android/launcher3/BaseRecyclerView.java index c84be4dac..864fa6e8a 100644 --- a/src/com/android/launcher3/BaseRecyclerView.java +++ b/src/com/android/launcher3/BaseRecyclerView.java @@ -22,6 +22,7 @@ import android.view.MotionEvent; import android.view.View; import android.view.ViewGroup; +import com.android.launcher3.compat.AccessibilityManagerCompat; import com.android.launcher3.views.RecyclerViewFastScroller; import androidx.recyclerview.widget.RecyclerView; @@ -171,4 +172,13 @@ public abstract class BaseRecyclerView extends RecyclerView { * <p>Override in each subclass of this base class. */ public void onFastScrollCompleted() {} + + @Override + public void onScrollStateChanged(int state) { + super.onScrollStateChanged(state); + + if (state == SCROLL_STATE_IDLE) { + AccessibilityManagerCompat.sendScrollFinishedEventToTest(getContext()); + } + } }
\ No newline at end of file diff --git a/src/com/android/launcher3/BubbleTextView.java b/src/com/android/launcher3/BubbleTextView.java index 22c69f59a..b1132494a 100644 --- a/src/com/android/launcher3/BubbleTextView.java +++ b/src/com/android/launcher3/BubbleTextView.java @@ -32,7 +32,6 @@ import android.graphics.drawable.ColorDrawable; import android.graphics.drawable.Drawable; import android.text.TextUtils.TruncateAt; import android.util.AttributeSet; -import android.util.Log; import android.util.Property; import android.util.TypedValue; import android.view.KeyEvent; @@ -54,8 +53,8 @@ import com.android.launcher3.icons.DotRenderer; import com.android.launcher3.icons.IconCache.IconLoadRequest; import com.android.launcher3.icons.IconCache.ItemInfoUpdateReceiver; import com.android.launcher3.model.PackageItemInfo; -import com.android.launcher3.testing.TestProtocol; import com.android.launcher3.views.ActivityContext; +import com.android.launcher3.views.IconLabelDotView; import java.text.NumberFormat; @@ -64,7 +63,8 @@ import java.text.NumberFormat; * because we want to make the bubble taller than the text and TextView's clip is * too aggressive. */ -public class BubbleTextView extends TextView implements ItemInfoUpdateReceiver, OnResumeCallback { +public class BubbleTextView extends TextView implements ItemInfoUpdateReceiver, OnResumeCallback, + IconLabelDotView { private static final int DISPLAY_WORKSPACE = 0; private static final int DISPLAY_ALL_APPS = 1; @@ -413,7 +413,8 @@ public class BubbleTextView extends TextView implements ItemInfoUpdateReceiver, } } - public void forceHideDot(boolean forceHideDot) { + @Override + public void setForceHideDot(boolean forceHideDot) { if (mForceHideDot == forceHideDot) { return; } @@ -602,6 +603,7 @@ public class BubbleTextView extends TextView implements ItemInfoUpdateReceiver, } } + @Override public void setIconVisible(boolean visible) { mIsIconVisible = visible; Drawable icon = visible ? mIcon : new ColorDrawable(Color.TRANSPARENT); diff --git a/src/com/android/launcher3/FastBitmapDrawable.java b/src/com/android/launcher3/FastBitmapDrawable.java index 7ab88a008..a90025e97 100644 --- a/src/com/android/launcher3/FastBitmapDrawable.java +++ b/src/com/android/launcher3/FastBitmapDrawable.java @@ -142,8 +142,11 @@ public class FastBitmapDrawable extends Drawable { @Override public void setAlpha(int alpha) { - mAlpha = alpha; - mPaint.setAlpha(alpha); + if (mAlpha != alpha) { + mAlpha = alpha; + mPaint.setAlpha(alpha); + invalidateSelf(); + } } @Override diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java index d79230f8b..257f0dfcf 100644 --- a/src/com/android/launcher3/Launcher.java +++ b/src/com/android/launcher3/Launcher.java @@ -157,6 +157,7 @@ import java.util.List; import java.util.function.Predicate; import androidx.annotation.Nullable; +import androidx.annotation.VisibleForTesting; /** * Default launcher application. @@ -209,9 +210,9 @@ public class Launcher extends BaseDraggingActivity implements LauncherExterns, private static final int ON_ACTIVITY_RESULT_ANIMATION_DELAY = 500; // How long to wait before the new-shortcut animation automatically pans the workspace - private static final int NEW_APPS_PAGE_MOVE_DELAY = 500; + @VisibleForTesting public static final int NEW_APPS_PAGE_MOVE_DELAY = 500; private static final int NEW_APPS_ANIMATION_INACTIVE_TIMEOUT_SECONDS = 5; - @Thunk static final int NEW_APPS_ANIMATION_DELAY = 500; + @Thunk @VisibleForTesting public static final int NEW_APPS_ANIMATION_DELAY = 500; private static final int APPS_VIEW_ALPHA_CHANNEL_INDEX = 1; private static final int SCRIM_VIEW_ALPHA_CHANNEL_INDEX = 0; diff --git a/src/com/android/launcher3/LauncherAppState.java b/src/com/android/launcher3/LauncherAppState.java index 2a801d6ef..b4a2216c5 100644 --- a/src/com/android/launcher3/LauncherAppState.java +++ b/src/com/android/launcher3/LauncherAppState.java @@ -94,6 +94,7 @@ public class LauncherAppState { if (FeatureFlags.IS_DOGFOOD_BUILD) { filter.addAction(ACTION_FORCE_ROLOAD); } + FeatureFlags.APP_SEARCH_IMPROVEMENTS.addChangeListener(context, mModel::forceReload); mContext.registerReceiver(mModel, filter); UserManagerCompat.getInstance(mContext).enableAndResetCache(); diff --git a/src/com/android/launcher3/allapps/AllAppsRecyclerView.java b/src/com/android/launcher3/allapps/AllAppsRecyclerView.java index 139930292..f82e380f8 100644 --- a/src/com/android/launcher3/allapps/AllAppsRecyclerView.java +++ b/src/com/android/launcher3/allapps/AllAppsRecyclerView.java @@ -34,6 +34,7 @@ import com.android.launcher3.ItemInfo; import com.android.launcher3.Launcher; import com.android.launcher3.LauncherAppState; import com.android.launcher3.R; +import com.android.launcher3.allapps.AllAppsGridAdapter.AppsGridLayoutManager; import com.android.launcher3.compat.AccessibilityManagerCompat; import com.android.launcher3.logging.StatsLogUtils.LogContainerProvider; import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType; @@ -113,6 +114,13 @@ public class AllAppsRecyclerView extends BaseRecyclerView implements LogContaine if (mScrollbar != null) { mScrollbar.reattachThumbToScroll(); } + if (getLayoutManager() instanceof AppsGridLayoutManager) { + AppsGridLayoutManager layoutManager = (AppsGridLayoutManager) getLayoutManager(); + if (layoutManager.findFirstCompletelyVisibleItemPosition() == 0) { + // We are at the top, so don't scrollToPosition (would cause unnecessary relayout). + return; + } + } scrollToPosition(0); } @@ -419,13 +427,4 @@ public class AllAppsRecyclerView extends BaseRecyclerView implements LogContaine public boolean hasOverlappingRendering() { return false; } - - @Override - public void onScrollStateChanged(int state) { - super.onScrollStateChanged(state); - - if (state == SCROLL_STATE_IDLE) { - AccessibilityManagerCompat.sendScrollFinishedEventToTest(getContext()); - } - } } diff --git a/src/com/android/launcher3/allapps/AllAppsTransitionController.java b/src/com/android/launcher3/allapps/AllAppsTransitionController.java index dfddc61d3..3836c9fdb 100644 --- a/src/com/android/launcher3/allapps/AllAppsTransitionController.java +++ b/src/com/android/launcher3/allapps/AllAppsTransitionController.java @@ -1,7 +1,5 @@ package com.android.launcher3.allapps; -import static android.view.View.ALPHA; - import static com.android.launcher3.LauncherState.ALL_APPS_CONTENT; import static com.android.launcher3.LauncherState.ALL_APPS_HEADER_EXTRA; import static com.android.launcher3.LauncherState.BACKGROUND_APP; @@ -12,7 +10,6 @@ import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_ALL_APPS_FADE; import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_ALL_APPS_HEADER_FADE; import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_OVERVIEW_SCALE; import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_VERTICAL_PROGRESS; -import static com.android.launcher3.anim.AnimatorSetBuilder.FLAG_DONT_UPDATE_ALL_APPS_VISIBILITY; import static com.android.launcher3.anim.Interpolators.FAST_OUT_SLOW_IN; import static com.android.launcher3.anim.Interpolators.LINEAR; import static com.android.launcher3.anim.PropertySetter.NO_ANIM_PROPERTY_SETTER; @@ -21,7 +18,6 @@ import static com.android.launcher3.util.SystemUiController.UI_STATE_ALL_APPS; import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.util.FloatProperty; -import android.view.View; import android.view.animation.Interpolator; import com.android.launcher3.DeviceProfile; @@ -215,12 +211,7 @@ public class AllAppsTransitionController implements StateHandler, OnDeviceProfil Interpolator allAppsFade = builder.getInterpolator(ANIM_ALL_APPS_FADE, LINEAR); Interpolator headerFade = builder.getInterpolator(ANIM_ALL_APPS_HEADER_FADE, allAppsFade); - View allAppsContent = mAppsView.getContentView(); - if (!hasAllAppsContent && builder.hasFlag(FLAG_DONT_UPDATE_ALL_APPS_VISIBILITY)) { - setter.setFloat(allAppsContent, ALPHA, 0, allAppsFade); - } else { - setter.setViewAlpha(allAppsContent, hasAllAppsContent ? 1 : 0, allAppsFade); - } + setter.setViewAlpha(mAppsView.getContentView(), hasAllAppsContent ? 1 : 0, allAppsFade); setter.setViewAlpha(mAppsView.getScrollBar(), hasAllAppsContent ? 1 : 0, allAppsFade); mAppsView.getFloatingHeaderView().setContentVisibility(hasHeaderExtra, hasAllAppsContent, setter, headerFade, allAppsFade); diff --git a/src/com/android/launcher3/anim/AnimatorSetBuilder.java b/src/com/android/launcher3/anim/AnimatorSetBuilder.java index 07e755345..cd30dea9c 100644 --- a/src/com/android/launcher3/anim/AnimatorSetBuilder.java +++ b/src/com/android/launcher3/anim/AnimatorSetBuilder.java @@ -43,7 +43,6 @@ public class AnimatorSetBuilder { public static final int ANIM_ALL_APPS_HEADER_FADE = 12; // e.g. predictions public static final int FLAG_DONT_ANIMATE_OVERVIEW = 1 << 0; - public static final int FLAG_DONT_UPDATE_ALL_APPS_VISIBILITY = 1 << 1; protected final ArrayList<Animator> mAnims = new ArrayList<>(); diff --git a/src/com/android/launcher3/compat/PackageInstallerCompatVL.java b/src/com/android/launcher3/compat/PackageInstallerCompatVL.java index bca66f7db..48ac05b71 100644 --- a/src/com/android/launcher3/compat/PackageInstallerCompatVL.java +++ b/src/com/android/launcher3/compat/PackageInstallerCompatVL.java @@ -140,14 +140,15 @@ public class PackageInstallerCompatVL extends PackageInstallerCompat { * Add a promise app icon to the workspace iff: * - The settings for it are enabled * - The user installed the app - * - There is a provided app icon (For apps with no launching activity, no icon is provided). + * - There is an app icon and label (For apps with no launching activity, no icon is provided). */ private void tryQueuePromiseAppIcon(SessionInfo sessionInfo) { if (Utilities.ATLEAST_OREO && FeatureFlags.PROMISE_APPS_NEW_INSTALLS.get() && SessionCommitReceiver.isEnabled(mAppContext) - && sessionInfo != null + && verify(sessionInfo) != null && sessionInfo.getInstallReason() == PackageManager.INSTALL_REASON_USER && sessionInfo.getAppIcon() != null + && !TextUtils.isEmpty(sessionInfo.getAppLabel()) && !mPromiseIconIds.contains(sessionInfo.getSessionId())) { SessionCommitReceiver.queuePromiseAppIconAddition(mAppContext, sessionInfo); mPromiseIconIds.add(sessionInfo.getSessionId()); diff --git a/src/com/android/launcher3/config/BaseFlags.java b/src/com/android/launcher3/config/BaseFlags.java index ea6261a6a..025087b9d 100644 --- a/src/com/android/launcher3/config/BaseFlags.java +++ b/src/com/android/launcher3/config/BaseFlags.java @@ -143,6 +143,8 @@ public abstract class BaseFlags { public static abstract class BaseTogglableFlag { private final String key; + // should be value that is hardcoded in client side. + // Comparatively, getDefaultValue() can be overridden. private final boolean defaultValue; private final String description; private boolean currentValue; @@ -152,8 +154,9 @@ public abstract class BaseFlags { boolean defaultValue, String description) { this.key = checkNotNull(key); - this.currentValue = this.defaultValue = getInitialValue(defaultValue); + this.currentValue = this.defaultValue = defaultValue; this.description = checkNotNull(description); + synchronized (sLock) { sFlags.add((TogglableFlag)this); } @@ -169,16 +172,18 @@ public abstract class BaseFlags { return key; } - void initialize(Context context) { - currentValue = getFromStorage(context, defaultValue); + protected void initialize(Context context) { + currentValue = getFromStorage(context, getDefaultValue()); } - protected abstract boolean getInitialValue(boolean value); + protected abstract boolean getOverridenDefaultValue(boolean value); + + protected abstract void addChangeListener(Context context, Runnable r); public void updateStorage(Context context, boolean value) { SharedPreferences.Editor editor = context.getSharedPreferences(FLAGS_PREF_NAME, Context.MODE_PRIVATE).edit(); - if (value == defaultValue) { + if (value == getDefaultValue()) { editor.remove(key).apply(); } else { editor.putBoolean(key, value).apply(); @@ -187,11 +192,11 @@ public abstract class BaseFlags { boolean getFromStorage(Context context, boolean defaultValue) { return context.getSharedPreferences(FLAGS_PREF_NAME, Context.MODE_PRIVATE) - .getBoolean(key, defaultValue); + .getBoolean(key, getDefaultValue()); } boolean getDefaultValue() { - return defaultValue; + return getOverridenDefaultValue(defaultValue); } /** Returns the value of the flag at process start, including any overrides present. */ @@ -208,6 +213,8 @@ public abstract class BaseFlags { return "TogglableFlag{" + "key=" + key + ", " + "defaultValue=" + defaultValue + ", " + + "overriddenDefaultValue=" + getOverridenDefaultValue(defaultValue) + ", " + + "currentValue=" + currentValue + ", " + "description=" + description + "}"; } @@ -220,7 +227,7 @@ public abstract class BaseFlags { if (o instanceof TogglableFlag) { BaseTogglableFlag that = (BaseTogglableFlag) o; return (this.key.equals(that.getKey())) - && (this.defaultValue == that.getDefaultValue()) + && (this.getDefaultValue() == that.getDefaultValue()) && (this.description.equals(that.getDescription())); } return false; @@ -232,7 +239,7 @@ public abstract class BaseFlags { h$ *= 1000003; h$ ^= key.hashCode(); h$ *= 1000003; - h$ ^= defaultValue ? 1231 : 1237; + h$ ^= getDefaultValue() ? 1231 : 1237; h$ *= 1000003; h$ ^= description.hashCode(); return h$; diff --git a/src/com/android/launcher3/dragndrop/DragDriver.java b/src/com/android/launcher3/dragndrop/DragDriver.java index bd2a03b6c..01e0f923c 100644 --- a/src/com/android/launcher3/dragndrop/DragDriver.java +++ b/src/com/android/launcher3/dragndrop/DragDriver.java @@ -61,6 +61,9 @@ public abstract class DragDriver { mEventListener.onDriverDragEnd(ev.getX(), ev.getY()); break; case MotionEvent.ACTION_CANCEL: + if (TestProtocol.sDebugTracing) { + Log.d(TestProtocol.NO_DRAG_TO_WORKSPACE, "DragDriver.ACTION_CANCEL"); + } mEventListener.onDriverDragCancel(); break; } diff --git a/src/com/android/launcher3/folder/Folder.java b/src/com/android/launcher3/folder/Folder.java index 2ef6d707e..f22b53338 100644 --- a/src/com/android/launcher3/folder/Folder.java +++ b/src/com/android/launcher3/folder/Folder.java @@ -516,7 +516,7 @@ public class Folder extends AbstractFloatingView implements ClipPathView, DragSo anim.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationStart(Animator animation) { - mFolderIcon.setBackgroundVisible(false); + mFolderIcon.setIconVisible(false); mFolderIcon.drawLeaveBehindIfExists(); } @Override @@ -646,7 +646,7 @@ public class Folder extends AbstractFloatingView implements ClipPathView, DragSo clearFocus(); if (mFolderIcon != null) { mFolderIcon.setVisibility(View.VISIBLE); - mFolderIcon.setBackgroundVisible(true); + mFolderIcon.setIconVisible(true); mFolderIcon.mFolderName.setTextVisibility(true); if (wasAnimated) { mFolderIcon.animateBgShadowAndStroke(); diff --git a/src/com/android/launcher3/folder/FolderIcon.java b/src/com/android/launcher3/folder/FolderIcon.java index 250169cdb..0e2d4673e 100644 --- a/src/com/android/launcher3/folder/FolderIcon.java +++ b/src/com/android/launcher3/folder/FolderIcon.java @@ -65,6 +65,7 @@ import com.android.launcher3.dragndrop.DragView; import com.android.launcher3.icons.DotRenderer; import com.android.launcher3.touch.ItemClickHandler; import com.android.launcher3.util.Thunk; +import com.android.launcher3.views.IconLabelDotView; import com.android.launcher3.widget.PendingAddShortcutInfo; import java.util.ArrayList; @@ -73,7 +74,7 @@ import java.util.List; /** * An icon that can appear on in the workspace representing an {@link Folder}. */ -public class FolderIcon extends FrameLayout implements FolderListener { +public class FolderIcon extends FrameLayout implements FolderListener, IconLabelDotView { @Thunk Launcher mLauncher; @Thunk Folder mFolder; @@ -107,6 +108,7 @@ public class FolderIcon extends FrameLayout implements FolderListener { private Alarm mOpenAlarm = new Alarm(); + private boolean mForceHideDot; @ViewDebug.ExportedProperty(category = "launcher", deepExport = true) private FolderDotInfo mDotInfo = new FolderDotInfo(); private DotRenderer mDotRenderer; @@ -409,6 +411,20 @@ public class FolderIcon extends FrameLayout implements FolderListener { return mPreviewLayoutRule; } + @Override + public void setForceHideDot(boolean forceHideDot) { + if (mForceHideDot == forceHideDot) { + return; + } + mForceHideDot = forceHideDot; + + if (forceHideDot) { + invalidate(); + } else if (hasDot()) { + animateDotScale(0, 1); + } + } + /** * Sets mDotScale to 1 or 0, animating if wasDotted or isDotted is false * (the dot is being added or removed). @@ -468,7 +484,8 @@ public class FolderIcon extends FrameLayout implements FolderListener { mBackground.setInvalidateDelegate(this); } - public void setBackgroundVisible(boolean visible) { + @Override + public void setIconVisible(boolean visible) { mBackgroundIsVisible = visible; invalidate(); } @@ -509,7 +526,7 @@ public class FolderIcon extends FrameLayout implements FolderListener { } public void drawDot(Canvas canvas) { - if ((mDotInfo != null && mDotInfo.hasDot()) || mDotScale > 0) { + if (!mForceHideDot && ((mDotInfo != null && mDotInfo.hasDot()) || mDotScale > 0)) { Rect iconBounds = mDotParams.iconBounds; BubbleTextView.getIconBounds(this, iconBounds, mLauncher.getWallpaperDeviceProfile().iconSizePx); diff --git a/src/com/android/launcher3/icons/IconCache.java b/src/com/android/launcher3/icons/IconCache.java index 55d58b9c0..abff237e8 100644 --- a/src/com/android/launcher3/icons/IconCache.java +++ b/src/com/android/launcher3/icons/IconCache.java @@ -42,6 +42,7 @@ import com.android.launcher3.Utilities; import com.android.launcher3.WorkspaceItemInfo; import com.android.launcher3.compat.LauncherAppsCompat; import com.android.launcher3.compat.UserManagerCompat; +import com.android.launcher3.config.FeatureFlags; import com.android.launcher3.icons.ComponentWithLabel.ComponentCachingLogic; import com.android.launcher3.icons.cache.BaseIconCache; import com.android.launcher3.icons.cache.CachingLogic; @@ -237,7 +238,8 @@ public class IconCache extends BaseIconCache { @Override protected String getIconSystemState(String packageName) { - return mIconProvider.getSystemStateForPackage(mSystemState, packageName); + return mIconProvider.getSystemStateForPackage(mSystemState, packageName) + + ",flags_asi:" + FeatureFlags.APP_SEARCH_IMPROVEMENTS.get(); } public static abstract class IconLoadRequest extends HandlerRunnable { diff --git a/src/com/android/launcher3/popup/PopupContainerWithArrow.java b/src/com/android/launcher3/popup/PopupContainerWithArrow.java index baaad6573..15fb4cea6 100644 --- a/src/com/android/launcher3/popup/PopupContainerWithArrow.java +++ b/src/com/android/launcher3/popup/PopupContainerWithArrow.java @@ -36,7 +36,6 @@ import android.os.Build; import android.os.Handler; import android.os.Looper; import android.util.AttributeSet; -import android.util.Log; import android.util.Pair; import android.view.MotionEvent; import android.view.View; @@ -53,7 +52,6 @@ import com.android.launcher3.ItemInfoWithIcon; import com.android.launcher3.Launcher; import com.android.launcher3.LauncherModel; import com.android.launcher3.R; -import com.android.launcher3.Utilities; import com.android.launcher3.accessibility.LauncherAccessibilityDelegate; import com.android.launcher3.accessibility.ShortcutMenuAccessibilityDelegate; import com.android.launcher3.dot.DotInfo; @@ -65,10 +63,8 @@ import com.android.launcher3.notification.NotificationInfo; import com.android.launcher3.notification.NotificationItemView; import com.android.launcher3.notification.NotificationKeyData; import com.android.launcher3.popup.PopupDataProvider.PopupDataChangeListener; -import com.android.launcher3.shortcuts.DeepShortcutManager; import com.android.launcher3.shortcuts.DeepShortcutView; import com.android.launcher3.shortcuts.ShortcutDragPreviewProvider; -import com.android.launcher3.testing.TestProtocol; import com.android.launcher3.touch.ItemClickHandler; import com.android.launcher3.touch.ItemLongClickListener; import com.android.launcher3.util.PackageUserKey; @@ -301,7 +297,7 @@ public class PopupContainerWithArrow extends ArrowPopup implements DragSource, } mLauncher.getDragController().addDragListener(this); - mOriginalIcon.forceHideDot(true); + mOriginalIcon.setForceHideDot(true); // All views are added. Animate layout from now on. setLayoutTransition(new LayoutTransition()); @@ -564,14 +560,14 @@ public class PopupContainerWithArrow extends ArrowPopup implements DragSource, protected void onCreateCloseAnimation(AnimatorSet anim) { // Animate original icon's text back in. anim.play(mOriginalIcon.createTextAlphaAnimator(true /* fadeIn */)); - mOriginalIcon.forceHideDot(false); + mOriginalIcon.setForceHideDot(false); } @Override protected void closeComplete() { super.closeComplete(); mOriginalIcon.setTextVisibility(mOriginalIcon.shouldTextBeVisible()); - mOriginalIcon.forceHideDot(false); + mOriginalIcon.setForceHideDot(false); } @Override diff --git a/src/com/android/launcher3/testing/TestInformationHandler.java b/src/com/android/launcher3/testing/TestInformationHandler.java index 4fd0f884d..243ff6f96 100644 --- a/src/com/android/launcher3/testing/TestInformationHandler.java +++ b/src/com/android/launcher3/testing/TestInformationHandler.java @@ -17,6 +17,7 @@ package com.android.launcher3.testing; import android.content.Context; import android.os.Bundle; +import android.os.Debug; import com.android.launcher3.DeviceProfile; import com.android.launcher3.InvariantDeviceProfile; @@ -113,13 +114,13 @@ public class TestInformationHandler implements ResourceBasedOverride { break; } - case TestProtocol.REQUEST_ALLOCATED_MEMORY: { - final Runtime runtime = Runtime.getRuntime(); - response.putLong(TestProtocol.TEST_INFO_RESPONSE_FIELD, - runtime.totalMemory() - runtime.freeMemory()); + case TestProtocol.REQUEST_TOTAL_PSS_KB: { + Debug.MemoryInfo mem = new Debug.MemoryInfo(); + Debug.getMemoryInfo(mem); + response.putInt(TestProtocol.TEST_INFO_RESPONSE_FIELD, mem.getTotalPss()); break; } } return response; } -} +}
\ No newline at end of file diff --git a/src/com/android/launcher3/testing/TestProtocol.java b/src/com/android/launcher3/testing/TestProtocol.java index d569d4007..60a59ddfa 100644 --- a/src/com/android/launcher3/testing/TestProtocol.java +++ b/src/com/android/launcher3/testing/TestProtocol.java @@ -73,7 +73,7 @@ public final class TestProtocol { public static final String REQUEST_APP_LIST_FREEZE_FLAGS = "app-list-freeze-flags"; public static final String REQUEST_OVERVIEW_LEFT_GESTURE_MARGIN = "overview-left-margin"; public static final String REQUEST_OVERVIEW_RIGHT_GESTURE_MARGIN = "overview-right-margin"; - public static final String REQUEST_ALLOCATED_MEMORY = "allocated-memory"; + public static final String REQUEST_TOTAL_PSS_KB = "total_pss"; public static boolean sDebugTracing = false; public static final String REQUEST_ENABLE_DEBUG_TRACING = "enable-debug-tracing"; diff --git a/src/com/android/launcher3/views/AbstractSlideInView.java b/src/com/android/launcher3/views/AbstractSlideInView.java index f948beb8d..a4518bae3 100644 --- a/src/com/android/launcher3/views/AbstractSlideInView.java +++ b/src/com/android/launcher3/views/AbstractSlideInView.java @@ -153,15 +153,15 @@ public abstract class AbstractSlideInView extends AbstractFloatingView } protected void handleClose(boolean animate, long defaultDuration) { - if (mIsOpen && !animate) { + if (!mIsOpen) { + return; + } + if (!animate) { mOpenCloseAnimator.cancel(); setTranslationShift(TRANSLATION_SHIFT_CLOSED); onCloseComplete(); return; } - if (!mIsOpen) { - return; - } mOpenCloseAnimator.setValues( PropertyValuesHolder.ofFloat(TRANSLATION_SHIFT, TRANSLATION_SHIFT_CLOSED)); mOpenCloseAnimator.addListener(new AnimatorListenerAdapter() { diff --git a/src/com/android/launcher3/views/BaseDragLayer.java b/src/com/android/launcher3/views/BaseDragLayer.java index 799762d8f..c08b65931 100644 --- a/src/com/android/launcher3/views/BaseDragLayer.java +++ b/src/com/android/launcher3/views/BaseDragLayer.java @@ -29,6 +29,7 @@ import android.graphics.Rect; import android.graphics.RectF; import android.os.Build; import android.util.AttributeSet; +import android.util.Log; import android.util.Property; import android.view.MotionEvent; import android.view.View; @@ -41,6 +42,7 @@ import android.widget.FrameLayout; import com.android.launcher3.AbstractFloatingView; import com.android.launcher3.InsettableFrameLayout; import com.android.launcher3.Utilities; +import com.android.launcher3.testing.TestProtocol; import com.android.launcher3.util.MultiValueAlpha; import com.android.launcher3.util.MultiValueAlpha.AlphaProperty; import com.android.launcher3.util.TouchController; @@ -261,6 +263,10 @@ public abstract class BaseDragLayer<T extends Context & ActivityContext> } case ACTION_CANCEL: case ACTION_UP: + if (TestProtocol.sDebugTracing) { + Log.d(TestProtocol.NO_DRAG_TO_WORKSPACE, + "BaseDragLayer.ACTION_UP/CANCEL " + ev); + } mTouchDispatchState &= ~TOUCH_DISPATCHING_GESTURE; mTouchDispatchState &= ~TOUCH_DISPATCHING_VIEW; break; diff --git a/src/com/android/launcher3/views/FloatingIconView.java b/src/com/android/launcher3/views/FloatingIconView.java index e09a9e8bf..f728a6776 100644 --- a/src/com/android/launcher3/views/FloatingIconView.java +++ b/src/com/android/launcher3/views/FloatingIconView.java @@ -18,7 +18,6 @@ package com.android.launcher3.views; import static com.android.launcher3.LauncherAnimUtils.DRAWABLE_ALPHA; import static com.android.launcher3.Utilities.getBadge; import static com.android.launcher3.Utilities.getFullDrawable; -import static com.android.launcher3.Utilities.isRtl; import static com.android.launcher3.Utilities.mapToRange; import static com.android.launcher3.anim.Interpolators.LINEAR; import static com.android.launcher3.config.FeatureFlags.ADAPTIVE_ICON_WINDOW_ANIM; @@ -564,11 +563,6 @@ public class FloatingIconView extends View implements */ private void checkIconResult(View originalView, boolean isOpening) { CancellationSignal cancellationSignal = new CancellationSignal(); - if (!isOpening) { - // Hide immediately since the floating view starts at a different location. - originalView.setVisibility(INVISIBLE); - cancellationSignal.setOnCancelListener(() -> originalView.setVisibility(VISIBLE)); - } if (mIconLoadResult == null) { Log.w(TAG, "No icon load result found in checkIconResult"); @@ -580,7 +574,7 @@ public class FloatingIconView extends View implements setIcon(originalView, mIconLoadResult.drawable, mIconLoadResult.badge, mIconLoadResult.iconOffset); if (isOpening) { - originalView.setVisibility(INVISIBLE); + hideOriginalView(originalView); } } else { mIconLoadResult.onIconLoaded = () -> { @@ -591,15 +585,26 @@ public class FloatingIconView extends View implements setIcon(originalView, mIconLoadResult.drawable, mIconLoadResult.badge, mIconLoadResult.iconOffset); - // Delay swapping views until the icon is loaded to prevent a flash. setVisibility(VISIBLE); - originalView.setVisibility(INVISIBLE); + if (isOpening) { + // Delay swapping views until the icon is loaded to prevent a flash. + hideOriginalView(originalView); + } }; mLoadIconSignal = cancellationSignal; } } } + private void hideOriginalView(View originalView) { + if (originalView instanceof BubbleTextView) { + ((BubbleTextView) originalView).setIconVisible(false); + ((BubbleTextView) originalView).setForceHideDot(true); + } else { + originalView.setVisibility(INVISIBLE); + } + } + private void setBackgroundDrawableBounds(float scale) { sTmpRect.set(mFinalDrawableBounds); Utilities.scaleRectAboutCenter(sTmpRect, scale); @@ -716,7 +721,7 @@ public class FloatingIconView extends View implements */ @UiThread public static IconLoadResult fetchIcon(Launcher l, View v, ItemInfo info, boolean isOpening) { - IconLoadResult result = new IconLoadResult(); + IconLoadResult result = new IconLoadResult(info); new Handler(LauncherModel.getWorkerLooper()).postAtFrontOfQueue(() -> { RectF position = new RectF(); getLocationBoundsForView(l, v, isOpening, position); @@ -745,10 +750,13 @@ public class FloatingIconView extends View implements // Get the drawable on the background thread boolean shouldLoadIcon = originalView.getTag() instanceof ItemInfo && hideOriginal; - view.mIconLoadResult = sIconLoadResult; - if (shouldLoadIcon && view.mIconLoadResult == null) { - view.mIconLoadResult = fetchIcon(launcher, originalView, - (ItemInfo) originalView.getTag(), isOpening); + if (shouldLoadIcon) { + if (sIconLoadResult != null && sIconLoadResult.itemInfo == originalView.getTag()) { + view.mIconLoadResult = sIconLoadResult; + } else { + view.mIconLoadResult = fetchIcon(launcher, originalView, + (ItemInfo) originalView.getTag(), isOpening); + } } sIconLoadResult = null; @@ -776,7 +784,12 @@ public class FloatingIconView extends View implements if (hideOriginal) { if (isOpening) { - originalView.setVisibility(VISIBLE); + if (originalView instanceof BubbleTextView) { + ((BubbleTextView) originalView).setIconVisible(true); + ((BubbleTextView) originalView).setForceHideDot(false); + } else { + originalView.setVisibility(VISIBLE); + } view.finish(dragLayer); } else { view.mFadeAnimatorSet = view.createFadeAnimation(originalView, dragLayer); @@ -804,38 +817,33 @@ public class FloatingIconView extends View implements } }); - if (mBadge != null && !(mOriginalIcon instanceof FolderIcon)) { + if (mBadge != null) { ObjectAnimator badgeFade = ObjectAnimator.ofInt(mBadge, DRAWABLE_ALPHA, 255); badgeFade.addUpdateListener(valueAnimator -> invalidate()); fade.play(badgeFade); } - if (originalView instanceof BubbleTextView) { - BubbleTextView btv = (BubbleTextView) originalView; - btv.forceHideDot(true); + if (originalView instanceof IconLabelDotView) { + IconLabelDotView view = (IconLabelDotView) originalView; fade.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { - btv.forceHideDot(false); + view.setIconVisible(true); + view.setForceHideDot(false); } }); } - if (originalView instanceof FolderIcon) { - FolderIcon folderIcon = (FolderIcon) originalView; - folderIcon.setBackgroundVisible(false); - folderIcon.getFolderName().setTextVisibility(false); - fade.play(folderIcon.getFolderName().createTextAlphaAnimator(true)); + if (originalView instanceof BubbleTextView) { + BubbleTextView btv = (BubbleTextView) originalView; fade.addListener(new AnimatorListenerAdapter() { @Override - public void onAnimationEnd(Animator animation) { - folderIcon.setBackgroundVisible(true); - if (folderIcon.hasDot()) { - folderIcon.animateDotScale(0, 1f); - } + public void onAnimationStart(Animator animation) { + btv.setIconVisible(true); } }); - } else { + fade.play(ObjectAnimator.ofInt(btv.getIcon(), DRAWABLE_ALPHA, 0, 255)); + } else if (!(originalView instanceof FolderIcon)) { fade.play(ObjectAnimator.ofFloat(originalView, ALPHA, 0f, 1f)); } @@ -890,10 +898,15 @@ public class FloatingIconView extends View implements } private static class IconLoadResult { + final ItemInfo itemInfo; Drawable drawable; Drawable badge; int iconOffset; Runnable onIconLoaded; boolean isIconLoaded; + + public IconLoadResult(ItemInfo itemInfo) { + this.itemInfo = itemInfo; + } } } diff --git a/src/com/android/launcher3/views/IconLabelDotView.java b/src/com/android/launcher3/views/IconLabelDotView.java new file mode 100644 index 000000000..057caafe7 --- /dev/null +++ b/src/com/android/launcher3/views/IconLabelDotView.java @@ -0,0 +1,24 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.launcher3.views; + +/** + * A view that has an icon, label, and notification dot. + */ +public interface IconLabelDotView { + void setIconVisible(boolean visible); + void setForceHideDot(boolean hide); +} diff --git a/src/com/android/launcher3/views/OptionsPopupView.java b/src/com/android/launcher3/views/OptionsPopupView.java index 63f742768..465df448e 100644 --- a/src/com/android/launcher3/views/OptionsPopupView.java +++ b/src/com/android/launcher3/views/OptionsPopupView.java @@ -18,10 +18,8 @@ package com.android.launcher3.views; import static com.android.launcher3.Utilities.EXTRA_WALLPAPER_FLAVOR; import static com.android.launcher3.Utilities.EXTRA_WALLPAPER_OFFSET; -import android.content.ComponentName; import android.content.Context; import android.content.Intent; -import android.content.pm.ResolveInfo; import android.graphics.Rect; import android.graphics.RectF; import android.text.TextUtils; @@ -33,6 +31,9 @@ import android.view.View.OnClickListener; import android.view.View.OnLongClickListener; import android.widget.Toast; +import androidx.annotation.Nullable; +import androidx.annotation.VisibleForTesting; + import com.android.launcher3.Launcher; import com.android.launcher3.R; import com.android.launcher3.Utilities; @@ -46,7 +47,6 @@ import com.android.launcher3.widget.WidgetsFullSheet; import java.util.ArrayList; import java.util.List; -import androidx.annotation.VisibleForTesting; /** * Popup shown on long pressing an empty space in launcher @@ -169,16 +169,17 @@ public class OptionsPopupView extends ArrowPopup } public static boolean onWidgetsClicked(View view) { - return openWidgets(Launcher.getLauncher(view.getContext())); + return openWidgets(Launcher.getLauncher(view.getContext())) != null; } - public static boolean openWidgets(Launcher launcher) { + /** Returns WidgetsFullSheet that was opened, or null if nothing was opened. */ + @Nullable + public static WidgetsFullSheet openWidgets(Launcher launcher) { if (launcher.getPackageManager().isSafeMode()) { Toast.makeText(launcher, R.string.safemode_widget_error, Toast.LENGTH_SHORT).show(); - return false; + return null; } else { - WidgetsFullSheet.show(launcher, true /* animated */); - return true; + return WidgetsFullSheet.show(launcher, true /* animated */); } } diff --git a/src/com/android/launcher3/views/ScrimView.java b/src/com/android/launcher3/views/ScrimView.java index c36011745..da1df3f89 100644 --- a/src/com/android/launcher3/views/ScrimView.java +++ b/src/com/android/launcher3/views/ScrimView.java @@ -18,14 +18,14 @@ package com.android.launcher3.views; import static android.content.Context.ACCESSIBILITY_SERVICE; import static android.view.MotionEvent.ACTION_DOWN; +import static androidx.core.graphics.ColorUtils.compositeColors; + import static com.android.launcher3.LauncherState.ALL_APPS; import static com.android.launcher3.LauncherState.NORMAL; import static com.android.launcher3.anim.Interpolators.ACCEL; import static com.android.launcher3.anim.Interpolators.DEACCEL; import static com.android.launcher3.icons.GraphicsUtils.setColorAlphaBound; -import static androidx.core.graphics.ColorUtils.compositeColors; - import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.animation.Keyframe; @@ -47,6 +47,13 @@ import android.view.View; import android.view.accessibility.AccessibilityManager; import android.view.accessibility.AccessibilityManager.AccessibilityStateChangeListener; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.core.view.ViewCompat; +import androidx.core.view.accessibility.AccessibilityNodeInfoCompat; +import androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat; +import androidx.customview.widget.ExploreByTouchHelper; + import com.android.launcher3.DeviceProfile; import com.android.launcher3.Insettable; import com.android.launcher3.Launcher; @@ -62,15 +69,10 @@ import com.android.launcher3.userevent.nano.LauncherLogProto.ControlType; import com.android.launcher3.util.MultiValueAlpha; import com.android.launcher3.util.MultiValueAlpha.AlphaProperty; import com.android.launcher3.util.Themes; +import com.android.launcher3.widget.WidgetsFullSheet; import java.util.List; -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import androidx.core.view.ViewCompat; -import androidx.core.view.accessibility.AccessibilityNodeInfoCompat; -import androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat; -import androidx.customview.widget.ExploreByTouchHelper; /** * Simple scrim which draws a flat color @@ -325,7 +327,7 @@ public class ScrimView extends View implements Insettable, OnChangeListener, if (enabled) { stateManager.addStateListener(this); - handleStateChangedComplete(mLauncher.getStateManager().getState()); + handleStateChangedComplete(stateManager.getState()); } else { setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS); } @@ -437,7 +439,24 @@ public class ScrimView extends View implements Insettable, OnChangeListener, } else if (action == WALLPAPERS) { return OptionsPopupView.startWallpaperPicker(ScrimView.this); } else if (action == WIDGETS) { - return OptionsPopupView.onWidgetsClicked(ScrimView.this); + int originalImportanceForAccessibility = getImportantForAccessibility(); + setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS); + WidgetsFullSheet widgetsFullSheet = OptionsPopupView.openWidgets(mLauncher); + if (widgetsFullSheet == null) { + setImportantForAccessibility(originalImportanceForAccessibility); + return false; + } + widgetsFullSheet.addOnAttachStateChangeListener(new OnAttachStateChangeListener() { + @Override + public void onViewAttachedToWindow(View view) {} + + @Override + public void onViewDetachedFromWindow(View view) { + setImportantForAccessibility(originalImportanceForAccessibility); + widgetsFullSheet.removeOnAttachStateChangeListener(this); + } + }); + return true; } else if (action == SETTINGS) { return OptionsPopupView.startSettings(ScrimView.this); } diff --git a/src_ui_overrides/com/android/launcher3/uioverrides/TogglableFlag.java b/src_ui_overrides/com/android/launcher3/uioverrides/TogglableFlag.java index e875a3c46..60f12d82a 100644 --- a/src_ui_overrides/com/android/launcher3/uioverrides/TogglableFlag.java +++ b/src_ui_overrides/com/android/launcher3/uioverrides/TogglableFlag.java @@ -16,6 +16,7 @@ package com.android.launcher3.uioverrides; +import android.content.Context; import com.android.launcher3.config.BaseFlags.BaseTogglableFlag; public class TogglableFlag extends BaseTogglableFlag { @@ -25,7 +26,10 @@ public class TogglableFlag extends BaseTogglableFlag { } @Override - public boolean getInitialValue(boolean value) { + public boolean getOverridenDefaultValue(boolean value) { return value; } + + @Override + public void addChangeListener(Context context, Runnable r) { } } diff --git a/tests/src/com/android/launcher3/compat/PromiseIconUiTest.java b/tests/src/com/android/launcher3/compat/PromiseIconUiTest.java new file mode 100644 index 000000000..efbd9c99c --- /dev/null +++ b/tests/src/com/android/launcher3/compat/PromiseIconUiTest.java @@ -0,0 +1,113 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.android.launcher3.compat; + +import android.content.pm.PackageInstaller.SessionParams; +import android.content.pm.PackageManager; +import android.graphics.Bitmap; +import android.text.TextUtils; + +import androidx.test.filters.LargeTest; +import androidx.test.runner.AndroidJUnit4; + +import com.android.launcher3.Launcher; +import com.android.launcher3.LauncherState; +import com.android.launcher3.Workspace; +import com.android.launcher3.ui.AbstractLauncherUiTest; + +import org.junit.After; +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.util.UUID; + + +/** + * Test to verify promise icon flow. + */ +@LargeTest +@RunWith(AndroidJUnit4.class) +public class PromiseIconUiTest extends AbstractLauncherUiTest { + + private int mSessionId = -1; + + @Override + public void setUp() throws Exception { + super.setUp(); + mDevice.pressHome(); + waitForLauncherCondition("Launcher didn't start", launcher -> launcher != null); + waitForState("Launcher internal state didn't switch to Home", LauncherState.NORMAL); + mSessionId = -1; + } + + @After + public void tearDown() { + if (mSessionId > -1) { + mTargetContext.getPackageManager().getPackageInstaller().abandonSession(mSessionId); + } + } + + /** + * Create a session and return the id. + */ + private int createSession(String label, Bitmap icon) throws Throwable { + SessionParams params = new SessionParams(SessionParams.MODE_FULL_INSTALL); + params.setAppPackageName("test.promise.app"); + params.setAppLabel(label); + params.setAppIcon(icon); + params.setInstallReason(PackageManager.INSTALL_REASON_USER); + return mTargetContext.getPackageManager().getPackageInstaller().createSession(params); + } + + @Test + public void testPromiseIcon_addedFromEligibleSession() throws Throwable { + final String appLabel = "Test Promise App " + UUID.randomUUID().toString(); + final Workspace.ItemOperator findPromiseApp = (info, view) -> + info != null && TextUtils.equals(info.title, appLabel); + + // Create and add test session + mSessionId = createSession(appLabel, Bitmap.createBitmap(100, 100, Bitmap.Config.ALPHA_8)); + + // Verify promise icon is added + waitForLauncherCondition("Test Promise App not found on workspace", launcher -> + launcher.getWorkspace().getFirstMatch(findPromiseApp) != null); + + // Remove session + mTargetContext.getPackageManager().getPackageInstaller().abandonSession(mSessionId); + mSessionId = -1; + + // Verify promise icon is removed + waitForLauncherCondition("Test Promise App not removed from workspace", launcher -> + launcher.getWorkspace().getFirstMatch(findPromiseApp) == null); + } + + @Test + public void testPromiseIcon_notAddedFromIneligibleSession() throws Throwable { + final String appLabel = "Test Promise App " + UUID.randomUUID().toString(); + final Workspace.ItemOperator findPromiseApp = (info, view) -> + info != null && TextUtils.equals(info.title, appLabel); + + // Create and add test session without icon or label + mSessionId = createSession(null, null); + + // Sleep for duration of animation if a view was to be added + some buffer time. + Thread.sleep(Launcher.NEW_APPS_PAGE_MOVE_DELAY + Launcher.NEW_APPS_ANIMATION_DELAY + 500); + + // Verify promise icon is not added + waitForLauncherCondition("Test Promise App not found on workspace", launcher -> + launcher.getWorkspace().getFirstMatch(findPromiseApp) == null); + } +} diff --git a/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java b/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java index fc19baace..dc890bb00 100644 --- a/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java +++ b/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java @@ -24,7 +24,6 @@ import static org.junit.Assert.assertTrue; import static java.lang.System.exit; -import android.app.Instrumentation; import android.content.BroadcastReceiver; import android.content.ComponentName; import android.content.Context; @@ -112,6 +111,7 @@ public abstract class AbstractLauncherUiTest { launcher -> checkLauncherIntegrity(launcher, containerType))); } + mLauncher.enableDebugTracing(); } protected final LauncherActivityRule mActivityMonitor = new LauncherActivityRule(); @@ -187,14 +187,6 @@ public abstract class AbstractLauncherUiTest { } } - protected void lockRotation(boolean naturalOrientation) throws RemoteException { - if (naturalOrientation) { - mDevice.setOrientationNatural(); - } else { - mDevice.setOrientationRight(); - } - } - protected void clearLauncherData() throws IOException, InterruptedException { if (TestHelpers.isInLauncherProcess()) { LauncherSettings.Settings.call(mTargetContext.getContentResolver(), @@ -202,6 +194,7 @@ public abstract class AbstractLauncherUiTest { resetLoaderState(); } else { clearPackageData(mDevice.getLauncherPackageName()); + mLauncher.enableDebugTracing(); } } @@ -275,6 +268,12 @@ public abstract class AbstractLauncherUiTest { // Cannot be used in TaplTests after injecting any gesture using Tapl because this can hide // flakiness. + protected <T> T getOnceNotNull(String message, Function<Launcher, T> f) { + return getOnceNotNull(message, f, DEFAULT_ACTIVITY_TIMEOUT); + } + + // Cannot be used in TaplTests after injecting any gesture using Tapl because this can hide + // flakiness. protected void waitForLauncherCondition( String message, Function<Launcher, Boolean> condition, long timeout) { if (!TestHelpers.isInLauncherProcess()) return; @@ -283,6 +282,20 @@ public abstract class AbstractLauncherUiTest { // Cannot be used in TaplTests after injecting any gesture using Tapl because this can hide // flakiness. + protected <T> T getOnceNotNull(String message, Function<Launcher, T> f, long timeout) { + if (!TestHelpers.isInLauncherProcess()) return null; + + final Object[] output = new Object[1]; + Wait.atMost(message, () -> { + final Object fromLauncher = getFromLauncher(f); + output[0] = fromLauncher; + return fromLauncher != null; + }, timeout); + return (T) output[0]; + } + + // Cannot be used in TaplTests after injecting any gesture using Tapl because this can hide + // flakiness. protected void waitForLauncherCondition( String message, Runnable testThreadAction, Function<Launcher, Boolean> condition, diff --git a/tests/src/com/android/launcher3/ui/PortraitLandscapeRunner.java b/tests/src/com/android/launcher3/ui/PortraitLandscapeRunner.java index ddcb4da88..80bb3eddd 100644 --- a/tests/src/com/android/launcher3/ui/PortraitLandscapeRunner.java +++ b/tests/src/com/android/launcher3/ui/PortraitLandscapeRunner.java @@ -44,8 +44,11 @@ class PortraitLandscapeRunner implements TestRule { } finally { mTest.mDevice.setOrientationNatural(); mTest.executeOnLauncher(launcher -> - launcher.getRotationHelper().forceAllowRotationForTesting( - false)); + { + if (launcher != null) { + launcher.getRotationHelper().forceAllowRotationForTesting(false); + } + }); mTest.mLauncher.setExpectedRotation(Surface.ROTATION_0); } } diff --git a/tests/src/com/android/launcher3/ui/TaplTestsLauncher3.java b/tests/src/com/android/launcher3/ui/TaplTestsLauncher3.java index 0c87ab908..c2a3c1c52 100644 --- a/tests/src/com/android/launcher3/ui/TaplTestsLauncher3.java +++ b/tests/src/com/android/launcher3/ui/TaplTestsLauncher3.java @@ -173,7 +173,6 @@ public class TaplTestsLauncher3 extends AbstractLauncherUiTest { @Test public void testWorkspace() throws Exception { - mLauncher.enableDebugTracing(); final Workspace workspace = mLauncher.getWorkspace(); // Test that ensureWorkspaceIsScrollable adds a page by dragging an icon there. @@ -209,7 +208,6 @@ public class TaplTestsLauncher3 extends AbstractLauncherUiTest { // Test starting a workspace app. final AppIcon app = workspace.getWorkspaceAppIcon("Chrome"); assertNotNull("No Chrome app in workspace", app); - mLauncher.disableDebugTracing(); } public static void runIconLaunchFromAllAppsTest(AbstractLauncherUiTest test, AllApps allApps) { @@ -300,7 +298,6 @@ public class TaplTestsLauncher3 extends AbstractLauncherUiTest { @Test @PortraitLandscape public void testDragAppIcon() throws Throwable { - mLauncher.enableDebugTracing(); // 1. Open all apps and wait for load complete. // 2. Drag icon to homescreen. // 3. Verify that the icon works on homescreen. @@ -317,13 +314,11 @@ public class TaplTestsLauncher3 extends AbstractLauncherUiTest { "Launcher activity is the top activity; expecting another activity to be the top " + "one", isInBackground(launcher))); - mLauncher.disableDebugTracing(); } @Test @PortraitLandscape public void testDragShortcut() throws Throwable { - mLauncher.enableDebugTracing(); // 1. Open all apps and wait for load complete. // 2. Find the app and long press it to show shortcuts. // 3. Press icon center until shortcuts appear @@ -343,7 +338,6 @@ public class TaplTestsLauncher3 extends AbstractLauncherUiTest { } finally { allApps.unfreeze(); } - mLauncher.disableDebugTracing(); } public static String getAppPackageName() { diff --git a/tests/src/com/android/launcher3/ui/widget/AddConfigWidgetTest.java b/tests/src/com/android/launcher3/ui/widget/AddConfigWidgetTest.java index 3206a69bb..7f427b303 100644 --- a/tests/src/com/android/launcher3/ui/widget/AddConfigWidgetTest.java +++ b/tests/src/com/android/launcher3/ui/widget/AddConfigWidgetTest.java @@ -69,34 +69,22 @@ public class AddConfigWidgetTest extends AbstractLauncherUiTest { } @Test + @PortraitLandscape public void testWidgetConfig() throws Throwable { - runTest(false, true); - } - - @Test - @Ignore // b/121280703 - public void testWidgetConfig_rotate() throws Throwable { - runTest(true, true); + runTest(true); } @Test + @PortraitLandscape public void testConfigCancelled() throws Throwable { - runTest(false, false); + runTest(false); } - @Test - @Ignore // b/121280703 - public void testConfigCancelled_rotate() throws Throwable { - runTest(true, false); - } /** - * @param rotateConfig should the config screen be rotated * @param acceptConfig accept the config activity */ - private void runTest(boolean rotateConfig, boolean acceptConfig) throws Throwable { - lockRotation(true); - + private void runTest(boolean acceptConfig) throws Throwable { clearHomescreen(); mDevice.pressHome(); @@ -110,13 +98,6 @@ public class AddConfigWidgetTest extends AbstractLauncherUiTest { // Widget id for which the config activity was opened mWidgetId = monitor.getWidgetId(); - if (rotateConfig) { - // Rotate the screen and verify that the config activity is recreated - monitor = new WidgetConfigStartupMonitor(); - lockRotation(false); - assertEquals(mWidgetId, monitor.getWidgetId()); - } - // Verify that the widget id is valid and bound assertNotNull(mAppWidgetManager.getAppWidgetInfo(mWidgetId)); diff --git a/tests/src/com/android/launcher3/ui/widget/AddWidgetTest.java b/tests/src/com/android/launcher3/ui/widget/AddWidgetTest.java index 276c6144a..cb586aceb 100644 --- a/tests/src/com/android/launcher3/ui/widget/AddWidgetTest.java +++ b/tests/src/com/android/launcher3/ui/widget/AddWidgetTest.java @@ -15,6 +15,9 @@ */ package com.android.launcher3.ui.widget; +import static com.android.launcher3.ui.TaplTestsLauncher3.getAppPackageName; + +import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; import androidx.test.filters.LargeTest; @@ -22,6 +25,7 @@ import androidx.test.runner.AndroidJUnit4; import com.android.launcher3.LauncherAppWidgetInfo; import com.android.launcher3.LauncherAppWidgetProviderInfo; +import com.android.launcher3.tapl.Widget; import com.android.launcher3.ui.AbstractLauncherUiTest; import com.android.launcher3.ui.TestViewHelpers; import com.android.launcher3.util.rule.ShellCommandRule; @@ -41,19 +45,8 @@ public class AddWidgetTest extends AbstractLauncherUiTest { @Rule public ShellCommandRule mGrantWidgetRule = ShellCommandRule.grantWidgetBind(); @Test - public void testDragIcon_portrait() throws Throwable { - lockRotation(true); - performTest(); - } - - @Test - @Ignore // b/121280703 - public void testDragIcon_landscape() throws Throwable { - lockRotation(false); - performTest(); - } - - private void performTest() throws Throwable { + @PortraitLandscape + public void testDragIcon() throws Throwable { clearHomescreen(); mDevice.pressHome(); @@ -70,5 +63,10 @@ public class AddWidgetTest extends AbstractLauncherUiTest { (info, view) -> info instanceof LauncherAppWidgetInfo && ((LauncherAppWidgetInfo) info).providerName.getClassName().equals( widgetInfo.provider.getClassName())).call()); + + final Widget widget = mLauncher.getWorkspace().tryGetWidget(widgetInfo.label, + DEFAULT_UI_TIMEOUT); + assertNotNull("Widget not found on the workspace", widget); + widget.launch(getAppPackageName()); } } diff --git a/tests/src/com/android/launcher3/ui/widget/RequestPinItemTest.java b/tests/src/com/android/launcher3/ui/widget/RequestPinItemTest.java index a9a509098..07129ddd9 100644 --- a/tests/src/com/android/launcher3/ui/widget/RequestPinItemTest.java +++ b/tests/src/com/android/launcher3/ui/widget/RequestPinItemTest.java @@ -128,8 +128,6 @@ public class RequestPinItemTest extends AbstractLauncherUiTest { if (!Utilities.ATLEAST_OREO) { return; } - lockRotation(true); - clearHomescreen(); mDevice.pressHome(); diff --git a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java index 9d433527d..c6e7daceb 100644 --- a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java +++ b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java @@ -368,7 +368,7 @@ public final class LauncherInstrumentation { } } - private void assertEquals(String message, String expected, String actual) { + void assertEquals(String message, String expected, String actual) { if (!TextUtils.equals(expected, actual)) { fail(message + " expected: '" + expected + "' but was: '" + actual + "'"); } @@ -763,8 +763,7 @@ public final class LauncherInstrumentation { final Bundle parcel = (Bundle) executeAndWaitForEvent( () -> linearGesture(startX, startY, endX, endY, steps), event -> TestProtocol.SWITCHED_TO_STATE_MESSAGE.equals(event.getClassName()), - "Swipe failed to receive an event for the swipe end: " + startX + ", " + startY - + ", " + endX + ", " + endY); + "Swipe failed to receive an event for the swipe end"); assertEquals("Swipe switched launcher to a wrong state;", TestProtocol.stateOrdinalToString(expectedState), TestProtocol.stateOrdinalToString(parcel.getInt(TestProtocol.STATE_FIELD))); @@ -958,8 +957,8 @@ public final class LauncherInstrumentation { getTestInfo(TestProtocol.REQUEST_DISABLE_DEBUG_TRACING); } - public long getAllocatedMemory() { - return getTestInfo(TestProtocol.REQUEST_ALLOCATED_MEMORY). - getLong(TestProtocol.TEST_INFO_RESPONSE_FIELD); + public int getTotalPssKb() { + return getTestInfo(TestProtocol.REQUEST_TOTAL_PSS_KB). + getInt(TestProtocol.TEST_INFO_RESPONSE_FIELD); } }
\ No newline at end of file diff --git a/tests/tapl/com/android/launcher3/tapl/Widgets.java b/tests/tapl/com/android/launcher3/tapl/Widgets.java index 2495933ac..208a2235d 100644 --- a/tests/tapl/com/android/launcher3/tapl/Widgets.java +++ b/tests/tapl/com/android/launcher3/tapl/Widgets.java @@ -19,6 +19,7 @@ package com.android.launcher3.tapl; import static org.junit.Assert.fail; import android.graphics.Point; +import android.graphics.Rect; import androidx.test.uiautomator.By; import androidx.test.uiautomator.BySelector; @@ -31,7 +32,8 @@ import com.android.launcher3.ResourceUtils; * All widgets container. */ public final class Widgets extends LauncherInstrumentation.VisibleContainer { - private static final int FLING_SPEED = 1500; + private static final Rect MARGINS = new Rect(100, 100, 100, 100); + private static final int FLING_STEPS = 10; Widgets(LauncherInstrumentation launcher) { super(launcher); @@ -46,11 +48,7 @@ public final class Widgets extends LauncherInstrumentation.VisibleContainer { "want to fling forward in widgets")) { LauncherInstrumentation.log("Widgets.flingForward enter"); final UiObject2 widgetsContainer = verifyActiveContainer(); - widgetsContainer.setGestureMargins(0, 0, 0, - ResourceUtils.getNavbarSize(ResourceUtils.NAVBAR_BOTTOM_GESTURE_SIZE, - mLauncher.getResources()) + 1); - widgetsContainer.fling(Direction.DOWN, - (int) (FLING_SPEED * mLauncher.getDisplayDensity())); + mLauncher.scroll(widgetsContainer, Direction.DOWN, 1f, MARGINS, FLING_STEPS); try (LauncherInstrumentation.Closable c1 = mLauncher.addContextLayer("flung forward")) { verifyActiveContainer(); } @@ -66,10 +64,7 @@ public final class Widgets extends LauncherInstrumentation.VisibleContainer { "want to fling backwards in widgets")) { LauncherInstrumentation.log("Widgets.flingBackward enter"); final UiObject2 widgetsContainer = verifyActiveContainer(); - widgetsContainer.setGestureMargin(100); - widgetsContainer.fling(Direction.UP, - (int) (FLING_SPEED * mLauncher.getDisplayDensity())); - mLauncher.waitForIdle(); + mLauncher.scroll(widgetsContainer, Direction.UP, 1f, MARGINS, FLING_STEPS); try (LauncherInstrumentation.Closable c1 = mLauncher.addContextLayer("flung back")) { verifyActiveContainer(); } @@ -82,7 +77,7 @@ public final class Widgets extends LauncherInstrumentation.VisibleContainer { return LauncherInstrumentation.ContainerType.WIDGETS; } - public Widget getWidget(String label) { + public Widget getWidget(String labelText) { final int margin = ResourceUtils.getNavbarSize( ResourceUtils.NAVBAR_BOTTOM_GESTURE_SIZE, mLauncher.getResources()) + 1; final UiObject2 widgetsContainer = verifyActiveContainer(); @@ -91,17 +86,24 @@ public final class Widgets extends LauncherInstrumentation.VisibleContainer { final Point displaySize = mLauncher.getRealDisplaySize(); int i = 0; - final BySelector selector = By. - clazz("com.android.launcher3.widget.WidgetCell"). - hasDescendant(By.text(label)); + final BySelector selector = By.clazz("android.widget.TextView").text(labelText); for (; ; ) { - final UiObject2 widget = mLauncher.tryWaitForLauncherObject(selector, 300); - if (widget != null && widget.getVisibleBounds().bottom <= displaySize.y - margin) { - return new Widget(mLauncher, widget); + final UiObject2 label = mLauncher.tryWaitForLauncherObject(selector, 300); + if (label != null) { + final UiObject2 widget = label.getParent().getParent(); + mLauncher.assertEquals( + "View is not WidgetCell", + "com.android.launcher3.widget.WidgetCell", + widget.getClassName()); + + if (widget.getVisibleBounds().bottom <= displaySize.y - margin) { + return new Widget(mLauncher, widget); + } } + if (++i > 40) fail("Too many attempts"); - widgetsContainer.scroll(Direction.DOWN, 1f); + mLauncher.scroll(widgetsContainer, Direction.DOWN, 0.8f, MARGINS, 50); } } } diff --git a/tests/tapl/com/android/launcher3/tapl/Workspace.java b/tests/tapl/com/android/launcher3/tapl/Workspace.java index 639902fa0..510ea1409 100644 --- a/tests/tapl/com/android/launcher3/tapl/Workspace.java +++ b/tests/tapl/com/android/launcher3/tapl/Workspace.java @@ -21,6 +21,7 @@ import static com.android.launcher3.testing.TestProtocol.ALL_APPS_STATE_ORDINAL; import static junit.framework.TestCase.assertTrue; import android.graphics.Point; +import android.graphics.Rect; import android.os.SystemClock; import android.view.KeyEvent; import android.view.MotionEvent; @@ -40,6 +41,7 @@ public final class Workspace extends Home { private static final float FLING_SPEED = LauncherInstrumentation.isAvd() ? 1500.0F : 3500.0F; private static final int DRAG_DURACTION = 2000; + private static final int FLING_STEPS = 10; private final UiObject2 mHotseat; Workspace(LauncherInstrumentation launcher) { @@ -180,9 +182,9 @@ public final class Workspace extends Home { */ public void flingForward() { final UiObject2 workspace = verifyActiveContainer(); - workspace.setGestureMargins(0, 0, mLauncher.getEdgeSensitivityWidth(), 0); - workspace.fling(Direction.RIGHT, (int) (FLING_SPEED * mLauncher.getDisplayDensity())); - mLauncher.waitForIdle(); + mLauncher.scroll(workspace, Direction.RIGHT, 1f, + new Rect(0, 0, mLauncher.getEdgeSensitivityWidth(), 0), + FLING_STEPS); verifyActiveContainer(); } @@ -192,9 +194,9 @@ public final class Workspace extends Home { */ public void flingBackward() { final UiObject2 workspace = verifyActiveContainer(); - workspace.setGestureMargins(mLauncher.getEdgeSensitivityWidth(), 0, 0, 0); - workspace.fling(Direction.LEFT, (int) (FLING_SPEED * mLauncher.getDisplayDensity())); - mLauncher.waitForIdle(); + mLauncher.scroll(workspace, Direction.LEFT, 1f, + new Rect(mLauncher.getEdgeSensitivityWidth(), 0, 0, 0), + FLING_STEPS); verifyActiveContainer(); } |