diff --git a/quickstep/res/layout/taskbar.xml b/quickstep/res/layout/taskbar.xml index dfa17d6cc4..c0e0862588 100644 --- a/quickstep/res/layout/taskbar.xml +++ b/quickstep/res/layout/taskbar.xml @@ -36,18 +36,27 @@ android:layout_height="wrap_content" android:layout_gravity="bottom" > + + + android:layout_gravity="end"/> "सुझाए गए ऐप्लिकेशन की सुविधा बंद है" "सुझाया गया ऐप्लिकेशन: %1$s" "पक्का करें कि आप स्क्रीन की दाईं या बाईं ओर के बिल्कुल किनारे से स्वाइप कर रहे हों." - "पक्का करें कि आप स्क्रीन के दाएं या बाएं किनारे से, स्क्रीन के बीच तक स्वाइप करें और फिर अपनी उंगली उठा लें." + "स्क्रीन के दाएं या बाएं किनारे से स्क्रीन के बीच तक स्वाइप करें और अपनी उंगली उठा लें." "आपने स्क्रीन के दाएं किनारे से स्वाइप करके, पिछली स्क्रीन पर वापस जाने का तरीका सीख लिया है. अब, एक ऐप से दूसरे ऐप पर जाने का तरीका सीखें." "आपने पेज पर पीछे ले जाने वाले हाथ के जेस्चर (हाव-भाव) के बारे में जान लिया है." "देखे लें कि आप स्क्रीन पर बिल्कुल नीचे तक स्वाइप न कर रहे हों." diff --git a/quickstep/res/values-ja/strings.xml b/quickstep/res/values-ja/strings.xml index 3ee1b99b08..9c2adefecd 100644 --- a/quickstep/res/values-ja/strings.xml +++ b/quickstep/res/values-ja/strings.xml @@ -48,16 +48,16 @@ "右端または左端からスワイプしてください。" "画面の右端または左端から中央に向かってスワイプし、指を離してください。" "右側からスワイプして前の画面に戻る方法を学習しました。次は、アプリを切り替える方法を覚えましょう。" - "「戻る」操作を完了しました。" + "「戻る」操作を学習しました。" "スワイプする際は画面の下部に近づきすぎないようにしましょう。" "「戻る」操作の感度を変更するには [設定] に移動します" - "スワイプで戻りましょう" + "スワイプで戻る" "直前の画面に戻るには、画面の左端または右端から中央に向かってスワイプします。" "画面の下端から上にスワイプしてください。" "指を離す前にいったん止めないでください。" "まっすぐ上にスワイプしてください。" - "「ホームに戻る」操作を完了しました。次は、前の画面に戻る方法を覚えましょう。" - "「ホームに戻る」操作を完了しました。" + "「ホームに戻る」操作を学習しました。次は、前の画面に戻る方法を覚えましょう。" + "「ホームに戻る」操作を学習しました。" "スワイプでホームに戻る" "画面を下から上にスワイプします。この操作でいつでもホーム画面に戻れます。" "画面の下端から上にスワイプしてください。" @@ -65,7 +65,7 @@ "まっすぐ上にスワイプしてから、いったん指を止めてください。" "主な操作方法を覚えました。操作を OFF にするには、設定に移動してください。" "「アプリを切り替える」操作を完了しました。" - "スワイプでアプリを切り替え" + "スワイプでアプリを切り替える" "アプリを切り替えるには、画面を下から上にスワイプして長押しし、指を離します。" "設定完了" "完了" @@ -81,7 +81,7 @@ "スクリーンショット" "この操作はアプリまたは組織で許可されていません" "操作チュートリアルをスキップしますか?" - "これは後から %1$s アプリで確認できます" + "チュートリアルは後から %1$s アプリで確認できます" "キャンセル" "スキップ" diff --git a/quickstep/res/values-mn/strings.xml b/quickstep/res/values-mn/strings.xml index dfa98e7432..79fbca6e49 100644 --- a/quickstep/res/values-mn/strings.xml +++ b/quickstep/res/values-mn/strings.xml @@ -47,7 +47,7 @@ "Таамаглаж буй апп: %1$s" "Та баруун зах эсвэл зүүн захын булангаас шударна уу." "Та баруун эсвэл зүүн булангаас дэлгэцийн дунд хэсэг хүртэл шударч, суллана уу." - "Та буцахын тулд баруунаас хэрхэн шудрахыг мэдэж авлаа Дараа нь аппыг хэрхэн сэлгэхийг мэдэж аваарай." + "Та буцахын тулд баруунаас хэрхэн шудрахыг мэдэж авлаа. Дараа нь аппууд хооронд хэрхэн сэлгэхийг мэдэж аваарай." "Та буцах зангааг гүйцэтгэлээ." "Та дэлгэцийн доод хэсэгтэй хэт ойр бүү шудраарай." "Буцах зангааны мэдрэгшлийг өөрчлөх бол Тохиргоо руу очно уу" diff --git a/quickstep/res/values-ne/strings.xml b/quickstep/res/values-ne/strings.xml index 4428cec16b..d873795edf 100644 --- a/quickstep/res/values-ne/strings.xml +++ b/quickstep/res/values-ne/strings.xml @@ -23,7 +23,7 @@ "फ्रिफर्म" "हालसालैको कुनै पनि वस्तु छैन" "एपको उपयोगका सेटिङहरू" - "सबै खाली गर्नुहोस्" + "सबै मेटाउनुहोस्" "हालसालैका एपहरू" "%1$s, %2$s" "< १ मिनेट" diff --git a/quickstep/res/values-th/strings.xml b/quickstep/res/values-th/strings.xml index 96e9060e7f..52b2878564 100644 --- a/quickstep/res/values-th/strings.xml +++ b/quickstep/res/values-th/strings.xml @@ -81,7 +81,7 @@ "ภาพหน้าจอ" "แอปหรือองค์กรของคุณไม่อนุญาตการดำเนินการนี้" "ข้ามบทแนะนำการนำทางไหม" - "คุณดูบทแนะนำนี้ได้ภายหลังในแอป %1$s" + "คุณดูบทแนะนำนี้ได้ภายหลังในแอป \"%1$s\"" "ยกเลิก" "ข้าม" diff --git a/quickstep/res/values-vi/strings.xml b/quickstep/res/values-vi/strings.xml index 6c192b28a6..7bd0c70420 100644 --- a/quickstep/res/values-vi/strings.xml +++ b/quickstep/res/values-vi/strings.xml @@ -47,11 +47,11 @@ "Ứng dụng dự đoán: %1$s" "Hãy vuốt từ mép ngoài cùng bên phải hoặc ngoài cùng bên trái." "Hãy vuốt từ mép phải hoặc mép trái tới giữa màn hình rồi thả tay ra." - "Bạn đã tìm hiểu cách vuốt từ mép phải để quay lại. Tiếp theo, hãy tìm hiểu cách chuyển đổi ứng dụng." + "Bạn đã học được cách vuốt từ mép phải để quay lại. Tiếp theo, hãy tìm hiểu cách chuyển đổi ứng dụng." "Bạn đã thực hiện xong cử chỉ quay lại." "Hãy nhớ không được vuốt quá gần phần cuối màn hình." "Để thay đổi độ nhạy của cử chỉ quay lại, hãy vào mục Cài đặt" - "Hãy vuốt để quay lại" + "Vuốt để quay lại" "Để quay lại màn hình gần đây nhất, hãy vuốt từ mép trái hoặc mép phải tới chính giữa màn hình." "Hãy vuốt lên từ mép dưới cùng của màn hình." "Hãy nhớ không được tạm dừng trước khi nhấc ngón tay." @@ -75,7 +75,7 @@ "Hướng dẫn %1$d/%2$d" "Đã hoàn tất!" "Vuốt lên để chuyển đến Màn hình chính" - "Hiện giờ, bạn đã có thể sử dụng điện thoại" + "Vậy là bạn đã sẵn sàng sử dụng điện thoại của mình" "Chế độ cài đặt di chuyển trên hệ thống" "Chia sẻ" "Chụp ảnh màn hình" diff --git a/quickstep/res/values/dimens.xml b/quickstep/res/values/dimens.xml index 1febc88292..f54070e3f3 100644 --- a/quickstep/res/values/dimens.xml +++ b/quickstep/res/values/dimens.xml @@ -70,6 +70,8 @@ 0.97 115dp + 100dp + 16sp 16dp diff --git a/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java b/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java index ebf8fb79d7..2da8a45a3b 100644 --- a/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java +++ b/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java @@ -40,7 +40,6 @@ import static com.android.launcher3.config.FeatureFlags.SEPARATE_RECENTS_ACTIVIT import static com.android.launcher3.dragndrop.DragLayer.ALPHA_INDEX_TRANSITIONS; import static com.android.launcher3.statehandlers.DepthController.DEPTH; import static com.android.launcher3.util.DisplayController.getSingleFrameMs; -import static com.android.quickstep.TaskUtils.taskIsATargetWithMode; import static com.android.quickstep.TaskViewUtils.findTaskViewToLaunch; import static com.android.systemui.shared.system.QuickStepContract.getWindowCornerRadius; import static com.android.systemui.shared.system.QuickStepContract.supportsRoundedCornersOnWindows; @@ -1047,7 +1046,7 @@ public class QuickstepTransitionManager implements OnDeviceProfileChangeListener mLauncherOpenTransition = RemoteAnimationAdapterCompat.buildRemoteTransition( new LauncherAnimationRunner(mHandler, mWallpaperOpenTransitionRunner, false /* startAtFrontOfQueue */)); - mLauncherOpenTransition.addHomeOpenCheck(); + mLauncherOpenTransition.addHomeOpenCheck(mLauncher.getComponentName()); SystemUiProxy.INSTANCE.getNoCreate().registerRemoteTransition(mLauncherOpenTransition); } } diff --git a/quickstep/src/com/android/launcher3/statehandlers/DepthController.java b/quickstep/src/com/android/launcher3/statehandlers/DepthController.java index 82582ee790..370fb8ef7c 100644 --- a/quickstep/src/com/android/launcher3/statehandlers/DepthController.java +++ b/quickstep/src/com/android/launcher3/statehandlers/DepthController.java @@ -100,9 +100,12 @@ public class DepthController implements StateHandler, } }; - private final Consumer mCrossWindowBlurListener = (enabled) -> { - mCrossWindowBlursEnabled = enabled; - dispatchTransactionSurface(); + private final Consumer mCrossWindowBlurListener = new Consumer() { + @Override + public void accept(Boolean enabled) { + mCrossWindowBlursEnabled = enabled; + dispatchTransactionSurface(mDepth); + } }; private final Launcher mLauncher; @@ -189,14 +192,14 @@ public class DepthController implements StateHandler, if (mSurface != surface) { mSurface = surface; if (surface != null) { - dispatchTransactionSurface(); + dispatchTransactionSurface(mDepth); } } } @Override public void setState(LauncherState toState) { - if (mIgnoreStateChangesDuringMultiWindowAnimation) { + if (mSurface == null || mIgnoreStateChangesDuringMultiWindowAnimation) { return; } @@ -204,7 +207,7 @@ public class DepthController implements StateHandler, if (Float.compare(mDepth, toDepth) != 0) { setDepth(toDepth); } else if (toState == LauncherState.OVERVIEW) { - dispatchTransactionSurface(); + dispatchTransactionSurface(mDepth); } } @@ -243,31 +246,36 @@ public class DepthController implements StateHandler, if (Float.compare(mDepth, depthF) == 0) { return; } - mDepth = depthF; - dispatchTransactionSurface(); + if (dispatchTransactionSurface(depthF)) { + mDepth = depthF; + } } - private void dispatchTransactionSurface() { + private boolean dispatchTransactionSurface(float depth) { boolean supportsBlur = BlurUtils.supportsBlursOnWindows(); + if (supportsBlur && (mSurface == null || !mSurface.isValid())) { + return false; + } ensureDependencies(); IBinder windowToken = mLauncher.getRootView().getWindowToken(); if (windowToken != null) { - mWallpaperManager.setWallpaperZoomOut(windowToken, mDepth); + mWallpaperManager.setWallpaperZoomOut(windowToken, depth); } - if (supportsBlur && (mSurface != null && mSurface.isValid())) { + if (supportsBlur) { // We cannot mark the window as opaque in overview because there will be an app window // below the launcher layer, and we need to draw it -- without blurs. boolean isOverview = mLauncher.isInState(LauncherState.OVERVIEW); boolean opaque = mLauncher.getScrimView().isFullyOpaque() && !isOverview; int blur = opaque || isOverview || !mCrossWindowBlursEnabled - || mBlurDisabledForAppLaunch ? 0 : (int) (mDepth * mMaxBlurRadius); + || mBlurDisabledForAppLaunch ? 0 : (int) (depth * mMaxBlurRadius); new SurfaceControl.Transaction() .setBackgroundBlurRadius(mSurface, blur) .setOpaque(mSurface, opaque) .apply(); } + return true; } @Override diff --git a/quickstep/src/com/android/launcher3/taskbar/NavbarButtonsViewController.java b/quickstep/src/com/android/launcher3/taskbar/NavbarButtonsViewController.java index 1edeba0a9d..357dc7bc1e 100644 --- a/quickstep/src/com/android/launcher3/taskbar/NavbarButtonsViewController.java +++ b/quickstep/src/com/android/launcher3/taskbar/NavbarButtonsViewController.java @@ -79,8 +79,10 @@ public class NavbarButtonsViewController { private final TaskbarActivityContext mContext; private final FrameLayout mNavButtonsView; - private final ViewGroup mStartContainer; - private final ViewGroup mEndContainer; + private final ViewGroup mNavButtonContainer; + // Used for IME+A11Y buttons + private final ViewGroup mEndContextualContainer; + private final ViewGroup mStartContextualContainer; // Initialized in init. private TaskbarControllers mControllers; @@ -91,8 +93,9 @@ public class NavbarButtonsViewController { public NavbarButtonsViewController(TaskbarActivityContext context, FrameLayout navButtonsView) { mContext = context; mNavButtonsView = navButtonsView; - mStartContainer = mNavButtonsView.findViewById(R.id.start_nav_buttons); - mEndContainer = mNavButtonsView.findViewById(R.id.end_nav_buttons); + mNavButtonContainer = mNavButtonsView.findViewById(R.id.end_nav_buttons); + mEndContextualContainer = mNavButtonsView.findViewById(R.id.end_contextual_buttons); + mStartContextualContainer = mNavButtonsView.findViewById(R.id.start_contextual_buttons); } /** @@ -114,21 +117,22 @@ public class NavbarButtonsViewController { // IME switcher View imeSwitcherButton = addButton(R.drawable.ic_ime_switcher, BUTTON_IME_SWITCH, - mEndContainer, mControllers.navButtonController, R.id.ime_switcher); + mEndContextualContainer, mControllers.navButtonController, R.id.ime_switcher); mPropertyHolders.add(new StatePropertyHolder(imeSwitcherButton, flags -> ((flags & MASK_IME_SWITCHER_VISIBLE) == MASK_IME_SWITCHER_VISIBLE) && ((flags & FLAG_ROTATION_BUTTON_VISIBLE) == 0) && ((flags & FLAG_A11Y_VISIBLE) == 0))); - mBackButton = addButton(R.drawable.ic_sysbar_back, BUTTON_BACK, - mStartContainer, mControllers.navButtonController, R.id.back); + View imeDownButton = addButton(R.drawable.ic_sysbar_back, BUTTON_BACK, + mStartContextualContainer, mControllers.navButtonController, R.id.back); + imeDownButton.setRotation(Utilities.isRtl(mContext.getResources()) ? 90 : -90); // Rotate when Ime visible - mPropertyHolders.add(new StatePropertyHolder(mBackButton, - flags -> (flags & FLAG_IME_VISIBLE) == 0, View.ROTATION, 0, - Utilities.isRtl(mContext.getResources()) ? 90 : -90)); + mPropertyHolders.add(new StatePropertyHolder(imeDownButton, + flags -> (flags & FLAG_IME_VISIBLE) != 0)); if (mContext.isThreeButtonNav()) { - initButtons(mStartContainer, mEndContainer, mControllers.navButtonController); + initButtons(mNavButtonContainer, mEndContextualContainer, + mControllers.navButtonController); // Animate taskbar background when IME shows mPropertyHolders.add(new StatePropertyHolder( @@ -142,21 +146,18 @@ public class NavbarButtonsViewController { // Rotation button RotationButton rotationButton = new RotationButtonImpl( - addButton(mEndContainer, R.id.rotate_suggestion)); + addButton(mEndContextualContainer, R.id.rotate_suggestion)); rotationButton.hide(); mControllers.rotationButtonController.setRotationButton(rotationButton); } else { mControllers.rotationButtonController.setRotationButton(new RotationButton() {}); - // Show when IME is visible - mPropertyHolders.add(new StatePropertyHolder(mBackButton, - flags -> (flags & FLAG_IME_VISIBLE) != 0)); } applyState(); mPropertyHolders.forEach(StatePropertyHolder::endAnimation); } - private void initButtons(ViewGroup startContainer, ViewGroup endContainer, + private void initButtons(ViewGroup navContainer, ViewGroup endContainer, TaskbarNavButtonController navButtonController) { // Hide when keyguard is showing, show when bouncer is showing @@ -164,14 +165,19 @@ public class NavbarButtonsViewController { flags -> (flags & FLAG_KEYGUARD_VISIBLE) == 0 || (flags & FLAG_ONLY_BACK_FOR_BOUNCER_VISIBLE) != 0)); + mBackButton = addButton(R.drawable.ic_sysbar_back, BUTTON_BACK, + mNavButtonContainer, mControllers.navButtonController, R.id.back); + mPropertyHolders.add(new StatePropertyHolder(mBackButton, + flags -> (flags & FLAG_IME_VISIBLE) == 0)); + // home and recents buttons - View homeButton = addButton(R.drawable.ic_sysbar_home, BUTTON_HOME, startContainer, + View homeButton = addButton(R.drawable.ic_sysbar_home, BUTTON_HOME, navContainer, navButtonController, R.id.home); mPropertyHolders.add(new StatePropertyHolder(homeButton, flags -> (flags & FLAG_IME_VISIBLE) == 0 && (flags & FLAG_KEYGUARD_VISIBLE) == 0)); View recentsButton = addButton(R.drawable.ic_sysbar_recent, BUTTON_RECENTS, - startContainer, navButtonController, R.id.recent_apps); + navContainer, navButtonController, R.id.recent_apps); mPropertyHolders.add(new StatePropertyHolder(recentsButton, flags -> (flags & FLAG_IME_VISIBLE) == 0 && (flags & FLAG_KEYGUARD_VISIBLE) == 0)); diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java index 6f53f2b60c..a4a92f7567 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java @@ -194,24 +194,30 @@ public class TaskbarView extends FrameLayout implements FolderIcon.FolderIconPar protected void onLayout(boolean changed, int left, int top, int right, int bottom) { int count = getChildCount(); int spaceNeeded = count * (mItemMarginLeftRight * 2 + mIconTouchSize); - int iconStart = (right - left - spaceNeeded) / 2; - int startOffset = ApiWrapper.getHotseatStartOffset(getContext()); - if (startOffset > iconStart) { - int diff = startOffset - iconStart; - iconStart = isLayoutRtl() ? (iconStart - diff) : iconStart + diff; + int navSpaceNeeded = ApiWrapper.getHotseatEndOffset(getContext()); + boolean layoutRtl = isLayoutRtl(); + int iconEnd = right - (right - left - spaceNeeded) / 2; + boolean needMoreSpaceForNav = layoutRtl ? + navSpaceNeeded > (iconEnd - spaceNeeded) : + iconEnd > (right - navSpaceNeeded); + if (needMoreSpaceForNav) { + int offset = layoutRtl ? + navSpaceNeeded - (iconEnd - spaceNeeded) : + (right - navSpaceNeeded) - iconEnd; + iconEnd += offset; } // Layout the children - mIconLayoutBounds.left = iconStart; + mIconLayoutBounds.right = iconEnd; mIconLayoutBounds.top = (bottom - top - mIconTouchSize) / 2; mIconLayoutBounds.bottom = mIconLayoutBounds.top + mIconTouchSize; - for (int i = 0; i < count; i++) { - View child = getChildAt(i); - iconStart += mItemMarginLeftRight; - int iconEnd = iconStart + mIconTouchSize; + for (int i = count; i > 0; i--) { + View child = getChildAt(i - 1); + iconEnd -= mItemMarginLeftRight; + int iconStart = iconEnd - mIconTouchSize; child.layout(iconStart, mIconLayoutBounds.top, iconEnd, mIconLayoutBounds.bottom); - iconStart = iconEnd + mItemMarginLeftRight; + iconEnd = iconStart - mItemMarginLeftRight; } - mIconLayoutBounds.right = iconStart; + mIconLayoutBounds.left = iconEnd; } @Override diff --git a/quickstep/src/com/android/launcher3/uioverrides/ApiWrapper.java b/quickstep/src/com/android/launcher3/uioverrides/ApiWrapper.java index a595f54322..85943b66a6 100644 --- a/quickstep/src/com/android/launcher3/uioverrides/ApiWrapper.java +++ b/quickstep/src/com/android/launcher3/uioverrides/ApiWrapper.java @@ -44,9 +44,9 @@ public class ApiWrapper { } /** - * Returns the minimum space that should be left empty at the start of hotseat + * Returns the minimum space that should be left empty at the end of hotseat */ - public static int getHotseatStartOffset(Context context) { + public static int getHotseatEndOffset(Context context) { if (SysUINavigationMode.INSTANCE.get(context).getMode() == Mode.THREE_BUTTONS) { Resources res = context.getResources(); return 2 * res.getDimensionPixelSize(R.dimen.taskbar_nav_buttons_spacing) diff --git a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java index 9180bd026f..357d407d7a 100644 --- a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java +++ b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java @@ -212,6 +212,8 @@ public abstract class AbsSwipeUpHandler, public static final long RECENTS_ATTACH_DURATION = 300; + private static final float MAX_QUICK_SWITCH_RECENTS_SCALE_PROGRESS = 0.07f; + /** * Used as the page index for logging when we return to the last task at the end of the gesture. */ @@ -252,6 +254,9 @@ public abstract class AbsSwipeUpHandler, private SwipePipToHomeAnimator mSwipePipToHomeAnimator; protected boolean mIsSwipingPipToHome; + // Interpolate RecentsView scale from start of quick switch scroll until this scroll threshold + private final float mQuickSwitchScaleScrollThreshold; + public AbsSwipeUpHandler(Context context, RecentsAnimationDeviceState deviceState, TaskAnimationManager taskAnimationManager, GestureState gestureState, long touchTimeMs, boolean continuingLastGesture, @@ -267,6 +272,8 @@ public abstract class AbsSwipeUpHandler, mTaskAnimationManager = taskAnimationManager; mTouchTimeMs = touchTimeMs; mContinuingLastGesture = continuingLastGesture; + mQuickSwitchScaleScrollThreshold = context.getResources().getDimension( + R.dimen.quick_switch_scaling_scroll_threshold); initAfterSubclassConstructor(); initStateCallbacks(); @@ -539,7 +546,7 @@ public abstract class AbsSwipeUpHandler, @Override public void onMotionPauseDetected() { mHasMotionEverBeenPaused = true; - maybeUpdateRecentsAttachedState(); + maybeUpdateRecentsAttachedState(true/* animate */, true/* moveFocusedTask */); performHapticFeedback(); } @@ -550,18 +557,24 @@ public abstract class AbsSwipeUpHandler, }; } - public void maybeUpdateRecentsAttachedState() { + private void maybeUpdateRecentsAttachedState() { maybeUpdateRecentsAttachedState(true /* animate */); } + private void maybeUpdateRecentsAttachedState(boolean animate) { + maybeUpdateRecentsAttachedState(animate, false /* moveFocusedTask */); + } + /** * Determines whether to show or hide RecentsView. The window is always * synchronized with its corresponding TaskView in RecentsView, so if * RecentsView is shown, it will appear to be attached to the window. * * Note this method has no effect unless the navigation mode is NO_BUTTON. + * @param animate whether to animate when attaching RecentsView + * @param moveFocusedTask whether to move focused task to front when attaching */ - private void maybeUpdateRecentsAttachedState(boolean animate) { + private void maybeUpdateRecentsAttachedState(boolean animate, boolean moveFocusedTask) { if (!mDeviceState.isFullyGesturalNavMode() || mRecentsView == null) { return; } @@ -580,6 +593,12 @@ public abstract class AbsSwipeUpHandler, } else { recentsAttachedToAppWindow = mHasMotionEverBeenPaused || mIsLikelyToStartNewTask; } + if (moveFocusedTask && !mAnimationFactory.hasRecentsEverAttachedToAppWindow() + && recentsAttachedToAppWindow) { + // Only move focused task if RecentsView has never been attached before, to avoid + // TaskView jumping to new position as we move the tasks. + mRecentsView.moveFocusedTaskToFront(); + } mAnimationFactory.setRecentsAttachedToAppWindow(recentsAttachedToAppWindow, animate); // Reapply window transform throughout the attach animation, as the animation affects how @@ -669,7 +688,8 @@ public abstract class AbsSwipeUpHandler, || !canCreateNewOrUpdateExistingLauncherTransitionController()) { return; } - mLauncherTransitionController.setProgress(mCurrentShift.value, mDragLengthFactor); + mLauncherTransitionController.setProgress( + Math.max(mCurrentShift.value, getScaleProgressDueToScroll()), mDragLengthFactor); } /** @@ -1784,7 +1804,9 @@ public abstract class AbsSwipeUpHandler, */ protected void applyWindowTransform() { if (mWindowTransitionController != null) { - mWindowTransitionController.setProgress(mCurrentShift.value, mDragLengthFactor); + mWindowTransitionController.setProgress( + Math.max(mCurrentShift.value, getScaleProgressDueToScroll()), + mDragLengthFactor); } // No need to apply any transform if there is ongoing swipe-pip-to-home animator since // that animator handles the leash solely. @@ -1797,6 +1819,35 @@ public abstract class AbsSwipeUpHandler, ProtoTracer.INSTANCE.get(mContext).scheduleFrameUpdate(); } + // Scaling of RecentsView during quick switch based on amount of recents scroll + private float getScaleProgressDueToScroll() { + if (!mActivity.getDeviceProfile().isTablet || mRecentsView == null + || !mRecentsViewScrollLinked) { + return 0; + } + + float scrollOffset = Math.abs(mRecentsView.getScrollOffset(mRecentsView.getCurrentPage())); + int maxScrollOffset = mRecentsView.getPagedOrientationHandler().getPrimaryValue( + mRecentsView.getLastComputedTaskSize().width(), + mRecentsView.getLastComputedTaskSize().height()); + maxScrollOffset += mRecentsView.getPageSpacing(); + + float maxScaleProgress = + MAX_QUICK_SWITCH_RECENTS_SCALE_PROGRESS * mRecentsView.getMaxScaleForFullScreen(); + float scaleProgress = maxScaleProgress; + + if (scrollOffset < mQuickSwitchScaleScrollThreshold) { + scaleProgress = Utilities.mapToRange(scrollOffset, 0, mQuickSwitchScaleScrollThreshold, + 0, maxScaleProgress, ACCEL_DEACCEL); + } else if (scrollOffset > (maxScrollOffset - mQuickSwitchScaleScrollThreshold)) { + scaleProgress = Utilities.mapToRange(scrollOffset, + (maxScrollOffset - mQuickSwitchScaleScrollThreshold), maxScrollOffset, + maxScaleProgress, 0, ACCEL_DEACCEL); + } + + return scaleProgress; + } + /** * Used for winscope tracing, see launcher_trace.proto * @see com.android.systemui.shared.tracing.ProtoTraceable#writeToProto diff --git a/quickstep/src/com/android/quickstep/BaseActivityInterface.java b/quickstep/src/com/android/quickstep/BaseActivityInterface.java index 615a510ebd..11fb1d0beb 100644 --- a/quickstep/src/com/android/quickstep/BaseActivityInterface.java +++ b/quickstep/src/com/android/quickstep/BaseActivityInterface.java @@ -400,6 +400,10 @@ public abstract class BaseActivityInterface mCallback; private boolean mIsAttachedToWindow; + private boolean mHasEverAttachedToWindow; DefaultAnimationFactory(Consumer callback) { mCallback = callback; @@ -462,6 +467,9 @@ public abstract class BaseActivityInterface tasks) { if (mPendingAnimation != null) { mPendingAnimation.addEndListener(success -> applyLoadPlan(tasks)); @@ -1792,7 +1835,7 @@ public abstract class RecentsView sideSpacing) { + if (endOffset > sideSpacing) { int diff = Utilities.isRtl(context.getResources()) - ? sideSpacing - startOffset - : startOffset - sideSpacing; - mHotseatPadding.left += diff; - mHotseatPadding.right -= diff; + ? sideSpacing - endOffset + : endOffset - sideSpacing; + mHotseatPadding.left -= diff; + mHotseatPadding.right += diff; } } else { // We want the edges of the hotseat to line up with the edges of the workspace, but the diff --git a/src/com/android/launcher3/touch/AbstractStateChangeTouchController.java b/src/com/android/launcher3/touch/AbstractStateChangeTouchController.java index 90f37f3404..5f8a4d4f3c 100644 --- a/src/com/android/launcher3/touch/AbstractStateChangeTouchController.java +++ b/src/com/android/launcher3/touch/AbstractStateChangeTouchController.java @@ -65,12 +65,12 @@ public abstract class AbstractStateChangeTouchController protected LauncherState mToState; protected AnimatorPlaybackController mCurrentAnimation; protected boolean mGoingBetweenStates = true; + // Ratio of transition process [0, 1] to drag displacement (px) + protected float mProgressMultiplier; private boolean mNoIntercept; private boolean mIsLogContainerSet; private float mStartProgress; - // Ratio of transition process [0, 1] to drag displacement (px) - private float mProgressMultiplier; private float mDisplacementShift; private boolean mCanBlockFling; private boolean mAllAppsOvershootStarted; diff --git a/src/com/android/launcher3/views/RecyclerViewFastScroller.java b/src/com/android/launcher3/views/RecyclerViewFastScroller.java index a88b8b7776..1c2534d9fd 100644 --- a/src/com/android/launcher3/views/RecyclerViewFastScroller.java +++ b/src/com/android/launcher3/views/RecyclerViewFastScroller.java @@ -278,12 +278,7 @@ public class RecyclerViewFastScroller extends View { mIgnoreDragGesture |= absDeltaY > mConfig.getScaledPagingTouchSlop(); if (!mIsDragging && !mIgnoreDragGesture && mRv.supportsFastScrolling()) { - // condition #1: triggering thumb is distance, angle based - if ((isNearThumb(mDownX, mLastY) - && absDeltaY > mConfig.getScaledPagingTouchSlop() - && absDeltaY > absDeltaX) - // condition#2: Fastscroll function is now time based - || (isNearScrollBar(mDownX) && ev.getEventTime() - mDownTimeStampMillis + if ((isNearThumb(mDownX, mLastY) && ev.getEventTime() - mDownTimeStampMillis > FASTSCROLL_THRESHOLD_MILLIS)) { calcTouchOffsetAndPrepToFastScroll(mDownY, mLastY); } @@ -433,9 +428,6 @@ public class RecyclerViewFastScroller extends View { } private void updatePopupY(int lastTouchY) { - if (!mPopupVisible) { - return; - } int height = mPopupView.getHeight(); // Aligns the rounded corner of the pop up with the top of the thumb. float top = mRv.getScrollBarTop() + lastTouchY + (getScrollThumbRadius() / 2f) diff --git a/src_ui_overrides/com/android/launcher3/uioverrides/ApiWrapper.java b/src_ui_overrides/com/android/launcher3/uioverrides/ApiWrapper.java index c606861cd8..cc90e6c513 100644 --- a/src_ui_overrides/com/android/launcher3/uioverrides/ApiWrapper.java +++ b/src_ui_overrides/com/android/launcher3/uioverrides/ApiWrapper.java @@ -39,9 +39,9 @@ public class ApiWrapper { } /** - * Returns the minimum space that should be left empty at the start of hotseat + * Returns the minimum space that should be left empty at the end of hotseat */ - public static int getHotseatStartOffset(Context context) { + public static int getHotseatEndOffset(Context context) { return 0; } } diff --git a/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java b/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java index 5e57df6755..bf4eba0f64 100644 --- a/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java +++ b/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java @@ -128,9 +128,6 @@ public abstract class AbstractLauncherUiTest { } public static void checkDetectedLeaks(LauncherInstrumentation launcher) { - // TODO(b/191449914): Temporarily disable leak detection on tablets until bug is resolved. - if (launcher.isTablet()) return; - if (sActivityLeakReported) return; if (sStrictmodeDetectedActivityLeak != null) { diff --git a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java index 1e7f8a5d1c..1f64131703 100644 --- a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java +++ b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java @@ -514,9 +514,8 @@ public final class LauncherInstrumentation { void fail(String message) { checkForAnomaly(); Assert.fail(formatSystemHealthMessage(formatErrorWithEvents( - "http://go/tapl test failure:\nContext: " + getContextDescription() - + " => resulting visible state is " + getVisibleStateMessage() - + ";\nDetails: " + message, true))); + "http://go/tapl test failure: " + message + ";\nContext: " + getContextDescription() + + "; now visible state is " + getVisibleStateMessage(), true))); } private String getContextDescription() { @@ -746,17 +745,13 @@ public final class LauncherInstrumentation { dumpViewHierarchy(); action = "swiping up to home"; - final boolean launcherIsVisible = isLauncherVisible(); swipeToState( displaySize.x / 2, displaySize.y - 1, displaySize.x / 2, 0, ZERO_BUTTON_STEPS_FROM_BACKGROUND_TO_HOME, NORMAL_STATE_ORDINAL, - launcherWasVisible + launcherWasVisible || isTablet() ? GestureScope.INSIDE_TO_OUTSIDE : GestureScope.OUTSIDE_WITH_PILFER); - // b/193653850: launcherWasVisible is a flaky indicator. - log("launcherWasVisible: " + launcherWasVisible + ", launcherIsVisible: " - + launcherIsVisible); } } else { log("Hierarchy before clicking home:");