Merge changes I95721d9b,Id43d2f10 into main

* changes:
  Connected displays: use Robolectric for tests
  CD settings: minimal DisplayDevice metadata class
This commit is contained in:
Matthew DeVore
2025-03-03 11:10:00 -08:00
committed by Android (Google) Code Review
9 changed files with 211 additions and 202 deletions

View File

@@ -0,0 +1,31 @@
/*
* 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.view.Display.Mode
import androidx.annotation.Keep
enum class DisplayIsEnabled { YES, NO, UNKNOWN }
/**
* Contains essential information from {@link android.view.Display} needed by the user to configure
* a display.
*/
@Keep
data class DisplayDevice(val id: Int, val name: String, val mode: Mode?,
val supportedModes: List<Mode>, val isEnabled: DisplayIsEnabled) {}

View File

@@ -19,7 +19,6 @@ package com.android.settings.connecteddevice.display;
import static com.android.settings.connecteddevice.display.ExternalDisplaySettingsConfiguration.DISPLAY_ID_ARG; import static com.android.settings.connecteddevice.display.ExternalDisplaySettingsConfiguration.DISPLAY_ID_ARG;
import static com.android.settings.connecteddevice.display.ExternalDisplaySettingsConfiguration.EXTERNAL_DISPLAY_HELP_URL; import static com.android.settings.connecteddevice.display.ExternalDisplaySettingsConfiguration.EXTERNAL_DISPLAY_HELP_URL;
import static com.android.settings.connecteddevice.display.ExternalDisplaySettingsConfiguration.EXTERNAL_DISPLAY_NOT_FOUND_RESOURCE; import static com.android.settings.connecteddevice.display.ExternalDisplaySettingsConfiguration.EXTERNAL_DISPLAY_NOT_FOUND_RESOURCE;
import static com.android.settings.connecteddevice.display.ExternalDisplaySettingsConfiguration.isDisplayAllowed;
import static com.android.settings.connecteddevice.display.ExternalDisplaySettingsConfiguration.isDisplaySizeSettingEnabled; import static com.android.settings.connecteddevice.display.ExternalDisplaySettingsConfiguration.isDisplaySizeSettingEnabled;
import static com.android.settings.connecteddevice.display.ExternalDisplaySettingsConfiguration.isResolutionSettingEnabled; import static com.android.settings.connecteddevice.display.ExternalDisplaySettingsConfiguration.isResolutionSettingEnabled;
import static com.android.settings.connecteddevice.display.ExternalDisplaySettingsConfiguration.isRotationSettingEnabled; import static com.android.settings.connecteddevice.display.ExternalDisplaySettingsConfiguration.isRotationSettingEnabled;
@@ -32,7 +31,6 @@ import android.content.Context;
import android.os.Bundle; import android.os.Bundle;
import android.os.SystemClock; import android.os.SystemClock;
import android.view.Choreographer; import android.view.Choreographer;
import android.view.Display;
import android.view.View; import android.view.View;
import android.widget.SeekBar; import android.widget.SeekBar;
import android.widget.TextView; import android.widget.TextView;
@@ -59,7 +57,6 @@ import com.android.settingslib.widget.FooterPreference;
import com.android.settingslib.widget.IllustrationPreference; import com.android.settingslib.widget.IllustrationPreference;
import com.android.settingslib.widget.MainSwitchPreference; import com.android.settingslib.widget.MainSwitchPreference;
import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
@@ -398,7 +395,8 @@ public class ExternalDisplayPreferenceFragment extends SettingsPreferenceFragmen
} }
private void updateScreen(final PrefRefresh screen, Context context) { private void updateScreen(final PrefRefresh screen, Context context) {
final var displaysToShow = externalDisplaysToShow(); final var displaysToShow = mInjector == null
? List.<DisplayDevice>of() : mInjector.getConnectedDisplays();
if (displaysToShow.isEmpty()) { if (displaysToShow.isEmpty()) {
showTextWhenNoDisplaysToShow(screen, context, /* position= */ 0); showTextWhenNoDisplaysToShow(screen, context, /* position= */ 0);
@@ -438,19 +436,18 @@ public class ExternalDisplayPreferenceFragment extends SettingsPreferenceFragmen
return category; return category;
} }
private void showDisplaySettings(Display display, PrefRefresh refresh, private void showDisplaySettings(DisplayDevice display, PrefRefresh refresh,
Context context, boolean includeV1Helpers, int position) { Context context, boolean includeV1Helpers, int position) {
final var isEnabled = mInjector != null && mInjector.isDisplayEnabled(display);
if (isUseDisplaySettingEnabled(mInjector)) { if (isUseDisplaySettingEnabled(mInjector)) {
addUseDisplayPreferenceForDisplay(context, refresh, display, isEnabled, position); addUseDisplayPreferenceForDisplay(context, refresh, display, position);
} }
final var displayRotation = getDisplayRotation(display.getDisplayId()); final var displayRotation = getDisplayRotation(display.getId());
if (includeV1Helpers && isEnabled) { if (includeV1Helpers && display.isEnabled() == DisplayIsEnabled.YES) {
addIllustrationImage(context, refresh, displayRotation); addIllustrationImage(context, refresh, displayRotation);
} }
addResolutionPreference(context, refresh, display, position, isEnabled); addResolutionPreference(context, refresh, display, position);
addRotationPreference(context, refresh, display, displayRotation, position, isEnabled); addRotationPreference(context, refresh, display, displayRotation, position);
if (isResolutionSettingEnabled(mInjector)) { if (isResolutionSettingEnabled(mInjector)) {
// Do not show the footer about changing resolution affecting apps. This is not in the // Do not show the footer about changing resolution affecting apps. This is not in the
// UX design for v2, and there is no good place to put it, since (a) if it is on the // UX design for v2, and there is no good place to put it, since (a) if it is on the
@@ -462,13 +459,13 @@ public class ExternalDisplayPreferenceFragment extends SettingsPreferenceFragmen
// inconsistent with the topology pane, which shows that display. // inconsistent with the topology pane, which shows that display.
// TODO(b/352648432): probably remove footer once the pane and rest of v2 UI is in // TODO(b/352648432): probably remove footer once the pane and rest of v2 UI is in
// place. // place.
if (includeV1Helpers && isEnabled) { if (includeV1Helpers && display.isEnabled() == DisplayIsEnabled.YES) {
addFooterPreference( addFooterPreference(
context, refresh, EXTERNAL_DISPLAY_CHANGE_RESOLUTION_FOOTER_RESOURCE); context, refresh, EXTERNAL_DISPLAY_CHANGE_RESOLUTION_FOOTER_RESOURCE);
} }
} }
if (isDisplaySizeSettingEnabled(mInjector)) { if (isDisplaySizeSettingEnabled(mInjector)) {
addSizePreference(context, refresh, display.getDisplayId(), position, isEnabled); addSizePreference(context, refresh, display, position);
} }
} }
@@ -485,7 +482,7 @@ public class ExternalDisplayPreferenceFragment extends SettingsPreferenceFragmen
} }
} }
private void showDisplaysList(@NonNull List<Display> displaysToShow, private void showDisplaysList(@NonNull List<DisplayDevice> displaysToShow,
@NonNull PrefRefresh screen, @NonNull Context context) { @NonNull PrefRefresh screen, @NonNull Context context) {
maybeAddV2Components(context, screen); maybeAddV2Components(context, screen);
int position = 0; int position = 0;
@@ -504,19 +501,6 @@ public class ExternalDisplayPreferenceFragment extends SettingsPreferenceFragmen
} }
} }
private List<Display> externalDisplaysToShow() {
if (mInjector == null) {
return List.of();
}
var displaysToShow = new ArrayList<Display>();
for (var display : mInjector.getAllDisplays()) {
if (display != null && isDisplayAllowed(display, mInjector)) {
displaysToShow.add(display);
}
}
return displaysToShow;
}
private void addUseDisplayPreferenceNoDisplaysFound(Context context, PrefRefresh refresh, private void addUseDisplayPreferenceNoDisplaysFound(Context context, PrefRefresh refresh,
int position) { int position) {
final var pref = reuseUseDisplayPreference(context, refresh, position); final var pref = reuseUseDisplayPreference(context, refresh, position);
@@ -526,9 +510,9 @@ public class ExternalDisplayPreferenceFragment extends SettingsPreferenceFragmen
} }
private void addUseDisplayPreferenceForDisplay(final Context context, private void addUseDisplayPreferenceForDisplay(final Context context,
PrefRefresh refresh, final Display display, boolean isEnabled, int position) { PrefRefresh refresh, final DisplayDevice display, int position) {
final var pref = reuseUseDisplayPreference(context, refresh, position); final var pref = reuseUseDisplayPreference(context, refresh, position);
pref.setChecked(isEnabled); pref.setChecked(display.isEnabled() == DisplayIsEnabled.YES);
pref.setEnabled(true); pref.setEnabled(true);
pref.setOnPreferenceChangeListener((p, newValue) -> { pref.setOnPreferenceChangeListener((p, newValue) -> {
writePreferenceClickMetric(p); writePreferenceClickMetric(p);
@@ -537,9 +521,9 @@ public class ExternalDisplayPreferenceFragment extends SettingsPreferenceFragmen
return false; return false;
} }
if ((Boolean) newValue) { if ((Boolean) newValue) {
result = mInjector.enableConnectedDisplay(display.getDisplayId()); result = mInjector.enableConnectedDisplay(display.getId());
} else { } else {
result = mInjector.disableConnectedDisplay(display.getDisplayId()); result = mInjector.disableConnectedDisplay(display.getId());
} }
if (result) { if (result) {
pref.setChecked((Boolean) newValue); pref.setChecked((Boolean) newValue);
@@ -559,7 +543,7 @@ public class ExternalDisplayPreferenceFragment extends SettingsPreferenceFragmen
} }
private void addRotationPreference(final Context context, PrefRefresh refresh, private void addRotationPreference(final Context context, PrefRefresh refresh,
final Display display, final int displayRotation, int position, boolean isEnabled) { final DisplayDevice display, final int displayRotation, int position) {
var pref = reuseRotationPreference(context, refresh, position); var pref = reuseRotationPreference(context, refresh, position);
if (mRotationEntries == null || mRotationEntriesValues == null) { if (mRotationEntries == null || mRotationEntriesValues == null) {
mRotationEntries = new String[] { mRotationEntries = new String[] {
@@ -576,39 +560,41 @@ public class ExternalDisplayPreferenceFragment extends SettingsPreferenceFragmen
pref.setOnPreferenceChangeListener((p, newValue) -> { pref.setOnPreferenceChangeListener((p, newValue) -> {
writePreferenceClickMetric(p); writePreferenceClickMetric(p);
var rotation = Integer.parseInt((String) newValue); var rotation = Integer.parseInt((String) newValue);
var displayId = display.getDisplayId(); var displayId = display.getId();
if (mInjector == null || !mInjector.freezeDisplayRotation(displayId, rotation)) { if (mInjector == null || !mInjector.freezeDisplayRotation(displayId, rotation)) {
return false; return false;
} }
pref.setValueIndex(rotation); pref.setValueIndex(rotation);
return true; return true;
}); });
pref.setEnabled(isEnabled && isRotationSettingEnabled(mInjector)); pref.setEnabled(display.isEnabled() == DisplayIsEnabled.YES
&& isRotationSettingEnabled(mInjector));
} }
private void addResolutionPreference(final Context context, PrefRefresh refresh, private void addResolutionPreference(final Context context, PrefRefresh refresh,
final Display display, int position, boolean isEnabled) { final DisplayDevice display, int position) {
var pref = reuseResolutionPreference(context, refresh, position); var pref = reuseResolutionPreference(context, refresh, position);
pref.setSummary(display.getMode().getPhysicalWidth() + " x " pref.setSummary(display.getMode().getPhysicalWidth() + " x "
+ display.getMode().getPhysicalHeight()); + display.getMode().getPhysicalHeight());
pref.setOnPreferenceClickListener((Preference p) -> { pref.setOnPreferenceClickListener((Preference p) -> {
writePreferenceClickMetric(p); writePreferenceClickMetric(p);
launchResolutionSelector(context, display.getDisplayId()); launchResolutionSelector(context, display.getId());
return true; return true;
}); });
pref.setEnabled(isEnabled && isResolutionSettingEnabled(mInjector)); pref.setEnabled(display.isEnabled() == DisplayIsEnabled.YES
&& isResolutionSettingEnabled(mInjector));
} }
private void addSizePreference(final Context context, PrefRefresh refresh, int displayId, private void addSizePreference(final Context context, PrefRefresh refresh,
int position, boolean isEnabled) { DisplayDevice display, int position) {
var pref = reuseSizePreference(context, refresh, displayId, position); var pref = reuseSizePreference(context, refresh, display.getId(), position);
pref.setSummary(EXTERNAL_DISPLAY_SIZE_SUMMARY_RESOURCE); pref.setSummary(EXTERNAL_DISPLAY_SIZE_SUMMARY_RESOURCE);
pref.setOnPreferenceClickListener( pref.setOnPreferenceClickListener(
(Preference p) -> { (Preference p) -> {
writePreferenceClickMetric(p); writePreferenceClickMetric(p);
return true; return true;
}); });
pref.setEnabled(isEnabled); pref.setEnabled(display.isEnabled() == DisplayIsEnabled.YES);
} }
private int getDisplayRotation(int displayId) { private int getDisplayRotation(int displayId) {

View File

@@ -44,6 +44,10 @@ import com.android.settings.R;
import com.android.settings.flags.FeatureFlags; import com.android.settings.flags.FeatureFlags;
import com.android.settings.flags.FeatureFlagsImpl; import com.android.settings.flags.FeatureFlagsImpl;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
public class ExternalDisplaySettingsConfiguration { public class ExternalDisplaySettingsConfiguration {
static final String VIRTUAL_DISPLAY_PACKAGE_NAME_SYSTEM_PROPERTY = static final String VIRTUAL_DISPLAY_PACKAGE_NAME_SYSTEM_PROPERTY =
"persist.demo.userrotation.package_name"; "persist.demo.userrotation.package_name";
@@ -114,40 +118,57 @@ public class ExternalDisplaySettingsConfiguration {
mHandler = handler; mHandler = handler;
} }
private static DisplayDevice wrapDmDisplay(Display display, DisplayIsEnabled isEnabled) {
return new DisplayDevice(display.getDisplayId(), display.getName(),
display.getMode(), List.<Mode>of(display.getSupportedModes()), isEnabled);
}
/** /**
* @return all displays including disabled. * @return all displays including disabled.
*/ */
@NonNull @NonNull
public Display[] getAllDisplays() { public List<DisplayDevice> getConnectedDisplays() {
var dm = getDisplayManager(); var dm = getDisplayManager();
if (dm == null) { if (dm == null) {
return new Display[0]; return List.of();
} }
return dm.getDisplays(DISPLAY_CATEGORY_ALL_INCLUDING_DISABLED);
}
/** var enabledIds = new HashSet<Integer>();
* @return enabled displays only. for (Display d : dm.getDisplays()) {
*/ enabledIds.add(d.getDisplayId());
@NonNull
public Display[] getEnabledDisplays() {
var dm = getDisplayManager();
if (dm == null) {
return new Display[0];
} }
return dm.getDisplays();
}
/** var displays = new ArrayList<DisplayDevice>();
* @return true if the display is enabled for (Display d : dm.getDisplays(DISPLAY_CATEGORY_ALL_INCLUDING_DISABLED)) {
*/ if (!isDisplayAllowed(d, this)) {
public boolean isDisplayEnabled(@NonNull Display display) { continue;
for (var enabledDisplay : getEnabledDisplays()) {
if (enabledDisplay.getDisplayId() == display.getDisplayId()) {
return true;
} }
var isEnabled = enabledIds.contains(d.getDisplayId())
? DisplayIsEnabled.YES : DisplayIsEnabled.NO;
displays.add(wrapDmDisplay(d, isEnabled));
} }
return false; return displays;
}
/**
* @param displayId which must be returned
* @return display object for the displayId, or null if display is not a connected display,
* the ID was not found, or the ID was invalid
*/
@Nullable
public DisplayDevice getDisplay(int displayId) {
if (displayId == INVALID_DISPLAY) {
return null;
}
var dm = getDisplayManager();
if (dm == null) {
return null;
}
var display = dm.getDisplay(displayId);
if (display == null || !isDisplayAllowed(display, this)) {
return null;
}
return wrapDmDisplay(display, DisplayIsEnabled.UNKNOWN);
} }
/** /**
@@ -206,22 +227,6 @@ public class ExternalDisplaySettingsConfiguration {
return true; return true;
} }
/**
* @param displayId which must be returned
* @return display object for the displayId
*/
@Nullable
public Display getDisplay(int displayId) {
if (displayId == INVALID_DISPLAY) {
return null;
}
var dm = getDisplayManager();
if (dm == null) {
return null;
}
return dm.getDisplay(displayId);
}
/** /**
* @return handler * @return handler
*/ */
@@ -323,8 +328,7 @@ public class ExternalDisplaySettingsConfiguration {
|| flags.displayTopologyPaneInDisplayList(); || flags.displayTopologyPaneInDisplayList();
} }
static boolean isDisplayAllowed(@NonNull Display display, private static boolean isDisplayAllowed(Display display, SystemServicesProvider props) {
@NonNull SystemServicesProvider props) {
return display.getType() == Display.TYPE_EXTERNAL return display.getType() == Display.TYPE_EXTERNAL
|| display.getType() == Display.TYPE_OVERLAY || display.getType() == Display.TYPE_OVERLAY
|| isVirtualDisplayAllowed(display, props); || isVirtualDisplayAllowed(display, props);
@@ -334,7 +338,7 @@ public class ExternalDisplaySettingsConfiguration {
return injector != null && injector.getFlags().displayTopologyPaneInDisplayList(); return injector != null && injector.getFlags().displayTopologyPaneInDisplayList();
} }
static boolean isVirtualDisplayAllowed(@NonNull Display display, private static boolean isVirtualDisplayAllowed(@NonNull Display display,
@NonNull SystemServicesProvider properties) { @NonNull SystemServicesProvider properties) {
var sysProp = properties.getSystemProperty(VIRTUAL_DISPLAY_PACKAGE_NAME_SYSTEM_PROPERTY); var sysProp = properties.getSystemProperty(VIRTUAL_DISPLAY_PACKAGE_NAME_SYSTEM_PROPERTY);
return !sysProp.isEmpty() && display.getType() == Display.TYPE_VIRTUAL return !sysProp.isEmpty() && display.getType() == Display.TYPE_VIRTUAL

View File

@@ -16,8 +16,6 @@
package com.android.settings.connecteddevice.display; package com.android.settings.connecteddevice.display;
import static com.android.settings.connecteddevice.display.ExternalDisplaySettingsConfiguration.isDisplayAllowed;
import android.content.Context; import android.content.Context;
import android.graphics.drawable.Drawable; import android.graphics.drawable.Drawable;
import android.os.UserHandle; import android.os.UserHandle;
@@ -134,19 +132,13 @@ public class ExternalDisplayUpdater {
return null; return null;
} }
for (var display : mInjector.getEnabledDisplays()) { var allDisplays = mInjector.getConnectedDisplays();
if (display != null && isDisplayAllowed(display, mInjector)) { for (var display : allDisplays) {
if (display.isEnabled() == DisplayIsEnabled.YES) {
return context.getString(R.string.external_display_on); return context.getString(R.string.external_display_on);
} }
} }
return allDisplays.isEmpty() ? null : context.getString(R.string.external_display_off);
for (var display : mInjector.getAllDisplays()) {
if (display != null && isDisplayAllowed(display, mInjector)) {
return context.getString(R.string.external_display_off);
}
}
return null;
} }
/** /**

View File

@@ -21,7 +21,6 @@ import static android.view.Display.INVALID_DISPLAY;
import static com.android.settings.connecteddevice.display.ExternalDisplaySettingsConfiguration.DISPLAY_ID_ARG; import static com.android.settings.connecteddevice.display.ExternalDisplaySettingsConfiguration.DISPLAY_ID_ARG;
import static com.android.settings.connecteddevice.display.ExternalDisplaySettingsConfiguration.EXTERNAL_DISPLAY_HELP_URL; import static com.android.settings.connecteddevice.display.ExternalDisplaySettingsConfiguration.EXTERNAL_DISPLAY_HELP_URL;
import static com.android.settings.connecteddevice.display.ExternalDisplaySettingsConfiguration.EXTERNAL_DISPLAY_NOT_FOUND_RESOURCE; import static com.android.settings.connecteddevice.display.ExternalDisplaySettingsConfiguration.EXTERNAL_DISPLAY_NOT_FOUND_RESOURCE;
import static com.android.settings.connecteddevice.display.ExternalDisplaySettingsConfiguration.isDisplayAllowed;
import android.app.settings.SettingsEnums; import android.app.settings.SettingsEnums;
import android.content.Context; import android.content.Context;
@@ -29,7 +28,6 @@ import android.content.res.Resources;
import android.os.Bundle; import android.os.Bundle;
import android.util.Log; import android.util.Log;
import android.util.Pair; import android.util.Pair;
import android.view.Display;
import android.view.Display.Mode; import android.view.Display.Mode;
import android.view.View; import android.view.View;
import android.widget.TextView; import android.widget.TextView;
@@ -50,6 +48,7 @@ import com.android.settingslib.widget.SelectorWithWidgetPreference;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashSet; import java.util.HashSet;
import java.util.List;
public class ResolutionPreferenceFragment extends SettingsPreferenceFragmentBase { public class ResolutionPreferenceFragment extends SettingsPreferenceFragmentBase {
private static final String TAG = "ResolutionPreference"; private static final String TAG = "ResolutionPreference";
@@ -164,7 +163,7 @@ public class ResolutionPreferenceFragment extends SettingsPreferenceFragmentBase
return; return;
} }
var display = mInjector.getDisplay(getDisplayIdArg()); var display = mInjector.getDisplay(getDisplayIdArg());
if (display == null || !isDisplayAllowed(display, mInjector)) { if (display == null) {
screen.removeAll(); screen.removeAll();
mTopOptionsPreference = null; mTopOptionsPreference = null;
mMoreOptionsPreference = null; mMoreOptionsPreference = null;
@@ -210,9 +209,9 @@ public class ResolutionPreferenceFragment extends SettingsPreferenceFragmentBase
} }
private void addRemainingPreferences(@NonNull Context context, private void addRemainingPreferences(@NonNull Context context,
@NonNull PreferenceCategory group, @NonNull Display display, @NonNull PreferenceCategory group, @NonNull DisplayDevice display,
boolean isSelectedModeFound, @NonNull Mode[] moreModes) { boolean isSelectedModeFound, @NonNull List<Mode> moreModes) {
if (moreModes.length == 0) { if (moreModes.isEmpty()) {
return; return;
} }
mMoreOptionsExpanded |= !isSelectedModeFound; mMoreOptionsExpanded |= !isSelectedModeFound;
@@ -220,12 +219,12 @@ public class ResolutionPreferenceFragment extends SettingsPreferenceFragmentBase
addModePreferences(context, group, moreModes, /*checkMode=*/ null, display); addModePreferences(context, group, moreModes, /*checkMode=*/ null, display);
} }
private Pair<Boolean, Mode[]> addModePreferences(@NonNull Context context, private Pair<Boolean, List<Mode>> addModePreferences(@NonNull Context context,
@NonNull PreferenceGroup group, @NonNull PreferenceGroup group,
@NonNull Mode[] modes, @NonNull List<Mode> modes,
@Nullable ToBooleanFunction<Mode> checkMode, @Nullable ToBooleanFunction<Mode> checkMode,
@NonNull Display display) { @NonNull DisplayDevice display) {
Display.Mode curMode = display.getMode(); Mode curMode = display.getMode();
var currentResolution = curMode.getPhysicalWidth() + "x" + curMode.getPhysicalHeight(); var currentResolution = curMode.getPhysicalWidth() + "x" + curMode.getPhysicalHeight();
var rotatedResolution = curMode.getPhysicalHeight() + "x" + curMode.getPhysicalWidth(); var rotatedResolution = curMode.getPhysicalHeight() + "x" + curMode.getPhysicalWidth();
var skippedModes = new ArrayList<Mode>(); var skippedModes = new ArrayList<Mode>();
@@ -260,7 +259,7 @@ public class ResolutionPreferenceFragment extends SettingsPreferenceFragmentBase
isAnyOfModesSelected |= isCurrentMode; isAnyOfModesSelected |= isCurrentMode;
group.addPreference(pref); group.addPreference(pref);
} }
return new Pair<>(isAnyOfModesSelected, skippedModes.toArray(Mode.EMPTY_ARRAY)); return new Pair<>(isAnyOfModesSelected, skippedModes);
} }
private boolean isTopMode(@NonNull Mode mode) { private boolean isTopMode(@NonNull Mode mode) {
@@ -309,7 +308,7 @@ public class ResolutionPreferenceFragment extends SettingsPreferenceFragmentBase
} }
private void onDisplayModeClicked(@NonNull SelectorWithWidgetPreference preference, private void onDisplayModeClicked(@NonNull SelectorWithWidgetPreference preference,
@NonNull Display display) { @NonNull DisplayDevice display) {
if (mInjector == null) { if (mInjector == null) {
return; return;
} }
@@ -319,7 +318,7 @@ public class ResolutionPreferenceFragment extends SettingsPreferenceFragmentBase
for (var mode : display.getSupportedModes()) { for (var mode : display.getSupportedModes()) {
if (mode.getPhysicalWidth() == width && mode.getPhysicalHeight() == height if (mode.getPhysicalWidth() == width && mode.getPhysicalHeight() == height
&& isAllowedMode(mode)) { && isAllowedMode(mode)) {
mInjector.setUserPreferredDisplayMode(display.getDisplayId(), mode); mInjector.setUserPreferredDisplayMode(display.getId(), mode);
return; return;
} }
} }

View File

@@ -27,7 +27,6 @@ import static com.android.settings.flags.Flags.FLAG_DISPLAY_TOPOLOGY_PANE_IN_DIS
import static com.google.common.truth.Truth.assertThat; import static com.google.common.truth.Truth.assertThat;
import static com.google.common.truth.Truth.assertWithMessage; import static com.google.common.truth.Truth.assertWithMessage;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mock;
@@ -38,7 +37,6 @@ import static org.mockito.Mockito.verify;
import android.app.Activity; import android.app.Activity;
import android.content.Context; import android.content.Context;
import android.os.Bundle; import android.os.Bundle;
import android.view.Display;
import android.view.View; import android.view.View;
import android.widget.TextView; import android.widget.TextView;
@@ -58,6 +56,8 @@ import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import org.mockito.Mock; import org.mockito.Mock;
import java.util.List;
/** Unit tests for {@link ExternalDisplayPreferenceFragment}. */ /** Unit tests for {@link ExternalDisplayPreferenceFragment}. */
@RunWith(AndroidJUnit4.class) @RunWith(AndroidJUnit4.class)
public class ExternalDisplayPreferenceFragmentTest extends ExternalDisplayTestBase { public class ExternalDisplayPreferenceFragmentTest extends ExternalDisplayTestBase {
@@ -103,10 +103,10 @@ public class ExternalDisplayPreferenceFragmentTest extends ExternalDisplayTestBa
assertDisplayListCount(0); assertDisplayListCount(0);
verify(mMockedInjector, never()).getAllDisplays(); verify(mMockedInjector, never()).getConnectedDisplays();
mHandler.flush(); mHandler.flush();
assertThat(mHandler.getPendingMessages().size()).isEqualTo(0); assertThat(mHandler.getPendingMessages().size()).isEqualTo(0);
verify(mMockedInjector).getAllDisplays(); verify(mMockedInjector).getConnectedDisplays();
assertDisplayListCount(2); assertDisplayListCount(2);
Preference pref = mPreferenceScreen.findPreference(PrefBasics.DISPLAY_TOPOLOGY.key); Preference pref = mPreferenceScreen.findPreference(PrefBasics.DISPLAY_TOPOLOGY.key);
@@ -122,7 +122,7 @@ public class ExternalDisplayPreferenceFragmentTest extends ExternalDisplayTestBa
mFlags.setFlag(FLAG_DISPLAY_TOPOLOGY_PANE_IN_DISPLAY_LIST, true); mFlags.setFlag(FLAG_DISPLAY_TOPOLOGY_PANE_IN_DISPLAY_LIST, true);
initFragment(); initFragment();
doReturn(new Display[] {mDisplays[1]}).when(mMockedInjector).getAllDisplays(); doReturn(List.of(mDisplays.get(0))).when(mMockedInjector).getConnectedDisplays();
mHandler.flush(); mHandler.flush();
var pref = mPreferenceScreen.findPreference(PrefBasics.DISPLAY_TOPOLOGY.key); var pref = mPreferenceScreen.findPreference(PrefBasics.DISPLAY_TOPOLOGY.key);
@@ -147,7 +147,7 @@ public class ExternalDisplayPreferenceFragmentTest extends ExternalDisplayTestBa
mFlags.setFlag(FLAG_DISPLAY_TOPOLOGY_PANE_IN_DISPLAY_LIST, true); mFlags.setFlag(FLAG_DISPLAY_TOPOLOGY_PANE_IN_DISPLAY_LIST, true);
initFragment(); initFragment();
doReturn(new Display[0]).when(mMockedInjector).getAllDisplays(); doReturn(List.of()).when(mMockedInjector).getConnectedDisplays();
mHandler.flush(); mHandler.flush();
// When no external display is attached, interactive preferences are omitted. // When no external display is attached, interactive preferences are omitted.
@@ -165,11 +165,10 @@ public class ExternalDisplayPreferenceFragmentTest extends ExternalDisplayTestBa
@Test @Test
@UiThreadTest @UiThreadTest
public void testShowDisplayControlsDisabled() { public void testShowDisplayControlsDisabled() {
doReturn(new Display[] {mDisplays[0], mDisplays[2]}).when(mMockedInjector) doReturn(List.of(
.getEnabledDisplays(); createExternalDisplay(DisplayIsEnabled.NO),
doReturn(true).when(mMockedInjector).isDisplayEnabled(mDisplays[0]); createOverlayDisplay(DisplayIsEnabled.YES)))
doReturn(false).when(mMockedInjector).isDisplayEnabled(mDisplays[1]); .when(mMockedInjector).getConnectedDisplays();
doReturn(true).when(mMockedInjector).isDisplayEnabled(mDisplays[2]);
initFragment(); initFragment();
mHandler.flush(); mHandler.flush();
@@ -194,7 +193,6 @@ public class ExternalDisplayPreferenceFragmentTest extends ExternalDisplayTestBa
@UiThreadTest @UiThreadTest
public void testLaunchDisplaySettingFromList() { public void testLaunchDisplaySettingFromList() {
initFragment(); initFragment();
doReturn(true).when(mMockedInjector).isDisplayEnabled(any());
mHandler.flush(); mHandler.flush();
assertDisplayListCount(2); assertDisplayListCount(2);
var display1Category = getExternalDisplayCategory(0); var display1Category = getExternalDisplayCategory(0);
@@ -219,9 +217,9 @@ public class ExternalDisplayPreferenceFragmentTest extends ExternalDisplayTestBa
public void testShowDisplayListForOnlyOneDisplay_PreviouslyShownList() { public void testShowDisplayListForOnlyOneDisplay_PreviouslyShownList() {
var fragment = initFragment(); var fragment = initFragment();
// Only one display available // Only one display available
doReturn(new Display[] {mDisplays[1]}).when(mMockedInjector).getAllDisplays(); doReturn(List.of(mDisplays.get(0))).when(mMockedInjector).getConnectedDisplays();
mHandler.flush(); mHandler.flush();
int attachedId = mDisplays[1].getDisplayId(); int attachedId = mDisplays.get(0).getId();
assertDisplayListCount(1); assertDisplayListCount(1);
assertThat("" + getExternalDisplayCategory(0).getTitle()).isEqualTo("HDMI"); assertThat("" + getExternalDisplayCategory(0).getTitle()).isEqualTo("HDMI");
} }
@@ -230,9 +228,8 @@ public class ExternalDisplayPreferenceFragmentTest extends ExternalDisplayTestBa
@UiThreadTest @UiThreadTest
public void testShowEnabledDisplay_OnlyOneDisplayAvailable_displaySizeDisabled() { public void testShowEnabledDisplay_OnlyOneDisplayAvailable_displaySizeDisabled() {
mFlags.setFlag(FLAG_DISPLAY_SIZE_CONNECTED_DISPLAY_SETTING, false); mFlags.setFlag(FLAG_DISPLAY_SIZE_CONNECTED_DISPLAY_SETTING, false);
doReturn(true).when(mMockedInjector).isDisplayEnabled(any());
// Only one display available // Only one display available
doReturn(new Display[] {mDisplays[1]}).when(mMockedInjector).getAllDisplays(); doReturn(List.of(mDisplays.get(0))).when(mMockedInjector).getConnectedDisplays();
// Init // Init
initFragment(); initFragment();
mHandler.flush(); mHandler.flush();
@@ -253,9 +250,8 @@ public class ExternalDisplayPreferenceFragmentTest extends ExternalDisplayTestBa
@Test @Test
@UiThreadTest @UiThreadTest
public void testShowEnabledDisplay_OnlyOneDisplayAvailable() { public void testShowEnabledDisplay_OnlyOneDisplayAvailable() {
doReturn(true).when(mMockedInjector).isDisplayEnabled(any());
// Only one display available // Only one display available
doReturn(new Display[] {mDisplays[1]}).when(mMockedInjector).getAllDisplays(); doReturn(List.of(mDisplays.get(0))).when(mMockedInjector).getConnectedDisplays();
// Init // Init
initFragment(); initFragment();
mHandler.flush(); mHandler.flush();
@@ -273,12 +269,11 @@ public class ExternalDisplayPreferenceFragmentTest extends ExternalDisplayTestBa
@Test @Test
@UiThreadTest @UiThreadTest
public void testShowOneEnabledDisplay_FewAvailable() { public void testShowOneEnabledDisplay_FewAvailable() {
doReturn(true).when(mMockedInjector).isDisplayEnabled(any());
initFragment(); initFragment();
verify(mMockedInjector, never()).getAllDisplays(); verify(mMockedInjector, never()).getConnectedDisplays();
mHandler.flush(); mHandler.flush();
verify(mMockedInjector, never()).getDisplay(anyInt()); verify(mMockedInjector, never()).getDisplay(anyInt());
verify(mMockedInjector).getAllDisplays(); verify(mMockedInjector).getConnectedDisplays();
var pref = mPreferenceScreen.findPreference( var pref = mPreferenceScreen.findPreference(
PrefBasics.EXTERNAL_DISPLAY_RESOLUTION.keyForNth(0)); PrefBasics.EXTERNAL_DISPLAY_RESOLUTION.keyForNth(0));
assertThat(pref).isNotNull(); assertThat(pref).isNotNull();
@@ -296,9 +291,13 @@ public class ExternalDisplayPreferenceFragmentTest extends ExternalDisplayTestBa
@UiThreadTest @UiThreadTest
public void testShowDisabledDisplay() { public void testShowDisabledDisplay() {
initFragment(); initFragment();
var disabledDisplays = List.of(
createExternalDisplay(DisplayIsEnabled.NO),
createOverlayDisplay(DisplayIsEnabled.NO));
doReturn(disabledDisplays).when(mMockedInjector).getConnectedDisplays();
mHandler.flush(); mHandler.flush();
verify(mMockedInjector, never()).getDisplay(anyInt()); verify(mMockedInjector, never()).getDisplay(anyInt());
verify(mMockedInjector).getAllDisplays(); verify(mMockedInjector).getConnectedDisplays();
var category = getExternalDisplayCategory(0); var category = getExternalDisplayCategory(0);
var mainPref = (MainSwitchPreference) category.findPreference( var mainPref = (MainSwitchPreference) category.findPreference(
PrefBasics.EXTERNAL_DISPLAY_USE.keyForNth(0)); PrefBasics.EXTERNAL_DISPLAY_USE.keyForNth(0));
@@ -321,7 +320,7 @@ public class ExternalDisplayPreferenceFragmentTest extends ExternalDisplayTestBa
@Test @Test
@UiThreadTest @UiThreadTest
public void testNoDisplays() { public void testNoDisplays() {
doReturn(new Display[0]).when(mMockedInjector).getAllDisplays(); doReturn(List.of()).when(mMockedInjector).getConnectedDisplays();
initFragment(); initFragment();
mHandler.flush(); mHandler.flush();
var mainPref = (MainSwitchPreference) mPreferenceScreen.findPreference( var mainPref = (MainSwitchPreference) mPreferenceScreen.findPreference(
@@ -342,7 +341,6 @@ public class ExternalDisplayPreferenceFragmentTest extends ExternalDisplayTestBa
@UiThreadTest @UiThreadTest
public void testDisplayRotationPreference() { public void testDisplayRotationPreference() {
final int displayId = 1; final int displayId = 1;
doReturn(true).when(mMockedInjector).isDisplayEnabled(any());
var fragment = initFragment(); var fragment = initFragment();
mHandler.flush(); mHandler.flush();
var category = getExternalDisplayCategory(0); var category = getExternalDisplayCategory(0);
@@ -375,7 +373,6 @@ public class ExternalDisplayPreferenceFragmentTest extends ExternalDisplayTestBa
@UiThreadTest @UiThreadTest
public void testDisplayResolutionPreference() { public void testDisplayResolutionPreference() {
final int displayId = 1; final int displayId = 1;
doReturn(true).when(mMockedInjector).isDisplayEnabled(any());
var fragment = initFragment(); var fragment = initFragment();
mHandler.flush(); mHandler.flush();
var category = getExternalDisplayCategory(0); var category = getExternalDisplayCategory(0);
@@ -393,7 +390,6 @@ public class ExternalDisplayPreferenceFragmentTest extends ExternalDisplayTestBa
@Test @Test
@UiThreadTest @UiThreadTest
public void testDisplaySizePreference() { public void testDisplaySizePreference() {
doReturn(true).when(mMockedInjector).isDisplayEnabled(any());
var fragment = initFragment(); var fragment = initFragment();
mHandler.flush(); mHandler.flush();
var category = getExternalDisplayCategory(0); var category = getExternalDisplayCategory(0);
@@ -412,7 +408,6 @@ public class ExternalDisplayPreferenceFragmentTest extends ExternalDisplayTestBa
@UiThreadTest @UiThreadTest
public void testUseDisplayPreference_EnabledDisplay() { public void testUseDisplayPreference_EnabledDisplay() {
final int displayId = 1; final int displayId = 1;
doReturn(true).when(mMockedInjector).isDisplayEnabled(any());
doReturn(true).when(mMockedInjector).enableConnectedDisplay(displayId); doReturn(true).when(mMockedInjector).enableConnectedDisplay(displayId);
doReturn(true).when(mMockedInjector).disableConnectedDisplay(displayId); doReturn(true).when(mMockedInjector).disableConnectedDisplay(displayId);
var fragment = initFragment(); var fragment = initFragment();

View File

@@ -26,21 +26,19 @@ import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.spy; import static org.mockito.Mockito.spy;
import static org.robolectric.Shadows.shadowOf;
import android.content.Context; import android.content.Context;
import android.content.res.Resources; import android.content.res.Resources;
import android.hardware.display.DisplayManagerGlobal; import android.os.Handler;
import android.hardware.display.IDisplayManager; import android.os.Message;
import android.os.RemoteException; import android.os.RemoteException;
import android.view.Display; import android.view.Display.Mode;
import android.view.DisplayAdjustments;
import android.view.DisplayInfo;
import androidx.preference.PreferenceManager; import androidx.preference.PreferenceManager;
import androidx.preference.PreferenceScreen; import androidx.preference.PreferenceScreen;
import androidx.test.core.app.ApplicationProvider; import androidx.test.core.app.ApplicationProvider;
import com.android.server.testutils.TestHandler;
import com.android.settings.connecteddevice.display.ExternalDisplaySettingsConfiguration.DisplayListener; import com.android.settings.connecteddevice.display.ExternalDisplaySettingsConfiguration.DisplayListener;
import com.android.settings.flags.FakeFeatureFlagsImpl; import com.android.settings.flags.FakeFeatureFlagsImpl;
@@ -48,6 +46,9 @@ import org.junit.Before;
import org.mockito.Mock; import org.mockito.Mock;
import org.mockito.MockitoAnnotations; import org.mockito.MockitoAnnotations;
import java.util.ArrayDeque;
import java.util.List;
public class ExternalDisplayTestBase { public class ExternalDisplayTestBase {
static final int EXTERNAL_DISPLAY_ID = 1; static final int EXTERNAL_DISPLAY_ID = 1;
static final int OVERLAY_DISPLAY_ID = 2; static final int OVERLAY_DISPLAY_ID = 2;
@@ -55,16 +56,46 @@ public class ExternalDisplayTestBase {
@Mock @Mock
ExternalDisplaySettingsConfiguration.Injector mMockedInjector; ExternalDisplaySettingsConfiguration.Injector mMockedInjector;
@Mock @Mock
IDisplayManager mMockedIDisplayManager;
Resources mResources; Resources mResources;
DisplayManagerGlobal mDisplayManagerGlobal;
FakeFeatureFlagsImpl mFlags = new FakeFeatureFlagsImpl(); FakeFeatureFlagsImpl mFlags = new FakeFeatureFlagsImpl();
Context mContext; Context mContext;
DisplayListener mListener; DisplayListener mListener;
TestHandler mHandler = new TestHandler(null); TestHandler mHandler;
PreferenceManager mPreferenceManager; PreferenceManager mPreferenceManager;
PreferenceScreen mPreferenceScreen; PreferenceScreen mPreferenceScreen;
Display[] mDisplays; List<DisplayDevice> mDisplays;
static class TestHandler extends Handler {
private final ArrayDeque<Message> mPending = new ArrayDeque<>();
private final Handler mSubhandler;
TestHandler(Handler subhandler) {
mSubhandler = subhandler;
}
ArrayDeque<Message> getPendingMessages() {
return mPending;
}
/**
* Schedules to send the message upon next invocation of {@link #flush()}. This ignores the
* time argument since our code doesn't meaningfully use it, but this is the most convenient
* way to intercept both Message and Callback objects synchronously.
*/
@Override
public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
mPending.add(msg);
return true;
}
void flush() {
for (var msg : mPending) {
mSubhandler.sendMessage(msg);
}
mPending.clear();
shadowOf(mSubhandler.getLooper()).idle();
}
}
/** /**
* Setup. * Setup.
@@ -77,20 +108,19 @@ public class ExternalDisplayTestBase {
doReturn(mResources).when(mContext).getResources(); doReturn(mResources).when(mContext).getResources();
mPreferenceManager = new PreferenceManager(mContext); mPreferenceManager = new PreferenceManager(mContext);
mPreferenceScreen = mPreferenceManager.createPreferenceScreen(mContext); mPreferenceScreen = mPreferenceManager.createPreferenceScreen(mContext);
doReturn(0).when(mMockedIDisplayManager).getPreferredWideGamutColorSpaceId();
mDisplayManagerGlobal = new DisplayManagerGlobal(mMockedIDisplayManager);
mFlags.setFlag(FLAG_DISPLAY_TOPOLOGY_PANE_IN_DISPLAY_LIST, false); mFlags.setFlag(FLAG_DISPLAY_TOPOLOGY_PANE_IN_DISPLAY_LIST, false);
mFlags.setFlag(FLAG_ROTATION_CONNECTED_DISPLAY_SETTING, true); mFlags.setFlag(FLAG_ROTATION_CONNECTED_DISPLAY_SETTING, true);
mFlags.setFlag(FLAG_RESOLUTION_AND_ENABLE_CONNECTED_DISPLAY_SETTING, true); mFlags.setFlag(FLAG_RESOLUTION_AND_ENABLE_CONNECTED_DISPLAY_SETTING, true);
mFlags.setFlag(FLAG_DISPLAY_SIZE_CONNECTED_DISPLAY_SETTING, true); mFlags.setFlag(FLAG_DISPLAY_SIZE_CONNECTED_DISPLAY_SETTING, true);
mDisplays = new Display[] { mDisplays = List.of(
createDefaultDisplay(), createExternalDisplay(), createOverlayDisplay()}; createExternalDisplay(DisplayIsEnabled.YES),
doReturn(mDisplays).when(mMockedInjector).getAllDisplays(); createOverlayDisplay(DisplayIsEnabled.YES));
doReturn(mDisplays).when(mMockedInjector).getEnabledDisplays(); doReturn(mDisplays).when(mMockedInjector).getConnectedDisplays();
for (var display : mDisplays) { for (var display : mDisplays) {
doReturn(display).when(mMockedInjector).getDisplay(display.getDisplayId()); doReturn(display).when(mMockedInjector).getDisplay(display.getId());
} }
doReturn(mFlags).when(mMockedInjector).getFlags(); doReturn(mFlags).when(mMockedInjector).getFlags();
mHandler = new TestHandler(mContext.getMainThreadHandler());
doReturn(mHandler).when(mMockedInjector).getHandler(); doReturn(mHandler).when(mMockedInjector).getHandler();
doReturn("").when(mMockedInjector).getSystemProperty( doReturn("").when(mMockedInjector).getSystemProperty(
VIRTUAL_DISPLAY_PACKAGE_NAME_SYSTEM_PROPERTY); VIRTUAL_DISPLAY_PACKAGE_NAME_SYSTEM_PROPERTY);
@@ -103,55 +133,26 @@ public class ExternalDisplayTestBase {
doReturn(mContext).when(mMockedInjector).getContext(); doReturn(mContext).when(mMockedInjector).getContext();
} }
Display createDefaultDisplay() throws RemoteException { DisplayDevice createExternalDisplay(DisplayIsEnabled isEnabled) {
int displayId = 0;
var displayInfo = new DisplayInfo();
doReturn(displayInfo).when(mMockedIDisplayManager).getDisplayInfo(displayId);
displayInfo.displayId = displayId;
displayInfo.name = "Built-in";
displayInfo.type = Display.TYPE_INTERNAL;
displayInfo.supportedModes = new Display.Mode[]{
new Display.Mode(0, 2048, 1024, 60, 60, new float[0],
new int[0])};
displayInfo.appsSupportedModes = displayInfo.supportedModes;
return createDisplay(displayInfo);
}
Display createExternalDisplay() throws RemoteException {
int displayId = EXTERNAL_DISPLAY_ID; int displayId = EXTERNAL_DISPLAY_ID;
var displayInfo = new DisplayInfo(); var supportedModes = List.of(
doReturn(displayInfo).when(mMockedIDisplayManager).getDisplayInfo(displayId); new Mode(0, 1920, 1080, 60, 60, new float[0], new int[0]),
displayInfo.displayId = displayId; new Mode(1, 800, 600, 60, 60, new float[0], new int[0]),
displayInfo.name = "HDMI"; new Mode(2, 320, 240, 70, 70, new float[0], new int[0]),
displayInfo.type = Display.TYPE_EXTERNAL; new Mode(3, 640, 480, 60, 60, new float[0], new int[0]),
displayInfo.supportedModes = new Display.Mode[]{ new Mode(4, 640, 480, 50, 60, new float[0], new int[0]),
new Display.Mode(0, 1920, 1080, 60, 60, new float[0], new int[0]), new Mode(5, 2048, 1024, 60, 60, new float[0], new int[0]),
new Display.Mode(1, 800, 600, 60, 60, new float[0], new int[0]), new Mode(6, 720, 480, 60, 60, new float[0], new int[0]));
new Display.Mode(2, 320, 240, 70, 70, new float[0], new int[0]), return new DisplayDevice(
new Display.Mode(3, 640, 480, 60, 60, new float[0], new int[0]), displayId, "HDMI", supportedModes.get(0), supportedModes, isEnabled);
new Display.Mode(4, 640, 480, 50, 60, new float[0], new int[0]),
new Display.Mode(5, 2048, 1024, 60, 60, new float[0], new int[0]),
new Display.Mode(6, 720, 480, 60, 60, new float[0], new int[0])};
displayInfo.appsSupportedModes = displayInfo.supportedModes;
return createDisplay(displayInfo);
} }
Display createOverlayDisplay() throws RemoteException { DisplayDevice createOverlayDisplay(DisplayIsEnabled isEnabled) {
int displayId = OVERLAY_DISPLAY_ID; int displayId = OVERLAY_DISPLAY_ID;
var displayInfo = new DisplayInfo(); var supportedModes = List.of(
doReturn(displayInfo).when(mMockedIDisplayManager).getDisplayInfo(displayId); new Mode(0, 1240, 780, 60, 60, new float[0],
displayInfo.displayId = displayId; new int[0]));
displayInfo.name = "Overlay #1"; return new DisplayDevice(
displayInfo.type = Display.TYPE_OVERLAY; displayId, "Overlay #1", supportedModes.get(0), supportedModes, isEnabled);
displayInfo.supportedModes = new Display.Mode[]{
new Display.Mode(0, 1240, 780, 60, 60, new float[0],
new int[0])};
displayInfo.appsSupportedModes = displayInfo.supportedModes;
return createDisplay(displayInfo);
}
Display createDisplay(DisplayInfo displayInfo) {
return new Display(mDisplayManagerGlobal, displayInfo.displayId, displayInfo,
(DisplayAdjustments) null);
} }
} }

View File

@@ -24,7 +24,6 @@ import static org.mockito.Mockito.doReturn;
import android.content.Context; import android.content.Context;
import android.graphics.drawable.Drawable; import android.graphics.drawable.Drawable;
import android.os.RemoteException; import android.os.RemoteException;
import android.view.Display;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.ext.junit.runners.AndroidJUnit4;
@@ -38,6 +37,8 @@ import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import org.mockito.Mock; import org.mockito.Mock;
import java.util.List;
/** Unit tests for {@link ExternalDisplayUpdater}. */ /** Unit tests for {@link ExternalDisplayUpdater}. */
@RunWith(AndroidJUnit4.class) @RunWith(AndroidJUnit4.class)
public class ExternalDisplayUpdaterTest extends ExternalDisplayTestBase { public class ExternalDisplayUpdaterTest extends ExternalDisplayTestBase {
@@ -92,8 +93,7 @@ public class ExternalDisplayUpdaterTest extends ExternalDisplayTestBase {
assertThat(mPreferenceAdded).isNotNull(); assertThat(mPreferenceAdded).isNotNull();
assertThat(mPreferenceRemoved).isNull(); assertThat(mPreferenceRemoved).isNull();
// Remove display // Remove display
doReturn(new Display[0]).when(mMockedInjector).getAllDisplays(); doReturn(List.of()).when(mMockedInjector).getConnectedDisplays();
doReturn(new Display[0]).when(mMockedInjector).getEnabledDisplays();
mListener.onDisplayRemoved(1); mListener.onDisplayRemoved(1);
mHandler.flush(); mHandler.flush();
assertThat(mPreferenceRemoved).isEqualTo(mPreferenceAdded); assertThat(mPreferenceRemoved).isEqualTo(mPreferenceAdded);

View File

@@ -134,14 +134,15 @@ public class ResolutionPreferenceFragmentTest extends ExternalDisplayTestBase {
@Test @Test
@UiThreadTest @UiThreadTest
public void testModeChange() { public void testModeChange() {
mDisplayIdArg = 1; DisplayDevice display = mDisplays.get(0);
mDisplayIdArg = display.getId();
initFragment(); initFragment();
mHandler.flush(); mHandler.flush();
PreferenceCategory topPref = mPreferenceScreen.findPreference(TOP_OPTIONS_KEY); PreferenceCategory topPref = mPreferenceScreen.findPreference(TOP_OPTIONS_KEY);
assertThat(topPref).isNotNull(); assertThat(topPref).isNotNull();
var modePref = (SelectorWithWidgetPreference) topPref.getPreference(1); var modePref = (SelectorWithWidgetPreference) topPref.getPreference(1);
modePref.onClick(); modePref.onClick();
var mode = mDisplays[mDisplayIdArg].getSupportedModes()[1]; var mode = display.getSupportedModes().get(1);
verify(mMockedInjector).setUserPreferredDisplayMode(mDisplayIdArg, mode); verify(mMockedInjector).setUserPreferredDisplayMode(mDisplayIdArg, mode);
} }