diff --git a/Android.bp b/Android.bp index 60ef5b1ab7..bab994add5 100644 --- a/Android.bp +++ b/Android.bp @@ -258,6 +258,10 @@ android_library { "go/res", "go/quickstep/res", ], + // Note the ordering here is important when it comes to resource + // overriding. We want the most specific resource overrides defined + // in QuickstepResLib to take precendece, so it should be the final + // dependency. See b/205278434 for how this can go wrong. static_libs: [ "Launcher3CommonDepsLib", "QuickstepResLib", @@ -283,11 +287,15 @@ android_library { libs: [ "framework-statsd", ], + // Note the ordering here is important when it comes to resource + // overriding. We want the most specific resource overrides defined + // in QuickstepResLib to take precendece, so it should be the final + // dependency. See b/208647810 for how this can go wrong. static_libs: [ - "QuickstepResLib", "SystemUI-statsd", "SystemUISharedLib", "Launcher3CommonDepsLib", + "QuickstepResLib", ], manifest: "quickstep/AndroidManifest.xml", platform_apis: true, diff --git a/quickstep/res/layout/overview_actions_container.xml b/quickstep/res/layout/overview_actions_container.xml index dd8afc22e0..1c7b5099a8 100644 --- a/quickstep/res/layout/overview_actions_container.xml +++ b/quickstep/res/layout/overview_actions_container.xml @@ -51,7 +51,6 @@ style="@style/OverviewActionButton" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:drawableStart="@drawable/ic_split_screen" android:text="@string/action_split" android:theme="@style/ThemeControlHighlightWorkspaceColor" android:visibility="gone" /> diff --git a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java index c9cbba1330..1a901f1271 100644 --- a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java +++ b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java @@ -55,6 +55,7 @@ import android.animation.AnimatorListenerAdapter; import android.animation.AnimatorSet; import android.animation.ValueAnimator; import android.annotation.TargetApi; +import android.app.Activity; import android.app.ActivityManager; import android.content.Context; import android.content.Intent; @@ -96,6 +97,7 @@ import com.android.quickstep.GestureState.GestureEndTarget; import com.android.quickstep.RemoteTargetGluer.RemoteTargetHandle; import com.android.quickstep.util.ActiveGestureLog; import com.android.quickstep.util.ActivityInitListener; +import com.android.launcher3.util.ActivityLifecycleCallbacksAdapter; import com.android.quickstep.util.AnimatorControllerWithResistance; import com.android.quickstep.util.InputConsumerProxy; import com.android.quickstep.util.InputProxyHandlerFactory; @@ -153,6 +155,17 @@ public abstract class AbsSwipeUpHandler, protected MultiStateCallback mStateCallback; protected boolean mCanceled; private boolean mRecentsViewScrollLinked = false; + private final ActivityLifecycleCallbacksAdapter mLifecycleCallbacks = + new ActivityLifecycleCallbacksAdapter() { + @Override + public void onActivityDestroyed(Activity activity) { + if (mActivity != activity) { + return; + } + mRecentsView = null; + mActivity = null; + } + }; private static int getFlagForIndex(int index, String name) { if (DEBUG_STATES) { @@ -416,6 +429,7 @@ public abstract class AbsSwipeUpHandler, setupRecentsViewUi(); linkRecentsViewScroll(); + mActivity.registerActivityLifecycleCallbacks(mLifecycleCallbacks); return true; } @@ -1542,6 +1556,9 @@ public abstract class AbsSwipeUpHandler, private void reset() { mStateCallback.setStateOnUiThread(STATE_HANDLER_INVALIDATED); + if (mActivity != null) { + mActivity.unregisterActivityLifecycleCallbacks(mLifecycleCallbacks); + } } /** diff --git a/quickstep/src/com/android/quickstep/LauncherSwipeHandlerV2.java b/quickstep/src/com/android/quickstep/LauncherSwipeHandlerV2.java index 8a30aad90a..5541a46524 100644 --- a/quickstep/src/com/android/quickstep/LauncherSwipeHandlerV2.java +++ b/quickstep/src/com/android/quickstep/LauncherSwipeHandlerV2.java @@ -115,8 +115,6 @@ public class LauncherSwipeHandlerV2 extends } private HomeAnimationFactory createIconHomeAnimationFactory(View workspaceView) { - final ResourceProvider rp = DynamicResource.provider(mActivity); - final float transY = dpToPx(rp.getFloat(R.dimen.swipe_up_trans_y_dp)); RectF iconLocation = new RectF(); FloatingIconView floatingIconView = getFloatingIconView(mActivity, workspaceView, true /* hideOriginal */, iconLocation, false /* isOpening */); @@ -127,19 +125,15 @@ public class LauncherSwipeHandlerV2 extends return new FloatingViewHomeAnimationFactory(floatingIconView) { - // There is a delay in loading the icon, so we need to keep the window - // opaque until it is ready. - private boolean mIsFloatingIconReady = false; - @Nullable @Override protected View getViewIgnoredInWorkspaceRevealAnimation() { return workspaceView; } + @NonNull @Override public RectF getWindowTargetRect() { - super.getWindowTargetRect(); return iconLocation; } @@ -151,15 +145,6 @@ public class LauncherSwipeHandlerV2 extends floatingIconView.setFastFinishRunnable(anim::end); } - @Override - public boolean keepWindowOpaque() { - if (mIsFloatingIconReady || floatingIconView.isVisibleToUser()) { - mIsFloatingIconReady = true; - return false; - } - return true; - } - @Override public void update(RectF currentRect, float progress, float radius) { super.update(currentRect, progress, radius); @@ -214,11 +199,6 @@ public class LauncherSwipeHandlerV2 extends floatingWidgetView.setFastFinishRunnable(anim::end); } - @Override - public boolean keepWindowOpaque() { - return false; - } - @Override public void update(RectF currentRect, float progress, float radius) { super.update(currentRect, progress, radius); diff --git a/quickstep/src/com/android/quickstep/SwipeUpAnimationLogic.java b/quickstep/src/com/android/quickstep/SwipeUpAnimationLogic.java index b36cb0afea..8e9b668c15 100644 --- a/quickstep/src/com/android/quickstep/SwipeUpAnimationLogic.java +++ b/quickstep/src/com/android/quickstep/SwipeUpAnimationLogic.java @@ -183,8 +183,6 @@ public abstract class SwipeUpAnimationLogic implements public void setAnimation(RectFSpringAnim anim) { } - public boolean keepWindowOpaque() { return false; } - public void update(RectF currentRect, float progress, float radius) { } public void onCancel() { } @@ -338,9 +336,6 @@ public abstract class SwipeUpAnimationLogic implements mMatrix.setRectToRect(mCropRectF, mWindowCurrentRect, ScaleToFit.FILL); float cornerRadius = Utilities.mapRange(progress, mStartRadius, mEndRadius); float alpha = mAnimationFactory.getWindowAlpha(progress); - if (mAnimationFactory.keepWindowOpaque()) { - alpha = 1f; - } mLocalTransformParams .setTargetAlpha(alpha) .setCornerRadius(cornerRadius); diff --git a/quickstep/src/com/android/quickstep/TaskViewUtils.java b/quickstep/src/com/android/quickstep/TaskViewUtils.java index e77ec78a0c..97fc6d7000 100644 --- a/quickstep/src/com/android/quickstep/TaskViewUtils.java +++ b/quickstep/src/com/android/quickstep/TaskViewUtils.java @@ -316,7 +316,7 @@ public final class TaskViewUtils { mt[i] = localMt; Matrix localMti = new Matrix(); - localMti.invert(localMt); + localMt.invert(localMti); mti[i] = localMti; } diff --git a/quickstep/src/com/android/quickstep/views/GroupedTaskView.java b/quickstep/src/com/android/quickstep/views/GroupedTaskView.java index 9311261624..b215ef1f54 100644 --- a/quickstep/src/com/android/quickstep/views/GroupedTaskView.java +++ b/quickstep/src/com/android/quickstep/views/GroupedTaskView.java @@ -249,7 +249,7 @@ public class GroupedTaskView extends TaskView { boolean isRtl = getLayoutDirection() == LAYOUT_DIRECTION_RTL; getPagedOrientationHandler().setSplitIconParams(mIconView, mIconView2, - taskIconHeight, mSnapshotView.getWidth(), mSnapshotView.getHeight(), + taskIconHeight, mSnapshotView.getMeasuredWidth(), mSnapshotView.getMeasuredHeight(), isRtl, deviceProfile, mSplitBoundsConfig); } diff --git a/quickstep/src/com/android/quickstep/views/OverviewActionsView.java b/quickstep/src/com/android/quickstep/views/OverviewActionsView.java index b6bf59f981..81c07a6a64 100644 --- a/quickstep/src/com/android/quickstep/views/OverviewActionsView.java +++ b/quickstep/src/com/android/quickstep/views/OverviewActionsView.java @@ -22,6 +22,7 @@ import android.graphics.Rect; import android.util.AttributeSet; import android.view.View; import android.view.View.OnClickListener; +import android.widget.Button; import android.widget.FrameLayout; import androidx.annotation.IntDef; @@ -80,7 +81,7 @@ public class OverviewActionsView extends FrameLayo private static final int INDEX_HIDDEN_FLAGS_ALPHA = 3; private final MultiValueAlpha mMultiValueAlpha; - private View mSplitButton; + private Button mSplitButton; @ActionsHiddenFlags private int mHiddenFlags; @@ -215,6 +216,10 @@ public class OverviewActionsView extends FrameLayo mDp = dp; updateVerticalMargin(SysUINavigationMode.getMode(getContext())); requestLayout(); + + mSplitButton.setCompoundDrawablesWithIntrinsicBounds( + (dp.isLandscape ? R.drawable.ic_split_horizontal : R.drawable.ic_split_vertical), + 0, 0, 0); } public void setSplitButtonVisible(boolean visible) { diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java index 3020dd905d..2ad586d2f2 100644 --- a/quickstep/src/com/android/quickstep/views/RecentsView.java +++ b/quickstep/src/com/android/quickstep/views/RecentsView.java @@ -1041,6 +1041,17 @@ public abstract class RecentsView= start && taskEnd <= end; + } + /** * Returns true if the task is in expected scroll position. * @@ -4853,6 +4873,62 @@ public abstract class RecentsView= 0) { + // Find the next page that is not fully visible. + TaskView taskView = getTaskViewAt(targetPage); + while ((taskView == null || isTaskViewFullyVisible(taskView)) && targetPage - 1 >= 0) { + taskView = getTaskViewAt(--targetPage); + } + // Target a scroll where targetPage is on left of screen but still fully visible. + int lastTaskEnd = (mIsRtl + ? mLastComputedGridSize.left + : mLastComputedGridSize.right) + + (mIsRtl ? mPageSpacing : -mPageSpacing); + int normalTaskEnd = mIsRtl + ? mLastComputedGridTaskSize.left + : mLastComputedGridTaskSize.right; + int targetScroll = getScrollForPage(targetPage) + normalTaskEnd - lastTaskEnd; + // Find a page that is close to targetScroll while not over it. + while (targetPage - 1 >= 0 + && (mIsRtl + ? getScrollForPage(targetPage - 1) < targetScroll + : getScrollForPage(targetPage - 1) > targetScroll)) { + targetPage--; + } + snapToPage(targetPage); + return true; + } + + return mAllowOverScroll; + } + + @Override + public boolean scrollRight() { + if (!showAsGrid()) { + return super.scrollRight(); + } + + int targetPage = getNextPage(); + if (targetPage < getChildCount()) { + // Find the next page that is not fully visible. + TaskView taskView = getTaskViewAt(targetPage); + while ((taskView != null && isTaskViewFullyVisible(taskView)) + && targetPage + 1 < getChildCount()) { + taskView = getTaskViewAt(++targetPage); + } + snapToPage(targetPage); + return true; + } + return mAllowOverScroll; + } + @Override protected void onScrollChanged(int l, int t, int oldl, int oldt) { super.onScrollChanged(l, t, oldl, oldt); diff --git a/res/drawable/ic_split_horizontal.xml b/res/drawable/ic_split_horizontal.xml new file mode 100644 index 0000000000..ee710d0797 --- /dev/null +++ b/res/drawable/ic_split_horizontal.xml @@ -0,0 +1,9 @@ + + + diff --git a/res/drawable/ic_split_left.xml b/res/drawable/ic_split_left.xml new file mode 100644 index 0000000000..fc9f699c29 --- /dev/null +++ b/res/drawable/ic_split_left.xml @@ -0,0 +1,9 @@ + + + diff --git a/res/drawable/ic_split_right.xml b/res/drawable/ic_split_right.xml new file mode 100644 index 0000000000..cc156225e8 --- /dev/null +++ b/res/drawable/ic_split_right.xml @@ -0,0 +1,9 @@ + + + diff --git a/res/drawable/ic_split_top.xml b/res/drawable/ic_split_top.xml new file mode 100644 index 0000000000..f8c15bd44d --- /dev/null +++ b/res/drawable/ic_split_top.xml @@ -0,0 +1,9 @@ + + + diff --git a/res/drawable/ic_split_vertical.xml b/res/drawable/ic_split_vertical.xml new file mode 100644 index 0000000000..9bc97851ab --- /dev/null +++ b/res/drawable/ic_split_vertical.xml @@ -0,0 +1,9 @@ + + + diff --git a/res/values/dimens.xml b/res/values/dimens.xml index c689942ada..2dfd5cc51a 100644 --- a/res/values/dimens.xml +++ b/res/values/dimens.xml @@ -300,6 +300,7 @@ 3dp 12sp 14sp + 504dp 10dp diff --git a/src/com/android/launcher3/PagedView.java b/src/com/android/launcher3/PagedView.java index 1ce7ebec4d..2c14f07779 100644 --- a/src/com/android/launcher3/PagedView.java +++ b/src/com/android/launcher3/PagedView.java @@ -1749,20 +1749,23 @@ public abstract class PagedView extends ViewGrou public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) { super.onInitializeAccessibilityNodeInfo(info); final boolean pagesFlipped = isPageOrderFlipped(); - int offset = (mAllowOverScroll ? 0 : 1); - info.setScrollable(getPageCount() > offset); - if (getCurrentPage() < getPageCount() - offset) { + info.setScrollable(getPageCount() > 0); + int primaryScroll = mOrientationHandler.getPrimaryScroll(this); + if (getCurrentPage() < getPageCount() - getPanelCount() + || (getCurrentPage() == getPageCount() - getPanelCount() + && primaryScroll != getScrollForPage(getPageCount() - getPanelCount()))) { info.addAction(pagesFlipped ? - AccessibilityNodeInfo.AccessibilityAction.ACTION_SCROLL_BACKWARD - : AccessibilityNodeInfo.AccessibilityAction.ACTION_SCROLL_FORWARD); + AccessibilityNodeInfo.AccessibilityAction.ACTION_SCROLL_BACKWARD + : AccessibilityNodeInfo.AccessibilityAction.ACTION_SCROLL_FORWARD); info.addAction(mIsRtl ? AccessibilityNodeInfo.AccessibilityAction.ACTION_PAGE_LEFT : AccessibilityNodeInfo.AccessibilityAction.ACTION_PAGE_RIGHT); } - if (getCurrentPage() >= offset) { + if (getCurrentPage() > 0 + || (getCurrentPage() == 0 && primaryScroll != getScrollForPage(0))) { info.addAction(pagesFlipped ? - AccessibilityNodeInfo.AccessibilityAction.ACTION_SCROLL_FORWARD - : AccessibilityNodeInfo.AccessibilityAction.ACTION_SCROLL_BACKWARD); + AccessibilityNodeInfo.AccessibilityAction.ACTION_SCROLL_FORWARD + : AccessibilityNodeInfo.AccessibilityAction.ACTION_SCROLL_BACKWARD); info.addAction(mIsRtl ? AccessibilityNodeInfo.AccessibilityAction.ACTION_PAGE_RIGHT : AccessibilityNodeInfo.AccessibilityAction.ACTION_PAGE_LEFT); @@ -1807,16 +1810,16 @@ public abstract class PagedView extends ViewGrou } break; case android.R.id.accessibilityActionPageRight: { if (!mIsRtl) { - return scrollRight(); + return scrollRight(); } else { - return scrollLeft(); + return scrollLeft(); } } case android.R.id.accessibilityActionPageLeft: { if (!mIsRtl) { - return scrollLeft(); + return scrollLeft(); } else { - return scrollRight(); + return scrollRight(); } } } diff --git a/src/com/android/launcher3/touch/LandscapePagedViewHandler.java b/src/com/android/launcher3/touch/LandscapePagedViewHandler.java index c2552250df..0c390679d9 100644 --- a/src/com/android/launcher3/touch/LandscapePagedViewHandler.java +++ b/src/com/android/launcher3/touch/LandscapePagedViewHandler.java @@ -357,7 +357,7 @@ public class LandscapePagedViewHandler implements PagedOrientationHandler { public List getSplitPositionOptions(DeviceProfile dp) { // Add "left" side of phone which is actually the top return Collections.singletonList(new SplitPositionOption( - R.drawable.ic_split_screen, R.string.split_screen_position_left, + R.drawable.ic_split_left, R.string.split_screen_position_left, STAGE_POSITION_TOP_OR_LEFT, STAGE_TYPE_MAIN)); } diff --git a/src/com/android/launcher3/touch/PortraitPagedViewHandler.java b/src/com/android/launcher3/touch/PortraitPagedViewHandler.java index e69944abef..cb1ba7d402 100644 --- a/src/com/android/launcher3/touch/PortraitPagedViewHandler.java +++ b/src/com/android/launcher3/touch/PortraitPagedViewHandler.java @@ -370,28 +370,27 @@ public class PortraitPagedViewHandler implements PagedOrientationHandler { public List getSplitPositionOptions(DeviceProfile dp) { List options = new ArrayList<>(1); // Add both left and right options if we're in tablet mode - // TODO: Add in correct icons if (dp.isTablet && dp.isLandscape) { options.add(new SplitPositionOption( - R.drawable.ic_split_screen, R.string.split_screen_position_right, + R.drawable.ic_split_right, R.string.split_screen_position_right, STAGE_POSITION_BOTTOM_OR_RIGHT, STAGE_TYPE_MAIN)); options.add(new SplitPositionOption( - R.drawable.ic_split_screen, R.string.split_screen_position_left, + R.drawable.ic_split_left, R.string.split_screen_position_left, STAGE_POSITION_TOP_OR_LEFT, STAGE_TYPE_MAIN)); } else { if (dp.isSeascape()) { // Add left/right options options.add(new SplitPositionOption( - R.drawable.ic_split_screen, R.string.split_screen_position_right, + R.drawable.ic_split_right, R.string.split_screen_position_right, STAGE_POSITION_BOTTOM_OR_RIGHT, STAGE_TYPE_MAIN)); } else if (dp.isLandscape) { options.add(new SplitPositionOption( - R.drawable.ic_split_screen, R.string.split_screen_position_left, + R.drawable.ic_split_left, R.string.split_screen_position_left, STAGE_POSITION_TOP_OR_LEFT, STAGE_TYPE_MAIN)); } else { // Only add top option options.add(new SplitPositionOption( - R.drawable.ic_split_screen, R.string.split_screen_position_top, + R.drawable.ic_split_top, R.string.split_screen_position_top, STAGE_POSITION_TOP_OR_LEFT, STAGE_TYPE_MAIN)); } } @@ -542,17 +541,18 @@ public class PortraitPagedViewHandler implements PagedOrientationHandler { if (deviceProfile.isLandscape) { primaryIconParams.gravity = TOP | START; - primaryIconView.setTranslationX(primarySnapshotWidth - primaryIconView.getWidth()); + primaryIconView.setTranslationX( + primarySnapshotWidth - primaryIconView.getMeasuredWidth()); primaryIconView.setTranslationY(0); secondaryIconParams.gravity = TOP | START; secondaryIconView.setTranslationX(primarySnapshotWidth + dividerBar); } else { primaryIconParams.gravity = TOP | CENTER_HORIZONTAL; - primaryIconView.setTranslationX(-(primaryIconView.getWidth()) / 2f); + primaryIconView.setTranslationX(-(primaryIconView.getMeasuredWidth()) / 2f); primaryIconView.setTranslationY(0); secondaryIconParams.gravity = TOP | CENTER_HORIZONTAL; - secondaryIconView.setTranslationX(secondaryIconView.getWidth() / 2f); + secondaryIconView.setTranslationX(secondaryIconView.getMeasuredWidth() / 2f); } secondaryIconView.setTranslationY(0); primaryIconView.setLayoutParams(primaryIconParams); diff --git a/src/com/android/launcher3/touch/SeascapePagedViewHandler.java b/src/com/android/launcher3/touch/SeascapePagedViewHandler.java index 539e3f82c5..ce2e13644d 100644 --- a/src/com/android/launcher3/touch/SeascapePagedViewHandler.java +++ b/src/com/android/launcher3/touch/SeascapePagedViewHandler.java @@ -115,7 +115,7 @@ public class SeascapePagedViewHandler extends LandscapePagedViewHandler { public List getSplitPositionOptions(DeviceProfile dp) { // Add "right" option which is actually the top return Collections.singletonList(new SplitPositionOption( - R.drawable.ic_split_screen, R.string.split_screen_position_right, + R.drawable.ic_split_right, R.string.split_screen_position_right, STAGE_POSITION_TOP_OR_LEFT, STAGE_TYPE_MAIN)); } diff --git a/src/com/android/launcher3/util/ActivityLifecycleCallbacksAdapter.java b/src/com/android/launcher3/util/ActivityLifecycleCallbacksAdapter.java new file mode 100644 index 0000000000..baa8418242 --- /dev/null +++ b/src/com/android/launcher3/util/ActivityLifecycleCallbacksAdapter.java @@ -0,0 +1,29 @@ +package com.android.launcher3.util; + +import android.app.Activity; +import android.app.Application.ActivityLifecycleCallbacks; +import android.os.Bundle; + +public interface ActivityLifecycleCallbacksAdapter extends ActivityLifecycleCallbacks { + + default void onActivityCreated(Activity activity, Bundle bundle) { + } + + default void onActivityDestroyed(Activity activity) { + } + + default void onActivityPaused(Activity activity) { + } + + default void onActivityResumed(Activity activity) { + } + + default void onActivitySaveInstanceState(Activity activity, Bundle bundle) { + } + + default void onActivityStarted(Activity activity) { + } + + default void onActivityStopped(Activity activity) { + } +} diff --git a/src/com/android/launcher3/views/Snackbar.java b/src/com/android/launcher3/views/Snackbar.java index f945819c8d..e582114fc9 100644 --- a/src/com/android/launcher3/views/Snackbar.java +++ b/src/com/android/launcher3/views/Snackbar.java @@ -88,9 +88,14 @@ public class Snackbar extends AbstractFloatingView { int maxMarginLeftRight = res.getDimensionPixelSize(R.dimen.snackbar_max_margin_left_right); int minMarginLeftRight = res.getDimensionPixelSize(R.dimen.snackbar_min_margin_left_right); int marginBottom = res.getDimensionPixelSize(R.dimen.snackbar_margin_bottom); + int absoluteMaxWidth = res.getDimensionPixelSize(R.dimen.snackbar_max_width); Rect insets = activity.getDeviceProfile().getInsets(); - int maxWidth = dragLayer.getWidth() - minMarginLeftRight * 2 - insets.left - insets.right; - int minWidth = dragLayer.getWidth() - maxMarginLeftRight * 2 - insets.left - insets.right; + int maxWidth = Math.min( + dragLayer.getWidth() - minMarginLeftRight * 2 - insets.left - insets.right, + absoluteMaxWidth); + int minWidth = Math.min( + dragLayer.getWidth() - maxMarginLeftRight * 2 - insets.left - insets.right, + absoluteMaxWidth); params.width = minWidth; params.setMargins(0, 0, 0, marginBottom + insets.bottom);