Merge changes I0eaf7473,Ib31a9bcb into udc-qpr-dev
* changes: Add status bar icon when a connected display is attached Introduce ConnectedDisplayInteractor
This commit is contained in:
committed by
Android (Google) Code Review
commit
7e79f07810
@@ -46,6 +46,7 @@
|
||||
<item><xliff:g id="id">@string/status_bar_secure</xliff:g></item>
|
||||
<item><xliff:g id="id">@string/status_bar_managed_profile</xliff:g></item>
|
||||
<item><xliff:g id="id">@string/status_bar_cast</xliff:g></item>
|
||||
<item><xliff:g id="id">@string/status_bar_connected_display</xliff:g></item>
|
||||
<item><xliff:g id="id">@string/status_bar_screen_record</xliff:g></item>
|
||||
<item><xliff:g id="id">@string/status_bar_vpn</xliff:g></item>
|
||||
<item><xliff:g id="id">@string/status_bar_bluetooth</xliff:g></item>
|
||||
@@ -72,6 +73,7 @@
|
||||
<string translatable="false" name="status_bar_sync_failing">sync_failing</string>
|
||||
<string translatable="false" name="status_bar_sync_active">sync_active</string>
|
||||
<string translatable="false" name="status_bar_cast">cast</string>
|
||||
<string translatable="false" name="status_bar_connected_display">connected_display</string>
|
||||
<string translatable="false" name="status_bar_hotspot">hotspot</string>
|
||||
<string translatable="false" name="status_bar_location">location</string>
|
||||
<string translatable="false" name="status_bar_bluetooth">bluetooth</string>
|
||||
|
||||
@@ -3100,6 +3100,7 @@
|
||||
<java-symbol type="string" name="status_bar_sync_failing" />
|
||||
<java-symbol type="string" name="status_bar_sync_active" />
|
||||
<java-symbol type="string" name="status_bar_cast" />
|
||||
<java-symbol type="string" name="status_bar_connected_display" />
|
||||
<java-symbol type="string" name="status_bar_hotspot" />
|
||||
<java-symbol type="string" name="status_bar_location" />
|
||||
<java-symbol type="string" name="status_bar_bluetooth" />
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
<!--
|
||||
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.
|
||||
-->
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:fillColor="@android:color/white"
|
||||
android:viewportWidth="960"
|
||||
android:viewportHeight="960">
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M320,840L320,760L400,760L400,680L160,680Q127,680 103.5,656.5Q80,633 80,600L80,200Q80,167 103.5,143.5Q127,120 160,120L800,120Q833,120 856.5,143.5Q880,167 880,200L880,600Q880,633 856.5,656.5Q833,680 800,680L560,680L560,760L640,760L640,840L320,840ZM160,600L800,600Q800,600 800,600Q800,600 800,600L800,200Q800,200 800,200Q800,200 800,200L160,200Q160,200 160,200Q160,200 160,200L160,600Q160,600 160,600Q160,600 160,600ZM160,600Q160,600 160,600Q160,600 160,600L160,200Q160,200 160,200Q160,200 160,200L160,200Q160,200 160,200Q160,200 160,200L160,600Q160,600 160,600Q160,600 160,600L160,600Z" />
|
||||
</vector>
|
||||
@@ -47,6 +47,7 @@ import com.android.systemui.controls.dagger.ControlsModule;
|
||||
import com.android.systemui.dagger.qualifiers.Main;
|
||||
import com.android.systemui.dagger.qualifiers.SystemUser;
|
||||
import com.android.systemui.demomode.dagger.DemoModeModule;
|
||||
import com.android.systemui.display.DisplayModule;
|
||||
import com.android.systemui.doze.dagger.DozeComponent;
|
||||
import com.android.systemui.dreams.dagger.DreamModule;
|
||||
import com.android.systemui.dump.DumpManager;
|
||||
@@ -163,6 +164,7 @@ import javax.inject.Named;
|
||||
ClipboardOverlayModule.class,
|
||||
ClockRegistryModule.class,
|
||||
CommonRepositoryModule.class,
|
||||
DisplayModule.class,
|
||||
ConnectivityModule.class,
|
||||
CoroutinesModule.class,
|
||||
DreamModule.class,
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* 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.display
|
||||
|
||||
import com.android.systemui.display.data.repository.DisplayRepository
|
||||
import com.android.systemui.display.data.repository.DisplayRepositoryImpl
|
||||
import com.android.systemui.display.domain.interactor.ConnectedDisplayInteractor
|
||||
import com.android.systemui.display.domain.interactor.ConnectedDisplayInteractorImpl
|
||||
import dagger.Binds
|
||||
import dagger.Module
|
||||
|
||||
/** Module binding display related classes. */
|
||||
@Module
|
||||
interface DisplayModule {
|
||||
@Binds
|
||||
fun bindConnectedDisplayInteractor(
|
||||
provider: ConnectedDisplayInteractorImpl
|
||||
): ConnectedDisplayInteractor
|
||||
|
||||
@Binds fun bindsDisplayRepository(displayRepository: DisplayRepositoryImpl): DisplayRepository
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
* 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.display.domain.interactor
|
||||
|
||||
import android.view.Display
|
||||
import com.android.systemui.dagger.SysUISingleton
|
||||
import com.android.systemui.display.data.repository.DisplayRepository
|
||||
import com.android.systemui.display.domain.interactor.ConnectedDisplayInteractor.State
|
||||
import javax.inject.Inject
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.distinctUntilChanged
|
||||
import kotlinx.coroutines.flow.map
|
||||
|
||||
/** Provides information about an external connected display. */
|
||||
interface ConnectedDisplayInteractor {
|
||||
/**
|
||||
* Provides the current external display state.
|
||||
*
|
||||
* The state is:
|
||||
* - [State.CONNECTED] when there is at least one display with [TYPE_EXTERNAL].
|
||||
* - [State.CONNECTED_SECURE] when is at least one display with both [TYPE_EXTERNAL] AND
|
||||
* [Display.FLAG_SECURE] set
|
||||
*/
|
||||
val connectedDisplayState: Flow<State>
|
||||
|
||||
/** Possible connected display state. */
|
||||
enum class State {
|
||||
DISCONNECTED,
|
||||
CONNECTED,
|
||||
CONNECTED_SECURE,
|
||||
}
|
||||
}
|
||||
|
||||
@SysUISingleton
|
||||
class ConnectedDisplayInteractorImpl
|
||||
@Inject
|
||||
constructor(
|
||||
displayRepository: DisplayRepository,
|
||||
) : ConnectedDisplayInteractor {
|
||||
|
||||
override val connectedDisplayState: Flow<State> =
|
||||
displayRepository.displays
|
||||
.map { displays ->
|
||||
val externalDisplays =
|
||||
displays.filter { display -> display.type == Display.TYPE_EXTERNAL }
|
||||
|
||||
val secureExternalDisplays =
|
||||
externalDisplays.filter { it.flags and Display.FLAG_SECURE != 0 }
|
||||
|
||||
if (externalDisplays.isEmpty()) {
|
||||
State.DISCONNECTED
|
||||
} else if (!secureExternalDisplays.isEmpty()) {
|
||||
State.CONNECTED_SECURE
|
||||
} else {
|
||||
State.CONNECTED
|
||||
}
|
||||
}
|
||||
.distinctUntilChanged()
|
||||
}
|
||||
@@ -48,6 +48,7 @@ import com.android.systemui.broadcast.BroadcastDispatcher;
|
||||
import com.android.systemui.dagger.qualifiers.DisplayId;
|
||||
import com.android.systemui.dagger.qualifiers.Main;
|
||||
import com.android.systemui.dagger.qualifiers.UiBackground;
|
||||
import com.android.systemui.display.domain.interactor.ConnectedDisplayInteractor;
|
||||
import com.android.systemui.privacy.PrivacyItem;
|
||||
import com.android.systemui.privacy.PrivacyItemController;
|
||||
import com.android.systemui.privacy.PrivacyType;
|
||||
@@ -74,6 +75,7 @@ import com.android.systemui.statusbar.policy.SensorPrivacyController;
|
||||
import com.android.systemui.statusbar.policy.UserInfoController;
|
||||
import com.android.systemui.statusbar.policy.ZenModeController;
|
||||
import com.android.systemui.util.RingerModeTracker;
|
||||
import com.android.systemui.util.kotlin.JavaAdapter;
|
||||
import com.android.systemui.util.time.DateFormatUtil;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
@@ -121,9 +123,12 @@ public class PhoneStatusBarPolicy
|
||||
private final String mSlotCamera;
|
||||
private final String mSlotSensorsOff;
|
||||
private final String mSlotScreenRecord;
|
||||
private final String mSlotConnectedDisplay;
|
||||
private final int mDisplayId;
|
||||
private final SharedPreferences mSharedPreferences;
|
||||
private final DateFormatUtil mDateFormatUtil;
|
||||
private final JavaAdapter mJavaAdapter;
|
||||
private final ConnectedDisplayInteractor mConnectedDisplayInteractor;
|
||||
private final TelecomManager mTelecomManager;
|
||||
|
||||
private final Handler mHandler;
|
||||
@@ -182,9 +187,13 @@ public class PhoneStatusBarPolicy
|
||||
@Main SharedPreferences sharedPreferences, DateFormatUtil dateFormatUtil,
|
||||
RingerModeTracker ringerModeTracker,
|
||||
PrivacyItemController privacyItemController,
|
||||
PrivacyLogger privacyLogger) {
|
||||
PrivacyLogger privacyLogger,
|
||||
ConnectedDisplayInteractor connectedDisplayInteractor,
|
||||
JavaAdapter javaAdapter
|
||||
) {
|
||||
mIconController = iconController;
|
||||
mCommandQueue = commandQueue;
|
||||
mConnectedDisplayInteractor = connectedDisplayInteractor;
|
||||
mBroadcastDispatcher = broadcastDispatcher;
|
||||
mHandler = new Handler(looper);
|
||||
mResources = resources;
|
||||
@@ -211,8 +220,11 @@ public class PhoneStatusBarPolicy
|
||||
mTelecomManager = telecomManager;
|
||||
mRingerModeTracker = ringerModeTracker;
|
||||
mPrivacyLogger = privacyLogger;
|
||||
mJavaAdapter = javaAdapter;
|
||||
|
||||
mSlotCast = resources.getString(com.android.internal.R.string.status_bar_cast);
|
||||
mSlotConnectedDisplay = resources.getString(
|
||||
com.android.internal.R.string.status_bar_connected_display);
|
||||
mSlotHotspot = resources.getString(com.android.internal.R.string.status_bar_hotspot);
|
||||
mSlotBluetooth = resources.getString(com.android.internal.R.string.status_bar_bluetooth);
|
||||
mSlotTty = resources.getString(com.android.internal.R.string.status_bar_tty);
|
||||
@@ -285,6 +297,10 @@ public class PhoneStatusBarPolicy
|
||||
mIconController.setIcon(mSlotCast, R.drawable.stat_sys_cast, null);
|
||||
mIconController.setIconVisibility(mSlotCast, false);
|
||||
|
||||
// connected display
|
||||
mIconController.setIcon(mSlotConnectedDisplay, R.drawable.stat_sys_connected_display, null);
|
||||
mIconController.setIconVisibility(mSlotConnectedDisplay, false);
|
||||
|
||||
// hotspot
|
||||
mIconController.setIcon(mSlotHotspot, R.drawable.stat_sys_hotspot,
|
||||
mResources.getString(R.string.accessibility_status_bar_hotspot));
|
||||
@@ -342,6 +358,8 @@ public class PhoneStatusBarPolicy
|
||||
mSensorPrivacyController.addCallback(mSensorPrivacyListener);
|
||||
mLocationController.addCallback(this);
|
||||
mRecordingController.addCallback(this);
|
||||
mJavaAdapter.alwaysCollectFlow(mConnectedDisplayInteractor.getConnectedDisplayState(),
|
||||
this::onConnectedDisplayAvailabilityChanged);
|
||||
|
||||
mCommandQueue.addCallback(this);
|
||||
}
|
||||
@@ -800,4 +818,14 @@ public class PhoneStatusBarPolicy
|
||||
if (DEBUG) Log.d(TAG, "screenrecord: hiding icon");
|
||||
mHandler.post(() -> mIconController.setIconVisibility(mSlotScreenRecord, false));
|
||||
}
|
||||
|
||||
private void onConnectedDisplayAvailabilityChanged(ConnectedDisplayInteractor.State state) {
|
||||
boolean visible = state != ConnectedDisplayInteractor.State.DISCONNECTED;
|
||||
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, "connected_display: " + (visible ? "showing" : "hiding") + " icon");
|
||||
}
|
||||
|
||||
mIconController.setIconVisibility(mSlotConnectedDisplay, visible);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,148 @@
|
||||
/*
|
||||
* 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.display.domain.interactor
|
||||
|
||||
import android.testing.AndroidTestingRunner
|
||||
import android.testing.TestableLooper
|
||||
import android.view.Display
|
||||
import android.view.Display.TYPE_EXTERNAL
|
||||
import android.view.Display.TYPE_INTERNAL
|
||||
import androidx.test.filters.SmallTest
|
||||
import com.android.systemui.SysuiTestCase
|
||||
import com.android.systemui.coroutines.FlowValue
|
||||
import com.android.systemui.coroutines.collectLastValue
|
||||
import com.android.systemui.display.data.repository.DisplayRepository
|
||||
import com.android.systemui.display.domain.interactor.ConnectedDisplayInteractor.State
|
||||
import com.android.systemui.util.mockito.mock
|
||||
import com.android.systemui.util.mockito.whenever
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.MutableSharedFlow
|
||||
import kotlinx.coroutines.test.TestScope
|
||||
import kotlinx.coroutines.test.UnconfinedTestDispatcher
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
|
||||
@RunWith(AndroidTestingRunner::class)
|
||||
@TestableLooper.RunWithLooper
|
||||
@OptIn(ExperimentalCoroutinesApi::class)
|
||||
@SmallTest
|
||||
class ConnectedDisplayInteractorTest : SysuiTestCase() {
|
||||
|
||||
private val fakeDisplayRepository = FakeDisplayRepository()
|
||||
private val connectedDisplayStateProvider: ConnectedDisplayInteractor =
|
||||
ConnectedDisplayInteractorImpl(fakeDisplayRepository)
|
||||
private val testScope = TestScope(UnconfinedTestDispatcher())
|
||||
|
||||
@Test
|
||||
fun displayState_nullDisplays_disconnected() =
|
||||
testScope.runTest {
|
||||
val value by lastValue()
|
||||
|
||||
fakeDisplayRepository.emit(emptySet())
|
||||
|
||||
assertThat(value).isEqualTo(State.DISCONNECTED)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun displayState_emptyDisplays_disconnected() =
|
||||
testScope.runTest {
|
||||
val value by lastValue()
|
||||
|
||||
fakeDisplayRepository.emit(emptySet())
|
||||
|
||||
assertThat(value).isEqualTo(State.DISCONNECTED)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun displayState_internalDisplay_disconnected() =
|
||||
testScope.runTest {
|
||||
val value by lastValue()
|
||||
|
||||
fakeDisplayRepository.emit(setOf(display(type = TYPE_INTERNAL)))
|
||||
|
||||
assertThat(value).isEqualTo(State.DISCONNECTED)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun displayState_externalDisplay_connected() =
|
||||
testScope.runTest {
|
||||
val value by lastValue()
|
||||
|
||||
fakeDisplayRepository.emit(setOf(display(type = TYPE_EXTERNAL)))
|
||||
|
||||
assertThat(value).isEqualTo(State.CONNECTED)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun displayState_multipleExternalDisplays_connected() =
|
||||
testScope.runTest {
|
||||
val value by lastValue()
|
||||
|
||||
fakeDisplayRepository.emit(
|
||||
setOf(display(type = TYPE_EXTERNAL), display(type = TYPE_EXTERNAL))
|
||||
)
|
||||
|
||||
assertThat(value).isEqualTo(State.CONNECTED)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun displayState_externalSecure_connectedSecure() =
|
||||
testScope.runTest {
|
||||
val value by lastValue()
|
||||
|
||||
fakeDisplayRepository.emit(
|
||||
setOf(display(type = TYPE_EXTERNAL, flags = Display.FLAG_SECURE))
|
||||
)
|
||||
|
||||
assertThat(value).isEqualTo(State.CONNECTED_SECURE)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun displayState_multipleExternal_onlyOneSecure_connectedSecure() =
|
||||
testScope.runTest {
|
||||
val value by lastValue()
|
||||
|
||||
fakeDisplayRepository.emit(
|
||||
setOf(
|
||||
display(type = TYPE_EXTERNAL, flags = Display.FLAG_SECURE),
|
||||
display(type = TYPE_EXTERNAL, flags = 0)
|
||||
)
|
||||
)
|
||||
|
||||
assertThat(value).isEqualTo(State.CONNECTED_SECURE)
|
||||
}
|
||||
|
||||
private fun TestScope.lastValue(): FlowValue<State?> =
|
||||
collectLastValue(connectedDisplayStateProvider.connectedDisplayState)
|
||||
|
||||
private fun display(type: Int, flags: Int = 0): Display {
|
||||
return mock<Display>().also { mockDisplay ->
|
||||
whenever(mockDisplay.type).thenReturn(type)
|
||||
whenever(mockDisplay.flags).thenReturn(flags)
|
||||
}
|
||||
}
|
||||
|
||||
private class FakeDisplayRepository : DisplayRepository {
|
||||
private val flow = MutableSharedFlow<Set<Display>>()
|
||||
suspend fun emit(value: Set<Display>) = flow.emit(value)
|
||||
override val displays: Flow<Set<Display>>
|
||||
get() = flow
|
||||
}
|
||||
}
|
||||
@@ -27,6 +27,8 @@ import android.testing.TestableLooper.RunWithLooper
|
||||
import androidx.test.filters.SmallTest
|
||||
import com.android.systemui.SysuiTestCase
|
||||
import com.android.systemui.broadcast.BroadcastDispatcher
|
||||
import com.android.systemui.display.domain.interactor.ConnectedDisplayInteractor
|
||||
import com.android.systemui.display.domain.interactor.ConnectedDisplayInteractor.State
|
||||
import com.android.systemui.privacy.PrivacyItemController
|
||||
import com.android.systemui.privacy.logging.PrivacyLogger
|
||||
import com.android.systemui.screenrecord.RecordingController
|
||||
@@ -46,9 +48,17 @@ import com.android.systemui.statusbar.policy.UserInfoController
|
||||
import com.android.systemui.statusbar.policy.ZenModeController
|
||||
import com.android.systemui.util.RingerModeTracker
|
||||
import com.android.systemui.util.concurrency.FakeExecutor
|
||||
import com.android.systemui.util.kotlin.JavaAdapter
|
||||
import com.android.systemui.util.mockito.capture
|
||||
import com.android.systemui.util.time.DateFormatUtil
|
||||
import com.android.systemui.util.time.FakeSystemClock
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.MutableSharedFlow
|
||||
import kotlinx.coroutines.test.TestScope
|
||||
import kotlinx.coroutines.test.UnconfinedTestDispatcher
|
||||
import kotlinx.coroutines.test.runCurrent
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
@@ -57,6 +67,8 @@ import org.mockito.ArgumentCaptor
|
||||
import org.mockito.Captor
|
||||
import org.mockito.Mock
|
||||
import org.mockito.Mockito.anyInt
|
||||
import org.mockito.Mockito.clearInvocations
|
||||
import org.mockito.Mockito.inOrder
|
||||
import org.mockito.Mockito.never
|
||||
import org.mockito.Mockito.verify
|
||||
import org.mockito.Mockito.`when` as whenever
|
||||
@@ -64,11 +76,13 @@ import org.mockito.MockitoAnnotations
|
||||
|
||||
@RunWith(AndroidTestingRunner::class)
|
||||
@RunWithLooper
|
||||
@OptIn(ExperimentalCoroutinesApi::class)
|
||||
@SmallTest
|
||||
class PhoneStatusBarPolicyTest : SysuiTestCase() {
|
||||
|
||||
companion object {
|
||||
private const val ALARM_SLOT = "alarm"
|
||||
private const val CONNECTED_DISPLAY_SLOT = "connected_display"
|
||||
}
|
||||
|
||||
@Mock private lateinit var iconController: StatusBarIconController
|
||||
@@ -102,6 +116,9 @@ class PhoneStatusBarPolicyTest : SysuiTestCase() {
|
||||
private lateinit var alarmCallbackCaptor:
|
||||
ArgumentCaptor<NextAlarmController.NextAlarmChangeCallback>
|
||||
|
||||
private val testScope = TestScope(UnconfinedTestDispatcher())
|
||||
private val fakeConnectedDisplayStateProvider = FakeConnectedDisplayStateProvider()
|
||||
|
||||
private lateinit var executor: FakeExecutor
|
||||
private lateinit var statusBarPolicy: PhoneStatusBarPolicy
|
||||
private lateinit var testableLooper: TestableLooper
|
||||
@@ -164,6 +181,57 @@ class PhoneStatusBarPolicyTest : SysuiTestCase() {
|
||||
verify(iconController).setIconVisibility(ALARM_SLOT, true)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun connectedDisplay_connected_iconShown() =
|
||||
testScope.runTest {
|
||||
statusBarPolicy.init()
|
||||
clearInvocations(iconController)
|
||||
|
||||
fakeConnectedDisplayStateProvider.emit(State.CONNECTED)
|
||||
runCurrent()
|
||||
|
||||
verify(iconController).setIconVisibility(CONNECTED_DISPLAY_SLOT, true)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun connectedDisplay_disconnected_iconHidden() =
|
||||
testScope.runTest {
|
||||
statusBarPolicy.init()
|
||||
clearInvocations(iconController)
|
||||
|
||||
fakeConnectedDisplayStateProvider.emit(State.DISCONNECTED)
|
||||
|
||||
verify(iconController).setIconVisibility(CONNECTED_DISPLAY_SLOT, false)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun connectedDisplay_disconnectedThenConnected_iconShown() =
|
||||
testScope.runTest {
|
||||
statusBarPolicy.init()
|
||||
clearInvocations(iconController)
|
||||
|
||||
fakeConnectedDisplayStateProvider.emit(State.CONNECTED)
|
||||
fakeConnectedDisplayStateProvider.emit(State.DISCONNECTED)
|
||||
fakeConnectedDisplayStateProvider.emit(State.CONNECTED)
|
||||
|
||||
inOrder(iconController).apply {
|
||||
verify(iconController).setIconVisibility(CONNECTED_DISPLAY_SLOT, true)
|
||||
verify(iconController).setIconVisibility(CONNECTED_DISPLAY_SLOT, false)
|
||||
verify(iconController).setIconVisibility(CONNECTED_DISPLAY_SLOT, true)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun connectedDisplay_connectSecureDisplay_iconShown() =
|
||||
testScope.runTest {
|
||||
statusBarPolicy.init()
|
||||
clearInvocations(iconController)
|
||||
|
||||
fakeConnectedDisplayStateProvider.emit(State.CONNECTED_SECURE)
|
||||
|
||||
verify(iconController).setIconVisibility(CONNECTED_DISPLAY_SLOT, true)
|
||||
}
|
||||
|
||||
private fun createAlarmInfo(): AlarmManager.AlarmClockInfo {
|
||||
return AlarmManager.AlarmClockInfo(10L, null)
|
||||
}
|
||||
@@ -200,7 +268,16 @@ class PhoneStatusBarPolicyTest : SysuiTestCase() {
|
||||
dateFormatUtil,
|
||||
ringerModeTracker,
|
||||
privacyItemController,
|
||||
privacyLogger
|
||||
privacyLogger,
|
||||
fakeConnectedDisplayStateProvider,
|
||||
JavaAdapter(testScope.backgroundScope)
|
||||
)
|
||||
}
|
||||
|
||||
private class FakeConnectedDisplayStateProvider : ConnectedDisplayInteractor {
|
||||
private val flow = MutableSharedFlow<State>()
|
||||
suspend fun emit(value: State) = flow.emit(value)
|
||||
override val connectedDisplayState: Flow<State>
|
||||
get() = flow
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user