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

Commit 31a50025 authored by Treehugger Robot's avatar Treehugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Replace custom header spy window with custom touchable regions" into main

parents ff515c54 5bf63371
Loading
Loading
Loading
Loading
+17 −6
Original line number Diff line number Diff line
@@ -26,6 +26,7 @@ import static android.view.WindowManager.TRANSIT_CHANGE;

import static com.android.window.flags.Flags.enableDisplayFocusInShellTransitions;

import android.annotation.NonNull;
import android.app.ActivityManager.RunningTaskInfo;
import android.content.ContentResolver;
import android.content.Context;
@@ -110,6 +111,7 @@ public class CaptionWindowDecorViewModel implements WindowDecorViewModel, FocusT
                    }
                    mMainExecutor.execute(() -> {
                        mExclusionRegion.set(systemGestureExclusion);
                        onExclusionRegionChanged(displayId, mExclusionRegion);
                    });
                }
            };
@@ -163,7 +165,7 @@ public class CaptionWindowDecorViewModel implements WindowDecorViewModel, FocusT
            boolean isFocusedGlobally) {
        final WindowDecoration decor = mWindowDecorByTaskId.get(taskId);
        if (decor != null) {
            decor.relayout(decor.mTaskInfo, isFocusedGlobally);
            decor.relayout(decor.mTaskInfo, isFocusedGlobally, decor.mExclusionRegion);
        }
    }

@@ -199,9 +201,9 @@ public class CaptionWindowDecorViewModel implements WindowDecorViewModel, FocusT

        if (enableDisplayFocusInShellTransitions()) {
            // Pass the current global focus status to avoid updates outside of a ShellTransition.
            decoration.relayout(taskInfo, decoration.mHasGlobalFocus);
            decoration.relayout(taskInfo, decoration.mHasGlobalFocus, decoration.mExclusionRegion);
        } else {
            decoration.relayout(taskInfo, taskInfo.isFocused);
            decoration.relayout(taskInfo, taskInfo.isFocused, decoration.mExclusionRegion);
        }
    }

@@ -240,7 +242,7 @@ public class CaptionWindowDecorViewModel implements WindowDecorViewModel, FocusT
        } else {
            decoration.relayout(taskInfo, startT, finishT, false /* applyStartTransactionOnDraw */,
                    false /* setTaskCropAndPosition */,
                    mFocusTransitionObserver.hasGlobalFocus(taskInfo));
                    mFocusTransitionObserver.hasGlobalFocus(taskInfo), mExclusionRegion);
        }
    }

@@ -254,7 +256,7 @@ public class CaptionWindowDecorViewModel implements WindowDecorViewModel, FocusT

        decoration.relayout(taskInfo, startT, finishT, false /* applyStartTransactionOnDraw */,
                false /* setTaskCropAndPosition */,
                mFocusTransitionObserver.hasGlobalFocus(taskInfo));
                mFocusTransitionObserver.hasGlobalFocus(taskInfo), mExclusionRegion);
    }

    @Override
@@ -266,6 +268,15 @@ public class CaptionWindowDecorViewModel implements WindowDecorViewModel, FocusT
        decoration.close();
    }

    private void onExclusionRegionChanged(int displayId, @NonNull Region exclusionRegion) {
        final int decorCount = mWindowDecorByTaskId.size();
        for (int i = 0; i < decorCount; i++) {
            final CaptionWindowDecoration decoration = mWindowDecorByTaskId.valueAt(i);
            if (decoration.mTaskInfo.displayId != displayId) continue;
            decoration.onExclusionRegionChanged(exclusionRegion);
        }
    }

    private boolean shouldShowWindowDecor(RunningTaskInfo taskInfo) {
        if (taskInfo.getWindowingMode() == WINDOWING_MODE_FREEFORM) {
            return true;
@@ -333,7 +344,7 @@ public class CaptionWindowDecorViewModel implements WindowDecorViewModel, FocusT
        windowDecoration.setTaskDragResizer(taskPositioner);
        windowDecoration.relayout(taskInfo, startT, finishT,
                false /* applyStartTransactionOnDraw */, false /* setTaskCropAndPosition */,
                mFocusTransitionObserver.hasGlobalFocus(taskInfo));
                mFocusTransitionObserver.hasGlobalFocus(taskInfo), mExclusionRegion);
    }

    private class CaptionTouchEventListener implements
