Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit b50716bb authored by Oleg Blinnikov's avatar Oleg Blinnikov
Browse files

ExternalDisplayStats on content mode changes

ExternalDisplayStatsService keeps track of the extended or mirror
setting based on display count. When it logs an event with display
count = 1 then metric will count it as content mode change.

In addition to this, right now there is only global settings toggle to
switch between extended and mirror globally. All displays are assumed to be either mirroring or extended.

Whenever display is getting disabled through disableConnectedDisplay API , this event is currently not logged. From metrics perspective display will stay in the content mode chosen in settings, and not in disabled state.

If the display is just connected and not yet Enabled by the user through the "Mirror/Dismiss dialog" - display stays in "Connected" state, not "mirroring" from metrics perspective.

With this CL, all External Displays get auto-enabled if the user switches "mirror"/"Extended" settings toggle. In addition to this, stats service now logs the event of switching between mirror/extended.

Bug: 400742534
Bug: 400384229
Test: atest ExternalDisplayStatsServiceTest ExternalDisplayPolicy
DisplayManagerServiceTest
Flag: com.android.server.display.feature.flags.enable_display_content_mode_management
Change-Id: I3c11f39f9028306443343a4b5f8c6b72f1e1e667
parent 38ea04a0
Loading
Loading
Loading
Loading
+17 −8
Original line number Diff line number Diff line
@@ -674,9 +674,8 @@ public final class DisplayManagerService extends SystemService {
        mConfigParameterProvider = new DeviceConfigParameterProvider(DeviceConfigInterface.REAL);
        mExtraDisplayLoggingPackageName = DisplayProperties.debug_vri_package().orElse(null);
        mExtraDisplayEventLogging = !TextUtils.isEmpty(mExtraDisplayLoggingPackageName);
        // TODO(b/400384229): stats service needs to react to mirror-extended switch
        mExternalDisplayStatsService = new ExternalDisplayStatsService(mContext, mHandler,
                this::isExtendedDisplayAllowed);
                () -> !shouldMirrorBuiltInDisplay());
        mDisplayNotificationManager = new DisplayNotificationManager(mFlags, mContext,
                mExternalDisplayStatsService);
        mExternalDisplayPolicy = new ExternalDisplayPolicy(new ExternalDisplayPolicyInjector());
