From 7eb5b5386505663ed5d2b8570e85e6bf7dc81a88 Mon Sep 17 00:00:00 2001 From: Tony Wickham Date: Fri, 17 Sep 2021 17:08:46 -0700 Subject: [PATCH] Keep insets stable when taskbar is destroyed/recreated - Calculate nav bar insets ourselves. Currently when taskbar is going to be present, we use taskbarSize as the nav bar insets. This is consistent with other existing calculations, but going forward we should instead always use the nav bar size instead of taskbar size, given we don't want taskbar to inset launcher (since taskbar is hidden). - Also update tappable insets to be 0 in gesture mode. Test: Swipe to all apps, ensure there's no background protection at the bottom. Test: Rotate device, no visual jumps Test: Stash taskbar, quick switch a couple times without settling, and swipe up to overview; no jank due to reapplyState() Bug: 198798034 Fixes: 197232424 Fixes: 197212581 Change-Id: I4c2bb5816dbb214846bd9f2a46c6f759c0545911 --- .../launcher3/BaseQuickstepLauncher.java | 16 +++++ .../android/launcher3/LauncherRootView.java | 72 ++++++++++++++++++- .../allapps/AllAppsContainerView.java | 3 +- .../statemanager/StatefulActivity.java | 12 ++++ 4 files changed, 99 insertions(+), 4 deletions(-) diff --git a/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java b/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java index d24d752491..cd085a075f 100644 --- a/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java +++ b/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java @@ -24,6 +24,7 @@ import static com.android.launcher3.config.FeatureFlags.ENABLE_QUICKSTEP_LIVE_TI import static com.android.launcher3.model.data.ItemInfo.NO_MATCHING_ID; import static com.android.launcher3.util.DisplayController.CHANGE_ACTIVE_SCREEN; import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR; +import static com.android.quickstep.SysUINavigationMode.Mode.NO_BUTTON; import static com.android.quickstep.SysUINavigationMode.Mode.TWO_BUTTONS; import static com.android.systemui.shared.system.ActivityManagerWrapper.CLOSE_SYSTEM_WINDOWS_REASON_HOME_KEY; @@ -35,6 +36,7 @@ import android.content.Context; import android.content.Intent; import android.content.IntentSender; import android.content.ServiceConnection; +import android.graphics.Insets; import android.hardware.SensorManager; import android.hardware.devicestate.DeviceStateManager; import android.os.Bundle; @@ -43,6 +45,7 @@ import android.os.Handler; import android.os.IBinder; import android.util.Log; import android.view.View; +import android.view.WindowInsets; import android.window.SplashScreen; import androidx.annotation.Nullable; @@ -638,4 +641,17 @@ public abstract class BaseQuickstepLauncher extends Launcher mDepthController.dump(prefix, writer); } } + + @Override + public void updateWindowInsets(WindowInsets.Builder updatedInsetsBuilder, + WindowInsets oldInsets) { + // Override the tappable insets to be 0 on the bottom for gesture nav (otherwise taskbar + // would count towards it). This is used for the bottom protection in All Apps for example. + if (SysUINavigationMode.getMode(this) == NO_BUTTON) { + Insets oldTappableInsets = oldInsets.getInsets(WindowInsets.Type.tappableElement()); + Insets newTappableInsets = Insets.of(oldTappableInsets.left, oldTappableInsets.top, + oldTappableInsets.right, 0); + updatedInsetsBuilder.setInsets(WindowInsets.Type.tappableElement(), newTappableInsets); + } + } } diff --git a/src/com/android/launcher3/LauncherRootView.java b/src/com/android/launcher3/LauncherRootView.java index f26cfe872e..28afc5768b 100644 --- a/src/com/android/launcher3/LauncherRootView.java +++ b/src/com/android/launcher3/LauncherRootView.java @@ -4,15 +4,20 @@ import static com.android.launcher3.config.FeatureFlags.SEPARATE_RECENTS_ACTIVIT import android.annotation.TargetApi; import android.content.Context; +import android.content.res.Resources; import android.graphics.Canvas; +import android.graphics.Insets; import android.graphics.Rect; import android.os.Build; import android.util.AttributeSet; import android.view.ViewDebug; import android.view.WindowInsets; +import androidx.annotation.RequiresApi; + import com.android.launcher3.graphics.SysUiScrim; import com.android.launcher3.statemanager.StatefulActivity; +import com.android.launcher3.uioverrides.ApiWrapper; import java.util.Collections; import java.util.List; @@ -61,12 +66,75 @@ public class LauncherRootView extends InsettableFrameLayout { @Override public WindowInsets onApplyWindowInsets(WindowInsets insets) { - mTempRect.set(insets.getSystemWindowInsetLeft(), insets.getSystemWindowInsetTop(), - insets.getSystemWindowInsetRight(), insets.getSystemWindowInsetBottom()); + if (Utilities.ATLEAST_R) { + insets = updateInsetsDueToTaskbar(insets); + Insets systemWindowInsets = insets.getInsetsIgnoringVisibility( + WindowInsets.Type.systemBars() | WindowInsets.Type.displayCutout()); + mTempRect.set(systemWindowInsets.left, systemWindowInsets.top, systemWindowInsets.right, + systemWindowInsets.bottom); + } else { + mTempRect.set(insets.getSystemWindowInsetLeft(), insets.getSystemWindowInsetTop(), + insets.getSystemWindowInsetRight(), insets.getSystemWindowInsetBottom()); + } handleSystemWindowInsets(mTempRect); return insets; } + /** + * Taskbar provides nav bar and tappable insets. However, taskbar is not attached immediately, + * and can be destroyed and recreated. Thus, instead of relying on taskbar being present to + * get its insets, we calculate them ourselves so they are stable regardless of whether taskbar + * is currently attached. + * + * TODO(b/198798034): Currently we always calculate nav insets as taskbarSize, but then we + * subtract nonOverlappingTaskbarInset in handleSystemWindowInsets(). Instead, we should just + * calculate the normal nav bar height here, and remove nonOverlappingTaskbarInset altogether. + * + * @param oldInsets The system-provided insets, which we are modifying. + * @return The updated insets. + */ + @RequiresApi(api = Build.VERSION_CODES.R) + private WindowInsets updateInsetsDueToTaskbar(WindowInsets oldInsets) { + if (!ApiWrapper.TASKBAR_DRAWN_IN_PROCESS) { + // 3P launchers based on Launcher3 should still be inset like normal. + return oldInsets; + } + + WindowInsets.Builder updatedInsetsBuilder = new WindowInsets.Builder(oldInsets); + + DeviceProfile dp = mActivity.getDeviceProfile(); + Resources resources = getResources(); + + Insets oldNavInsets = oldInsets.getInsets(WindowInsets.Type.navigationBars()); + Rect newNavInsets = new Rect(oldNavInsets.left, oldNavInsets.top, oldNavInsets.right, + oldNavInsets.bottom); + if (dp.isTaskbarPresent) { + // TODO (see javadoc): Remove this block and fall into the next one instead. + newNavInsets.bottom = dp.taskbarSize; + } else if (dp.isLandscape) { + if (dp.isTablet) { + newNavInsets.bottom = ResourceUtils.getNavbarSize( + "navigation_bar_height_landscape", resources); + } else { + int navWidth = ResourceUtils.getNavbarSize("navigation_bar_width", resources); + if (dp.isSeascape()) { + newNavInsets.left = navWidth; + } else { + newNavInsets.right = navWidth; + } + } + } else { + newNavInsets.bottom = ResourceUtils.getNavbarSize("navigation_bar_height", resources); + } + updatedInsetsBuilder.setInsets(WindowInsets.Type.navigationBars(), Insets.of(newNavInsets)); + updatedInsetsBuilder.setInsetsIgnoringVisibility(WindowInsets.Type.navigationBars(), + Insets.of(newNavInsets)); + + mActivity.updateWindowInsets(updatedInsetsBuilder, oldInsets); + + return updatedInsetsBuilder.build(); + } + @Override public void setInsets(Rect insets) { // If the insets haven't changed, this is a no-op. Avoid unnecessary layout caused by diff --git a/src/com/android/launcher3/allapps/AllAppsContainerView.java b/src/com/android/launcher3/allapps/AllAppsContainerView.java index ee5f7e4a71..f30ca1ba3c 100644 --- a/src/com/android/launcher3/allapps/AllAppsContainerView.java +++ b/src/com/android/launcher3/allapps/AllAppsContainerView.java @@ -426,8 +426,7 @@ public class AllAppsContainerView extends SpringRelativeLayout implements DragSo @Override public WindowInsets dispatchApplyWindowInsets(WindowInsets insets) { if (Utilities.ATLEAST_Q) { - mNavBarScrimHeight = insets.getTappableElementInsets().bottom - - mLauncher.getDeviceProfile().nonOverlappingTaskbarInset; + mNavBarScrimHeight = insets.getTappableElementInsets().bottom; } else { mNavBarScrimHeight = insets.getStableInsetBottom(); } diff --git a/src/com/android/launcher3/statemanager/StatefulActivity.java b/src/com/android/launcher3/statemanager/StatefulActivity.java index 8a35cb33c0..7a23caa884 100644 --- a/src/com/android/launcher3/statemanager/StatefulActivity.java +++ b/src/com/android/launcher3/statemanager/StatefulActivity.java @@ -17,11 +17,15 @@ package com.android.launcher3.statemanager; import static com.android.launcher3.LauncherState.FLAG_NON_INTERACTIVE; +import android.graphics.Insets; +import android.os.Build; import android.os.Handler; import android.view.LayoutInflater; import android.view.View; +import android.view.WindowInsets; import androidx.annotation.CallSuper; +import androidx.annotation.RequiresApi; import com.android.launcher3.BaseDraggingActivity; import com.android.launcher3.LauncherRootView; @@ -173,4 +177,12 @@ public abstract class StatefulActivity> mHandler.removeCallbacks(mHandleDeferredResume); Utilities.postAsyncCallback(mHandler, mHandleDeferredResume); } + + /** + * Gives subclasses a chance to override some window insets (via + * {@link android.view.WindowInsets.Builder#setInsets(int, Insets)}). + */ + @RequiresApi(api = Build.VERSION_CODES.R) + public void updateWindowInsets(WindowInsets.Builder updatedInsetsBuilder, + WindowInsets oldInsets) { } }