Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 7eb5b538 authored by Tony Wickham's avatar Tony Wickham
Browse files

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
parent 5f8bbcd5
Loading
Loading
Loading
Loading
+16 −0
Original line number Diff line number Diff line
@@ -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);
        }
    }
}
+70 −2
Original line number Diff line number Diff line
@@ -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) {
        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
+1 −2
Original line number Diff line number Diff line
@@ -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();
        }
+12 −0
Original line number Diff line number Diff line
@@ -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<STATE_TYPE extends BaseState<STATE_TYPE>>
        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) { }
}