Loading packages/SystemUI/AndroidManifest.xml +3 −0 Original line number Diff line number Diff line Loading @@ -349,6 +349,9 @@ <uses-permission android:name="android.permission.MONITOR_KEYBOARD_BACKLIGHT" /> <!-- Listen to (dis-)connection of external displays and enable / disable them. --> <uses-permission android:name="android.permission.MANAGE_DISPLAYS" /> <protected-broadcast android:name="com.android.settingslib.action.REGISTER_SLICE_RECEIVER" /> <protected-broadcast android:name="com.android.settingslib.action.UNREGISTER_SLICE_RECEIVER" /> <protected-broadcast android:name="com.android.settings.flashlight.action.FLASHLIGHT_CHANGED" /> Loading packages/SystemUI/res/layout/connected_display_dialog.xml 0 → 100644 +69 −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. --> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:androidprv="http://schemas.android.com/apk/prv/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:gravity="center_horizontal" android:orientation="vertical" android:paddingHorizontal="@dimen/dialog_side_padding" android:paddingTop="@dimen/dialog_top_padding" android:background="@*android:drawable/bottomsheet_background" android:paddingBottom="@dimen/dialog_bottom_padding"> <ImageView android:id="@+id/connected_display_dialog_icon" android:layout_width="@dimen/screenrecord_logo_size" android:layout_height="@dimen/screenrecord_logo_size" android:importantForAccessibility="no" android:src="@drawable/stat_sys_connected_display" android:tint="?androidprv:attr/materialColorPrimary" /> <TextView android:id="@+id/connected_display_dialog_title" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="@dimen/screenrecord_title_margin_top" android:gravity="center" android:text="@string/connected_display_dialog_start_mirroring" android:textAppearance="@style/TextAppearance.Dialog.Title" /> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="@dimen/screenrecord_buttons_margin_top" android:orientation="horizontal"> <Button android:id="@+id/cancel" style="@style/Widget.Dialog.Button.BorderButton" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/cancel" /> <Space android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="1" /> <Button android:id="@+id/enable_display" style="@style/Widget.Dialog.Button" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/enable_display" /> </LinearLayout> </LinearLayout> No newline at end of file packages/SystemUI/res/values/strings.xml +6 −0 Original line number Diff line number Diff line Loading @@ -3184,6 +3184,12 @@ <!-- Label for a button that, when clicked, sends the user to the app store to install an app. [CHAR LIMIT=64]. --> <string name="install_app">Install app</string> <!--- Title of the dialog appearing when an external display is connected, asking whether to start mirroring [CHAR LIMIT=NONE]--> <string name="connected_display_dialog_start_mirroring">Mirror to external display?</string> <!--- Label of the "enable display" button of the dialog appearing when an external display is connected [CHAR LIMIT=NONE]--> <string name="enable_display">Enable display</string> <!-- Title of the privacy dialog, shown for active / recent app usage of some phone sensors [CHAR LIMIT=30] --> <string name="privacy_dialog_title">Microphone & Camera</string> <!-- Subtitle of the privacy dialog, shown for active / recent app usage of some phone sensors [CHAR LIMIT=NONE] --> Loading packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java +7 −0 Original line number Diff line number Diff line Loading @@ -22,6 +22,7 @@ import com.android.systemui.Dependency; import com.android.systemui.InitController; import com.android.systemui.SystemUIAppComponentFactoryBase; import com.android.systemui.dagger.qualifiers.PerUser; import com.android.systemui.display.ui.viewmodel.ConnectingDisplayViewModel; import com.android.systemui.dump.DumpManager; import com.android.systemui.keyguard.KeyguardSliceProvider; import com.android.systemui.media.muteawait.MediaMuteAwaitConnectionCli; Loading Loading @@ -140,6 +141,7 @@ public interface SysUIComponent { getMediaMuteAwaitConnectionCli(); getNearbyMediaDevicesManager(); getUnfoldLatencyTracker().init(); getConnectingDisplayViewModel().init(); getFoldStateLoggingProvider().ifPresent(FoldStateLoggingProvider::init); getFoldStateLogger().ifPresent(FoldStateLogger::init); getUnfoldTransitionProgressProvider().ifPresent((progressProvider) -> Loading Loading @@ -228,6 +230,11 @@ public interface SysUIComponent { /** */ NearbyMediaDevicesManager getNearbyMediaDevicesManager(); /** * Creates a ConnectingDisplayViewModel */ ConnectingDisplayViewModel getConnectingDisplayViewModel(); /** * Returns {@link CoreStartable}s that should be started with the application. */ Loading packages/SystemUI/src/com/android/systemui/display/data/repository/DisplayRepository.kt +60 −1 Original line number Diff line number Diff line Loading @@ -22,6 +22,7 @@ import android.hardware.display.DisplayManager.EVENT_FLAG_DISPLAY_ADDED import android.hardware.display.DisplayManager.EVENT_FLAG_DISPLAY_CHANGED import android.hardware.display.DisplayManager.EVENT_FLAG_DISPLAY_REMOVED import android.os.Handler import android.util.Log import android.view.Display import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow import com.android.systemui.dagger.SysUISingleton Loading @@ -41,6 +42,13 @@ import kotlinx.coroutines.flow.stateIn interface DisplayRepository { /** Provides a nullable set of displays. */ val displays: Flow<Set<Display>> /** * Pending display id that can be enabled/disabled. * * When `null`, it means there is no pending display waiting to be enabled. */ val pendingDisplay: Flow<Int?> } @SysUISingleton Loading Loading @@ -85,8 +93,59 @@ constructor( initialValue = getDisplays() ) fun getDisplays(): Set<Display> = private fun getDisplays(): Set<Display> = traceSection("DisplayRepository#getDisplays()") { displayManager.displays?.toSet() ?: emptySet() } override val pendingDisplay: Flow<Int?> = conflatedCallbackFlow { val callback = object : DisplayConnectionListener { private val pendingIds = mutableSetOf<Int>() override fun onDisplayConnected(id: Int) { pendingIds += id trySend(id) } override fun onDisplayDisconnected(id: Int) { if (id in pendingIds) { pendingIds -= id trySend(null) } else { Log.e( TAG, "onDisplayDisconnected received for unknown display. " + "id=$id, knownIds=$pendingIds" ) } } } displayManager.registerDisplayListener( callback, backgroundHandler, DisplayManager.EVENT_FLAG_DISPLAY_CONNECTION_CHANGED, ) awaitClose { displayManager.unregisterDisplayListener(callback) } } .flowOn(backgroundCoroutineDispatcher) .stateIn( applicationScope, started = SharingStarted.WhileSubscribed(), initialValue = null ) private companion object { const val TAG = "DisplayRepository" } } /** Used to provide default implementations for all methods. */ private interface DisplayConnectionListener : DisplayListener { override fun onDisplayConnected(id: Int) {} override fun onDisplayDisconnected(id: Int) {} override fun onDisplayAdded(id: Int) {} override fun onDisplayRemoved(id: Int) {} override fun onDisplayChanged(id: Int) {} } Loading
packages/SystemUI/AndroidManifest.xml +3 −0 Original line number Diff line number Diff line Loading @@ -349,6 +349,9 @@ <uses-permission android:name="android.permission.MONITOR_KEYBOARD_BACKLIGHT" /> <!-- Listen to (dis-)connection of external displays and enable / disable them. --> <uses-permission android:name="android.permission.MANAGE_DISPLAYS" /> <protected-broadcast android:name="com.android.settingslib.action.REGISTER_SLICE_RECEIVER" /> <protected-broadcast android:name="com.android.settingslib.action.UNREGISTER_SLICE_RECEIVER" /> <protected-broadcast android:name="com.android.settings.flashlight.action.FLASHLIGHT_CHANGED" /> Loading
packages/SystemUI/res/layout/connected_display_dialog.xml 0 → 100644 +69 −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. --> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:androidprv="http://schemas.android.com/apk/prv/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:gravity="center_horizontal" android:orientation="vertical" android:paddingHorizontal="@dimen/dialog_side_padding" android:paddingTop="@dimen/dialog_top_padding" android:background="@*android:drawable/bottomsheet_background" android:paddingBottom="@dimen/dialog_bottom_padding"> <ImageView android:id="@+id/connected_display_dialog_icon" android:layout_width="@dimen/screenrecord_logo_size" android:layout_height="@dimen/screenrecord_logo_size" android:importantForAccessibility="no" android:src="@drawable/stat_sys_connected_display" android:tint="?androidprv:attr/materialColorPrimary" /> <TextView android:id="@+id/connected_display_dialog_title" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="@dimen/screenrecord_title_margin_top" android:gravity="center" android:text="@string/connected_display_dialog_start_mirroring" android:textAppearance="@style/TextAppearance.Dialog.Title" /> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="@dimen/screenrecord_buttons_margin_top" android:orientation="horizontal"> <Button android:id="@+id/cancel" style="@style/Widget.Dialog.Button.BorderButton" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/cancel" /> <Space android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="1" /> <Button android:id="@+id/enable_display" style="@style/Widget.Dialog.Button" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/enable_display" /> </LinearLayout> </LinearLayout> No newline at end of file
packages/SystemUI/res/values/strings.xml +6 −0 Original line number Diff line number Diff line Loading @@ -3184,6 +3184,12 @@ <!-- Label for a button that, when clicked, sends the user to the app store to install an app. [CHAR LIMIT=64]. --> <string name="install_app">Install app</string> <!--- Title of the dialog appearing when an external display is connected, asking whether to start mirroring [CHAR LIMIT=NONE]--> <string name="connected_display_dialog_start_mirroring">Mirror to external display?</string> <!--- Label of the "enable display" button of the dialog appearing when an external display is connected [CHAR LIMIT=NONE]--> <string name="enable_display">Enable display</string> <!-- Title of the privacy dialog, shown for active / recent app usage of some phone sensors [CHAR LIMIT=30] --> <string name="privacy_dialog_title">Microphone & Camera</string> <!-- Subtitle of the privacy dialog, shown for active / recent app usage of some phone sensors [CHAR LIMIT=NONE] --> Loading
packages/SystemUI/src/com/android/systemui/dagger/SysUIComponent.java +7 −0 Original line number Diff line number Diff line Loading @@ -22,6 +22,7 @@ import com.android.systemui.Dependency; import com.android.systemui.InitController; import com.android.systemui.SystemUIAppComponentFactoryBase; import com.android.systemui.dagger.qualifiers.PerUser; import com.android.systemui.display.ui.viewmodel.ConnectingDisplayViewModel; import com.android.systemui.dump.DumpManager; import com.android.systemui.keyguard.KeyguardSliceProvider; import com.android.systemui.media.muteawait.MediaMuteAwaitConnectionCli; Loading Loading @@ -140,6 +141,7 @@ public interface SysUIComponent { getMediaMuteAwaitConnectionCli(); getNearbyMediaDevicesManager(); getUnfoldLatencyTracker().init(); getConnectingDisplayViewModel().init(); getFoldStateLoggingProvider().ifPresent(FoldStateLoggingProvider::init); getFoldStateLogger().ifPresent(FoldStateLogger::init); getUnfoldTransitionProgressProvider().ifPresent((progressProvider) -> Loading Loading @@ -228,6 +230,11 @@ public interface SysUIComponent { /** */ NearbyMediaDevicesManager getNearbyMediaDevicesManager(); /** * Creates a ConnectingDisplayViewModel */ ConnectingDisplayViewModel getConnectingDisplayViewModel(); /** * Returns {@link CoreStartable}s that should be started with the application. */ Loading
packages/SystemUI/src/com/android/systemui/display/data/repository/DisplayRepository.kt +60 −1 Original line number Diff line number Diff line Loading @@ -22,6 +22,7 @@ import android.hardware.display.DisplayManager.EVENT_FLAG_DISPLAY_ADDED import android.hardware.display.DisplayManager.EVENT_FLAG_DISPLAY_CHANGED import android.hardware.display.DisplayManager.EVENT_FLAG_DISPLAY_REMOVED import android.os.Handler import android.util.Log import android.view.Display import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow import com.android.systemui.dagger.SysUISingleton Loading @@ -41,6 +42,13 @@ import kotlinx.coroutines.flow.stateIn interface DisplayRepository { /** Provides a nullable set of displays. */ val displays: Flow<Set<Display>> /** * Pending display id that can be enabled/disabled. * * When `null`, it means there is no pending display waiting to be enabled. */ val pendingDisplay: Flow<Int?> } @SysUISingleton Loading Loading @@ -85,8 +93,59 @@ constructor( initialValue = getDisplays() ) fun getDisplays(): Set<Display> = private fun getDisplays(): Set<Display> = traceSection("DisplayRepository#getDisplays()") { displayManager.displays?.toSet() ?: emptySet() } override val pendingDisplay: Flow<Int?> = conflatedCallbackFlow { val callback = object : DisplayConnectionListener { private val pendingIds = mutableSetOf<Int>() override fun onDisplayConnected(id: Int) { pendingIds += id trySend(id) } override fun onDisplayDisconnected(id: Int) { if (id in pendingIds) { pendingIds -= id trySend(null) } else { Log.e( TAG, "onDisplayDisconnected received for unknown display. " + "id=$id, knownIds=$pendingIds" ) } } } displayManager.registerDisplayListener( callback, backgroundHandler, DisplayManager.EVENT_FLAG_DISPLAY_CONNECTION_CHANGED, ) awaitClose { displayManager.unregisterDisplayListener(callback) } } .flowOn(backgroundCoroutineDispatcher) .stateIn( applicationScope, started = SharingStarted.WhileSubscribed(), initialValue = null ) private companion object { const val TAG = "DisplayRepository" } } /** Used to provide default implementations for all methods. */ private interface DisplayConnectionListener : DisplayListener { override fun onDisplayConnected(id: Int) {} override fun onDisplayDisconnected(id: Int) {} override fun onDisplayAdded(id: Int) {} override fun onDisplayRemoved(id: Int) {} override fun onDisplayChanged(id: Int) {} }