+11 −5
Original line number Diff line number Diff line
@@ -36,6 +36,7 @@ import android.graphics.Color;
import android.graphics.Insets;
import android.graphics.Point;
import android.graphics.Rect;
import android.graphics.Region;
import android.graphics.drawable.GradientDrawable;
import android.os.Handler;
import android.util.Size;
@@ -174,7 +175,8 @@ public class CaptionWindowDecoration extends WindowDecoration<WindowDecorLinearL
    }

    @Override
    void relayout(RunningTaskInfo taskInfo, boolean hasGlobalFocus) {
    void relayout(RunningTaskInfo taskInfo, boolean hasGlobalFocus,
            @NonNull Region displayExclusionRegion) {
        final SurfaceControl.Transaction t = new SurfaceControl.Transaction();
        // The crop and position of the task should only be set when a task is fluid resizing. In
        // all other cases, it is expected that the transition handler positions and crops the task
@@ -186,7 +188,7 @@ public class CaptionWindowDecoration extends WindowDecoration<WindowDecorLinearL
        // synced with the buffer transaction (that draws the View). Both will be shown on screen
        // at the same, whereas applying them independently causes flickering. See b/270202228.
        relayout(taskInfo, t, t, true /* applyStartTransactionOnDraw */,
                shouldSetTaskVisibilityPositionAndCrop, hasGlobalFocus);
                shouldSetTaskVisibilityPositionAndCrop, hasGlobalFocus, displayExclusionRegion);
    }

    @VisibleForTesting
@@ -198,7 +200,8 @@ public class CaptionWindowDecoration extends WindowDecoration<WindowDecorLinearL
            boolean isStatusBarVisible,
            boolean isKeyguardVisibleAndOccluded,
            InsetsState displayInsetsState,
            boolean hasGlobalFocus) {
            boolean hasGlobalFocus,
            @NonNull Region globalExclusionRegion) {
        relayoutParams.reset();
        relayoutParams.mRunningTaskInfo = taskInfo;
        relayoutParams.mLayoutResId = R.layout.caption_window_decor;
@@ -210,6 +213,7 @@ public class CaptionWindowDecoration extends WindowDecoration<WindowDecorLinearL
        relayoutParams.mSetTaskVisibilityPositionAndCrop = shouldSetTaskVisibilityPositionAndCrop;
        relayoutParams.mIsCaptionVisible = taskInfo.isFreeform()
                || (isStatusBarVisible && !isKeyguardVisibleAndOccluded);
        relayoutParams.mDisplayExclusionRegion.set(globalExclusionRegion);

        if (TaskInfoKt.isTransparentCaptionBarAppearance(taskInfo)) {
            // If the app is requesting to customize the caption bar, allow input to fall
@@ -236,7 +240,8 @@ public class CaptionWindowDecoration extends WindowDecoration<WindowDecorLinearL
    void relayout(RunningTaskInfo taskInfo,
            SurfaceControl.Transaction startT, SurfaceControl.Transaction finishT,
            boolean applyStartTransactionOnDraw, boolean shouldSetTaskVisibilityPositionAndCrop,
            boolean hasGlobalFocus) {
            boolean hasGlobalFocus,
            @NonNull Region globalExclusionRegion) {
        final boolean isFreeform =
                taskInfo.getWindowingMode() == WindowConfiguration.WINDOWING_MODE_FREEFORM;
        final boolean isDragResizeable = ENABLE_WINDOWING_SCALED_RESIZING.isTrue()
@@ -249,7 +254,8 @@ public class CaptionWindowDecoration extends WindowDecoration<WindowDecorLinearL
        updateRelayoutParams(mRelayoutParams, taskInfo, applyStartTransactionOnDraw,
                shouldSetTaskVisibilityPositionAndCrop, mIsStatusBarVisible,
                mIsKeyguardVisibleAndOccluded,
                mDisplayController.getInsetsState(taskInfo.displayId), hasGlobalFocus);
                mDisplayController.getInsetsState(taskInfo.displayId), hasGlobalFocus,
                globalExclusionRegion);

        relayout(mRelayoutParams, startT, finishT, wct, oldRootView, mResult);
        // After this line, mTaskInfo is up-to-date and should be used instead of taskInfo
+36 −17
Original line number Diff line number Diff line
@@ -220,6 +220,7 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel,
                    }
                    mMainExecutor.execute(() -> {
                        mExclusionRegion.set(systemGestureExclusion);
                        onExclusionRegionChanged(displayId, mExclusionRegion);
                    });
                }
            };
