diff --git a/media/java/android/media/metrics/IPlaybackMetricsManager.aidl b/media/java/android/media/metrics/IPlaybackMetricsManager.aidl index a1b13ba31bef4..52d952c5066dd 100644 --- a/media/java/android/media/metrics/IPlaybackMetricsManager.aidl +++ b/media/java/android/media/metrics/IPlaybackMetricsManager.aidl @@ -19,6 +19,7 @@ package android.media.metrics; import android.media.metrics.NetworkEvent; import android.media.metrics.PlaybackErrorEvent; import android.media.metrics.PlaybackMetrics; +import android.media.metrics.PlaybackStateEvent; /** * Interface to the playback manager service. @@ -27,6 +28,7 @@ import android.media.metrics.PlaybackMetrics; interface IPlaybackMetricsManager { void reportPlaybackMetrics(in String sessionId, in PlaybackMetrics metrics, int userId); String getSessionId(int userId); - void reportPlaybackErrorEvent(in String sessionId, in PlaybackErrorEvent event, int userId); void reportNetworkEvent(in String sessionId, in NetworkEvent event, int userId); + void reportPlaybackErrorEvent(in String sessionId, in PlaybackErrorEvent event, int userId); + void reportPlaybackStateEvent(in String sessionId, in PlaybackStateEvent event, int userId); } \ No newline at end of file diff --git a/media/java/android/media/metrics/PlaybackMetricsManager.java b/media/java/android/media/metrics/PlaybackMetricsManager.java index 95f64ea9f11eb..63a50ae311346 100644 --- a/media/java/android/media/metrics/PlaybackMetricsManager.java +++ b/media/java/android/media/metrics/PlaybackMetricsManager.java @@ -60,6 +60,18 @@ public class PlaybackMetricsManager { } } + /** + * Reports playback state event. + * @hide + */ + public void reportPlaybackStateEvent(@NonNull String sessionId, PlaybackStateEvent event) { + try { + mService.reportPlaybackStateEvent(sessionId, event, mUserId); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + /** * Creates a playback session. */ diff --git a/media/java/android/media/metrics/PlaybackSession.java b/media/java/android/media/metrics/PlaybackSession.java index 3e2f4e1f4c9ac..061e66532d556 100644 --- a/media/java/android/media/metrics/PlaybackSession.java +++ b/media/java/android/media/metrics/PlaybackSession.java @@ -64,6 +64,13 @@ public final class PlaybackSession implements AutoCloseable { mManager.reportNetworkEvent(mId, event); } + /** + * Reports playback state event. + */ + public void reportPlaybackStateEvent(PlaybackStateEvent event) { + mManager.reportPlaybackStateEvent(mId, event); + } + public @NonNull String getId() { return mId; } diff --git a/media/java/android/media/metrics/PlaybackStateEvent.aidl b/media/java/android/media/metrics/PlaybackStateEvent.aidl new file mode 100644 index 0000000000000..8b8d05bd4093d --- /dev/null +++ b/media/java/android/media/metrics/PlaybackStateEvent.aidl @@ -0,0 +1,19 @@ +/* + * Copyright (C) 2020 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 android.media.metrics; + +parcelable PlaybackStateEvent; diff --git a/media/java/android/media/metrics/PlaybackStateEvent.java b/media/java/android/media/metrics/PlaybackStateEvent.java new file mode 100644 index 0000000000000..6ce5bf0f0f331 --- /dev/null +++ b/media/java/android/media/metrics/PlaybackStateEvent.java @@ -0,0 +1,153 @@ +/* + * Copyright (C) 2020 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 android.media.metrics; + +import android.annotation.IntDef; +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.os.Parcel; +import android.os.Parcelable; + +import java.lang.annotation.Retention; +import java.util.Objects; + +/** + * Playback state event. + * @hide + */ +public final class PlaybackStateEvent implements Parcelable { + // TODO: more states + /** Playback has not started (initial state) */ + public static final int STATE_NOT_STARTED = 0; + /** Playback is buffering in the background for initial playback start */ + public static final int STATE_JOINING_BACKGROUND = 1; + /** Playback is buffering in the foreground for initial playback start */ + public static final int STATE_JOINING_FOREGROUND = 2; + /** Playback is actively playing */ + public static final int STATE_PLAYING = 3; + /** Playback is paused but ready to play */ + public static final int STATE_PAUSED = 4; + + private int mState; + private long mTimeSincePlaybackCreatedMillis; + + // These track ExoPlayer states. See the ExoPlayer documentation for the state transitions. + @IntDef(prefix = "STATE_", value = { + STATE_NOT_STARTED, + STATE_JOINING_BACKGROUND, + STATE_JOINING_FOREGROUND, + STATE_PLAYING, + STATE_PAUSED + }) + @Retention(java.lang.annotation.RetentionPolicy.SOURCE) + public @interface State {} + + /** + * Converts playback state to string. + */ + public static String stateToString(@State int value) { + switch (value) { + case STATE_NOT_STARTED: + return "STATE_NOT_STARTED"; + case STATE_JOINING_BACKGROUND: + return "STATE_JOINING_BACKGROUND"; + case STATE_JOINING_FOREGROUND: + return "STATE_JOINING_FOREGROUND"; + case STATE_PLAYING: + return "STATE_PLAYING"; + case STATE_PAUSED: + return "STATE_PAUSED"; + default: + return Integer.toHexString(value); + } + } + + /** + * Creates a new PlaybackStateEvent. + * + * @hide + */ + public PlaybackStateEvent( + int state, + long timeSincePlaybackCreatedMillis) { + this.mState = state; + this.mTimeSincePlaybackCreatedMillis = timeSincePlaybackCreatedMillis; + } + + /** + * Gets playback state. + * @return + */ + public int getState() { + return mState; + } + + /** + * Gets time since the corresponding playback is created in millisecond. + */ + public long getTimeSincePlaybackCreatedMillis() { + return mTimeSincePlaybackCreatedMillis; + } + + @Override + public boolean equals(@Nullable Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + PlaybackStateEvent that = (PlaybackStateEvent) o; + return mState == that.mState + && mTimeSincePlaybackCreatedMillis == that.mTimeSincePlaybackCreatedMillis; + } + + @Override + public int hashCode() { + return Objects.hash(mState, mTimeSincePlaybackCreatedMillis); + } + + @Override + public void writeToParcel(@NonNull Parcel dest, int flags) { + dest.writeInt(mState); + dest.writeLong(mTimeSincePlaybackCreatedMillis); + } + + @Override + public int describeContents() { + return 0; + } + + /** @hide */ + /* package-private */ PlaybackStateEvent(@NonNull Parcel in) { + int state = in.readInt(); + long timeSincePlaybackCreatedMillis = in.readLong(); + + this.mState = state; + this.mTimeSincePlaybackCreatedMillis = timeSincePlaybackCreatedMillis; + } + + public static final @NonNull Parcelable.Creator CREATOR = + new Parcelable.Creator() { + @Override + public PlaybackStateEvent[] newArray(int size) { + return new PlaybackStateEvent[size]; + } + + @Override + public PlaybackStateEvent createFromParcel(@NonNull Parcel in) { + return new PlaybackStateEvent(in); + } + }; + +} diff --git a/services/core/java/com/android/server/media/metrics/PlaybackMetricsManagerService.java b/services/core/java/com/android/server/media/metrics/PlaybackMetricsManagerService.java index 765949c99133a..2a3cc907d675c 100644 --- a/services/core/java/com/android/server/media/metrics/PlaybackMetricsManagerService.java +++ b/services/core/java/com/android/server/media/metrics/PlaybackMetricsManagerService.java @@ -21,6 +21,7 @@ import android.media.metrics.IPlaybackMetricsManager; import android.media.metrics.NetworkEvent; import android.media.metrics.PlaybackErrorEvent; import android.media.metrics.PlaybackMetrics; +import android.media.metrics.PlaybackStateEvent; import android.os.Binder; import android.util.Base64; import android.util.StatsEvent; @@ -79,6 +80,12 @@ public final class PlaybackMetricsManagerService extends SystemService { StatsLog.write(statsEvent); } + @Override + public void reportPlaybackStateEvent( + String sessionId, PlaybackStateEvent event, int userId) { + // TODO: log it to statsd + } + @Override public String getSessionId(int userId) { byte[] byteId = new byte[16]; // 128 bits