diff options
| author | 2024-08-29 16:29:28 +0000 | |
|---|---|---|
| committer | 2024-08-29 16:29:28 +0000 | |
| commit | 1d41bc8d916f23be4702bf72695e1354d61a77f9 (patch) | |
| tree | a2169c2b06f3ddd385f70a259b64dd68d9efc5ee | |
| parent | b8a4bf7d0842e4625e45817610f2af5f31fac918 (diff) | |
| parent | e3d259bad6dded85ab222f8ed43b7f0fc1878ab8 (diff) | |
Merge "Use AirplaneModeInteractor to update airplane icon in the status bar" into main
4 files changed, 251 insertions, 6 deletions
diff --git a/packages/SystemUI/aconfig/systemui.aconfig b/packages/SystemUI/aconfig/systemui.aconfig index df4b51a9b7b9..92e657636203 100644 --- a/packages/SystemUI/aconfig/systemui.aconfig +++ b/packages/SystemUI/aconfig/systemui.aconfig @@ -363,6 +363,13 @@ flag { } flag { + name: "status_bar_signal_policy_refactor" + namespace: "systemui" + description: "Use a settings observer for airplane mode and make StatusBarSignalPolicy startable" + bug: "264539100" +} + +flag { name: "status_bar_swipe_over_chip" namespace: "systemui" description: "Allow users to swipe over the status bar chip to open the shade" diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarSignalPolicy.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarSignalPolicy.java index ba5939835a08..62297b0d0306 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarSignalPolicy.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarSignalPolicy.java @@ -16,6 +16,8 @@ package com.android.systemui.statusbar.phone; +import static com.android.systemui.Flags.statusBarSignalPolicyRefactor; + import android.annotation.NonNull; import android.content.Context; import android.os.Handler; @@ -29,10 +31,12 @@ import com.android.systemui.statusbar.connectivity.IconState; import com.android.systemui.statusbar.connectivity.NetworkController; import com.android.systemui.statusbar.connectivity.SignalCallback; import com.android.systemui.statusbar.phone.ui.StatusBarIconController; +import com.android.systemui.statusbar.pipeline.airplane.domain.interactor.AirplaneModeInteractor; import com.android.systemui.statusbar.policy.SecurityController; import com.android.systemui.tuner.TunerService; import com.android.systemui.tuner.TunerService.Tunable; import com.android.systemui.util.CarrierConfigTracker; +import com.android.systemui.util.kotlin.JavaAdapter; import java.util.ArrayList; import java.util.List; @@ -61,15 +65,14 @@ public class StatusBarSignalPolicy implements SignalCallback, private final Handler mHandler = Handler.getMain(); private final CarrierConfigTracker mCarrierConfigTracker; private final TunerService mTunerService; + private final JavaAdapter mJavaAdapter; + private final AirplaneModeInteractor mAirplaneModeInteractor; private boolean mHideAirplane; private boolean mHideMobile; private boolean mHideEthernet; private boolean mActivityEnabled; - // Track as little state as possible, and only for padding purposes - private boolean mIsAirplaneMode = false; - private ArrayList<CallIndicatorIconState> mCallIndicatorStates = new ArrayList<>(); private boolean mInitialized; @@ -80,15 +83,19 @@ public class StatusBarSignalPolicy implements SignalCallback, CarrierConfigTracker carrierConfigTracker, NetworkController networkController, SecurityController securityController, - TunerService tunerService + TunerService tunerService, + JavaAdapter javaAdapter, + AirplaneModeInteractor airplaneModeInteractor ) { mContext = context; mIconController = iconController; mCarrierConfigTracker = carrierConfigTracker; + mJavaAdapter = javaAdapter; mNetworkController = networkController; mSecurityController = securityController; mTunerService = tunerService; + mAirplaneModeInteractor = airplaneModeInteractor; mSlotAirplane = mContext.getString(com.android.internal.R.string.status_bar_airplane); mSlotMobile = mContext.getString(com.android.internal.R.string.status_bar_mobile); @@ -109,6 +116,12 @@ public class StatusBarSignalPolicy implements SignalCallback, mTunerService.addTunable(this, StatusBarIconController.ICON_HIDE_LIST); mNetworkController.addCallback(this); mSecurityController.addCallback(this); + + if (statusBarSignalPolicyRefactor()) { + mJavaAdapter.alwaysCollectFlow( + mAirplaneModeInteractor.isAirplaneMode(), + this::updateAirplaneModeIcon); + } } public void destroy() { @@ -222,15 +235,19 @@ public class StatusBarSignalPolicy implements SignalCallback, @Override public void setIsAirplaneMode(IconState icon) { + if (statusBarSignalPolicyRefactor()) { + return; + } + if (DEBUG) { Log.d(TAG, "setIsAirplaneMode: " + "icon = " + (icon == null ? "" : icon.toString())); } - mIsAirplaneMode = icon.visible && !mHideAirplane; + boolean isAirplaneMode = icon.visible && !mHideAirplane; int resId = icon.icon; String description = icon.contentDescription; - if (mIsAirplaneMode && resId > 0) { + if (isAirplaneMode && resId > 0) { mIconController.setIcon(mSlotAirplane, resId, description); mIconController.setIconVisibility(mSlotAirplane, true); } else { @@ -238,6 +255,21 @@ public class StatusBarSignalPolicy implements SignalCallback, } } + public void updateAirplaneModeIcon(boolean isAirplaneModeOn) { + if (StatusBarSignalPolicyRefactor.isUnexpectedlyInLegacyMode()) { + return; + } + + boolean isAirplaneMode = isAirplaneModeOn && !mHideAirplane; + mIconController.setIconVisibility(mSlotAirplane, isAirplaneMode); + if (isAirplaneMode) { + mIconController.setIcon( + mSlotAirplane, + TelephonyIcons.FLIGHT_MODE_ICON, + mContext.getString(R.string.accessibility_airplane_mode)); + } + } + /** * Stores the statusbar state for no Calling & SMS. */ diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarSignalPolicyRefactor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarSignalPolicyRefactor.kt new file mode 100644 index 000000000000..0577f495dd4f --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarSignalPolicyRefactor.kt @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2024 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 + +import com.android.systemui.Flags +import com.android.systemui.flags.FlagToken +import com.android.systemui.flags.RefactorFlagUtils + +/** Helper for reading or using the status_bar_signal_policy_refactor flag state. */ +@Suppress("NOTHING_TO_INLINE") +object StatusBarSignalPolicyRefactor { + /** The aconfig flag name */ + const val FLAG_NAME = Flags.FLAG_STATUS_BAR_SIGNAL_POLICY_REFACTOR + + /** A token used for dependency declaration */ + val token: FlagToken + get() = FlagToken(FLAG_NAME, isEnabled) + + /** Is the refactor enabled */ + @JvmStatic + inline val isEnabled + get() = Flags.statusBarSignalPolicyRefactor() + + /** + * Called to ensure code is only run when the flag is enabled. This protects users from the + * unintended behaviors caused by accidentally running new logic, while also crashing on an eng + * build to ensure that the refactor author catches issues in testing. + */ + @JvmStatic + inline fun isUnexpectedlyInLegacyMode() = + RefactorFlagUtils.isUnexpectedlyInLegacyMode(isEnabled, FLAG_NAME) + + /** + * Called to ensure code is only run when the flag is disabled. This will throw an exception if + * the flag is enabled to ensure that the refactor author catches issues in testing. + */ + @JvmStatic + inline fun assertInLegacyMode() = RefactorFlagUtils.assertInLegacyMode(isEnabled, FLAG_NAME) +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarSignalPolicyTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarSignalPolicyTest.kt new file mode 100644 index 000000000000..cdd5296a4cd7 --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarSignalPolicyTest.kt @@ -0,0 +1,153 @@ +/* + * Copyright (C) 2024 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 + +import android.platform.test.annotations.DisableFlags +import android.platform.test.annotations.EnableFlags +import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.filters.SmallTest +import com.android.internal.R +import com.android.settingslib.mobile.TelephonyIcons +import com.android.systemui.Flags.FLAG_STATUS_BAR_SIGNAL_POLICY_REFACTOR +import com.android.systemui.SysuiTestCase +import com.android.systemui.kosmos.Kosmos +import com.android.systemui.kosmos.testCase +import com.android.systemui.statusbar.connectivity.IconState +import com.android.systemui.statusbar.connectivity.NetworkController +import com.android.systemui.statusbar.phone.StatusBarSignalPolicy +import com.android.systemui.statusbar.phone.StatusBarSignalPolicy_Factory +import com.android.systemui.statusbar.phone.ui.StatusBarIconController +import com.android.systemui.statusbar.pipeline.airplane.domain.interactor.airplaneModeInteractor +import com.android.systemui.statusbar.policy.securityController +import com.android.systemui.tuner.TunerService +import com.android.systemui.util.CarrierConfigTracker +import com.android.systemui.util.kotlin.JavaAdapter +import com.android.systemui.util.mockito.mock +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.test.TestScope +import kotlinx.coroutines.test.runCurrent +import kotlinx.coroutines.test.runTest +import org.junit.Before +import org.junit.runner.RunWith +import org.mockito.Mockito.verify +import org.mockito.kotlin.clearInvocations +import org.mockito.kotlin.verifyZeroInteractions +import kotlin.test.Test + +@OptIn(ExperimentalCoroutinesApi::class) +@SmallTest +@RunWith(AndroidJUnit4::class) +class StatusBarSignalPolicyTest : SysuiTestCase() { + private val kosmos = Kosmos().also { it.testCase = this } + + private lateinit var underTest: StatusBarSignalPolicy + + private val testScope = TestScope() + + private val javaAdapter = JavaAdapter(testScope.backgroundScope) + private val airplaneModeInteractor = kosmos.airplaneModeInteractor + private val securityController = kosmos.securityController + + private val tunerService = mock<TunerService>() + private val statusBarIconController = mock<StatusBarIconController>() + private val networkController = mock<NetworkController>() + private val carrierConfigTracker = mock<CarrierConfigTracker>() + + private var slotAirplane: String? = null + + @Before + fun setup() { + underTest = + StatusBarSignalPolicy_Factory.newInstance( + mContext, + statusBarIconController, + carrierConfigTracker, + networkController, + securityController, + tunerService, + javaAdapter, + airplaneModeInteractor, + ) + + slotAirplane = mContext.getString(R.string.status_bar_airplane) + } + + @Test + @EnableFlags(FLAG_STATUS_BAR_SIGNAL_POLICY_REFACTOR) + fun airplaneModeViaInteractor_statusBarSignalPolicyRefactorFlagEnabled_iconUpdated() = + testScope.runTest { + underTest.init() + airplaneModeInteractor.setIsAirplaneMode(true) + runCurrent() + verify(statusBarIconController).setIconVisibility(slotAirplane, true) + + airplaneModeInteractor.setIsAirplaneMode(false) + runCurrent() + verify(statusBarIconController).setIconVisibility(slotAirplane, false) + } + + @Test + @EnableFlags(FLAG_STATUS_BAR_SIGNAL_POLICY_REFACTOR) + fun airplaneModeViaSignalCallback_statusBarSignalPolicyRefactorFlagEnabled_iconNotUpdated() = + testScope.runTest { + underTest.init() + runCurrent() + clearInvocations(statusBarIconController) + + // Make sure the legacy code path does not change airplane mode when the refactor + // flag is enabled. + underTest.setIsAirplaneMode(IconState(true, TelephonyIcons.FLIGHT_MODE_ICON, "")) + runCurrent() + verifyZeroInteractions(statusBarIconController) + + underTest.setIsAirplaneMode(IconState(false, TelephonyIcons.FLIGHT_MODE_ICON, "")) + runCurrent() + verifyZeroInteractions(statusBarIconController) + } + + @Test + @DisableFlags(FLAG_STATUS_BAR_SIGNAL_POLICY_REFACTOR) + fun airplaneModeViaSignalCallback_statusBarSignalPolicyRefactorFlagDisabled_iconUpdated() = + testScope.runTest { + underTest.init() + + underTest.setIsAirplaneMode(IconState(true, TelephonyIcons.FLIGHT_MODE_ICON, "")) + runCurrent() + verify(statusBarIconController).setIconVisibility(slotAirplane, true) + + underTest.setIsAirplaneMode(IconState(false, TelephonyIcons.FLIGHT_MODE_ICON, "")) + runCurrent() + verify(statusBarIconController).setIconVisibility(slotAirplane, false) + } + + @Test + @DisableFlags(FLAG_STATUS_BAR_SIGNAL_POLICY_REFACTOR) + fun airplaneModeViaInteractor_statusBarSignalPolicyRefactorFlagDisabled_iconNotUpdated() = + testScope.runTest { + underTest.init() + + // Make sure changing airplane mode from airplaneModeRepository does nothing + // if the StatusBarSignalPolicyRefactor is not enabled. + airplaneModeInteractor.setIsAirplaneMode(true) + runCurrent() + verifyZeroInteractions(statusBarIconController) + + airplaneModeInteractor.setIsAirplaneMode(false) + runCurrent() + verifyZeroInteractions(statusBarIconController) + } +} |