@@ -432,7 +433,7 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel,
            boolean isFocusedGlobally) {
        final WindowDecoration decor = mWindowDecorByTaskId.get(taskId);
        if (decor != null) {
            decor.relayout(decor.mTaskInfo, isFocusedGlobally);
            decor.relayout(decor.mTaskInfo, isFocusedGlobally, decor.mExclusionRegion);
        }
    }

@@ -471,9 +472,9 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel,
        }
        if (enableDisplayFocusInShellTransitions()) {
            // Pass the current global focus status to avoid updates outside of a ShellTransition.
            decoration.relayout(taskInfo, decoration.mHasGlobalFocus);
            decoration.relayout(taskInfo, decoration.mHasGlobalFocus, decoration.mExclusionRegion);
        } else {
            decoration.relayout(taskInfo, taskInfo.isFocused);
            decoration.relayout(taskInfo, taskInfo.isFocused, decoration.mExclusionRegion);
        }
        mActivityOrientationChangeHandler.ifPresent(handler ->
                handler.handleActivityOrientationChange(oldTaskInfo, taskInfo));
@@ -514,7 +515,8 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel,
        } else {
            decoration.relayout(taskInfo, startT, finishT, false /* applyStartTransactionOnDraw */,
                    false /* shouldSetTaskPositionAndCrop */,
                    mFocusTransitionObserver.hasGlobalFocus(taskInfo));
                    mFocusTransitionObserver.hasGlobalFocus(taskInfo),
                    mExclusionRegion);
        }
    }

@@ -528,7 +530,8 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel,

        decoration.relayout(taskInfo, startT, finishT, false /* applyStartTransactionOnDraw */,
                false /* shouldSetTaskPositionAndCrop */,
                mFocusTransitionObserver.hasGlobalFocus(taskInfo));
                mFocusTransitionObserver.hasGlobalFocus(taskInfo),
                mExclusionRegion);
    }

    @Override
