diff options
5 files changed, 114 insertions, 18 deletions
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecAtomWriter.java b/services/core/java/com/android/server/hdmi/HdmiCecAtomWriter.java index 2e66fbc16496..102de73374b7 100644 --- a/services/core/java/com/android/server/hdmi/HdmiCecAtomWriter.java +++ b/services/core/java/com/android/server/hdmi/HdmiCecAtomWriter.java @@ -265,6 +265,26 @@ public class HdmiCecAtomWriter { enumLogReason); } + /** + * Writes a HdmiPowerStateChangeOnActiveSourceLostToggled atom representing a + * HdmiControlManager.CEC_SETTING_NAME_POWER_STATE_CHANGE_ON_ACTIVE_SOURCE_LOST setting change. + * @param isEnabled Whether the setting is enabled. + * @param enumLogReason The event that triggered the log. + * @param manufacturerPnpId Manufacturer PNP ID reported in the EDID. + * @param manufacturerYear Manufacture year reported in the EDID. + * @param manufacturerWeek Manufacture week reporter in the EDID. + */ + public void powerStateChangeOnActiveSourceLostChanged(boolean isEnabled, int enumLogReason, + String manufacturerPnpId, int manufacturerYear, int manufacturerWeek) { + FrameworkStatsLog.write( + FrameworkStatsLog.HDMI_POWER_STATE_CHANGE_ON_ACTIVE_SOURCE_LOST_TOGGLED, + isEnabled, + enumLogReason, + manufacturerPnpId, + manufacturerYear, + manufacturerWeek); + } + private int earcStateToEnum(int earcState) { switch (earcState) { case HDMI_EARC_STATUS_IDLE: diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java index 1b527daafd24..0b667fc10880 100644 --- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java +++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java @@ -21,6 +21,7 @@ import android.content.ActivityNotFoundException; import android.content.ComponentName; import android.content.Context; import android.content.Intent; +import android.hardware.display.DeviceProductInfo; import android.hardware.hdmi.HdmiControlManager; import android.hardware.hdmi.HdmiDeviceInfo; import android.hardware.hdmi.IHdmiControlCallback; @@ -31,6 +32,7 @@ import android.os.PowerManager; import android.os.SystemProperties; import android.sysprop.HdmiProperties; import android.util.Slog; +import android.view.Display; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.app.LocalePicker; @@ -82,6 +84,8 @@ public class HdmiCecLocalDevicePlayback extends HdmiCecLocalDeviceSource { // lost. private Handler mDelayedPopupOnActiveSourceLostHandler; + private boolean mIsActiveSourceLostPopupLaunched; + // Determines what action should be taken upon receiving Routing Control messages. @VisibleForTesting protected HdmiProperties.playback_device_action_on_routing_control_values @@ -96,6 +100,7 @@ public class HdmiCecLocalDevicePlayback extends HdmiCecLocalDeviceSource { mDelayedStandbyOnActiveSourceLostHandler = new Handler(service.getServiceLooper()); mDelayedPopupOnActiveSourceLostHandler = new Handler(service.getServiceLooper()); mStandbyHandler = new HdmiCecStandbyModeHandler(service, this); + mIsActiveSourceLostPopupLaunched = false; } @Override @@ -275,6 +280,7 @@ public class HdmiCecLocalDevicePlayback extends HdmiCecLocalDeviceSource { public void run() { if (!isActiveSource()) { mService.standby(); + mIsActiveSourceLostPopupLaunched = false; } } } @@ -283,6 +289,7 @@ public class HdmiCecLocalDevicePlayback extends HdmiCecLocalDeviceSource { void dismissUiOnActiveSourceStatusRecovered() { assertRunOnServiceThread(); Intent intent = new Intent(HdmiControlManager.ACTION_ON_ACTIVE_SOURCE_RECOVERED_DISMISS_UI); + mIsActiveSourceLostPopupLaunched = false; mService.sendBroadcastAsUser(intent); } @@ -516,6 +523,7 @@ public class HdmiCecLocalDevicePlayback extends HdmiCecLocalDeviceSource { ))); intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); context.startActivityAsUser(intent, context.getUser()); + mIsActiveSourceLostPopupLaunched = true; } catch (ActivityNotFoundException e) { Slog.e(TAG, "Unable to start HdmiCecActiveSourceLostActivity"); } finally { @@ -733,6 +741,14 @@ public class HdmiCecLocalDevicePlayback extends HdmiCecLocalDeviceSource { return Constants.ADDR_TV; } + boolean isActiveSourceLostPopupLaunched() { + return mIsActiveSourceLostPopupLaunched; + } + + void setIsActiveSourceLostPopupLaunched(boolean isActiveSourceLostPopupLaunched) { + mIsActiveSourceLostPopupLaunched = isActiveSourceLostPopupLaunched; + } + @Override @ServiceThreadOnly protected void disableDevice(boolean initiatedByCec, PendingActionClearedCallback callback) { diff --git a/services/core/java/com/android/server/hdmi/HdmiControlService.java b/services/core/java/com/android/server/hdmi/HdmiControlService.java index f049ef316cb1..35ef18b144e7 100644 --- a/services/core/java/com/android/server/hdmi/HdmiControlService.java +++ b/services/core/java/com/android/server/hdmi/HdmiControlService.java @@ -50,6 +50,7 @@ import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.database.ContentObserver; +import android.hardware.display.DeviceProductInfo; import android.hardware.display.DisplayManager; import android.hardware.hdmi.DeviceFeatures; import android.hardware.hdmi.HdmiControlManager; @@ -106,6 +107,7 @@ import android.util.Slog; import android.util.SparseArray; import android.view.Display; import android.view.KeyEvent; +import android.view.WindowManager; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; @@ -1007,6 +1009,21 @@ public class HdmiControlService extends SystemService { } }, mServiceThreadExecutor); + if (isPlaybackDevice()) { + mHdmiCecConfig.registerChangeListener( + HdmiControlManager.CEC_SETTING_NAME_POWER_STATE_CHANGE_ON_ACTIVE_SOURCE_LOST, + new HdmiCecConfig.SettingChangeListener() { + @Override + public void onChange(String setting) { + boolean goToStandbyOnActiveSourceLost = + mHdmiCecConfig.getStringValue( + HdmiControlManager.CEC_SETTING_NAME_POWER_STATE_CHANGE_ON_ACTIVE_SOURCE_LOST) + .equals(HdmiControlManager.POWER_STATE_CHANGE_ON_ACTIVE_SOURCE_LOST_STANDBY_NOW); + writePowerStateChangeOnActiveSourceLostAtom(goToStandbyOnActiveSourceLost); + } + }, mServiceThreadExecutor); + } + mDeviceConfig.addOnPropertiesChangedListener(getContext().getMainExecutor(), new DeviceConfig.OnPropertiesChangedListener() { @Override @@ -3189,6 +3206,7 @@ public class HdmiControlService extends SystemService { // Cancel an existing timer to send the device to sleep since OTP was triggered. playback().mDelayedStandbyOnActiveSourceLostHandler .removeCallbacksAndMessages(null); + playback().setIsActiveSourceLostPopupLaunched(false); } if (source == null) { @@ -5227,6 +5245,34 @@ public class HdmiControlService extends SystemService { } /** + * Writes a HdmiPowerStateChangeOnActiveSourceLostToggled atom representing a + * HdmiControlManager.CEC_SETTING_NAME_POWER_STATE_CHANGE_ON_ACTIVE_SOURCE_LOST setting change. + */ + protected void writePowerStateChangeOnActiveSourceLostAtom(boolean isSettingEnabled) { + String manufacturerPnpId = "undefined"; + int manufactureYear = -1; + int manufactureWeek = -1; + Display display = getContext().getDisplay(); + if (display != null) { + DeviceProductInfo deviceProductInfo = display.getDeviceProductInfo(); + manufacturerPnpId = deviceProductInfo.getManufacturerPnpId(); + manufactureYear = deviceProductInfo.getManufactureYear(); + } + int enumLogReason = + HdmiStatsEnums.LOG_REASON_POWER_STATE_CHANGE_ON_ACTIVE_SOURCE_LOST_TOGGLE_UNKNOWN; + if (playback() != null) { + if (playback().isActiveSourceLostPopupLaunched()) { + enumLogReason = HdmiStatsEnums.LOG_REASON_POWER_STATE_CHANGE_ON_ACTIVE_SOURCE_LOST_TOGGLE_POP_UP; + } else { + enumLogReason = HdmiStatsEnums.LOG_REASON_POWER_STATE_CHANGE_ON_ACTIVE_SOURCE_LOST_TOGGLE_SETTING; + } + } + + getAtomWriter().powerStateChangeOnActiveSourceLostChanged(isSettingEnabled, enumLogReason, + manufacturerPnpId, manufactureYear, manufactureWeek); + } + + /** * Reads the property that checks if CEC was enabled by the user while in offline mode such that * it won't be disabled when going to sleep by low energy mode. */ diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecAtomLoggingTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecAtomLoggingTest.java index dd4101e9796f..30dac9f3813d 100644 --- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecAtomLoggingTest.java +++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecAtomLoggingTest.java @@ -433,4 +433,21 @@ public class HdmiCecAtomLoggingTest { .dsmStatusChanged(anyBoolean(), anyBoolean(), eq(HdmiStatsEnums.LOG_REASON_DSM_SETTING_TOGGLED)); } + + @Test + public void testPowerStateChangeOnActiveSourceLostToggled_writesAtom_logReasonSetting() { + mHdmiControlServiceSpy.onWakeUp(WAKE_UP_SCREEN_ON); + Mockito.clearInvocations(mHdmiCecAtomWriterSpy); + mTestLooper.dispatchAll(); + + mHdmiControlServiceSpy.writePowerStateChangeOnActiveSourceLostAtom(true); + mTestLooper.dispatchAll(); + + verify(mHdmiCecAtomWriterSpy, times(1)) + .powerStateChangeOnActiveSourceLostChanged(eq(true), + eq(HdmiStatsEnums.LOG_REASON_POWER_STATE_CHANGE_ON_ACTIVE_SOURCE_LOST_TOGGLE_SETTING), anyString(), anyInt(), anyInt()); + verify(mHdmiCecAtomWriterSpy, never()) + .powerStateChangeOnActiveSourceLostChanged(eq(true), + eq(HdmiStatsEnums.LOG_REASON_POWER_STATE_CHANGE_ON_ACTIVE_SOURCE_LOST_TOGGLE_POP_UP), anyString(), anyInt(), anyInt()); + } } diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDevicePlaybackTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDevicePlaybackTest.java index 077bb03c8359..861e72d4ac79 100644 --- a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDevicePlaybackTest.java +++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDevicePlaybackTest.java @@ -95,9 +95,6 @@ public class HdmiCecLocalDevicePlaybackTest { private boolean mActiveMediaSessionsPaused; private FakePowerManagerInternalWrapper mPowerManagerInternal = new FakePowerManagerInternalWrapper(); - - private boolean mIsOnActiveSourceLostPopupActive; - @Before public void setUp() { MockitoAnnotations.initMocks(this); @@ -165,12 +162,12 @@ public class HdmiCecLocalDevicePlaybackTest { mHdmiCecLocalDevicePlayback = new HdmiCecLocalDevicePlayback(mHdmiControlService) { @Override void startHdmiCecActiveSourceLostActivity() { - mIsOnActiveSourceLostPopupActive = true; + setIsActiveSourceLostPopupLaunched(true); } @Override void dismissUiOnActiveSourceStatusRecovered() { - mIsOnActiveSourceLostPopupActive = false; + setIsActiveSourceLostPopupLaunched(false); } }; mHdmiCecLocalDevicePlayback.init(); @@ -2389,7 +2386,7 @@ public class HdmiCecLocalDevicePlaybackTest { mTestLooper.dispatchAll(); assertThat(mHdmiCecLocalDevicePlayback.getActiveSource().logicalAddress).isEqualTo(ADDR_TV); - assertThat(mIsOnActiveSourceLostPopupActive).isTrue(); + assertThat(mHdmiCecLocalDevicePlayback.isActiveSourceLostPopupLaunched()).isTrue(); } @Test @@ -2430,7 +2427,7 @@ public class HdmiCecLocalDevicePlaybackTest { // Pop-up is not shown, playback device asserts active source since TV doesn't answer the // request. - assertThat(mIsOnActiveSourceLostPopupActive).isFalse(); + assertThat(mHdmiCecLocalDevicePlayback.isActiveSourceLostPopupLaunched()).isFalse(); assertThat(mNativeWrapper.getResultMessages().contains(activeSourceFromPlayback)).isTrue(); assertThat(mHdmiCecLocalDevicePlayback.getActiveSource().logicalAddress) .isEqualTo(mPlaybackLogicalAddress); @@ -2480,7 +2477,7 @@ public class HdmiCecLocalDevicePlaybackTest { mTestLooper.dispatchAll(); // Pop-up is not shown since playback device is active source. - assertThat(mIsOnActiveSourceLostPopupActive).isFalse(); + assertThat(mHdmiCecLocalDevicePlayback.isActiveSourceLostPopupLaunched()).isFalse(); assertThat(mNativeWrapper.getResultMessages().contains(activeSourceFromPlayback)).isTrue(); assertThat(mHdmiCecLocalDevicePlayback.getActiveSource().logicalAddress) .isEqualTo(mPlaybackLogicalAddress); @@ -2532,7 +2529,7 @@ public class HdmiCecLocalDevicePlaybackTest { // Pop-up is shown, playback device doesn't assert active source since active path is // switched to a non-CEC device. - assertThat(mIsOnActiveSourceLostPopupActive).isTrue(); + assertThat(mHdmiCecLocalDevicePlayback.isActiveSourceLostPopupLaunched()).isTrue(); assertThat(mHdmiCecLocalDevicePlayback.getActiveSource().logicalAddress) .isEqualTo(ADDR_INVALID); assertThat(mHdmiCecLocalDevicePlayback.getActiveSource().physicalAddress) @@ -2569,7 +2566,7 @@ public class HdmiCecLocalDevicePlaybackTest { }); mTestLooper.dispatchAll(); - assertThat(mIsOnActiveSourceLostPopupActive).isFalse(); + assertThat(mHdmiCecLocalDevicePlayback.isActiveSourceLostPopupLaunched()).isFalse(); assertThat(mPowerManager.isInteractive()).isTrue(); assertThat(mNativeWrapper.getResultMessages().contains(activeSourceFromPlayback)).isTrue(); assertThat(mHdmiCecLocalDevicePlayback.getActiveSource().logicalAddress) @@ -2609,13 +2606,13 @@ public class HdmiCecLocalDevicePlaybackTest { mNativeWrapper.onCecMessage(activeSourceFromTv); mTestLooper.dispatchAll(); - assertThat(mIsOnActiveSourceLostPopupActive).isTrue(); + assertThat(mHdmiCecLocalDevicePlayback.isActiveSourceLostPopupLaunched()).isTrue(); assertThat(mHdmiCecLocalDevicePlayback.handleSetStreamPath(setStreamPathToPlayback)) .isEqualTo(Constants.HANDLED); mTestLooper.dispatchAll(); - assertThat(mIsOnActiveSourceLostPopupActive).isFalse(); + assertThat(mHdmiCecLocalDevicePlayback.isActiveSourceLostPopupLaunched()).isFalse(); assertThat(mNativeWrapper.getResultMessages().contains(activeSourceFromPlayback)).isTrue(); assertThat(mHdmiCecLocalDevicePlayback.getActiveSource().logicalAddress) .isEqualTo(mPlaybackLogicalAddress); @@ -2664,13 +2661,13 @@ public class HdmiCecLocalDevicePlaybackTest { // Pop-up is triggered. mTestLooper.moveTimeForward(POPUP_AFTER_ACTIVE_SOURCE_LOST_DELAY_MS); mTestLooper.dispatchAll(); - assertThat(mIsOnActiveSourceLostPopupActive).isTrue(); + assertThat(mHdmiCecLocalDevicePlayback.isActiveSourceLostPopupLaunched()).isTrue(); assertThat(mHdmiCecLocalDevicePlayback.handleRoutingChange(routingChangeToPlayback)) .isEqualTo(Constants.HANDLED); mTestLooper.dispatchAll(); - assertThat(mIsOnActiveSourceLostPopupActive).isFalse(); + assertThat(mHdmiCecLocalDevicePlayback.isActiveSourceLostPopupLaunched()).isFalse(); assertThat(mNativeWrapper.getResultMessages().contains(activeSourceFromPlayback)).isTrue(); assertThat(mHdmiCecLocalDevicePlayback.getActiveSource().logicalAddress) .isEqualTo(mPlaybackLogicalAddress); @@ -2711,7 +2708,7 @@ public class HdmiCecLocalDevicePlaybackTest { mNativeWrapper.onCecMessage(activeSourceFromTv); mTestLooper.dispatchAll(); - assertThat(mIsOnActiveSourceLostPopupActive).isTrue(); + assertThat(mHdmiCecLocalDevicePlayback.isActiveSourceLostPopupLaunched()).isTrue(); mHdmiControlService.oneTouchPlay(new IHdmiControlCallback() { @Override public void onComplete(int result) throws RemoteException { @@ -2724,7 +2721,7 @@ public class HdmiCecLocalDevicePlaybackTest { }); mTestLooper.dispatchAll(); - assertThat(mIsOnActiveSourceLostPopupActive).isFalse(); + assertThat(mHdmiCecLocalDevicePlayback.isActiveSourceLostPopupLaunched()).isFalse(); assertThat(mNativeWrapper.getResultMessages().contains(activeSourceFromPlayback)).isTrue(); assertThat(mHdmiCecLocalDevicePlayback.getActiveSource().logicalAddress) .isEqualTo(mPlaybackLogicalAddress); @@ -2897,11 +2894,11 @@ public class HdmiCecLocalDevicePlaybackTest { } else { mTestLooper.moveTimeForward(TIMEOUT_MS); mTestLooper.dispatchAll(); - assertThat(mIsOnActiveSourceLostPopupActive).isFalse(); + assertThat(mHdmiCecLocalDevicePlayback.isActiveSourceLostPopupLaunched()).isFalse(); return; } } - assertThat(mIsOnActiveSourceLostPopupActive).isTrue(); + assertThat(mHdmiCecLocalDevicePlayback.isActiveSourceLostPopupLaunched()).isTrue(); mPowerManagerInternal.setIdleDuration(idleDuration); mTestLooper.moveTimeForward(STANDBY_AFTER_ACTIVE_SOURCE_LOST_DELAY_MS); |