0

Add ActiveState property to DisplayUnitInfo

This new property can be used if the display is in active (detected)
state.

Bug: b/277952661
Test: DisplayManagerTest.UpdateDisplayTest, DisplayInfoProviderChromeosTest.GetBasic
Change-Id: I5ea2a19ef9a28a9e21b7e61a67442aa8a8a74c06
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4644292
Commit-Queue: Mitsuru Oshima <oshima@chromium.org>
Reviewed-by: Ahmed Fakhry <afakhry@chromium.org>
Reviewed-by: Stefan Kuhne <skuhne@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1164506}
This commit is contained in:
Mitsuru Oshima
2023-06-30 03:41:42 +00:00
committed by Chromium LUCI CQ
parent c030b422a1
commit 9dc9cf99e9
15 changed files with 150 additions and 18 deletions

@ -315,6 +315,7 @@ crosapi::mojom::DisplayUnitInfoPtr GetDisplayUnitInfo(
info->is_primary = display.id() == primary_id;
info->is_internal = display.IsInternal();
info->is_enabled = true;
info->is_detected = display.detected();
info->is_auto_rotation_allowed =
Shell::Get()->screen_orientation_controller()->IsAutoRotationAllowed() &&
display.IsInternal();

@ -109,14 +109,14 @@ class DisplayManagerTest : public AshTestBase,
const vector<display::Display>& changed() const { return changed_; }
const vector<display::Display>& added() const { return added_; }
uint32_t changed_metrics() const {
uint32_t changed_metrics = 0;
int32_t changed_metrics() const {
int32_t changed_metrics = 0;
for (const auto& display_metrics : changed_metrics_) {
changed_metrics |= display_metrics.second;
}
return changed_metrics;
}
uint32_t changed_metrics(int64_t display_id) const {
int32_t changed_metrics(int64_t display_id) const {
return changed_metrics_.at(display_id);
}
@ -336,16 +336,34 @@ TEST_F(DisplayManagerTest, UpdateDisplayTest) {
const vector<display::ManagedDisplayInfo> empty;
display_manager()->OnNativeDisplaysChanged(empty);
EXPECT_EQ(1U, display_manager()->GetNumDisplays());
// Going to 0 displays doesn't actually change the list and is effectively
// ignored.
EXPECT_EQ("0 0 0 0 0", GetCountSummary());
// Going to 0 displays doesn't actually change the list and but the detected
// is set to false.
EXPECT_EQ("1 0 0 0 0", GetCountSummary());
EXPECT_FALSE(root_window_destroyed());
// Display configuration stays the same
EXPECT_EQ(gfx::Rect(0, 0, 800, 300),
display_manager()->GetDisplayAt(0).bounds());
EXPECT_FALSE(display_manager()->GetDisplayAt(0).detected());
EXPECT_EQ(changed_metrics(),
display::DisplayObserver::DISPLAY_METRIC_DETECTED);
reset();
// Connect to display again
// Connect to display again.
UpdateDisplay("1+1-800x300");
EXPECT_EQ(1U, display_manager()->GetNumDisplays());
EXPECT_EQ("1 0 0 1 1", GetCountSummary());
EXPECT_FALSE(root_window_destroyed());
EXPECT_EQ(gfx::Rect(800, 300), changed()[0].bounds());
EXPECT_EQ(gfx::Rect(1, 1, 800, 300),
GetDisplayInfo(changed()[0]).bounds_in_native());
EXPECT_TRUE(display_manager()->GetDisplayAt(0).detected());
EXPECT_EQ(changed_metrics(),
display::DisplayObserver::DISPLAY_METRIC_DETECTED);
// Resumed with different resolution.
display_manager()->OnNativeDisplaysChanged(empty);
EXPECT_EQ(1U, display_manager()->GetNumDisplays());
reset();
UpdateDisplay("100+100-500x400");
EXPECT_EQ(1U, display_manager()->GetNumDisplays());
EXPECT_EQ("1 0 0 1 1", GetCountSummary());
@ -353,6 +371,12 @@ TEST_F(DisplayManagerTest, UpdateDisplayTest) {
EXPECT_EQ(gfx::Rect(0, 0, 500, 400), changed()[0].bounds());
EXPECT_EQ(gfx::Rect(100, 100, 500, 400),
GetDisplayInfo(changed()[0]).bounds_in_native());
EXPECT_TRUE(display_manager()->GetDisplayAt(0).detected());
EXPECT_EQ(changed_metrics(),
(display::DisplayObserver::DISPLAY_METRIC_DETECTED |
display::DisplayObserver::DISPLAY_METRIC_BOUNDS |
display::DisplayObserver::DISPLAY_METRIC_WORK_AREA));
reset();
// Go back to zero and wake up with multiple displays.
@ -1967,7 +1991,7 @@ TEST_F(DisplayManagerTest, DisplayRemovedOnlyOnceWhenEnteringDockedMode) {
// There should only be 1 display change, 0 adds, and 1 removal.
EXPECT_EQ("1 0 1 1 1", GetCountSummary());
const unsigned int expected_changed_metrics =
const int expected_changed_metrics =
display::DisplayObserver::DISPLAY_METRIC_BOUNDS |
display::DisplayObserver::DISPLAY_METRIC_WORK_AREA |
display::DisplayObserver::DISPLAY_METRIC_PRIMARY;

@ -220,6 +220,7 @@ TEST_F(DisplayInfoProviderChromeosTest, GetBasic) {
EXPECT_EQ(96, result[0].dpi_y);
EXPECT_TRUE(result[0].mirroring_source_id.empty());
EXPECT_TRUE(result[0].is_enabled);
EXPECT_EQ(api::system_display::ActiveState::kActive, result[0].active_state);
ASSERT_TRUE(base::StringToInt64(result[1].id, &display_id))
<< "Display id must be convertible to integer: " << result[0].id;
@ -237,6 +238,39 @@ TEST_F(DisplayInfoProviderChromeosTest, GetBasic) {
EXPECT_EQ(96, result[1].dpi_y);
EXPECT_TRUE(result[1].mirroring_source_id.empty());
EXPECT_TRUE(result[1].is_enabled);
EXPECT_EQ(api::system_display::ActiveState::kActive, result[1].active_state);
// Disconnect all displays.
UpdateDisplay("");
result = GetAllDisplaysInfo();
ASSERT_EQ(2u, result.size());
ASSERT_TRUE(base::StringToInt64(result[0].id, &display_id))
<< "Display id must be convertible to integer: " << result[0].id;
ASSERT_TRUE(DisplayExists(display_id)) << display_id << " not found";
EXPECT_TRUE(result[0].is_primary);
EXPECT_EQ(api::system_display::ActiveState::kInactive,
result[0].active_state);
ASSERT_TRUE(base::StringToInt64(result[1].id, &display_id))
<< "Display id must be convertible to integer: " << result[0].id;
ASSERT_TRUE(DisplayExists(display_id)) << display_id << " not found";
EXPECT_EQ("500,0 400x520", SystemInfoDisplayBoundsToString(result[1].bounds));
EXPECT_FALSE(result[1].is_primary);
EXPECT_EQ(api::system_display::ActiveState::kInactive,
result[1].active_state);
// Reconnect first display.
UpdateDisplay("500x600");
result = GetAllDisplaysInfo();
ASSERT_EQ(1u, result.size());
ASSERT_TRUE(base::StringToInt64(result[0].id, &display_id))
<< "Display id must be convertible to integer: " << result[0].id;
ASSERT_TRUE(DisplayExists(display_id)) << display_id << " not found";
EXPECT_TRUE(result[0].is_primary);
EXPECT_EQ(api::system_display::ActiveState::kActive, result[0].active_state);
}
TEST_F(DisplayInfoProviderChromeosTest, GetWithUnifiedDesktop) {

@ -202,6 +202,9 @@ system_display::DisplayUnitInfo GetDisplayUnitInfoFromMojo(
}
info.is_primary = mojo_info.is_primary;
info.is_internal = mojo_info.is_internal;
info.active_state = mojo_info.is_detected
? system_display::ActiveState::kActive
: system_display::ActiveState::kInactive;
info.is_enabled = mojo_info.is_enabled;
info.is_auto_rotation_allowed = mojo_info.is_auto_rotation_allowed;
info.dpi_x = mojo_info.dpi_x;

@ -8,6 +8,7 @@ import "ui/gfx/geometry/mojom/geometry.mojom";
import "ui/display/mojom/display.mojom";
// This API is used for communication between Settings WebUI and Ash C++ code.
// Next MinVersion: 2
// All points, bounds, and insets are in display pixels unless otherwise
// sepcified.
@ -259,6 +260,8 @@ struct DisplayUnitInfo {
double display_zoom_factor@17;
// The list of allowed zoom factor values for the display.
array<double> available_display_zoom_factors@18;
// True if the display was detected by the system.
[MinVersion=1] bool is_detected@19;
};
// Properties for configuring an individual display, used in

@ -79,6 +79,9 @@ api::system_display::DisplayUnitInfo DisplayInfoProvider::CreateDisplayUnitInfo(
unit.id = base::NumberToString(display.id());
unit.is_primary = (display.id() == primary_display_id);
unit.is_internal = display.IsInternal();
unit.active_state = display.detected()
? api::system_display::ActiveState::kActive
: api::system_display::ActiveState::kInactive;
unit.is_enabled = true;
unit.is_unified = false;
unit.rotation = RotationToDegrees(display.rotation());
@ -134,7 +137,6 @@ void DisplayInfoProvider::GetAllDisplaysInfo(
provided_screen_ ? provided_screen_.get() : display::Screen::GetScreen();
int64_t primary_id = screen->GetPrimaryDisplay().id();
std::vector<display::Display> displays = screen->GetAllDisplays();
DisplayUnitInfoList all_displays;
base::ThreadPool::PostTaskAndReplyWithResult(
FROM_HERE,
base::BindOnce(&DisplayInfoProvider::GetAllDisplaysInfoList,

@ -130,6 +130,14 @@ namespace system.display {
long yearOfManufacture;
};
// An enum to tell if the display is detected and used by the
// system. The display is considered 'inactive', if it is not
// detected by the system (maybe disconnected, or considered
// disconnected due to sleep mode, etc). This state is used to keep
// existing display when the all displays are disconnected, for
// example.
enum ActiveState { active, inactive };
dictionary DisplayUnitInfo {
// The unique identifier of the display.
DOMString id;
@ -160,6 +168,9 @@ namespace system.display {
// True if this display is enabled.
boolean isEnabled;
// Active if the display is detected and used by the system.
ActiveState activeState;
// True for all displays when in unified desktop mode. See documentation
// for $(ref:enableUnifiedDesktop).
boolean isUnified;

@ -57,6 +57,14 @@ declare global {
LEFT = 'left',
}
/**
* @see https://developer.chrome.com/extensions/system.display#type-ActiveState
*/
export enum ActiveState {
ACTIVE = 'active',
INACTIVE = 'inactive',
}
/**
* @see https://developer.chrome.com/extensions/system.display#type-DisplayLayout
*/
@ -87,6 +95,7 @@ declare global {
mirroringDestinationIds: string[];
isPrimary: boolean;
isInternal: boolean;
activeState: ActiveState;
isEnabled: boolean;
isUnified: boolean;
isAutoRotationAllowed?: boolean;

@ -306,11 +306,12 @@ gfx::Size Display::GetSizeInPixel() const {
std::string Display::ToString() const {
return base::StringPrintf(
"Display[%lld] bounds=[%s], workarea=[%s], scale=%g, rotation=%s, "
"panel_rotation=%s %s.",
"panel_rotation=%s %s %s",
static_cast<long long int>(id_), bounds_.ToString().c_str(),
work_area_.ToString().c_str(), device_scale_factor_,
ToRotationString(rotation_), ToRotationString(panel_rotation()),
IsInternal() ? "internal" : "external");
IsInternal() ? "internal" : "external",
detected() ? "detected" : "not-detected");
}
bool Display::IsInternal() const {
@ -326,7 +327,7 @@ int64_t Display::InternalDisplayId() {
bool Display::operator==(const Display& rhs) const {
return id_ == rhs.id_ && bounds_ == rhs.bounds_ &&
size_in_pixels_ == rhs.size_in_pixels_ &&
size_in_pixels_ == rhs.size_in_pixels_ && detected_ == rhs.detected_ &&
work_area_ == rhs.work_area_ &&
device_scale_factor_ == rhs.device_scale_factor_ &&
rotation_ == rhs.rotation_ && touch_support_ == rhs.touch_support_ &&

@ -203,6 +203,16 @@ class DISPLAY_EXPORT Display final {
// True if the display corresponds to internal panel.
bool IsInternal() const;
// Returns true if the display is detected by the system. A display can
// stay 'active' when all displays are disconnected from SW point of view,
// because this can happen when the display went to sleep mode, or the
// device went to sleep mode, and in that case, we do not want to change
// the display configuration (so that it starts in the same state when
// resumed). Use this if you want to check if the display is detected by the
// system.
bool detected() const { return detected_; }
void set_detected(bool detected) { detected_ = detected; }
// [Deprecated] Use `display::GetInternalDisplayIds()`.
// Gets an id of display corresponding to internal panel.
static int64_t InternalDisplayId();
@ -294,6 +304,7 @@ class DISPLAY_EXPORT Display final {
int color_depth_;
int depth_per_component_;
bool is_monochrome_ = false;
bool detected_ = true;
int display_frequency_ = 0;
std::string label_;
uint32_t audio_formats_ = 0;

@ -31,6 +31,7 @@ class DISPLAY_EXPORT DisplayObserver : public base::CheckedObserver {
DISPLAY_METRIC_INTERLACED = 1 << 8,
DISPLAY_METRIC_LABEL = 1 << 9,
DISPLAY_METRIC_VRR = 1 << 10,
DISPLAY_METRIC_DETECTED = 1 << 11,
};
// This may be called before other methods to signal changes are about to

@ -750,10 +750,12 @@ void DisplayManager::OnNativeDisplaysChanged(
DisplayInfoList init_displays;
init_displays.push_back(
ManagedDisplayInfo::CreateFromSpec(std::string()));
init_displays[0].set_detected(false);
MaybeInitInternalDisplay(&init_displays[0]);
OnNativeDisplaysChanged(init_displays);
} else {
// Otherwise don't update the displays when all displays are disconnected.
// Otherwise just update the displays' detected state when all displays
// are disconnected.
// This happens when:
// - the device is idle and powerd requested to turn off all displays.
// - the device is suspended. (kernel turns off all displays)
@ -763,6 +765,17 @@ void DisplayManager::OnNativeDisplaysChanged(
// disconnected.
// The display will be updated when one of displays is turned on, and the
// display list will be updated correctly.
for (auto& display : active_display_list_) {
if (display.detected()) {
ManagedDisplayInfo info = GetDisplayInfo(display.id());
info.set_detected(false);
display.set_detected(false);
InsertAndUpdateDisplayInfo(info);
NotifyMetricsChanged(display,
DisplayObserver::DISPLAY_METRIC_DETECTED);
}
}
}
return;
}
@ -999,6 +1012,9 @@ void DisplayManager::UpdateDisplaysWith(
new_display_info.vsync_rate_min()) {
metrics |= DisplayObserver::DISPLAY_METRIC_VRR;
}
if (current_display_info.detected() != new_display_info.detected()) {
metrics |= DisplayObserver::DISPLAY_METRIC_DETECTED;
}
if (metrics != DisplayObserver::DISPLAY_METRIC_NONE) {
display_changes.insert(
@ -1097,13 +1113,17 @@ void DisplayManager::UpdateDisplaysWith(
for (auto iter = display_changes.begin(); iter != display_changes.end();
++iter) {
uint32_t metrics = iter->second;
const Display& updated_display = active_display_list_[iter->first];
Display& updated_display = active_display_list_[iter->first];
if (notify_primary_change &&
updated_display.id() == screen_->GetPrimaryDisplay().id()) {
metrics |= DisplayObserver::DISPLAY_METRIC_PRIMARY;
notify_primary_change = false;
}
if (!updated_display.detected()) {
updated_display.set_detected(true);
metrics |= DisplayObserver::DISPLAY_METRIC_DETECTED;
}
NotifyMetricsChanged(updated_display, metrics);
}
@ -2093,6 +2113,7 @@ Display DisplayManager::CreateDisplayFromDisplayInfoById(int64_t id) {
new_display.set_label(display_info.name());
new_display.SetDRMFormatsAndModifiers(
display_info.GetDRMFormatsAndModifiers());
new_display.set_detected(display_info.detected());
constexpr uint32_t kNormalBitDepthNumBitsPerChannel = 8u;
if (display_info.bits_per_channel() > kNormalBitDepthNumBitsPerChannel) {

@ -470,6 +470,7 @@ void ManagedDisplayInfo::Copy(const ManagedDisplayInfo& native_info) {
drm_formats_and_modifiers_ = native_info.drm_formats_and_modifiers_;
variable_refresh_rate_state_ = native_info.variable_refresh_rate_state_;
vsync_rate_min_ = native_info.vsync_rate_min_;
detected_ = native_info.detected_;
// Rotation, color_profile and overscan are given by preference,
// or unit tests. Don't copy if this native_info came from
@ -577,7 +578,7 @@ std::string ManagedDisplayInfo::ToString() const {
std::string result = base::StringPrintf(
"ManagedDisplayInfo[%lld] native bounds=%s, size=%s, device-scale=%g, "
"display-zoom=%g, overscan=%s, rotation=%d, touchscreen=%s, "
"panel_corners_radii=%s, panel_orientation=%s",
"panel_corners_radii=%s, panel_orientation=%s, detected=%s",
static_cast<long long int>(id_), bounds_in_native_.ToString().c_str(),
size_in_pixel_.ToString().c_str(), device_scale_factor_, zoom_factor_,
overscan_insets_in_dip_.ToString().c_str(), rotation_degree,
@ -585,7 +586,8 @@ std::string ManagedDisplayInfo::ToString() const {
: touch_support_ == Display::TouchSupport::UNAVAILABLE ? "no"
: "unknown",
panel_corners_radii_.ToString().c_str(),
PanelOrientationToString(panel_orientation_).c_str());
PanelOrientationToString(panel_orientation_).c_str(),
detected_ ? "true" : "false");
return result;
}

@ -226,6 +226,9 @@ class DISPLAY_MANAGER_EXPORT ManagedDisplayInfo {
return active_rotation_source_;
}
bool detected() const { return detected_; }
void set_detected(bool detected) { detected_ = detected; }
// Returns the rotation set by a given |source|.
Display::Rotation GetRotation(Display::RotationSource source) const;
@ -427,6 +430,11 @@ class DISPLAY_MANAGER_EXPORT ManagedDisplayInfo {
// to distinguish the empty overscan insets from native display info.
bool clear_overscan_insets_;
// True if the display is detected by the system. The system will keep at
// least one display available even if all displays are disconnected, and this
// field is set to false in such a case.
bool detected_ = true;
// The list of modes supported by this display.
ManagedDisplayModeList display_modes_;

@ -161,14 +161,15 @@ TEST_F(DisplayInfoTest, TestToStringFormat) {
"device-scale=1, display-zoom=1, overscan=x:0,0 y:0,0, rotation=0, "
"touchscreen=unknown, "
"panel_corners_radii=0.000000,0.000000,0.000000,0.000000, "
"panel_orientation=Normal");
"panel_orientation=Normal, detected=true");
EXPECT_EQ(info.ToFullString(),
"ManagedDisplayInfo[10] native bounds=0,0 200x100, size=200x100, "
"device-scale=1, display-zoom=1, overscan=x:0,0 y:0,0, rotation=0, "
"touchscreen=unknown, "
"panel_corners_radii=0.000000,0.000000,0.000000,0.000000, "
"panel_orientation=Normal, display_modes==(200x100@60P(N) 1)");
"panel_orientation=Normal, detected=true, "
"display_modes==(200x100@60P(N) 1)");
}
} // namespace display