@@ -813,7 +812,11 @@ public final class DisplayManagerService extends SystemService {
            handleMinimalPostProcessingAllowedSettingChange();

            if (mFlags.isDisplayContentModeManagementEnabled()) {
                updateMirrorBuiltInDisplaySettingLocked(/*shouldSendDisplayChangeEvent=*/ true);
                if (updateMirrorBuiltInDisplaySettingLocked(
                        /*shouldSendDisplayChangeEvent=*/ true)) {
                    mExternalDisplayPolicy.handleMirrorBuiltInDisplaySettingChangeLocked(
                            /*enableDisplays=*/ true);
                }
            }

            final UserManager userManager = getUserManager();
@@ -1240,8 +1243,11 @@ public final class DisplayManagerService extends SystemService {
            if (Settings.Secure.getUriFor(MIRROR_BUILT_IN_DISPLAY).equals(uri)) {
                synchronized (mSyncRoot) {
                    if (mFlags.isDisplayContentModeManagementEnabled()) {
                        updateMirrorBuiltInDisplaySettingLocked(/*shouldSendDisplayChangeEvent=*/
                                true);
                        if (updateMirrorBuiltInDisplaySettingLocked(
                                /*shouldSendDisplayChangeEvent=*/ true)) {
                            mExternalDisplayPolicy.handleMirrorBuiltInDisplaySettingChangeLocked(
                                /*enableDisplays=*/ true);
                        }
                    }
                }
                return;
@@ -1262,12 +1268,13 @@ public final class DisplayManagerService extends SystemService {
                1, UserHandle.USER_CURRENT) != 0);
    }

    private void updateMirrorBuiltInDisplaySettingLocked(boolean shouldSendDisplayChangeEvent) {
    private boolean updateMirrorBuiltInDisplaySettingLocked(boolean shouldSendDisplayChangeEvent) {
        ContentResolver resolver = mContext.getContentResolver();
        final boolean mirrorBuiltInDisplay = Settings.Secure.getIntForUser(resolver,
                MIRROR_BUILT_IN_DISPLAY, 0, UserHandle.USER_CURRENT) != 0;
        if (mMirrorBuiltInDisplay == mirrorBuiltInDisplay) {
            return;
            // No change in setting.
            return false;
        }
        mMirrorBuiltInDisplay = mirrorBuiltInDisplay;
        if (mFlags.isDisplayContentModeManagementEnabled()) {
@@ -1276,6 +1283,8 @@ public final class DisplayManagerService extends SystemService {
                            shouldSendDisplayChangeEvent);
            });
        }
        // setting changed.
        return true;
    }

    private void restoreResolutionFromBackup() {
@@ -2440,7 +2449,7 @@ public final class DisplayManagerService extends SystemService {

        updateLogicalDisplayState(display);

        mExternalDisplayPolicy.handleLogicalDisplayAddedLocked(display);
        mExternalDisplayPolicy.handleLogicalDisplayContentModeChange(display);

        if (mFlags.isApplyDisplayChangedDuringDisplayAddedEnabled()) {
            applyDisplayChangedLocked(display);
+27 −4
Original line number Diff line number Diff line
@@ -125,6 +125,8 @@ class ExternalDisplayPolicy {
    }

    /**
     * Handles the displays which were connected before the boot completed.
     * Handles content mode for external displays.
     * Starts listening for temperature changes.
     */
    void onBootCompleted() {
@@ -142,6 +144,10 @@ class ExternalDisplayPolicy {
            mDisplayIdsWaitingForBootCompletion.clear();
        }

        if (mFlags.isDisplayContentModeManagementEnabled()) {
            handleMirrorBuiltInDisplaySettingChangeLocked(/*enableDisplays=*/ false);
        }

        if (!mFlags.isConnectedDisplayErrorHandlingEnabled()) {
            if (DEBUG) {
                Slog.d(TAG, "ConnectedDisplayErrorHandlingEnabled is not enabled on your device:"
@@ -155,6 +161,22 @@ class ExternalDisplayPolicy {
        }
    }

    /**
     * Handles content mode change for all displays and
     * enables all external displays if needed.
     */
    void handleMirrorBuiltInDisplaySettingChangeLocked(boolean enableDisplays) {
        mLogicalDisplayMapper.forEachLocked(logicalDisplay -> {
            if (!isExternalDisplayLocked(logicalDisplay)) {
                return;
            }
            if (!logicalDisplay.isEnabledLocked() && enableDisplays) {
                setExternalDisplayEnabledLocked(logicalDisplay, true);
            }
            handleLogicalDisplayContentModeChange(logicalDisplay);
        });
    }

    /**
     * Checks the display type is external, and if it is external then enables/disables it.
     */
@@ -236,14 +258,15 @@ class ExternalDisplayPolicy {
    }

    /**
     * Upon external display gets added.
     * Upon external display content mode change.
     */
    void handleLogicalDisplayAddedLocked(@NonNull final LogicalDisplay logicalDisplay) {
        if (!isExternalDisplayLocked(logicalDisplay)) {
    void handleLogicalDisplayContentModeChange(@NonNull final LogicalDisplay logicalDisplay) {
        if (!isExternalDisplayLocked(logicalDisplay) || !logicalDisplay.isEnabledLocked()) {
            return;
        }

        mExternalDisplayStatsService.onDisplayAdded(logicalDisplay.getDisplayIdLocked());
        mExternalDisplayStatsService.onDisplayContentModeChange(
            logicalDisplay.getDisplayIdLocked());
    }

    /**
+1 −1
Original line number Diff line number Diff line
@@ -241,7 +241,7 @@ public final class ExternalDisplayStatsService {
        logStateConnected(display.getDisplayIdLocked());
    }

    void onDisplayAdded(int displayId) {
    void onDisplayContentModeChange(int displayId) {
        if (mInjector.isExtendedDisplayEnabled()) {
            logStateExtended(displayId);
        } else {
+4 −3
Original line number Diff line number Diff line
@@ -194,9 +194,10 @@ public class ExternalDisplayPolicyTest {
    }

    @Test
    public void testHandleDisplayAdded() {
        mExternalDisplayPolicy.handleLogicalDisplayAddedLocked(mMockedLogicalDisplay);
        verify(mMockedExternalDisplayStatsService).onDisplayAdded(eq(EXTERNAL_DISPLAY_ID));
    public void testHandleDisplayContentModeChange() {
        mExternalDisplayPolicy.handleLogicalDisplayContentModeChange(mMockedLogicalDisplay);
        verify(mMockedExternalDisplayStatsService).onDisplayContentModeChange(
            eq(EXTERNAL_DISPLAY_ID));
    }

    @Test
+29 −5
Original line number Diff line number Diff line
@@ -154,7 +154,7 @@ public class ExternalDisplayStatsServiceTest {
    public void testDisplayInteractivityChangesWhileMirroring(
            @TestParameter final boolean isExternalDisplayUsedForAudio) {
        mExternalDisplayStatsService.onDisplayConnected(mMockedLogicalDisplay);
        mExternalDisplayStatsService.onDisplayAdded(EXTERNAL_DISPLAY_ID);
        mExternalDisplayStatsService.onDisplayContentModeChange(EXTERNAL_DISPLAY_ID);
        mHandler.flush();
        assertThat(mInteractivityReceiver).isNotNull();

@@ -234,7 +234,7 @@ public class ExternalDisplayStatsServiceTest {
        initAudioPlayback(isExternalDisplayUsedForAudio);
        clearInvocations(mMockedInjector);

        mExternalDisplayStatsService.onDisplayAdded(EXTERNAL_DISPLAY_ID);
        mExternalDisplayStatsService.onDisplayContentModeChange(EXTERNAL_DISPLAY_ID);
        verify(mMockedInjector).writeLog(FrameworkStatsLog.EXTERNAL_DISPLAY_STATE_CHANGED,
                FrameworkStatsLog.EXTERNAL_DISPLAY_STATE_CHANGED__STATE__MIRRORING,
                /*numberOfDisplays=*/ 1,
@@ -250,20 +250,44 @@ public class ExternalDisplayStatsServiceTest {
        clearInvocations(mMockedInjector);

        when(mMockedInjector.isExtendedDisplayEnabled()).thenReturn(true);
        mExternalDisplayStatsService.onDisplayAdded(EXTERNAL_DISPLAY_ID);
        mExternalDisplayStatsService.onDisplayContentModeChange(EXTERNAL_DISPLAY_ID);
        verify(mMockedInjector).writeLog(FrameworkStatsLog.EXTERNAL_DISPLAY_STATE_CHANGED,
                FrameworkStatsLog.EXTERNAL_DISPLAY_STATE_CHANGED__STATE__EXTENDED,
                /*numberOfDisplays=*/ 1,
                isExternalDisplayUsedForAudio);
    }

    @Test
    public void testOnDisplayContentModeChange(
            @TestParameter final boolean isExternalDisplayUsedForAudio) {
        mExternalDisplayStatsService.onDisplayConnected(mMockedLogicalDisplay);
        mHandler.flush();
        initAudioPlayback(isExternalDisplayUsedForAudio);
        clearInvocations(mMockedInjector);

        when(mMockedInjector.isExtendedDisplayEnabled()).thenReturn(true);
        mExternalDisplayStatsService.onDisplayContentModeChange(EXTERNAL_DISPLAY_ID);
        verify(mMockedInjector).writeLog(FrameworkStatsLog.EXTERNAL_DISPLAY_STATE_CHANGED,
                FrameworkStatsLog.EXTERNAL_DISPLAY_STATE_CHANGED__STATE__EXTENDED,
                /*numberOfDisplays=*/ 1,
                isExternalDisplayUsedForAudio);

        clearInvocations(mMockedInjector);
        when(mMockedInjector.isExtendedDisplayEnabled()).thenReturn(false);
        mExternalDisplayStatsService.onDisplayContentModeChange(EXTERNAL_DISPLAY_ID);
        verify(mMockedInjector).writeLog(FrameworkStatsLog.EXTERNAL_DISPLAY_STATE_CHANGED,
                FrameworkStatsLog.EXTERNAL_DISPLAY_STATE_CHANGED__STATE__MIRRORING,
                /*numberOfDisplays=*/ 1,
                isExternalDisplayUsedForAudio);
    }

    @Test
    public void testOnDisplayDisabled(
            @TestParameter final boolean isExternalDisplayUsedForAudio) {
        mExternalDisplayStatsService.onDisplayConnected(mMockedLogicalDisplay);
        mHandler.flush();
        initAudioPlayback(isExternalDisplayUsedForAudio);
        mExternalDisplayStatsService.onDisplayAdded(EXTERNAL_DISPLAY_ID);
        mExternalDisplayStatsService.onDisplayContentModeChange(EXTERNAL_DISPLAY_ID);
        clearInvocations(mMockedInjector);

        mExternalDisplayStatsService.onDisplayDisabled(EXTERNAL_DISPLAY_ID);
@@ -299,7 +323,7 @@ public class ExternalDisplayStatsServiceTest {
        mExternalDisplayStatsService.onDisplayConnected(mMockedLogicalDisplay);
        mHandler.flush();
        initAudioPlayback(isExternalDisplayUsedForAudio);
        mExternalDisplayStatsService.onDisplayAdded(EXTERNAL_DISPLAY_ID);
        mExternalDisplayStatsService.onDisplayContentModeChange(EXTERNAL_DISPLAY_ID);
        clearInvocations(mMockedInjector);

        mExternalDisplayStatsService.onPresentationWindowAdded(EXTERNAL_DISPLAY_ID);