Merge changes Ia815d9d8,I30ce0527 into main
* changes:
Interrupt temporarily engaged timer while priority session is active
Extend user-engaged timeout to STOPPED, NONE, ERROR states
diff --git a/services/core/java/com/android/server/media/MediaSession2Record.java b/services/core/java/com/android/server/media/MediaSession2Record.java
index 89555a9..c8a8799 100644
--- a/services/core/java/com/android/server/media/MediaSession2Record.java
+++ b/services/core/java/com/android/server/media/MediaSession2Record.java
@@ -161,6 +161,11 @@
}
@Override
+ public void onGlobalPrioritySessionActiveChanged(boolean isGlobalPrioritySessionActive) {
+ // NA as MediaSession2 doesn't support UserEngagementStates for FGS.
+ }
+
+ @Override
public boolean sendMediaButton(String packageName, int pid, int uid, boolean asSystemService,
KeyEvent ke, int sequenceId, ResultReceiver cb) {
// TODO(jaewan): Implement.
diff --git a/services/core/java/com/android/server/media/MediaSessionRecord.java b/services/core/java/com/android/server/media/MediaSessionRecord.java
index 0a9109b..0d779af 100644
--- a/services/core/java/com/android/server/media/MediaSessionRecord.java
+++ b/services/core/java/com/android/server/media/MediaSessionRecord.java
@@ -234,51 +234,49 @@
private final Runnable mUserEngagementTimeoutExpirationRunnable =
() -> {
synchronized (mLock) {
- updateUserEngagedStateIfNeededLocked(/* isTimeoutExpired= */ true);
+ updateUserEngagedStateIfNeededLocked(
+ /* isTimeoutExpired= */ true,
+ /* isGlobalPrioritySessionActive= */ false);
}
};
@GuardedBy("mLock")
private @UserEngagementState int mUserEngagementState = USER_DISENGAGED;
- @IntDef({USER_PERMANENTLY_ENGAGED, USER_TEMPORARY_ENGAGED, USER_DISENGAGED})
+ @IntDef({USER_PERMANENTLY_ENGAGED, USER_TEMPORARILY_ENGAGED, USER_DISENGAGED})
@Retention(RetentionPolicy.SOURCE)
private @interface UserEngagementState {}
/**
- * Indicates that the session is active and in one of the user engaged states.
+ * Indicates that the session is {@linkplain MediaSession#isActive() active} and in one of the
+ * {@linkplain PlaybackState#isActive() active states}.
*
* @see #updateUserEngagedStateIfNeededLocked(boolean)
*/
private static final int USER_PERMANENTLY_ENGAGED = 0;
/**
- * Indicates that the session is active and in {@link PlaybackState#STATE_PAUSED} state.
+ * Indicates that the session is {@linkplain MediaSession#isActive() active} and has recently
+ * switched to one of the {@linkplain PlaybackState#isActive() inactive states}.
*
* @see #updateUserEngagedStateIfNeededLocked(boolean)
*/
- private static final int USER_TEMPORARY_ENGAGED = 1;
+ private static final int USER_TEMPORARILY_ENGAGED = 1;
/**
- * Indicates that the session is either not active or in one of the user disengaged states
+ * Indicates that the session is either not {@linkplain MediaSession#isActive() active} or in
+ * one of the {@linkplain PlaybackState#isActive() inactive states}.
*
* @see #updateUserEngagedStateIfNeededLocked(boolean)
*/
private static final int USER_DISENGAGED = 2;
/**
- * Indicates the duration of the temporary engaged states, in milliseconds.
+ * Indicates the duration of the temporary engaged state, in milliseconds.
*
- * <p>Some {@link MediaSession} states like {@link PlaybackState#STATE_PAUSED} are temporarily
- * engaged, meaning the corresponding session is only considered in an engaged state for the
- * duration of this timeout, and only if coming from an engaged state.
- *
- * <p>For example, if a session is transitioning from a user-engaged state {@link
- * PlaybackState#STATE_PLAYING} to a temporary user-engaged state {@link
- * PlaybackState#STATE_PAUSED}, then the session will be considered in a user-engaged state for
- * the duration of this timeout, starting at the transition instant. However, a temporary
- * user-engaged state is not considered user-engaged when transitioning from a non-user engaged
- * state {@link PlaybackState#STATE_STOPPED}.
+ * <p>When switching to an {@linkplain PlaybackState#isActive() inactive state}, the user is
+ * treated as temporarily engaged, meaning the corresponding session is only considered in an
+ * engaged state for the duration of this timeout, and only if coming from an engaged state.
*/
private static final int TEMP_USER_ENGAGED_TIMEOUT_MS = 600000;
@@ -604,7 +602,8 @@
mSessionCb.mCb.asBinder().unlinkToDeath(this, 0);
mDestroyed = true;
mPlaybackState = null;
- updateUserEngagedStateIfNeededLocked(/* isTimeoutExpired= */ true);
+ updateUserEngagedStateIfNeededLocked(
+ /* isTimeoutExpired= */ true, /* isGlobalPrioritySessionActive= */ false);
mHandler.post(MessageHandler.MSG_DESTROYED);
}
}
@@ -621,6 +620,24 @@
mHandler.post(mUserEngagementTimeoutExpirationRunnable);
}
+ @Override
+ public void onGlobalPrioritySessionActiveChanged(boolean isGlobalPrioritySessionActive) {
+ mHandler.post(
+ () -> {
+ synchronized (mLock) {
+ if (isGlobalPrioritySessionActive) {
+ mHandler.removeCallbacks(mUserEngagementTimeoutExpirationRunnable);
+ } else {
+ if (mUserEngagementState == USER_TEMPORARILY_ENGAGED) {
+ mHandler.postDelayed(
+ mUserEngagementTimeoutExpirationRunnable,
+ TEMP_USER_ENGAGED_TIMEOUT_MS);
+ }
+ }
+ }
+ });
+ }
+
/**
* Sends media button.
*
@@ -1111,21 +1128,20 @@
}
@GuardedBy("mLock")
- private void updateUserEngagedStateIfNeededLocked(boolean isTimeoutExpired) {
+ private void updateUserEngagedStateIfNeededLocked(
+ boolean isTimeoutExpired, boolean isGlobalPrioritySessionActive) {
if (!Flags.enableNotifyingActivityManagerWithMediaSessionStatusChange()) {
return;
}
int oldUserEngagedState = mUserEngagementState;
int newUserEngagedState;
- if (!isActive() || mPlaybackState == null || mDestroyed) {
+ if (!isActive() || mPlaybackState == null) {
newUserEngagedState = USER_DISENGAGED;
- } else if (isActive() && mPlaybackState.isActive()) {
+ } else if (mPlaybackState.isActive()) {
newUserEngagedState = USER_PERMANENTLY_ENGAGED;
- } else if (mPlaybackState.getState() == PlaybackState.STATE_PAUSED) {
- newUserEngagedState =
- oldUserEngagedState == USER_PERMANENTLY_ENGAGED || !isTimeoutExpired
- ? USER_TEMPORARY_ENGAGED
- : USER_DISENGAGED;
+ } else if (oldUserEngagedState == USER_PERMANENTLY_ENGAGED
+ || (oldUserEngagedState == USER_TEMPORARILY_ENGAGED && !isTimeoutExpired)) {
+ newUserEngagedState = USER_TEMPORARILY_ENGAGED;
} else {
newUserEngagedState = USER_DISENGAGED;
}
@@ -1134,7 +1150,7 @@
}
mUserEngagementState = newUserEngagedState;
- if (newUserEngagedState == USER_TEMPORARY_ENGAGED) {
+ if (newUserEngagedState == USER_TEMPORARILY_ENGAGED && !isGlobalPrioritySessionActive) {
mHandler.postDelayed(
mUserEngagementTimeoutExpirationRunnable, TEMP_USER_ENGAGED_TIMEOUT_MS);
} else {
@@ -1189,9 +1205,11 @@
.logFgsApiEnd(ActivityManager.FOREGROUND_SERVICE_API_TYPE_MEDIA_PLAYBACK,
callingUid, callingPid);
}
+ boolean isGlobalPrioritySessionActive = mService.isGlobalPrioritySessionActive();
synchronized (mLock) {
mIsActive = active;
- updateUserEngagedStateIfNeededLocked(/* isTimeoutExpired= */ false);
+ updateUserEngagedStateIfNeededLocked(
+ /* isTimeoutExpired= */ false, isGlobalPrioritySessionActive);
}
long token = Binder.clearCallingIdentity();
try {
@@ -1348,9 +1366,11 @@
boolean shouldUpdatePriority = ALWAYS_PRIORITY_STATES.contains(newState)
|| (!TRANSITION_PRIORITY_STATES.contains(oldState)
&& TRANSITION_PRIORITY_STATES.contains(newState));
+ boolean isGlobalPrioritySessionActive = mService.isGlobalPrioritySessionActive();
synchronized (mLock) {
mPlaybackState = state;
- updateUserEngagedStateIfNeededLocked(/* isTimeoutExpired= */ false);
+ updateUserEngagedStateIfNeededLocked(
+ /* isTimeoutExpired= */ false, isGlobalPrioritySessionActive);
}
final long token = Binder.clearCallingIdentity();
try {
diff --git a/services/core/java/com/android/server/media/MediaSessionRecordImpl.java b/services/core/java/com/android/server/media/MediaSessionRecordImpl.java
index 15f90d4..6c3b123 100644
--- a/services/core/java/com/android/server/media/MediaSessionRecordImpl.java
+++ b/services/core/java/com/android/server/media/MediaSessionRecordImpl.java
@@ -206,6 +206,10 @@
*/
public abstract void expireTempEngaged();
+ /** Notifies record that the global priority session active state changed. */
+ public abstract void onGlobalPrioritySessionActiveChanged(
+ boolean isGlobalPrioritySessionActive);
+
@Override
public final boolean equals(Object o) {
if (this == o) return true;
diff --git a/services/core/java/com/android/server/media/MediaSessionService.java b/services/core/java/com/android/server/media/MediaSessionService.java
index 1ebc856..2b29fbd 100644
--- a/services/core/java/com/android/server/media/MediaSessionService.java
+++ b/services/core/java/com/android/server/media/MediaSessionService.java
@@ -362,6 +362,7 @@
+ record.isActive());
}
user.pushAddressedPlayerChangedLocked();
+ mHandler.post(this::notifyGlobalPrioritySessionActiveChanged);
} else {
if (!user.mPriorityStack.contains(record)) {
Log.w(TAG, "Unknown session updated. Ignoring.");
@@ -394,11 +395,16 @@
// Currently only media1 can become global priority session.
void setGlobalPrioritySession(MediaSessionRecord record) {
+ boolean globalPrioritySessionActiveChanged = false;
synchronized (mLock) {
FullUserRecord user = getFullUserRecordLocked(record.getUserId());
if (mGlobalPrioritySession != record) {
Log.d(TAG, "Global priority session is changed from " + mGlobalPrioritySession
+ " to " + record);
+ globalPrioritySessionActiveChanged =
+ (mGlobalPrioritySession == null && record.isActive())
+ || (mGlobalPrioritySession != null
+ && mGlobalPrioritySession.isActive() != record.isActive());
mGlobalPrioritySession = record;
if (user != null && user.mPriorityStack.contains(record)) {
// Handle the global priority session separately.
@@ -409,6 +415,30 @@
}
}
}
+ if (globalPrioritySessionActiveChanged) {
+ mHandler.post(this::notifyGlobalPrioritySessionActiveChanged);
+ }
+ }
+
+ /** Returns whether the global priority session is active. */
+ boolean isGlobalPrioritySessionActive() {
+ synchronized (mLock) {
+ return isGlobalPriorityActiveLocked();
+ }
+ }
+
+ private void notifyGlobalPrioritySessionActiveChanged() {
+ if (!Flags.enableNotifyingActivityManagerWithMediaSessionStatusChange()) {
+ return;
+ }
+ synchronized (mLock) {
+ boolean isGlobalPriorityActive = isGlobalPriorityActiveLocked();
+ for (Set<MediaSessionRecordImpl> records : mUserEngagedSessionsForFgs.values()) {
+ for (MediaSessionRecordImpl record : records) {
+ record.onGlobalPrioritySessionActiveChanged(isGlobalPriorityActive);
+ }
+ }
+ }
}
private List<MediaSessionRecord> getActiveSessionsLocked(int userId) {
@@ -646,8 +676,11 @@
if (mGlobalPrioritySession == session) {
mGlobalPrioritySession = null;
- if (session.isActive() && user != null) {
- user.pushAddressedPlayerChangedLocked();
+ if (session.isActive()) {
+ if (user != null) {
+ user.pushAddressedPlayerChangedLocked();
+ }
+ mHandler.post(this::notifyGlobalPrioritySessionActiveChanged);
}
} else {
if (user != null) {