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

Commit 1067feb9 authored by Caitlin Shkuratov's avatar Caitlin Shkuratov
Browse files

[Status Bar] Store disable flag calculations in a data class.

The disable flags are split into two ints and are difficult to reason
about because they're negative booleans and involve bitwise logic.

This immediately converts the disable flags into a data class object
with clear naming and positive booleans.

Fixes: 279899176
Test: atest CollapsedStatuBarFragmentTest (existing tests are mostly
sufficient, added a few additional ones)
Test: atest StatusBarVisibilityModelTest
Test: verify status bar still hidden on keyguard
Test: verify clock & notif icons hidden when there's a HUN
Test: verify notif icons hidden when there's an ongoing call
Test: verify CollapsedSbFragmentLog statements

Change-Id: If0d82a5be1858d71a68e2c1aeda9c790be229168
parent b3ca9f6d
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -209,7 +209,7 @@ public class LogModule {
    @SysUISingleton
    @CollapsedSbFragmentLog
    public static LogBuffer provideCollapsedSbFragmentLogBuffer(LogBufferFactory factory) {
        return factory.create("CollapsedSbFragmentLog", 20);
        return factory.create("CollapsedSbFragmentLog", 40);
    }

    /**
+52 −68
Original line number Diff line number Diff line
@@ -14,11 +14,7 @@

package com.android.systemui.statusbar.phone.fragment;

import static android.app.StatusBarManager.DISABLE2_SYSTEM_ICONS;
import static android.app.StatusBarManager.DISABLE_CLOCK;
import static android.app.StatusBarManager.DISABLE_NOTIFICATION_ICONS;
import static android.app.StatusBarManager.DISABLE_ONGOING_CALL_CHIP;
import static android.app.StatusBarManager.DISABLE_SYSTEM_INFO;


import static com.android.systemui.statusbar.events.SystemStatusAnimationSchedulerKt.IDLE;
import static com.android.systemui.statusbar.events.SystemStatusAnimationSchedulerKt.SHOWING_PERSISTENT_DOT;
@@ -112,13 +108,13 @@ public class CollapsedStatusBarFragment extends Fragment implements CommandQueue
    private View mClockView;
    private View mOngoingCallChip;
    private View mNotificationIconAreaInner;
    // Disabled flags come in from external callers, but we also sometimes modify them internally.
    // We need to store both so that we don't accidentally propagate our internally modified flags
    // for too long.
    private int mExternalDisabled1;
    private int mExternalDisabled2;
    private int mInternalDisabled1;
    private int mInternalDisabled2;
    // Visibilities come in from external system callers via disable flags, but we also sometimes
    // modify the visibilities internally. We need to store both so that we don't accidentally
    // propagate our internally modified flags for too long.
    private StatusBarVisibilityModel mLastSystemVisibility =
            StatusBarVisibilityModel.createDefaultModel();
    private StatusBarVisibilityModel mLastModifiedVisibility =
            StatusBarVisibilityModel.createDefaultModel();
    private DarkIconManager mDarkIconManager;
    private final StatusBarFragmentComponent.Factory mStatusBarFragmentComponentFactory;
    private final CommandQueue mCommandQueue;
@@ -393,8 +389,7 @@ public class CollapsedStatusBarFragment extends Fragment implements CommandQueue
        }
        notificationIconArea.addView(mNotificationIconAreaInner);

        // #disable should have already been called, so use the disable values to set visibility.
        updateNotificationIconAreaAndCallChip(mInternalDisabled1, false);
        updateNotificationIconAreaAndCallChip(/* animate= */ false);
    }

    /**
@@ -408,63 +403,55 @@ public class CollapsedStatusBarFragment extends Fragment implements CommandQueue
        return mStatusBarFragmentComponent;
    }

    private void updateStatusBarVisibilities(boolean animate) {
        // Make sure that we pass the last *external* flags so that we don't accidentally propagate
        // our internal adjustments.
        disable(getContext().getDisplayId(), mExternalDisabled1, mExternalDisabled2, animate);
    }

    @Override
    public void disable(int displayId, int state1, int state2, boolean animate) {
        if (displayId != getContext().getDisplayId()) {
            return;
        }
        mCollapsedStatusBarFragmentLogger
                .logDisableFlagChange(new DisableState(state1, state2));
        mLastSystemVisibility =
                StatusBarVisibilityModel.createModelFromFlags(state1, state2);
        updateStatusBarVisibilities(animate);
    }

        mExternalDisabled1 = state1;
        mExternalDisabled2 = state2;

        int state1BeforeAdjustment = state1;
        state1 = adjustDisableFlags(state1);

        mCollapsedStatusBarFragmentLogger.logDisableFlagChange(
                /* new= */ new DisableState(state1BeforeAdjustment, state2),
                /* newAfterLocalModification= */ new DisableState(state1, state2));
    private void updateStatusBarVisibilities(boolean animate) {
        StatusBarVisibilityModel previousModel = mLastModifiedVisibility;
        StatusBarVisibilityModel newModel = calculateInternalModel(mLastSystemVisibility);
        mCollapsedStatusBarFragmentLogger.logVisibilityModel(newModel);
        mLastModifiedVisibility = newModel;

        final int old1 = mInternalDisabled1;
        final int diff1 = state1 ^ old1;
        final int old2 = mInternalDisabled2;
        final int diff2 = state2 ^ old2;
        mInternalDisabled1 = state1;
        mInternalDisabled2 = state2;
        if ((diff1 & DISABLE_SYSTEM_INFO) != 0 || ((diff2 & DISABLE2_SYSTEM_ICONS) != 0)) {
            if ((state1 & DISABLE_SYSTEM_INFO) != 0 || ((state2 & DISABLE2_SYSTEM_ICONS) != 0)) {
                hideEndSideContent(animate);
                hideOperatorName(animate);
            } else {
        if (newModel.getShowSystemInfo() != previousModel.getShowSystemInfo()) {
            if (newModel.getShowSystemInfo()) {
                showEndSideContent(animate);
                showOperatorName(animate);
            } else {
                hideEndSideContent(animate);
                hideOperatorName(animate);
            }
        }

        // The ongoing call chip and notification icon visibilities are intertwined, so update both
        // if either change.
        if (((diff1 & DISABLE_ONGOING_CALL_CHIP) != 0)
                || ((diff1 & DISABLE_NOTIFICATION_ICONS) != 0)) {
            updateNotificationIconAreaAndCallChip(state1, animate);
        if (newModel.getShowNotificationIcons() != previousModel.getShowNotificationIcons()
                || newModel.getShowOngoingCallChip() != previousModel.getShowOngoingCallChip()) {
            updateNotificationIconAreaAndCallChip(animate);
        }

        // The clock may have already been hidden, but we might want to shift its
        // visibility to GONE from INVISIBLE or vice versa
        if ((diff1 & DISABLE_CLOCK) != 0 || mClockView.getVisibility() != clockHiddenMode()) {
            if ((state1 & DISABLE_CLOCK) != 0) {
                hideClock(animate);
            } else {
        if (newModel.getShowClock() != previousModel.getShowClock()
                || mClockView.getVisibility() != clockHiddenMode()) {
            if (newModel.getShowClock()) {
                showClock(animate);
            } else {
                hideClock(animate);
            }
        }
    }

    protected int adjustDisableFlags(int state) {
    private StatusBarVisibilityModel calculateInternalModel(
            StatusBarVisibilityModel externalModel) {
        boolean headsUpVisible =
                mStatusBarFragmentComponent.getHeadsUpAppearanceController().shouldBeVisible();

@@ -473,34 +460,31 @@ public class CollapsedStatusBarFragment extends Fragment implements CommandQueue
                && shouldHideNotificationIcons()
                && !(mStatusBarStateController.getState() == StatusBarState.KEYGUARD
                        && headsUpVisible)) {
            state |= DISABLE_NOTIFICATION_ICONS;
            state |= DISABLE_SYSTEM_INFO;
            state |= DISABLE_CLOCK;
        }

        if (mOngoingCallController.hasOngoingCall()) {
            state &= ~DISABLE_ONGOING_CALL_CHIP;
        } else {
            state |= DISABLE_ONGOING_CALL_CHIP;
        }

        if (headsUpVisible) {
            // Disable everything on the left side of the status bar, since the app name for the
            // heads up notification appears there instead.
            state |= DISABLE_CLOCK;
            state |= DISABLE_ONGOING_CALL_CHIP;
            // Hide everything
            return new StatusBarVisibilityModel(
                    /* showClock= */ false,
                    /* showNotificationIcons= */ false,
                    /* showOngoingCallChip= */ false,
                    /* showSystemInfo= */ false);
        }

        return state;
        boolean showClock = externalModel.getShowClock() && !headsUpVisible;
        boolean showOngoingCallChip = mOngoingCallController.hasOngoingCall() && !headsUpVisible;
        return new StatusBarVisibilityModel(
                showClock,
                externalModel.getShowNotificationIcons(),
                showOngoingCallChip,
                externalModel.getShowSystemInfo());
    }

    /**
     * Updates the visibility of the notification icon area and ongoing call chip based on disabled1
     * state.
     */
    private void updateNotificationIconAreaAndCallChip(int state1, boolean animate) {
        boolean disableNotifications = (state1 & DISABLE_NOTIFICATION_ICONS) != 0;
        boolean hasOngoingCall = (state1 & DISABLE_ONGOING_CALL_CHIP) == 0;
    private void updateNotificationIconAreaAndCallChip(boolean animate) {
        StatusBarVisibilityModel visibilityModel = mLastModifiedVisibility;
        boolean disableNotifications = !visibilityModel.getShowNotificationIcons();
        boolean hasOngoingCall = visibilityModel.getShowOngoingCallChip();

        // Hide notifications if the disable flag is set or we have an ongoing call.
        if (disableNotifications || hasOngoingCall) {
+19 −5
Original line number Diff line number Diff line
@@ -37,7 +37,6 @@ class CollapsedStatusBarFragmentLogger @Inject constructor(
     */
    fun logDisableFlagChange(
        new: DisableFlagsLogger.DisableState,
        newAfterLocalModification: DisableFlagsLogger.DisableState
    ) {
        buffer.log(
                TAG,
@@ -45,19 +44,34 @@ class CollapsedStatusBarFragmentLogger @Inject constructor(
                {
                    int1 = new.disable1
                    int2 = new.disable2
                    long1 = newAfterLocalModification.disable1.toLong()
                    long2 = newAfterLocalModification.disable2.toLong()
                },
                {
                    disableFlagsLogger.getDisableFlagsString(
                        old = null,
                        new = DisableFlagsLogger.DisableState(int1, int2),
                        newAfterLocalModification =
                            DisableFlagsLogger.DisableState(long1.toInt(), long2.toInt())
                    )
                }
        )
    }

    fun logVisibilityModel(model: StatusBarVisibilityModel) {
        buffer.log(
            TAG,
            LogLevel.INFO,
            {
                bool1 = model.showClock
                bool2 = model.showNotificationIcons
                bool3 = model.showOngoingCallChip
                bool4 = model.showSystemInfo
            },
            { "New visibilities calculated internally. " +
                    "showClock=$bool1 " +
                    "showNotificationIcons=$bool2 " +
                    "showOngoingCallChip=$bool3 " +
                    "showSystemInfo=$bool4"
            }
        )
    }
}

private const val TAG = "CollapsedSbFragment"
+58 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2023 The Android Open Source 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.fragment

import android.app.StatusBarManager.DISABLE2_NONE
import android.app.StatusBarManager.DISABLE2_SYSTEM_ICONS
import android.app.StatusBarManager.DISABLE_CLOCK
import android.app.StatusBarManager.DISABLE_NONE
import android.app.StatusBarManager.DISABLE_NOTIFICATION_ICONS
import android.app.StatusBarManager.DISABLE_ONGOING_CALL_CHIP
import android.app.StatusBarManager.DISABLE_SYSTEM_INFO

/** A model for which parts of the status bar should be visible or not visible. */
data class StatusBarVisibilityModel(
    val showClock: Boolean,
    val showNotificationIcons: Boolean,
    val showOngoingCallChip: Boolean,
    val showSystemInfo: Boolean,
) {
    companion object {
        /** Creates the default model. */
        @JvmStatic
        fun createDefaultModel(): StatusBarVisibilityModel {
            return createModelFromFlags(DISABLE_NONE, DISABLE2_NONE)
        }

        /**
         * Given a set of disabled flags, converts them into the correct visibility statuses.
         *
         * See [CommandQueue.Callbacks.disable].
         */
        @JvmStatic
        fun createModelFromFlags(disabled1: Int, disabled2: Int): StatusBarVisibilityModel {
            return StatusBarVisibilityModel(
                showClock = (disabled1 and DISABLE_CLOCK) == 0,
                showNotificationIcons = (disabled1 and DISABLE_NOTIFICATION_ICONS) == 0,
                // TODO(b/279899176): [CollapsedStatusBarFragment] always overwrites this with the
                //  value of [OngoingCallController]. Do we need to process the flag here?
                showOngoingCallChip = (disabled1 and DISABLE_ONGOING_CALL_CHIP) == 0,
                showSystemInfo =
                    (disabled1 and DISABLE_SYSTEM_INFO) == 0 &&
                        (disabled2 and DISABLE2_SYSTEM_ICONS) == 0
            )
        }
    }
}
+28 −4
Original line number Diff line number Diff line
@@ -43,15 +43,39 @@ class CollapsedStatusBarFragmentLoggerTest : SysuiTestCase() {
    fun logDisableFlagChange_bufferHasStates() {
        val state = DisableFlagsLogger.DisableState(0, 1)

        logger.logDisableFlagChange(state, state)
        logger.logDisableFlagChange(state)

        val stringWriter = StringWriter()
        buffer.dump(PrintWriter(stringWriter), tailLength = 0)
        val actualString = stringWriter.toString()
        val expectedLogString = disableFlagsLogger.getDisableFlagsString(
            old = null, new = state, newAfterLocalModification = state
        val expectedLogString =
            disableFlagsLogger.getDisableFlagsString(
                old = null,
                new = state,
                newAfterLocalModification = null,
            )

        assertThat(actualString).contains(expectedLogString)
    }

    @Test
    fun logVisibilityModel_bufferCorrect() {
        logger.logVisibilityModel(
            StatusBarVisibilityModel(
                showClock = false,
                showNotificationIcons = true,
                showOngoingCallChip = false,
                showSystemInfo = true,
            )
        )

        val stringWriter = StringWriter()
        buffer.dump(PrintWriter(stringWriter), tailLength = 0)
        val actualString = stringWriter.toString()

        assertThat(actualString).contains("showClock=false")
        assertThat(actualString).contains("showNotificationIcons=true")
        assertThat(actualString).contains("showOngoingCallChip=false")
        assertThat(actualString).contains("showSystemInfo=true")
    }
}
Loading