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) { } }