135a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim/* 235a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim * Copyright 2018 The Android Open Source Project 335a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim * 435a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim * Licensed under the Apache License, Version 2.0 (the "License"); 535a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim * you may not use this file except in compliance with the License. 635a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim * You may obtain a copy of the License at 735a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim * 835a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim * http://www.apache.org/licenses/LICENSE-2.0 935a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim * 1035a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim * Unless required by applicable law or agreed to in writing, software 1135a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim * distributed under the License is distributed on an "AS IS" BASIS, 1235a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1335a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim * See the License for the specific language governing permissions and 1435a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim * limitations under the License. 1535a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim */ 1635a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim 1735a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kimpackage com.android.media; 1835a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim 19d5b878d0cf0c987caf18be697a0e1637fb632d66Jaewan Kimimport static android.media.SessionCommand2.COMMAND_CODE_SET_VOLUME; 20d5b878d0cf0c987caf18be697a0e1637fb632d66Jaewan Kimimport static android.media.SessionCommand2.COMMAND_CODE_PLAYLIST_ADD_ITEM; 21d5b878d0cf0c987caf18be697a0e1637fb632d66Jaewan Kimimport static android.media.SessionCommand2.COMMAND_CODE_PLAYLIST_REMOVE_ITEM; 22d5b878d0cf0c987caf18be697a0e1637fb632d66Jaewan Kimimport static android.media.SessionCommand2.COMMAND_CODE_PLAYLIST_REPLACE_ITEM; 23d5b878d0cf0c987caf18be697a0e1637fb632d66Jaewan Kimimport static android.media.SessionCommand2.COMMAND_CODE_PLAYLIST_SET_LIST; 24d5b878d0cf0c987caf18be697a0e1637fb632d66Jaewan Kimimport static android.media.SessionCommand2.COMMAND_CODE_PLAYLIST_SET_LIST_METADATA; 25d5b878d0cf0c987caf18be697a0e1637fb632d66Jaewan Kimimport static android.media.SessionCommand2.COMMAND_CODE_PLAYLIST_SET_REPEAT_MODE; 26d5b878d0cf0c987caf18be697a0e1637fb632d66Jaewan Kimimport static android.media.SessionCommand2.COMMAND_CODE_PLAYLIST_SET_SHUFFLE_MODE; 27d5b878d0cf0c987caf18be697a0e1637fb632d66Jaewan Kimimport static android.media.SessionCommand2.COMMAND_CODE_SESSION_PLAY_FROM_MEDIA_ID; 28d5b878d0cf0c987caf18be697a0e1637fb632d66Jaewan Kimimport static android.media.SessionCommand2.COMMAND_CODE_SESSION_PLAY_FROM_SEARCH; 29d5b878d0cf0c987caf18be697a0e1637fb632d66Jaewan Kimimport static android.media.SessionCommand2.COMMAND_CODE_SESSION_PLAY_FROM_URI; 30d5b878d0cf0c987caf18be697a0e1637fb632d66Jaewan Kimimport static android.media.SessionCommand2.COMMAND_CODE_SESSION_PREPARE_FROM_MEDIA_ID; 31d5b878d0cf0c987caf18be697a0e1637fb632d66Jaewan Kimimport static android.media.SessionCommand2.COMMAND_CODE_SESSION_PREPARE_FROM_SEARCH; 32d5b878d0cf0c987caf18be697a0e1637fb632d66Jaewan Kimimport static android.media.SessionCommand2.COMMAND_CODE_SESSION_PREPARE_FROM_URI; 33483261f98e9eeb6191d42873970a2ae9709ac1fcJaewan Kim 34da59499289a68a2558370b6acfd4096d3feb8107Jaewan Kimimport android.app.PendingIntent; 3535a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kimimport android.content.ComponentName; 3635a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kimimport android.content.Context; 3735a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kimimport android.content.Intent; 3835a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kimimport android.content.ServiceConnection; 39991a25e6fd2aa7456fa7686de0baf619ebd50c2cJaewan Kimimport android.media.AudioAttributes; 40785d2f41ea05d9372fe7e06a76c58661f9727db3Hyundo Moonimport android.media.MediaController2; 41785d2f41ea05d9372fe7e06a76c58661f9727db3Hyundo Moonimport android.media.MediaController2.ControllerCallback; 42da59499289a68a2558370b6acfd4096d3feb8107Jaewan Kimimport android.media.MediaController2.PlaybackInfo; 43da59499289a68a2558370b6acfd4096d3feb8107Jaewan Kimimport android.media.MediaItem2; 44e0a38c69b26945394936922dd837cc7e9fa37d3cJaewan Kimimport android.media.MediaMetadata2; 4544648206f6a9c66f9f9478a8091685cb702349eeJaewan Kimimport android.media.MediaPlaylistAgent.RepeatMode; 4644648206f6a9c66f9f9478a8091685cb702349eeJaewan Kimimport android.media.MediaPlaylistAgent.ShuffleMode; 47d5b878d0cf0c987caf18be697a0e1637fb632d66Jaewan Kimimport android.media.SessionCommand2; 489b67177ebfe5f46c0c6216f87f5ee98c03e5cbadJaewan Kimimport android.media.MediaSession2.CommandButton; 49d5b878d0cf0c987caf18be697a0e1637fb632d66Jaewan Kimimport android.media.SessionCommandGroup2; 5035a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kimimport android.media.MediaSessionService2; 51da59499289a68a2558370b6acfd4096d3feb8107Jaewan Kimimport android.media.Rating2; 527027e8019ad974d2e474a7fcaf43adedbdf08f23Jaewan Kimimport android.media.SessionToken2; 5335a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kimimport android.media.update.MediaController2Provider; 54da59499289a68a2558370b6acfd4096d3feb8107Jaewan Kimimport android.net.Uri; 553bad8ce270642d8780f3cd450a0c8af94788fde4Jaewan Kimimport android.os.Bundle; 5635a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kimimport android.os.IBinder; 577cda0f098a62cc0297d63f9c9dfa6b5345c7fbf9Jaewan Kimimport android.os.Process; 5835a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kimimport android.os.RemoteException; 59da59499289a68a2558370b6acfd4096d3feb8107Jaewan Kimimport android.os.ResultReceiver; 607cda0f098a62cc0297d63f9c9dfa6b5345c7fbf9Jaewan Kimimport android.os.UserHandle; 6135a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kimimport android.support.annotation.GuardedBy; 6298fdf3583d3bfd1178ef1e0102e3de6d2b1dd2bcHyundo Moonimport android.text.TextUtils; 6335a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kimimport android.util.Log; 6435a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim 6535a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kimimport java.util.ArrayList; 6635a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kimimport java.util.List; 6735a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kimimport java.util.concurrent.Executor; 6835a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim 6935a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kimpublic class MediaController2Impl implements MediaController2Provider { 7035a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim private static final String TAG = "MediaController2"; 7135a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim private static final boolean DEBUG = true; // TODO(jaewan): Change 7235a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim 7335a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim private final MediaController2 mInstance; 7478e257713ebf4805647772f32fac433d2621405eSungsoo Lim private final Context mContext; 7535a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim private final Object mLock = new Object(); 7635a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim 7798f280314350160874af3bc3fd660aa3e9a0fabeSungsoo Lim private final MediaController2Stub mControllerStub; 787027e8019ad974d2e474a7fcaf43adedbdf08f23Jaewan Kim private final SessionToken2 mToken; 7935a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim private final ControllerCallback mCallback; 8035a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim private final Executor mCallbackExecutor; 8135a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim private final IBinder.DeathRecipient mDeathRecipient; 8235a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim 8335a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim @GuardedBy("mLock") 8435a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim private SessionServiceConnection mServiceConnection; 8535a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim @GuardedBy("mLock") 8635a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim private boolean mIsReleased; 8798421b59b047196e2605ad1696e47ecca890dcf3Jaewan Kim @GuardedBy("mLock") 883923b1b71628e668f9b11ed4891ed2840dd331cdHyundo Moon private List<MediaItem2> mPlaylist; 893923b1b71628e668f9b11ed4891ed2840dd331cdHyundo Moon @GuardedBy("mLock") 90e0a38c69b26945394936922dd837cc7e9fa37d3cJaewan Kim private MediaMetadata2 mPlaylistMetadata; 91e0a38c69b26945394936922dd837cc7e9fa37d3cJaewan Kim @GuardedBy("mLock") 9244648206f6a9c66f9f9478a8091685cb702349eeJaewan Kim private @RepeatMode int mRepeatMode; 9344648206f6a9c66f9f9478a8091685cb702349eeJaewan Kim @GuardedBy("mLock") 9444648206f6a9c66f9f9478a8091685cb702349eeJaewan Kim private @ShuffleMode int mShuffleMode; 95c81e4db8363fb9736bc2362f0ff213b5d9e33ac3Hyundo Moon @GuardedBy("mLock") 9679f5e126cb9a8c6f72904d8cb4c611ee69405993Hyundo Moon private int mPlayerState; 9779f5e126cb9a8c6f72904d8cb4c611ee69405993Hyundo Moon @GuardedBy("mLock") 9879f5e126cb9a8c6f72904d8cb4c611ee69405993Hyundo Moon private long mPositionEventTimeMs; 9979f5e126cb9a8c6f72904d8cb4c611ee69405993Hyundo Moon @GuardedBy("mLock") 10079f5e126cb9a8c6f72904d8cb4c611ee69405993Hyundo Moon private long mPositionMs; 10179f5e126cb9a8c6f72904d8cb4c611ee69405993Hyundo Moon @GuardedBy("mLock") 10279f5e126cb9a8c6f72904d8cb4c611ee69405993Hyundo Moon private float mPlaybackSpeed; 10379f5e126cb9a8c6f72904d8cb4c611ee69405993Hyundo Moon @GuardedBy("mLock") 10479f5e126cb9a8c6f72904d8cb4c611ee69405993Hyundo Moon private long mBufferedPositionMs; 10579f5e126cb9a8c6f72904d8cb4c611ee69405993Hyundo Moon @GuardedBy("mLock") 106c81e4db8363fb9736bc2362f0ff213b5d9e33ac3Hyundo Moon private PlaybackInfo mPlaybackInfo; 107c4a9db19b2c4a4bf1283dd060147e17e48142beeJaewan Kim @GuardedBy("mLock") 1080261708bf17cb0469de8eb3c81455e2f48ff9433Jaewan Kim private PendingIntent mSessionActivity; 1090261708bf17cb0469de8eb3c81455e2f48ff9433Jaewan Kim @GuardedBy("mLock") 110d5b878d0cf0c987caf18be697a0e1637fb632d66Jaewan Kim private SessionCommandGroup2 mAllowedCommands; 11135a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim 11235a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim // Assignment should be used with the lock hold, but should be used without a lock to prevent 11335a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim // potential deadlock. 11435a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim // Postfix -Binder is added to explicitly show that it's potentially remote process call. 11535a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim // Technically -Interface is more correct, but it may misread that it's interface (vs class) 11635a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim // so let's keep this postfix until we find better postfix. 11735a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim @GuardedBy("mLock") 11835a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim private volatile IMediaSession2 mSessionBinder; 11935a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim 12035a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim // TODO(jaewan): Require session activeness changed listener, because controller can be 12135a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim // available when the session's player is null. 122c21a36910245a441d60f5f3c053e3e1bdaa24d5eJaewan Kim public MediaController2Impl(Context context, MediaController2 instance, SessionToken2 token, 123c21a36910245a441d60f5f3c053e3e1bdaa24d5eJaewan Kim Executor executor, ControllerCallback callback) { 12435a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim mInstance = instance; 12535a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim if (context == null) { 12635a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim throw new IllegalArgumentException("context shouldn't be null"); 12735a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim } 12835a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim if (token == null) { 12935a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim throw new IllegalArgumentException("token shouldn't be null"); 13035a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim } 13135a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim if (callback == null) { 13235a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim throw new IllegalArgumentException("callback shouldn't be null"); 13335a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim } 13435a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim if (executor == null) { 13535a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim throw new IllegalArgumentException("executor shouldn't be null"); 13635a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim } 13735a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim mContext = context; 13898f280314350160874af3bc3fd660aa3e9a0fabeSungsoo Lim mControllerStub = new MediaController2Stub(this); 13935a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim mToken = token; 14035a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim mCallback = callback; 14135a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim mCallbackExecutor = executor; 14235a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim mDeathRecipient = () -> { 143113a561d324e89b1db5edcc39c903c879e08dd94Jaewan Kim mInstance.close(); 14435a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim }; 14535a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim 14635a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim mSessionBinder = null; 147dd4397861fd98aefae95e6d6036a96f499eaf8b1Jaewan Kim } 14835a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim 149dd4397861fd98aefae95e6d6036a96f499eaf8b1Jaewan Kim @Override 150dd4397861fd98aefae95e6d6036a96f499eaf8b1Jaewan Kim public void initialize() { 151dd4397861fd98aefae95e6d6036a96f499eaf8b1Jaewan Kim // TODO(jaewan): More sanity checks. 152e38637402cf0426808f77b47483b83096112be5fSungsoo Lim if (mToken.getType() == SessionToken2.TYPE_SESSION) { 153e38637402cf0426808f77b47483b83096112be5fSungsoo Lim // Session 154e38637402cf0426808f77b47483b83096112be5fSungsoo Lim mServiceConnection = null; 155e38637402cf0426808f77b47483b83096112be5fSungsoo Lim connectToSession(SessionToken2Impl.from(mToken).getSessionBinder()); 156e38637402cf0426808f77b47483b83096112be5fSungsoo Lim } else { 157dd4397861fd98aefae95e6d6036a96f499eaf8b1Jaewan Kim // Session service 1587cda0f098a62cc0297d63f9c9dfa6b5345c7fbf9Jaewan Kim if (Process.myUid() == Process.SYSTEM_UID) { 1597cda0f098a62cc0297d63f9c9dfa6b5345c7fbf9Jaewan Kim // It's system server (MediaSessionService) that wants to monitor session. 1607cda0f098a62cc0297d63f9c9dfa6b5345c7fbf9Jaewan Kim // Don't bind if able.. 1617cda0f098a62cc0297d63f9c9dfa6b5345c7fbf9Jaewan Kim IMediaSession2 binder = SessionToken2Impl.from(mToken).getSessionBinder(); 1627cda0f098a62cc0297d63f9c9dfa6b5345c7fbf9Jaewan Kim if (binder != null) { 1637cda0f098a62cc0297d63f9c9dfa6b5345c7fbf9Jaewan Kim // Use binder in the session token instead of bind by its own. 1647cda0f098a62cc0297d63f9c9dfa6b5345c7fbf9Jaewan Kim // Otherwise server will holds the binding to the service *forever* and service 1657cda0f098a62cc0297d63f9c9dfa6b5345c7fbf9Jaewan Kim // will never stop. 1667cda0f098a62cc0297d63f9c9dfa6b5345c7fbf9Jaewan Kim mServiceConnection = null; 1677cda0f098a62cc0297d63f9c9dfa6b5345c7fbf9Jaewan Kim connectToSession(SessionToken2Impl.from(mToken).getSessionBinder()); 1687cda0f098a62cc0297d63f9c9dfa6b5345c7fbf9Jaewan Kim return; 1697cda0f098a62cc0297d63f9c9dfa6b5345c7fbf9Jaewan Kim } else if (DEBUG) { 1707cda0f098a62cc0297d63f9c9dfa6b5345c7fbf9Jaewan Kim // Should happen only when system server wants to dispatch media key events to 1717cda0f098a62cc0297d63f9c9dfa6b5345c7fbf9Jaewan Kim // a dead service. 1727cda0f098a62cc0297d63f9c9dfa6b5345c7fbf9Jaewan Kim Log.d(TAG, "System server binds to a session service. Should unbind" 1737cda0f098a62cc0297d63f9c9dfa6b5345c7fbf9Jaewan Kim + " immediately after the use."); 1747cda0f098a62cc0297d63f9c9dfa6b5345c7fbf9Jaewan Kim } 1757cda0f098a62cc0297d63f9c9dfa6b5345c7fbf9Jaewan Kim } 17635a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim mServiceConnection = new SessionServiceConnection(); 17735a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim connectToService(); 17835a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim } 17935a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim } 18035a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim 18135a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim private void connectToService() { 18235a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim // Service. Needs to get fresh binder whenever connection is needed. 183dd4397861fd98aefae95e6d6036a96f499eaf8b1Jaewan Kim SessionToken2Impl impl = SessionToken2Impl.from(mToken); 18435a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim final Intent intent = new Intent(MediaSessionService2.SERVICE_INTERFACE); 185dd4397861fd98aefae95e6d6036a96f499eaf8b1Jaewan Kim intent.setClassName(mToken.getPackageName(), impl.getServiceName()); 18635a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim 18735a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim // Use bindService() instead of startForegroundService() to start session service for three 18835a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim // reasons. 18935a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim // 1. Prevent session service owner's stopSelf() from destroying service. 19035a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim // With the startForegroundService(), service's call of stopSelf() will trigger immediate 19135a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim // onDestroy() calls on the main thread even when onConnect() is running in another 19235a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim // thread. 19335a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim // 2. Minimize APIs for developers to take care about. 19435a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim // With bindService(), developers only need to take care about Service.onBind() 19535a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim // but Service.onStartCommand() should be also taken care about with the 19635a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim // startForegroundService(). 19735a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim // 3. Future support for UI-less playback 19835a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim // If a service wants to keep running, it should be either foreground service or 19935a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim // bounded service. But there had been request for the feature for system apps 20035a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim // and using bindService() will be better fit with it. 2017cda0f098a62cc0297d63f9c9dfa6b5345c7fbf9Jaewan Kim boolean result; 2027cda0f098a62cc0297d63f9c9dfa6b5345c7fbf9Jaewan Kim if (Process.myUid() == Process.SYSTEM_UID) { 2037cda0f098a62cc0297d63f9c9dfa6b5345c7fbf9Jaewan Kim // Use bindServiceAsUser() for binding from system service to avoid following warning. 2047cda0f098a62cc0297d63f9c9dfa6b5345c7fbf9Jaewan Kim // ContextImpl: Calling a method in the system process without a qualified user 2057cda0f098a62cc0297d63f9c9dfa6b5345c7fbf9Jaewan Kim result = mContext.bindServiceAsUser(intent, mServiceConnection, Context.BIND_AUTO_CREATE, 2067cda0f098a62cc0297d63f9c9dfa6b5345c7fbf9Jaewan Kim UserHandle.getUserHandleForUid(mToken.getUid())); 2077cda0f098a62cc0297d63f9c9dfa6b5345c7fbf9Jaewan Kim } else { 2087cda0f098a62cc0297d63f9c9dfa6b5345c7fbf9Jaewan Kim result = mContext.bindService(intent, mServiceConnection, Context.BIND_AUTO_CREATE); 2097cda0f098a62cc0297d63f9c9dfa6b5345c7fbf9Jaewan Kim } 21035a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim if (!result) { 21135a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim Log.w(TAG, "bind to " + mToken + " failed"); 21235a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim } else if (DEBUG) { 21335a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim Log.d(TAG, "bind to " + mToken + " success"); 21435a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim } 21535a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim } 21635a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim 21735a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim private void connectToSession(IMediaSession2 sessionBinder) { 21835a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim try { 21998f280314350160874af3bc3fd660aa3e9a0fabeSungsoo Lim sessionBinder.connect(mControllerStub, mContext.getPackageName()); 22035a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim } catch (RemoteException e) { 22135a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim Log.w(TAG, "Failed to call connection request. Framework will retry" 22235a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim + " automatically"); 22335a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim } 22435a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim } 22535a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim 22635a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim @Override 227113a561d324e89b1db5edcc39c903c879e08dd94Jaewan Kim public void close_impl() { 2285aec249a238ff2dcb9bb5bc0434b7a17fa96a035Jaewan Kim if (DEBUG) { 229dd4397861fd98aefae95e6d6036a96f499eaf8b1Jaewan Kim Log.d(TAG, "release from " + mToken); 2305aec249a238ff2dcb9bb5bc0434b7a17fa96a035Jaewan Kim } 23135a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim final IMediaSession2 binder; 23235a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim synchronized (mLock) { 23335a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim if (mIsReleased) { 23435a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim // Prevent re-enterance from the ControllerCallback.onDisconnected() 23535a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim return; 23635a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim } 23735a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim mIsReleased = true; 23835a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim if (mServiceConnection != null) { 23935a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim mContext.unbindService(mServiceConnection); 24035a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim mServiceConnection = null; 24135a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim } 24235a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim binder = mSessionBinder; 24335a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim mSessionBinder = null; 24498f280314350160874af3bc3fd660aa3e9a0fabeSungsoo Lim mControllerStub.destroy(); 24535a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim } 24635a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim if (binder != null) { 24735a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim try { 24835a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim binder.asBinder().unlinkToDeath(mDeathRecipient, 0); 24998f280314350160874af3bc3fd660aa3e9a0fabeSungsoo Lim binder.release(mControllerStub); 25035a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim } catch (RemoteException e) { 25135a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim // No-op. 25235a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim } 25335a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim } 25435a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim mCallbackExecutor.execute(() -> { 255d3d75358db7e3fe87805f1d91aa53abe1b0c2e92Jaewan Kim mCallback.onDisconnected(mInstance); 25635a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim }); 25735a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim } 25835a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim 259735f3430f9cd1224a68e87b015baca0789debe22Jaewan Kim IMediaSession2 getSessionBinder() { 260735f3430f9cd1224a68e87b015baca0789debe22Jaewan Kim return mSessionBinder; 261735f3430f9cd1224a68e87b015baca0789debe22Jaewan Kim } 262735f3430f9cd1224a68e87b015baca0789debe22Jaewan Kim 26398f280314350160874af3bc3fd660aa3e9a0fabeSungsoo Lim MediaController2Stub getControllerStub() { 26498f280314350160874af3bc3fd660aa3e9a0fabeSungsoo Lim return mControllerStub; 265735f3430f9cd1224a68e87b015baca0789debe22Jaewan Kim } 266735f3430f9cd1224a68e87b015baca0789debe22Jaewan Kim 2675aec249a238ff2dcb9bb5bc0434b7a17fa96a035Jaewan Kim Executor getCallbackExecutor() { 2685aec249a238ff2dcb9bb5bc0434b7a17fa96a035Jaewan Kim return mCallbackExecutor; 2695aec249a238ff2dcb9bb5bc0434b7a17fa96a035Jaewan Kim } 2705aec249a238ff2dcb9bb5bc0434b7a17fa96a035Jaewan Kim 27178e257713ebf4805647772f32fac433d2621405eSungsoo Lim Context getContext() { 272b41bfb59dd52decb1e5c5952d6ed786f159d772dJaewan Kim return mContext; 273b41bfb59dd52decb1e5c5952d6ed786f159d772dJaewan Kim } 274b41bfb59dd52decb1e5c5952d6ed786f159d772dJaewan Kim 275b41bfb59dd52decb1e5c5952d6ed786f159d772dJaewan Kim MediaController2 getInstance() { 276b41bfb59dd52decb1e5c5952d6ed786f159d772dJaewan Kim return mInstance; 27778e257713ebf4805647772f32fac433d2621405eSungsoo Lim } 27878e257713ebf4805647772f32fac433d2621405eSungsoo Lim 279483261f98e9eeb6191d42873970a2ae9709ac1fcJaewan Kim // Returns session binder if the controller can send the command. 280483261f98e9eeb6191d42873970a2ae9709ac1fcJaewan Kim IMediaSession2 getSessionBinderIfAble(int commandCode) { 281483261f98e9eeb6191d42873970a2ae9709ac1fcJaewan Kim synchronized (mLock) { 282483261f98e9eeb6191d42873970a2ae9709ac1fcJaewan Kim if (!mAllowedCommands.hasCommand(commandCode)) { 283483261f98e9eeb6191d42873970a2ae9709ac1fcJaewan Kim // Cannot send because isn't allowed to. 284483261f98e9eeb6191d42873970a2ae9709ac1fcJaewan Kim Log.w(TAG, "Controller isn't allowed to call command, commandCode=" 285483261f98e9eeb6191d42873970a2ae9709ac1fcJaewan Kim + commandCode); 286483261f98e9eeb6191d42873970a2ae9709ac1fcJaewan Kim return null; 287483261f98e9eeb6191d42873970a2ae9709ac1fcJaewan Kim } 288483261f98e9eeb6191d42873970a2ae9709ac1fcJaewan Kim } 289483261f98e9eeb6191d42873970a2ae9709ac1fcJaewan Kim // TODO(jaewan): Should we do this with the lock hold? 290483261f98e9eeb6191d42873970a2ae9709ac1fcJaewan Kim final IMediaSession2 binder = mSessionBinder; 291483261f98e9eeb6191d42873970a2ae9709ac1fcJaewan Kim if (binder == null) { 292483261f98e9eeb6191d42873970a2ae9709ac1fcJaewan Kim // Cannot send because disconnected. 293483261f98e9eeb6191d42873970a2ae9709ac1fcJaewan Kim Log.w(TAG, "Session is disconnected"); 294483261f98e9eeb6191d42873970a2ae9709ac1fcJaewan Kim } 295483261f98e9eeb6191d42873970a2ae9709ac1fcJaewan Kim return binder; 296483261f98e9eeb6191d42873970a2ae9709ac1fcJaewan Kim } 297483261f98e9eeb6191d42873970a2ae9709ac1fcJaewan Kim 298483261f98e9eeb6191d42873970a2ae9709ac1fcJaewan Kim // Returns session binder if the controller can send the command. 299d5b878d0cf0c987caf18be697a0e1637fb632d66Jaewan Kim IMediaSession2 getSessionBinderIfAble(SessionCommand2 command) { 300483261f98e9eeb6191d42873970a2ae9709ac1fcJaewan Kim synchronized (mLock) { 301483261f98e9eeb6191d42873970a2ae9709ac1fcJaewan Kim if (!mAllowedCommands.hasCommand(command)) { 302483261f98e9eeb6191d42873970a2ae9709ac1fcJaewan Kim Log.w(TAG, "Controller isn't allowed to call command, command=" + command); 303483261f98e9eeb6191d42873970a2ae9709ac1fcJaewan Kim return null; 304483261f98e9eeb6191d42873970a2ae9709ac1fcJaewan Kim } 305483261f98e9eeb6191d42873970a2ae9709ac1fcJaewan Kim } 306483261f98e9eeb6191d42873970a2ae9709ac1fcJaewan Kim // TODO(jaewan): Should we do this with the lock hold? 307483261f98e9eeb6191d42873970a2ae9709ac1fcJaewan Kim final IMediaSession2 binder = mSessionBinder; 308483261f98e9eeb6191d42873970a2ae9709ac1fcJaewan Kim if (binder == null) { 309483261f98e9eeb6191d42873970a2ae9709ac1fcJaewan Kim // Cannot send because disconnected. 310483261f98e9eeb6191d42873970a2ae9709ac1fcJaewan Kim Log.w(TAG, "Session is disconnected"); 311483261f98e9eeb6191d42873970a2ae9709ac1fcJaewan Kim } 312483261f98e9eeb6191d42873970a2ae9709ac1fcJaewan Kim return binder; 313483261f98e9eeb6191d42873970a2ae9709ac1fcJaewan Kim } 314483261f98e9eeb6191d42873970a2ae9709ac1fcJaewan Kim 31535a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim @Override 3167027e8019ad974d2e474a7fcaf43adedbdf08f23Jaewan Kim public SessionToken2 getSessionToken_impl() { 31735a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim return mToken; 31835a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim } 31935a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim 32035a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim @Override 32135a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim public boolean isConnected_impl() { 32235a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim final IMediaSession2 binder = mSessionBinder; 32335a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim return binder != null; 32435a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim } 32535a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim 32635a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim @Override 32735a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim public void play_impl() { 328d5b878d0cf0c987caf18be697a0e1637fb632d66Jaewan Kim sendTransportControlCommand(SessionCommand2.COMMAND_CODE_PLAYBACK_PLAY); 32935a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim } 33035a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim 33135a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim @Override 33235a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim public void pause_impl() { 333d5b878d0cf0c987caf18be697a0e1637fb632d66Jaewan Kim sendTransportControlCommand(SessionCommand2.COMMAND_CODE_PLAYBACK_PAUSE); 33435a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim } 33535a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim 33635a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim @Override 33735a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim public void stop_impl() { 338d5b878d0cf0c987caf18be697a0e1637fb632d66Jaewan Kim sendTransportControlCommand(SessionCommand2.COMMAND_CODE_PLAYBACK_STOP); 33935a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim } 34035a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim 34135a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim @Override 34254d638619dc3473e35a2aa61738fb6034d77b8deJaewan Kim public void skipToPlaylistItem_impl(MediaItem2 item) { 34354d638619dc3473e35a2aa61738fb6034d77b8deJaewan Kim if (item == null) { 34454d638619dc3473e35a2aa61738fb6034d77b8deJaewan Kim throw new IllegalArgumentException("item shouldn't be null"); 34554d638619dc3473e35a2aa61738fb6034d77b8deJaewan Kim } 34654d638619dc3473e35a2aa61738fb6034d77b8deJaewan Kim final IMediaSession2 binder = mSessionBinder; 34754d638619dc3473e35a2aa61738fb6034d77b8deJaewan Kim if (binder != null) { 34854d638619dc3473e35a2aa61738fb6034d77b8deJaewan Kim try { 34954d638619dc3473e35a2aa61738fb6034d77b8deJaewan Kim binder.skipToPlaylistItem(mControllerStub, item.toBundle()); 35054d638619dc3473e35a2aa61738fb6034d77b8deJaewan Kim } catch (RemoteException e) { 35154d638619dc3473e35a2aa61738fb6034d77b8deJaewan Kim Log.w(TAG, "Cannot connect to the service or the session is gone", e); 35254d638619dc3473e35a2aa61738fb6034d77b8deJaewan Kim } 35354d638619dc3473e35a2aa61738fb6034d77b8deJaewan Kim } else { 35454d638619dc3473e35a2aa61738fb6034d77b8deJaewan Kim Log.w(TAG, "Session isn't active", new IllegalStateException()); 35554d638619dc3473e35a2aa61738fb6034d77b8deJaewan Kim } 35654d638619dc3473e35a2aa61738fb6034d77b8deJaewan Kim } 35754d638619dc3473e35a2aa61738fb6034d77b8deJaewan Kim 35854d638619dc3473e35a2aa61738fb6034d77b8deJaewan Kim @Override 359c8508bf04576790230c5a32b329a4b47468ac7fbJaewan Kim public void skipToPreviousItem_impl() { 36054d638619dc3473e35a2aa61738fb6034d77b8deJaewan Kim final IMediaSession2 binder = mSessionBinder; 36154d638619dc3473e35a2aa61738fb6034d77b8deJaewan Kim if (binder != null) { 36254d638619dc3473e35a2aa61738fb6034d77b8deJaewan Kim try { 36354d638619dc3473e35a2aa61738fb6034d77b8deJaewan Kim binder.skipToPreviousItem(mControllerStub); 36454d638619dc3473e35a2aa61738fb6034d77b8deJaewan Kim } catch (RemoteException e) { 36554d638619dc3473e35a2aa61738fb6034d77b8deJaewan Kim Log.w(TAG, "Cannot connect to the service or the session is gone", e); 36654d638619dc3473e35a2aa61738fb6034d77b8deJaewan Kim } 36754d638619dc3473e35a2aa61738fb6034d77b8deJaewan Kim } else { 36854d638619dc3473e35a2aa61738fb6034d77b8deJaewan Kim Log.w(TAG, "Session isn't active", new IllegalStateException()); 36954d638619dc3473e35a2aa61738fb6034d77b8deJaewan Kim } 37035a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim } 37135a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim 37235a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim @Override 373c8508bf04576790230c5a32b329a4b47468ac7fbJaewan Kim public void skipToNextItem_impl() { 37454d638619dc3473e35a2aa61738fb6034d77b8deJaewan Kim final IMediaSession2 binder = mSessionBinder; 37554d638619dc3473e35a2aa61738fb6034d77b8deJaewan Kim if (binder != null) { 37654d638619dc3473e35a2aa61738fb6034d77b8deJaewan Kim try { 37754d638619dc3473e35a2aa61738fb6034d77b8deJaewan Kim binder.skipToNextItem(mControllerStub); 37854d638619dc3473e35a2aa61738fb6034d77b8deJaewan Kim } catch (RemoteException e) { 37954d638619dc3473e35a2aa61738fb6034d77b8deJaewan Kim Log.w(TAG, "Cannot connect to the service or the session is gone", e); 38054d638619dc3473e35a2aa61738fb6034d77b8deJaewan Kim } 38154d638619dc3473e35a2aa61738fb6034d77b8deJaewan Kim } else { 38254d638619dc3473e35a2aa61738fb6034d77b8deJaewan Kim Log.w(TAG, "Session isn't active", new IllegalStateException()); 38354d638619dc3473e35a2aa61738fb6034d77b8deJaewan Kim } 3843bad8ce270642d8780f3cd450a0c8af94788fde4Jaewan Kim } 3853bad8ce270642d8780f3cd450a0c8af94788fde4Jaewan Kim 386f6f272f8c4bdd41274537761ff0efb7b7a801f3dJaewan Kim private void sendTransportControlCommand(int commandCode) { 387e71339cbe74fc7b87c822ae95d1c842d7944942bHyundo Moon sendTransportControlCommand(commandCode, null); 388f6f272f8c4bdd41274537761ff0efb7b7a801f3dJaewan Kim } 3893bad8ce270642d8780f3cd450a0c8af94788fde4Jaewan Kim 390e71339cbe74fc7b87c822ae95d1c842d7944942bHyundo Moon private void sendTransportControlCommand(int commandCode, Bundle args) { 39135a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim final IMediaSession2 binder = mSessionBinder; 39235a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim if (binder != null) { 39335a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim try { 39498f280314350160874af3bc3fd660aa3e9a0fabeSungsoo Lim binder.sendTransportControlCommand(mControllerStub, commandCode, args); 39535a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim } catch (RemoteException e) { 39635a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim Log.w(TAG, "Cannot connect to the service or the session is gone", e); 39735a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim } 39835a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim } else { 39935a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim Log.w(TAG, "Session isn't active", new IllegalStateException()); 40035a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim } 40135a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim } 40235a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim 40335a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim @Override 404da59499289a68a2558370b6acfd4096d3feb8107Jaewan Kim public PendingIntent getSessionActivity_impl() { 4050261708bf17cb0469de8eb3c81455e2f48ff9433Jaewan Kim return mSessionActivity; 40635a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim } 40735a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim 40835a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim @Override 409da59499289a68a2558370b6acfd4096d3feb8107Jaewan Kim public void setVolumeTo_impl(int value, int flags) { 410c7840a9c538949820d8b3481072d4bc13081d85dHyundo Moon // TODO(hdmoon): sanity check 411d5b878d0cf0c987caf18be697a0e1637fb632d66Jaewan Kim final IMediaSession2 binder = getSessionBinderIfAble(COMMAND_CODE_SET_VOLUME); 412c7840a9c538949820d8b3481072d4bc13081d85dHyundo Moon if (binder != null) { 413c7840a9c538949820d8b3481072d4bc13081d85dHyundo Moon try { 41498f280314350160874af3bc3fd660aa3e9a0fabeSungsoo Lim binder.setVolumeTo(mControllerStub, value, flags); 415c7840a9c538949820d8b3481072d4bc13081d85dHyundo Moon } catch (RemoteException e) { 416c7840a9c538949820d8b3481072d4bc13081d85dHyundo Moon Log.w(TAG, "Cannot connect to the service or the session is gone", e); 417c7840a9c538949820d8b3481072d4bc13081d85dHyundo Moon } 418c7840a9c538949820d8b3481072d4bc13081d85dHyundo Moon } else { 419c7840a9c538949820d8b3481072d4bc13081d85dHyundo Moon Log.w(TAG, "Session isn't active", new IllegalStateException()); 420c7840a9c538949820d8b3481072d4bc13081d85dHyundo Moon } 421da59499289a68a2558370b6acfd4096d3feb8107Jaewan Kim } 422da59499289a68a2558370b6acfd4096d3feb8107Jaewan Kim 423da59499289a68a2558370b6acfd4096d3feb8107Jaewan Kim @Override 424da59499289a68a2558370b6acfd4096d3feb8107Jaewan Kim public void adjustVolume_impl(int direction, int flags) { 425c7840a9c538949820d8b3481072d4bc13081d85dHyundo Moon // TODO(hdmoon): sanity check 426d5b878d0cf0c987caf18be697a0e1637fb632d66Jaewan Kim final IMediaSession2 binder = getSessionBinderIfAble(COMMAND_CODE_SET_VOLUME); 427c7840a9c538949820d8b3481072d4bc13081d85dHyundo Moon if (binder != null) { 428c7840a9c538949820d8b3481072d4bc13081d85dHyundo Moon try { 42998f280314350160874af3bc3fd660aa3e9a0fabeSungsoo Lim binder.adjustVolume(mControllerStub, direction, flags); 430c7840a9c538949820d8b3481072d4bc13081d85dHyundo Moon } catch (RemoteException e) { 431c7840a9c538949820d8b3481072d4bc13081d85dHyundo Moon Log.w(TAG, "Cannot connect to the service or the session is gone", e); 432c7840a9c538949820d8b3481072d4bc13081d85dHyundo Moon } 433c7840a9c538949820d8b3481072d4bc13081d85dHyundo Moon } else { 434c7840a9c538949820d8b3481072d4bc13081d85dHyundo Moon Log.w(TAG, "Session isn't active", new IllegalStateException()); 435c7840a9c538949820d8b3481072d4bc13081d85dHyundo Moon } 436da59499289a68a2558370b6acfd4096d3feb8107Jaewan Kim } 437da59499289a68a2558370b6acfd4096d3feb8107Jaewan Kim 438da59499289a68a2558370b6acfd4096d3feb8107Jaewan Kim @Override 439da59499289a68a2558370b6acfd4096d3feb8107Jaewan Kim public void prepareFromUri_impl(Uri uri, Bundle extras) { 44054936be442ba7153667cb582fb9d2035f9f1f63cJaewan Kim final IMediaSession2 binder = getSessionBinderIfAble(COMMAND_CODE_SESSION_PREPARE_FROM_URI); 44198fdf3583d3bfd1178ef1e0102e3de6d2b1dd2bcHyundo Moon if (uri == null) { 44298fdf3583d3bfd1178ef1e0102e3de6d2b1dd2bcHyundo Moon throw new IllegalArgumentException("uri shouldn't be null"); 44398fdf3583d3bfd1178ef1e0102e3de6d2b1dd2bcHyundo Moon } 444edd9171c285692efc04a8f38b3aed0140ae1e56cJaewan Kim if (binder != null) { 445edd9171c285692efc04a8f38b3aed0140ae1e56cJaewan Kim try { 44698f280314350160874af3bc3fd660aa3e9a0fabeSungsoo Lim binder.prepareFromUri(mControllerStub, uri, extras); 447edd9171c285692efc04a8f38b3aed0140ae1e56cJaewan Kim } catch (RemoteException e) { 448edd9171c285692efc04a8f38b3aed0140ae1e56cJaewan Kim Log.w(TAG, "Cannot connect to the service or the session is gone", e); 449edd9171c285692efc04a8f38b3aed0140ae1e56cJaewan Kim } 450edd9171c285692efc04a8f38b3aed0140ae1e56cJaewan Kim } else { 451edd9171c285692efc04a8f38b3aed0140ae1e56cJaewan Kim // TODO(jaewan): Handle. 452edd9171c285692efc04a8f38b3aed0140ae1e56cJaewan Kim } 453da59499289a68a2558370b6acfd4096d3feb8107Jaewan Kim } 454da59499289a68a2558370b6acfd4096d3feb8107Jaewan Kim 455da59499289a68a2558370b6acfd4096d3feb8107Jaewan Kim @Override 456da59499289a68a2558370b6acfd4096d3feb8107Jaewan Kim public void prepareFromSearch_impl(String query, Bundle extras) { 45754936be442ba7153667cb582fb9d2035f9f1f63cJaewan Kim final IMediaSession2 binder = getSessionBinderIfAble( 45854936be442ba7153667cb582fb9d2035f9f1f63cJaewan Kim COMMAND_CODE_SESSION_PREPARE_FROM_SEARCH); 45998fdf3583d3bfd1178ef1e0102e3de6d2b1dd2bcHyundo Moon if (TextUtils.isEmpty(query)) { 46098fdf3583d3bfd1178ef1e0102e3de6d2b1dd2bcHyundo Moon throw new IllegalArgumentException("query shouldn't be empty"); 46198fdf3583d3bfd1178ef1e0102e3de6d2b1dd2bcHyundo Moon } 462edd9171c285692efc04a8f38b3aed0140ae1e56cJaewan Kim if (binder != null) { 463edd9171c285692efc04a8f38b3aed0140ae1e56cJaewan Kim try { 46498f280314350160874af3bc3fd660aa3e9a0fabeSungsoo Lim binder.prepareFromSearch(mControllerStub, query, extras); 465edd9171c285692efc04a8f38b3aed0140ae1e56cJaewan Kim } catch (RemoteException e) { 466edd9171c285692efc04a8f38b3aed0140ae1e56cJaewan Kim Log.w(TAG, "Cannot connect to the service or the session is gone", e); 467edd9171c285692efc04a8f38b3aed0140ae1e56cJaewan Kim } 468edd9171c285692efc04a8f38b3aed0140ae1e56cJaewan Kim } else { 469edd9171c285692efc04a8f38b3aed0140ae1e56cJaewan Kim // TODO(jaewan): Handle. 470edd9171c285692efc04a8f38b3aed0140ae1e56cJaewan Kim } 471da59499289a68a2558370b6acfd4096d3feb8107Jaewan Kim } 472da59499289a68a2558370b6acfd4096d3feb8107Jaewan Kim 473da59499289a68a2558370b6acfd4096d3feb8107Jaewan Kim @Override 47498fdf3583d3bfd1178ef1e0102e3de6d2b1dd2bcHyundo Moon public void prepareFromMediaId_impl(String mediaId, Bundle extras) { 47554936be442ba7153667cb582fb9d2035f9f1f63cJaewan Kim final IMediaSession2 binder = getSessionBinderIfAble( 47654936be442ba7153667cb582fb9d2035f9f1f63cJaewan Kim COMMAND_CODE_SESSION_PREPARE_FROM_MEDIA_ID); 47798fdf3583d3bfd1178ef1e0102e3de6d2b1dd2bcHyundo Moon if (mediaId == null) { 47898fdf3583d3bfd1178ef1e0102e3de6d2b1dd2bcHyundo Moon throw new IllegalArgumentException("mediaId shouldn't be null"); 47998fdf3583d3bfd1178ef1e0102e3de6d2b1dd2bcHyundo Moon } 480edd9171c285692efc04a8f38b3aed0140ae1e56cJaewan Kim if (binder != null) { 481edd9171c285692efc04a8f38b3aed0140ae1e56cJaewan Kim try { 48298f280314350160874af3bc3fd660aa3e9a0fabeSungsoo Lim binder.prepareFromMediaId(mControllerStub, mediaId, extras); 483edd9171c285692efc04a8f38b3aed0140ae1e56cJaewan Kim } catch (RemoteException e) { 484edd9171c285692efc04a8f38b3aed0140ae1e56cJaewan Kim Log.w(TAG, "Cannot connect to the service or the session is gone", e); 485edd9171c285692efc04a8f38b3aed0140ae1e56cJaewan Kim } 486edd9171c285692efc04a8f38b3aed0140ae1e56cJaewan Kim } else { 487edd9171c285692efc04a8f38b3aed0140ae1e56cJaewan Kim // TODO(jaewan): Handle. 488edd9171c285692efc04a8f38b3aed0140ae1e56cJaewan Kim } 489da59499289a68a2558370b6acfd4096d3feb8107Jaewan Kim } 490da59499289a68a2558370b6acfd4096d3feb8107Jaewan Kim 491da59499289a68a2558370b6acfd4096d3feb8107Jaewan Kim @Override 492edd9171c285692efc04a8f38b3aed0140ae1e56cJaewan Kim public void playFromUri_impl(Uri uri, Bundle extras) { 49354936be442ba7153667cb582fb9d2035f9f1f63cJaewan Kim final IMediaSession2 binder = getSessionBinderIfAble(COMMAND_CODE_SESSION_PLAY_FROM_URI); 49498fdf3583d3bfd1178ef1e0102e3de6d2b1dd2bcHyundo Moon if (uri == null) { 49598fdf3583d3bfd1178ef1e0102e3de6d2b1dd2bcHyundo Moon throw new IllegalArgumentException("uri shouldn't be null"); 49698fdf3583d3bfd1178ef1e0102e3de6d2b1dd2bcHyundo Moon } 497edd9171c285692efc04a8f38b3aed0140ae1e56cJaewan Kim if (binder != null) { 498edd9171c285692efc04a8f38b3aed0140ae1e56cJaewan Kim try { 49998f280314350160874af3bc3fd660aa3e9a0fabeSungsoo Lim binder.playFromUri(mControllerStub, uri, extras); 500edd9171c285692efc04a8f38b3aed0140ae1e56cJaewan Kim } catch (RemoteException e) { 501edd9171c285692efc04a8f38b3aed0140ae1e56cJaewan Kim Log.w(TAG, "Cannot connect to the service or the session is gone", e); 502edd9171c285692efc04a8f38b3aed0140ae1e56cJaewan Kim } 503edd9171c285692efc04a8f38b3aed0140ae1e56cJaewan Kim } else { 504edd9171c285692efc04a8f38b3aed0140ae1e56cJaewan Kim // TODO(jaewan): Handle. 505edd9171c285692efc04a8f38b3aed0140ae1e56cJaewan Kim } 506da59499289a68a2558370b6acfd4096d3feb8107Jaewan Kim } 507da59499289a68a2558370b6acfd4096d3feb8107Jaewan Kim 508da59499289a68a2558370b6acfd4096d3feb8107Jaewan Kim @Override 509edd9171c285692efc04a8f38b3aed0140ae1e56cJaewan Kim public void playFromSearch_impl(String query, Bundle extras) { 51054936be442ba7153667cb582fb9d2035f9f1f63cJaewan Kim final IMediaSession2 binder = getSessionBinderIfAble(COMMAND_CODE_SESSION_PLAY_FROM_SEARCH); 51198fdf3583d3bfd1178ef1e0102e3de6d2b1dd2bcHyundo Moon if (TextUtils.isEmpty(query)) { 51298fdf3583d3bfd1178ef1e0102e3de6d2b1dd2bcHyundo Moon throw new IllegalArgumentException("query shouldn't be empty"); 51398fdf3583d3bfd1178ef1e0102e3de6d2b1dd2bcHyundo Moon } 514edd9171c285692efc04a8f38b3aed0140ae1e56cJaewan Kim if (binder != null) { 515edd9171c285692efc04a8f38b3aed0140ae1e56cJaewan Kim try { 51698f280314350160874af3bc3fd660aa3e9a0fabeSungsoo Lim binder.playFromSearch(mControllerStub, query, extras); 517edd9171c285692efc04a8f38b3aed0140ae1e56cJaewan Kim } catch (RemoteException e) { 518edd9171c285692efc04a8f38b3aed0140ae1e56cJaewan Kim Log.w(TAG, "Cannot connect to the service or the session is gone", e); 519edd9171c285692efc04a8f38b3aed0140ae1e56cJaewan Kim } 520edd9171c285692efc04a8f38b3aed0140ae1e56cJaewan Kim } else { 521edd9171c285692efc04a8f38b3aed0140ae1e56cJaewan Kim // TODO(jaewan): Handle. 522edd9171c285692efc04a8f38b3aed0140ae1e56cJaewan Kim } 523da59499289a68a2558370b6acfd4096d3feb8107Jaewan Kim } 524da59499289a68a2558370b6acfd4096d3feb8107Jaewan Kim 525da59499289a68a2558370b6acfd4096d3feb8107Jaewan Kim @Override 526da59499289a68a2558370b6acfd4096d3feb8107Jaewan Kim public void playFromMediaId_impl(String mediaId, Bundle extras) { 52754936be442ba7153667cb582fb9d2035f9f1f63cJaewan Kim final IMediaSession2 binder = getSessionBinderIfAble( 52854936be442ba7153667cb582fb9d2035f9f1f63cJaewan Kim COMMAND_CODE_SESSION_PLAY_FROM_MEDIA_ID); 52998fdf3583d3bfd1178ef1e0102e3de6d2b1dd2bcHyundo Moon if (mediaId == null) { 53098fdf3583d3bfd1178ef1e0102e3de6d2b1dd2bcHyundo Moon throw new IllegalArgumentException("mediaId shouldn't be null"); 53198fdf3583d3bfd1178ef1e0102e3de6d2b1dd2bcHyundo Moon } 532edd9171c285692efc04a8f38b3aed0140ae1e56cJaewan Kim if (binder != null) { 533edd9171c285692efc04a8f38b3aed0140ae1e56cJaewan Kim try { 53498f280314350160874af3bc3fd660aa3e9a0fabeSungsoo Lim binder.playFromMediaId(mControllerStub, mediaId, extras); 535edd9171c285692efc04a8f38b3aed0140ae1e56cJaewan Kim } catch (RemoteException e) { 536edd9171c285692efc04a8f38b3aed0140ae1e56cJaewan Kim Log.w(TAG, "Cannot connect to the service or the session is gone", e); 537edd9171c285692efc04a8f38b3aed0140ae1e56cJaewan Kim } 538edd9171c285692efc04a8f38b3aed0140ae1e56cJaewan Kim } else { 539edd9171c285692efc04a8f38b3aed0140ae1e56cJaewan Kim // TODO(jaewan): Handle. 540edd9171c285692efc04a8f38b3aed0140ae1e56cJaewan Kim } 541da59499289a68a2558370b6acfd4096d3feb8107Jaewan Kim } 542af063f1179a5046c13b55710a42aaba993e19fcbHyundo Moon 543da59499289a68a2558370b6acfd4096d3feb8107Jaewan Kim @Override 544af063f1179a5046c13b55710a42aaba993e19fcbHyundo Moon public void setRating_impl(String mediaId, Rating2 rating) { 545af063f1179a5046c13b55710a42aaba993e19fcbHyundo Moon if (mediaId == null) { 546af063f1179a5046c13b55710a42aaba993e19fcbHyundo Moon throw new IllegalArgumentException("mediaId shouldn't be null"); 547af063f1179a5046c13b55710a42aaba993e19fcbHyundo Moon } 548af063f1179a5046c13b55710a42aaba993e19fcbHyundo Moon if (rating == null) { 549af063f1179a5046c13b55710a42aaba993e19fcbHyundo Moon throw new IllegalArgumentException("rating shouldn't be null"); 550af063f1179a5046c13b55710a42aaba993e19fcbHyundo Moon } 551af063f1179a5046c13b55710a42aaba993e19fcbHyundo Moon 552af063f1179a5046c13b55710a42aaba993e19fcbHyundo Moon final IMediaSession2 binder = mSessionBinder; 553af063f1179a5046c13b55710a42aaba993e19fcbHyundo Moon if (binder != null) { 554af063f1179a5046c13b55710a42aaba993e19fcbHyundo Moon try { 55598f280314350160874af3bc3fd660aa3e9a0fabeSungsoo Lim binder.setRating(mControllerStub, mediaId, rating.toBundle()); 556af063f1179a5046c13b55710a42aaba993e19fcbHyundo Moon } catch (RemoteException e) { 557af063f1179a5046c13b55710a42aaba993e19fcbHyundo Moon Log.w(TAG, "Cannot connect to the service or the session is gone", e); 558af063f1179a5046c13b55710a42aaba993e19fcbHyundo Moon } 559af063f1179a5046c13b55710a42aaba993e19fcbHyundo Moon } else { 560af063f1179a5046c13b55710a42aaba993e19fcbHyundo Moon // TODO(jaewan): Handle. 561af063f1179a5046c13b55710a42aaba993e19fcbHyundo Moon } 562da59499289a68a2558370b6acfd4096d3feb8107Jaewan Kim } 563da59499289a68a2558370b6acfd4096d3feb8107Jaewan Kim 564da59499289a68a2558370b6acfd4096d3feb8107Jaewan Kim @Override 565d5b878d0cf0c987caf18be697a0e1637fb632d66Jaewan Kim public void sendCustomCommand_impl(SessionCommand2 command, Bundle args, ResultReceiver cb) { 566bf9606868a825bf9f606d4d3ec8d15e7f29b76a7Jaewan Kim if (command == null) { 567bf9606868a825bf9f606d4d3ec8d15e7f29b76a7Jaewan Kim throw new IllegalArgumentException("command shouldn't be null"); 568bf9606868a825bf9f606d4d3ec8d15e7f29b76a7Jaewan Kim } 569483261f98e9eeb6191d42873970a2ae9709ac1fcJaewan Kim final IMediaSession2 binder = getSessionBinderIfAble(command); 570bf9606868a825bf9f606d4d3ec8d15e7f29b76a7Jaewan Kim if (binder != null) { 571bf9606868a825bf9f606d4d3ec8d15e7f29b76a7Jaewan Kim try { 57298f280314350160874af3bc3fd660aa3e9a0fabeSungsoo Lim binder.sendCustomCommand(mControllerStub, command.toBundle(), args, cb); 573bf9606868a825bf9f606d4d3ec8d15e7f29b76a7Jaewan Kim } catch (RemoteException e) { 574bf9606868a825bf9f606d4d3ec8d15e7f29b76a7Jaewan Kim Log.w(TAG, "Cannot connect to the service or the session is gone", e); 575bf9606868a825bf9f606d4d3ec8d15e7f29b76a7Jaewan Kim } 576bf9606868a825bf9f606d4d3ec8d15e7f29b76a7Jaewan Kim } else { 577bf9606868a825bf9f606d4d3ec8d15e7f29b76a7Jaewan Kim Log.w(TAG, "Session isn't active", new IllegalStateException()); 578bf9606868a825bf9f606d4d3ec8d15e7f29b76a7Jaewan Kim } 579da59499289a68a2558370b6acfd4096d3feb8107Jaewan Kim } 580da59499289a68a2558370b6acfd4096d3feb8107Jaewan Kim 581da59499289a68a2558370b6acfd4096d3feb8107Jaewan Kim @Override 582da59499289a68a2558370b6acfd4096d3feb8107Jaewan Kim public List<MediaItem2> getPlaylist_impl() { 5833923b1b71628e668f9b11ed4891ed2840dd331cdHyundo Moon synchronized (mLock) { 5843923b1b71628e668f9b11ed4891ed2840dd331cdHyundo Moon return mPlaylist; 5853923b1b71628e668f9b11ed4891ed2840dd331cdHyundo Moon } 586da59499289a68a2558370b6acfd4096d3feb8107Jaewan Kim } 587da59499289a68a2558370b6acfd4096d3feb8107Jaewan Kim 588da59499289a68a2558370b6acfd4096d3feb8107Jaewan Kim @Override 589e0a38c69b26945394936922dd837cc7e9fa37d3cJaewan Kim public void setPlaylist_impl(List<MediaItem2> list, MediaMetadata2 metadata) { 590e0a38c69b26945394936922dd837cc7e9fa37d3cJaewan Kim if (list == null) { 591e0a38c69b26945394936922dd837cc7e9fa37d3cJaewan Kim throw new IllegalArgumentException("list shouldn't be null"); 592e0a38c69b26945394936922dd837cc7e9fa37d3cJaewan Kim } 593e0a38c69b26945394936922dd837cc7e9fa37d3cJaewan Kim final IMediaSession2 binder = getSessionBinderIfAble(COMMAND_CODE_PLAYLIST_SET_LIST); 594e0a38c69b26945394936922dd837cc7e9fa37d3cJaewan Kim if (binder != null) { 595e0a38c69b26945394936922dd837cc7e9fa37d3cJaewan Kim List<Bundle> bundleList = new ArrayList<>(); 596e0a38c69b26945394936922dd837cc7e9fa37d3cJaewan Kim for (int i = 0; i < list.size(); i++) { 597e0a38c69b26945394936922dd837cc7e9fa37d3cJaewan Kim bundleList.add(list.get(i).toBundle()); 598e0a38c69b26945394936922dd837cc7e9fa37d3cJaewan Kim } 599e0a38c69b26945394936922dd837cc7e9fa37d3cJaewan Kim Bundle metadataBundle = (metadata == null) ? null : metadata.toBundle(); 600e0a38c69b26945394936922dd837cc7e9fa37d3cJaewan Kim try { 60198f280314350160874af3bc3fd660aa3e9a0fabeSungsoo Lim binder.setPlaylist(mControllerStub, bundleList, metadataBundle); 602e0a38c69b26945394936922dd837cc7e9fa37d3cJaewan Kim } catch (RemoteException e) { 603e0a38c69b26945394936922dd837cc7e9fa37d3cJaewan Kim Log.w(TAG, "Cannot connect to the service or the session is gone", e); 604e0a38c69b26945394936922dd837cc7e9fa37d3cJaewan Kim } 605e0a38c69b26945394936922dd837cc7e9fa37d3cJaewan Kim } else { 606e0a38c69b26945394936922dd837cc7e9fa37d3cJaewan Kim Log.w(TAG, "Session isn't active", new IllegalStateException()); 607e0a38c69b26945394936922dd837cc7e9fa37d3cJaewan Kim } 608e0a38c69b26945394936922dd837cc7e9fa37d3cJaewan Kim } 609e0a38c69b26945394936922dd837cc7e9fa37d3cJaewan Kim 610e0a38c69b26945394936922dd837cc7e9fa37d3cJaewan Kim @Override 611df4f8498f40e995abeedbbdf6053c252c0fa3350Jaewan Kim public MediaMetadata2 getPlaylistMetadata_impl() { 612df4f8498f40e995abeedbbdf6053c252c0fa3350Jaewan Kim synchronized (mLock) { 613df4f8498f40e995abeedbbdf6053c252c0fa3350Jaewan Kim return mPlaylistMetadata; 614df4f8498f40e995abeedbbdf6053c252c0fa3350Jaewan Kim } 615df4f8498f40e995abeedbbdf6053c252c0fa3350Jaewan Kim } 616df4f8498f40e995abeedbbdf6053c252c0fa3350Jaewan Kim 617df4f8498f40e995abeedbbdf6053c252c0fa3350Jaewan Kim @Override 618df4f8498f40e995abeedbbdf6053c252c0fa3350Jaewan Kim public void updatePlaylistMetadata_impl(MediaMetadata2 metadata) { 619df4f8498f40e995abeedbbdf6053c252c0fa3350Jaewan Kim final IMediaSession2 binder = getSessionBinderIfAble( 620df4f8498f40e995abeedbbdf6053c252c0fa3350Jaewan Kim COMMAND_CODE_PLAYLIST_SET_LIST_METADATA); 621df4f8498f40e995abeedbbdf6053c252c0fa3350Jaewan Kim if (binder != null) { 622df4f8498f40e995abeedbbdf6053c252c0fa3350Jaewan Kim Bundle metadataBundle = (metadata == null) ? null : metadata.toBundle(); 623df4f8498f40e995abeedbbdf6053c252c0fa3350Jaewan Kim try { 62498f280314350160874af3bc3fd660aa3e9a0fabeSungsoo Lim binder.updatePlaylistMetadata(mControllerStub, metadataBundle); 625df4f8498f40e995abeedbbdf6053c252c0fa3350Jaewan Kim } catch (RemoteException e) { 626df4f8498f40e995abeedbbdf6053c252c0fa3350Jaewan Kim Log.w(TAG, "Cannot connect to the service or the session is gone", e); 627df4f8498f40e995abeedbbdf6053c252c0fa3350Jaewan Kim } 628df4f8498f40e995abeedbbdf6053c252c0fa3350Jaewan Kim } else { 629df4f8498f40e995abeedbbdf6053c252c0fa3350Jaewan Kim Log.w(TAG, "Session isn't active", new IllegalStateException()); 630df4f8498f40e995abeedbbdf6053c252c0fa3350Jaewan Kim } 631df4f8498f40e995abeedbbdf6053c252c0fa3350Jaewan Kim } 632df4f8498f40e995abeedbbdf6053c252c0fa3350Jaewan Kim 633df4f8498f40e995abeedbbdf6053c252c0fa3350Jaewan Kim @Override 634da59499289a68a2558370b6acfd4096d3feb8107Jaewan Kim public void prepare_impl() { 635d5b878d0cf0c987caf18be697a0e1637fb632d66Jaewan Kim sendTransportControlCommand(SessionCommand2.COMMAND_CODE_PLAYBACK_PREPARE); 636da59499289a68a2558370b6acfd4096d3feb8107Jaewan Kim } 637da59499289a68a2558370b6acfd4096d3feb8107Jaewan Kim 638da59499289a68a2558370b6acfd4096d3feb8107Jaewan Kim @Override 639da59499289a68a2558370b6acfd4096d3feb8107Jaewan Kim public void fastForward_impl() { 640076d7da0936e85fc5243761ffd393d5c2beeee20Jaewan Kim // TODO(jaewan): Implement this. Note that fast forward isn't a transport command anymore 641076d7da0936e85fc5243761ffd393d5c2beeee20Jaewan Kim //sendTransportControlCommand(MediaSession2.COMMAND_CODE_SESSION_FAST_FORWARD); 642da59499289a68a2558370b6acfd4096d3feb8107Jaewan Kim } 643da59499289a68a2558370b6acfd4096d3feb8107Jaewan Kim 644da59499289a68a2558370b6acfd4096d3feb8107Jaewan Kim @Override 645da59499289a68a2558370b6acfd4096d3feb8107Jaewan Kim public void rewind_impl() { 646076d7da0936e85fc5243761ffd393d5c2beeee20Jaewan Kim // TODO(jaewan): Implement this. Note that rewind isn't a transport command anymore 647076d7da0936e85fc5243761ffd393d5c2beeee20Jaewan Kim //sendTransportControlCommand(MediaSession2.COMMAND_CODE_SESSION_REWIND); 648da59499289a68a2558370b6acfd4096d3feb8107Jaewan Kim } 649da59499289a68a2558370b6acfd4096d3feb8107Jaewan Kim 650da59499289a68a2558370b6acfd4096d3feb8107Jaewan Kim @Override 651da59499289a68a2558370b6acfd4096d3feb8107Jaewan Kim public void seekTo_impl(long pos) { 65298fdf3583d3bfd1178ef1e0102e3de6d2b1dd2bcHyundo Moon if (pos < 0) { 65398fdf3583d3bfd1178ef1e0102e3de6d2b1dd2bcHyundo Moon throw new IllegalArgumentException("position shouldn't be negative"); 65498fdf3583d3bfd1178ef1e0102e3de6d2b1dd2bcHyundo Moon } 655e71339cbe74fc7b87c822ae95d1c842d7944942bHyundo Moon Bundle args = new Bundle(); 656e71339cbe74fc7b87c822ae95d1c842d7944942bHyundo Moon args.putLong(MediaSession2Stub.ARGUMENT_KEY_POSITION, pos); 657d5b878d0cf0c987caf18be697a0e1637fb632d66Jaewan Kim sendTransportControlCommand(SessionCommand2.COMMAND_CODE_PLAYBACK_SEEK_TO, args); 658da59499289a68a2558370b6acfd4096d3feb8107Jaewan Kim } 659da59499289a68a2558370b6acfd4096d3feb8107Jaewan Kim 660da59499289a68a2558370b6acfd4096d3feb8107Jaewan Kim @Override 661f82f720c00cf35a8f0f9a6135551ee47855dd6a0Sungsoo Lim public void addPlaylistItem_impl(int index, MediaItem2 item) { 66298fdf3583d3bfd1178ef1e0102e3de6d2b1dd2bcHyundo Moon if (index < 0) { 66398fdf3583d3bfd1178ef1e0102e3de6d2b1dd2bcHyundo Moon throw new IllegalArgumentException("index shouldn't be negative"); 66498fdf3583d3bfd1178ef1e0102e3de6d2b1dd2bcHyundo Moon } 66598fdf3583d3bfd1178ef1e0102e3de6d2b1dd2bcHyundo Moon if (item == null) { 66698fdf3583d3bfd1178ef1e0102e3de6d2b1dd2bcHyundo Moon throw new IllegalArgumentException("item shouldn't be null"); 66798fdf3583d3bfd1178ef1e0102e3de6d2b1dd2bcHyundo Moon } 66824ab94cf1e42ea5bcfedebff29fd7a237641f6dfJaewan Kim final IMediaSession2 binder = getSessionBinderIfAble(COMMAND_CODE_PLAYLIST_ADD_ITEM); 66924ab94cf1e42ea5bcfedebff29fd7a237641f6dfJaewan Kim if (binder != null) { 67024ab94cf1e42ea5bcfedebff29fd7a237641f6dfJaewan Kim try { 67198f280314350160874af3bc3fd660aa3e9a0fabeSungsoo Lim binder.addPlaylistItem(mControllerStub, index, item.toBundle()); 67224ab94cf1e42ea5bcfedebff29fd7a237641f6dfJaewan Kim } catch (RemoteException e) { 67324ab94cf1e42ea5bcfedebff29fd7a237641f6dfJaewan Kim Log.w(TAG, "Cannot connect to the service or the session is gone", e); 67424ab94cf1e42ea5bcfedebff29fd7a237641f6dfJaewan Kim } 67524ab94cf1e42ea5bcfedebff29fd7a237641f6dfJaewan Kim } else { 67624ab94cf1e42ea5bcfedebff29fd7a237641f6dfJaewan Kim Log.w(TAG, "Session isn't active", new IllegalStateException()); 67724ab94cf1e42ea5bcfedebff29fd7a237641f6dfJaewan Kim } 678da59499289a68a2558370b6acfd4096d3feb8107Jaewan Kim } 679da59499289a68a2558370b6acfd4096d3feb8107Jaewan Kim 680da59499289a68a2558370b6acfd4096d3feb8107Jaewan Kim @Override 681f82f720c00cf35a8f0f9a6135551ee47855dd6a0Sungsoo Lim public void removePlaylistItem_impl(MediaItem2 item) { 68298fdf3583d3bfd1178ef1e0102e3de6d2b1dd2bcHyundo Moon if (item == null) { 68398fdf3583d3bfd1178ef1e0102e3de6d2b1dd2bcHyundo Moon throw new IllegalArgumentException("item shouldn't be null"); 68498fdf3583d3bfd1178ef1e0102e3de6d2b1dd2bcHyundo Moon } 68524ab94cf1e42ea5bcfedebff29fd7a237641f6dfJaewan Kim final IMediaSession2 binder = getSessionBinderIfAble(COMMAND_CODE_PLAYLIST_REMOVE_ITEM); 68624ab94cf1e42ea5bcfedebff29fd7a237641f6dfJaewan Kim if (binder != null) { 68724ab94cf1e42ea5bcfedebff29fd7a237641f6dfJaewan Kim try { 68898f280314350160874af3bc3fd660aa3e9a0fabeSungsoo Lim binder.removePlaylistItem(mControllerStub, item.toBundle()); 68924ab94cf1e42ea5bcfedebff29fd7a237641f6dfJaewan Kim } catch (RemoteException e) { 69024ab94cf1e42ea5bcfedebff29fd7a237641f6dfJaewan Kim Log.w(TAG, "Cannot connect to the service or the session is gone", e); 69124ab94cf1e42ea5bcfedebff29fd7a237641f6dfJaewan Kim } 69224ab94cf1e42ea5bcfedebff29fd7a237641f6dfJaewan Kim } else { 69324ab94cf1e42ea5bcfedebff29fd7a237641f6dfJaewan Kim Log.w(TAG, "Session isn't active", new IllegalStateException()); 69424ab94cf1e42ea5bcfedebff29fd7a237641f6dfJaewan Kim } 695da59499289a68a2558370b6acfd4096d3feb8107Jaewan Kim } 696da59499289a68a2558370b6acfd4096d3feb8107Jaewan Kim 697da59499289a68a2558370b6acfd4096d3feb8107Jaewan Kim @Override 698414ef561baf181397ecab5aac0e4a3ce66a9fd96Jean-Michel Trivi public void replacePlaylistItem_impl(int index, MediaItem2 item) { 69998fdf3583d3bfd1178ef1e0102e3de6d2b1dd2bcHyundo Moon if (index < 0) { 70098fdf3583d3bfd1178ef1e0102e3de6d2b1dd2bcHyundo Moon throw new IllegalArgumentException("index shouldn't be negative"); 70198fdf3583d3bfd1178ef1e0102e3de6d2b1dd2bcHyundo Moon } 70298fdf3583d3bfd1178ef1e0102e3de6d2b1dd2bcHyundo Moon if (item == null) { 70398fdf3583d3bfd1178ef1e0102e3de6d2b1dd2bcHyundo Moon throw new IllegalArgumentException("item shouldn't be null"); 70498fdf3583d3bfd1178ef1e0102e3de6d2b1dd2bcHyundo Moon } 70524ab94cf1e42ea5bcfedebff29fd7a237641f6dfJaewan Kim final IMediaSession2 binder = getSessionBinderIfAble(COMMAND_CODE_PLAYLIST_REPLACE_ITEM); 70624ab94cf1e42ea5bcfedebff29fd7a237641f6dfJaewan Kim if (binder != null) { 70724ab94cf1e42ea5bcfedebff29fd7a237641f6dfJaewan Kim try { 70898f280314350160874af3bc3fd660aa3e9a0fabeSungsoo Lim binder.replacePlaylistItem(mControllerStub, index, item.toBundle()); 70924ab94cf1e42ea5bcfedebff29fd7a237641f6dfJaewan Kim } catch (RemoteException e) { 71024ab94cf1e42ea5bcfedebff29fd7a237641f6dfJaewan Kim Log.w(TAG, "Cannot connect to the service or the session is gone", e); 71124ab94cf1e42ea5bcfedebff29fd7a237641f6dfJaewan Kim } 71224ab94cf1e42ea5bcfedebff29fd7a237641f6dfJaewan Kim } else { 71324ab94cf1e42ea5bcfedebff29fd7a237641f6dfJaewan Kim Log.w(TAG, "Session isn't active", new IllegalStateException()); 71424ab94cf1e42ea5bcfedebff29fd7a237641f6dfJaewan Kim } 715414ef561baf181397ecab5aac0e4a3ce66a9fd96Jean-Michel Trivi } 716414ef561baf181397ecab5aac0e4a3ce66a9fd96Jean-Michel Trivi 717414ef561baf181397ecab5aac0e4a3ce66a9fd96Jean-Michel Trivi @Override 71844648206f6a9c66f9f9478a8091685cb702349eeJaewan Kim public int getShuffleMode_impl() { 71944648206f6a9c66f9f9478a8091685cb702349eeJaewan Kim return mShuffleMode; 72044648206f6a9c66f9f9478a8091685cb702349eeJaewan Kim } 72144648206f6a9c66f9f9478a8091685cb702349eeJaewan Kim 72244648206f6a9c66f9f9478a8091685cb702349eeJaewan Kim @Override 72344648206f6a9c66f9f9478a8091685cb702349eeJaewan Kim public void setShuffleMode_impl(int shuffleMode) { 72444648206f6a9c66f9f9478a8091685cb702349eeJaewan Kim final IMediaSession2 binder = getSessionBinderIfAble( 72544648206f6a9c66f9f9478a8091685cb702349eeJaewan Kim COMMAND_CODE_PLAYLIST_SET_SHUFFLE_MODE); 72644648206f6a9c66f9f9478a8091685cb702349eeJaewan Kim if (binder != null) { 72744648206f6a9c66f9f9478a8091685cb702349eeJaewan Kim try { 72844648206f6a9c66f9f9478a8091685cb702349eeJaewan Kim binder.setShuffleMode(mControllerStub, shuffleMode); 72944648206f6a9c66f9f9478a8091685cb702349eeJaewan Kim } catch (RemoteException e) { 73044648206f6a9c66f9f9478a8091685cb702349eeJaewan Kim Log.w(TAG, "Cannot connect to the service or the session is gone", e); 73144648206f6a9c66f9f9478a8091685cb702349eeJaewan Kim } 73244648206f6a9c66f9f9478a8091685cb702349eeJaewan Kim } else { 73344648206f6a9c66f9f9478a8091685cb702349eeJaewan Kim Log.w(TAG, "Session isn't active", new IllegalStateException()); 734e71339cbe74fc7b87c822ae95d1c842d7944942bHyundo Moon } 73535a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim } 73635a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim 737621289a788c968d46df85ff238c3e41cf0f34476Jaewan Kim @Override 73844648206f6a9c66f9f9478a8091685cb702349eeJaewan Kim public int getRepeatMode_impl() { 73944648206f6a9c66f9f9478a8091685cb702349eeJaewan Kim return mRepeatMode; 74044648206f6a9c66f9f9478a8091685cb702349eeJaewan Kim } 74144648206f6a9c66f9f9478a8091685cb702349eeJaewan Kim 74244648206f6a9c66f9f9478a8091685cb702349eeJaewan Kim @Override 74344648206f6a9c66f9f9478a8091685cb702349eeJaewan Kim public void setRepeatMode_impl(int repeatMode) { 74444648206f6a9c66f9f9478a8091685cb702349eeJaewan Kim final IMediaSession2 binder = getSessionBinderIfAble(COMMAND_CODE_PLAYLIST_SET_REPEAT_MODE); 74544648206f6a9c66f9f9478a8091685cb702349eeJaewan Kim if (binder != null) { 74644648206f6a9c66f9f9478a8091685cb702349eeJaewan Kim try { 74744648206f6a9c66f9f9478a8091685cb702349eeJaewan Kim binder.setRepeatMode(mControllerStub, repeatMode); 74844648206f6a9c66f9f9478a8091685cb702349eeJaewan Kim } catch (RemoteException e) { 74944648206f6a9c66f9f9478a8091685cb702349eeJaewan Kim Log.w(TAG, "Cannot connect to the service or the session is gone", e); 75044648206f6a9c66f9f9478a8091685cb702349eeJaewan Kim } 75144648206f6a9c66f9f9478a8091685cb702349eeJaewan Kim } else { 75244648206f6a9c66f9f9478a8091685cb702349eeJaewan Kim Log.w(TAG, "Session isn't active", new IllegalStateException()); 753c81e4db8363fb9736bc2362f0ff213b5d9e33ac3Hyundo Moon } 754c81e4db8363fb9736bc2362f0ff213b5d9e33ac3Hyundo Moon } 755c81e4db8363fb9736bc2362f0ff213b5d9e33ac3Hyundo Moon 756c81e4db8363fb9736bc2362f0ff213b5d9e33ac3Hyundo Moon @Override 75744648206f6a9c66f9f9478a8091685cb702349eeJaewan Kim public PlaybackInfo getPlaybackInfo_impl() { 75844648206f6a9c66f9f9478a8091685cb702349eeJaewan Kim synchronized (mLock) { 75944648206f6a9c66f9f9478a8091685cb702349eeJaewan Kim return mPlaybackInfo; 760e71339cbe74fc7b87c822ae95d1c842d7944942bHyundo Moon } 761621289a788c968d46df85ff238c3e41cf0f34476Jaewan Kim } 762621289a788c968d46df85ff238c3e41cf0f34476Jaewan Kim 76381c1b87234bdab435259acd355ba2df4730da3ceJaewan Kim @Override 76481c1b87234bdab435259acd355ba2df4730da3ceJaewan Kim public int getPlayerState_impl() { 76579f5e126cb9a8c6f72904d8cb4c611ee69405993Hyundo Moon synchronized (mLock) { 76679f5e126cb9a8c6f72904d8cb4c611ee69405993Hyundo Moon return mPlayerState; 76779f5e126cb9a8c6f72904d8cb4c611ee69405993Hyundo Moon } 76881c1b87234bdab435259acd355ba2df4730da3ceJaewan Kim } 76981c1b87234bdab435259acd355ba2df4730da3ceJaewan Kim 77081c1b87234bdab435259acd355ba2df4730da3ceJaewan Kim @Override 7711fe063606ecf3ef1fd71496bc2bcdd0d8ce8342dJaewan Kim public long getCurrentPosition_impl() { 77279f5e126cb9a8c6f72904d8cb4c611ee69405993Hyundo Moon synchronized (mLock) { 77379f5e126cb9a8c6f72904d8cb4c611ee69405993Hyundo Moon long timeDiff = System.currentTimeMillis() - mPositionEventTimeMs; 77479f5e126cb9a8c6f72904d8cb4c611ee69405993Hyundo Moon long expectedPosition = mPositionMs + (long) (mPlaybackSpeed * timeDiff); 77579f5e126cb9a8c6f72904d8cb4c611ee69405993Hyundo Moon return Math.max(0, expectedPosition); 77679f5e126cb9a8c6f72904d8cb4c611ee69405993Hyundo Moon } 77781c1b87234bdab435259acd355ba2df4730da3ceJaewan Kim } 77881c1b87234bdab435259acd355ba2df4730da3ceJaewan Kim 77981c1b87234bdab435259acd355ba2df4730da3ceJaewan Kim @Override 78081c1b87234bdab435259acd355ba2df4730da3ceJaewan Kim public float getPlaybackSpeed_impl() { 78179f5e126cb9a8c6f72904d8cb4c611ee69405993Hyundo Moon synchronized (mLock) { 78279f5e126cb9a8c6f72904d8cb4c611ee69405993Hyundo Moon return mPlaybackSpeed; 78379f5e126cb9a8c6f72904d8cb4c611ee69405993Hyundo Moon } 78481c1b87234bdab435259acd355ba2df4730da3ceJaewan Kim } 78581c1b87234bdab435259acd355ba2df4730da3ceJaewan Kim 78681c1b87234bdab435259acd355ba2df4730da3ceJaewan Kim @Override 78781c1b87234bdab435259acd355ba2df4730da3ceJaewan Kim public long getBufferedPosition_impl() { 78879f5e126cb9a8c6f72904d8cb4c611ee69405993Hyundo Moon synchronized (mLock) { 78979f5e126cb9a8c6f72904d8cb4c611ee69405993Hyundo Moon return mBufferedPositionMs; 79079f5e126cb9a8c6f72904d8cb4c611ee69405993Hyundo Moon } 79181c1b87234bdab435259acd355ba2df4730da3ceJaewan Kim } 79281c1b87234bdab435259acd355ba2df4730da3ceJaewan Kim 79381c1b87234bdab435259acd355ba2df4730da3ceJaewan Kim @Override 794c8508bf04576790230c5a32b329a4b47468ac7fbJaewan Kim public MediaItem2 getCurrentMediaItem_impl() { 79581c1b87234bdab435259acd355ba2df4730da3ceJaewan Kim // TODO(jaewan): Implement 79681c1b87234bdab435259acd355ba2df4730da3ceJaewan Kim return null; 79781c1b87234bdab435259acd355ba2df4730da3ceJaewan Kim } 79881c1b87234bdab435259acd355ba2df4730da3ceJaewan Kim 79979f5e126cb9a8c6f72904d8cb4c611ee69405993Hyundo Moon void pushPlayerStateChanges(final int state) { 80079f5e126cb9a8c6f72904d8cb4c611ee69405993Hyundo Moon synchronized (mLock) { 80179f5e126cb9a8c6f72904d8cb4c611ee69405993Hyundo Moon mPlayerState = state; 80279f5e126cb9a8c6f72904d8cb4c611ee69405993Hyundo Moon } 80379f5e126cb9a8c6f72904d8cb4c611ee69405993Hyundo Moon mCallbackExecutor.execute(() -> { 80479f5e126cb9a8c6f72904d8cb4c611ee69405993Hyundo Moon if (!mInstance.isConnected()) { 80579f5e126cb9a8c6f72904d8cb4c611ee69405993Hyundo Moon return; 80679f5e126cb9a8c6f72904d8cb4c611ee69405993Hyundo Moon } 80779f5e126cb9a8c6f72904d8cb4c611ee69405993Hyundo Moon mCallback.onPlayerStateChanged(mInstance, state); 80879f5e126cb9a8c6f72904d8cb4c611ee69405993Hyundo Moon }); 80979f5e126cb9a8c6f72904d8cb4c611ee69405993Hyundo Moon } 81079f5e126cb9a8c6f72904d8cb4c611ee69405993Hyundo Moon 8114a7b86426b7139dae80d1362eddb842e675bc069Jaewan Kim // TODO(jaewan): Rename to seek completed 81279f5e126cb9a8c6f72904d8cb4c611ee69405993Hyundo Moon void pushPositionChanges(final long eventTimeMs, final long positionMs) { 81379f5e126cb9a8c6f72904d8cb4c611ee69405993Hyundo Moon synchronized (mLock) { 81479f5e126cb9a8c6f72904d8cb4c611ee69405993Hyundo Moon mPositionEventTimeMs = eventTimeMs; 81579f5e126cb9a8c6f72904d8cb4c611ee69405993Hyundo Moon mPositionMs = positionMs; 81679f5e126cb9a8c6f72904d8cb4c611ee69405993Hyundo Moon } 81779f5e126cb9a8c6f72904d8cb4c611ee69405993Hyundo Moon mCallbackExecutor.execute(() -> { 81879f5e126cb9a8c6f72904d8cb4c611ee69405993Hyundo Moon if (!mInstance.isConnected()) { 81979f5e126cb9a8c6f72904d8cb4c611ee69405993Hyundo Moon return; 82079f5e126cb9a8c6f72904d8cb4c611ee69405993Hyundo Moon } 8214a7b86426b7139dae80d1362eddb842e675bc069Jaewan Kim mCallback.onSeekCompleted(mInstance, positionMs); 82279f5e126cb9a8c6f72904d8cb4c611ee69405993Hyundo Moon }); 82379f5e126cb9a8c6f72904d8cb4c611ee69405993Hyundo Moon } 82479f5e126cb9a8c6f72904d8cb4c611ee69405993Hyundo Moon 82579f5e126cb9a8c6f72904d8cb4c611ee69405993Hyundo Moon void pushPlaybackSpeedChanges(final float speed) { 82679f5e126cb9a8c6f72904d8cb4c611ee69405993Hyundo Moon synchronized (mLock) { 82779f5e126cb9a8c6f72904d8cb4c611ee69405993Hyundo Moon mPlaybackSpeed = speed; 82879f5e126cb9a8c6f72904d8cb4c611ee69405993Hyundo Moon } 82979f5e126cb9a8c6f72904d8cb4c611ee69405993Hyundo Moon mCallbackExecutor.execute(() -> { 83079f5e126cb9a8c6f72904d8cb4c611ee69405993Hyundo Moon if (!mInstance.isConnected()) { 83179f5e126cb9a8c6f72904d8cb4c611ee69405993Hyundo Moon return; 83279f5e126cb9a8c6f72904d8cb4c611ee69405993Hyundo Moon } 83379f5e126cb9a8c6f72904d8cb4c611ee69405993Hyundo Moon mCallback.onPlaybackSpeedChanged(mInstance, speed); 83479f5e126cb9a8c6f72904d8cb4c611ee69405993Hyundo Moon }); 83579f5e126cb9a8c6f72904d8cb4c611ee69405993Hyundo Moon } 83679f5e126cb9a8c6f72904d8cb4c611ee69405993Hyundo Moon 83779f5e126cb9a8c6f72904d8cb4c611ee69405993Hyundo Moon void pushBufferedPositionChanges(final long bufferedPositionMs) { 83835a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim synchronized (mLock) { 83979f5e126cb9a8c6f72904d8cb4c611ee69405993Hyundo Moon mBufferedPositionMs = bufferedPositionMs; 84035a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim } 841e71339cbe74fc7b87c822ae95d1c842d7944942bHyundo Moon mCallbackExecutor.execute(() -> { 842e71339cbe74fc7b87c822ae95d1c842d7944942bHyundo Moon if (!mInstance.isConnected()) { 843e71339cbe74fc7b87c822ae95d1c842d7944942bHyundo Moon return; 844e71339cbe74fc7b87c822ae95d1c842d7944942bHyundo Moon } 8451fe063606ecf3ef1fd71496bc2bcdd0d8ce8342dJaewan Kim // TODO(jaewan): Fix this -- it's now buffered state 8461fe063606ecf3ef1fd71496bc2bcdd0d8ce8342dJaewan Kim //mCallback.onBufferedPositionChanged(mInstance, bufferedPositionMs); 847e71339cbe74fc7b87c822ae95d1c842d7944942bHyundo Moon }); 848e71339cbe74fc7b87c822ae95d1c842d7944942bHyundo Moon } 849e71339cbe74fc7b87c822ae95d1c842d7944942bHyundo Moon 85044648206f6a9c66f9f9478a8091685cb702349eeJaewan Kim void pushPlaybackInfoChanges(final PlaybackInfo info) { 851e71339cbe74fc7b87c822ae95d1c842d7944942bHyundo Moon synchronized (mLock) { 85244648206f6a9c66f9f9478a8091685cb702349eeJaewan Kim mPlaybackInfo = info; 853e71339cbe74fc7b87c822ae95d1c842d7944942bHyundo Moon } 854e71339cbe74fc7b87c822ae95d1c842d7944942bHyundo Moon mCallbackExecutor.execute(() -> { 855e71339cbe74fc7b87c822ae95d1c842d7944942bHyundo Moon if (!mInstance.isConnected()) { 856e71339cbe74fc7b87c822ae95d1c842d7944942bHyundo Moon return; 857e71339cbe74fc7b87c822ae95d1c842d7944942bHyundo Moon } 85844648206f6a9c66f9f9478a8091685cb702349eeJaewan Kim mCallback.onPlaybackInfoChanged(mInstance, info); 859e71339cbe74fc7b87c822ae95d1c842d7944942bHyundo Moon }); 86035a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim } 86135a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim 86244648206f6a9c66f9f9478a8091685cb702349eeJaewan Kim void pushPlaylistChanges(final List<MediaItem2> playlist, final MediaMetadata2 metadata) { 863c81e4db8363fb9736bc2362f0ff213b5d9e33ac3Hyundo Moon synchronized (mLock) { 86444648206f6a9c66f9f9478a8091685cb702349eeJaewan Kim mPlaylist = playlist; 86544648206f6a9c66f9f9478a8091685cb702349eeJaewan Kim mPlaylistMetadata = metadata; 866c81e4db8363fb9736bc2362f0ff213b5d9e33ac3Hyundo Moon } 867c81e4db8363fb9736bc2362f0ff213b5d9e33ac3Hyundo Moon mCallbackExecutor.execute(() -> { 868c81e4db8363fb9736bc2362f0ff213b5d9e33ac3Hyundo Moon if (!mInstance.isConnected()) { 869c81e4db8363fb9736bc2362f0ff213b5d9e33ac3Hyundo Moon return; 870c81e4db8363fb9736bc2362f0ff213b5d9e33ac3Hyundo Moon } 871cf1e1332e0b6880b4776d0bab31506092163423fJaewan Kim mCallback.onPlaylistChanged(mInstance, playlist, metadata); 872c81e4db8363fb9736bc2362f0ff213b5d9e33ac3Hyundo Moon }); 873c81e4db8363fb9736bc2362f0ff213b5d9e33ac3Hyundo Moon } 874c81e4db8363fb9736bc2362f0ff213b5d9e33ac3Hyundo Moon 87544648206f6a9c66f9f9478a8091685cb702349eeJaewan Kim void pushPlaylistMetadataChanges(MediaMetadata2 metadata) { 8763923b1b71628e668f9b11ed4891ed2840dd331cdHyundo Moon synchronized (mLock) { 877e0a38c69b26945394936922dd837cc7e9fa37d3cJaewan Kim mPlaylistMetadata = metadata; 8783923b1b71628e668f9b11ed4891ed2840dd331cdHyundo Moon } 879e0a38c69b26945394936922dd837cc7e9fa37d3cJaewan Kim mCallbackExecutor.execute(() -> { 880e0a38c69b26945394936922dd837cc7e9fa37d3cJaewan Kim if (!mInstance.isConnected()) { 881e0a38c69b26945394936922dd837cc7e9fa37d3cJaewan Kim return; 882e0a38c69b26945394936922dd837cc7e9fa37d3cJaewan Kim } 883cf1e1332e0b6880b4776d0bab31506092163423fJaewan Kim mCallback.onPlaylistMetadataChanged(mInstance, metadata); 884e0a38c69b26945394936922dd837cc7e9fa37d3cJaewan Kim }); 8853923b1b71628e668f9b11ed4891ed2840dd331cdHyundo Moon } 8863923b1b71628e668f9b11ed4891ed2840dd331cdHyundo Moon 88744648206f6a9c66f9f9478a8091685cb702349eeJaewan Kim void pushShuffleModeChanges(int shuffleMode) { 888df4f8498f40e995abeedbbdf6053c252c0fa3350Jaewan Kim synchronized (mLock) { 88944648206f6a9c66f9f9478a8091685cb702349eeJaewan Kim mShuffleMode = shuffleMode; 890df4f8498f40e995abeedbbdf6053c252c0fa3350Jaewan Kim } 891df4f8498f40e995abeedbbdf6053c252c0fa3350Jaewan Kim mCallbackExecutor.execute(() -> { 892df4f8498f40e995abeedbbdf6053c252c0fa3350Jaewan Kim if (!mInstance.isConnected()) { 893df4f8498f40e995abeedbbdf6053c252c0fa3350Jaewan Kim return; 894df4f8498f40e995abeedbbdf6053c252c0fa3350Jaewan Kim } 895cf1e1332e0b6880b4776d0bab31506092163423fJaewan Kim mCallback.onShuffleModeChanged(mInstance, shuffleMode); 89644648206f6a9c66f9f9478a8091685cb702349eeJaewan Kim }); 89744648206f6a9c66f9f9478a8091685cb702349eeJaewan Kim } 89844648206f6a9c66f9f9478a8091685cb702349eeJaewan Kim 89944648206f6a9c66f9f9478a8091685cb702349eeJaewan Kim void pushRepeatModeChanges(int repeatMode) { 90044648206f6a9c66f9f9478a8091685cb702349eeJaewan Kim synchronized (mLock) { 90144648206f6a9c66f9f9478a8091685cb702349eeJaewan Kim mRepeatMode = repeatMode; 90244648206f6a9c66f9f9478a8091685cb702349eeJaewan Kim } 90344648206f6a9c66f9f9478a8091685cb702349eeJaewan Kim mCallbackExecutor.execute(() -> { 90444648206f6a9c66f9f9478a8091685cb702349eeJaewan Kim if (!mInstance.isConnected()) { 90544648206f6a9c66f9f9478a8091685cb702349eeJaewan Kim return; 90644648206f6a9c66f9f9478a8091685cb702349eeJaewan Kim } 907cf1e1332e0b6880b4776d0bab31506092163423fJaewan Kim mCallback.onRepeatModeChanged(mInstance, repeatMode); 908df4f8498f40e995abeedbbdf6053c252c0fa3350Jaewan Kim }); 909df4f8498f40e995abeedbbdf6053c252c0fa3350Jaewan Kim } 910df4f8498f40e995abeedbbdf6053c252c0fa3350Jaewan Kim 9116ae7465a068f4a63d679423a83c786f77e034b3cHyundo Moon void pushError(int errorCode, Bundle extras) { 9126ae7465a068f4a63d679423a83c786f77e034b3cHyundo Moon mCallbackExecutor.execute(() -> { 9136ae7465a068f4a63d679423a83c786f77e034b3cHyundo Moon if (!mInstance.isConnected()) { 9146ae7465a068f4a63d679423a83c786f77e034b3cHyundo Moon return; 9156ae7465a068f4a63d679423a83c786f77e034b3cHyundo Moon } 9166ae7465a068f4a63d679423a83c786f77e034b3cHyundo Moon mCallback.onError(mInstance, errorCode, extras); 9176ae7465a068f4a63d679423a83c786f77e034b3cHyundo Moon }); 9186ae7465a068f4a63d679423a83c786f77e034b3cHyundo Moon } 9196ae7465a068f4a63d679423a83c786f77e034b3cHyundo Moon 92035a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim // Should be used without a lock to prevent potential deadlock. 921b41bfb59dd52decb1e5c5952d6ed786f159d772dJaewan Kim void onConnectedNotLocked(IMediaSession2 sessionBinder, 922d5b878d0cf0c987caf18be697a0e1637fb632d66Jaewan Kim final SessionCommandGroup2 allowedCommands, 92379f5e126cb9a8c6f72904d8cb4c611ee69405993Hyundo Moon final int playerState, 92479f5e126cb9a8c6f72904d8cb4c611ee69405993Hyundo Moon final long positionEventTimeMs, 92579f5e126cb9a8c6f72904d8cb4c611ee69405993Hyundo Moon final long positionMs, 92679f5e126cb9a8c6f72904d8cb4c611ee69405993Hyundo Moon final float playbackSpeed, 92779f5e126cb9a8c6f72904d8cb4c611ee69405993Hyundo Moon final long bufferedPositionMs, 92879f5e126cb9a8c6f72904d8cb4c611ee69405993Hyundo Moon final PlaybackInfo info, 92944648206f6a9c66f9f9478a8091685cb702349eeJaewan Kim final int repeatMode, 93044648206f6a9c66f9f9478a8091685cb702349eeJaewan Kim final int shuffleMode, 93144648206f6a9c66f9f9478a8091685cb702349eeJaewan Kim final List<MediaItem2> playlist, 9320261708bf17cb0469de8eb3c81455e2f48ff9433Jaewan Kim final PendingIntent sessionActivity) { 93335a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim if (DEBUG) { 934c4a9db19b2c4a4bf1283dd060147e17e48142beeJaewan Kim Log.d(TAG, "onConnectedNotLocked sessionBinder=" + sessionBinder 935483261f98e9eeb6191d42873970a2ae9709ac1fcJaewan Kim + ", allowedCommands=" + allowedCommands); 93635a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim } 937c4a9db19b2c4a4bf1283dd060147e17e48142beeJaewan Kim boolean close = false; 93835a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim try { 939483261f98e9eeb6191d42873970a2ae9709ac1fcJaewan Kim if (sessionBinder == null || allowedCommands == null) { 94035a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim // Connection rejected. 941c4a9db19b2c4a4bf1283dd060147e17e48142beeJaewan Kim close = true; 94235a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim return; 94335a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim } 94435a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim synchronized (mLock) { 94535a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim if (mIsReleased) { 94635a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim return; 94735a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim } 94835a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim if (mSessionBinder != null) { 94935a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim Log.e(TAG, "Cannot be notified about the connection result many times." 95035a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim + " Probably a bug or malicious app."); 951c4a9db19b2c4a4bf1283dd060147e17e48142beeJaewan Kim close = true; 95235a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim return; 95335a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim } 954483261f98e9eeb6191d42873970a2ae9709ac1fcJaewan Kim mAllowedCommands = allowedCommands; 95579f5e126cb9a8c6f72904d8cb4c611ee69405993Hyundo Moon mPlayerState = playerState; 95679f5e126cb9a8c6f72904d8cb4c611ee69405993Hyundo Moon mPositionEventTimeMs = positionEventTimeMs; 95779f5e126cb9a8c6f72904d8cb4c611ee69405993Hyundo Moon mPositionMs = positionMs; 95879f5e126cb9a8c6f72904d8cb4c611ee69405993Hyundo Moon mPlaybackSpeed = playbackSpeed; 95979f5e126cb9a8c6f72904d8cb4c611ee69405993Hyundo Moon mBufferedPositionMs = bufferedPositionMs; 9600261708bf17cb0469de8eb3c81455e2f48ff9433Jaewan Kim mPlaybackInfo = info; 96144648206f6a9c66f9f9478a8091685cb702349eeJaewan Kim mRepeatMode = repeatMode; 96244648206f6a9c66f9f9478a8091685cb702349eeJaewan Kim mShuffleMode = shuffleMode; 9630261708bf17cb0469de8eb3c81455e2f48ff9433Jaewan Kim mPlaylist = playlist; 9640261708bf17cb0469de8eb3c81455e2f48ff9433Jaewan Kim mSessionActivity = sessionActivity; 96535a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim mSessionBinder = sessionBinder; 96635a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim try { 96735a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim // Implementation for the local binder is no-op, 96835a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim // so can be used without worrying about deadlock. 96935a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim mSessionBinder.asBinder().linkToDeath(mDeathRecipient, 0); 97035a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim } catch (RemoteException e) { 9715aec249a238ff2dcb9bb5bc0434b7a17fa96a035Jaewan Kim if (DEBUG) { 9725aec249a238ff2dcb9bb5bc0434b7a17fa96a035Jaewan Kim Log.d(TAG, "Session died too early.", e); 9735aec249a238ff2dcb9bb5bc0434b7a17fa96a035Jaewan Kim } 974c4a9db19b2c4a4bf1283dd060147e17e48142beeJaewan Kim close = true; 97535a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim return; 97635a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim } 97735a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim } 97835a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim // TODO(jaewan): Keep commands to prevents illegal API calls. 97935a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim mCallbackExecutor.execute(() -> { 980c4a9db19b2c4a4bf1283dd060147e17e48142beeJaewan Kim // Note: We may trigger ControllerCallbacks with the initial values 981c4a9db19b2c4a4bf1283dd060147e17e48142beeJaewan Kim // But it's hard to define the order of the controller callbacks 982c4a9db19b2c4a4bf1283dd060147e17e48142beeJaewan Kim // Only notify about the 983d3d75358db7e3fe87805f1d91aa53abe1b0c2e92Jaewan Kim mCallback.onConnected(mInstance, allowedCommands); 98435a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim }); 98535a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim } finally { 986c4a9db19b2c4a4bf1283dd060147e17e48142beeJaewan Kim if (close) { 98735a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim // Trick to call release() without holding the lock, to prevent potential deadlock 98835a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim // with the developer's custom lock within the ControllerCallback.onDisconnected(). 989113a561d324e89b1db5edcc39c903c879e08dd94Jaewan Kim mInstance.close(); 99035a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim } 99135a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim } 99235a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim } 99335a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim 994d5b878d0cf0c987caf18be697a0e1637fb632d66Jaewan Kim void onCustomCommand(final SessionCommand2 command, final Bundle args, 995bf9606868a825bf9f606d4d3ec8d15e7f29b76a7Jaewan Kim final ResultReceiver receiver) { 996bf9606868a825bf9f606d4d3ec8d15e7f29b76a7Jaewan Kim if (DEBUG) { 997bf9606868a825bf9f606d4d3ec8d15e7f29b76a7Jaewan Kim Log.d(TAG, "onCustomCommand cmd=" + command); 998bf9606868a825bf9f606d4d3ec8d15e7f29b76a7Jaewan Kim } 999bf9606868a825bf9f606d4d3ec8d15e7f29b76a7Jaewan Kim mCallbackExecutor.execute(() -> { 1000bf9606868a825bf9f606d4d3ec8d15e7f29b76a7Jaewan Kim // TODO(jaewan): Double check if the controller exists. 1001d3d75358db7e3fe87805f1d91aa53abe1b0c2e92Jaewan Kim mCallback.onCustomCommand(mInstance, command, args, receiver); 1002bf9606868a825bf9f606d4d3ec8d15e7f29b76a7Jaewan Kim }); 1003bf9606868a825bf9f606d4d3ec8d15e7f29b76a7Jaewan Kim } 1004bf9606868a825bf9f606d4d3ec8d15e7f29b76a7Jaewan Kim 1005d5b878d0cf0c987caf18be697a0e1637fb632d66Jaewan Kim void onAllowedCommandsChanged(final SessionCommandGroup2 commands) { 1006e0e207174080d93a97b5c0ab84dcf84dd47c730cHyundo Moon mCallbackExecutor.execute(() -> { 1007e0e207174080d93a97b5c0ab84dcf84dd47c730cHyundo Moon mCallback.onAllowedCommandsChanged(mInstance, commands); 1008e0e207174080d93a97b5c0ab84dcf84dd47c730cHyundo Moon }); 1009e0e207174080d93a97b5c0ab84dcf84dd47c730cHyundo Moon } 1010e0e207174080d93a97b5c0ab84dcf84dd47c730cHyundo Moon 10119b67177ebfe5f46c0c6216f87f5ee98c03e5cbadJaewan Kim void onCustomLayoutChanged(final List<CommandButton> layout) { 10129b67177ebfe5f46c0c6216f87f5ee98c03e5cbadJaewan Kim mCallbackExecutor.execute(() -> { 1013d3d75358db7e3fe87805f1d91aa53abe1b0c2e92Jaewan Kim mCallback.onCustomLayoutChanged(mInstance, layout); 10149b67177ebfe5f46c0c6216f87f5ee98c03e5cbadJaewan Kim }); 10159b67177ebfe5f46c0c6216f87f5ee98c03e5cbadJaewan Kim } 10169b67177ebfe5f46c0c6216f87f5ee98c03e5cbadJaewan Kim 101735a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim // This will be called on the main thread. 101835a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim private class SessionServiceConnection implements ServiceConnection { 101935a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim @Override 102035a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim public void onServiceConnected(ComponentName name, IBinder service) { 102135a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim // Note that it's always main-thread. 102235a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim if (DEBUG) { 102335a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim Log.d(TAG, "onServiceConnected " + name + " " + this); 102435a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim } 102535a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim // Sanity check 102635a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim if (!mToken.getPackageName().equals(name.getPackageName())) { 102735a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim Log.wtf(TAG, name + " was connected, but expected pkg=" 102835a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim + mToken.getPackageName() + " with id=" + mToken.getId()); 102935a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim return; 103035a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim } 103135a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim final IMediaSession2 sessionBinder = IMediaSession2.Stub.asInterface(service); 103235a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim connectToSession(sessionBinder); 103335a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim } 103435a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim 103535a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim @Override 103635a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim public void onServiceDisconnected(ComponentName name) { 103735a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim // Temporal lose of the binding because of the service crash. System will automatically 103835a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim // rebind, so just no-op. 103935a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim // TODO(jaewan): Really? Either disconnect cleanly or 104035a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim if (DEBUG) { 104135a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim Log.w(TAG, "Session service " + name + " is disconnected."); 104235a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim } 104335a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim } 104435a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim 104535a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim @Override 104635a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim public void onBindingDied(ComponentName name) { 104735a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim // Permanent lose of the binding because of the service package update or removed. 104835a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim // This SessionServiceRecord will be removed accordingly, but forget session binder here 104935a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim // for sure. 1050113a561d324e89b1db5edcc39c903c879e08dd94Jaewan Kim mInstance.close(); 105135a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim } 105235a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim } 1053991a25e6fd2aa7456fa7686de0baf619ebd50c2cJaewan Kim 1054991a25e6fd2aa7456fa7686de0baf619ebd50c2cJaewan Kim public static final class PlaybackInfoImpl implements PlaybackInfoProvider { 1055991a25e6fd2aa7456fa7686de0baf619ebd50c2cJaewan Kim 1056991a25e6fd2aa7456fa7686de0baf619ebd50c2cJaewan Kim private static final String KEY_PLAYBACK_TYPE = 1057991a25e6fd2aa7456fa7686de0baf619ebd50c2cJaewan Kim "android.media.playbackinfo_impl.playback_type"; 1058991a25e6fd2aa7456fa7686de0baf619ebd50c2cJaewan Kim private static final String KEY_CONTROL_TYPE = 1059991a25e6fd2aa7456fa7686de0baf619ebd50c2cJaewan Kim "android.media.playbackinfo_impl.control_type"; 1060991a25e6fd2aa7456fa7686de0baf619ebd50c2cJaewan Kim private static final String KEY_MAX_VOLUME = 1061991a25e6fd2aa7456fa7686de0baf619ebd50c2cJaewan Kim "android.media.playbackinfo_impl.max_volume"; 1062991a25e6fd2aa7456fa7686de0baf619ebd50c2cJaewan Kim private static final String KEY_CURRENT_VOLUME = 1063991a25e6fd2aa7456fa7686de0baf619ebd50c2cJaewan Kim "android.media.playbackinfo_impl.current_volume"; 1064991a25e6fd2aa7456fa7686de0baf619ebd50c2cJaewan Kim private static final String KEY_AUDIO_ATTRIBUTES = 1065991a25e6fd2aa7456fa7686de0baf619ebd50c2cJaewan Kim "android.media.playbackinfo_impl.audio_attrs"; 1066991a25e6fd2aa7456fa7686de0baf619ebd50c2cJaewan Kim 1067991a25e6fd2aa7456fa7686de0baf619ebd50c2cJaewan Kim private final PlaybackInfo mInstance; 1068991a25e6fd2aa7456fa7686de0baf619ebd50c2cJaewan Kim 1069991a25e6fd2aa7456fa7686de0baf619ebd50c2cJaewan Kim private final int mPlaybackType; 1070991a25e6fd2aa7456fa7686de0baf619ebd50c2cJaewan Kim private final int mControlType; 1071991a25e6fd2aa7456fa7686de0baf619ebd50c2cJaewan Kim private final int mMaxVolume; 1072991a25e6fd2aa7456fa7686de0baf619ebd50c2cJaewan Kim private final int mCurrentVolume; 1073991a25e6fd2aa7456fa7686de0baf619ebd50c2cJaewan Kim private final AudioAttributes mAudioAttrs; 1074991a25e6fd2aa7456fa7686de0baf619ebd50c2cJaewan Kim 10750de7babb75683eba98af2db52101d262372235daChristofer Åkersten private PlaybackInfoImpl(int playbackType, AudioAttributes attrs, int controlType, 10760de7babb75683eba98af2db52101d262372235daChristofer Åkersten int max, int current) { 1077991a25e6fd2aa7456fa7686de0baf619ebd50c2cJaewan Kim mPlaybackType = playbackType; 1078991a25e6fd2aa7456fa7686de0baf619ebd50c2cJaewan Kim mAudioAttrs = attrs; 1079991a25e6fd2aa7456fa7686de0baf619ebd50c2cJaewan Kim mControlType = controlType; 1080991a25e6fd2aa7456fa7686de0baf619ebd50c2cJaewan Kim mMaxVolume = max; 1081991a25e6fd2aa7456fa7686de0baf619ebd50c2cJaewan Kim mCurrentVolume = current; 1082991a25e6fd2aa7456fa7686de0baf619ebd50c2cJaewan Kim mInstance = new PlaybackInfo(this); 1083991a25e6fd2aa7456fa7686de0baf619ebd50c2cJaewan Kim } 1084991a25e6fd2aa7456fa7686de0baf619ebd50c2cJaewan Kim 1085991a25e6fd2aa7456fa7686de0baf619ebd50c2cJaewan Kim @Override 1086991a25e6fd2aa7456fa7686de0baf619ebd50c2cJaewan Kim public int getPlaybackType_impl() { 1087991a25e6fd2aa7456fa7686de0baf619ebd50c2cJaewan Kim return mPlaybackType; 1088991a25e6fd2aa7456fa7686de0baf619ebd50c2cJaewan Kim } 1089991a25e6fd2aa7456fa7686de0baf619ebd50c2cJaewan Kim 1090991a25e6fd2aa7456fa7686de0baf619ebd50c2cJaewan Kim @Override 1091991a25e6fd2aa7456fa7686de0baf619ebd50c2cJaewan Kim public AudioAttributes getAudioAttributes_impl() { 1092991a25e6fd2aa7456fa7686de0baf619ebd50c2cJaewan Kim return mAudioAttrs; 1093991a25e6fd2aa7456fa7686de0baf619ebd50c2cJaewan Kim } 1094991a25e6fd2aa7456fa7686de0baf619ebd50c2cJaewan Kim 1095991a25e6fd2aa7456fa7686de0baf619ebd50c2cJaewan Kim @Override 1096991a25e6fd2aa7456fa7686de0baf619ebd50c2cJaewan Kim public int getControlType_impl() { 1097991a25e6fd2aa7456fa7686de0baf619ebd50c2cJaewan Kim return mControlType; 1098991a25e6fd2aa7456fa7686de0baf619ebd50c2cJaewan Kim } 1099991a25e6fd2aa7456fa7686de0baf619ebd50c2cJaewan Kim 1100991a25e6fd2aa7456fa7686de0baf619ebd50c2cJaewan Kim @Override 1101991a25e6fd2aa7456fa7686de0baf619ebd50c2cJaewan Kim public int getMaxVolume_impl() { 1102991a25e6fd2aa7456fa7686de0baf619ebd50c2cJaewan Kim return mMaxVolume; 1103991a25e6fd2aa7456fa7686de0baf619ebd50c2cJaewan Kim } 1104991a25e6fd2aa7456fa7686de0baf619ebd50c2cJaewan Kim 1105991a25e6fd2aa7456fa7686de0baf619ebd50c2cJaewan Kim @Override 1106991a25e6fd2aa7456fa7686de0baf619ebd50c2cJaewan Kim public int getCurrentVolume_impl() { 1107991a25e6fd2aa7456fa7686de0baf619ebd50c2cJaewan Kim return mCurrentVolume; 1108991a25e6fd2aa7456fa7686de0baf619ebd50c2cJaewan Kim } 1109991a25e6fd2aa7456fa7686de0baf619ebd50c2cJaewan Kim 11100de7babb75683eba98af2db52101d262372235daChristofer Åkersten PlaybackInfo getInstance() { 1111991a25e6fd2aa7456fa7686de0baf619ebd50c2cJaewan Kim return mInstance; 1112991a25e6fd2aa7456fa7686de0baf619ebd50c2cJaewan Kim } 1113991a25e6fd2aa7456fa7686de0baf619ebd50c2cJaewan Kim 11140de7babb75683eba98af2db52101d262372235daChristofer Åkersten Bundle toBundle() { 1115991a25e6fd2aa7456fa7686de0baf619ebd50c2cJaewan Kim Bundle bundle = new Bundle(); 1116991a25e6fd2aa7456fa7686de0baf619ebd50c2cJaewan Kim bundle.putInt(KEY_PLAYBACK_TYPE, mPlaybackType); 1117991a25e6fd2aa7456fa7686de0baf619ebd50c2cJaewan Kim bundle.putInt(KEY_CONTROL_TYPE, mControlType); 1118991a25e6fd2aa7456fa7686de0baf619ebd50c2cJaewan Kim bundle.putInt(KEY_MAX_VOLUME, mMaxVolume); 1119991a25e6fd2aa7456fa7686de0baf619ebd50c2cJaewan Kim bundle.putInt(KEY_CURRENT_VOLUME, mCurrentVolume); 1120991a25e6fd2aa7456fa7686de0baf619ebd50c2cJaewan Kim bundle.putParcelable(KEY_AUDIO_ATTRIBUTES, mAudioAttrs); 1121991a25e6fd2aa7456fa7686de0baf619ebd50c2cJaewan Kim return bundle; 1122991a25e6fd2aa7456fa7686de0baf619ebd50c2cJaewan Kim } 1123991a25e6fd2aa7456fa7686de0baf619ebd50c2cJaewan Kim 11240de7babb75683eba98af2db52101d262372235daChristofer Åkersten static PlaybackInfo createPlaybackInfo(int playbackType, AudioAttributes attrs, 11250de7babb75683eba98af2db52101d262372235daChristofer Åkersten int controlType, int max, int current) { 11260de7babb75683eba98af2db52101d262372235daChristofer Åkersten return new PlaybackInfoImpl(playbackType, attrs, controlType, max, current) 1127991a25e6fd2aa7456fa7686de0baf619ebd50c2cJaewan Kim .getInstance(); 1128991a25e6fd2aa7456fa7686de0baf619ebd50c2cJaewan Kim } 1129991a25e6fd2aa7456fa7686de0baf619ebd50c2cJaewan Kim 11300de7babb75683eba98af2db52101d262372235daChristofer Åkersten static PlaybackInfo fromBundle(Bundle bundle) { 1131991a25e6fd2aa7456fa7686de0baf619ebd50c2cJaewan Kim if (bundle == null) { 1132991a25e6fd2aa7456fa7686de0baf619ebd50c2cJaewan Kim return null; 1133991a25e6fd2aa7456fa7686de0baf619ebd50c2cJaewan Kim } 1134991a25e6fd2aa7456fa7686de0baf619ebd50c2cJaewan Kim final int volumeType = bundle.getInt(KEY_PLAYBACK_TYPE); 1135991a25e6fd2aa7456fa7686de0baf619ebd50c2cJaewan Kim final int volumeControl = bundle.getInt(KEY_CONTROL_TYPE); 1136991a25e6fd2aa7456fa7686de0baf619ebd50c2cJaewan Kim final int maxVolume = bundle.getInt(KEY_MAX_VOLUME); 1137991a25e6fd2aa7456fa7686de0baf619ebd50c2cJaewan Kim final int currentVolume = bundle.getInt(KEY_CURRENT_VOLUME); 1138991a25e6fd2aa7456fa7686de0baf619ebd50c2cJaewan Kim final AudioAttributes attrs = bundle.getParcelable(KEY_AUDIO_ATTRIBUTES); 1139991a25e6fd2aa7456fa7686de0baf619ebd50c2cJaewan Kim 11400de7babb75683eba98af2db52101d262372235daChristofer Åkersten return createPlaybackInfo(volumeType, attrs, volumeControl, maxVolume, currentVolume); 1141991a25e6fd2aa7456fa7686de0baf619ebd50c2cJaewan Kim } 1142991a25e6fd2aa7456fa7686de0baf619ebd50c2cJaewan Kim } 114335a6aa31951fa0178efe7245fe09e628275c2200Jaewan Kim} 1144