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

Commit d4bc5b68 authored by Roman Birg's avatar Roman Birg
Browse files

SystemUI: fix navbar drawing issues in landscape



Originally StatusBarWindowView was responsible for laying out the scrims
and making sure they are full screen (behind navbar), while the other
views were respecting the navbar insets.

This was broken for two reasons for us:

 1) our scrims are more complex and aren't always direct subchildren of
    the StatusBarWindowView (mainly to display the visualizer correctly)

 2) we declared fitSystemWindows=false, so the logic to add insets was
    never actually executing.

We now split out the logic for insets into its own class and apply it to
the scrims properly.

Ref: CYNGNOS-1502
Change-Id: I5b8295d7a64b72dc911fce6d529936592f24e98b
Signed-off-by: default avatarRoman Birg <roman@cyngn.com>
parent 573109ec
Loading
Loading
Loading
Loading
+16 −11
Original line number Diff line number Diff line
@@ -18,13 +18,13 @@
-->

<!-- This is the combined status bar / notification panel window. -->
<FrameLayout
<com.android.systemui.statusbar.phone.NavBarInsetLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:sysui="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:focusable="true"
    android:fitsSystemWindows="false"
    android:fitsSystemWindows="true"
    android:descendantFocusability="afterDescendants">

    <com.android.systemui.statusbar.BackDropView
@@ -45,14 +45,18 @@
                   android:visibility="invisible" />
    </com.android.systemui.statusbar.BackDropView>

    <FrameLayout android:id="@+id/scrimview"
    <com.android.systemui.statusbar.phone.NavBarInsetLayout
                 android:id="@+id/scrimview"
                 android:layout_width="match_parent"
                 android:layout_height="match_parent"
                 android:visibility="visible">
                 android:visibility="visible"
                 sysui:ignoreRightInset="true"
                 android:fitsSystemWindows="true">
        <com.android.systemui.statusbar.ScrimView
                android:id="@+id/scrim_behind"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                sysui:ignoreRightInset="true"
                android:importantForAccessibility="no"/>
        <com.android.systemui.statusbar.AlphaOptimizedView
                android:id="@+id/heads_up_scrim"
@@ -66,8 +70,9 @@
                android:layout_gravity="bottom"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                sysui:ignoreRightInset="true"
                android:visibility="visible"/>
    </FrameLayout>
    </com.android.systemui.statusbar.phone.NavBarInsetLayout>

    <include layout="@layout/status_bar"
        android:layout_width="match_parent"
@@ -109,4 +114,4 @@
        sysui:ignoreRightInset="true"
        />

</FrameLayout>
</com.android.systemui.statusbar.phone.NavBarInsetLayout>
+217 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2016 The CyanogenMod Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.systemui.statusbar.phone;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.Rect;
import android.os.Handler;
import android.os.IBinder;
import android.os.UserHandle;
import android.util.AttributeSet;
import android.view.View;
import android.view.WindowManager;
import android.view.WindowManagerGlobal;
import android.widget.FrameLayout;
import com.android.systemui.R;
import com.android.systemui.cm.UserContentObserver;
import com.android.systemui.statusbar.BaseStatusBar;
import cyanogenmod.providers.CMSettings;

public class NavBarInsetLayout extends FrameLayout {
    public static final String TAG = "NavBarInsetLayout";
    public static final boolean DEBUG = BaseStatusBar.DEBUG;

    boolean mLeftInsetMode = false;

    private int mLeftInset = 0;
    private int mRightInset = 0;

    private final Paint mTransparentSrcPaint = new Paint();

    private SettingsObserver mSettingsObserver;

    @Override
    protected void onAttachedToWindow() {
        super.onAttachedToWindow();
        mSettingsObserver.observe();
    }

    @Override
    protected void onDetachedFromWindow() {
        super.onDetachedFromWindow();
        mSettingsObserver.unobserve();
    }

