1 /* 2 * Copyright (C) 2013 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package androidx.mediarouter.media; 18 19 import android.app.PendingIntent; 20 import android.os.Bundle; 21 import android.os.SystemClock; 22 23 import androidx.core.util.TimeUtils; 24 25 /** 26 * Describes the playback status of a media session. 27 * <p> 28 * This class is part of the remote playback protocol described by the 29 * {@link MediaControlIntent MediaControlIntent} class. 30 * </p><p> 31 * When a media session is created, it is initially in the 32 * {@link #SESSION_STATE_ACTIVE active} state. When the media session ends 33 * normally, it transitions to the {@link #SESSION_STATE_ENDED ended} state. 34 * If the media session is invalidated due to another session forcibly taking 35 * control of the route, then it transitions to the 36 * {@link #SESSION_STATE_INVALIDATED invalidated} state. 37 * Refer to the documentation of each state for an explanation of its meaning. 38 * </p><p> 39 * To monitor session status, the application should supply a {@link PendingIntent} to use as the 40 * {@link MediaControlIntent#EXTRA_SESSION_STATUS_UPDATE_RECEIVER session status update receiver} 41 * for a given {@link MediaControlIntent#ACTION_START_SESSION session start request}. 42 * </p><p> 43 * This object is immutable once created using a {@link Builder} instance. 44 * </p> 45 */ 46 public final class MediaSessionStatus { 47 static final String KEY_TIMESTAMP = "timestamp"; 48 static final String KEY_SESSION_STATE = "sessionState"; 49 static final String KEY_QUEUE_PAUSED = "queuePaused"; 50 static final String KEY_EXTRAS = "extras"; 51 52 final Bundle mBundle; 53 54 /** 55 * Session state: Active. 56 * <p> 57 * Indicates that the media session is active and in control of the route. 58 * </p> 59 */ 60 public static final int SESSION_STATE_ACTIVE = 0; 61 62 /** 63 * Session state: Ended. 64 * <p> 65 * Indicates that the media session was ended normally using the 66 * {@link MediaControlIntent#ACTION_END_SESSION end session} action. 67 * </p><p> 68 * A terminated media session cannot be used anymore. To play more media, the 69 * application must start a new session. 70 * </p> 71 */ 72 public static final int SESSION_STATE_ENDED = 1; 73 74 /** 75 * Session state: Invalidated. 76 * <p> 77 * Indicates that the media session was invalidated involuntarily due to 78 * another session taking control of the route. 79 * </p><p> 80 * An invalidated media session cannot be used anymore. To play more media, the 81 * application must start a new session. 82 * </p> 83 */ 84 public static final int SESSION_STATE_INVALIDATED = 2; 85 MediaSessionStatus(Bundle bundle)86 MediaSessionStatus(Bundle bundle) { 87 mBundle = bundle; 88 } 89 90 /** 91 * Gets the timestamp associated with the status information in 92 * milliseconds since boot in the {@link SystemClock#elapsedRealtime} time base. 93 * 94 * @return The status timestamp in the {@link SystemClock#elapsedRealtime()} time base. 95 */ getTimestamp()96 public long getTimestamp() { 97 return mBundle.getLong(KEY_TIMESTAMP); 98 } 99 100 /** 101 * Gets the session state. 102 * 103 * @return The session state. One of {@link #SESSION_STATE_ACTIVE}, 104 * {@link #SESSION_STATE_ENDED}, or {@link #SESSION_STATE_INVALIDATED}. 105 */ getSessionState()106 public int getSessionState() { 107 return mBundle.getInt(KEY_SESSION_STATE, SESSION_STATE_INVALIDATED); 108 } 109 110 /** 111 * Returns true if the session's queue is paused. 112 * 113 * @return True if the session's queue is paused. 114 */ isQueuePaused()115 public boolean isQueuePaused() { 116 return mBundle.getBoolean(KEY_QUEUE_PAUSED); 117 } 118 119 /** 120 * Gets a bundle of extras for this status object. 121 * The extras will be ignored by the media router but they may be used 122 * by applications. 123 */ getExtras()124 public Bundle getExtras() { 125 return mBundle.getBundle(KEY_EXTRAS); 126 } 127 128 @Override toString()129 public String toString() { 130 StringBuilder result = new StringBuilder(); 131 result.append("MediaSessionStatus{ "); 132 result.append("timestamp="); 133 TimeUtils.formatDuration(SystemClock.elapsedRealtime() - getTimestamp(), result); 134 result.append(" ms ago"); 135 result.append(", sessionState=").append(sessionStateToString(getSessionState())); 136 result.append(", queuePaused=").append(isQueuePaused()); 137 result.append(", extras=").append(getExtras()); 138 result.append(" }"); 139 return result.toString(); 140 } 141 sessionStateToString(int sessionState)142 private static String sessionStateToString(int sessionState) { 143 switch (sessionState) { 144 case SESSION_STATE_ACTIVE: 145 return "active"; 146 case SESSION_STATE_ENDED: 147 return "ended"; 148 case SESSION_STATE_INVALIDATED: 149 return "invalidated"; 150 } 151 return Integer.toString(sessionState); 152 } 153 154 /** 155 * Converts this object to a bundle for serialization. 156 * 157 * @return The contents of the object represented as a bundle. 158 */ asBundle()159 public Bundle asBundle() { 160 return mBundle; 161 } 162 163 /** 164 * Creates an instance from a bundle. 165 * 166 * @param bundle The bundle, or null if none. 167 * @return The new instance, or null if the bundle was null. 168 */ fromBundle(Bundle bundle)169 public static MediaSessionStatus fromBundle(Bundle bundle) { 170 return bundle != null ? new MediaSessionStatus(bundle) : null; 171 } 172 173 /** 174 * Builder for {@link MediaSessionStatus media session status objects}. 175 */ 176 public static final class Builder { 177 private final Bundle mBundle; 178 179 /** 180 * Creates a media session status builder using the current time as the 181 * reference timestamp. 182 * 183 * @param sessionState The session state. 184 */ Builder(int sessionState)185 public Builder(int sessionState) { 186 mBundle = new Bundle(); 187 setTimestamp(SystemClock.elapsedRealtime()); 188 setSessionState(sessionState); 189 } 190 191 /** 192 * Creates a media session status builder whose initial contents are 193 * copied from an existing status. 194 */ Builder(MediaSessionStatus status)195 public Builder(MediaSessionStatus status) { 196 if (status == null) { 197 throw new IllegalArgumentException("status must not be null"); 198 } 199 200 mBundle = new Bundle(status.mBundle); 201 } 202 203 /** 204 * Sets the timestamp associated with the status information in 205 * milliseconds since boot in the {@link SystemClock#elapsedRealtime} time base. 206 */ setTimestamp(long elapsedRealtimeTimestamp)207 public Builder setTimestamp(long elapsedRealtimeTimestamp) { 208 mBundle.putLong(KEY_TIMESTAMP, elapsedRealtimeTimestamp); 209 return this; 210 } 211 212 /** 213 * Sets the session state. 214 */ setSessionState(int sessionState)215 public Builder setSessionState(int sessionState) { 216 mBundle.putInt(KEY_SESSION_STATE, sessionState); 217 return this; 218 } 219 220 /** 221 * Sets whether the queue is paused. 222 */ setQueuePaused(boolean queuePaused)223 public Builder setQueuePaused(boolean queuePaused) { 224 mBundle.putBoolean(KEY_QUEUE_PAUSED, queuePaused); 225 return this; 226 } 227 228 /** 229 * Sets a bundle of extras for this status object. 230 * The extras will be ignored by the media router but they may be used 231 * by applications. 232 */ setExtras(Bundle extras)233 public Builder setExtras(Bundle extras) { 234 mBundle.putBundle(KEY_EXTRAS, extras); 235 return this; 236 } 237 238 /** 239 * Builds the {@link MediaSessionStatus media session status object}. 240 */ build()241 public MediaSessionStatus build() { 242 return new MediaSessionStatus(mBundle); 243 } 244 } 245 } 246