@@ -548,6 +551,15 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel,
        mWindowDecorByTaskId.remove(taskInfo.taskId);
    }

    private void onExclusionRegionChanged(int displayId, @NonNull Region exclusionRegion) {
        final int decorCount = mWindowDecorByTaskId.size();
        for (int i = 0; i < decorCount; i++) {
            final DesktopModeWindowDecoration decoration = mWindowDecorByTaskId.valueAt(i);
            if (decoration.mTaskInfo.displayId != displayId) continue;
            decoration.onExclusionRegionChanged(exclusionRegion);
        }
    }

    private void openHandleMenu(int taskId) {
        final DesktopModeWindowDecoration decoration = mWindowDecorByTaskId.get(taskId);
        decoration.createHandleMenu(checkNumberOfOtherInstances(decoration.mTaskInfo)
@@ -750,10 +762,13 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel,

        /**
         * Whether to pilfer the next motion event to send cancellations to the windows below.
         * Useful when the caption window is spy and the gesture should be handle by the system
         * Useful when the caption window is spy and the gesture should be handled by the system
         * instead of by the app for their custom header content.
         * Should not have any effect when {@link Flags#enableAccessibleCustomHeaders()}, because
         * a spy window is not used then.
         */
        private boolean mShouldPilferCaptionEvents;
        private boolean mIsCustomHeaderGesture;
        private boolean mIsResizeGesture;
        private boolean mIsDragging;
        private boolean mTouchscreenInUse;
        private boolean mHasLongClicked;
@@ -867,7 +882,7 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel,
                // to offset position relative to caption as a whole.
                int[] viewLocation = new int[2];
                v.getLocationInWindow(viewLocation);
                final boolean isResizeEvent = decoration.shouldResizeListenerHandleEvent(e,
                mIsResizeGesture = decoration.shouldResizeListenerHandleEvent(e,
                        new Point(viewLocation[0], viewLocation[1]));
                // The caption window may be a spy window when the caption background is
                // transparent, which means events will fall through to the app window. Make
@@ -875,21 +890,23 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel,
                // customizable region and what the app reported as exclusion areas, because
                // the drag-move or other caption gestures should take priority outside those
                // regions.
                mShouldPilferCaptionEvents = !(downInCustomizableCaptionRegion
                        && downInExclusionRegion && isTransparentCaption) && !isResizeEvent;
                mIsCustomHeaderGesture = downInCustomizableCaptionRegion
                        && downInExclusionRegion && isTransparentCaption;
            }
            if (!mShouldPilferCaptionEvents) {
                // The event will be handled by a window below or pilfered by resize handler.
            if (mIsCustomHeaderGesture || mIsResizeGesture) {
                // The event will be handled by the custom window below or pilfered by resize
                // handler.
                return false;
            }
            // Otherwise pilfer so that windows below receive cancellations for this gesture, and
            // continue normal handling as a caption gesture.
            if (mInputManager != null) {
            if (mInputManager != null
                    && !Flags.enableAccessibleCustomHeaders()) {
                // Pilfer so that windows below receive cancellations for this gesture.
                mInputManager.pilferPointers(v.getViewRootImpl().getInputToken());
            }
            if (isUpOrCancel) {
                // Gesture is finished, reset state.
                mShouldPilferCaptionEvents = false;
                mIsCustomHeaderGesture = false;
                mIsResizeGesture = false;
            }
            if (isAppHandle) {
                return mHandleDragDetector.onMotionEvent(v, e);
@@ -1592,7 +1609,8 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel,
        windowDecoration.setDragPositioningCallback(taskPositioner);
        windowDecoration.relayout(taskInfo, startT, finishT,
                false /* applyStartTransactionOnDraw */, false /* shouldSetTaskPositionAndCrop */,
                mFocusTransitionObserver.hasGlobalFocus(taskInfo));
                mFocusTransitionObserver.hasGlobalFocus(taskInfo),
                mExclusionRegion);
        if (!DesktopModeFlags.ENABLE_HANDLE_INPUT_FIX.isTrue()) {
            incrementEventReceiverTasks(taskInfo.displayId);
        }
@@ -1618,6 +1636,7 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel,
        pw.println(innerPrefix + "mTransitionDragActive=" + mTransitionDragActive);
        pw.println(innerPrefix + "mEventReceiversByDisplay=" + mEventReceiversByDisplay);
        pw.println(innerPrefix + "mWindowDecorByTaskId=" + mWindowDecorByTaskId);
        pw.println(innerPrefix + "mExclusionRegion=" + mExclusionRegion);
    }

    private class DesktopModeOnTaskRepositionAnimationListener
+31 −16
Original line number Diff line number Diff line
@@ -394,7 +394,8 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin
    }

    @Override
    void relayout(ActivityManager.RunningTaskInfo taskInfo, boolean hasGlobalFocus) {
    void relayout(ActivityManager.RunningTaskInfo taskInfo, boolean hasGlobalFocus,
            @NonNull Region displayExclusionRegion) {
        final SurfaceControl.Transaction t = mSurfaceControlTransactionSupplier.get();
        // The visibility, crop and position of the task should only be set when a task is
        // fluid resizing. In all other cases, it is expected that the transition handler sets
@@ -415,7 +416,7 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin
        // causes flickering. See b/270202228.
        final boolean applyTransactionOnDraw = taskInfo.isFreeform();
        relayout(taskInfo, t, t, applyTransactionOnDraw, shouldSetTaskVisibilityPositionAndCrop,
                hasGlobalFocus);
                hasGlobalFocus, displayExclusionRegion);
        if (!applyTransactionOnDraw) {
            t.apply();
        }
@@ -442,18 +443,18 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin
    void relayout(ActivityManager.RunningTaskInfo taskInfo,
            SurfaceControl.Transaction startT, SurfaceControl.Transaction finishT,
            boolean applyStartTransactionOnDraw, boolean shouldSetTaskVisibilityPositionAndCrop,
            boolean hasGlobalFocus) {
            boolean hasGlobalFocus, @NonNull Region displayExclusionRegion) {
        Trace.beginSection("DesktopModeWindowDecoration#relayout");
        if (taskInfo.isFreeform()) {
            // The Task is in Freeform mode -> show its header in sync since it's an integral part
            // of the window itself - a delayed header might cause bad UX.
            relayoutInSync(taskInfo, startT, finishT, applyStartTransactionOnDraw,
                    shouldSetTaskVisibilityPositionAndCrop, hasGlobalFocus);
                    shouldSetTaskVisibilityPositionAndCrop, hasGlobalFocus, displayExclusionRegion);
        } else {
            // The Task is outside Freeform mode -> allow the handle view to be delayed since the
            // handle is just a small addition to the window.
            relayoutWithDelayedViewHost(taskInfo, startT, finishT, applyStartTransactionOnDraw,
                    shouldSetTaskVisibilityPositionAndCrop, hasGlobalFocus);
                    shouldSetTaskVisibilityPositionAndCrop, hasGlobalFocus, displayExclusionRegion);
        }
        Trace.endSection();
    }
@@ -462,11 +463,11 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin
    private void relayoutInSync(ActivityManager.RunningTaskInfo taskInfo,
            SurfaceControl.Transaction startT, SurfaceControl.Transaction finishT,
            boolean applyStartTransactionOnDraw, boolean shouldSetTaskVisibilityPositionAndCrop,
            boolean hasGlobalFocus) {
            boolean hasGlobalFocus, @NonNull Region displayExclusionRegion) {
        // Clear the current ViewHost runnable as we will update the ViewHost here
        clearCurrentViewHostRunnable();
        updateRelayoutParamsAndSurfaces(taskInfo, startT, finishT, applyStartTransactionOnDraw,
                shouldSetTaskVisibilityPositionAndCrop, hasGlobalFocus);
                shouldSetTaskVisibilityPositionAndCrop, hasGlobalFocus, displayExclusionRegion);
        if (mResult.mRootView != null) {
            updateViewHost(mRelayoutParams, startT, mResult);
        }
@@ -489,7 +490,8 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin
    private void relayoutWithDelayedViewHost(ActivityManager.RunningTaskInfo taskInfo,
            SurfaceControl.Transaction startT, SurfaceControl.Transaction finishT,
            boolean applyStartTransactionOnDraw, boolean shouldSetTaskVisibilityPositionAndCrop,
            boolean hasGlobalFocus) {
            boolean hasGlobalFocus,
            @NonNull Region displayExclusionRegion) {
        if (applyStartTransactionOnDraw) {
            throw new IllegalArgumentException(
                    "We cannot both sync viewhost ondraw and delay viewhost creation.");
@@ -498,7 +500,7 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin
        clearCurrentViewHostRunnable();
        updateRelayoutParamsAndSurfaces(taskInfo, startT, finishT,
                false /* applyStartTransactionOnDraw */, shouldSetTaskVisibilityPositionAndCrop,
                hasGlobalFocus);
                hasGlobalFocus, displayExclusionRegion);
        if (mResult.mRootView == null) {
            // This means something blocks the window decor from showing, e.g. the task is hidden.
            // Nothing is set up in this case including the decoration surface.
@@ -513,7 +515,7 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin
    private void updateRelayoutParamsAndSurfaces(ActivityManager.RunningTaskInfo taskInfo,
            SurfaceControl.Transaction startT, SurfaceControl.Transaction finishT,
            boolean applyStartTransactionOnDraw, boolean shouldSetTaskVisibilityPositionAndCrop,
            boolean hasGlobalFocus) {
            boolean hasGlobalFocus, @NonNull Region displayExclusionRegion) {
        Trace.beginSection("DesktopModeWindowDecoration#updateRelayoutParamsAndSurfaces");
        if (Flags.enableDesktopWindowingAppToWeb()) {
            setCapturedLink(taskInfo.capturedLink, taskInfo.capturedLinkTimestamp);
@@ -538,7 +540,8 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin
        updateRelayoutParams(mRelayoutParams, mContext, taskInfo, applyStartTransactionOnDraw,
                shouldSetTaskVisibilityPositionAndCrop, mIsStatusBarVisible,
                mIsKeyguardVisibleAndOccluded, inFullImmersive,
                mDisplayController.getInsetsState(taskInfo.displayId), hasGlobalFocus);
                mDisplayController.getInsetsState(taskInfo.displayId), hasGlobalFocus,
                displayExclusionRegion);

        final WindowDecorLinearLayout oldRootView = mResult.mRootView;
        final SurfaceControl oldDecorationSurface = mDecorationContainerSurface;
@@ -879,7 +882,8 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin
            boolean isKeyguardVisibleAndOccluded,
            boolean inFullImmersiveMode,
            @NonNull InsetsState displayInsetsState,
            boolean hasGlobalFocus) {
            boolean hasGlobalFocus,
            @NonNull Region displayExclusionRegion) {
        final int captionLayoutId = getDesktopModeWindowDecorLayoutId(taskInfo.getWindowingMode());
        final boolean isAppHeader =
                captionLayoutId == R.layout.desktop_mode_app_header;
@@ -890,6 +894,7 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin
        relayoutParams.mCaptionHeightId = getCaptionHeightIdStatic(taskInfo.getWindowingMode());
        relayoutParams.mCaptionWidthId = getCaptionWidthId(relayoutParams.mLayoutResId);
        relayoutParams.mHasGlobalFocus = hasGlobalFocus;
        relayoutParams.mDisplayExclusionRegion.set(displayExclusionRegion);

        final boolean showCaption;
        if (Flags.enableFullyImmersiveInDesktop()) {
@@ -915,10 +920,20 @@ public class DesktopModeWindowDecoration extends WindowDecoration<WindowDecorLin
        relayoutParams.mIsInsetSource = isAppHeader && !inFullImmersiveMode;
        if (isAppHeader) {
            if (TaskInfoKt.isTransparentCaptionBarAppearance(taskInfo)) {
                // If the app is requesting to customize the caption bar, allow input to fall
                // through to the windows below so that the app can respond to input events on
                // their custom content.
                // The app is requesting to customize the caption bar, which means input on
                // customizable/exclusion regions must go to the app instead of to the system.
                // This may be accomplished with spy windows or custom touchable regions:
                if (Flags.enableAccessibleCustomHeaders()) {
                    // Set the touchable region of the caption to only the areas where input should
                    // be handled by the system (i.e. non custom-excluded areas). The region will
                    // be calculated based on occluding caption elements and exclusion areas
                    // reported by the app.
                    relayoutParams.mLimitTouchRegionToSystemAreas = true;
                } else {
                    // Allow input to fall through to the windows below so that the app can respond
                    // to input events on their custom content.
                    relayoutParams.mInputFeatures |= WindowManager.LayoutParams.INPUT_FEATURE_SPY;
                }
            } else {
                if (ENABLE_CAPTION_COMPAT_INSET_FORCE_CONSUMPTION.isTrue()) {
                    // Force-consume the caption bar insets when the app tries to hide the caption.
+102 −10

File changed.

Preview size limit exceeded, changes collapsed.

Loading