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