diff --git a/res/values/strings.xml b/res/values/strings.xml index 9930c3685c0..21a60e1385c 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -2120,6 +2120,8 @@ More options Hold and drag to rearrange displays. + + Mirror built-in display Cast diff --git a/src/com/android/settings/connecteddevice/display/DisplayTopology.kt b/src/com/android/settings/connecteddevice/display/DisplayTopology.kt index c4f0b29ac00..a5086b108b7 100644 --- a/src/com/android/settings/connecteddevice/display/DisplayTopology.kt +++ b/src/com/android/settings/connecteddevice/display/DisplayTopology.kt @@ -157,7 +157,7 @@ class TopologyScale( } } -const val PREFERENCE_KEY = "display_topology_preference" +const val TOPOLOGY_PREFERENCE_KEY = "display_topology_preference" /** Padding in pane coordinate pixels on each side of a display block. */ const val BLOCK_PADDING = 2f @@ -220,7 +220,8 @@ class DisplayTopologyPreference(context : Context) // Prevent highlight when hovering with mouse. isSelectable = false - key = PREFERENCE_KEY + key = TOPOLOGY_PREFERENCE_KEY + isPersistent = false injector = Injector(context) } diff --git a/src/com/android/settings/connecteddevice/display/ExternalDisplayPreferenceFragment.java b/src/com/android/settings/connecteddevice/display/ExternalDisplayPreferenceFragment.java index de1363d24cd..1314737839d 100644 --- a/src/com/android/settings/connecteddevice/display/ExternalDisplayPreferenceFragment.java +++ b/src/com/android/settings/connecteddevice/display/ExternalDisplayPreferenceFragment.java @@ -102,6 +102,8 @@ public class ExternalDisplayPreferenceFragment extends SettingsPreferenceFragmen @Nullable private Preference mDisplayTopologyPreference; @Nullable + private Preference mMirrorPreference; + @Nullable private PreferenceCategory mDisplaysPreference; @Nullable private PreferenceCategory mBuiltinDisplayPreference; @@ -292,6 +294,7 @@ public class ExternalDisplayPreferenceFragment extends SettingsPreferenceFragmen if (mDisplaysPreference == null) { mDisplaysPreference = new PreferenceCategory(context); mDisplaysPreference.setPersistent(false); + mDisplaysPreference.setOrder(40); } return mDisplaysPreference; } @@ -301,6 +304,7 @@ public class ExternalDisplayPreferenceFragment extends SettingsPreferenceFragmen if (mBuiltinDisplayPreference == null) { mBuiltinDisplayPreference = new PreferenceCategory(context); mBuiltinDisplayPreference.setPersistent(false); + mBuiltinDisplayPreference.setOrder(30); } return mBuiltinDisplayPreference; } @@ -308,11 +312,19 @@ public class ExternalDisplayPreferenceFragment extends SettingsPreferenceFragmen @NonNull Preference getDisplayTopologyPreference(@NonNull Context context) { if (mDisplayTopologyPreference == null) { mDisplayTopologyPreference = new DisplayTopologyPreference(context); - mDisplayTopologyPreference.setPersistent(false); + mDisplayTopologyPreference.setOrder(10); } return mDisplayTopologyPreference; } + @NonNull Preference getMirrorPreference(@NonNull Context context) { + if (mMirrorPreference == null) { + mMirrorPreference = new MirrorPreference(context); + mMirrorPreference.setOrder(20); + } + return mMirrorPreference; + } + private void restoreState(@Nullable Bundle savedInstanceState) { if (savedInstanceState == null) { return; @@ -399,6 +411,9 @@ public class ExternalDisplayPreferenceFragment extends SettingsPreferenceFragmen @NonNull PreferenceScreen screen, @NonNull Context context) { if (mInjector != null && mInjector.getFlags().displayTopologyPaneInDisplayList()) { screen.addPreference(getDisplayTopologyPreference(context)); + if (!displaysToShow.isEmpty()) { + screen.addPreference(getMirrorPreference(context)); + } // If topology is shown, we also show a preference for the built-in display for // consistency with the topology. diff --git a/src/com/android/settings/connecteddevice/display/Mirroring.kt b/src/com/android/settings/connecteddevice/display/Mirroring.kt new file mode 100644 index 00000000000..ff35294604c --- /dev/null +++ b/src/com/android/settings/connecteddevice/display/Mirroring.kt @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2025 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.settings.connecteddevice.display + +import android.content.Context +import android.provider.Settings + +import androidx.preference.SwitchPreferenceCompat + +import com.android.settings.R + +const val MIRROR_PREFERENCE_KEY = "mirror_builtin_display" + +/** + * A switch preference which is backed by the MIRROR_BUILT_IN_DISPLAY global setting. + */ +class MirrorPreference(context: Context): SwitchPreferenceCompat(context) { + init { + setTitle(R.string.external_display_mirroring_title) + + key = MIRROR_PREFERENCE_KEY + isPersistent = false + } + + override fun onAttached() { + super.onAttached() + setChecked(0 != Settings.Global.getInt( + context.contentResolver, Settings.Secure.MIRROR_BUILT_IN_DISPLAY, 0)) + } + + override fun onClick() { + super.onClick() + Settings.Global.putInt( + context.contentResolver, Settings.Secure.MIRROR_BUILT_IN_DISPLAY, + if (isChecked()) 1 else 0) + } +} diff --git a/tests/unit/src/com/android/settings/connecteddevice/display/ExternalDisplayPreferenceFragmentTest.java b/tests/unit/src/com/android/settings/connecteddevice/display/ExternalDisplayPreferenceFragmentTest.java index 93ba97b27f5..87af6b09708 100644 --- a/tests/unit/src/com/android/settings/connecteddevice/display/ExternalDisplayPreferenceFragmentTest.java +++ b/tests/unit/src/com/android/settings/connecteddevice/display/ExternalDisplayPreferenceFragmentTest.java @@ -105,7 +105,7 @@ public class ExternalDisplayPreferenceFragmentTest extends ExternalDisplayTestBa fragment.onSaveInstanceStateCallback(outState); assertThat(outState.getBoolean(PREVIOUSLY_SHOWN_LIST_KEY)).isTrue(); - pref = mPreferenceScreen.findPreference(DisplayTopologyKt.PREFERENCE_KEY); + pref = mPreferenceScreen.findPreference(DisplayTopologyKt.TOPOLOGY_PREFERENCE_KEY); assertThat(pref).isNull(); pref = mPreferenceScreen.findPreference( @@ -122,7 +122,9 @@ public class ExternalDisplayPreferenceFragmentTest extends ExternalDisplayTestBa doReturn(new Display[] {mDisplays[1]}).when(mMockedInjector).getAllDisplays(); mHandler.flush(); - var pref = mPreferenceScreen.findPreference(DisplayTopologyKt.PREFERENCE_KEY); + var pref = mPreferenceScreen.findPreference(DisplayTopologyKt.TOPOLOGY_PREFERENCE_KEY); + assertThat(pref).isNotNull(); + pref = mPreferenceScreen.findPreference(MirroringKt.MIRROR_PREFERENCE_KEY); assertThat(pref).isNotNull(); PreferenceCategory listPref = @@ -145,8 +147,10 @@ public class ExternalDisplayPreferenceFragmentTest extends ExternalDisplayTestBa doReturn(new Display[0]).when(mMockedInjector).getAllDisplays(); mHandler.flush(); - var pref = mPreferenceScreen.findPreference(DisplayTopologyKt.PREFERENCE_KEY); + var pref = mPreferenceScreen.findPreference(DisplayTopologyKt.TOPOLOGY_PREFERENCE_KEY); assertThat(pref).isNotNull(); + pref = mPreferenceScreen.findPreference(MirroringKt.MIRROR_PREFERENCE_KEY); + assertThat(pref).isNull(); PreferenceCategory listPref = mPreferenceScreen.findPreference(DISPLAYS_LIST_PREFERENCE_KEY);