diff options
8 files changed, 478 insertions, 15 deletions
diff --git a/packages/SettingsLib/src/com/android/settingslib/satellite/SatelliteDialogUtils.kt b/packages/SettingsLib/src/com/android/settingslib/satellite/SatelliteDialogUtils.kt new file mode 100644 index 000000000000..d69c87b318e2 --- /dev/null +++ b/packages/SettingsLib/src/com/android/settingslib/satellite/SatelliteDialogUtils.kt @@ -0,0 +1,145 @@ +/* + * 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.settingslib.satellite + +import android.content.ComponentName +import android.content.Context +import android.content.Intent +import android.os.OutcomeReceiver +import android.telephony.satellite.SatelliteManager +import android.util.Log +import android.view.WindowManager +import androidx.lifecycle.LifecycleOwner +import androidx.lifecycle.lifecycleScope +import com.android.settingslib.wifi.WifiUtils +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.Dispatchers.Default +import kotlinx.coroutines.Job +import kotlinx.coroutines.asExecutor +import kotlinx.coroutines.launch +import kotlinx.coroutines.suspendCancellableCoroutine +import kotlinx.coroutines.withContext +import java.util.concurrent.ExecutionException +import java.util.concurrent.TimeoutException +import kotlin.coroutines.resume + +/** A util for Satellite dialog */ +object SatelliteDialogUtils { + + /** + * Uses to start Satellite dialog to prevent users from using the BT, Airplane Mode, and + * Wifi during the satellite mode is on. + */ + @JvmStatic + fun mayStartSatelliteWarningDialog( + context: Context, + lifecycleOwner: LifecycleOwner, + type: Int, + allowClick: (isAllowed: Boolean) -> Unit + ): Job { + return mayStartSatelliteWarningDialog( + context, lifecycleOwner.lifecycleScope, type, allowClick) + } + + /** + * Uses to start Satellite dialog to prevent users from using the BT, Airplane Mode, and + * Wifi during the satellite mode is on. + */ + @JvmStatic + fun mayStartSatelliteWarningDialog( + context: Context, + coroutineScope: CoroutineScope, + type: Int, + allowClick: (isAllowed: Boolean) -> Unit + ): Job = + coroutineScope.launch { + var isSatelliteModeOn = false + try { + isSatelliteModeOn = requestIsEnabled(context) + } catch (e: InterruptedException) { + Log.w(TAG, "Error to get satellite status : $e") + } catch (e: ExecutionException) { + Log.w(TAG, "Error to get satellite status : $e") + } catch (e: TimeoutException) { + Log.w(TAG, "Error to get satellite status : $e") + } + + if (isSatelliteModeOn) { + startSatelliteWarningDialog(context, type) + } + withContext(Dispatchers.Main) { + allowClick(!isSatelliteModeOn) + } + } + + private fun startSatelliteWarningDialog(context: Context, type: Int) { + context.startActivity(Intent(Intent.ACTION_MAIN).apply { + component = ComponentName( + "com.android.settings", + "com.android.settings.network.SatelliteWarningDialogActivity" + ) + putExtra(WifiUtils.DIALOG_WINDOW_TYPE, + WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG) + putExtra(EXTRA_TYPE_OF_SATELLITE_WARNING_DIALOG, type) + addFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_SINGLE_TOP) + }) + } + + /** + * Checks if the satellite modem is enabled. + * + * @param executor The executor to run the asynchronous operation on + * @return A ListenableFuture that will resolve to `true` if the satellite modem enabled, + * `false` otherwise. + */ + private suspend fun requestIsEnabled( + context: Context, + ): Boolean = withContext(Default) { + val satelliteManager: SatelliteManager? = + context.getSystemService(SatelliteManager::class.java) + if (satelliteManager == null) { + Log.w(TAG, "SatelliteManager is null") + return@withContext false + } + + suspendCancellableCoroutine {continuation -> + satelliteManager?.requestIsEnabled(Default.asExecutor(), + object : OutcomeReceiver<Boolean, SatelliteManager.SatelliteException> { + override fun onResult(result: Boolean) { + Log.i(TAG, "Satellite modem enabled status: $result") + continuation.resume(result) + } + + override fun onError(error: SatelliteManager.SatelliteException) { + super.onError(error) + Log.w(TAG, "Can't get satellite modem enabled status", error) + continuation.resume(false) + } + }) + } + } + + const val TAG = "SatelliteDialogUtils" + + const val EXTRA_TYPE_OF_SATELLITE_WARNING_DIALOG: String = + "extra_type_of_satellite_warning_dialog" + const val TYPE_IS_UNKNOWN = -1 + const val TYPE_IS_WIFI = 0 + const val TYPE_IS_BLUETOOTH = 1 + const val TYPE_IS_AIRPLANE_MODE = 2 +}
\ No newline at end of file diff --git a/packages/SettingsLib/tests/robotests/Android.bp b/packages/SettingsLib/tests/robotests/Android.bp index f4ddd0ac59df..916e57190b97 100644 --- a/packages/SettingsLib/tests/robotests/Android.bp +++ b/packages/SettingsLib/tests/robotests/Android.bp @@ -41,7 +41,10 @@ android_app { //########################################################### android_robolectric_test { name: "SettingsLibRoboTests", - srcs: ["src/**/*.java"], + srcs: [ + "src/**/*.java", + "src/**/*.kt", + ], static_libs: [ "Settings_robolectric_meta_service_file", "Robolectric_shadows_androidx_fragment_upstream", diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/satellite/SatelliteDialogUtilsTest.kt b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/satellite/SatelliteDialogUtilsTest.kt new file mode 100644 index 000000000000..aeda1ed66d16 --- /dev/null +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/satellite/SatelliteDialogUtilsTest.kt @@ -0,0 +1,162 @@ +/* + * 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.settingslib.satellite + +import android.content.Context +import android.content.Intent +import android.os.OutcomeReceiver +import android.platform.test.annotations.RequiresFlagsEnabled +import android.telephony.satellite.SatelliteManager +import android.telephony.satellite.SatelliteManager.SatelliteException +import android.util.AndroidRuntimeException +import androidx.test.core.app.ApplicationProvider +import com.android.internal.telephony.flags.Flags +import com.android.settingslib.satellite.SatelliteDialogUtils.TYPE_IS_WIFI +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.runBlocking +import org.junit.Assert.assertFalse +import org.junit.Assert.assertTrue +import org.junit.Before +import org.junit.Rule +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.Mock +import org.mockito.Mockito.any +import org.mockito.Mockito.`when` +import org.mockito.Spy +import org.mockito.junit.MockitoJUnit +import org.mockito.junit.MockitoRule +import org.mockito.Mockito.verify +import org.mockito.internal.verification.Times +import org.robolectric.RobolectricTestRunner + +@RunWith(RobolectricTestRunner::class) +class SatelliteDialogUtilsTest { + @JvmField + @Rule + val mockitoRule: MockitoRule = MockitoJUnit.rule() + + @Spy + var context: Context = ApplicationProvider.getApplicationContext() + @Mock + private lateinit var satelliteManager: SatelliteManager + + private val coroutineScope = CoroutineScope(Dispatchers.Main) + + @Before + fun setUp() { + `when`(context.getSystemService(SatelliteManager::class.java)) + .thenReturn(satelliteManager) + } + + @Test + @RequiresFlagsEnabled(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG) + fun mayStartSatelliteWarningDialog_satelliteIsOn_showWarningDialog() = runBlocking { + `when`( + satelliteManager.requestIsEnabled( + any(), any<OutcomeReceiver<Boolean, SatelliteManager.SatelliteException>>() + ) + ) + .thenAnswer { invocation -> + val receiver = invocation + .getArgument< + OutcomeReceiver<Boolean, SatelliteManager.SatelliteException>>( + 1 + ) + receiver.onResult(true) + null + } + + try { + SatelliteDialogUtils.mayStartSatelliteWarningDialog( + context, coroutineScope, TYPE_IS_WIFI, allowClick = { + assertTrue(it) + }) + } catch (e: AndroidRuntimeException) { + // Catch exception of starting activity . + } + } + + @Test + @RequiresFlagsEnabled(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG) + fun mayStartSatelliteWarningDialog_satelliteIsOff_notShowWarningDialog() = runBlocking { + `when`( + satelliteManager.requestIsEnabled( + any(), any<OutcomeReceiver<Boolean, SatelliteManager.SatelliteException>>() + ) + ) + .thenAnswer { invocation -> + val receiver = invocation + .getArgument< + OutcomeReceiver<Boolean, SatelliteManager.SatelliteException>>( + 1 + ) + receiver.onResult(false) + null + } + + + SatelliteDialogUtils.mayStartSatelliteWarningDialog( + context, coroutineScope, TYPE_IS_WIFI, allowClick = { + assertFalse(it) + }) + + verify(context, Times(0)).startActivity(any<Intent>()) + } + + @Test + @RequiresFlagsEnabled(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG) + fun mayStartSatelliteWarningDialog_noSatelliteManager_notShowWarningDialog() = runBlocking { + `when`(context.getSystemService(SatelliteManager::class.java)) + .thenReturn(null) + + SatelliteDialogUtils.mayStartSatelliteWarningDialog( + context, coroutineScope, TYPE_IS_WIFI, allowClick = { + assertFalse(it) + }) + + verify(context, Times(0)).startActivity(any<Intent>()) + } + + @Test + @RequiresFlagsEnabled(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG) + fun mayStartSatelliteWarningDialog_satelliteErrorResult_notShowWarningDialog() = runBlocking { + `when`( + satelliteManager.requestIsEnabled( + any(), any<OutcomeReceiver<Boolean, SatelliteManager.SatelliteException>>() + ) + ) + .thenAnswer { invocation -> + val receiver = invocation + .getArgument< + OutcomeReceiver<Boolean, SatelliteManager.SatelliteException>>( + 1 + ) + receiver.onError(SatelliteException(SatelliteManager.SATELLITE_RESULT_ERROR)) + null + } + + + SatelliteDialogUtils.mayStartSatelliteWarningDialog( + context, coroutineScope, TYPE_IS_WIFI, allowClick = { + assertFalse(it) + }) + + verify(context, Times(0)).startActivity(any<Intent>()) + } +} diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/AirplaneModeTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/AirplaneModeTile.java index 17251c37473f..f96bc0401c2a 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/AirplaneModeTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/AirplaneModeTile.java @@ -16,6 +16,8 @@ package com.android.systemui.qs.tiles; +import static com.android.settingslib.satellite.SatelliteDialogUtils.TYPE_IS_AIRPLANE_MODE; + import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; @@ -33,9 +35,12 @@ import android.view.View; import android.widget.Switch; import androidx.annotation.Nullable; +import androidx.annotation.VisibleForTesting; import com.android.internal.logging.MetricsLogger; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; +import com.android.internal.telephony.flags.Flags; +import com.android.settingslib.satellite.SatelliteDialogUtils; import com.android.systemui.broadcast.BroadcastDispatcher; import com.android.systemui.dagger.qualifiers.Background; import com.android.systemui.dagger.qualifiers.Main; @@ -56,6 +61,8 @@ import dagger.Lazy; import javax.inject.Inject; +import kotlinx.coroutines.Job; + /** Quick settings tile: Airplane mode **/ public class AirplaneModeTile extends QSTileImpl<BooleanState> { @@ -66,6 +73,9 @@ public class AirplaneModeTile extends QSTileImpl<BooleanState> { private final Lazy<ConnectivityManager> mLazyConnectivityManager; private boolean mListening; + @Nullable + @VisibleForTesting + Job mClickJob; @Inject public AirplaneModeTile( @@ -111,6 +121,21 @@ public class AirplaneModeTile extends QSTileImpl<BooleanState> { new Intent(TelephonyManager.ACTION_SHOW_NOTICE_ECM_BLOCK_OTHERS), 0); return; } + + if (Flags.oemEnabledSatelliteFlag()) { + if (mClickJob != null && !mClickJob.isCompleted()) { + return; + } + mClickJob = SatelliteDialogUtils.mayStartSatelliteWarningDialog( + mContext, this, TYPE_IS_AIRPLANE_MODE, isAllowClick -> { + if (isAllowClick) { + setEnabled(!airplaneModeEnabled); + } + return null; + }); + return; + } + setEnabled(!airplaneModeEnabled); } diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java index b0707db0d02d..410cc8cf1370 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java @@ -16,6 +16,7 @@ package com.android.systemui.qs.tiles; +import static com.android.settingslib.satellite.SatelliteDialogUtils.TYPE_IS_BLUETOOTH; import static com.android.systemui.util.PluralMessageFormaterKt.icuMessageFormat; import android.annotation.Nullable; @@ -34,11 +35,15 @@ import android.util.Log; import android.view.View; import android.widget.Switch; +import androidx.annotation.VisibleForTesting; + import com.android.internal.logging.MetricsLogger; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.settingslib.Utils; import com.android.settingslib.bluetooth.BluetoothUtils; import com.android.settingslib.bluetooth.CachedBluetoothDevice; +import com.android.settingslib.satellite.SatelliteDialogUtils; +import com.android.systemui.bluetooth.qsdialog.BluetoothTileDialogViewModel; import com.android.systemui.dagger.qualifiers.Background; import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.flags.FeatureFlags; @@ -60,6 +65,8 @@ import java.util.concurrent.Executor; import javax.inject.Inject; +import kotlinx.coroutines.Job; + /** Quick settings tile: Bluetooth **/ public class BluetoothTile extends QSTileImpl<BooleanState> { @@ -78,6 +85,9 @@ public class BluetoothTile extends QSTileImpl<BooleanState> { private final BluetoothTileDialogViewModel mDialogViewModel; private final FeatureFlags mFeatureFlags; + @Nullable + @VisibleForTesting + Job mClickJob; @Inject public BluetoothTile( @@ -110,6 +120,24 @@ public class BluetoothTile extends QSTileImpl<BooleanState> { @Override protected void handleClick(@Nullable View view) { + if (com.android.internal.telephony.flags.Flags.oemEnabledSatelliteFlag()) { + if (mClickJob != null && !mClickJob.isCompleted()) { + return; + } + mClickJob = SatelliteDialogUtils.mayStartSatelliteWarningDialog( + mContext, this, TYPE_IS_BLUETOOTH, isAllowClick -> { + if (!isAllowClick) { + return null; + } + handleClickEvent(view); + return null; + }); + return; + } + handleClickEvent(view); + } + + private void handleClickEvent(@Nullable View view) { if (mFeatureFlags.isEnabled(Flags.BLUETOOTH_QS_TILE_DIALOG)) { mDialogViewModel.showDialog(view); } else { diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogDelegate.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogDelegate.java index f30a838552e3..1d14a8fd906c 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogDelegate.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogDelegate.java @@ -15,6 +15,7 @@ */ package com.android.systemui.qs.tiles.dialog; +import static com.android.settingslib.satellite.SatelliteDialogUtils.TYPE_IS_WIFI; import static com.android.systemui.Prefs.Key.QS_HAS_TURNED_OFF_MOBILE_DATA; import static com.android.systemui.qs.tiles.dialog.InternetDialogController.MAX_WIFI_ENTRY_COUNT; @@ -57,6 +58,8 @@ import androidx.recyclerview.widget.RecyclerView; import com.android.internal.logging.UiEvent; import com.android.internal.logging.UiEventLogger; +import com.android.internal.telephony.flags.Flags; +import com.android.settingslib.satellite.SatelliteDialogUtils; import com.android.settingslib.wifi.WifiEnterpriseRestrictionUtils; import com.android.systemui.Prefs; import com.android.systemui.accessibility.floatingmenu.AnnotationLinkSpan; @@ -72,11 +75,12 @@ import dagger.assisted.Assisted; import dagger.assisted.AssistedFactory; import dagger.assisted.AssistedInject; -import kotlinx.coroutines.CoroutineScope; - import java.util.List; import java.util.concurrent.Executor; +import kotlinx.coroutines.CoroutineScope; +import kotlinx.coroutines.Job; + /** * Dialog for showing mobile network, connected Wi-Fi network and Wi-Fi networks. */ @@ -161,6 +165,9 @@ public class InternetDialogDelegate implements // Wi-Fi scanning progress bar protected boolean mIsProgressBarVisible; private SystemUIDialog mDialog; + private final CoroutineScope mCoroutineScope; + @Nullable + private Job mClickJob; @AssistedFactory public interface Factory { @@ -203,7 +210,7 @@ public class InternetDialogDelegate implements mCanConfigWifi = canConfigWifi; mCanChangeWifiState = WifiEnterpriseRestrictionUtils.isChangeWifiStateAllowed(context); mKeyguard = keyguardStateController; - + mCoroutineScope = coroutineScope; mUiEventLogger = uiEventLogger; mDialogTransitionAnimator = dialogTransitionAnimator; mAdapter = new InternetAdapter(mInternetDialogController); @@ -388,11 +395,9 @@ public class InternetDialogDelegate implements }); mConnectedWifListLayout.setOnClickListener(this::onClickConnectedWifi); mSeeAllLayout.setOnClickListener(this::onClickSeeMoreButton); - mWiFiToggle.setOnCheckedChangeListener( - (buttonView, isChecked) -> { - if (mInternetDialogController.isWifiEnabled() == isChecked) return; - mInternetDialogController.setWifiEnabled(isChecked); - }); + mWiFiToggle.setOnClickListener(v -> { + handleWifiToggleClicked(mWiFiToggle.isChecked()); + }); mDoneButton.setOnClickListener(v -> dialog.dismiss()); mShareWifiButton.setOnClickListener(v -> { if (mInternetDialogController.mayLaunchShareWifiSettings(mConnectedWifiEntry)) { @@ -404,6 +409,32 @@ public class InternetDialogDelegate implements }); } + private void handleWifiToggleClicked(boolean isChecked) { + if (Flags.oemEnabledSatelliteFlag()) { + if (mClickJob != null && !mClickJob.isCompleted()) { + return; + } + mClickJob = SatelliteDialogUtils.mayStartSatelliteWarningDialog( + mDialog.getContext(), mCoroutineScope, TYPE_IS_WIFI, isAllowClick -> { + if (isAllowClick) { + setWifiEnable(isChecked); + } else { + mWiFiToggle.setChecked(!isChecked); + } + return null; + }); + return; + } + setWifiEnable(isChecked); + } + + private void setWifiEnable(boolean isChecked) { + if (mInternetDialogController.isWifiEnabled() == isChecked) { + return; + } + mInternetDialogController.setWifiEnabled(isChecked); + } + @MainThread private void updateEthernet() { mEthernetLayout.setVisibility( diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/AirplaneModeTileTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/AirplaneModeTileTest.kt index e2a3fac60ee8..ad87315c34f7 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/AirplaneModeTileTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/AirplaneModeTileTest.kt @@ -22,7 +22,7 @@ import android.testing.AndroidTestingRunner import android.testing.TestableLooper import androidx.test.filters.SmallTest import com.android.internal.logging.MetricsLogger -import com.android.systemui.res.R +import com.android.internal.telephony.flags.Flags import com.android.systemui.SysuiTestCase import com.android.systemui.broadcast.BroadcastDispatcher import com.android.systemui.classifier.FalsingManagerFake @@ -33,10 +33,12 @@ import com.android.systemui.qs.QSHost import com.android.systemui.qs.QsEventLogger import com.android.systemui.qs.logging.QSLogger import com.android.systemui.qs.tileimpl.QSTileImpl +import com.android.systemui.res.R import com.android.systemui.settings.UserTracker import com.android.systemui.util.settings.GlobalSettings import com.google.common.truth.Truth.assertThat import dagger.Lazy +import kotlinx.coroutines.Job import org.junit.After import org.junit.Before import org.junit.Test @@ -44,11 +46,15 @@ import org.junit.runner.RunWith import org.mockito.Mock import org.mockito.Mockito import org.mockito.MockitoAnnotations +import org.mockito.kotlin.any +import org.mockito.kotlin.times +import org.mockito.kotlin.verify @RunWith(AndroidTestingRunner::class) @TestableLooper.RunWithLooper(setAsMainLooper = true) @SmallTest class AirplaneModeTileTest : SysuiTestCase() { + @Mock private lateinit var mHost: QSHost @Mock @@ -62,7 +68,9 @@ class AirplaneModeTileTest : SysuiTestCase() { @Mock private lateinit var mBroadcastDispatcher: BroadcastDispatcher @Mock - private lateinit var mConnectivityManager: Lazy<ConnectivityManager> + private lateinit var mLazyConnectivityManager: Lazy<ConnectivityManager> + @Mock + private lateinit var mConnectivityManager: ConnectivityManager @Mock private lateinit var mGlobalSettings: GlobalSettings @Mock @@ -72,13 +80,15 @@ class AirplaneModeTileTest : SysuiTestCase() { private lateinit var mTestableLooper: TestableLooper private lateinit var mTile: AirplaneModeTile + @Mock + private lateinit var mClickJob: Job @Before fun setUp() { MockitoAnnotations.initMocks(this) mTestableLooper = TestableLooper.get(this) Mockito.`when`(mHost.context).thenReturn(mContext) Mockito.`when`(mHost.userContext).thenReturn(mContext) - + Mockito.`when`(mLazyConnectivityManager.get()).thenReturn(mConnectivityManager) mTile = AirplaneModeTile( mHost, mUiEventLogger, @@ -90,7 +100,7 @@ class AirplaneModeTileTest : SysuiTestCase() { mActivityStarter, mQsLogger, mBroadcastDispatcher, - mConnectivityManager, + mLazyConnectivityManager, mGlobalSettings, mUserTracker) } @@ -120,4 +130,24 @@ class AirplaneModeTileTest : SysuiTestCase() { assertThat(state.icon) .isEqualTo(QSTileImpl.ResourceIcon.get(R.drawable.qs_airplane_icon_on)) } + + @Test + fun handleClick_noSatelliteFeature_directSetAirplaneMode() { + mSetFlagsRule.disableFlags(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG) + + mTile.handleClick(null) + + verify(mConnectivityManager).setAirplaneMode(any()) + } + + @Test + fun handleClick_hasSatelliteFeatureButClickIsProcessing_doNothing() { + mSetFlagsRule.enableFlags(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG) + Mockito.`when`(mClickJob.isCompleted).thenReturn(false) + mTile.mClickJob = mClickJob + + mTile.handleClick(null) + + verify(mConnectivityManager, times(0)).setAirplaneMode(any()) + } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/BluetoothTileTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/BluetoothTileTest.kt index 82ee99a29427..4213d4867e5e 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/BluetoothTileTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/BluetoothTileTest.kt @@ -9,10 +9,11 @@ import android.testing.TestableLooper import android.testing.TestableLooper.RunWithLooper import androidx.test.filters.SmallTest import com.android.internal.logging.MetricsLogger +import com.android.internal.telephony.flags.Flags import com.android.settingslib.Utils import com.android.settingslib.bluetooth.CachedBluetoothDevice -import com.android.systemui.res.R import com.android.systemui.SysuiTestCase +import com.android.systemui.bluetooth.qsdialog.BluetoothTileDialogViewModel import com.android.systemui.classifier.FalsingManagerFake import com.android.systemui.flags.FeatureFlagsClassic import com.android.systemui.plugins.ActivityStarter @@ -24,12 +25,14 @@ import com.android.systemui.qs.QsEventLogger import com.android.systemui.qs.logging.QSLogger import com.android.systemui.qs.tileimpl.QSTileImpl import com.android.systemui.qs.tiles.dialog.bluetooth.BluetoothTileDialogViewModel +import com.android.systemui.res.R import com.android.systemui.statusbar.policy.BluetoothController import com.android.systemui.util.mockito.any import com.android.systemui.util.mockito.eq import com.android.systemui.util.mockito.mock import com.android.systemui.util.mockito.whenever import com.google.common.truth.Truth.assertThat +import kotlinx.coroutines.Job import org.junit.After import org.junit.Before import org.junit.Test @@ -37,6 +40,7 @@ import org.junit.runner.RunWith import org.mockito.Mock import org.mockito.Mockito.times import org.mockito.Mockito.verify +import org.mockito.Mockito.`when` import org.mockito.MockitoAnnotations @RunWith(AndroidTestingRunner::class) @@ -54,7 +58,7 @@ class BluetoothTileTest : SysuiTestCase() { @Mock private lateinit var uiEventLogger: QsEventLogger @Mock private lateinit var featureFlags: FeatureFlagsClassic @Mock private lateinit var bluetoothTileDialogViewModel: BluetoothTileDialogViewModel - + @Mock private lateinit var clickJob: Job private lateinit var testableLooper: TestableLooper private lateinit var tile: FakeBluetoothTile @@ -191,6 +195,41 @@ class BluetoothTileTest : SysuiTestCase() { } @Test + fun handleClick_hasSatelliteFeatureButNoQsTileDialogAndClickIsProcessing_doNothing() { + mSetFlagsRule.enableFlags(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG) + `when`(featureFlags.isEnabled(com.android.systemui.flags.Flags.BLUETOOTH_QS_TILE_DIALOG)) + .thenReturn(false) + `when`(clickJob.isCompleted).thenReturn(false) + tile.mClickJob = clickJob + + tile.handleClick(null) + + verify(bluetoothController, times(0)).setBluetoothEnabled(any()) + } + + @Test + fun handleClick_noSatelliteFeatureAndNoQsTileDialog_directSetBtEnable() { + mSetFlagsRule.disableFlags(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG) + `when`(featureFlags.isEnabled(com.android.systemui.flags.Flags.BLUETOOTH_QS_TILE_DIALOG)) + .thenReturn(false) + + tile.handleClick(null) + + verify(bluetoothController).setBluetoothEnabled(any()) + } + + @Test + fun handleClick_noSatelliteFeatureButHasQsTileDialog_showDialog() { + mSetFlagsRule.disableFlags(Flags.FLAG_OEM_ENABLED_SATELLITE_FLAG) + `when`(featureFlags.isEnabled(com.android.systemui.flags.Flags.BLUETOOTH_QS_TILE_DIALOG)) + .thenReturn(true) + + tile.handleClick(null) + + verify(bluetoothTileDialogViewModel).showDialog(null) + } + + @Test fun testMetadataListener_whenDisconnected_isUnregistered() { val state = QSTile.BooleanState() val cachedDevice = mock<CachedBluetoothDevice>() |