    public NavBarInsetLayout(Context context, AttributeSet attrs) {
        super(context, attrs);
        mTransparentSrcPaint.setColor(0);
        mTransparentSrcPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC));

        mSettingsObserver = new SettingsObserver(new Handler());
    }

    @Override
    protected boolean fitSystemWindows(Rect insets) {
        if (getFitsSystemWindows()) {
            boolean paddingChanged;

            if (mLeftInsetMode) {
                paddingChanged = insets.right != getPaddingRight()
                        || insets.top != getPaddingTop()
                        || insets.bottom != getPaddingBottom();

                if (insets.left != mLeftInset) {
                    mLeftInset = insets.left;
                    applyMargins();
                }
            } else {
                paddingChanged = insets.left != getPaddingLeft()
                        || insets.top != getPaddingTop()
                        || insets.bottom != getPaddingBottom();

                if (insets.right != mRightInset) {
                    mRightInset = insets.right;
                    applyMargins();
                }
            }

            // Drop top inset, apply left inset and pass through bottom inset.
            if (paddingChanged) {
                setPadding(mLeftInsetMode ? 0 : insets.left,
                        0,
                        mLeftInsetMode ? insets.right : 0,
                        0);
            }
            insets.left = 0;
            insets.top = 0;
            insets.right = 0;
        } else {
            boolean applyMargins = false;
            if (mLeftInset != 0) {
                mLeftInset = 0;
                applyMargins = true;
            }
            if (mRightInset != 0) {
                mRightInset = 0;
                applyMargins = true;
            }
            if (applyMargins) {
                applyMargins();
            }
            boolean changed = getPaddingLeft() != 0
                    || getPaddingRight() != 0
                    || getPaddingTop() != 0
                    || getPaddingBottom() != 0;
            if (changed) {
                setPadding(0, 0, 0, 0);
            }
            insets.top = 0;
        }
        return false;
    }

    private void applyMargins() {
        final int N = getChildCount();
        for (int i = 0; i < N; i++) {
            View child = getChildAt(i);
            if (child.getLayoutParams() instanceof InsetLayoutParams) {
                InsetLayoutParams lp = (InsetLayoutParams) child.getLayoutParams();
                if (!lp.ignoreRightInset) {
                    if (mLeftInsetMode && lp.leftMargin != mLeftInset) {
                        lp.leftMargin = mLeftInset;
                        if (lp.rightMargin != 0) {
                            lp.rightMargin = 0;
                        }
                    } else if (lp.rightMargin != mRightInset) {
                        lp.rightMargin = mRightInset;
                        if (lp.leftMargin != 0) {
                            lp.leftMargin = 0;
                        }
                    }
                    child.requestLayout();
                }
            }
        }
    }

    @Override
    public FrameLayout.LayoutParams generateLayoutParams(AttributeSet attrs) {
        return new InsetLayoutParams(getContext(), attrs);
    }

    @Override
    protected FrameLayout.LayoutParams generateDefaultLayoutParams() {
        return new InsetLayoutParams(InsetLayoutParams.MATCH_PARENT,
                InsetLayoutParams.MATCH_PARENT);
    }

    private class SettingsObserver extends UserContentObserver {

        public SettingsObserver(Handler handler) {
            super(handler);
        }

        @Override
        protected void observe() {
            super.observe();
            mContext.getContentResolver().registerContentObserver(
                    CMSettings.System.getUriFor(CMSettings.System.NAVBAR_LEFT_IN_LANDSCAPE), false,
                    this, UserHandle.USER_CURRENT);
            update();
        }

        @Override
        protected void unobserve() {
            super.unobserve();
            mContext.getContentResolver().unregisterContentObserver(this);
        }

        @Override
        protected void update() {
            boolean before = mLeftInsetMode;
            mLeftInsetMode = CMSettings.System.getIntForUser(mContext.getContentResolver(),
                    CMSettings.System.NAVBAR_LEFT_IN_LANDSCAPE, 0, UserHandle.USER_CURRENT) == 1;
            if (mLeftInsetMode != before) {
                applyMargins();
            }
        }
    }

    public static class InsetLayoutParams extends FrameLayout.LayoutParams {

        public boolean ignoreRightInset;

        public InsetLayoutParams(int width, int height) {
            super(width, height);
        }

        public InsetLayoutParams(Context c, AttributeSet attrs) {
            super(c, attrs);

            TypedArray a = c.obtainStyledAttributes(attrs, R.styleable.StatusBarWindowView_Layout);
            ignoreRightInset = a.getBoolean(
                    R.styleable.StatusBarWindowView_Layout_ignoreRightInset, false);
            a.recycle();
        }
    }
}
+18 −86
Original line number Diff line number Diff line
@@ -64,8 +64,6 @@ public class StatusBarWindowView extends FrameLayout {
    private NotificationPanelView mNotificationPanel;
    private View mBrightnessMirror;

    private int mRightInset = 0;

    private PhoneStatusBar mService;
    private final Paint mTransparentSrcPaint = new Paint();

@@ -86,66 +84,6 @@ public class StatusBarWindowView extends FrameLayout {
        mSettingsObserver = new SettingsObserver(mHandler);
    }

    @Override
    protected boolean fitSystemWindows(Rect insets) {
        if (getFitsSystemWindows()) {
            boolean paddingChanged = insets.left != getPaddingLeft()
                    || insets.top != getPaddingTop()
                    || insets.bottom != getPaddingBottom();

            // Super-special right inset handling, because scrims and backdrop need to ignore it.
            if (insets.right != mRightInset) {
                mRightInset = insets.right;
                applyMargins();
            }
            // Drop top inset, apply left inset and pass through bottom inset.
            if (paddingChanged) {
                setPadding(insets.left, 0, 0, 0);
            }
            insets.left = 0;
            insets.top = 0;
            insets.right = 0;
        } else {
            if (mRightInset != 0) {
                mRightInset = 0;
                applyMargins();
            }
            boolean changed = getPaddingLeft() != 0
                    || getPaddingRight() != 0
                    || getPaddingTop() != 0
                    || getPaddingBottom() != 0;
            if (changed) {
                setPadding(0, 0, 0, 0);
            }
            insets.top = 0;
        }
        return false;
    }

    private void applyMargins() {
        final int N = getChildCount();
        for (int i = 0; i < N; i++) {
            View child = getChildAt(i);
            if (child.getLayoutParams() instanceof LayoutParams) {
                LayoutParams lp = (LayoutParams) child.getLayoutParams();
                if (!lp.ignoreRightInset && lp.rightMargin != mRightInset) {
                    lp.rightMargin = mRightInset;
                    child.requestLayout();
                }
            }
        }
    }

    @Override
    public FrameLayout.LayoutParams generateLayoutParams(AttributeSet attrs) {
        return new LayoutParams(getContext(), attrs);
    }

    @Override
    protected FrameLayout.LayoutParams generateDefaultLayoutParams() {
        return new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
    }

    @Override
    protected void onFinishInflate() {
        super.onFinishInflate();
@@ -190,11 +128,13 @@ public class StatusBarWindowView extends FrameLayout {
        // occur if our window is translucent. Since we are drawing the whole window anyway with
        // the scrim, we don't need the window to be cleared in the beginning.
        if (mService.isScrimSrcModeEnabled()) {
            IBinder windowToken = getWindowToken();
            if (getLayoutParams() instanceof WindowManager.LayoutParams) {
                WindowManager.LayoutParams lp = (WindowManager.LayoutParams) getLayoutParams();
                IBinder windowToken = getWindowToken();
                lp.token = windowToken;
                setLayoutParams(lp);
                WindowManagerGlobal.getInstance().changeCanvasOpacity(windowToken, true);
            }
            setWillNotDraw(false);
        } else {
            setWillNotDraw(!DEBUG);
@@ -207,6 +147,16 @@ public class StatusBarWindowView extends FrameLayout {
        mSettingsObserver.unobserve();
    }

    @Override
    protected boolean fitSystemWindows(Rect insets) {
        insets.bottom = 0;
        insets.top = 0;
        insets.right = 0;
        insets.left = 0;
        super.fitSystemWindows(insets);
        return false;
    }

    @Override
    public boolean dispatchKeyEvent(KeyEvent event) {
        boolean down = event.getAction() == KeyEvent.ACTION_DOWN;
@@ -300,7 +250,7 @@ public class StatusBarWindowView extends FrameLayout {
    }

    @Override
    public void onDraw(Canvas canvas) {
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        if (mService.isScrimSrcModeEnabled()) {
            // We need to ensure that our window is always drawn fully even when we have paddings,
@@ -351,24 +301,6 @@ public class StatusBarWindowView extends FrameLayout {
        removeView(content);
    }

    public class LayoutParams extends FrameLayout.LayoutParams {

        public boolean ignoreRightInset;

        public LayoutParams(int width, int height) {
            super(width, height);
        }

        public LayoutParams(Context c, AttributeSet attrs) {
            super(c, attrs);

            TypedArray a = c.obtainStyledAttributes(attrs, R.styleable.StatusBarWindowView_Layout);
            ignoreRightInset = a.getBoolean(
                    R.styleable.StatusBarWindowView_Layout_ignoreRightInset, false);
            a.recycle();
        }
    }

    class SettingsObserver extends ContentObserver {
        SettingsObserver(Handler handler) {
            super(handler);