RemoteControlClient.java revision 3114ce3861f20f9a5c2c59dd2629197a1f4874a8
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;
213114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Triviimport android.content.Context;
226e920e6dac11c3ebf6c0c19402934834e9e491bfJean-Michel Triviimport android.content.Intent;
23178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Triviimport android.graphics.Bitmap;
244426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Triviimport android.graphics.Canvas;
254426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Triviimport android.graphics.Paint;
264426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Triviimport android.graphics.RectF;
275ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Triviimport android.media.MediaMetadataRetriever;
284426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Triviimport android.os.Bundle;
294426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Triviimport android.os.Handler;
303114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Triviimport android.os.IBinder;
314426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Triviimport android.os.Looper;
324426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Triviimport android.os.Message;
334426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Triviimport android.os.RemoteException;
343114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Triviimport android.os.ServiceManager;
3568622396b62f9084781add1e12f4d513b633ab54Jean-Michel Triviimport android.os.SystemClock;
364426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Triviimport android.util.Log;
374426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi
385ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Triviimport java.lang.IllegalArgumentException;
39178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi
40178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi/**
414426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi * RemoteControlClient enables exposing information meant to be consumed by remote controls
42466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi * capable of displaying metadata, artwork and media transport control buttons.
43ad87f5b40f2a3fd2d506dc15e00b8af28a8fa2baJean-Michel Trivi *
44ad87f5b40f2a3fd2d506dc15e00b8af28a8fa2baJean-Michel Trivi * <p>A remote control client object is associated with a media button event receiver. This
45466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi * event receiver must have been previously registered with
46466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi * {@link AudioManager#registerMediaButtonEventReceiver(ComponentName)} before the
47466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi * RemoteControlClient can be registered through
484426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi * {@link AudioManager#registerRemoteControlClient(RemoteControlClient)}.
49ad87f5b40f2a3fd2d506dc15e00b8af28a8fa2baJean-Michel Trivi *
50ad87f5b40f2a3fd2d506dc15e00b8af28a8fa2baJean-Michel Trivi * <p>Here is an example of creating a RemoteControlClient instance after registering a media
51ad87f5b40f2a3fd2d506dc15e00b8af28a8fa2baJean-Michel Trivi * button event receiver:
52ad87f5b40f2a3fd2d506dc15e00b8af28a8fa2baJean-Michel Trivi * <pre>ComponentName myEventReceiver = new ComponentName(getPackageName(), MyRemoteControlEventReceiver.class.getName());
53ad87f5b40f2a3fd2d506dc15e00b8af28a8fa2baJean-Michel Trivi * AudioManager myAudioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
54ad87f5b40f2a3fd2d506dc15e00b8af28a8fa2baJean-Michel Trivi * myAudioManager.registerMediaButtonEventReceiver(myEventReceiver);
55ad87f5b40f2a3fd2d506dc15e00b8af28a8fa2baJean-Michel Trivi * // build the PendingIntent for the remote control client
56ad87f5b40f2a3fd2d506dc15e00b8af28a8fa2baJean-Michel Trivi * Intent mediaButtonIntent = new Intent(Intent.ACTION_MEDIA_BUTTON);
57ad87f5b40f2a3fd2d506dc15e00b8af28a8fa2baJean-Michel Trivi * mediaButtonIntent.setComponent(myEventReceiver);
58ad87f5b40f2a3fd2d506dc15e00b8af28a8fa2baJean-Michel Trivi * PendingIntent mediaPendingIntent = PendingIntent.getBroadcast(getApplicationContext(), 0, mediaButtonIntent, 0);
59ad87f5b40f2a3fd2d506dc15e00b8af28a8fa2baJean-Michel Trivi * // create and register the remote control client
60ad87f5b40f2a3fd2d506dc15e00b8af28a8fa2baJean-Michel Trivi * RemoteControlClient myRemoteControlClient = new RemoteControlClient(mediaPendingIntent);
61ad87f5b40f2a3fd2d506dc15e00b8af28a8fa2baJean-Michel Trivi * myAudioManager.registerRemoteControlClient(myRemoteControlClient);</pre>
62178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi */
634426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivipublic class RemoteControlClient
64178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi{
654426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    private final static String TAG = "RemoteControlClient";
664426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi
67178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi    /**
68178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     * Playback state of a RemoteControlClient which is stopped.
69178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     *
704426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     * @see #setPlaybackState(int)
71178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     */
72178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi    public final static int PLAYSTATE_STOPPED            = 1;
73178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi    /**
74178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     * Playback state of a RemoteControlClient which is paused.
75178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     *
764426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     * @see #setPlaybackState(int)
77178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     */
78178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi    public final static int PLAYSTATE_PAUSED             = 2;
79178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi    /**
80178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     * Playback state of a RemoteControlClient which is playing media.
81178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     *
824426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     * @see #setPlaybackState(int)
83178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     */
84178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi    public final static int PLAYSTATE_PLAYING            = 3;
85178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi    /**
86178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     * Playback state of a RemoteControlClient which is fast forwarding in the media
87178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     *    it is currently playing.
88178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     *
894426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     * @see #setPlaybackState(int)
90178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     */
91178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi    public final static int PLAYSTATE_FAST_FORWARDING    = 4;
92178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi    /**
93178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     * Playback state of a RemoteControlClient which is fast rewinding in the media
94178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     *    it is currently playing.
95178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     *
964426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     * @see #setPlaybackState(int)
97178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     */
98178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi    public final static int PLAYSTATE_REWINDING          = 5;
99178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi    /**
100178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     * Playback state of a RemoteControlClient which is skipping to the next
101178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     *    logical chapter (such as a song in a playlist) in the media it is currently playing.
102178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     *
1034426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     * @see #setPlaybackState(int)
104178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     */
105178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi    public final static int PLAYSTATE_SKIPPING_FORWARDS  = 6;
106178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi    /**
107178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     * Playback state of a RemoteControlClient which is skipping back to the previous
108178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     *    logical chapter (such as a song in a playlist) in the media it is currently playing.
109178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     *
1104426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     * @see #setPlaybackState(int)
111178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     */
112178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi    public final static int PLAYSTATE_SKIPPING_BACKWARDS = 7;
113178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi    /**
114178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     * Playback state of a RemoteControlClient which is buffering data to play before it can
115178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     *    start or resume playback.
116178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     *
1174426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     * @see #setPlaybackState(int)
118178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     */
119178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi    public final static int PLAYSTATE_BUFFERING          = 8;
120178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi    /**
121178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     * Playback state of a RemoteControlClient which cannot perform any playback related
122178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     *    operation because of an internal error. Examples of such situations are no network
123178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     *    connectivity when attempting to stream data from a server, or expired user credentials
124178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     *    when trying to play subscription-based content.
125178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     *
1264426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     * @see #setPlaybackState(int)
127178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     */
128178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi    public final static int PLAYSTATE_ERROR              = 9;
1294426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    /**
1304426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     * @hide
131466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi     * The value of a playback state when none has been declared.
132466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi     * Intentionally hidden as an application shouldn't set such a playback state value.
1334426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     */
1344426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    public final static int PLAYSTATE_NONE               = 0;
135178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi
136178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi    /**
1373114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     * @hide (to be un-hidden)
1383114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     * The default playback type, "local", indicating the presentation of the media is happening on
1393114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     * the same device (e.g. a phone, a tablet) as where it is controlled from.
1403114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     */
1413114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    public final static int PLAYBACK_TYPE_LOCAL = 0;
1423114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    /**
1433114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     * @hide (to be un-hidden)
1443114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     * A playback type indicating the presentation of the media is happening on
1453114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     * a different device (i.e. the remote device) than where it is controlled from.
1463114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     */
1473114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    public final static int PLAYBACK_TYPE_REMOTE = 1;
1483114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    private final static int PLAYBACK_TYPE_MIN = PLAYBACK_TYPE_LOCAL;
1493114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    private final static int PLAYBACK_TYPE_MAX = PLAYBACK_TYPE_REMOTE;
1503114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    /**
1513114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     * @hide (to be un-hidden)
1523114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     * Playback information indicating the playback volume is fixed, i.e. it cannot be controlled
1533114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     * from this object. An example of fixed playback volume is a remote player, playing over HDMI
1543114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     * where the user prefer to control the volume on the HDMI sink, rather than attenuate at the
1553114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     * source.
1563114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     * @see #PLAYBACKINFO_VOLUME_HANDLING.
1573114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     */
1583114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    public final static int PLAYBACK_VOLUME_FIXED = 0;
1593114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    /**
1603114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     * @hide (to be un-hidden)
1613114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     * Playback information indicating the playback volume is variable and can be controlled from
1623114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     * this object.
1633114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     * @see #PLAYBACKINFO_VOLUME_HANDLING.
1643114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     */
1653114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    public final static int PLAYBACK_VOLUME_VARIABLE = 1;
1663114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    /**
1673114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     * @hide (to be un-hidden)
1683114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     * The playback information value indicating the value of a given information type is invalid.
1693114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     * @see #PLAYBACKINFO_VOLUME_HANDLING.
1703114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     */
1713114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    public final static int PLAYBACKINFO_INVALID_VALUE = Integer.MIN_VALUE;
1723114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi
1733114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    //==========================================
1743114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    // Public keys for playback information
1753114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    /**
1763114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     * @hide (to be un-hidden)
1773114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     * Playback information that defines the type of playback associated with this
1783114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     * RemoteControlClient. See {@link #PLAYBACK_TYPE_LOCAL} and {@link #PLAYBACK_TYPE_REMOTE}.
1793114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     */
1803114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    public final static int PLAYBACKINFO_PLAYBACK_TYPE = 1;
1813114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    /**
1823114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     * @hide (to be un-hidden)
1833114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     * Playback information that defines at what volume the playback associated with this
1843114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     * RemoteControlClient is performed. This information is only used when the playback type is not
1853114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     * local (see {@link #PLAYBACKINFO_PLAYBACK_TYPE}).
1863114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     */
1873114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    public final static int PLAYBACKINFO_VOLUME = 2;
1883114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    /**
1893114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     * @hide (to be un-hidden)
1903114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     * Playback information that defines the maximum volume volume value that is supported
1913114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     * by the playback associated with this RemoteControlClient. This information is only used
1923114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     * when the playback type is not local (see {@link #PLAYBACKINFO_PLAYBACK_TYPE}).
1933114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     */
1943114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    public final static int PLAYBACKINFO_VOLUME_MAX = 3;
1953114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    /**
1963114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     * @hide (to be un-hidden)
1973114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     * Playback information that defines how volume is handled for the presentation of the media.
1983114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     * @see #PLAYBACK_VOLUME_FIXED
1993114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     * @see #PLAYBACK_VOLUME_VARIABLE
2003114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     */
2013114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    public final static int PLAYBACKINFO_VOLUME_HANDLING = 4;
2023114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    /**
2033114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     * @hide (to be un-hidden)
2043114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     * Playback information that defines over what stream type the media is presented.
2053114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     */
2063114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    public final static int PLAYBACKINFO_USES_STREAM = 5;
2073114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi
2083114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    //==========================================
2093114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    // Private keys for playback information
2103114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    /**
2113114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     * @hide
2123114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     * Used internally to relay playback state (set by the application with
2133114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     * {@link #setPlaybackState(int)}) to AudioService
2143114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     */
2153114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    public final static int PLAYBACKINFO_PLAYSTATE = 255;
2163114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi
2173114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi
2183114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    /**
219178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     * Flag indicating a RemoteControlClient makes use of the "previous" media key.
220178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     *
2214426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     * @see #setTransportControlFlags(int)
222178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     * @see android.view.KeyEvent#KEYCODE_MEDIA_PREVIOUS
223178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     */
224178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi    public final static int FLAG_KEY_MEDIA_PREVIOUS = 1 << 0;
225178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi    /**
226466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi     * Flag indicating a RemoteControlClient makes use of the "rewind" media key.
227178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     *
2284426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     * @see #setTransportControlFlags(int)
229178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     * @see android.view.KeyEvent#KEYCODE_MEDIA_REWIND
230178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     */
231178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi    public final static int FLAG_KEY_MEDIA_REWIND = 1 << 1;
232178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi    /**
233178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     * Flag indicating a RemoteControlClient makes use of the "play" media key.
234178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     *
2354426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     * @see #setTransportControlFlags(int)
236178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     * @see android.view.KeyEvent#KEYCODE_MEDIA_PLAY
237178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     */
238178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi    public final static int FLAG_KEY_MEDIA_PLAY = 1 << 2;
239178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi    /**
240178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     * Flag indicating a RemoteControlClient makes use of the "play/pause" media key.
241178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     *
2424426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     * @see #setTransportControlFlags(int)
243178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     * @see android.view.KeyEvent#KEYCODE_MEDIA_PLAY_PAUSE
244178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     */
245178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi    public final static int FLAG_KEY_MEDIA_PLAY_PAUSE = 1 << 3;
246178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi    /**
247178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     * Flag indicating a RemoteControlClient makes use of the "pause" media key.
248178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     *
2494426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     * @see #setTransportControlFlags(int)
250178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     * @see android.view.KeyEvent#KEYCODE_MEDIA_PAUSE
251178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     */
252178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi    public final static int FLAG_KEY_MEDIA_PAUSE = 1 << 4;
253178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi    /**
254178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     * Flag indicating a RemoteControlClient makes use of the "stop" media key.
255178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     *
2564426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     * @see #setTransportControlFlags(int)
257178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     * @see android.view.KeyEvent#KEYCODE_MEDIA_STOP
258178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     */
259178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi    public final static int FLAG_KEY_MEDIA_STOP = 1 << 5;
260178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi    /**
261178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     * Flag indicating a RemoteControlClient makes use of the "fast forward" media key.
262178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     *
2634426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     * @see #setTransportControlFlags(int)
264178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     * @see android.view.KeyEvent#KEYCODE_MEDIA_FAST_FORWARD
265178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     */
266178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi    public final static int FLAG_KEY_MEDIA_FAST_FORWARD = 1 << 6;
267178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi    /**
268178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     * Flag indicating a RemoteControlClient makes use of the "next" media key.
269178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     *
2704426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     * @see #setTransportControlFlags(int)
271178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     * @see android.view.KeyEvent#KEYCODE_MEDIA_NEXT
272178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     */
273178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi    public final static int FLAG_KEY_MEDIA_NEXT = 1 << 7;
274178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi
275178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi    /**
2764426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     * @hide
277466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi     * The flags for when no media keys are declared supported.
278466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi     * Intentionally hidden as an application shouldn't set the transport control flags
279466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi     *     to this value.
2804426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     */
2814426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    public final static int FLAGS_KEY_MEDIA_NONE = 0;
2824426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi
2834426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    /**
2844426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     * @hide
2854426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     * Flag used to signal some type of metadata exposed by the RemoteControlClient is requested.
286178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     */
2874426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    public final static int FLAG_INFORMATION_REQUEST_METADATA = 1 << 0;
288178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi    /**
2894426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     * @hide
290178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     * Flag used to signal that the transport control buttons supported by the
291466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi     *     RemoteControlClient are requested.
292178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     * This can for instance happen when playback is at the end of a playlist, and the "next"
293178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     * operation is not supported anymore.
294178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     */
2954426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    public final static int FLAG_INFORMATION_REQUEST_KEY_MEDIA = 1 << 1;
296178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi    /**
2974426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     * @hide
298466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi     * Flag used to signal that the playback state of the RemoteControlClient is requested.
299178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     */
3004426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    public final static int FLAG_INFORMATION_REQUEST_PLAYSTATE = 1 << 2;
301178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi    /**
3024426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     * @hide
303466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi     * Flag used to signal that the album art for the RemoteControlClient is requested.
304178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     */
3054426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    public final static int FLAG_INFORMATION_REQUEST_ALBUM_ART = 1 << 3;
3064426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi
3074426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    /**
3086e920e6dac11c3ebf6c0c19402934834e9e491bfJean-Michel Trivi     * Class constructor.
3096e920e6dac11c3ebf6c0c19402934834e9e491bfJean-Michel Trivi     * @param mediaButtonIntent The intent that will be sent for the media button events sent
3106e920e6dac11c3ebf6c0c19402934834e9e491bfJean-Michel Trivi     *     by remote controls.
3116e920e6dac11c3ebf6c0c19402934834e9e491bfJean-Michel Trivi     *     This intent needs to have been constructed with the {@link Intent#ACTION_MEDIA_BUTTON}
3126e920e6dac11c3ebf6c0c19402934834e9e491bfJean-Michel Trivi     *     action, and have a component that will handle the intent (set with
3136e920e6dac11c3ebf6c0c19402934834e9e491bfJean-Michel Trivi     *     {@link Intent#setComponent(ComponentName)}) registered with
3146e920e6dac11c3ebf6c0c19402934834e9e491bfJean-Michel Trivi     *     {@link AudioManager#registerMediaButtonEventReceiver(ComponentName)}
3156e920e6dac11c3ebf6c0c19402934834e9e491bfJean-Michel Trivi     *     before this new RemoteControlClient can itself be registered with
3166e920e6dac11c3ebf6c0c19402934834e9e491bfJean-Michel Trivi     *     {@link AudioManager#registerRemoteControlClient(RemoteControlClient)}.
3176e920e6dac11c3ebf6c0c19402934834e9e491bfJean-Michel Trivi     * @see AudioManager#registerMediaButtonEventReceiver(ComponentName)
3186e920e6dac11c3ebf6c0c19402934834e9e491bfJean-Michel Trivi     * @see AudioManager#registerRemoteControlClient(RemoteControlClient)
3196e920e6dac11c3ebf6c0c19402934834e9e491bfJean-Michel Trivi     */
3206e920e6dac11c3ebf6c0c19402934834e9e491bfJean-Michel Trivi    public RemoteControlClient(PendingIntent mediaButtonIntent) {
321f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi        mRcMediaIntent = mediaButtonIntent;
3226e920e6dac11c3ebf6c0c19402934834e9e491bfJean-Michel Trivi
3236e920e6dac11c3ebf6c0c19402934834e9e491bfJean-Michel Trivi        Looper looper;
3246e920e6dac11c3ebf6c0c19402934834e9e491bfJean-Michel Trivi        if ((looper = Looper.myLooper()) != null) {
3256e920e6dac11c3ebf6c0c19402934834e9e491bfJean-Michel Trivi            mEventHandler = new EventHandler(this, looper);
3266e920e6dac11c3ebf6c0c19402934834e9e491bfJean-Michel Trivi        } else if ((looper = Looper.getMainLooper()) != null) {
3276e920e6dac11c3ebf6c0c19402934834e9e491bfJean-Michel Trivi            mEventHandler = new EventHandler(this, looper);
3286e920e6dac11c3ebf6c0c19402934834e9e491bfJean-Michel Trivi        } else {
3296e920e6dac11c3ebf6c0c19402934834e9e491bfJean-Michel Trivi            mEventHandler = null;
3306e920e6dac11c3ebf6c0c19402934834e9e491bfJean-Michel Trivi            Log.e(TAG, "RemoteControlClient() couldn't find main application thread");
3316e920e6dac11c3ebf6c0c19402934834e9e491bfJean-Michel Trivi        }
3326e920e6dac11c3ebf6c0c19402934834e9e491bfJean-Michel Trivi    }
3336e920e6dac11c3ebf6c0c19402934834e9e491bfJean-Michel Trivi
3346e920e6dac11c3ebf6c0c19402934834e9e491bfJean-Michel Trivi    /**
3356e920e6dac11c3ebf6c0c19402934834e9e491bfJean-Michel Trivi     * Class constructor for a remote control client whose internal event handling
3366e920e6dac11c3ebf6c0c19402934834e9e491bfJean-Michel Trivi     * happens on a user-provided Looper.
3376e920e6dac11c3ebf6c0c19402934834e9e491bfJean-Michel Trivi     * @param mediaButtonIntent The intent that will be sent for the media button events sent
3386e920e6dac11c3ebf6c0c19402934834e9e491bfJean-Michel Trivi     *     by remote controls.
3396e920e6dac11c3ebf6c0c19402934834e9e491bfJean-Michel Trivi     *     This intent needs to have been constructed with the {@link Intent#ACTION_MEDIA_BUTTON}
3406e920e6dac11c3ebf6c0c19402934834e9e491bfJean-Michel Trivi     *     action, and have a component that will handle the intent (set with
3416e920e6dac11c3ebf6c0c19402934834e9e491bfJean-Michel Trivi     *     {@link Intent#setComponent(ComponentName)}) registered with
3426e920e6dac11c3ebf6c0c19402934834e9e491bfJean-Michel Trivi     *     {@link AudioManager#registerMediaButtonEventReceiver(ComponentName)}
3436e920e6dac11c3ebf6c0c19402934834e9e491bfJean-Michel Trivi     *     before this new RemoteControlClient can itself be registered with
3446e920e6dac11c3ebf6c0c19402934834e9e491bfJean-Michel Trivi     *     {@link AudioManager#registerRemoteControlClient(RemoteControlClient)}.
3456e920e6dac11c3ebf6c0c19402934834e9e491bfJean-Michel Trivi     * @param looper The Looper running the event loop.
3466e920e6dac11c3ebf6c0c19402934834e9e491bfJean-Michel Trivi     * @see AudioManager#registerMediaButtonEventReceiver(ComponentName)
3476e920e6dac11c3ebf6c0c19402934834e9e491bfJean-Michel Trivi     * @see AudioManager#registerRemoteControlClient(RemoteControlClient)
3486e920e6dac11c3ebf6c0c19402934834e9e491bfJean-Michel Trivi     */
3496e920e6dac11c3ebf6c0c19402934834e9e491bfJean-Michel Trivi    public RemoteControlClient(PendingIntent mediaButtonIntent, Looper looper) {
350f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi        mRcMediaIntent = mediaButtonIntent;
3516e920e6dac11c3ebf6c0c19402934834e9e491bfJean-Michel Trivi
3526e920e6dac11c3ebf6c0c19402934834e9e491bfJean-Michel Trivi        mEventHandler = new EventHandler(this, looper);
3536e920e6dac11c3ebf6c0c19402934834e9e491bfJean-Michel Trivi    }
3546e920e6dac11c3ebf6c0c19402934834e9e491bfJean-Michel Trivi
3555ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Trivi    private static final int[] METADATA_KEYS_TYPE_STRING = {
3565ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Trivi        MediaMetadataRetriever.METADATA_KEY_ALBUM,
3575ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Trivi        MediaMetadataRetriever.METADATA_KEY_ALBUMARTIST,
3585ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Trivi        MediaMetadataRetriever.METADATA_KEY_TITLE,
3595ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Trivi        MediaMetadataRetriever.METADATA_KEY_ARTIST,
3605ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Trivi        MediaMetadataRetriever.METADATA_KEY_AUTHOR,
3615ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Trivi        MediaMetadataRetriever.METADATA_KEY_COMPILATION,
3625ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Trivi        MediaMetadataRetriever.METADATA_KEY_COMPOSER,
3635ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Trivi        MediaMetadataRetriever.METADATA_KEY_DATE,
3645ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Trivi        MediaMetadataRetriever.METADATA_KEY_GENRE,
3655ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Trivi        MediaMetadataRetriever.METADATA_KEY_TITLE,
3665ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Trivi        MediaMetadataRetriever.METADATA_KEY_WRITER };
3675ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Trivi    private static final int[] METADATA_KEYS_TYPE_LONG = {
3685ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Trivi        MediaMetadataRetriever.METADATA_KEY_CD_TRACK_NUMBER,
3695ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Trivi        MediaMetadataRetriever.METADATA_KEY_DISC_NUMBER,
3705ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Trivi        MediaMetadataRetriever.METADATA_KEY_DURATION };
3715ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Trivi
3724426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    /**
3734426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     * Class used to modify metadata in a {@link RemoteControlClient} object.
374466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi     * Use {@link RemoteControlClient#editMetadata(boolean)} to create an instance of an editor,
375466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi     * on which you set the metadata for the RemoteControlClient instance. Once all the information
376466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi     * has been set, use {@link #apply()} to make it the new metadata that should be displayed
377466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi     * for the associated client. Once the metadata has been "applied", you cannot reuse this
378466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi     * instance of the MetadataEditor.
3794426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     */
3804426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    public class MetadataEditor {
381466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi        /**
382466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi         * @hide
383466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi         */
3844da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi        protected boolean mMetadataChanged;
385466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi        /**
386466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi         * @hide
387466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi         */
3884da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi        protected boolean mArtworkChanged;
389466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi        /**
390466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi         * @hide
391466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi         */
3924da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi        protected Bitmap mEditorArtwork;
393466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi        /**
394466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi         * @hide
395466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi         */
3964da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi        protected Bundle mEditorMetadata;
3974da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi        private boolean mApplied = false;
3984da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi
3994da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi        // only use RemoteControlClient.editMetadata() to get a MetadataEditor instance
4004da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi        private MetadataEditor() { }
4014da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi        /**
4024da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi         * @hide
4034da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi         */
4044da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi        public Object clone() throws CloneNotSupportedException {
4054da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi            throw new CloneNotSupportedException();
4064426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi        }
4074426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi
4084da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi        /**
4095ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Trivi         * The metadata key for the content artwork / album art.
4105ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Trivi         */
411466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi        public final static int BITMAP_KEY_ARTWORK = 100;
412466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi        /**
413466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi         * @hide
414466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi         * TODO(jmtrivi) have lockscreen and music move to the new key name
415466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi         */
416466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi        public final static int METADATA_KEY_ARTWORK = BITMAP_KEY_ARTWORK;
4175ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Trivi
4185ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Trivi        /**
4194da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi         * Adds textual information to be displayed.
4204da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi         * Note that none of the information added after {@link #apply()} has been called,
4214da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi         * will be displayed.
422466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi         * @param key The identifier of a the metadata field to set. Valid values are
4234da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi         *      {@link android.media.MediaMetadataRetriever#METADATA_KEY_ALBUM},
4244da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi         *      {@link android.media.MediaMetadataRetriever#METADATA_KEY_ALBUMARTIST},
4254da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi         *      {@link android.media.MediaMetadataRetriever#METADATA_KEY_TITLE},
4264da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi         *      {@link android.media.MediaMetadataRetriever#METADATA_KEY_ARTIST},
4274da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi         *      {@link android.media.MediaMetadataRetriever#METADATA_KEY_AUTHOR},
4284da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi         *      {@link android.media.MediaMetadataRetriever#METADATA_KEY_COMPILATION},
4294da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi         *      {@link android.media.MediaMetadataRetriever#METADATA_KEY_COMPOSER},
4304da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi         *      {@link android.media.MediaMetadataRetriever#METADATA_KEY_DATE},
4314da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi         *      {@link android.media.MediaMetadataRetriever#METADATA_KEY_GENRE},
4324da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi         *      {@link android.media.MediaMetadataRetriever#METADATA_KEY_TITLE},
433466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi         *      {@link android.media.MediaMetadataRetriever#METADATA_KEY_WRITER}.
434466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi         * @param value The text for the given key, or {@code null} to signify there is no valid
4354da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi         *      information for the field.
436466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi         * @return Returns a reference to the same MetadataEditor object, so you can chain put
437466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi         *      calls together.
4384da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi         */
4395ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Trivi        public synchronized MetadataEditor putString(int key, String value)
4405ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Trivi                throws IllegalArgumentException {
4414da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi            if (mApplied) {
4424da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi                Log.e(TAG, "Can't edit a previously applied MetadataEditor");
4434da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi                return this;
4444da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi            }
4455ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Trivi            if (!validTypeForKey(key, METADATA_KEYS_TYPE_STRING)) {
4465ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Trivi                throw(new IllegalArgumentException("Invalid type 'String' for key "+ key));
4475ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Trivi            }
4484da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi            mEditorMetadata.putString(String.valueOf(key), value);
4494da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi            mMetadataChanged = true;
4504426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi            return this;
4514426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi        }
4524426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi
4534da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi        /**
454466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi         * Adds numerical information to be displayed.
455466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi         * Note that none of the information added after {@link #apply()} has been called,
456466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi         * will be displayed.
4575ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Trivi         * @param key the identifier of a the metadata field to set. Valid values are
4585ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Trivi         *      {@link android.media.MediaMetadataRetriever#METADATA_KEY_CD_TRACK_NUMBER},
4595ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Trivi         *      {@link android.media.MediaMetadataRetriever#METADATA_KEY_DISC_NUMBER},
4605ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Trivi         *      {@link android.media.MediaMetadataRetriever#METADATA_KEY_DURATION} (with a value
4615ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Trivi         *      expressed in milliseconds),
4625ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Trivi         *      {@link android.media.MediaMetadataRetriever#METADATA_KEY_YEAR}.
463466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi         * @param value The long value for the given key
464466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi         * @return Returns a reference to the same MetadataEditor object, so you can chain put
465466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi         *      calls together.
4665ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Trivi         * @throws IllegalArgumentException
4674da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi         */
4685ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Trivi        public synchronized MetadataEditor putLong(int key, long value)
4695ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Trivi                throws IllegalArgumentException {
4705ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Trivi            if (mApplied) {
4715ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Trivi                Log.e(TAG, "Can't edit a previously applied MetadataEditor");
4725ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Trivi                return this;
4735ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Trivi            }
4745ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Trivi            if (!validTypeForKey(key, METADATA_KEYS_TYPE_LONG)) {
4755ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Trivi                throw(new IllegalArgumentException("Invalid type 'long' for key "+ key));
4765ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Trivi            }
4775ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Trivi            mEditorMetadata.putLong(String.valueOf(key), value);
4785ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Trivi            mMetadataChanged = true;
4795ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Trivi            return this;
4805ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Trivi        }
4814da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi
4824da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi        /**
4834da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi         * Sets the album / artwork picture to be displayed on the remote control.
484466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi         * @param key the identifier of the bitmap to set. The only valid value is
485466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi         *      {@link #BITMAP_KEY_ARTWORK}
486466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi         * @param bitmap The bitmap for the artwork, or null if there isn't any.
487466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi         * @return Returns a reference to the same MetadataEditor object, so you can chain put
488466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi         *      calls together.
4895ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Trivi         * @throws IllegalArgumentException
4904da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi         * @see android.graphics.Bitmap
4914da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi         */
4925ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Trivi        public synchronized MetadataEditor putBitmap(int key, Bitmap bitmap)
4935ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Trivi                throws IllegalArgumentException {
4944da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi            if (mApplied) {
4954da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi                Log.e(TAG, "Can't edit a previously applied MetadataEditor");
4964da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi                return this;
4974da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi            }
498466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi            if (key != BITMAP_KEY_ARTWORK) {
4995ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Trivi                throw(new IllegalArgumentException("Invalid type 'Bitmap' for key "+ key));
5004da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi            }
5014da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi            if ((mArtworkExpectedWidth > 0) && (mArtworkExpectedHeight > 0)) {
5024da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi                mEditorArtwork = scaleBitmapIfTooBig(bitmap,
5034da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi                        mArtworkExpectedWidth, mArtworkExpectedHeight);
5044da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi            } else {
5054da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi                // no valid resize dimensions, store as is
5064da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi                mEditorArtwork = bitmap;
5074da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi            }
5084da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi            mArtworkChanged = true;
5094da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi            return this;
5104426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi        }
511178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi
5124da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi        /**
513466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi         * Clears all the metadata that has been set since the MetadataEditor instance was
514466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi         *     created with {@link RemoteControlClient#editMetadata(boolean)}.
5154da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi         */
5164da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi        public synchronized void clear() {
5174da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi            if (mApplied) {
5184da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi                Log.e(TAG, "Can't clear a previously applied MetadataEditor");
5194da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi                return;
5204da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi            }
5214da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi            mEditorMetadata.clear();
5224da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi            mEditorArtwork = null;
5234426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi        }
524178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi
5254da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi        /**
526466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi         * Associates all the metadata that has been set since the MetadataEditor instance was
527466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi         *     created with {@link RemoteControlClient#editMetadata(boolean)}, or since
528466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi         *     {@link #clear()} was called, with the RemoteControlClient. Once "applied",
529466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi         *     this MetadataEditor cannot be reused to edit the RemoteControlClient's metadata.
5304da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi         */
5314da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi        public synchronized void apply() {
5324da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi            if (mApplied) {
5334da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi                Log.e(TAG, "Can't apply a previously applied MetadataEditor");
5344da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi                return;
5354da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi            }
5364da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi            synchronized(mCacheLock) {
5374da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi                // assign the edited data
5384da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi                mMetadata = new Bundle(mEditorMetadata);
53934d0d300cac645b48cce5a1735f45e1102d4ef0eJean-Michel Trivi                if ((mArtwork != null) && (!mArtwork.equals(mEditorArtwork))) {
54034d0d300cac645b48cce5a1735f45e1102d4ef0eJean-Michel Trivi                    mArtwork.recycle();
54134d0d300cac645b48cce5a1735f45e1102d4ef0eJean-Michel Trivi                }
5424da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi                mArtwork = mEditorArtwork;
54334d0d300cac645b48cce5a1735f45e1102d4ef0eJean-Michel Trivi                mEditorArtwork = null;
5444da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi                if (mMetadataChanged & mArtworkChanged) {
5454da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi                    // send to remote control display if conditions are met
54644413e5b514a91806a4bb4c7780029ea43be6f81Jean-Michel Trivi                    sendMetadataWithArtwork_syncCacheLock();
5474da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi                } else if (mMetadataChanged) {
5484da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi                    // send to remote control display if conditions are met
5494da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi                    sendMetadata_syncCacheLock();
5504da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi                } else if (mArtworkChanged) {
5514da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi                    // send to remote control display if conditions are met
5524da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi                    sendArtwork_syncCacheLock();
5534da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi                }
5544da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi                mApplied = true;
5554da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi            }
5564426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi        }
5574426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    }
5584426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi
5594426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    /**
560466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi     * Creates a {@link MetadataEditor}.
561466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi     * @param startEmpty Set to false if you want the MetadataEditor to contain the metadata that
562466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi     *     was previously applied to the RemoteControlClient, or true if it is to be created empty.
563466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi     * @return a new MetadataEditor instance.
5644426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     */
5654da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi    public MetadataEditor editMetadata(boolean startEmpty) {
5664da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi        MetadataEditor editor = new MetadataEditor();
5674da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi        if (startEmpty) {
5684da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi            editor.mEditorMetadata = new Bundle();
5694da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi            editor.mEditorArtwork = null;
5704da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi            editor.mMetadataChanged = true;
5714da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi            editor.mArtworkChanged = true;
5724da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi        } else {
5734da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi            editor.mEditorMetadata = new Bundle(mMetadata);
5744da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi            editor.mEditorArtwork = mArtwork;
5754da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi            editor.mMetadataChanged = false;
5764da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi            editor.mArtworkChanged = false;
5774426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi        }
5784da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi        return editor;
5794426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    }
5804426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi
5814426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    /**
5824426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     * Sets the current playback state.
583466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi     * @param state The current playback state, one of the following values:
584178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     *       {@link #PLAYSTATE_STOPPED},
585178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     *       {@link #PLAYSTATE_PAUSED},
586178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     *       {@link #PLAYSTATE_PLAYING},
587178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     *       {@link #PLAYSTATE_FAST_FORWARDING},
588178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     *       {@link #PLAYSTATE_REWINDING},
589178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     *       {@link #PLAYSTATE_SKIPPING_FORWARDS},
590178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     *       {@link #PLAYSTATE_SKIPPING_BACKWARDS},
591178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     *       {@link #PLAYSTATE_BUFFERING},
592178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     *       {@link #PLAYSTATE_ERROR}.
593178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     */
5944426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    public void setPlaybackState(int state) {
5954426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi        synchronized(mCacheLock) {
59668622396b62f9084781add1e12f4d513b633ab54Jean-Michel Trivi            if (mPlaybackState != state) {
59768622396b62f9084781add1e12f4d513b633ab54Jean-Michel Trivi                // store locally
59868622396b62f9084781add1e12f4d513b633ab54Jean-Michel Trivi                mPlaybackState = state;
59968622396b62f9084781add1e12f4d513b633ab54Jean-Michel Trivi                // keep track of when the state change occurred
60068622396b62f9084781add1e12f4d513b633ab54Jean-Michel Trivi                mPlaybackStateChangeTimeMs = SystemClock.elapsedRealtime();
60168622396b62f9084781add1e12f4d513b633ab54Jean-Michel Trivi
60268622396b62f9084781add1e12f4d513b633ab54Jean-Michel Trivi                // send to remote control display if conditions are met
60368622396b62f9084781add1e12f4d513b633ab54Jean-Michel Trivi                sendPlaybackState_syncCacheLock();
6043114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                // update AudioService
6053114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                sendAudioServiceNewPlaybackInfo_syncCacheLock(PLAYBACKINFO_PLAYSTATE, state);
60668622396b62f9084781add1e12f4d513b633ab54Jean-Michel Trivi            }
6074426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi        }
6084426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    }
609178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi
610178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi    /**
6114426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     * Sets the flags for the media transport control buttons that this client supports.
612466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi     * @param transportControlFlags A combination of the following flags:
6134426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     *      {@link #FLAG_KEY_MEDIA_PREVIOUS},
614178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     *      {@link #FLAG_KEY_MEDIA_REWIND},
615178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     *      {@link #FLAG_KEY_MEDIA_PLAY},
616178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     *      {@link #FLAG_KEY_MEDIA_PLAY_PAUSE},
617178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     *      {@link #FLAG_KEY_MEDIA_PAUSE},
618178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     *      {@link #FLAG_KEY_MEDIA_STOP},
619178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     *      {@link #FLAG_KEY_MEDIA_FAST_FORWARD},
620178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     *      {@link #FLAG_KEY_MEDIA_NEXT}
621178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     */
6224426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    public void setTransportControlFlags(int transportControlFlags) {
6234426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi        synchronized(mCacheLock) {
6244426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi            // store locally
6254426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi            mTransportControlFlags = transportControlFlags;
6264426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi
6274426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi            // send to remote control display if conditions are met
6284426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi            sendTransportControlFlags_syncCacheLock();
6294426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi        }
6304426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    }
631178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi
6323114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    /** @hide */
6333114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    public final static int DEFAULT_PLAYBACK_VOLUME_HANDLING = PLAYBACK_VOLUME_VARIABLE;
6343114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    /** @hide */
6353114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    // hard-coded to the same number of steps as AudioService.MAX_STREAM_VOLUME[STREAM_MUSIC]
6363114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    public final static int DEFAULT_PLAYBACK_VOLUME = 15;
6373114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi
6383114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    private int mPlaybackType = PLAYBACK_TYPE_LOCAL;
6393114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    private int mPlaybackVolumeMax = DEFAULT_PLAYBACK_VOLUME;
6403114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    private int mPlaybackVolume = DEFAULT_PLAYBACK_VOLUME;
6413114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    private int mPlaybackVolumeHandling = DEFAULT_PLAYBACK_VOLUME_HANDLING;
6423114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    private int mPlaybackStream = AudioManager.STREAM_MUSIC;
6433114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi
6443114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    /**
6453114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     * @hide  (to be un-hidden)
6463114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     * Set information describing information related to the playback of media so the system
6473114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     * can implement additional behavior to handle non-local playback usecases.
6483114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     * @param what a key to specify the type of information to set. Valid keys are
6493114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     *        {@link #PLAYBACKINFO_PLAYBACK_TYPE},
6503114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     *        {@link #PLAYBACKINFO_USES_STREAM},
6513114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     *        {@link #PLAYBACKINFO_VOLUME},
6523114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     *        {@link #PLAYBACKINFO_VOLUME_MAX},
6533114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     *        and {@link #PLAYBACKINFO_VOLUME_HANDLING}.
6543114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     * @param value the value for the supplied information to set.
6553114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     */
6563114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    public void setPlaybackInformation(int what, int value) {
6573114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        synchronized(mCacheLock) {
6583114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi            switch (what) {
6593114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                case PLAYBACKINFO_PLAYBACK_TYPE:
6603114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                    if ((value >= PLAYBACK_TYPE_MIN) && (value <= PLAYBACK_TYPE_MAX)) {
6613114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                        if (mPlaybackType != value) {
6623114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                            mPlaybackType = value;
6633114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                            sendAudioServiceNewPlaybackInfo_syncCacheLock(what, value);
6643114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                        }
6653114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                    } else {
6663114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                        Log.w(TAG, "using invalid value for PLAYBACKINFO_PLAYBACK_TYPE");
6673114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                    }
6683114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                    break;
6693114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                case PLAYBACKINFO_VOLUME:
6703114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                    if ((value > -1) && (value <= mPlaybackVolumeMax)) {
6713114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                        if (mPlaybackVolume != value) {
6723114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                            mPlaybackVolume = value;
6733114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                            sendAudioServiceNewPlaybackInfo_syncCacheLock(what, value);
6743114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                        }
6753114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                    } else {
6763114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                        Log.w(TAG, "using invalid value for PLAYBACKINFO_VOLUME");
6773114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                    }
6783114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                    break;
6793114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                case PLAYBACKINFO_VOLUME_MAX:
6803114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                    if (value > 0) {
6813114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                        if (mPlaybackVolumeMax != value) {
6823114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                            mPlaybackVolumeMax = value;
6833114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                            sendAudioServiceNewPlaybackInfo_syncCacheLock(what, value);
6843114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                        }
6853114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                    } else {
6863114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                        Log.w(TAG, "using invalid value for PLAYBACKINFO_VOLUME_MAX");
6873114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                    }
6883114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                    break;
6893114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                case PLAYBACKINFO_USES_STREAM:
6903114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                    if ((value >= 0) && (value < AudioSystem.getNumStreamTypes())) {
6913114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                        mPlaybackStream = value;
6923114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                    } else {
6933114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                        Log.w(TAG, "using invalid value for PLAYBACKINFO_USES_STREAM");
6943114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                    }
6953114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                    break;
6963114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                case PLAYBACKINFO_VOLUME_HANDLING:
6973114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                    if ((value >= PLAYBACK_VOLUME_FIXED) && (value <= PLAYBACK_VOLUME_VARIABLE)) {
6983114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                        if (mPlaybackVolumeHandling != value) {
6993114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                            mPlaybackVolumeHandling = value;
7003114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                            sendAudioServiceNewPlaybackInfo_syncCacheLock(what, value);
7013114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                        }
7023114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                    } else {
7033114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                        Log.w(TAG, "using invalid value for PLAYBACKINFO_VOLUME_HANDLING");
7043114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                    }
7053114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                    break;
7063114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                default:
7073114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                    // not throwing an exception or returning an error if more keys are to be
7083114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                    // supported in the future
7093114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                    Log.w(TAG, "setPlaybackInformation() ignoring unknown key " + what);
7103114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                    break;
7113114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi            }
7123114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        }
7133114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    }
7143114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi
7153114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    /**
7163114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     * @hide  (to be un-hidden)
7173114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     * Return playback information represented as an integer value.
7183114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     * @param what a key to specify the type of information to retrieve. Valid keys are
7193114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     *        {@link #PLAYBACKINFO_PLAYBACK_TYPE},
7203114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     *        {@link #PLAYBACKINFO_USES_STREAM},
7213114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     *        {@link #PLAYBACKINFO_VOLUME},
7223114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     *        {@link #PLAYBACKINFO_VOLUME_MAX},
7233114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     *        and {@link #PLAYBACKINFO_VOLUME_HANDLING}.
7243114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     * @return the current value for the given information type, or
7253114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     *   {@link #PLAYBACKINFO_INVALID_VALUE} if an error occurred or the request is invalid, or
7263114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     *   the value is unknown.
7273114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     */
7283114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    public int getIntPlaybackInformation(int what) {
7293114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        synchronized(mCacheLock) {
7303114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi            switch (what) {
7313114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                case PLAYBACKINFO_PLAYBACK_TYPE:
7323114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                    return mPlaybackType;
7333114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                case PLAYBACKINFO_VOLUME:
7343114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                    return mPlaybackVolume;
7353114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                case PLAYBACKINFO_VOLUME_MAX:
7363114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                    return mPlaybackVolumeMax;
7373114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                case PLAYBACKINFO_USES_STREAM:
7383114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                    return mPlaybackStream;
7393114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                case PLAYBACKINFO_VOLUME_HANDLING:
7403114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                    return mPlaybackVolumeHandling;
7413114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                default:
7423114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                    Log.e(TAG, "getIntPlaybackInformation() unknown key " + what);
7433114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                    return PLAYBACKINFO_INVALID_VALUE;
7443114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi            }
7453114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        }
7463114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    }
7473114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi
748178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi    /**
7494426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     * Lock for all cached data
7504426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     */
7514426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    private final Object mCacheLock = new Object();
7524426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    /**
7534426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     * Cache for the playback state.
7544426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     * Access synchronized on mCacheLock
755178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     */
7564426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    private int mPlaybackState = PLAYSTATE_NONE;
7574426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    /**
75868622396b62f9084781add1e12f4d513b633ab54Jean-Michel Trivi     * Time of last play state change
75968622396b62f9084781add1e12f4d513b633ab54Jean-Michel Trivi     * Access synchronized on mCacheLock
76068622396b62f9084781add1e12f4d513b633ab54Jean-Michel Trivi     */
76168622396b62f9084781add1e12f4d513b633ab54Jean-Michel Trivi    private long mPlaybackStateChangeTimeMs = 0;
76268622396b62f9084781add1e12f4d513b633ab54Jean-Michel Trivi    /**
7634426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     * Cache for the artwork bitmap.
7644426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     * Access synchronized on mCacheLock
7654da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi     * Artwork and metadata are not kept in one Bundle because the bitmap sometimes needs to be
7664da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi     * accessed to be resized, in which case a copy will be made. This would add overhead in
7674da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi     * Bundle operations.
7684426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     */
7694426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    private Bitmap mArtwork;
7704426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    private final int ARTWORK_DEFAULT_SIZE = 256;
77144413e5b514a91806a4bb4c7780029ea43be6f81Jean-Michel Trivi    private final int ARTWORK_INVALID_SIZE = -1;
7724426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    private int mArtworkExpectedWidth = ARTWORK_DEFAULT_SIZE;
7734426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    private int mArtworkExpectedHeight = ARTWORK_DEFAULT_SIZE;
7744426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    /**
7754426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     * Cache for the transport control mask.
7764426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     * Access synchronized on mCacheLock
7774426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     */
7784426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    private int mTransportControlFlags = FLAGS_KEY_MEDIA_NONE;
7794426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    /**
7804426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     * Cache for the metadata strings.
7814426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     * Access synchronized on mCacheLock
78230c918ce7fbe171944b28fc91b3f22b3d631872dGlenn Kasten     * This is re-initialized in apply() and so cannot be final.
7834426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     */
7844426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    private Bundle mMetadata = new Bundle();
7854da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi
7864426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    /**
7874426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     * The current remote control client generation ID across the system
7884426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     */
7894426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    private int mCurrentClientGenId = -1;
7904426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    /**
7914426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     * The remote control client generation ID, the last time it was told it was the current RC.
7924426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     * If (mCurrentClientGenId == mInternalClientGenId) is true, it means that this remote control
7934426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     * client is the "focused" one, and that whenever this client's info is updated, it needs to
7944426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     * send it to the known IRemoteControlDisplay interfaces.
7954426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     */
7964426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    private int mInternalClientGenId = -2;
7974426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi
7984426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    /**
799f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi     * The media button intent description associated with this remote control client
800f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi     * (can / should include target component for intent handling)
8014426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     */
802f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi    private final PendingIntent mRcMediaIntent;
8034426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi
8044426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    /**
8054426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     * The remote control display to which this client will send information.
8064426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     * NOTE: Only one IRemoteControlDisplay supported in this implementation
8074426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     */
8084426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    private IRemoteControlDisplay mRcDisplay;
8094426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi
8104426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    /**
8114426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     * @hide
812f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi     * Accessor to media button intent description (includes target component)
8134426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     */
814f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi    public PendingIntent getRcMediaIntent() {
815f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi        return mRcMediaIntent;
8164426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    }
8174426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    /**
8184426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     * @hide
8194426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     * Accessor to IRemoteControlClient
8204426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     */
8214426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    public IRemoteControlClient getIRemoteControlClient() {
8224426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi        return mIRCC;
8234426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    }
8244426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi
8254426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    /**
8264426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     * The IRemoteControlClient implementation
8274426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     */
82830c918ce7fbe171944b28fc91b3f22b3d631872dGlenn Kasten    private final IRemoteControlClient mIRCC = new IRemoteControlClient.Stub() {
8294426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi
8304426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi        public void onInformationRequested(int clientGeneration, int infoFlags,
8314426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi                int artWidth, int artHeight) {
8324426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi            // only post messages, we can't block here
8334426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi            if (mEventHandler != null) {
8344426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi                // signal new client
8354426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi                mEventHandler.removeMessages(MSG_NEW_INTERNAL_CLIENT_GEN);
8364426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi                mEventHandler.dispatchMessage(
8374426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi                        mEventHandler.obtainMessage(
8384426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi                                MSG_NEW_INTERNAL_CLIENT_GEN,
8394426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi                                artWidth, artHeight,
8404426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi                                new Integer(clientGeneration)));
8414426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi                // send the information
8424426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi                mEventHandler.removeMessages(MSG_REQUEST_PLAYBACK_STATE);
8434426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi                mEventHandler.removeMessages(MSG_REQUEST_METADATA);
8444426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi                mEventHandler.removeMessages(MSG_REQUEST_TRANSPORTCONTROL);
8454426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi                mEventHandler.removeMessages(MSG_REQUEST_ARTWORK);
8464426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi                mEventHandler.dispatchMessage(
8474426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi                        mEventHandler.obtainMessage(MSG_REQUEST_PLAYBACK_STATE));
8484426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi                mEventHandler.dispatchMessage(
8494426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi                        mEventHandler.obtainMessage(MSG_REQUEST_TRANSPORTCONTROL));
8504426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi                mEventHandler.dispatchMessage(mEventHandler.obtainMessage(MSG_REQUEST_METADATA));
8514426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi                mEventHandler.dispatchMessage(mEventHandler.obtainMessage(MSG_REQUEST_ARTWORK));
8524426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi            }
8534426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi        }
8544426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi
8554426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi        public void setCurrentClientGenerationId(int clientGeneration) {
8564426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi            // only post messages, we can't block here
8574426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi            if (mEventHandler != null) {
8584426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi                mEventHandler.removeMessages(MSG_NEW_CURRENT_CLIENT_GEN);
8594426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi                mEventHandler.dispatchMessage(mEventHandler.obtainMessage(
8604426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi                        MSG_NEW_CURRENT_CLIENT_GEN, clientGeneration, 0/*ignored*/));
8614426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi            }
8624426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi        }
8634426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi
8644426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi        public void plugRemoteControlDisplay(IRemoteControlDisplay rcd) {
8654426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi            // only post messages, we can't block here
8664426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi            if (mEventHandler != null) {
8674426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi                mEventHandler.dispatchMessage(mEventHandler.obtainMessage(
8684426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi                        MSG_PLUG_DISPLAY, rcd));
8694426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi            }
8704426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi        }
8714426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi
8724426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi        public void unplugRemoteControlDisplay(IRemoteControlDisplay rcd) {
8734426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi            // only post messages, we can't block here
8744426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi            if (mEventHandler != null) {
8754426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi                mEventHandler.dispatchMessage(mEventHandler.obtainMessage(
8764426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi                        MSG_UNPLUG_DISPLAY, rcd));
8774426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi            }
8784426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi        }
8794426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    };
8804426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi
8813114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    /**
8823114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     * @hide
8833114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     * Default value for the unique identifier
8843114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     */
8853114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    public final static int RCSE_ID_UNREGISTERED = -1;
8863114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    /**
8873114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     * Unique identifier of the RemoteControlStackEntry in AudioService with which
8883114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     * this RemoteControlClient is associated.
8893114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     */
8903114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    private int mRcseId = RCSE_ID_UNREGISTERED;
8913114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    /**
8923114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     * @hide
8933114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     * To be only used by AudioManager after it has received the unique id from
8943114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     * IAudioService.registerRemoteControlClient()
8953114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     * @param id the unique identifier of the RemoteControlStackEntry in AudioService with which
8963114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     *              this RemoteControlClient is associated.
8973114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     */
8983114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    public void setRcseId(int id) {
8993114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        mRcseId = id;
9003114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    }
9013114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi
9024426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    private EventHandler mEventHandler;
9034426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    private final static int MSG_REQUEST_PLAYBACK_STATE = 1;
9044426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    private final static int MSG_REQUEST_METADATA = 2;
9054426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    private final static int MSG_REQUEST_TRANSPORTCONTROL = 3;
9064426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    private final static int MSG_REQUEST_ARTWORK = 4;
9074426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    private final static int MSG_NEW_INTERNAL_CLIENT_GEN = 5;
9084426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    private final static int MSG_NEW_CURRENT_CLIENT_GEN = 6;
9094426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    private final static int MSG_PLUG_DISPLAY = 7;
9104426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    private final static int MSG_UNPLUG_DISPLAY = 8;
9114426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi
9124426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    private class EventHandler extends Handler {
9134426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi        public EventHandler(RemoteControlClient rcc, Looper looper) {
9144426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi            super(looper);
9154426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi        }
9164426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi
9174426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi        @Override
9184426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi        public void handleMessage(Message msg) {
9194426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi            switch(msg.what) {
9204426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi                case MSG_REQUEST_PLAYBACK_STATE:
9214426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi                    synchronized (mCacheLock) {
9224426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi                        sendPlaybackState_syncCacheLock();
9234426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi                    }
9244426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi                    break;
9254426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi                case MSG_REQUEST_METADATA:
9264426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi                    synchronized (mCacheLock) {
9274426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi                        sendMetadata_syncCacheLock();
9284426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi                    }
9294426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi                    break;
9304426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi                case MSG_REQUEST_TRANSPORTCONTROL:
9314426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi                    synchronized (mCacheLock) {
9324426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi                        sendTransportControlFlags_syncCacheLock();
9334426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi                    }
9344426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi                    break;
9354426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi                case MSG_REQUEST_ARTWORK:
9364426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi                    synchronized (mCacheLock) {
9374426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi                        sendArtwork_syncCacheLock();
9384426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi                    }
9394426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi                    break;
9404426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi                case MSG_NEW_INTERNAL_CLIENT_GEN:
9414426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi                    onNewInternalClientGen((Integer)msg.obj, msg.arg1, msg.arg2);
9424426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi                    break;
9434426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi                case MSG_NEW_CURRENT_CLIENT_GEN:
9444426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi                    onNewCurrentClientGen(msg.arg1);
9454426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi                    break;
9464426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi                case MSG_PLUG_DISPLAY:
9474426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi                    onPlugDisplay((IRemoteControlDisplay)msg.obj);
9484426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi                    break;
9494426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi                case MSG_UNPLUG_DISPLAY:
9504426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi                    onUnplugDisplay((IRemoteControlDisplay)msg.obj);
9514426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi                    break;
9524426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi                default:
9534426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi                    Log.e(TAG, "Unknown event " + msg.what + " in RemoteControlClient handler");
9544426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi            }
9554426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi        }
9564426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    }
9574426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi
9583114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    //===========================================================
9593114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    // Communication with IRemoteControlDisplay
9603114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi
96144413e5b514a91806a4bb4c7780029ea43be6f81Jean-Michel Trivi    private void detachFromDisplay_syncCacheLock() {
96244413e5b514a91806a4bb4c7780029ea43be6f81Jean-Michel Trivi        mRcDisplay = null;
96344413e5b514a91806a4bb4c7780029ea43be6f81Jean-Michel Trivi        mArtworkExpectedWidth = ARTWORK_INVALID_SIZE;
96444413e5b514a91806a4bb4c7780029ea43be6f81Jean-Michel Trivi        mArtworkExpectedHeight = ARTWORK_INVALID_SIZE;
96544413e5b514a91806a4bb4c7780029ea43be6f81Jean-Michel Trivi    }
96644413e5b514a91806a4bb4c7780029ea43be6f81Jean-Michel Trivi
9674426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    private void sendPlaybackState_syncCacheLock() {
9684426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi        if ((mCurrentClientGenId == mInternalClientGenId) && (mRcDisplay != null)) {
9694426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi            try {
97068622396b62f9084781add1e12f4d513b633ab54Jean-Michel Trivi                mRcDisplay.setPlaybackState(mInternalClientGenId, mPlaybackState,
97168622396b62f9084781add1e12f4d513b633ab54Jean-Michel Trivi                        mPlaybackStateChangeTimeMs);
9724426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi            } catch (RemoteException e) {
9734426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi                Log.e(TAG, "Error in setPlaybackState(), dead display "+e);
97444413e5b514a91806a4bb4c7780029ea43be6f81Jean-Michel Trivi                detachFromDisplay_syncCacheLock();
9754426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi            }
9764426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi        }
9774426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    }
9784426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi
9794426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    private void sendMetadata_syncCacheLock() {
9804426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi        if ((mCurrentClientGenId == mInternalClientGenId) && (mRcDisplay != null)) {
9814426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi            try {
9824426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi                mRcDisplay.setMetadata(mInternalClientGenId, mMetadata);
9834426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi            } catch (RemoteException e) {
9844426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi                Log.e(TAG, "Error in sendPlaybackState(), dead display "+e);
98544413e5b514a91806a4bb4c7780029ea43be6f81Jean-Michel Trivi                detachFromDisplay_syncCacheLock();
9864426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi            }
9874426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi        }
9884426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    }
9894426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi
9904426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    private void sendTransportControlFlags_syncCacheLock() {
9914426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi        if ((mCurrentClientGenId == mInternalClientGenId) && (mRcDisplay != null)) {
9924426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi            try {
9934426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi                mRcDisplay.setTransportControlFlags(mInternalClientGenId,
9944426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi                        mTransportControlFlags);
9954426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi            } catch (RemoteException e) {
9964426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi                Log.e(TAG, "Error in sendTransportControlFlags(), dead display "+e);
99744413e5b514a91806a4bb4c7780029ea43be6f81Jean-Michel Trivi                detachFromDisplay_syncCacheLock();
9984426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi            }
9994426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi        }
10004426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    }
10014426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi
10024426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    private void sendArtwork_syncCacheLock() {
10034426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi        if ((mCurrentClientGenId == mInternalClientGenId) && (mRcDisplay != null)) {
10044426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi            // even though we have already scaled in setArtwork(), when this client needs to
10054426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi            // send the bitmap, there might be newer and smaller expected dimensions, so we have
10064426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi            // to check again.
10074426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi            mArtwork = scaleBitmapIfTooBig(mArtwork, mArtworkExpectedWidth, mArtworkExpectedHeight);
10084426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi            try {
10094426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi                mRcDisplay.setArtwork(mInternalClientGenId, mArtwork);
10104426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi            } catch (RemoteException e) {
10114426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi                Log.e(TAG, "Error in sendArtwork(), dead display "+e);
101244413e5b514a91806a4bb4c7780029ea43be6f81Jean-Michel Trivi                detachFromDisplay_syncCacheLock();
101344413e5b514a91806a4bb4c7780029ea43be6f81Jean-Michel Trivi            }
101444413e5b514a91806a4bb4c7780029ea43be6f81Jean-Michel Trivi        }
101544413e5b514a91806a4bb4c7780029ea43be6f81Jean-Michel Trivi    }
101644413e5b514a91806a4bb4c7780029ea43be6f81Jean-Michel Trivi
101744413e5b514a91806a4bb4c7780029ea43be6f81Jean-Michel Trivi    private void sendMetadataWithArtwork_syncCacheLock() {
101844413e5b514a91806a4bb4c7780029ea43be6f81Jean-Michel Trivi        if ((mCurrentClientGenId == mInternalClientGenId) && (mRcDisplay != null)) {
101944413e5b514a91806a4bb4c7780029ea43be6f81Jean-Michel Trivi            // even though we have already scaled in setArtwork(), when this client needs to
102044413e5b514a91806a4bb4c7780029ea43be6f81Jean-Michel Trivi            // send the bitmap, there might be newer and smaller expected dimensions, so we have
102144413e5b514a91806a4bb4c7780029ea43be6f81Jean-Michel Trivi            // to check again.
102244413e5b514a91806a4bb4c7780029ea43be6f81Jean-Michel Trivi            mArtwork = scaleBitmapIfTooBig(mArtwork, mArtworkExpectedWidth, mArtworkExpectedHeight);
102344413e5b514a91806a4bb4c7780029ea43be6f81Jean-Michel Trivi            try {
102444413e5b514a91806a4bb4c7780029ea43be6f81Jean-Michel Trivi                mRcDisplay.setAllMetadata(mInternalClientGenId, mMetadata, mArtwork);
102544413e5b514a91806a4bb4c7780029ea43be6f81Jean-Michel Trivi            } catch (RemoteException e) {
102644413e5b514a91806a4bb4c7780029ea43be6f81Jean-Michel Trivi                Log.e(TAG, "Error in setAllMetadata(), dead display "+e);
102744413e5b514a91806a4bb4c7780029ea43be6f81Jean-Michel Trivi                detachFromDisplay_syncCacheLock();
10284426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi            }
10294426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi        }
10304426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    }
10314426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi
10323114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    //===========================================================
10333114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    // Communication with AudioService
10343114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi
10353114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    private static IAudioService sService;
10363114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi
10373114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    private static IAudioService getService()
10383114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    {
10393114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        if (sService != null) {
10403114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi            return sService;
10413114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        }
10423114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        IBinder b = ServiceManager.getService(Context.AUDIO_SERVICE);
10433114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        sService = IAudioService.Stub.asInterface(b);
10443114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        return sService;
10453114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    }
10463114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi
10473114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    private void sendAudioServiceNewPlaybackInfo_syncCacheLock(int what, int value) {
10483114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        if (mRcseId == RCSE_ID_UNREGISTERED) {
10493114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi            return;
10503114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        }
10513114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        Log.d(TAG, "sending to AudioService key=" + what + ", value=" + value);
10523114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        IAudioService service = getService();
10533114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        try {
10543114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi            service.setPlaybackInfoForRcc(mRcseId, what, value);
10553114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        } catch (RemoteException e) {
10563114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi            Log.e(TAG, "Dead object in sendAudioServiceNewPlaybackInfo_syncCacheLock", e);
10573114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        }
10583114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    }
10593114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi
10603114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    //===========================================================
10613114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    // Message handlers
10623114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi
10634426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    private void onNewInternalClientGen(Integer clientGeneration, int artWidth, int artHeight) {
10644426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi        synchronized (mCacheLock) {
10654426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi            // this remote control client is told it is the "focused" one:
10664426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi            // it implies that now (mCurrentClientGenId == mInternalClientGenId) is true
10674426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi            mInternalClientGenId = clientGeneration.intValue();
10684426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi            if (artWidth > 0) {
10694426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi                mArtworkExpectedWidth = artWidth;
10704426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi                mArtworkExpectedHeight = artHeight;
10714426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi            }
10724426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi        }
10734426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    }
10744426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi
10754426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    private void onNewCurrentClientGen(int clientGeneration) {
10764426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi        synchronized (mCacheLock) {
10774426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi            mCurrentClientGenId = clientGeneration;
10784426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi        }
10794426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    }
10804426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi
10814426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    private void onPlugDisplay(IRemoteControlDisplay rcd) {
10824426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi        synchronized(mCacheLock) {
10834426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi            mRcDisplay = rcd;
10844426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi        }
10854426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    }
10864426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi
10874426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    private void onUnplugDisplay(IRemoteControlDisplay rcd) {
10884426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi        synchronized(mCacheLock) {
10897309c83b95b36eac141680158df70ac1ce02a160Jean-Michel Trivi            if ((mRcDisplay != null) && (mRcDisplay.asBinder().equals(rcd.asBinder()))) {
10904426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi                mRcDisplay = null;
10914426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi                mArtworkExpectedWidth = ARTWORK_DEFAULT_SIZE;
10924426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi                mArtworkExpectedHeight = ARTWORK_DEFAULT_SIZE;
10934426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi            }
10944426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi        }
10954426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    }
10964426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi
10973114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    //===========================================================
10983114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    // Internal utilities
10993114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi
11004426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    /**
11014426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     * Scale a bitmap to fit the smallest dimension by uniformly scaling the incoming bitmap.
11024426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     * If the bitmap fits, then do nothing and return the original.
11034426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     *
11044426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     * @param bitmap
11054426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     * @param maxWidth
11064426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     * @param maxHeight
11074426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     * @return
11084426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     */
11094426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi
11104426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    private Bitmap scaleBitmapIfTooBig(Bitmap bitmap, int maxWidth, int maxHeight) {
11116e679d5a53091b348a2cdc0c76f4e8fa4ac52d4bJean-Michel Trivi        if (bitmap != null) {
11126e679d5a53091b348a2cdc0c76f4e8fa4ac52d4bJean-Michel Trivi            final int width = bitmap.getWidth();
11136e679d5a53091b348a2cdc0c76f4e8fa4ac52d4bJean-Michel Trivi            final int height = bitmap.getHeight();
11146e679d5a53091b348a2cdc0c76f4e8fa4ac52d4bJean-Michel Trivi            if (width > maxWidth || height > maxHeight) {
11156e679d5a53091b348a2cdc0c76f4e8fa4ac52d4bJean-Michel Trivi                float scale = Math.min((float) maxWidth / width, (float) maxHeight / height);
11166e679d5a53091b348a2cdc0c76f4e8fa4ac52d4bJean-Michel Trivi                int newWidth = Math.round(scale * width);
11176e679d5a53091b348a2cdc0c76f4e8fa4ac52d4bJean-Michel Trivi                int newHeight = Math.round(scale * height);
111805c66cc5cc6357be19fdef0fc131731368c38646Jack Palevich                Bitmap.Config newConfig = bitmap.getConfig();
111905c66cc5cc6357be19fdef0fc131731368c38646Jack Palevich                if (newConfig == null) {
112005c66cc5cc6357be19fdef0fc131731368c38646Jack Palevich                    newConfig = Bitmap.Config.ARGB_8888;
112105c66cc5cc6357be19fdef0fc131731368c38646Jack Palevich                }
112205c66cc5cc6357be19fdef0fc131731368c38646Jack Palevich                Bitmap outBitmap = Bitmap.createBitmap(newWidth, newHeight, newConfig);
11236e679d5a53091b348a2cdc0c76f4e8fa4ac52d4bJean-Michel Trivi                Canvas canvas = new Canvas(outBitmap);
11246e679d5a53091b348a2cdc0c76f4e8fa4ac52d4bJean-Michel Trivi                Paint paint = new Paint();
11256e679d5a53091b348a2cdc0c76f4e8fa4ac52d4bJean-Michel Trivi                paint.setAntiAlias(true);
11266e679d5a53091b348a2cdc0c76f4e8fa4ac52d4bJean-Michel Trivi                paint.setFilterBitmap(true);
11276e679d5a53091b348a2cdc0c76f4e8fa4ac52d4bJean-Michel Trivi                canvas.drawBitmap(bitmap, null,
11286e679d5a53091b348a2cdc0c76f4e8fa4ac52d4bJean-Michel Trivi                        new RectF(0, 0, outBitmap.getWidth(), outBitmap.getHeight()), paint);
11296e679d5a53091b348a2cdc0c76f4e8fa4ac52d4bJean-Michel Trivi                bitmap = outBitmap;
11306e679d5a53091b348a2cdc0c76f4e8fa4ac52d4bJean-Michel Trivi            }
11314426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi        }
11324426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi        return bitmap;
11335ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Trivi    }
11344426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi
11355ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Trivi    /**
11365ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Trivi     *  Fast routine to go through an array of allowed keys and return whether the key is part
11375ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Trivi     *  of that array
11385ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Trivi     * @param key the key value
11395ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Trivi     * @param validKeys the array of valid keys for a given type
11405ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Trivi     * @return true if the key is part of the array, false otherwise
11415ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Trivi     */
11425ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Trivi    private static boolean validTypeForKey(int key, int[] validKeys) {
11435ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Trivi        try {
11445ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Trivi            for (int i = 0 ; ; i++) {
11455ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Trivi                if (key == validKeys[i]) {
11465ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Trivi                    return true;
11475ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Trivi                }
11485ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Trivi            }
11495ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Trivi        } catch (ArrayIndexOutOfBoundsException e) {
11505ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Trivi            return false;
11515ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Trivi        }
11524426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    }
1153178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi}
1154