17ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi/* 27ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi * Copyright (C) 2013 The Android Open Source Project 37ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi * 47ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi * Licensed under the Apache License, Version 2.0 (the "License"); 57ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi * you may not use this file except in compliance with the License. 67ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi * You may obtain a copy of the License at 77ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi * 87ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi * http://www.apache.org/licenses/LICENSE-2.0 97ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi * 107ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi * Unless required by applicable law or agreed to in writing, software 117ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi * distributed under the License is distributed on an "AS IS" BASIS, 127ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 137ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi * See the License for the specific language governing permissions and 147ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi * limitations under the License. 157ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi */ 167ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi 177ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivipackage android.media; 187ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi 19a83487e8c618f3c267c3fe3a72d4eb9f1388d07eJean-Michel Triviimport android.Manifest; 20f8895248e2ac4dbb46622f3e04c7256f03175b4fAdam Powellimport android.app.ActivityManager; 217ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Triviimport android.app.PendingIntent; 227ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Triviimport android.app.PendingIntent.CanceledException; 237ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Triviimport android.content.Context; 247ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Triviimport android.content.Intent; 257ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Triviimport android.graphics.Bitmap; 267ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Triviimport android.media.IRemoteControlDisplay; 277ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Triviimport android.media.MediaMetadataEditor; 287ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Triviimport android.os.Bundle; 297ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Triviimport android.os.Handler; 307ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Triviimport android.os.Looper; 317ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Triviimport android.os.Message; 327ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Triviimport android.os.RemoteException; 337ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Triviimport android.os.ServiceManager; 34f8895248e2ac4dbb46622f3e04c7256f03175b4fAdam Powellimport android.os.SystemClock; 35f8895248e2ac4dbb46622f3e04c7256f03175b4fAdam Powellimport android.util.DisplayMetrics; 367ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Triviimport android.util.Log; 377ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Triviimport android.view.KeyEvent; 387ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi 394348a73bbe4e66ab691aea5971107046df806511Jean-Michel Triviimport java.lang.ref.WeakReference; 404348a73bbe4e66ab691aea5971107046df806511Jean-Michel Trivi 417ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi/** 427ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi * The RemoteController class is used to control media playback, display and update media metadata 437ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi * and playback status, published by applications using the {@link RemoteControlClient} class. 447ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi * <p> 457ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi * A RemoteController shall be registered through 467ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi * {@link AudioManager#registerRemoteController(RemoteController)} in order for the system to send 47f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi * media event updates to the {@link OnClientUpdateListener} listener set in the class constructor. 48f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi * Implement the methods of the interface to receive the information published by the active 49f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi * {@link RemoteControlClient} instances. 50f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi * <br>By default an {@link OnClientUpdateListener} implementation will not receive bitmaps for 51f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi * album art. Use {@link #setArtworkConfiguration(int, int)} to receive images as well. 527ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi * <p> 53f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi * Registration requires the {@link OnClientUpdateListener} listener to be one of the enabled 54f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi * notification listeners (see {@link android.service.notification.NotificationListenerService}). 557ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi */ 56a83487e8c618f3c267c3fe3a72d4eb9f1388d07eJean-Michel Trivipublic final class RemoteController 577ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi{ 587ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi private final static int MAX_BITMAP_DIMENSION = 512; 597ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi private final static int TRANSPORT_UNKNOWN = 0; 607ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi private final static String TAG = "RemoteController"; 617ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi private final static boolean DEBUG = false; 627ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi private final static Object mGenLock = new Object(); 637ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi private final static Object mInfoLock = new Object(); 64a83487e8c618f3c267c3fe3a72d4eb9f1388d07eJean-Michel Trivi private final RcDisplay mRcd; 65a83487e8c618f3c267c3fe3a72d4eb9f1388d07eJean-Michel Trivi private final Context mContext; 66a83487e8c618f3c267c3fe3a72d4eb9f1388d07eJean-Michel Trivi private final AudioManager mAudioManager; 67f8895248e2ac4dbb46622f3e04c7256f03175b4fAdam Powell private final int mMaxBitmapDimension; 687ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi private MetadataEditor mMetadataEditor; 697ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi 707ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi /** 717ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi * Synchronized on mGenLock 727ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi */ 737ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi private int mClientGenerationIdCurrent = 0; 747ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi 757ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi /** 767ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi * Synchronized on mInfoLock 777ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi */ 787ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi private boolean mIsRegistered = false; 797ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi private PendingIntent mClientPendingIntentCurrent; 807ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi private OnClientUpdateListener mOnClientUpdateListener; 817ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi private PlaybackInfo mLastPlaybackInfo; 828ab8c2d06185dfefb5c69e614271f684e77eef63Jean-Michel Trivi private int mArtworkWidth = -1; 838ab8c2d06185dfefb5c69e614271f684e77eef63Jean-Michel Trivi private int mArtworkHeight = -1; 84f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi private boolean mEnabled = true; 857ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi 867ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi /** 87a83487e8c618f3c267c3fe3a72d4eb9f1388d07eJean-Michel Trivi * Class constructor. 88f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi * @param context the {@link Context}, must be non-null. 89f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi * @param updateListener the listener to be called whenever new client information is available, 90f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi * must be non-null. 91f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi * @throws IllegalArgumentException 927ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi */ 93f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi public RemoteController(Context context, OnClientUpdateListener updateListener) 94f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi throws IllegalArgumentException { 95f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi this(context, updateListener, null); 967ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi } 977ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi 987ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi /** 99a83487e8c618f3c267c3fe3a72d4eb9f1388d07eJean-Michel Trivi * Class constructor. 100f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi * @param context the {@link Context}, must be non-null. 101f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi * @param updateListener the listener to be called whenever new client information is available, 102f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi * must be non-null. 103a83487e8c618f3c267c3fe3a72d4eb9f1388d07eJean-Michel Trivi * @param looper the {@link Looper} on which to run the event loop, 104a83487e8c618f3c267c3fe3a72d4eb9f1388d07eJean-Michel Trivi * or null to use the current thread's looper. 1057ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi * @throws java.lang.IllegalArgumentException 1067ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi */ 107f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi public RemoteController(Context context, OnClientUpdateListener updateListener, Looper looper) 108f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi throws IllegalArgumentException { 109a83487e8c618f3c267c3fe3a72d4eb9f1388d07eJean-Michel Trivi if (context == null) { 1107ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi throw new IllegalArgumentException("Invalid null Context"); 1117ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi } 112f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi if (updateListener == null) { 113f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi throw new IllegalArgumentException("Invalid null OnClientUpdateListener"); 114f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi } 115a83487e8c618f3c267c3fe3a72d4eb9f1388d07eJean-Michel Trivi if (looper != null) { 116a83487e8c618f3c267c3fe3a72d4eb9f1388d07eJean-Michel Trivi mEventHandler = new EventHandler(this, looper); 117a83487e8c618f3c267c3fe3a72d4eb9f1388d07eJean-Michel Trivi } else { 118a83487e8c618f3c267c3fe3a72d4eb9f1388d07eJean-Michel Trivi Looper l = Looper.myLooper(); 119a83487e8c618f3c267c3fe3a72d4eb9f1388d07eJean-Michel Trivi if (l != null) { 120a83487e8c618f3c267c3fe3a72d4eb9f1388d07eJean-Michel Trivi mEventHandler = new EventHandler(this, l); 121a83487e8c618f3c267c3fe3a72d4eb9f1388d07eJean-Michel Trivi } else { 122a83487e8c618f3c267c3fe3a72d4eb9f1388d07eJean-Michel Trivi throw new IllegalArgumentException("Calling thread not associated with a looper"); 123a83487e8c618f3c267c3fe3a72d4eb9f1388d07eJean-Michel Trivi } 124a83487e8c618f3c267c3fe3a72d4eb9f1388d07eJean-Michel Trivi } 125f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi mOnClientUpdateListener = updateListener; 126a83487e8c618f3c267c3fe3a72d4eb9f1388d07eJean-Michel Trivi mContext = context; 1274348a73bbe4e66ab691aea5971107046df806511Jean-Michel Trivi mRcd = new RcDisplay(this); 128a83487e8c618f3c267c3fe3a72d4eb9f1388d07eJean-Michel Trivi mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE); 129f8895248e2ac4dbb46622f3e04c7256f03175b4fAdam Powell 130f8895248e2ac4dbb46622f3e04c7256f03175b4fAdam Powell if (ActivityManager.isLowRamDeviceStatic()) { 131f8895248e2ac4dbb46622f3e04c7256f03175b4fAdam Powell mMaxBitmapDimension = MAX_BITMAP_DIMENSION; 132f8895248e2ac4dbb46622f3e04c7256f03175b4fAdam Powell } else { 133f8895248e2ac4dbb46622f3e04c7256f03175b4fAdam Powell final DisplayMetrics dm = context.getResources().getDisplayMetrics(); 134f8895248e2ac4dbb46622f3e04c7256f03175b4fAdam Powell mMaxBitmapDimension = Math.max(dm.widthPixels, dm.heightPixels); 135f8895248e2ac4dbb46622f3e04c7256f03175b4fAdam Powell } 1367ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi } 1377ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi 1387ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi 1397ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi /** 140f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi * Interface definition for the callbacks to be invoked whenever media events, metadata 141a83487e8c618f3c267c3fe3a72d4eb9f1388d07eJean-Michel Trivi * and playback status are available. 1427ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi */ 143f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi public interface OnClientUpdateListener { 1447ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi /** 145f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi * Called whenever all information, previously received through the other 146a83487e8c618f3c267c3fe3a72d4eb9f1388d07eJean-Michel Trivi * methods of the listener, is no longer valid and is about to be refreshed. 147a83487e8c618f3c267c3fe3a72d4eb9f1388d07eJean-Michel Trivi * This is typically called whenever a new {@link RemoteControlClient} has been selected 148a83487e8c618f3c267c3fe3a72d4eb9f1388d07eJean-Michel Trivi * by the system to have its media information published. 149a83487e8c618f3c267c3fe3a72d4eb9f1388d07eJean-Michel Trivi * @param clearing true if there is no selected RemoteControlClient and no information 150a83487e8c618f3c267c3fe3a72d4eb9f1388d07eJean-Michel Trivi * is available. 1517ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi */ 152f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi public void onClientChange(boolean clearing); 153a83487e8c618f3c267c3fe3a72d4eb9f1388d07eJean-Michel Trivi 1547ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi /** 155f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi * Called whenever the playback state has changed. 156a83487e8c618f3c267c3fe3a72d4eb9f1388d07eJean-Michel Trivi * It is called when no information is known about the playback progress in the media and 157a83487e8c618f3c267c3fe3a72d4eb9f1388d07eJean-Michel Trivi * the playback speed. 158a83487e8c618f3c267c3fe3a72d4eb9f1388d07eJean-Michel Trivi * @param state one of the playback states authorized 159a83487e8c618f3c267c3fe3a72d4eb9f1388d07eJean-Michel Trivi * in {@link RemoteControlClient#setPlaybackState(int)}. 1607ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi */ 161f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi public void onClientPlaybackStateUpdate(int state); 1627ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi /** 163f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi * Called whenever the playback state has changed, and playback position 164f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi * and speed are known. 165a83487e8c618f3c267c3fe3a72d4eb9f1388d07eJean-Michel Trivi * @param state one of the playback states authorized 166a83487e8c618f3c267c3fe3a72d4eb9f1388d07eJean-Michel Trivi * in {@link RemoteControlClient#setPlaybackState(int)}. 167a83487e8c618f3c267c3fe3a72d4eb9f1388d07eJean-Michel Trivi * @param stateChangeTimeMs the system time at which the state change was reported, 16870cb8021ef7d1804982032c464685139629f68a2Adam Powell * expressed in ms. Based on {@link android.os.SystemClock#elapsedRealtime()}. 169a83487e8c618f3c267c3fe3a72d4eb9f1388d07eJean-Michel Trivi * @param currentPosMs a positive value for the current media playback position expressed 170a83487e8c618f3c267c3fe3a72d4eb9f1388d07eJean-Michel Trivi * in ms, a negative value if the position is temporarily unknown. 171a83487e8c618f3c267c3fe3a72d4eb9f1388d07eJean-Michel Trivi * @param speed a value expressed as a ratio of 1x playback: 1.0f is normal playback, 172a83487e8c618f3c267c3fe3a72d4eb9f1388d07eJean-Michel Trivi * 2.0f is 2x, 0.5f is half-speed, -2.0f is rewind at 2x speed. 0.0f means nothing is 173a83487e8c618f3c267c3fe3a72d4eb9f1388d07eJean-Michel Trivi * playing (e.g. when state is {@link RemoteControlClient#PLAYSTATE_ERROR}). 1747ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi */ 1757ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi public void onClientPlaybackStateUpdate(int state, long stateChangeTimeMs, 176f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi long currentPosMs, float speed); 1777ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi /** 178f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi * Called whenever the transport control flags have changed. 179a83487e8c618f3c267c3fe3a72d4eb9f1388d07eJean-Michel Trivi * @param transportControlFlags one of the flags authorized 180a83487e8c618f3c267c3fe3a72d4eb9f1388d07eJean-Michel Trivi * in {@link RemoteControlClient#setTransportControlFlags(int)}. 1817ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi */ 182f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi public void onClientTransportControlUpdate(int transportControlFlags); 1837ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi /** 184f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi * Called whenever new metadata is available. 185a83487e8c618f3c267c3fe3a72d4eb9f1388d07eJean-Michel Trivi * See the {@link MediaMetadataEditor#putLong(int, long)}, 186a83487e8c618f3c267c3fe3a72d4eb9f1388d07eJean-Michel Trivi * {@link MediaMetadataEditor#putString(int, String)}, 187a83487e8c618f3c267c3fe3a72d4eb9f1388d07eJean-Michel Trivi * {@link MediaMetadataEditor#putBitmap(int, Bitmap)}, and 188a83487e8c618f3c267c3fe3a72d4eb9f1388d07eJean-Michel Trivi * {@link MediaMetadataEditor#putObject(int, Object)} methods for the various keys that 189a83487e8c618f3c267c3fe3a72d4eb9f1388d07eJean-Michel Trivi * can be queried. 190a83487e8c618f3c267c3fe3a72d4eb9f1388d07eJean-Michel Trivi * @param metadataEditor the container of the new metadata. 1917ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi */ 192f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi public void onClientMetadataUpdate(MetadataEditor metadataEditor); 1937ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi }; 1947ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi 1957ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi 196f8895248e2ac4dbb46622f3e04c7256f03175b4fAdam Powell /** 197f8895248e2ac4dbb46622f3e04c7256f03175b4fAdam Powell * @hide 198f8895248e2ac4dbb46622f3e04c7256f03175b4fAdam Powell */ 199f8895248e2ac4dbb46622f3e04c7256f03175b4fAdam Powell public String getRemoteControlClientPackageName() { 200f8895248e2ac4dbb46622f3e04c7256f03175b4fAdam Powell return mClientPendingIntentCurrent != null ? 201f8895248e2ac4dbb46622f3e04c7256f03175b4fAdam Powell mClientPendingIntentCurrent.getCreatorPackage() : null; 202f8895248e2ac4dbb46622f3e04c7256f03175b4fAdam Powell } 203f8895248e2ac4dbb46622f3e04c7256f03175b4fAdam Powell 204f8895248e2ac4dbb46622f3e04c7256f03175b4fAdam Powell /** 205f8895248e2ac4dbb46622f3e04c7256f03175b4fAdam Powell * Return the estimated playback position of the current media track or a negative value 206f8895248e2ac4dbb46622f3e04c7256f03175b4fAdam Powell * if not available. 207f8895248e2ac4dbb46622f3e04c7256f03175b4fAdam Powell * 208f8895248e2ac4dbb46622f3e04c7256f03175b4fAdam Powell * <p>The value returned is estimated by the current process and may not be perfect. 209f8895248e2ac4dbb46622f3e04c7256f03175b4fAdam Powell * The time returned by this method is calculated from the last state change time based 210f8895248e2ac4dbb46622f3e04c7256f03175b4fAdam Powell * on the current play position at that time and the last known playback speed. 211f8895248e2ac4dbb46622f3e04c7256f03175b4fAdam Powell * An application may call {@link #setSynchronizationMode(int)} to apply 212f8895248e2ac4dbb46622f3e04c7256f03175b4fAdam Powell * a synchronization policy that will periodically re-sync the estimated position 213f8895248e2ac4dbb46622f3e04c7256f03175b4fAdam Powell * with the RemoteControlClient.</p> 214f8895248e2ac4dbb46622f3e04c7256f03175b4fAdam Powell * 215f8895248e2ac4dbb46622f3e04c7256f03175b4fAdam Powell * @return the current estimated playback position in milliseconds or a negative value 216f8895248e2ac4dbb46622f3e04c7256f03175b4fAdam Powell * if not available 217f8895248e2ac4dbb46622f3e04c7256f03175b4fAdam Powell * 218f8895248e2ac4dbb46622f3e04c7256f03175b4fAdam Powell * @see OnClientUpdateListener#onClientPlaybackStateUpdate(int, long, long, float) 219f8895248e2ac4dbb46622f3e04c7256f03175b4fAdam Powell */ 220f8895248e2ac4dbb46622f3e04c7256f03175b4fAdam Powell public long getEstimatedMediaPosition() { 221f8895248e2ac4dbb46622f3e04c7256f03175b4fAdam Powell if (mLastPlaybackInfo != null) { 222f8895248e2ac4dbb46622f3e04c7256f03175b4fAdam Powell if (!RemoteControlClient.playbackPositionShouldMove(mLastPlaybackInfo.mState)) { 223f8895248e2ac4dbb46622f3e04c7256f03175b4fAdam Powell return mLastPlaybackInfo.mCurrentPosMs; 224f8895248e2ac4dbb46622f3e04c7256f03175b4fAdam Powell } 225f8895248e2ac4dbb46622f3e04c7256f03175b4fAdam Powell 226f8895248e2ac4dbb46622f3e04c7256f03175b4fAdam Powell // Take the current position at the time of state change and estimate. 227f8895248e2ac4dbb46622f3e04c7256f03175b4fAdam Powell final long thenPos = mLastPlaybackInfo.mCurrentPosMs; 228f8895248e2ac4dbb46622f3e04c7256f03175b4fAdam Powell if (thenPos < 0) { 229f8895248e2ac4dbb46622f3e04c7256f03175b4fAdam Powell return -1; 230f8895248e2ac4dbb46622f3e04c7256f03175b4fAdam Powell } 231f8895248e2ac4dbb46622f3e04c7256f03175b4fAdam Powell 232f8895248e2ac4dbb46622f3e04c7256f03175b4fAdam Powell final long now = SystemClock.elapsedRealtime(); 233f8895248e2ac4dbb46622f3e04c7256f03175b4fAdam Powell final long then = mLastPlaybackInfo.mStateChangeTimeMs; 234f8895248e2ac4dbb46622f3e04c7256f03175b4fAdam Powell final long sinceThen = now - then; 235f8895248e2ac4dbb46622f3e04c7256f03175b4fAdam Powell final long scaledSinceThen = (long) (sinceThen * mLastPlaybackInfo.mSpeed); 236f8895248e2ac4dbb46622f3e04c7256f03175b4fAdam Powell return thenPos + scaledSinceThen; 237f8895248e2ac4dbb46622f3e04c7256f03175b4fAdam Powell } 238f8895248e2ac4dbb46622f3e04c7256f03175b4fAdam Powell return -1; 239f8895248e2ac4dbb46622f3e04c7256f03175b4fAdam Powell } 2407ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi 241f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi 2427ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi /** 243a83487e8c618f3c267c3fe3a72d4eb9f1388d07eJean-Michel Trivi * Send a simulated key event for a media button to be received by the current client. 244a83487e8c618f3c267c3fe3a72d4eb9f1388d07eJean-Michel Trivi * To simulate a key press, you must first send a KeyEvent built with 245a83487e8c618f3c267c3fe3a72d4eb9f1388d07eJean-Michel Trivi * a {@link KeyEvent#ACTION_DOWN} action, then another event with the {@link KeyEvent#ACTION_UP} 246a83487e8c618f3c267c3fe3a72d4eb9f1388d07eJean-Michel Trivi * action. 247a83487e8c618f3c267c3fe3a72d4eb9f1388d07eJean-Michel Trivi * <p>The key event will be sent to the registered receiver 248a83487e8c618f3c267c3fe3a72d4eb9f1388d07eJean-Michel Trivi * (see {@link AudioManager#registerMediaButtonEventReceiver(PendingIntent)}) whose associated 249a83487e8c618f3c267c3fe3a72d4eb9f1388d07eJean-Michel Trivi * {@link RemoteControlClient}'s metadata and playback state is published (there may be 250a83487e8c618f3c267c3fe3a72d4eb9f1388d07eJean-Michel Trivi * none under some circumstances). 2517ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi * @param keyEvent a {@link KeyEvent} instance whose key code is one of 252a83487e8c618f3c267c3fe3a72d4eb9f1388d07eJean-Michel Trivi * {@link KeyEvent#KEYCODE_MUTE}, 253a83487e8c618f3c267c3fe3a72d4eb9f1388d07eJean-Michel Trivi * {@link KeyEvent#KEYCODE_HEADSETHOOK}, 254a83487e8c618f3c267c3fe3a72d4eb9f1388d07eJean-Michel Trivi * {@link KeyEvent#KEYCODE_MEDIA_PLAY}, 255a83487e8c618f3c267c3fe3a72d4eb9f1388d07eJean-Michel Trivi * {@link KeyEvent#KEYCODE_MEDIA_PAUSE}, 256a83487e8c618f3c267c3fe3a72d4eb9f1388d07eJean-Michel Trivi * {@link KeyEvent#KEYCODE_MEDIA_PLAY_PAUSE}, 257a83487e8c618f3c267c3fe3a72d4eb9f1388d07eJean-Michel Trivi * {@link KeyEvent#KEYCODE_MEDIA_STOP}, 258a83487e8c618f3c267c3fe3a72d4eb9f1388d07eJean-Michel Trivi * {@link KeyEvent#KEYCODE_MEDIA_NEXT}, 259a83487e8c618f3c267c3fe3a72d4eb9f1388d07eJean-Michel Trivi * {@link KeyEvent#KEYCODE_MEDIA_PREVIOUS}, 260a83487e8c618f3c267c3fe3a72d4eb9f1388d07eJean-Michel Trivi * {@link KeyEvent#KEYCODE_MEDIA_REWIND}, 261a83487e8c618f3c267c3fe3a72d4eb9f1388d07eJean-Michel Trivi * {@link KeyEvent#KEYCODE_MEDIA_RECORD}, 262a83487e8c618f3c267c3fe3a72d4eb9f1388d07eJean-Michel Trivi * {@link KeyEvent#KEYCODE_MEDIA_FAST_FORWARD}, 263a83487e8c618f3c267c3fe3a72d4eb9f1388d07eJean-Michel Trivi * {@link KeyEvent#KEYCODE_MEDIA_CLOSE}, 264a83487e8c618f3c267c3fe3a72d4eb9f1388d07eJean-Michel Trivi * {@link KeyEvent#KEYCODE_MEDIA_EJECT}, 265a83487e8c618f3c267c3fe3a72d4eb9f1388d07eJean-Michel Trivi * or {@link KeyEvent#KEYCODE_MEDIA_AUDIO_TRACK}. 266f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi * @return true if the event was successfully sent, false otherwise. 267f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi * @throws IllegalArgumentException 2687ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi */ 269f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi public boolean sendMediaKeyEvent(KeyEvent keyEvent) throws IllegalArgumentException { 2707ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi if (!MediaFocusControl.isMediaKeyCode(keyEvent.getKeyCode())) { 271f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi throw new IllegalArgumentException("not a media key event"); 2727ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi } 2737ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi final PendingIntent pi; 2747ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi synchronized(mInfoLock) { 275a83487e8c618f3c267c3fe3a72d4eb9f1388d07eJean-Michel Trivi if (!mIsRegistered) { 276a83487e8c618f3c267c3fe3a72d4eb9f1388d07eJean-Michel Trivi Log.e(TAG, "Cannot use sendMediaKeyEvent() from an unregistered RemoteController"); 277f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi return false; 278f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi } 279f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi if (!mEnabled) { 280f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi Log.e(TAG, "Cannot use sendMediaKeyEvent() from a disabled RemoteController"); 281f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi return false; 282a83487e8c618f3c267c3fe3a72d4eb9f1388d07eJean-Michel Trivi } 2837ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi pi = mClientPendingIntentCurrent; 2847ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi } 285a83487e8c618f3c267c3fe3a72d4eb9f1388d07eJean-Michel Trivi if (pi != null) { 286a83487e8c618f3c267c3fe3a72d4eb9f1388d07eJean-Michel Trivi Intent intent = new Intent(Intent.ACTION_MEDIA_BUTTON); 287a83487e8c618f3c267c3fe3a72d4eb9f1388d07eJean-Michel Trivi intent.putExtra(Intent.EXTRA_KEY_EVENT, keyEvent); 288a83487e8c618f3c267c3fe3a72d4eb9f1388d07eJean-Michel Trivi try { 289a83487e8c618f3c267c3fe3a72d4eb9f1388d07eJean-Michel Trivi pi.send(mContext, 0, intent); 290a83487e8c618f3c267c3fe3a72d4eb9f1388d07eJean-Michel Trivi } catch (CanceledException e) { 291a83487e8c618f3c267c3fe3a72d4eb9f1388d07eJean-Michel Trivi Log.e(TAG, "Error sending intent for media button down: ", e); 292f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi return false; 2937ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi } 2947ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi } else { 295a83487e8c618f3c267c3fe3a72d4eb9f1388d07eJean-Michel Trivi Log.i(TAG, "No-op when sending key click, no receiver right now"); 296f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi return false; 2977ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi } 298f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi return true; 2997ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi } 3007ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi 3017ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi 3027ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi /** 303a83487e8c618f3c267c3fe3a72d4eb9f1388d07eJean-Michel Trivi * Sets the new playback position. 304a83487e8c618f3c267c3fe3a72d4eb9f1388d07eJean-Michel Trivi * This method can only be called on a registered RemoteController. 305a83487e8c618f3c267c3fe3a72d4eb9f1388d07eJean-Michel Trivi * @param timeMs a 0 or positive value for the new playback position, expressed in ms. 306f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi * @return true if the command to set the playback position was successfully sent. 307f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi * @throws IllegalArgumentException 3087ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi */ 309f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi public boolean seekTo(long timeMs) throws IllegalArgumentException { 310f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi if (!mEnabled) { 311f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi Log.e(TAG, "Cannot use seekTo() from a disabled RemoteController"); 312f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi return false; 313f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi } 3147ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi if (timeMs < 0) { 315f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi throw new IllegalArgumentException("illegal negative time value"); 3167ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi } 3177ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi final int genId; 3187ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi synchronized (mGenLock) { 3197ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi genId = mClientGenerationIdCurrent; 3207ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi } 3217ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi mAudioManager.setRemoteControlClientPlaybackPosition(genId, timeMs); 322f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi return true; 3237ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi } 3247ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi 3257ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi 3267ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi /** 3277ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi * @hide 3287ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi * @param wantBitmap 3297ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi * @param width 3307ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi * @param height 331f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi * @return true if successful 332f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi * @throws IllegalArgumentException 3337ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi */ 334f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi public boolean setArtworkConfiguration(boolean wantBitmap, int width, int height) 335f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi throws IllegalArgumentException { 3367ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi synchronized (mInfoLock) { 3378ab8c2d06185dfefb5c69e614271f684e77eef63Jean-Michel Trivi if (wantBitmap) { 3388ab8c2d06185dfefb5c69e614271f684e77eef63Jean-Michel Trivi if ((width > 0) && (height > 0)) { 339f8895248e2ac4dbb46622f3e04c7256f03175b4fAdam Powell if (width > mMaxBitmapDimension) { width = mMaxBitmapDimension; } 340f8895248e2ac4dbb46622f3e04c7256f03175b4fAdam Powell if (height > mMaxBitmapDimension) { height = mMaxBitmapDimension; } 3418ab8c2d06185dfefb5c69e614271f684e77eef63Jean-Michel Trivi mArtworkWidth = width; 3428ab8c2d06185dfefb5c69e614271f684e77eef63Jean-Michel Trivi mArtworkHeight = height; 3438ab8c2d06185dfefb5c69e614271f684e77eef63Jean-Michel Trivi } else { 344f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi throw new IllegalArgumentException("Invalid dimensions"); 3458ab8c2d06185dfefb5c69e614271f684e77eef63Jean-Michel Trivi } 3467ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi } else { 3478ab8c2d06185dfefb5c69e614271f684e77eef63Jean-Michel Trivi mArtworkWidth = -1; 3488ab8c2d06185dfefb5c69e614271f684e77eef63Jean-Michel Trivi mArtworkHeight = -1; 3497ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi } 3508ab8c2d06185dfefb5c69e614271f684e77eef63Jean-Michel Trivi if (mIsRegistered) { 3518ab8c2d06185dfefb5c69e614271f684e77eef63Jean-Michel Trivi mAudioManager.remoteControlDisplayUsesBitmapSize(mRcd, 3528ab8c2d06185dfefb5c69e614271f684e77eef63Jean-Michel Trivi mArtworkWidth, mArtworkHeight); 3538ab8c2d06185dfefb5c69e614271f684e77eef63Jean-Michel Trivi } // else new values have been stored, and will be read by AudioManager with 3548ab8c2d06185dfefb5c69e614271f684e77eef63Jean-Michel Trivi // RemoteController.getArtworkSize() when AudioManager.registerRemoteController() 3558ab8c2d06185dfefb5c69e614271f684e77eef63Jean-Michel Trivi // is called. 3567ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi } 357f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi return true; 3587ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi } 3597ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi 3607ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi /** 361a83487e8c618f3c267c3fe3a72d4eb9f1388d07eJean-Michel Trivi * Set the maximum artwork image dimensions to be received in the metadata. 362a83487e8c618f3c267c3fe3a72d4eb9f1388d07eJean-Michel Trivi * No bitmaps will be received unless this has been specified. 363a83487e8c618f3c267c3fe3a72d4eb9f1388d07eJean-Michel Trivi * @param width the maximum width in pixels 364a83487e8c618f3c267c3fe3a72d4eb9f1388d07eJean-Michel Trivi * @param height the maximum height in pixels 365f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi * @return true if the artwork dimension was successfully set. 366f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi * @throws IllegalArgumentException 3677ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi */ 368f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi public boolean setArtworkConfiguration(int width, int height) throws IllegalArgumentException { 369a83487e8c618f3c267c3fe3a72d4eb9f1388d07eJean-Michel Trivi return setArtworkConfiguration(true, width, height); 3707ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi } 3717ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi 3727ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi /** 373a83487e8c618f3c267c3fe3a72d4eb9f1388d07eJean-Michel Trivi * Prevents this RemoteController from receiving artwork images. 374f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi * @return true if receiving artwork images was successfully disabled. 3757ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi */ 376f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi public boolean clearArtworkConfiguration() { 377a83487e8c618f3c267c3fe3a72d4eb9f1388d07eJean-Michel Trivi return setArtworkConfiguration(false, -1, -1); 3787ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi } 3797ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi 3807ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi 3817ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi /** 3827ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi * Default playback position synchronization mode where the RemoteControlClient is not 3837ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi * asked regularly for its playback position to see if it has drifted from the estimated 3847ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi * position. 3857ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi */ 3867ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi public static final int POSITION_SYNCHRONIZATION_NONE = 0; 3877ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi 3887ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi /** 3897ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi * The playback position synchronization mode where the RemoteControlClient instances which 3907ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi * expose their playback position to the framework, will be regularly polled to check 3917ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi * whether any drift has been noticed between their estimated position and the one they report. 3927ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi * Note that this mode should only ever be used when needing to display very accurate playback 3937ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi * position, as regularly polling a RemoteControlClient for its position may have an impact 3947ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi * on battery life (if applicable) when this query will trigger network transactions in the 3957ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi * case of remote playback. 3967ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi */ 3977ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi public static final int POSITION_SYNCHRONIZATION_CHECK = 1; 3987ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi 3997ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi /** 4007ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi * Set the playback position synchronization mode. 4017ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi * Must be called on a registered RemoteController. 4027ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi * @param sync {@link #POSITION_SYNCHRONIZATION_NONE} or {@link #POSITION_SYNCHRONIZATION_CHECK} 403f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi * @return true if the synchronization mode was successfully set. 404f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi * @throws IllegalArgumentException 4057ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi */ 406f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi public boolean setSynchronizationMode(int sync) throws IllegalArgumentException { 4077ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi if ((sync != POSITION_SYNCHRONIZATION_NONE) || (sync != POSITION_SYNCHRONIZATION_CHECK)) { 408f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi throw new IllegalArgumentException("Unknown synchronization mode " + sync); 4097ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi } 4107ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi if (!mIsRegistered) { 4117ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi Log.e(TAG, "Cannot set synchronization mode on an unregistered RemoteController"); 412f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi return false; 4137ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi } 4147ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi mAudioManager.remoteControlDisplayWantsPlaybackPositionSync(mRcd, 4157ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi POSITION_SYNCHRONIZATION_CHECK == sync); 416f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi return true; 4177ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi } 4187ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi 4197ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi 4207ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi /** 4217ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi * Creates a {@link MetadataEditor} for updating metadata values of the editable keys of 4227ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi * the current {@link RemoteControlClient}. 423a83487e8c618f3c267c3fe3a72d4eb9f1388d07eJean-Michel Trivi * This method can only be called on a registered RemoteController. 4247ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi * @return a new MetadataEditor instance. 4257ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi */ 4267ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi public MetadataEditor editMetadata() { 4277ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi MetadataEditor editor = new MetadataEditor(); 4287ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi editor.mEditorMetadata = new Bundle(); 4297ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi editor.mEditorArtwork = null; 4307ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi editor.mMetadataChanged = true; 4317ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi editor.mArtworkChanged = true; 4327ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi editor.mEditableKeys = 0; 4337ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi return editor; 4347ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi } 4357ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi 4367ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi 4377ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi /** 438a83487e8c618f3c267c3fe3a72d4eb9f1388d07eJean-Michel Trivi * A class to read the metadata published by a {@link RemoteControlClient}, or send a 4397ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi * {@link RemoteControlClient} new values for keys that can be edited. 4407ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi */ 4417ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi public class MetadataEditor extends MediaMetadataEditor { 4427ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi /** 4437ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi * @hide 4447ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi */ 4457ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi protected MetadataEditor() { } 4467ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi 4477ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi /** 4487ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi * @hide 4497ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi */ 4507ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi protected MetadataEditor(Bundle metadata, long editableKeys) { 4517ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi mEditorMetadata = metadata; 4527ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi mEditableKeys = editableKeys; 453f8895248e2ac4dbb46622f3e04c7256f03175b4fAdam Powell 454f8895248e2ac4dbb46622f3e04c7256f03175b4fAdam Powell mEditorArtwork = (Bitmap) metadata.getParcelable( 455f8895248e2ac4dbb46622f3e04c7256f03175b4fAdam Powell String.valueOf(MediaMetadataEditor.BITMAP_KEY_ARTWORK)); 456f8895248e2ac4dbb46622f3e04c7256f03175b4fAdam Powell if (mEditorArtwork != null) { 457f8895248e2ac4dbb46622f3e04c7256f03175b4fAdam Powell cleanupBitmapFromBundle(MediaMetadataEditor.BITMAP_KEY_ARTWORK); 458f8895248e2ac4dbb46622f3e04c7256f03175b4fAdam Powell } 459f8895248e2ac4dbb46622f3e04c7256f03175b4fAdam Powell 4607ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi mMetadataChanged = true; 4617ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi mArtworkChanged = true; 4627ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi mApplied = false; 4637ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi } 4647ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi 4656d298811ef642bc4f179ca3e9f4de028fb1ddb74Jean-Michel Trivi private void cleanupBitmapFromBundle(int key) { 4666d298811ef642bc4f179ca3e9f4de028fb1ddb74Jean-Michel Trivi if (METADATA_KEYS_TYPE.get(key, METADATA_TYPE_INVALID) == METADATA_TYPE_BITMAP) { 4676d298811ef642bc4f179ca3e9f4de028fb1ddb74Jean-Michel Trivi mEditorMetadata.remove(String.valueOf(key)); 4686d298811ef642bc4f179ca3e9f4de028fb1ddb74Jean-Michel Trivi } 4696d298811ef642bc4f179ca3e9f4de028fb1ddb74Jean-Michel Trivi } 4706d298811ef642bc4f179ca3e9f4de028fb1ddb74Jean-Michel Trivi 4717ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi /** 472a83487e8c618f3c267c3fe3a72d4eb9f1388d07eJean-Michel Trivi * Applies all of the metadata changes that have been set since the MediaMetadataEditor 473a83487e8c618f3c267c3fe3a72d4eb9f1388d07eJean-Michel Trivi * instance was created with {@link RemoteController#editMetadata()} 474a83487e8c618f3c267c3fe3a72d4eb9f1388d07eJean-Michel Trivi * or since {@link #clear()} was called. 4757ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi */ 4767ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi public synchronized void apply() { 4777ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi // "applying" a metadata bundle in RemoteController is only for sending edited 4787ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi // key values back to the RemoteControlClient, so here we only care about the only 4797ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi // editable key we support: RATING_KEY_BY_USER 4807ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi if (!mMetadataChanged) { 4817ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi return; 4827ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi } 4837ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi final int genId; 4847ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi synchronized(mGenLock) { 4857ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi genId = mClientGenerationIdCurrent; 4867ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi } 4877ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi synchronized(mInfoLock) { 4887ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi if (mEditorMetadata.containsKey( 4897ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi String.valueOf(MediaMetadataEditor.RATING_KEY_BY_USER))) { 4907ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi Rating rating = (Rating) getObject( 4917ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi MediaMetadataEditor.RATING_KEY_BY_USER, null); 4927ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi mAudioManager.updateRemoteControlClientMetadata(genId, 4937ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi MediaMetadataEditor.RATING_KEY_BY_USER, 4947ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi rating); 4957ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi } else { 4967ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi Log.e(TAG, "no metadata to apply"); 4977ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi } 4987ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi // NOT setting mApplied to true as this type of MetadataEditor will be applied 4997ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi // multiple times, whenever the user of a RemoteController needs to change the 5007ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi // metadata (e.g. user changes the rating of a song more than once during playback) 5017ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi mApplied = false; 5027ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi } 5037ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi } 5047ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi 5057ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi } 5067ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi 5077ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi 5087ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi //================================================== 5097ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi // Implementation of IRemoteControlDisplay interface 5104348a73bbe4e66ab691aea5971107046df806511Jean-Michel Trivi private static class RcDisplay extends IRemoteControlDisplay.Stub { 5114348a73bbe4e66ab691aea5971107046df806511Jean-Michel Trivi private final WeakReference<RemoteController> mController; 5124348a73bbe4e66ab691aea5971107046df806511Jean-Michel Trivi 5134348a73bbe4e66ab691aea5971107046df806511Jean-Michel Trivi RcDisplay(RemoteController rc) { 5144348a73bbe4e66ab691aea5971107046df806511Jean-Michel Trivi mController = new WeakReference<RemoteController>(rc); 5154348a73bbe4e66ab691aea5971107046df806511Jean-Michel Trivi } 516a83487e8c618f3c267c3fe3a72d4eb9f1388d07eJean-Michel Trivi 5177ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi public void setCurrentClientId(int genId, PendingIntent clientMediaIntent, 5187ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi boolean clearing) { 5194348a73bbe4e66ab691aea5971107046df806511Jean-Michel Trivi final RemoteController rc = mController.get(); 5204348a73bbe4e66ab691aea5971107046df806511Jean-Michel Trivi if (rc == null) { 5214348a73bbe4e66ab691aea5971107046df806511Jean-Michel Trivi return; 5224348a73bbe4e66ab691aea5971107046df806511Jean-Michel Trivi } 5237ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi boolean isNew = false; 5247ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi synchronized(mGenLock) { 5254348a73bbe4e66ab691aea5971107046df806511Jean-Michel Trivi if (rc.mClientGenerationIdCurrent != genId) { 5264348a73bbe4e66ab691aea5971107046df806511Jean-Michel Trivi rc.mClientGenerationIdCurrent = genId; 5277ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi isNew = true; 5287ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi } 5297ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi } 5307ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi if (clientMediaIntent != null) { 5314348a73bbe4e66ab691aea5971107046df806511Jean-Michel Trivi sendMsg(rc.mEventHandler, MSG_NEW_PENDING_INTENT, SENDMSG_REPLACE, 5327ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi genId /*arg1*/, 0, clientMediaIntent /*obj*/, 0 /*delay*/); 5337ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi } 5347ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi if (isNew || clearing) { 5354348a73bbe4e66ab691aea5971107046df806511Jean-Michel Trivi sendMsg(rc.mEventHandler, MSG_CLIENT_CHANGE, SENDMSG_REPLACE, 5367ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi genId /*arg1*/, clearing ? 1 : 0, null /*obj*/, 0 /*delay*/); 5377ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi } 5387ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi } 5397ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi 540f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi public void setEnabled(boolean enabled) { 5414348a73bbe4e66ab691aea5971107046df806511Jean-Michel Trivi final RemoteController rc = mController.get(); 5424348a73bbe4e66ab691aea5971107046df806511Jean-Michel Trivi if (rc == null) { 5434348a73bbe4e66ab691aea5971107046df806511Jean-Michel Trivi return; 5444348a73bbe4e66ab691aea5971107046df806511Jean-Michel Trivi } 5454348a73bbe4e66ab691aea5971107046df806511Jean-Michel Trivi sendMsg(rc.mEventHandler, MSG_DISPLAY_ENABLE, SENDMSG_REPLACE, 546f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi enabled ? 1 : 0 /*arg1*/, 0, null /*obj*/, 0 /*delay*/); 547f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi } 548f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi 5497ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi public void setPlaybackState(int genId, int state, 5507ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi long stateChangeTimeMs, long currentPosMs, float speed) { 5514348a73bbe4e66ab691aea5971107046df806511Jean-Michel Trivi final RemoteController rc = mController.get(); 5524348a73bbe4e66ab691aea5971107046df806511Jean-Michel Trivi if (rc == null) { 5534348a73bbe4e66ab691aea5971107046df806511Jean-Michel Trivi return; 5544348a73bbe4e66ab691aea5971107046df806511Jean-Michel Trivi } 5557ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi if (DEBUG) { 5567ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi Log.d(TAG, "> new playback state: genId="+genId 5577ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi + " state="+ state 5587ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi + " changeTime="+ stateChangeTimeMs 5597ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi + " pos=" + currentPosMs 5607ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi + "ms speed=" + speed); 5617ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi } 5627ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi 5637ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi synchronized(mGenLock) { 5644348a73bbe4e66ab691aea5971107046df806511Jean-Michel Trivi if (rc.mClientGenerationIdCurrent != genId) { 5657ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi return; 5667ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi } 5677ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi } 5687ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi final PlaybackInfo playbackInfo = 5697ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi new PlaybackInfo(state, stateChangeTimeMs, currentPosMs, speed); 5704348a73bbe4e66ab691aea5971107046df806511Jean-Michel Trivi sendMsg(rc.mEventHandler, MSG_NEW_PLAYBACK_INFO, SENDMSG_REPLACE, 5717ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi genId /*arg1*/, 0, playbackInfo /*obj*/, 0 /*delay*/); 5727ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi 5737ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi } 5747ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi 5757ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi public void setTransportControlInfo(int genId, int transportControlFlags, 5767ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi int posCapabilities) { 5774348a73bbe4e66ab691aea5971107046df806511Jean-Michel Trivi final RemoteController rc = mController.get(); 5784348a73bbe4e66ab691aea5971107046df806511Jean-Michel Trivi if (rc == null) { 5794348a73bbe4e66ab691aea5971107046df806511Jean-Michel Trivi return; 5804348a73bbe4e66ab691aea5971107046df806511Jean-Michel Trivi } 5817ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi synchronized(mGenLock) { 5824348a73bbe4e66ab691aea5971107046df806511Jean-Michel Trivi if (rc.mClientGenerationIdCurrent != genId) { 5837ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi return; 5847ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi } 5857ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi } 5864348a73bbe4e66ab691aea5971107046df806511Jean-Michel Trivi sendMsg(rc.mEventHandler, MSG_NEW_TRANSPORT_INFO, SENDMSG_REPLACE, 5877ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi genId /*arg1*/, transportControlFlags /*arg2*/, 5887ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi null /*obj*/, 0 /*delay*/); 5897ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi } 5907ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi 5917ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi public void setMetadata(int genId, Bundle metadata) { 5924348a73bbe4e66ab691aea5971107046df806511Jean-Michel Trivi final RemoteController rc = mController.get(); 5934348a73bbe4e66ab691aea5971107046df806511Jean-Michel Trivi if (rc == null) { 5944348a73bbe4e66ab691aea5971107046df806511Jean-Michel Trivi return; 5954348a73bbe4e66ab691aea5971107046df806511Jean-Michel Trivi } 5967ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi if (DEBUG) { Log.e(TAG, "setMetadata("+genId+")"); } 5977ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi if (metadata == null) { 5987ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi return; 5997ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi } 6007ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi synchronized(mGenLock) { 6014348a73bbe4e66ab691aea5971107046df806511Jean-Michel Trivi if (rc.mClientGenerationIdCurrent != genId) { 6027ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi return; 6037ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi } 6047ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi } 6054348a73bbe4e66ab691aea5971107046df806511Jean-Michel Trivi sendMsg(rc.mEventHandler, MSG_NEW_METADATA, SENDMSG_QUEUE, 6067ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi genId /*arg1*/, 0 /*arg2*/, 6077ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi metadata /*obj*/, 0 /*delay*/); 6087ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi } 6097ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi 6107ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi public void setArtwork(int genId, Bitmap artwork) { 6114348a73bbe4e66ab691aea5971107046df806511Jean-Michel Trivi final RemoteController rc = mController.get(); 6124348a73bbe4e66ab691aea5971107046df806511Jean-Michel Trivi if (rc == null) { 6134348a73bbe4e66ab691aea5971107046df806511Jean-Michel Trivi return; 6144348a73bbe4e66ab691aea5971107046df806511Jean-Michel Trivi } 6157ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi if (DEBUG) { Log.v(TAG, "setArtwork("+genId+")"); } 6167ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi synchronized(mGenLock) { 6174348a73bbe4e66ab691aea5971107046df806511Jean-Michel Trivi if (rc.mClientGenerationIdCurrent != genId) { 6187ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi return; 6197ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi } 6207ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi } 6217ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi Bundle metadata = new Bundle(1); 6227ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi metadata.putParcelable(String.valueOf(MediaMetadataEditor.BITMAP_KEY_ARTWORK), artwork); 6234348a73bbe4e66ab691aea5971107046df806511Jean-Michel Trivi sendMsg(rc.mEventHandler, MSG_NEW_METADATA, SENDMSG_QUEUE, 6247ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi genId /*arg1*/, 0 /*arg2*/, 6257ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi metadata /*obj*/, 0 /*delay*/); 6267ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi } 6277ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi 6287ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi public void setAllMetadata(int genId, Bundle metadata, Bitmap artwork) { 6294348a73bbe4e66ab691aea5971107046df806511Jean-Michel Trivi final RemoteController rc = mController.get(); 6304348a73bbe4e66ab691aea5971107046df806511Jean-Michel Trivi if (rc == null) { 6314348a73bbe4e66ab691aea5971107046df806511Jean-Michel Trivi return; 6324348a73bbe4e66ab691aea5971107046df806511Jean-Michel Trivi } 6337ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi if (DEBUG) { Log.e(TAG, "setAllMetadata("+genId+")"); } 6347ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi if ((metadata == null) && (artwork == null)) { 6357ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi return; 6367ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi } 6377ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi synchronized(mGenLock) { 6384348a73bbe4e66ab691aea5971107046df806511Jean-Michel Trivi if (rc.mClientGenerationIdCurrent != genId) { 6397ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi return; 6407ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi } 6417ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi } 6427ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi if (metadata == null) { 6437ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi metadata = new Bundle(1); 6447ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi } 6457ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi if (artwork != null) { 6467ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi metadata.putParcelable(String.valueOf(MediaMetadataEditor.BITMAP_KEY_ARTWORK), 6477ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi artwork); 6487ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi } 6494348a73bbe4e66ab691aea5971107046df806511Jean-Michel Trivi sendMsg(rc.mEventHandler, MSG_NEW_METADATA, SENDMSG_QUEUE, 6507ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi genId /*arg1*/, 0 /*arg2*/, 6517ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi metadata /*obj*/, 0 /*delay*/); 6527ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi } 6537ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi } 6547ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi 6557ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi //================================================== 6567ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi // Event handling 657a83487e8c618f3c267c3fe3a72d4eb9f1388d07eJean-Michel Trivi private final EventHandler mEventHandler; 6587ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi private final static int MSG_NEW_PENDING_INTENT = 0; 6597ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi private final static int MSG_NEW_PLAYBACK_INFO = 1; 6607ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi private final static int MSG_NEW_TRANSPORT_INFO = 2; 6617ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi private final static int MSG_NEW_METADATA = 3; // msg always has non-null obj parameter 662a83487e8c618f3c267c3fe3a72d4eb9f1388d07eJean-Michel Trivi private final static int MSG_CLIENT_CHANGE = 4; 663f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi private final static int MSG_DISPLAY_ENABLE = 5; 6647ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi 6657ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi private class EventHandler extends Handler { 6667ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi 6677ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi public EventHandler(RemoteController rc, Looper looper) { 6687ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi super(looper); 6697ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi } 6707ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi 6717ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi @Override 6727ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi public void handleMessage(Message msg) { 6737ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi switch(msg.what) { 6747ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi case MSG_NEW_PENDING_INTENT: 6757ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi onNewPendingIntent(msg.arg1, (PendingIntent) msg.obj); 6767ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi break; 6777ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi case MSG_NEW_PLAYBACK_INFO: 6787ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi onNewPlaybackInfo(msg.arg1, (PlaybackInfo) msg.obj); 6797ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi break; 6807ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi case MSG_NEW_TRANSPORT_INFO: 6817ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi onNewTransportInfo(msg.arg1, msg.arg2); 6827ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi break; 6837ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi case MSG_NEW_METADATA: 6847ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi onNewMetadata(msg.arg1, (Bundle)msg.obj); 6857ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi break; 686a83487e8c618f3c267c3fe3a72d4eb9f1388d07eJean-Michel Trivi case MSG_CLIENT_CHANGE: 687a83487e8c618f3c267c3fe3a72d4eb9f1388d07eJean-Michel Trivi onClientChange(msg.arg1, msg.arg2 == 1); 6887ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi break; 689f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi case MSG_DISPLAY_ENABLE: 690f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi onDisplayEnable(msg.arg1 == 1); 691f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi break; 6927ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi default: 6937ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi Log.e(TAG, "unknown event " + msg.what); 6947ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi } 6957ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi } 6967ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi } 6977ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi 6987ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi /** If the msg is already queued, replace it with this one. */ 6997ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi private static final int SENDMSG_REPLACE = 0; 7007ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi /** If the msg is already queued, ignore this one and leave the old. */ 7017ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi private static final int SENDMSG_NOOP = 1; 7027ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi /** If the msg is already queued, queue this one and leave the old. */ 7037ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi private static final int SENDMSG_QUEUE = 2; 7047ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi 7057ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi private static void sendMsg(Handler handler, int msg, int existingMsgPolicy, 7067ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi int arg1, int arg2, Object obj, int delayMs) { 7077ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi if (handler == null) { 7087ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi Log.e(TAG, "null event handler, will not deliver message " + msg); 7097ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi return; 7107ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi } 7117ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi if (existingMsgPolicy == SENDMSG_REPLACE) { 7127ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi handler.removeMessages(msg); 7137ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi } else if (existingMsgPolicy == SENDMSG_NOOP && handler.hasMessages(msg)) { 7147ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi return; 7157ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi } 7167ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi handler.sendMessageDelayed(handler.obtainMessage(msg, arg1, arg2, obj), delayMs); 7177ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi } 7187ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi 7197ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi private void onNewPendingIntent(int genId, PendingIntent pi) { 7207ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi synchronized(mGenLock) { 7217ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi if (mClientGenerationIdCurrent != genId) { 7227ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi return; 7237ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi } 7247ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi } 7257ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi synchronized(mInfoLock) { 7267ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi mClientPendingIntentCurrent = pi; 7277ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi } 7287ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi } 7297ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi 7307ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi private void onNewPlaybackInfo(int genId, PlaybackInfo pi) { 7317ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi synchronized(mGenLock) { 7327ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi if (mClientGenerationIdCurrent != genId) { 7337ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi return; 7347ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi } 7357ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi } 7367ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi final OnClientUpdateListener l; 7377ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi synchronized(mInfoLock) { 7387ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi l = this.mOnClientUpdateListener; 7397ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi mLastPlaybackInfo = pi; 7407ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi } 7417ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi if (l != null) { 7427ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi if (pi.mCurrentPosMs == RemoteControlClient.PLAYBACK_POSITION_ALWAYS_UNKNOWN) { 7437ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi l.onClientPlaybackStateUpdate(pi.mState); 7447ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi } else { 7457ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi l.onClientPlaybackStateUpdate(pi.mState, pi.mStateChangeTimeMs, pi.mCurrentPosMs, 7467ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi pi.mSpeed); 7477ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi } 7487ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi } 7497ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi } 7507ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi 7517ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi private void onNewTransportInfo(int genId, int transportControlFlags) { 7527ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi synchronized(mGenLock) { 7537ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi if (mClientGenerationIdCurrent != genId) { 7547ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi return; 7557ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi } 7567ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi } 7577ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi final OnClientUpdateListener l; 7587ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi synchronized(mInfoLock) { 7597ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi l = mOnClientUpdateListener; 7607ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi } 7617ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi if (l != null) { 7627ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi l.onClientTransportControlUpdate(transportControlFlags); 7637ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi } 7647ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi } 7657ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi 7667ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi /** 7677ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi * @param genId 7687ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi * @param metadata guaranteed to be always non-null 7697ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi */ 7707ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi private void onNewMetadata(int genId, Bundle metadata) { 7717ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi synchronized(mGenLock) { 7727ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi if (mClientGenerationIdCurrent != genId) { 7737ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi return; 7747ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi } 7757ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi } 7767ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi final OnClientUpdateListener l; 7777ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi final MetadataEditor metadataEditor; 7787ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi // prepare the received Bundle to be used inside a MetadataEditor 7797ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi final long editableKeys = metadata.getLong( 7807ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi String.valueOf(MediaMetadataEditor.KEY_EDITABLE_MASK), 0); 7817ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi if (editableKeys != 0) { 7827ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi metadata.remove(String.valueOf(MediaMetadataEditor.KEY_EDITABLE_MASK)); 7837ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi } 7847ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi synchronized(mInfoLock) { 7857ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi l = mOnClientUpdateListener; 7867ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi if ((mMetadataEditor != null) && (mMetadataEditor.mEditorMetadata != null)) { 7877ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi if (mMetadataEditor.mEditorMetadata != metadata) { 7887ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi // existing metadata, merge existing and new 7897ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi mMetadataEditor.mEditorMetadata.putAll(metadata); 7907ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi } 791f8895248e2ac4dbb46622f3e04c7256f03175b4fAdam Powell 7926d298811ef642bc4f179ca3e9f4de028fb1ddb74Jean-Michel Trivi mMetadataEditor.putBitmap(MediaMetadataEditor.BITMAP_KEY_ARTWORK, 7936d298811ef642bc4f179ca3e9f4de028fb1ddb74Jean-Michel Trivi (Bitmap)metadata.getParcelable( 7946d298811ef642bc4f179ca3e9f4de028fb1ddb74Jean-Michel Trivi String.valueOf(MediaMetadataEditor.BITMAP_KEY_ARTWORK))); 7956d298811ef642bc4f179ca3e9f4de028fb1ddb74Jean-Michel Trivi mMetadataEditor.cleanupBitmapFromBundle(MediaMetadataEditor.BITMAP_KEY_ARTWORK); 7967ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi } else { 7977ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi mMetadataEditor = new MetadataEditor(metadata, editableKeys); 7987ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi } 7997ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi metadataEditor = mMetadataEditor; 8007ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi } 8017ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi if (l != null) { 8027ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi l.onClientMetadataUpdate(metadataEditor); 8037ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi } 8047ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi } 8057ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi 806a83487e8c618f3c267c3fe3a72d4eb9f1388d07eJean-Michel Trivi private void onClientChange(int genId, boolean clearing) { 8077ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi synchronized(mGenLock) { 8087ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi if (mClientGenerationIdCurrent != genId) { 8097ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi return; 8107ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi } 8117ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi } 8127ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi final OnClientUpdateListener l; 8137ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi synchronized(mInfoLock) { 8147ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi l = mOnClientUpdateListener; 8153b435fb2f0c868c468f3fb2cb2e3ea8314a1755aAdam Powell mMetadataEditor = null; 8167ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi } 8177ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi if (l != null) { 818a83487e8c618f3c267c3fe3a72d4eb9f1388d07eJean-Michel Trivi l.onClientChange(clearing); 8197ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi } 8207ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi } 8217ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi 822f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi private void onDisplayEnable(boolean enabled) { 82319566543c4833f50e7c22aff0c707388f8a338d2Jean-Michel Trivi final OnClientUpdateListener l; 824f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi synchronized(mInfoLock) { 825f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi mEnabled = enabled; 82619566543c4833f50e7c22aff0c707388f8a338d2Jean-Michel Trivi l = this.mOnClientUpdateListener; 82719566543c4833f50e7c22aff0c707388f8a338d2Jean-Michel Trivi } 82819566543c4833f50e7c22aff0c707388f8a338d2Jean-Michel Trivi if (!enabled) { 82919566543c4833f50e7c22aff0c707388f8a338d2Jean-Michel Trivi // when disabling, reset all info sent to the user 83019566543c4833f50e7c22aff0c707388f8a338d2Jean-Michel Trivi final int genId; 83119566543c4833f50e7c22aff0c707388f8a338d2Jean-Michel Trivi synchronized (mGenLock) { 83219566543c4833f50e7c22aff0c707388f8a338d2Jean-Michel Trivi genId = mClientGenerationIdCurrent; 83319566543c4833f50e7c22aff0c707388f8a338d2Jean-Michel Trivi } 83419566543c4833f50e7c22aff0c707388f8a338d2Jean-Michel Trivi // send "stopped" state, happened "now", playback position is 0, speed 0.0f 83519566543c4833f50e7c22aff0c707388f8a338d2Jean-Michel Trivi final PlaybackInfo pi = new PlaybackInfo(RemoteControlClient.PLAYSTATE_STOPPED, 83619566543c4833f50e7c22aff0c707388f8a338d2Jean-Michel Trivi SystemClock.elapsedRealtime() /*stateChangeTimeMs*/, 83719566543c4833f50e7c22aff0c707388f8a338d2Jean-Michel Trivi 0 /*currentPosMs*/, 0.0f /*speed*/); 83819566543c4833f50e7c22aff0c707388f8a338d2Jean-Michel Trivi sendMsg(mEventHandler, MSG_NEW_PLAYBACK_INFO, SENDMSG_REPLACE, 83919566543c4833f50e7c22aff0c707388f8a338d2Jean-Michel Trivi genId /*arg1*/, 0 /*arg2, ignored*/, pi /*obj*/, 0 /*delay*/); 84019566543c4833f50e7c22aff0c707388f8a338d2Jean-Michel Trivi // send "blank" transport control info: no controls are supported 84119566543c4833f50e7c22aff0c707388f8a338d2Jean-Michel Trivi sendMsg(mEventHandler, MSG_NEW_TRANSPORT_INFO, SENDMSG_REPLACE, 84219566543c4833f50e7c22aff0c707388f8a338d2Jean-Michel Trivi genId /*arg1*/, 0 /*arg2, no flags*/, 84319566543c4833f50e7c22aff0c707388f8a338d2Jean-Michel Trivi null /*obj, ignored*/, 0 /*delay*/); 84419566543c4833f50e7c22aff0c707388f8a338d2Jean-Michel Trivi // send dummy metadata with empty string for title and artist, duration of 0 84519566543c4833f50e7c22aff0c707388f8a338d2Jean-Michel Trivi Bundle metadata = new Bundle(3); 84619566543c4833f50e7c22aff0c707388f8a338d2Jean-Michel Trivi metadata.putString(String.valueOf(MediaMetadataRetriever.METADATA_KEY_TITLE), ""); 84719566543c4833f50e7c22aff0c707388f8a338d2Jean-Michel Trivi metadata.putString(String.valueOf(MediaMetadataRetriever.METADATA_KEY_ARTIST), ""); 84819566543c4833f50e7c22aff0c707388f8a338d2Jean-Michel Trivi metadata.putLong(String.valueOf(MediaMetadataRetriever.METADATA_KEY_DURATION), 0); 84919566543c4833f50e7c22aff0c707388f8a338d2Jean-Michel Trivi sendMsg(mEventHandler, MSG_NEW_METADATA, SENDMSG_QUEUE, 85019566543c4833f50e7c22aff0c707388f8a338d2Jean-Michel Trivi genId /*arg1*/, 0 /*arg2, ignored*/, metadata /*obj*/, 0 /*delay*/); 851f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi } 852f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi } 8537ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi 8547ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi //================================================== 8557ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi private static class PlaybackInfo { 8567ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi int mState; 8577ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi long mStateChangeTimeMs; 8587ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi long mCurrentPosMs; 8597ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi float mSpeed; 8607ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi 8617ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi PlaybackInfo(int state, long stateChangeTimeMs, long currentPosMs, float speed) { 8627ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi mState = state; 8637ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi mStateChangeTimeMs = stateChangeTimeMs; 8647ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi mCurrentPosMs = currentPosMs; 8657ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi mSpeed = speed; 8667ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi } 8677ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi } 8687ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi 8697ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi /** 8707ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi * @hide 8717ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi * Used by AudioManager to mark this instance as registered. 8727ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi * @param registered 8737ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi */ 874f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi void setIsRegistered(boolean registered) { 8757ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi synchronized (mInfoLock) { 8767ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi mIsRegistered = registered; 8777ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi } 8787ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi } 8797ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi 8807ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi /** 8817ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi * @hide 8827ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi * Used by AudioManager to access binder to be registered/unregistered inside MediaFocusControl 8837ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi * @return 8847ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi */ 885f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi RcDisplay getRcDisplay() { 8867ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi return mRcd; 8877ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi } 8888ab8c2d06185dfefb5c69e614271f684e77eef63Jean-Michel Trivi 8898ab8c2d06185dfefb5c69e614271f684e77eef63Jean-Michel Trivi /** 8908ab8c2d06185dfefb5c69e614271f684e77eef63Jean-Michel Trivi * @hide 8918ab8c2d06185dfefb5c69e614271f684e77eef63Jean-Michel Trivi * Used by AudioManager to read the current artwork dimension 8928ab8c2d06185dfefb5c69e614271f684e77eef63Jean-Michel Trivi * @return array containing width (index 0) and height (index 1) of currently set artwork size 8938ab8c2d06185dfefb5c69e614271f684e77eef63Jean-Michel Trivi */ 894f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi int[] getArtworkSize() { 8958ab8c2d06185dfefb5c69e614271f684e77eef63Jean-Michel Trivi synchronized (mInfoLock) { 8968ab8c2d06185dfefb5c69e614271f684e77eef63Jean-Michel Trivi int[] size = { mArtworkWidth, mArtworkHeight }; 8978ab8c2d06185dfefb5c69e614271f684e77eef63Jean-Michel Trivi return size; 8988ab8c2d06185dfefb5c69e614271f684e77eef63Jean-Michel Trivi } 8998ab8c2d06185dfefb5c69e614271f684e77eef63Jean-Michel Trivi } 9008ab8c2d06185dfefb5c69e614271f684e77eef63Jean-Michel Trivi 901f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi /** 902f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi * @hide 903f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi * Used by AudioManager to access user listener receiving the client update notifications 904f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi * @return 905f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi */ 906f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi OnClientUpdateListener getUpdateListener() { 907f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi return mOnClientUpdateListener; 908f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi } 9097ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi} 910