RemoteControlClient.java revision ad87f5b40f2a3fd2d506dc15e00b8af28a8fa2ba
1178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi/* 2178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi * Copyright (C) 2011 The Android Open Source Project 3178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi * 4178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi * Licensed under the Apache License, Version 2.0 (the "License"); 5178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi * you may not use this file except in compliance with the License. 6178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi * You may obtain a copy of the License at 7178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi * 8178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi * http://www.apache.org/licenses/LICENSE-2.0 9178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi * 10178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi * Unless required by applicable law or agreed to in writing, software 11178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi * distributed under the License is distributed on an "AS IS" BASIS, 12178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi * See the License for the specific language governing permissions and 14178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi * limitations under the License. 15178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi */ 16178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi 17178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivipackage android.media; 18178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi 196e920e6dac11c3ebf6c0c19402934834e9e491bfJean-Michel Triviimport android.app.PendingIntent; 20178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Triviimport android.content.ComponentName; 216e920e6dac11c3ebf6c0c19402934834e9e491bfJean-Michel Triviimport android.content.Intent; 22178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Triviimport android.graphics.Bitmap; 234426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Triviimport android.graphics.Canvas; 244426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Triviimport android.graphics.Paint; 254426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Triviimport android.graphics.RectF; 265ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Triviimport android.media.MediaMetadataRetriever; 274426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Triviimport android.os.Bundle; 284426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Triviimport android.os.Handler; 294426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Triviimport android.os.Looper; 304426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Triviimport android.os.Message; 314426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Triviimport android.os.RemoteException; 3268622396b62f9084781add1e12f4d513b633ab54Jean-Michel Triviimport android.os.SystemClock; 334426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Triviimport android.util.Log; 344426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi 355ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Triviimport java.lang.IllegalArgumentException; 36178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi 37178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi/** 384426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi * RemoteControlClient enables exposing information meant to be consumed by remote controls 39466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi * capable of displaying metadata, artwork and media transport control buttons. 40ad87f5b40f2a3fd2d506dc15e00b8af28a8fa2baJean-Michel Trivi * 41ad87f5b40f2a3fd2d506dc15e00b8af28a8fa2baJean-Michel Trivi * <p>A remote control client object is associated with a media button event receiver. This 42466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi * event receiver must have been previously registered with 43466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi * {@link AudioManager#registerMediaButtonEventReceiver(ComponentName)} before the 44466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi * RemoteControlClient can be registered through 454426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi * {@link AudioManager#registerRemoteControlClient(RemoteControlClient)}. 46ad87f5b40f2a3fd2d506dc15e00b8af28a8fa2baJean-Michel Trivi * 47ad87f5b40f2a3fd2d506dc15e00b8af28a8fa2baJean-Michel Trivi * <p>Here is an example of creating a RemoteControlClient instance after registering a media 48ad87f5b40f2a3fd2d506dc15e00b8af28a8fa2baJean-Michel Trivi * button event receiver: 49ad87f5b40f2a3fd2d506dc15e00b8af28a8fa2baJean-Michel Trivi * <pre>ComponentName myEventReceiver = new ComponentName(getPackageName(), MyRemoteControlEventReceiver.class.getName()); 50ad87f5b40f2a3fd2d506dc15e00b8af28a8fa2baJean-Michel Trivi * AudioManager myAudioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE); 51ad87f5b40f2a3fd2d506dc15e00b8af28a8fa2baJean-Michel Trivi * myAudioManager.registerMediaButtonEventReceiver(myEventReceiver); 52ad87f5b40f2a3fd2d506dc15e00b8af28a8fa2baJean-Michel Trivi * // build the PendingIntent for the remote control client 53ad87f5b40f2a3fd2d506dc15e00b8af28a8fa2baJean-Michel Trivi * Intent mediaButtonIntent = new Intent(Intent.ACTION_MEDIA_BUTTON); 54ad87f5b40f2a3fd2d506dc15e00b8af28a8fa2baJean-Michel Trivi * mediaButtonIntent.setComponent(myEventReceiver); 55ad87f5b40f2a3fd2d506dc15e00b8af28a8fa2baJean-Michel Trivi * PendingIntent mediaPendingIntent = PendingIntent.getBroadcast(getApplicationContext(), 0, mediaButtonIntent, 0); 56ad87f5b40f2a3fd2d506dc15e00b8af28a8fa2baJean-Michel Trivi * // create and register the remote control client 57ad87f5b40f2a3fd2d506dc15e00b8af28a8fa2baJean-Michel Trivi * RemoteControlClient myRemoteControlClient = new RemoteControlClient(mediaPendingIntent); 58ad87f5b40f2a3fd2d506dc15e00b8af28a8fa2baJean-Michel Trivi * myAudioManager.registerRemoteControlClient(myRemoteControlClient);</pre> 59178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi */ 604426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivipublic class RemoteControlClient 61178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi{ 624426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi private final static String TAG = "RemoteControlClient"; 634426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi 64178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi /** 65178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi * Playback state of a RemoteControlClient which is stopped. 66178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi * 674426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi * @see #setPlaybackState(int) 68178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi */ 69178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi public final static int PLAYSTATE_STOPPED = 1; 70178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi /** 71178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi * Playback state of a RemoteControlClient which is paused. 72178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi * 734426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi * @see #setPlaybackState(int) 74178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi */ 75178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi public final static int PLAYSTATE_PAUSED = 2; 76178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi /** 77178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi * Playback state of a RemoteControlClient which is playing media. 78178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi * 794426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi * @see #setPlaybackState(int) 80178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi */ 81178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi public final static int PLAYSTATE_PLAYING = 3; 82178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi /** 83178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi * Playback state of a RemoteControlClient which is fast forwarding in the media 84178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi * it is currently playing. 85178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi * 864426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi * @see #setPlaybackState(int) 87178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi */ 88178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi public final static int PLAYSTATE_FAST_FORWARDING = 4; 89178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi /** 90178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi * Playback state of a RemoteControlClient which is fast rewinding in the media 91178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi * it is currently playing. 92178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi * 934426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi * @see #setPlaybackState(int) 94178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi */ 95178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi public final static int PLAYSTATE_REWINDING = 5; 96178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi /** 97178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi * Playback state of a RemoteControlClient which is skipping to the next 98178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi * logical chapter (such as a song in a playlist) in the media it is currently playing. 99178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi * 1004426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi * @see #setPlaybackState(int) 101178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi */ 102178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi public final static int PLAYSTATE_SKIPPING_FORWARDS = 6; 103178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi /** 104178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi * Playback state of a RemoteControlClient which is skipping back to the previous 105178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi * logical chapter (such as a song in a playlist) in the media it is currently playing. 106178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi * 1074426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi * @see #setPlaybackState(int) 108178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi */ 109178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi public final static int PLAYSTATE_SKIPPING_BACKWARDS = 7; 110178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi /** 111178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi * Playback state of a RemoteControlClient which is buffering data to play before it can 112178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi * start or resume playback. 113178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi * 1144426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi * @see #setPlaybackState(int) 115178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi */ 116178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi public final static int PLAYSTATE_BUFFERING = 8; 117178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi /** 118178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi * Playback state of a RemoteControlClient which cannot perform any playback related 119178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi * operation because of an internal error. Examples of such situations are no network 120178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi * connectivity when attempting to stream data from a server, or expired user credentials 121178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi * when trying to play subscription-based content. 122178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi * 1234426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi * @see #setPlaybackState(int) 124178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi */ 125178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi public final static int PLAYSTATE_ERROR = 9; 1264426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi /** 1274426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi * @hide 128466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi * The value of a playback state when none has been declared. 129466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi * Intentionally hidden as an application shouldn't set such a playback state value. 1304426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi */ 1314426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi public final static int PLAYSTATE_NONE = 0; 132178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi 133178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi /** 134178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi * Flag indicating a RemoteControlClient makes use of the "previous" media key. 135178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi * 1364426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi * @see #setTransportControlFlags(int) 137178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi * @see android.view.KeyEvent#KEYCODE_MEDIA_PREVIOUS 138178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi */ 139178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi public final static int FLAG_KEY_MEDIA_PREVIOUS = 1 << 0; 140178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi /** 141466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi * Flag indicating a RemoteControlClient makes use of the "rewind" media key. 142178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi * 1434426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi * @see #setTransportControlFlags(int) 144178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi * @see android.view.KeyEvent#KEYCODE_MEDIA_REWIND 145178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi */ 146178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi public final static int FLAG_KEY_MEDIA_REWIND = 1 << 1; 147178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi /** 148178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi * Flag indicating a RemoteControlClient makes use of the "play" media key. 149178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi * 1504426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi * @see #setTransportControlFlags(int) 151178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi * @see android.view.KeyEvent#KEYCODE_MEDIA_PLAY 152178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi */ 153178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi public final static int FLAG_KEY_MEDIA_PLAY = 1 << 2; 154178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi /** 155178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi * Flag indicating a RemoteControlClient makes use of the "play/pause" media key. 156178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi * 1574426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi * @see #setTransportControlFlags(int) 158178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi * @see android.view.KeyEvent#KEYCODE_MEDIA_PLAY_PAUSE 159178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi */ 160178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi public final static int FLAG_KEY_MEDIA_PLAY_PAUSE = 1 << 3; 161178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi /** 162178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi * Flag indicating a RemoteControlClient makes use of the "pause" media key. 163178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi * 1644426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi * @see #setTransportControlFlags(int) 165178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi * @see android.view.KeyEvent#KEYCODE_MEDIA_PAUSE 166178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi */ 167178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi public final static int FLAG_KEY_MEDIA_PAUSE = 1 << 4; 168178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi /** 169178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi * Flag indicating a RemoteControlClient makes use of the "stop" media key. 170178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi * 1714426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi * @see #setTransportControlFlags(int) 172178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi * @see android.view.KeyEvent#KEYCODE_MEDIA_STOP 173178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi */ 174178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi public final static int FLAG_KEY_MEDIA_STOP = 1 << 5; 175178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi /** 176178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi * Flag indicating a RemoteControlClient makes use of the "fast forward" media key. 177178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi * 1784426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi * @see #setTransportControlFlags(int) 179178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi * @see android.view.KeyEvent#KEYCODE_MEDIA_FAST_FORWARD 180178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi */ 181178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi public final static int FLAG_KEY_MEDIA_FAST_FORWARD = 1 << 6; 182178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi /** 183178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi * Flag indicating a RemoteControlClient makes use of the "next" media key. 184178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi * 1854426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi * @see #setTransportControlFlags(int) 186178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi * @see android.view.KeyEvent#KEYCODE_MEDIA_NEXT 187178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi */ 188178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi public final static int FLAG_KEY_MEDIA_NEXT = 1 << 7; 189178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi 190178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi /** 1914426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi * @hide 192466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi * The flags for when no media keys are declared supported. 193466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi * Intentionally hidden as an application shouldn't set the transport control flags 194466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi * to this value. 1954426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi */ 1964426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi public final static int FLAGS_KEY_MEDIA_NONE = 0; 1974426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi 1984426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi /** 1994426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi * @hide 2004426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi * Flag used to signal some type of metadata exposed by the RemoteControlClient is requested. 201178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi */ 2024426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi public final static int FLAG_INFORMATION_REQUEST_METADATA = 1 << 0; 203178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi /** 2044426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi * @hide 205178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi * Flag used to signal that the transport control buttons supported by the 206466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi * RemoteControlClient are requested. 207178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi * This can for instance happen when playback is at the end of a playlist, and the "next" 208178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi * operation is not supported anymore. 209178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi */ 2104426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi public final static int FLAG_INFORMATION_REQUEST_KEY_MEDIA = 1 << 1; 211178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi /** 2124426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi * @hide 213466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi * Flag used to signal that the playback state of the RemoteControlClient is requested. 214178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi */ 2154426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi public final static int FLAG_INFORMATION_REQUEST_PLAYSTATE = 1 << 2; 216178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi /** 2174426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi * @hide 218466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi * Flag used to signal that the album art for the RemoteControlClient is requested. 219178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi */ 2204426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi public final static int FLAG_INFORMATION_REQUEST_ALBUM_ART = 1 << 3; 2214426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi 2224426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi /** 2236e920e6dac11c3ebf6c0c19402934834e9e491bfJean-Michel Trivi * Class constructor. 2246e920e6dac11c3ebf6c0c19402934834e9e491bfJean-Michel Trivi * @param mediaButtonIntent The intent that will be sent for the media button events sent 2256e920e6dac11c3ebf6c0c19402934834e9e491bfJean-Michel Trivi * by remote controls. 2266e920e6dac11c3ebf6c0c19402934834e9e491bfJean-Michel Trivi * This intent needs to have been constructed with the {@link Intent#ACTION_MEDIA_BUTTON} 2276e920e6dac11c3ebf6c0c19402934834e9e491bfJean-Michel Trivi * action, and have a component that will handle the intent (set with 2286e920e6dac11c3ebf6c0c19402934834e9e491bfJean-Michel Trivi * {@link Intent#setComponent(ComponentName)}) registered with 2296e920e6dac11c3ebf6c0c19402934834e9e491bfJean-Michel Trivi * {@link AudioManager#registerMediaButtonEventReceiver(ComponentName)} 2306e920e6dac11c3ebf6c0c19402934834e9e491bfJean-Michel Trivi * before this new RemoteControlClient can itself be registered with 2316e920e6dac11c3ebf6c0c19402934834e9e491bfJean-Michel Trivi * {@link AudioManager#registerRemoteControlClient(RemoteControlClient)}. 2326e920e6dac11c3ebf6c0c19402934834e9e491bfJean-Michel Trivi * @see AudioManager#registerMediaButtonEventReceiver(ComponentName) 2336e920e6dac11c3ebf6c0c19402934834e9e491bfJean-Michel Trivi * @see AudioManager#registerRemoteControlClient(RemoteControlClient) 2346e920e6dac11c3ebf6c0c19402934834e9e491bfJean-Michel Trivi */ 2356e920e6dac11c3ebf6c0c19402934834e9e491bfJean-Michel Trivi public RemoteControlClient(PendingIntent mediaButtonIntent) { 236f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi mRcMediaIntent = mediaButtonIntent; 2376e920e6dac11c3ebf6c0c19402934834e9e491bfJean-Michel Trivi 2386e920e6dac11c3ebf6c0c19402934834e9e491bfJean-Michel Trivi Looper looper; 2396e920e6dac11c3ebf6c0c19402934834e9e491bfJean-Michel Trivi if ((looper = Looper.myLooper()) != null) { 2406e920e6dac11c3ebf6c0c19402934834e9e491bfJean-Michel Trivi mEventHandler = new EventHandler(this, looper); 2416e920e6dac11c3ebf6c0c19402934834e9e491bfJean-Michel Trivi } else if ((looper = Looper.getMainLooper()) != null) { 2426e920e6dac11c3ebf6c0c19402934834e9e491bfJean-Michel Trivi mEventHandler = new EventHandler(this, looper); 2436e920e6dac11c3ebf6c0c19402934834e9e491bfJean-Michel Trivi } else { 2446e920e6dac11c3ebf6c0c19402934834e9e491bfJean-Michel Trivi mEventHandler = null; 2456e920e6dac11c3ebf6c0c19402934834e9e491bfJean-Michel Trivi Log.e(TAG, "RemoteControlClient() couldn't find main application thread"); 2466e920e6dac11c3ebf6c0c19402934834e9e491bfJean-Michel Trivi } 2476e920e6dac11c3ebf6c0c19402934834e9e491bfJean-Michel Trivi } 2486e920e6dac11c3ebf6c0c19402934834e9e491bfJean-Michel Trivi 2496e920e6dac11c3ebf6c0c19402934834e9e491bfJean-Michel Trivi /** 2506e920e6dac11c3ebf6c0c19402934834e9e491bfJean-Michel Trivi * Class constructor for a remote control client whose internal event handling 2516e920e6dac11c3ebf6c0c19402934834e9e491bfJean-Michel Trivi * happens on a user-provided Looper. 2526e920e6dac11c3ebf6c0c19402934834e9e491bfJean-Michel Trivi * @param mediaButtonIntent The intent that will be sent for the media button events sent 2536e920e6dac11c3ebf6c0c19402934834e9e491bfJean-Michel Trivi * by remote controls. 2546e920e6dac11c3ebf6c0c19402934834e9e491bfJean-Michel Trivi * This intent needs to have been constructed with the {@link Intent#ACTION_MEDIA_BUTTON} 2556e920e6dac11c3ebf6c0c19402934834e9e491bfJean-Michel Trivi * action, and have a component that will handle the intent (set with 2566e920e6dac11c3ebf6c0c19402934834e9e491bfJean-Michel Trivi * {@link Intent#setComponent(ComponentName)}) registered with 2576e920e6dac11c3ebf6c0c19402934834e9e491bfJean-Michel Trivi * {@link AudioManager#registerMediaButtonEventReceiver(ComponentName)} 2586e920e6dac11c3ebf6c0c19402934834e9e491bfJean-Michel Trivi * before this new RemoteControlClient can itself be registered with 2596e920e6dac11c3ebf6c0c19402934834e9e491bfJean-Michel Trivi * {@link AudioManager#registerRemoteControlClient(RemoteControlClient)}. 2606e920e6dac11c3ebf6c0c19402934834e9e491bfJean-Michel Trivi * @param looper The Looper running the event loop. 2616e920e6dac11c3ebf6c0c19402934834e9e491bfJean-Michel Trivi * @see AudioManager#registerMediaButtonEventReceiver(ComponentName) 2626e920e6dac11c3ebf6c0c19402934834e9e491bfJean-Michel Trivi * @see AudioManager#registerRemoteControlClient(RemoteControlClient) 2636e920e6dac11c3ebf6c0c19402934834e9e491bfJean-Michel Trivi */ 2646e920e6dac11c3ebf6c0c19402934834e9e491bfJean-Michel Trivi public RemoteControlClient(PendingIntent mediaButtonIntent, Looper looper) { 265f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi mRcMediaIntent = mediaButtonIntent; 2666e920e6dac11c3ebf6c0c19402934834e9e491bfJean-Michel Trivi 2676e920e6dac11c3ebf6c0c19402934834e9e491bfJean-Michel Trivi mEventHandler = new EventHandler(this, looper); 2686e920e6dac11c3ebf6c0c19402934834e9e491bfJean-Michel Trivi } 2696e920e6dac11c3ebf6c0c19402934834e9e491bfJean-Michel Trivi 2705ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Trivi private static final int[] METADATA_KEYS_TYPE_STRING = { 2715ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Trivi MediaMetadataRetriever.METADATA_KEY_ALBUM, 2725ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Trivi MediaMetadataRetriever.METADATA_KEY_ALBUMARTIST, 2735ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Trivi MediaMetadataRetriever.METADATA_KEY_TITLE, 2745ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Trivi MediaMetadataRetriever.METADATA_KEY_ARTIST, 2755ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Trivi MediaMetadataRetriever.METADATA_KEY_AUTHOR, 2765ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Trivi MediaMetadataRetriever.METADATA_KEY_COMPILATION, 2775ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Trivi MediaMetadataRetriever.METADATA_KEY_COMPOSER, 2785ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Trivi MediaMetadataRetriever.METADATA_KEY_DATE, 2795ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Trivi MediaMetadataRetriever.METADATA_KEY_GENRE, 2805ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Trivi MediaMetadataRetriever.METADATA_KEY_TITLE, 2815ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Trivi MediaMetadataRetriever.METADATA_KEY_WRITER }; 2825ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Trivi private static final int[] METADATA_KEYS_TYPE_LONG = { 2835ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Trivi MediaMetadataRetriever.METADATA_KEY_CD_TRACK_NUMBER, 2845ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Trivi MediaMetadataRetriever.METADATA_KEY_DISC_NUMBER, 2855ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Trivi MediaMetadataRetriever.METADATA_KEY_DURATION }; 2865ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Trivi 2874426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi /** 2884426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi * Class used to modify metadata in a {@link RemoteControlClient} object. 289466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi * Use {@link RemoteControlClient#editMetadata(boolean)} to create an instance of an editor, 290466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi * on which you set the metadata for the RemoteControlClient instance. Once all the information 291466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi * has been set, use {@link #apply()} to make it the new metadata that should be displayed 292466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi * for the associated client. Once the metadata has been "applied", you cannot reuse this 293466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi * instance of the MetadataEditor. 2944426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi */ 2954426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi public class MetadataEditor { 296466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi /** 297466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi * @hide 298466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi */ 2994da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi protected boolean mMetadataChanged; 300466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi /** 301466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi * @hide 302466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi */ 3034da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi protected boolean mArtworkChanged; 304466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi /** 305466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi * @hide 306466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi */ 3074da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi protected Bitmap mEditorArtwork; 308466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi /** 309466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi * @hide 310466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi */ 3114da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi protected Bundle mEditorMetadata; 3124da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi private boolean mApplied = false; 3134da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi 3144da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi // only use RemoteControlClient.editMetadata() to get a MetadataEditor instance 3154da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi private MetadataEditor() { } 3164da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi /** 3174da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi * @hide 3184da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi */ 3194da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi public Object clone() throws CloneNotSupportedException { 3204da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi throw new CloneNotSupportedException(); 3214426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi } 3224426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi 3234da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi /** 3245ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Trivi * The metadata key for the content artwork / album art. 3255ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Trivi */ 326466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi public final static int BITMAP_KEY_ARTWORK = 100; 327466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi /** 328466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi * @hide 329466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi * TODO(jmtrivi) have lockscreen and music move to the new key name 330466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi */ 331466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi public final static int METADATA_KEY_ARTWORK = BITMAP_KEY_ARTWORK; 3325ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Trivi 3335ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Trivi /** 3344da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi * Adds textual information to be displayed. 3354da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi * Note that none of the information added after {@link #apply()} has been called, 3364da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi * will be displayed. 337466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi * @param key The identifier of a the metadata field to set. Valid values are 3384da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi * {@link android.media.MediaMetadataRetriever#METADATA_KEY_ALBUM}, 3394da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi * {@link android.media.MediaMetadataRetriever#METADATA_KEY_ALBUMARTIST}, 3404da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi * {@link android.media.MediaMetadataRetriever#METADATA_KEY_TITLE}, 3414da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi * {@link android.media.MediaMetadataRetriever#METADATA_KEY_ARTIST}, 3424da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi * {@link android.media.MediaMetadataRetriever#METADATA_KEY_AUTHOR}, 3434da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi * {@link android.media.MediaMetadataRetriever#METADATA_KEY_COMPILATION}, 3444da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi * {@link android.media.MediaMetadataRetriever#METADATA_KEY_COMPOSER}, 3454da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi * {@link android.media.MediaMetadataRetriever#METADATA_KEY_DATE}, 3464da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi * {@link android.media.MediaMetadataRetriever#METADATA_KEY_GENRE}, 3474da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi * {@link android.media.MediaMetadataRetriever#METADATA_KEY_TITLE}, 348466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi * {@link android.media.MediaMetadataRetriever#METADATA_KEY_WRITER}. 349466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi * @param value The text for the given key, or {@code null} to signify there is no valid 3504da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi * information for the field. 351466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi * @return Returns a reference to the same MetadataEditor object, so you can chain put 352466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi * calls together. 3534da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi */ 3545ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Trivi public synchronized MetadataEditor putString(int key, String value) 3555ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Trivi throws IllegalArgumentException { 3564da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi if (mApplied) { 3574da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi Log.e(TAG, "Can't edit a previously applied MetadataEditor"); 3584da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi return this; 3594da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi } 3605ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Trivi if (!validTypeForKey(key, METADATA_KEYS_TYPE_STRING)) { 3615ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Trivi throw(new IllegalArgumentException("Invalid type 'String' for key "+ key)); 3625ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Trivi } 3634da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi mEditorMetadata.putString(String.valueOf(key), value); 3644da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi mMetadataChanged = true; 3654426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi return this; 3664426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi } 3674426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi 3684da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi /** 369466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi * Adds numerical information to be displayed. 370466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi * Note that none of the information added after {@link #apply()} has been called, 371466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi * will be displayed. 3725ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Trivi * @param key the identifier of a the metadata field to set. Valid values are 3735ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Trivi * {@link android.media.MediaMetadataRetriever#METADATA_KEY_CD_TRACK_NUMBER}, 3745ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Trivi * {@link android.media.MediaMetadataRetriever#METADATA_KEY_DISC_NUMBER}, 3755ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Trivi * {@link android.media.MediaMetadataRetriever#METADATA_KEY_DURATION} (with a value 3765ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Trivi * expressed in milliseconds), 3775ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Trivi * {@link android.media.MediaMetadataRetriever#METADATA_KEY_YEAR}. 378466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi * @param value The long value for the given key 379466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi * @return Returns a reference to the same MetadataEditor object, so you can chain put 380466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi * calls together. 3815ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Trivi * @throws IllegalArgumentException 3824da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi */ 3835ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Trivi public synchronized MetadataEditor putLong(int key, long value) 3845ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Trivi throws IllegalArgumentException { 3855ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Trivi if (mApplied) { 3865ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Trivi Log.e(TAG, "Can't edit a previously applied MetadataEditor"); 3875ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Trivi return this; 3885ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Trivi } 3895ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Trivi if (!validTypeForKey(key, METADATA_KEYS_TYPE_LONG)) { 3905ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Trivi throw(new IllegalArgumentException("Invalid type 'long' for key "+ key)); 3915ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Trivi } 3925ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Trivi mEditorMetadata.putLong(String.valueOf(key), value); 3935ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Trivi mMetadataChanged = true; 3945ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Trivi return this; 3955ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Trivi } 3964da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi 3974da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi /** 3984da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi * Sets the album / artwork picture to be displayed on the remote control. 399466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi * @param key the identifier of the bitmap to set. The only valid value is 400466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi * {@link #BITMAP_KEY_ARTWORK} 401466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi * @param bitmap The bitmap for the artwork, or null if there isn't any. 402466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi * @return Returns a reference to the same MetadataEditor object, so you can chain put 403466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi * calls together. 4045ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Trivi * @throws IllegalArgumentException 4054da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi * @see android.graphics.Bitmap 4064da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi */ 4075ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Trivi public synchronized MetadataEditor putBitmap(int key, Bitmap bitmap) 4085ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Trivi throws IllegalArgumentException { 4094da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi if (mApplied) { 4104da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi Log.e(TAG, "Can't edit a previously applied MetadataEditor"); 4114da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi return this; 4124da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi } 413466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi if (key != BITMAP_KEY_ARTWORK) { 4145ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Trivi throw(new IllegalArgumentException("Invalid type 'Bitmap' for key "+ key)); 4154da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi } 4164da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi if ((mArtworkExpectedWidth > 0) && (mArtworkExpectedHeight > 0)) { 4174da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi mEditorArtwork = scaleBitmapIfTooBig(bitmap, 4184da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi mArtworkExpectedWidth, mArtworkExpectedHeight); 4194da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi } else { 4204da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi // no valid resize dimensions, store as is 4214da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi mEditorArtwork = bitmap; 4224da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi } 4234da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi mArtworkChanged = true; 4244da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi return this; 4254426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi } 426178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi 4274da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi /** 428466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi * Clears all the metadata that has been set since the MetadataEditor instance was 429466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi * created with {@link RemoteControlClient#editMetadata(boolean)}. 4304da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi */ 4314da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi public synchronized void clear() { 4324da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi if (mApplied) { 4334da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi Log.e(TAG, "Can't clear a previously applied MetadataEditor"); 4344da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi return; 4354da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi } 4364da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi mEditorMetadata.clear(); 4374da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi mEditorArtwork = null; 4384426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi } 439178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi 4404da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi /** 441466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi * Associates all the metadata that has been set since the MetadataEditor instance was 442466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi * created with {@link RemoteControlClient#editMetadata(boolean)}, or since 443466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi * {@link #clear()} was called, with the RemoteControlClient. Once "applied", 444466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi * this MetadataEditor cannot be reused to edit the RemoteControlClient's metadata. 4454da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi */ 4464da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi public synchronized void apply() { 4474da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi if (mApplied) { 4484da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi Log.e(TAG, "Can't apply a previously applied MetadataEditor"); 4494da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi return; 4504da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi } 4514da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi synchronized(mCacheLock) { 4524da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi // assign the edited data 4534da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi mMetadata = new Bundle(mEditorMetadata); 45434d0d300cac645b48cce5a1735f45e1102d4ef0eJean-Michel Trivi if ((mArtwork != null) && (!mArtwork.equals(mEditorArtwork))) { 45534d0d300cac645b48cce5a1735f45e1102d4ef0eJean-Michel Trivi mArtwork.recycle(); 45634d0d300cac645b48cce5a1735f45e1102d4ef0eJean-Michel Trivi } 4574da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi mArtwork = mEditorArtwork; 45834d0d300cac645b48cce5a1735f45e1102d4ef0eJean-Michel Trivi mEditorArtwork = null; 4594da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi if (mMetadataChanged & mArtworkChanged) { 4604da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi // send to remote control display if conditions are met 46144413e5b514a91806a4bb4c7780029ea43be6f81Jean-Michel Trivi sendMetadataWithArtwork_syncCacheLock(); 4624da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi } else if (mMetadataChanged) { 4634da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi // send to remote control display if conditions are met 4644da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi sendMetadata_syncCacheLock(); 4654da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi } else if (mArtworkChanged) { 4664da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi // send to remote control display if conditions are met 4674da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi sendArtwork_syncCacheLock(); 4684da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi } 4694da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi mApplied = true; 4704da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi } 4714426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi } 4724426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi } 4734426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi 4744426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi /** 475466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi * Creates a {@link MetadataEditor}. 476466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi * @param startEmpty Set to false if you want the MetadataEditor to contain the metadata that 477466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi * was previously applied to the RemoteControlClient, or true if it is to be created empty. 478466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi * @return a new MetadataEditor instance. 4794426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi */ 4804da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi public MetadataEditor editMetadata(boolean startEmpty) { 4814da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi MetadataEditor editor = new MetadataEditor(); 4824da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi if (startEmpty) { 4834da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi editor.mEditorMetadata = new Bundle(); 4844da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi editor.mEditorArtwork = null; 4854da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi editor.mMetadataChanged = true; 4864da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi editor.mArtworkChanged = true; 4874da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi } else { 4884da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi editor.mEditorMetadata = new Bundle(mMetadata); 4894da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi editor.mEditorArtwork = mArtwork; 4904da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi editor.mMetadataChanged = false; 4914da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi editor.mArtworkChanged = false; 4924426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi } 4934da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi return editor; 4944426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi } 4954426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi 4964426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi /** 4974426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi * Sets the current playback state. 498466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi * @param state The current playback state, one of the following values: 499178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi * {@link #PLAYSTATE_STOPPED}, 500178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi * {@link #PLAYSTATE_PAUSED}, 501178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi * {@link #PLAYSTATE_PLAYING}, 502178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi * {@link #PLAYSTATE_FAST_FORWARDING}, 503178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi * {@link #PLAYSTATE_REWINDING}, 504178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi * {@link #PLAYSTATE_SKIPPING_FORWARDS}, 505178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi * {@link #PLAYSTATE_SKIPPING_BACKWARDS}, 506178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi * {@link #PLAYSTATE_BUFFERING}, 507178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi * {@link #PLAYSTATE_ERROR}. 508178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi */ 5094426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi public void setPlaybackState(int state) { 5104426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi synchronized(mCacheLock) { 51168622396b62f9084781add1e12f4d513b633ab54Jean-Michel Trivi if (mPlaybackState != state) { 51268622396b62f9084781add1e12f4d513b633ab54Jean-Michel Trivi // store locally 51368622396b62f9084781add1e12f4d513b633ab54Jean-Michel Trivi mPlaybackState = state; 51468622396b62f9084781add1e12f4d513b633ab54Jean-Michel Trivi // keep track of when the state change occurred 51568622396b62f9084781add1e12f4d513b633ab54Jean-Michel Trivi mPlaybackStateChangeTimeMs = SystemClock.elapsedRealtime(); 51668622396b62f9084781add1e12f4d513b633ab54Jean-Michel Trivi 51768622396b62f9084781add1e12f4d513b633ab54Jean-Michel Trivi // send to remote control display if conditions are met 51868622396b62f9084781add1e12f4d513b633ab54Jean-Michel Trivi sendPlaybackState_syncCacheLock(); 51968622396b62f9084781add1e12f4d513b633ab54Jean-Michel Trivi } 5204426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi } 5214426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi } 522178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi 523178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi /** 5244426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi * Sets the flags for the media transport control buttons that this client supports. 525466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi * @param transportControlFlags A combination of the following flags: 5264426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi * {@link #FLAG_KEY_MEDIA_PREVIOUS}, 527178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi * {@link #FLAG_KEY_MEDIA_REWIND}, 528178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi * {@link #FLAG_KEY_MEDIA_PLAY}, 529178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi * {@link #FLAG_KEY_MEDIA_PLAY_PAUSE}, 530178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi * {@link #FLAG_KEY_MEDIA_PAUSE}, 531178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi * {@link #FLAG_KEY_MEDIA_STOP}, 532178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi * {@link #FLAG_KEY_MEDIA_FAST_FORWARD}, 533178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi * {@link #FLAG_KEY_MEDIA_NEXT} 534178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi */ 5354426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi public void setTransportControlFlags(int transportControlFlags) { 5364426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi synchronized(mCacheLock) { 5374426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi // store locally 5384426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi mTransportControlFlags = transportControlFlags; 5394426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi 5404426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi // send to remote control display if conditions are met 5414426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi sendTransportControlFlags_syncCacheLock(); 5424426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi } 5434426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi } 544178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi 545178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi /** 5464426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi * Lock for all cached data 5474426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi */ 5484426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi private final Object mCacheLock = new Object(); 5494426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi /** 5504426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi * Cache for the playback state. 5514426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi * Access synchronized on mCacheLock 552178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi */ 5534426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi private int mPlaybackState = PLAYSTATE_NONE; 5544426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi /** 55568622396b62f9084781add1e12f4d513b633ab54Jean-Michel Trivi * Time of last play state change 55668622396b62f9084781add1e12f4d513b633ab54Jean-Michel Trivi * Access synchronized on mCacheLock 55768622396b62f9084781add1e12f4d513b633ab54Jean-Michel Trivi */ 55868622396b62f9084781add1e12f4d513b633ab54Jean-Michel Trivi private long mPlaybackStateChangeTimeMs = 0; 55968622396b62f9084781add1e12f4d513b633ab54Jean-Michel Trivi /** 5604426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi * Cache for the artwork bitmap. 5614426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi * Access synchronized on mCacheLock 5624da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi * Artwork and metadata are not kept in one Bundle because the bitmap sometimes needs to be 5634da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi * accessed to be resized, in which case a copy will be made. This would add overhead in 5644da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi * Bundle operations. 5654426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi */ 5664426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi private Bitmap mArtwork; 5674426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi private final int ARTWORK_DEFAULT_SIZE = 256; 56844413e5b514a91806a4bb4c7780029ea43be6f81Jean-Michel Trivi private final int ARTWORK_INVALID_SIZE = -1; 5694426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi private int mArtworkExpectedWidth = ARTWORK_DEFAULT_SIZE; 5704426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi private int mArtworkExpectedHeight = ARTWORK_DEFAULT_SIZE; 5714426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi /** 5724426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi * Cache for the transport control mask. 5734426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi * Access synchronized on mCacheLock 5744426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi */ 5754426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi private int mTransportControlFlags = FLAGS_KEY_MEDIA_NONE; 5764426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi /** 5774426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi * Cache for the metadata strings. 5784426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi * Access synchronized on mCacheLock 5794426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi */ 5804426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi private Bundle mMetadata = new Bundle(); 5814da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi 5824426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi /** 5834426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi * The current remote control client generation ID across the system 5844426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi */ 5854426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi private int mCurrentClientGenId = -1; 5864426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi /** 5874426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi * The remote control client generation ID, the last time it was told it was the current RC. 5884426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi * If (mCurrentClientGenId == mInternalClientGenId) is true, it means that this remote control 5894426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi * client is the "focused" one, and that whenever this client's info is updated, it needs to 5904426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi * send it to the known IRemoteControlDisplay interfaces. 5914426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi */ 5924426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi private int mInternalClientGenId = -2; 5934426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi 5944426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi /** 595f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi * The media button intent description associated with this remote control client 596f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi * (can / should include target component for intent handling) 5974426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi */ 598f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi private final PendingIntent mRcMediaIntent; 5994426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi 6004426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi /** 6014426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi * The remote control display to which this client will send information. 6024426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi * NOTE: Only one IRemoteControlDisplay supported in this implementation 6034426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi */ 6044426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi private IRemoteControlDisplay mRcDisplay; 6054426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi 6064426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi /** 6074426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi * @hide 608f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi * Accessor to media button intent description (includes target component) 6094426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi */ 610f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi public PendingIntent getRcMediaIntent() { 611f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi return mRcMediaIntent; 6124426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi } 6134426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi /** 6144426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi * @hide 6154426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi * Accessor to IRemoteControlClient 6164426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi */ 6174426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi public IRemoteControlClient getIRemoteControlClient() { 6184426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi return mIRCC; 6194426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi } 6204426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi 6214426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi /** 6224426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi * The IRemoteControlClient implementation 6234426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi */ 6244426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi private IRemoteControlClient mIRCC = new IRemoteControlClient.Stub() { 6254426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi 6264426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi public void onInformationRequested(int clientGeneration, int infoFlags, 6274426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi int artWidth, int artHeight) { 6284426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi // only post messages, we can't block here 6294426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi if (mEventHandler != null) { 6304426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi // signal new client 6314426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi mEventHandler.removeMessages(MSG_NEW_INTERNAL_CLIENT_GEN); 6324426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi mEventHandler.dispatchMessage( 6334426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi mEventHandler.obtainMessage( 6344426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi MSG_NEW_INTERNAL_CLIENT_GEN, 6354426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi artWidth, artHeight, 6364426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi new Integer(clientGeneration))); 6374426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi // send the information 6384426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi mEventHandler.removeMessages(MSG_REQUEST_PLAYBACK_STATE); 6394426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi mEventHandler.removeMessages(MSG_REQUEST_METADATA); 6404426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi mEventHandler.removeMessages(MSG_REQUEST_TRANSPORTCONTROL); 6414426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi mEventHandler.removeMessages(MSG_REQUEST_ARTWORK); 6424426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi mEventHandler.dispatchMessage( 6434426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi mEventHandler.obtainMessage(MSG_REQUEST_PLAYBACK_STATE)); 6444426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi mEventHandler.dispatchMessage( 6454426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi mEventHandler.obtainMessage(MSG_REQUEST_TRANSPORTCONTROL)); 6464426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi mEventHandler.dispatchMessage(mEventHandler.obtainMessage(MSG_REQUEST_METADATA)); 6474426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi mEventHandler.dispatchMessage(mEventHandler.obtainMessage(MSG_REQUEST_ARTWORK)); 6484426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi } 6494426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi } 6504426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi 6514426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi public void setCurrentClientGenerationId(int clientGeneration) { 6524426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi // only post messages, we can't block here 6534426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi if (mEventHandler != null) { 6544426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi mEventHandler.removeMessages(MSG_NEW_CURRENT_CLIENT_GEN); 6554426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi mEventHandler.dispatchMessage(mEventHandler.obtainMessage( 6564426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi MSG_NEW_CURRENT_CLIENT_GEN, clientGeneration, 0/*ignored*/)); 6574426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi } 6584426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi } 6594426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi 6604426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi public void plugRemoteControlDisplay(IRemoteControlDisplay rcd) { 6614426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi // only post messages, we can't block here 6624426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi if (mEventHandler != null) { 6634426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi mEventHandler.dispatchMessage(mEventHandler.obtainMessage( 6644426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi MSG_PLUG_DISPLAY, rcd)); 6654426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi } 6664426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi } 6674426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi 6684426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi public void unplugRemoteControlDisplay(IRemoteControlDisplay rcd) { 6694426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi // only post messages, we can't block here 6704426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi if (mEventHandler != null) { 6714426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi mEventHandler.dispatchMessage(mEventHandler.obtainMessage( 6724426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi MSG_UNPLUG_DISPLAY, rcd)); 6734426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi } 6744426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi } 6754426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi }; 6764426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi 6774426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi private EventHandler mEventHandler; 6784426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi private final static int MSG_REQUEST_PLAYBACK_STATE = 1; 6794426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi private final static int MSG_REQUEST_METADATA = 2; 6804426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi private final static int MSG_REQUEST_TRANSPORTCONTROL = 3; 6814426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi private final static int MSG_REQUEST_ARTWORK = 4; 6824426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi private final static int MSG_NEW_INTERNAL_CLIENT_GEN = 5; 6834426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi private final static int MSG_NEW_CURRENT_CLIENT_GEN = 6; 6844426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi private final static int MSG_PLUG_DISPLAY = 7; 6854426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi private final static int MSG_UNPLUG_DISPLAY = 8; 6864426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi 6874426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi private class EventHandler extends Handler { 6884426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi public EventHandler(RemoteControlClient rcc, Looper looper) { 6894426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi super(looper); 6904426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi } 6914426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi 6924426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi @Override 6934426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi public void handleMessage(Message msg) { 6944426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi switch(msg.what) { 6954426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi case MSG_REQUEST_PLAYBACK_STATE: 6964426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi synchronized (mCacheLock) { 6974426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi sendPlaybackState_syncCacheLock(); 6984426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi } 6994426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi break; 7004426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi case MSG_REQUEST_METADATA: 7014426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi synchronized (mCacheLock) { 7024426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi sendMetadata_syncCacheLock(); 7034426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi } 7044426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi break; 7054426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi case MSG_REQUEST_TRANSPORTCONTROL: 7064426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi synchronized (mCacheLock) { 7074426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi sendTransportControlFlags_syncCacheLock(); 7084426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi } 7094426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi break; 7104426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi case MSG_REQUEST_ARTWORK: 7114426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi synchronized (mCacheLock) { 7124426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi sendArtwork_syncCacheLock(); 7134426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi } 7144426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi break; 7154426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi case MSG_NEW_INTERNAL_CLIENT_GEN: 7164426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi onNewInternalClientGen((Integer)msg.obj, msg.arg1, msg.arg2); 7174426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi break; 7184426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi case MSG_NEW_CURRENT_CLIENT_GEN: 7194426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi onNewCurrentClientGen(msg.arg1); 7204426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi break; 7214426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi case MSG_PLUG_DISPLAY: 7224426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi onPlugDisplay((IRemoteControlDisplay)msg.obj); 7234426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi break; 7244426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi case MSG_UNPLUG_DISPLAY: 7254426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi onUnplugDisplay((IRemoteControlDisplay)msg.obj); 7264426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi break; 7274426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi default: 7284426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi Log.e(TAG, "Unknown event " + msg.what + " in RemoteControlClient handler"); 7294426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi } 7304426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi } 7314426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi } 7324426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi 73344413e5b514a91806a4bb4c7780029ea43be6f81Jean-Michel Trivi private void detachFromDisplay_syncCacheLock() { 73444413e5b514a91806a4bb4c7780029ea43be6f81Jean-Michel Trivi mRcDisplay = null; 73544413e5b514a91806a4bb4c7780029ea43be6f81Jean-Michel Trivi mArtworkExpectedWidth = ARTWORK_INVALID_SIZE; 73644413e5b514a91806a4bb4c7780029ea43be6f81Jean-Michel Trivi mArtworkExpectedHeight = ARTWORK_INVALID_SIZE; 73744413e5b514a91806a4bb4c7780029ea43be6f81Jean-Michel Trivi } 73844413e5b514a91806a4bb4c7780029ea43be6f81Jean-Michel Trivi 7394426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi private void sendPlaybackState_syncCacheLock() { 7404426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi if ((mCurrentClientGenId == mInternalClientGenId) && (mRcDisplay != null)) { 7414426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi try { 74268622396b62f9084781add1e12f4d513b633ab54Jean-Michel Trivi mRcDisplay.setPlaybackState(mInternalClientGenId, mPlaybackState, 74368622396b62f9084781add1e12f4d513b633ab54Jean-Michel Trivi mPlaybackStateChangeTimeMs); 7444426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi } catch (RemoteException e) { 7454426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi Log.e(TAG, "Error in setPlaybackState(), dead display "+e); 74644413e5b514a91806a4bb4c7780029ea43be6f81Jean-Michel Trivi detachFromDisplay_syncCacheLock(); 7474426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi } 7484426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi } 7494426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi } 7504426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi 7514426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi private void sendMetadata_syncCacheLock() { 7524426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi if ((mCurrentClientGenId == mInternalClientGenId) && (mRcDisplay != null)) { 7534426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi try { 7544426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi mRcDisplay.setMetadata(mInternalClientGenId, mMetadata); 7554426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi } catch (RemoteException e) { 7564426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi Log.e(TAG, "Error in sendPlaybackState(), dead display "+e); 75744413e5b514a91806a4bb4c7780029ea43be6f81Jean-Michel Trivi detachFromDisplay_syncCacheLock(); 7584426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi } 7594426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi } 7604426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi } 7614426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi 7624426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi private void sendTransportControlFlags_syncCacheLock() { 7634426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi if ((mCurrentClientGenId == mInternalClientGenId) && (mRcDisplay != null)) { 7644426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi try { 7654426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi mRcDisplay.setTransportControlFlags(mInternalClientGenId, 7664426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi mTransportControlFlags); 7674426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi } catch (RemoteException e) { 7684426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi Log.e(TAG, "Error in sendTransportControlFlags(), dead display "+e); 76944413e5b514a91806a4bb4c7780029ea43be6f81Jean-Michel Trivi detachFromDisplay_syncCacheLock(); 7704426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi } 7714426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi } 7724426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi } 7734426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi 7744426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi private void sendArtwork_syncCacheLock() { 7754426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi if ((mCurrentClientGenId == mInternalClientGenId) && (mRcDisplay != null)) { 7764426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi // even though we have already scaled in setArtwork(), when this client needs to 7774426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi // send the bitmap, there might be newer and smaller expected dimensions, so we have 7784426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi // to check again. 7794426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi mArtwork = scaleBitmapIfTooBig(mArtwork, mArtworkExpectedWidth, mArtworkExpectedHeight); 7804426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi try { 7814426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi mRcDisplay.setArtwork(mInternalClientGenId, mArtwork); 7824426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi } catch (RemoteException e) { 7834426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi Log.e(TAG, "Error in sendArtwork(), dead display "+e); 78444413e5b514a91806a4bb4c7780029ea43be6f81Jean-Michel Trivi detachFromDisplay_syncCacheLock(); 78544413e5b514a91806a4bb4c7780029ea43be6f81Jean-Michel Trivi } 78644413e5b514a91806a4bb4c7780029ea43be6f81Jean-Michel Trivi } 78744413e5b514a91806a4bb4c7780029ea43be6f81Jean-Michel Trivi } 78844413e5b514a91806a4bb4c7780029ea43be6f81Jean-Michel Trivi 78944413e5b514a91806a4bb4c7780029ea43be6f81Jean-Michel Trivi private void sendMetadataWithArtwork_syncCacheLock() { 79044413e5b514a91806a4bb4c7780029ea43be6f81Jean-Michel Trivi if ((mCurrentClientGenId == mInternalClientGenId) && (mRcDisplay != null)) { 79144413e5b514a91806a4bb4c7780029ea43be6f81Jean-Michel Trivi // even though we have already scaled in setArtwork(), when this client needs to 79244413e5b514a91806a4bb4c7780029ea43be6f81Jean-Michel Trivi // send the bitmap, there might be newer and smaller expected dimensions, so we have 79344413e5b514a91806a4bb4c7780029ea43be6f81Jean-Michel Trivi // to check again. 79444413e5b514a91806a4bb4c7780029ea43be6f81Jean-Michel Trivi mArtwork = scaleBitmapIfTooBig(mArtwork, mArtworkExpectedWidth, mArtworkExpectedHeight); 79544413e5b514a91806a4bb4c7780029ea43be6f81Jean-Michel Trivi try { 79644413e5b514a91806a4bb4c7780029ea43be6f81Jean-Michel Trivi mRcDisplay.setAllMetadata(mInternalClientGenId, mMetadata, mArtwork); 79744413e5b514a91806a4bb4c7780029ea43be6f81Jean-Michel Trivi } catch (RemoteException e) { 79844413e5b514a91806a4bb4c7780029ea43be6f81Jean-Michel Trivi Log.e(TAG, "Error in setAllMetadata(), dead display "+e); 79944413e5b514a91806a4bb4c7780029ea43be6f81Jean-Michel Trivi detachFromDisplay_syncCacheLock(); 8004426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi } 8014426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi } 8024426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi } 8034426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi 8044426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi private void onNewInternalClientGen(Integer clientGeneration, int artWidth, int artHeight) { 8054426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi synchronized (mCacheLock) { 8064426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi // this remote control client is told it is the "focused" one: 8074426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi // it implies that now (mCurrentClientGenId == mInternalClientGenId) is true 8084426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi mInternalClientGenId = clientGeneration.intValue(); 8094426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi if (artWidth > 0) { 8104426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi mArtworkExpectedWidth = artWidth; 8114426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi mArtworkExpectedHeight = artHeight; 8124426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi } 8134426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi } 8144426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi } 8154426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi 8164426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi private void onNewCurrentClientGen(int clientGeneration) { 8174426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi synchronized (mCacheLock) { 8184426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi mCurrentClientGenId = clientGeneration; 8194426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi } 8204426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi } 8214426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi 8224426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi private void onPlugDisplay(IRemoteControlDisplay rcd) { 8234426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi synchronized(mCacheLock) { 8244426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi mRcDisplay = rcd; 8254426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi } 8264426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi } 8274426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi 8284426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi private void onUnplugDisplay(IRemoteControlDisplay rcd) { 8294426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi synchronized(mCacheLock) { 8307309c83b95b36eac141680158df70ac1ce02a160Jean-Michel Trivi if ((mRcDisplay != null) && (mRcDisplay.asBinder().equals(rcd.asBinder()))) { 8314426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi mRcDisplay = null; 8324426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi mArtworkExpectedWidth = ARTWORK_DEFAULT_SIZE; 8334426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi mArtworkExpectedHeight = ARTWORK_DEFAULT_SIZE; 8344426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi } 8354426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi } 8364426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi } 8374426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi 8384426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi /** 8394426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi * Scale a bitmap to fit the smallest dimension by uniformly scaling the incoming bitmap. 8404426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi * If the bitmap fits, then do nothing and return the original. 8414426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi * 8424426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi * @param bitmap 8434426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi * @param maxWidth 8444426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi * @param maxHeight 8454426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi * @return 8464426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi */ 8474426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi 8484426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi private Bitmap scaleBitmapIfTooBig(Bitmap bitmap, int maxWidth, int maxHeight) { 8496e679d5a53091b348a2cdc0c76f4e8fa4ac52d4bJean-Michel Trivi if (bitmap != null) { 8506e679d5a53091b348a2cdc0c76f4e8fa4ac52d4bJean-Michel Trivi final int width = bitmap.getWidth(); 8516e679d5a53091b348a2cdc0c76f4e8fa4ac52d4bJean-Michel Trivi final int height = bitmap.getHeight(); 8526e679d5a53091b348a2cdc0c76f4e8fa4ac52d4bJean-Michel Trivi if (width > maxWidth || height > maxHeight) { 8536e679d5a53091b348a2cdc0c76f4e8fa4ac52d4bJean-Michel Trivi float scale = Math.min((float) maxWidth / width, (float) maxHeight / height); 8546e679d5a53091b348a2cdc0c76f4e8fa4ac52d4bJean-Michel Trivi int newWidth = Math.round(scale * width); 8556e679d5a53091b348a2cdc0c76f4e8fa4ac52d4bJean-Michel Trivi int newHeight = Math.round(scale * height); 8566e679d5a53091b348a2cdc0c76f4e8fa4ac52d4bJean-Michel Trivi Bitmap outBitmap = Bitmap.createBitmap(newWidth, newHeight, bitmap.getConfig()); 8576e679d5a53091b348a2cdc0c76f4e8fa4ac52d4bJean-Michel Trivi Canvas canvas = new Canvas(outBitmap); 8586e679d5a53091b348a2cdc0c76f4e8fa4ac52d4bJean-Michel Trivi Paint paint = new Paint(); 8596e679d5a53091b348a2cdc0c76f4e8fa4ac52d4bJean-Michel Trivi paint.setAntiAlias(true); 8606e679d5a53091b348a2cdc0c76f4e8fa4ac52d4bJean-Michel Trivi paint.setFilterBitmap(true); 8616e679d5a53091b348a2cdc0c76f4e8fa4ac52d4bJean-Michel Trivi canvas.drawBitmap(bitmap, null, 8626e679d5a53091b348a2cdc0c76f4e8fa4ac52d4bJean-Michel Trivi new RectF(0, 0, outBitmap.getWidth(), outBitmap.getHeight()), paint); 8636e679d5a53091b348a2cdc0c76f4e8fa4ac52d4bJean-Michel Trivi bitmap = outBitmap; 8646e679d5a53091b348a2cdc0c76f4e8fa4ac52d4bJean-Michel Trivi } 8654426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi } 8664426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi return bitmap; 8675ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Trivi } 8684426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi 8695ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Trivi /** 8705ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Trivi * Fast routine to go through an array of allowed keys and return whether the key is part 8715ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Trivi * of that array 8725ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Trivi * @param key the key value 8735ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Trivi * @param validKeys the array of valid keys for a given type 8745ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Trivi * @return true if the key is part of the array, false otherwise 8755ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Trivi */ 8765ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Trivi private static boolean validTypeForKey(int key, int[] validKeys) { 8775ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Trivi try { 8785ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Trivi for (int i = 0 ; ; i++) { 8795ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Trivi if (key == validKeys[i]) { 8805ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Trivi return true; 8815ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Trivi } 8825ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Trivi } 8835ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Trivi } catch (ArrayIndexOutOfBoundsException e) { 8845ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Trivi return false; 8855ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Trivi } 8864426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi } 887178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi} 888