RemoteControlClient.java revision c3c4babf8424f65b3d3d2700f60fae6e94e9cd00
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;
394a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Triviimport java.util.ArrayList;
404a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Triviimport java.util.Iterator;
41178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi
42178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi/**
434426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi * RemoteControlClient enables exposing information meant to be consumed by remote controls
44466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi * capable of displaying metadata, artwork and media transport control buttons.
45ad87f5b40f2a3fd2d506dc15e00b8af28a8fa2baJean-Michel Trivi *
46ad87f5b40f2a3fd2d506dc15e00b8af28a8fa2baJean-Michel Trivi * <p>A remote control client object is associated with a media button event receiver. This
47466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi * event receiver must have been previously registered with
48466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi * {@link AudioManager#registerMediaButtonEventReceiver(ComponentName)} before the
49466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi * RemoteControlClient can be registered through
504426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi * {@link AudioManager#registerRemoteControlClient(RemoteControlClient)}.
51ad87f5b40f2a3fd2d506dc15e00b8af28a8fa2baJean-Michel Trivi *
52ad87f5b40f2a3fd2d506dc15e00b8af28a8fa2baJean-Michel Trivi * <p>Here is an example of creating a RemoteControlClient instance after registering a media
53ad87f5b40f2a3fd2d506dc15e00b8af28a8fa2baJean-Michel Trivi * button event receiver:
54ad87f5b40f2a3fd2d506dc15e00b8af28a8fa2baJean-Michel Trivi * <pre>ComponentName myEventReceiver = new ComponentName(getPackageName(), MyRemoteControlEventReceiver.class.getName());
55ad87f5b40f2a3fd2d506dc15e00b8af28a8fa2baJean-Michel Trivi * AudioManager myAudioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
56ad87f5b40f2a3fd2d506dc15e00b8af28a8fa2baJean-Michel Trivi * myAudioManager.registerMediaButtonEventReceiver(myEventReceiver);
57ad87f5b40f2a3fd2d506dc15e00b8af28a8fa2baJean-Michel Trivi * // build the PendingIntent for the remote control client
58ad87f5b40f2a3fd2d506dc15e00b8af28a8fa2baJean-Michel Trivi * Intent mediaButtonIntent = new Intent(Intent.ACTION_MEDIA_BUTTON);
59ad87f5b40f2a3fd2d506dc15e00b8af28a8fa2baJean-Michel Trivi * mediaButtonIntent.setComponent(myEventReceiver);
60ad87f5b40f2a3fd2d506dc15e00b8af28a8fa2baJean-Michel Trivi * PendingIntent mediaPendingIntent = PendingIntent.getBroadcast(getApplicationContext(), 0, mediaButtonIntent, 0);
61ad87f5b40f2a3fd2d506dc15e00b8af28a8fa2baJean-Michel Trivi * // create and register the remote control client
62ad87f5b40f2a3fd2d506dc15e00b8af28a8fa2baJean-Michel Trivi * RemoteControlClient myRemoteControlClient = new RemoteControlClient(mediaPendingIntent);
63ad87f5b40f2a3fd2d506dc15e00b8af28a8fa2baJean-Michel Trivi * myAudioManager.registerRemoteControlClient(myRemoteControlClient);</pre>
64178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi */
654426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivipublic class RemoteControlClient
66178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi{
674426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    private final static String TAG = "RemoteControlClient";
68521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi    private final static boolean DEBUG = false;
694426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi
70178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi    /**
71178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     * Playback state of a RemoteControlClient which is stopped.
72178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     *
734426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     * @see #setPlaybackState(int)
74178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     */
75178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi    public final static int PLAYSTATE_STOPPED            = 1;
76178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi    /**
77178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     * Playback state of a RemoteControlClient which is paused.
78178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     *
794426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     * @see #setPlaybackState(int)
80178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     */
81178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi    public final static int PLAYSTATE_PAUSED             = 2;
82178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi    /**
83178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     * Playback state of a RemoteControlClient which is playing media.
84178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     *
854426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     * @see #setPlaybackState(int)
86178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     */
87178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi    public final static int PLAYSTATE_PLAYING            = 3;
88178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi    /**
89178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     * Playback state of a RemoteControlClient which is fast forwarding in the media
90178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     *    it is currently playing.
91178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     *
924426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     * @see #setPlaybackState(int)
93178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     */
94178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi    public final static int PLAYSTATE_FAST_FORWARDING    = 4;
95178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi    /**
96178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     * Playback state of a RemoteControlClient which is fast rewinding in the media
97178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     *    it is currently playing.
98178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     *
994426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     * @see #setPlaybackState(int)
100178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     */
101178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi    public final static int PLAYSTATE_REWINDING          = 5;
102178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi    /**
103178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     * Playback state of a RemoteControlClient which is skipping to the next
104178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     *    logical chapter (such as a song in a playlist) in the media it is currently playing.
105178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     *
1064426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     * @see #setPlaybackState(int)
107178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     */
108178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi    public final static int PLAYSTATE_SKIPPING_FORWARDS  = 6;
109178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi    /**
110178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     * Playback state of a RemoteControlClient which is skipping back to the previous
111178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     *    logical chapter (such as a song in a playlist) in the media it is currently playing.
112178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     *
1134426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     * @see #setPlaybackState(int)
114178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     */
115178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi    public final static int PLAYSTATE_SKIPPING_BACKWARDS = 7;
116178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi    /**
117178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     * Playback state of a RemoteControlClient which is buffering data to play before it can
118178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     *    start or resume playback.
119178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     *
1204426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     * @see #setPlaybackState(int)
121178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     */
122178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi    public final static int PLAYSTATE_BUFFERING          = 8;
123178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi    /**
124178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     * Playback state of a RemoteControlClient which cannot perform any playback related
125178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     *    operation because of an internal error. Examples of such situations are no network
126178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     *    connectivity when attempting to stream data from a server, or expired user credentials
127178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     *    when trying to play subscription-based content.
128178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     *
1294426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     * @see #setPlaybackState(int)
130178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     */
131178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi    public final static int PLAYSTATE_ERROR              = 9;
1324426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    /**
1334426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     * @hide
134466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi     * The value of a playback state when none has been declared.
135466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi     * Intentionally hidden as an application shouldn't set such a playback state value.
1364426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     */
1374426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    public final static int PLAYSTATE_NONE               = 0;
138178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi
139178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi    /**
1401357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi     * @hide
1413114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     * The default playback type, "local", indicating the presentation of the media is happening on
1423114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     * the same device (e.g. a phone, a tablet) as where it is controlled from.
1433114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     */
1443114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    public final static int PLAYBACK_TYPE_LOCAL = 0;
1453114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    /**
1461357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi     * @hide
1473114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     * A playback type indicating the presentation of the media is happening on
1483114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     * a different device (i.e. the remote device) than where it is controlled from.
1493114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     */
1503114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    public final static int PLAYBACK_TYPE_REMOTE = 1;
1513114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    private final static int PLAYBACK_TYPE_MIN = PLAYBACK_TYPE_LOCAL;
1523114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    private final static int PLAYBACK_TYPE_MAX = PLAYBACK_TYPE_REMOTE;
1533114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    /**
1541357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi     * @hide
1553114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     * Playback information indicating the playback volume is fixed, i.e. it cannot be controlled
1563114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     * from this object. An example of fixed playback volume is a remote player, playing over HDMI
1573114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     * where the user prefer to control the volume on the HDMI sink, rather than attenuate at the
1583114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     * source.
1593114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     * @see #PLAYBACKINFO_VOLUME_HANDLING.
1603114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     */
1613114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    public final static int PLAYBACK_VOLUME_FIXED = 0;
1623114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    /**
1631357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi     * @hide
1643114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     * Playback information indicating the playback volume is variable and can be controlled from
1653114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     * this object.
1663114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     * @see #PLAYBACKINFO_VOLUME_HANDLING.
1673114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     */
1683114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    public final static int PLAYBACK_VOLUME_VARIABLE = 1;
1693114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    /**
1703114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     * @hide (to be un-hidden)
1713114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     * The playback information value indicating the value of a given information type is invalid.
1723114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     * @see #PLAYBACKINFO_VOLUME_HANDLING.
1733114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     */
1743114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    public final static int PLAYBACKINFO_INVALID_VALUE = Integer.MIN_VALUE;
1753114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi
176bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi    /**
177bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi     * @hide
178bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi     * An unknown or invalid playback position value.
179bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi     */
180bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi    public final static long PLAYBACK_POSITION_INVALID = -1;
181bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi    /**
182bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi     * @hide
183bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi     * The default playback speed, 1x.
184bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi     */
185bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi    public final static float PLAYBACK_SPEED_1X = 1.0f;
186bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi
1873114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    //==========================================
1883114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    // Public keys for playback information
1893114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    /**
1901357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi     * @hide
1913114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     * Playback information that defines the type of playback associated with this
1923114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     * RemoteControlClient. See {@link #PLAYBACK_TYPE_LOCAL} and {@link #PLAYBACK_TYPE_REMOTE}.
1933114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     */
1943114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    public final static int PLAYBACKINFO_PLAYBACK_TYPE = 1;
1953114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    /**
1961357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi     * @hide
1973114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     * Playback information that defines at what volume the playback associated with this
1983114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     * RemoteControlClient is performed. This information is only used when the playback type is not
1993114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     * local (see {@link #PLAYBACKINFO_PLAYBACK_TYPE}).
2003114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     */
2013114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    public final static int PLAYBACKINFO_VOLUME = 2;
2023114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    /**
2031357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi     * @hide
2043114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     * Playback information that defines the maximum volume volume value that is supported
2053114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     * by the playback associated with this RemoteControlClient. This information is only used
2063114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     * when the playback type is not local (see {@link #PLAYBACKINFO_PLAYBACK_TYPE}).
2073114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     */
2083114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    public final static int PLAYBACKINFO_VOLUME_MAX = 3;
2093114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    /**
2101357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi     * @hide
2113114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     * Playback information that defines how volume is handled for the presentation of the media.
2123114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     * @see #PLAYBACK_VOLUME_FIXED
2133114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     * @see #PLAYBACK_VOLUME_VARIABLE
2143114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     */
2153114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    public final static int PLAYBACKINFO_VOLUME_HANDLING = 4;
2163114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    /**
2171357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi     * @hide
2183114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     * Playback information that defines over what stream type the media is presented.
2193114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     */
2203114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    public final static int PLAYBACKINFO_USES_STREAM = 5;
2213114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi
2223114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    //==========================================
223521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi    // Public flags for the supported transport control capabilities
2243114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    /**
225178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     * Flag indicating a RemoteControlClient makes use of the "previous" media key.
226178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     *
2274426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     * @see #setTransportControlFlags(int)
228178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     * @see android.view.KeyEvent#KEYCODE_MEDIA_PREVIOUS
229178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     */
230178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi    public final static int FLAG_KEY_MEDIA_PREVIOUS = 1 << 0;
231178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi    /**
232466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi     * Flag indicating a RemoteControlClient makes use of the "rewind" media key.
233178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     *
2344426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     * @see #setTransportControlFlags(int)
235178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     * @see android.view.KeyEvent#KEYCODE_MEDIA_REWIND
236178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     */
237178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi    public final static int FLAG_KEY_MEDIA_REWIND = 1 << 1;
238178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi    /**
239178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     * Flag indicating a RemoteControlClient makes use of the "play" media key.
240178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     *
2414426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     * @see #setTransportControlFlags(int)
242178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     * @see android.view.KeyEvent#KEYCODE_MEDIA_PLAY
243178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     */
244178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi    public final static int FLAG_KEY_MEDIA_PLAY = 1 << 2;
245178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi    /**
246178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     * Flag indicating a RemoteControlClient makes use of the "play/pause" media key.
247178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     *
2484426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     * @see #setTransportControlFlags(int)
249178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     * @see android.view.KeyEvent#KEYCODE_MEDIA_PLAY_PAUSE
250178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     */
251178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi    public final static int FLAG_KEY_MEDIA_PLAY_PAUSE = 1 << 3;
252178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi    /**
253178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     * Flag indicating a RemoteControlClient makes use of the "pause" media key.
254178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     *
2554426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     * @see #setTransportControlFlags(int)
256178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     * @see android.view.KeyEvent#KEYCODE_MEDIA_PAUSE
257178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     */
258178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi    public final static int FLAG_KEY_MEDIA_PAUSE = 1 << 4;
259178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi    /**
260178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     * Flag indicating a RemoteControlClient makes use of the "stop" media key.
261178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     *
2624426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     * @see #setTransportControlFlags(int)
263178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     * @see android.view.KeyEvent#KEYCODE_MEDIA_STOP
264178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     */
265178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi    public final static int FLAG_KEY_MEDIA_STOP = 1 << 5;
266178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi    /**
267178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     * Flag indicating a RemoteControlClient makes use of the "fast forward" media key.
268178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     *
2694426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     * @see #setTransportControlFlags(int)
270178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     * @see android.view.KeyEvent#KEYCODE_MEDIA_FAST_FORWARD
271178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     */
272178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi    public final static int FLAG_KEY_MEDIA_FAST_FORWARD = 1 << 6;
273178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi    /**
274178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     * Flag indicating a RemoteControlClient makes use of the "next" media key.
275178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     *
2764426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     * @see #setTransportControlFlags(int)
277178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     * @see android.view.KeyEvent#KEYCODE_MEDIA_NEXT
278178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     */
279178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi    public final static int FLAG_KEY_MEDIA_NEXT = 1 << 7;
280bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi    /**
281bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi     * Flag indicating a RemoteControlClient can receive changes in the media playback position
282e63b0609c3b5f6c21d4e006ee9ddd3ba98a4e684Scott Main     * through the {@link OnPlaybackPositionUpdateListener} interface. This flag must be set
2833261b537c5fdec824575a1f6ad6d8942715e82e2Jean-Michel Trivi     * in order for components that display the RemoteControlClient information, to display and
2843261b537c5fdec824575a1f6ad6d8942715e82e2Jean-Michel Trivi     * let the user control media playback position.
285bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi     * @see #setTransportControlFlags(int)
286915747730060dff71b5b2ca7e4ee4073024fc24eJean-Michel Trivi     * @see #setOnGetPlaybackPositionListener(OnGetPlaybackPositionListener)
2873261b537c5fdec824575a1f6ad6d8942715e82e2Jean-Michel Trivi     * @see #setPlaybackPositionUpdateListener(OnPlaybackPositionUpdateListener)
288bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi     */
289bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi    public final static int FLAG_KEY_MEDIA_POSITION_UPDATE = 1 << 8;
290178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi
291178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi    /**
2924426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     * @hide
293466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi     * The flags for when no media keys are declared supported.
294466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi     * Intentionally hidden as an application shouldn't set the transport control flags
295466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi     *     to this value.
2964426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     */
2974426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    public final static int FLAGS_KEY_MEDIA_NONE = 0;
2984426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi
2994426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    /**
3004426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     * @hide
3014426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     * Flag used to signal some type of metadata exposed by the RemoteControlClient is requested.
302178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     */
3034426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    public final static int FLAG_INFORMATION_REQUEST_METADATA = 1 << 0;
304178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi    /**
3054426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     * @hide
306178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     * Flag used to signal that the transport control buttons supported by the
307466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi     *     RemoteControlClient are requested.
308178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     * This can for instance happen when playback is at the end of a playlist, and the "next"
309178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     * operation is not supported anymore.
310178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     */
3114426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    public final static int FLAG_INFORMATION_REQUEST_KEY_MEDIA = 1 << 1;
312178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi    /**
3134426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     * @hide
314466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi     * Flag used to signal that the playback state of the RemoteControlClient is requested.
315178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     */
3164426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    public final static int FLAG_INFORMATION_REQUEST_PLAYSTATE = 1 << 2;
317178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi    /**
3184426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     * @hide
319466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi     * Flag used to signal that the album art for the RemoteControlClient is requested.
320178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     */
3214426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    public final static int FLAG_INFORMATION_REQUEST_ALBUM_ART = 1 << 3;
3224426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi
3234426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    /**
3246e920e6dac11c3ebf6c0c19402934834e9e491bfJean-Michel Trivi     * Class constructor.
3256e920e6dac11c3ebf6c0c19402934834e9e491bfJean-Michel Trivi     * @param mediaButtonIntent The intent that will be sent for the media button events sent
3266e920e6dac11c3ebf6c0c19402934834e9e491bfJean-Michel Trivi     *     by remote controls.
3276e920e6dac11c3ebf6c0c19402934834e9e491bfJean-Michel Trivi     *     This intent needs to have been constructed with the {@link Intent#ACTION_MEDIA_BUTTON}
3286e920e6dac11c3ebf6c0c19402934834e9e491bfJean-Michel Trivi     *     action, and have a component that will handle the intent (set with
3296e920e6dac11c3ebf6c0c19402934834e9e491bfJean-Michel Trivi     *     {@link Intent#setComponent(ComponentName)}) registered with
3306e920e6dac11c3ebf6c0c19402934834e9e491bfJean-Michel Trivi     *     {@link AudioManager#registerMediaButtonEventReceiver(ComponentName)}
3316e920e6dac11c3ebf6c0c19402934834e9e491bfJean-Michel Trivi     *     before this new RemoteControlClient can itself be registered with
3326e920e6dac11c3ebf6c0c19402934834e9e491bfJean-Michel Trivi     *     {@link AudioManager#registerRemoteControlClient(RemoteControlClient)}.
3336e920e6dac11c3ebf6c0c19402934834e9e491bfJean-Michel Trivi     * @see AudioManager#registerMediaButtonEventReceiver(ComponentName)
3346e920e6dac11c3ebf6c0c19402934834e9e491bfJean-Michel Trivi     * @see AudioManager#registerRemoteControlClient(RemoteControlClient)
3356e920e6dac11c3ebf6c0c19402934834e9e491bfJean-Michel Trivi     */
3366e920e6dac11c3ebf6c0c19402934834e9e491bfJean-Michel Trivi    public RemoteControlClient(PendingIntent mediaButtonIntent) {
337f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi        mRcMediaIntent = mediaButtonIntent;
3386e920e6dac11c3ebf6c0c19402934834e9e491bfJean-Michel Trivi
3396e920e6dac11c3ebf6c0c19402934834e9e491bfJean-Michel Trivi        Looper looper;
3406e920e6dac11c3ebf6c0c19402934834e9e491bfJean-Michel Trivi        if ((looper = Looper.myLooper()) != null) {
3416e920e6dac11c3ebf6c0c19402934834e9e491bfJean-Michel Trivi            mEventHandler = new EventHandler(this, looper);
3426e920e6dac11c3ebf6c0c19402934834e9e491bfJean-Michel Trivi        } else if ((looper = Looper.getMainLooper()) != null) {
3436e920e6dac11c3ebf6c0c19402934834e9e491bfJean-Michel Trivi            mEventHandler = new EventHandler(this, looper);
3446e920e6dac11c3ebf6c0c19402934834e9e491bfJean-Michel Trivi        } else {
3456e920e6dac11c3ebf6c0c19402934834e9e491bfJean-Michel Trivi            mEventHandler = null;
3466e920e6dac11c3ebf6c0c19402934834e9e491bfJean-Michel Trivi            Log.e(TAG, "RemoteControlClient() couldn't find main application thread");
3476e920e6dac11c3ebf6c0c19402934834e9e491bfJean-Michel Trivi        }
3486e920e6dac11c3ebf6c0c19402934834e9e491bfJean-Michel Trivi    }
3496e920e6dac11c3ebf6c0c19402934834e9e491bfJean-Michel Trivi
3506e920e6dac11c3ebf6c0c19402934834e9e491bfJean-Michel Trivi    /**
3516e920e6dac11c3ebf6c0c19402934834e9e491bfJean-Michel Trivi     * Class constructor for a remote control client whose internal event handling
3526e920e6dac11c3ebf6c0c19402934834e9e491bfJean-Michel Trivi     * happens on a user-provided Looper.
3536e920e6dac11c3ebf6c0c19402934834e9e491bfJean-Michel Trivi     * @param mediaButtonIntent The intent that will be sent for the media button events sent
3546e920e6dac11c3ebf6c0c19402934834e9e491bfJean-Michel Trivi     *     by remote controls.
3556e920e6dac11c3ebf6c0c19402934834e9e491bfJean-Michel Trivi     *     This intent needs to have been constructed with the {@link Intent#ACTION_MEDIA_BUTTON}
3566e920e6dac11c3ebf6c0c19402934834e9e491bfJean-Michel Trivi     *     action, and have a component that will handle the intent (set with
3576e920e6dac11c3ebf6c0c19402934834e9e491bfJean-Michel Trivi     *     {@link Intent#setComponent(ComponentName)}) registered with
3586e920e6dac11c3ebf6c0c19402934834e9e491bfJean-Michel Trivi     *     {@link AudioManager#registerMediaButtonEventReceiver(ComponentName)}
3596e920e6dac11c3ebf6c0c19402934834e9e491bfJean-Michel Trivi     *     before this new RemoteControlClient can itself be registered with
3606e920e6dac11c3ebf6c0c19402934834e9e491bfJean-Michel Trivi     *     {@link AudioManager#registerRemoteControlClient(RemoteControlClient)}.
3616e920e6dac11c3ebf6c0c19402934834e9e491bfJean-Michel Trivi     * @param looper The Looper running the event loop.
3626e920e6dac11c3ebf6c0c19402934834e9e491bfJean-Michel Trivi     * @see AudioManager#registerMediaButtonEventReceiver(ComponentName)
3636e920e6dac11c3ebf6c0c19402934834e9e491bfJean-Michel Trivi     * @see AudioManager#registerRemoteControlClient(RemoteControlClient)
3646e920e6dac11c3ebf6c0c19402934834e9e491bfJean-Michel Trivi     */
3656e920e6dac11c3ebf6c0c19402934834e9e491bfJean-Michel Trivi    public RemoteControlClient(PendingIntent mediaButtonIntent, Looper looper) {
366f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi        mRcMediaIntent = mediaButtonIntent;
3676e920e6dac11c3ebf6c0c19402934834e9e491bfJean-Michel Trivi
3686e920e6dac11c3ebf6c0c19402934834e9e491bfJean-Michel Trivi        mEventHandler = new EventHandler(this, looper);
3696e920e6dac11c3ebf6c0c19402934834e9e491bfJean-Michel Trivi    }
3706e920e6dac11c3ebf6c0c19402934834e9e491bfJean-Michel Trivi
3715ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Trivi    private static final int[] METADATA_KEYS_TYPE_STRING = {
3725ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Trivi        MediaMetadataRetriever.METADATA_KEY_ALBUM,
3735ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Trivi        MediaMetadataRetriever.METADATA_KEY_ALBUMARTIST,
3745ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Trivi        MediaMetadataRetriever.METADATA_KEY_TITLE,
3755ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Trivi        MediaMetadataRetriever.METADATA_KEY_ARTIST,
3765ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Trivi        MediaMetadataRetriever.METADATA_KEY_AUTHOR,
3775ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Trivi        MediaMetadataRetriever.METADATA_KEY_COMPILATION,
3785ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Trivi        MediaMetadataRetriever.METADATA_KEY_COMPOSER,
3795ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Trivi        MediaMetadataRetriever.METADATA_KEY_DATE,
3805ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Trivi        MediaMetadataRetriever.METADATA_KEY_GENRE,
3815ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Trivi        MediaMetadataRetriever.METADATA_KEY_TITLE,
3825ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Trivi        MediaMetadataRetriever.METADATA_KEY_WRITER };
3835ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Trivi    private static final int[] METADATA_KEYS_TYPE_LONG = {
3845ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Trivi        MediaMetadataRetriever.METADATA_KEY_CD_TRACK_NUMBER,
3855ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Trivi        MediaMetadataRetriever.METADATA_KEY_DISC_NUMBER,
3865ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Trivi        MediaMetadataRetriever.METADATA_KEY_DURATION };
3875ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Trivi
3884426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    /**
3894426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     * Class used to modify metadata in a {@link RemoteControlClient} object.
390466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi     * Use {@link RemoteControlClient#editMetadata(boolean)} to create an instance of an editor,
391466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi     * on which you set the metadata for the RemoteControlClient instance. Once all the information
392466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi     * has been set, use {@link #apply()} to make it the new metadata that should be displayed
393466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi     * for the associated client. Once the metadata has been "applied", you cannot reuse this
394466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi     * instance of the MetadataEditor.
3954426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     */
3964426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    public class MetadataEditor {
397466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi        /**
398466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi         * @hide
399466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi         */
4004da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi        protected boolean mMetadataChanged;
401466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi        /**
402466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi         * @hide
403466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi         */
4044da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi        protected boolean mArtworkChanged;
405466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi        /**
406466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi         * @hide
407466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi         */
4084da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi        protected Bitmap mEditorArtwork;
409466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi        /**
410466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi         * @hide
411466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi         */
4124da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi        protected Bundle mEditorMetadata;
4134da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi        private boolean mApplied = false;
4144da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi
4154da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi        // only use RemoteControlClient.editMetadata() to get a MetadataEditor instance
4164da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi        private MetadataEditor() { }
4174da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi        /**
4184da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi         * @hide
4194da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi         */
4204da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi        public Object clone() throws CloneNotSupportedException {
4214da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi            throw new CloneNotSupportedException();
4224426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi        }
4234426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi
4244da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi        /**
4255ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Trivi         * The metadata key for the content artwork / album art.
4265ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Trivi         */
427466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi        public final static int BITMAP_KEY_ARTWORK = 100;
428466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi        /**
429466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi         * @hide
430466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi         * TODO(jmtrivi) have lockscreen and music move to the new key name
431466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi         */
432466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi        public final static int METADATA_KEY_ARTWORK = BITMAP_KEY_ARTWORK;
4335ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Trivi
4345ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Trivi        /**
4354da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi         * Adds textual information to be displayed.
4364da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi         * Note that none of the information added after {@link #apply()} has been called,
4374da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi         * will be displayed.
438466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi         * @param key The identifier of a the metadata field to set. Valid values are
4394da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi         *      {@link android.media.MediaMetadataRetriever#METADATA_KEY_ALBUM},
4404da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi         *      {@link android.media.MediaMetadataRetriever#METADATA_KEY_ALBUMARTIST},
4414da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi         *      {@link android.media.MediaMetadataRetriever#METADATA_KEY_TITLE},
4424da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi         *      {@link android.media.MediaMetadataRetriever#METADATA_KEY_ARTIST},
4434da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi         *      {@link android.media.MediaMetadataRetriever#METADATA_KEY_AUTHOR},
4444da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi         *      {@link android.media.MediaMetadataRetriever#METADATA_KEY_COMPILATION},
4454da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi         *      {@link android.media.MediaMetadataRetriever#METADATA_KEY_COMPOSER},
4464da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi         *      {@link android.media.MediaMetadataRetriever#METADATA_KEY_DATE},
4474da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi         *      {@link android.media.MediaMetadataRetriever#METADATA_KEY_GENRE},
4484da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi         *      {@link android.media.MediaMetadataRetriever#METADATA_KEY_TITLE},
449466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi         *      {@link android.media.MediaMetadataRetriever#METADATA_KEY_WRITER}.
450466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi         * @param value The text for the given key, or {@code null} to signify there is no valid
4514da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi         *      information for the field.
452466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi         * @return Returns a reference to the same MetadataEditor object, so you can chain put
453466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi         *      calls together.
4544da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi         */
4555ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Trivi        public synchronized MetadataEditor putString(int key, String value)
4565ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Trivi                throws IllegalArgumentException {
4574da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi            if (mApplied) {
4584da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi                Log.e(TAG, "Can't edit a previously applied MetadataEditor");
4594da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi                return this;
4604da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi            }
4615ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Trivi            if (!validTypeForKey(key, METADATA_KEYS_TYPE_STRING)) {
4625ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Trivi                throw(new IllegalArgumentException("Invalid type 'String' for key "+ key));
4635ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Trivi            }
4644da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi            mEditorMetadata.putString(String.valueOf(key), value);
4654da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi            mMetadataChanged = true;
4664426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi            return this;
4674426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi        }
4684426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi
4694da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi        /**
470466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi         * Adds numerical information to be displayed.
471466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi         * Note that none of the information added after {@link #apply()} has been called,
472466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi         * will be displayed.
4735ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Trivi         * @param key the identifier of a the metadata field to set. Valid values are
4745ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Trivi         *      {@link android.media.MediaMetadataRetriever#METADATA_KEY_CD_TRACK_NUMBER},
4755ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Trivi         *      {@link android.media.MediaMetadataRetriever#METADATA_KEY_DISC_NUMBER},
4765ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Trivi         *      {@link android.media.MediaMetadataRetriever#METADATA_KEY_DURATION} (with a value
4775ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Trivi         *      expressed in milliseconds),
4785ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Trivi         *      {@link android.media.MediaMetadataRetriever#METADATA_KEY_YEAR}.
479466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi         * @param value The long value for the given key
480466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi         * @return Returns a reference to the same MetadataEditor object, so you can chain put
481466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi         *      calls together.
4825ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Trivi         * @throws IllegalArgumentException
4834da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi         */
4845ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Trivi        public synchronized MetadataEditor putLong(int key, long value)
4855ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Trivi                throws IllegalArgumentException {
4865ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Trivi            if (mApplied) {
4875ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Trivi                Log.e(TAG, "Can't edit a previously applied MetadataEditor");
4885ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Trivi                return this;
4895ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Trivi            }
4905ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Trivi            if (!validTypeForKey(key, METADATA_KEYS_TYPE_LONG)) {
4915ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Trivi                throw(new IllegalArgumentException("Invalid type 'long' for key "+ key));
4925ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Trivi            }
4935ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Trivi            mEditorMetadata.putLong(String.valueOf(key), value);
4945ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Trivi            mMetadataChanged = true;
4955ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Trivi            return this;
4965ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Trivi        }
4974da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi
4984da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi        /**
4994da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi         * Sets the album / artwork picture to be displayed on the remote control.
500466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi         * @param key the identifier of the bitmap to set. The only valid value is
501466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi         *      {@link #BITMAP_KEY_ARTWORK}
502466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi         * @param bitmap The bitmap for the artwork, or null if there isn't any.
503466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi         * @return Returns a reference to the same MetadataEditor object, so you can chain put
504466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi         *      calls together.
5055ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Trivi         * @throws IllegalArgumentException
5064da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi         * @see android.graphics.Bitmap
5074da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi         */
5085ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Trivi        public synchronized MetadataEditor putBitmap(int key, Bitmap bitmap)
5095ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Trivi                throws IllegalArgumentException {
5104da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi            if (mApplied) {
5114da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi                Log.e(TAG, "Can't edit a previously applied MetadataEditor");
5124da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi                return this;
5134da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi            }
514466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi            if (key != BITMAP_KEY_ARTWORK) {
5155ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Trivi                throw(new IllegalArgumentException("Invalid type 'Bitmap' for key "+ key));
5164da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi            }
5174a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi            mEditorArtwork = bitmap;
5184da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi            mArtworkChanged = true;
5194da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi            return this;
5204426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi        }
521178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi
5224da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi        /**
523466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi         * Clears all the metadata that has been set since the MetadataEditor instance was
524466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi         *     created with {@link RemoteControlClient#editMetadata(boolean)}.
5254da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi         */
5264da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi        public synchronized void clear() {
5274da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi            if (mApplied) {
5284da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi                Log.e(TAG, "Can't clear a previously applied MetadataEditor");
5294da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi                return;
5304da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi            }
5314da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi            mEditorMetadata.clear();
5324da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi            mEditorArtwork = null;
5334426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi        }
534178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi
5354da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi        /**
536466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi         * Associates all the metadata that has been set since the MetadataEditor instance was
537466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi         *     created with {@link RemoteControlClient#editMetadata(boolean)}, or since
538466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi         *     {@link #clear()} was called, with the RemoteControlClient. Once "applied",
539466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi         *     this MetadataEditor cannot be reused to edit the RemoteControlClient's metadata.
5404da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi         */
5414da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi        public synchronized void apply() {
5424da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi            if (mApplied) {
5434da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi                Log.e(TAG, "Can't apply a previously applied MetadataEditor");
5444da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi                return;
5454da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi            }
5464da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi            synchronized(mCacheLock) {
5474da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi                // assign the edited data
5484da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi                mMetadata = new Bundle(mEditorMetadata);
5494a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi                if ((mOriginalArtwork != null) && (!mOriginalArtwork.equals(mEditorArtwork))) {
5504a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi                    mOriginalArtwork.recycle();
55134d0d300cac645b48cce5a1735f45e1102d4ef0eJean-Michel Trivi                }
5524a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi                mOriginalArtwork = mEditorArtwork;
55334d0d300cac645b48cce5a1735f45e1102d4ef0eJean-Michel Trivi                mEditorArtwork = null;
5544da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi                if (mMetadataChanged & mArtworkChanged) {
5554da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi                    // send to remote control display if conditions are met
55644413e5b514a91806a4bb4c7780029ea43be6f81Jean-Michel Trivi                    sendMetadataWithArtwork_syncCacheLock();
5574da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi                } else if (mMetadataChanged) {
5584da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi                    // send to remote control display if conditions are met
5594da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi                    sendMetadata_syncCacheLock();
5604da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi                } else if (mArtworkChanged) {
5614da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi                    // send to remote control display if conditions are met
5624da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi                    sendArtwork_syncCacheLock();
5634da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi                }
5644da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi                mApplied = true;
5654da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi            }
5664426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi        }
5674426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    }
5684426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi
5694426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    /**
570466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi     * Creates a {@link MetadataEditor}.
571466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi     * @param startEmpty Set to false if you want the MetadataEditor to contain the metadata that
572466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi     *     was previously applied to the RemoteControlClient, or true if it is to be created empty.
573466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi     * @return a new MetadataEditor instance.
5744426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     */
5754da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi    public MetadataEditor editMetadata(boolean startEmpty) {
5764da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi        MetadataEditor editor = new MetadataEditor();
5774da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi        if (startEmpty) {
5784da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi            editor.mEditorMetadata = new Bundle();
5794da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi            editor.mEditorArtwork = null;
5804da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi            editor.mMetadataChanged = true;
5814da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi            editor.mArtworkChanged = true;
5824da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi        } else {
5834da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi            editor.mEditorMetadata = new Bundle(mMetadata);
5844a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi            editor.mEditorArtwork = mOriginalArtwork;
5854da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi            editor.mMetadataChanged = false;
5864da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi            editor.mArtworkChanged = false;
5874426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi        }
5884da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi        return editor;
5894426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    }
5904426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi
5914426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    /**
5924426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     * Sets the current playback state.
593466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi     * @param state The current playback state, one of the following values:
594178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     *       {@link #PLAYSTATE_STOPPED},
595178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     *       {@link #PLAYSTATE_PAUSED},
596178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     *       {@link #PLAYSTATE_PLAYING},
597178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     *       {@link #PLAYSTATE_FAST_FORWARDING},
598178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     *       {@link #PLAYSTATE_REWINDING},
599178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     *       {@link #PLAYSTATE_SKIPPING_FORWARDS},
600178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     *       {@link #PLAYSTATE_SKIPPING_BACKWARDS},
601178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     *       {@link #PLAYSTATE_BUFFERING},
602178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     *       {@link #PLAYSTATE_ERROR}.
603178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     */
6044426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    public void setPlaybackState(int state) {
605bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi        setPlaybackState(state, PLAYBACK_POSITION_INVALID, PLAYBACK_SPEED_1X);
606bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi    }
607bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi
608bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi    /**
609bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi     * Sets the current playback state and the matching media position for the current playback
610bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi     *   speed.
611bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi     * @param state The current playback state, one of the following values:
612bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi     *       {@link #PLAYSTATE_STOPPED},
613bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi     *       {@link #PLAYSTATE_PAUSED},
614bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi     *       {@link #PLAYSTATE_PLAYING},
615bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi     *       {@link #PLAYSTATE_FAST_FORWARDING},
616bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi     *       {@link #PLAYSTATE_REWINDING},
617bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi     *       {@link #PLAYSTATE_SKIPPING_FORWARDS},
618bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi     *       {@link #PLAYSTATE_SKIPPING_BACKWARDS},
619bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi     *       {@link #PLAYSTATE_BUFFERING},
620bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi     *       {@link #PLAYSTATE_ERROR}.
621bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi     * @param timeInMs a 0 or positive value for the current media position expressed in ms
622bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi     *    (same unit as for when sending the media duration, if applicable, with
623bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi     *    {@link android.media.MediaMetadataRetriever#METADATA_KEY_DURATION} in the
624bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi     *    {@link RemoteControlClient.MetadataEditor}). Negative values imply that position is not
625bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi     *    known (e.g. listening to a live stream of a radio) or not applicable (e.g. when state
626bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi     *    is {@link #PLAYSTATE_BUFFERING} and nothing had played yet).
627bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi     * @param playbackSpeed a value expressed as a ratio of 1x playback: 1.0f is normal playback,
628bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi     *    2.0f is 2x, 0.5f is half-speed, -2.0f is rewind at 2x speed. 0.0f means nothing is
629bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi     *    playing (e.g. when state is {@link #PLAYSTATE_ERROR}).
630bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi     */
631bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi    public void setPlaybackState(int state, long timeInMs, float playbackSpeed) {
6324426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi        synchronized(mCacheLock) {
633bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi            if ((mPlaybackState != state) || (mPlaybackPositionMs != timeInMs)
634bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi                    || (mPlaybackSpeed != playbackSpeed)) {
63568622396b62f9084781add1e12f4d513b633ab54Jean-Michel Trivi                // store locally
63668622396b62f9084781add1e12f4d513b633ab54Jean-Michel Trivi                mPlaybackState = state;
637bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi                mPlaybackPositionMs = timeInMs;
638bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi                mPlaybackSpeed = playbackSpeed;
63968622396b62f9084781add1e12f4d513b633ab54Jean-Michel Trivi                // keep track of when the state change occurred
64068622396b62f9084781add1e12f4d513b633ab54Jean-Michel Trivi                mPlaybackStateChangeTimeMs = SystemClock.elapsedRealtime();
64168622396b62f9084781add1e12f4d513b633ab54Jean-Michel Trivi
64268622396b62f9084781add1e12f4d513b633ab54Jean-Michel Trivi                // send to remote control display if conditions are met
64368622396b62f9084781add1e12f4d513b633ab54Jean-Michel Trivi                sendPlaybackState_syncCacheLock();
6443114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                // update AudioService
645bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi                sendAudioServiceNewPlaybackState_syncCacheLock();
646521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi
647521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi                // handle automatic playback position refreshes
648c3c4babf8424f65b3d3d2700f60fae6e94e9cd00Jean-Michel Trivi                initiateCheckForDrift_syncCacheLock();
649521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi            }
650521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi        }
651521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi    }
652521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi
653c3c4babf8424f65b3d3d2700f60fae6e94e9cd00Jean-Michel Trivi    private void initiateCheckForDrift_syncCacheLock() {
654c3c4babf8424f65b3d3d2700f60fae6e94e9cd00Jean-Michel Trivi        if (mEventHandler == null) {
655c3c4babf8424f65b3d3d2700f60fae6e94e9cd00Jean-Michel Trivi            return;
656c3c4babf8424f65b3d3d2700f60fae6e94e9cd00Jean-Michel Trivi        }
657c3c4babf8424f65b3d3d2700f60fae6e94e9cd00Jean-Michel Trivi        mEventHandler.removeMessages(MSG_POSITION_DRIFT_CHECK);
658c3c4babf8424f65b3d3d2700f60fae6e94e9cd00Jean-Michel Trivi        if (!mNeedsPositionSync) {
659c3c4babf8424f65b3d3d2700f60fae6e94e9cd00Jean-Michel Trivi            return;
660c3c4babf8424f65b3d3d2700f60fae6e94e9cd00Jean-Michel Trivi        }
661c3c4babf8424f65b3d3d2700f60fae6e94e9cd00Jean-Michel Trivi        if (mPlaybackPositionMs < 0) {
662c3c4babf8424f65b3d3d2700f60fae6e94e9cd00Jean-Michel Trivi            // the current playback state has no known playback position, it's no use
663c3c4babf8424f65b3d3d2700f60fae6e94e9cd00Jean-Michel Trivi            // trying to see if there is any drift at this point
664c3c4babf8424f65b3d3d2700f60fae6e94e9cd00Jean-Michel Trivi            // (this also bypasses this mechanism for older apps that use the old
665c3c4babf8424f65b3d3d2700f60fae6e94e9cd00Jean-Michel Trivi            //  setPlaybackState(int) API)
666c3c4babf8424f65b3d3d2700f60fae6e94e9cd00Jean-Michel Trivi            return;
667c3c4babf8424f65b3d3d2700f60fae6e94e9cd00Jean-Michel Trivi        }
668c3c4babf8424f65b3d3d2700f60fae6e94e9cd00Jean-Michel Trivi        if (playbackPositionShouldMove(mPlaybackState)) {
669c3c4babf8424f65b3d3d2700f60fae6e94e9cd00Jean-Michel Trivi            // playback position moving, schedule next position drift check
670c3c4babf8424f65b3d3d2700f60fae6e94e9cd00Jean-Michel Trivi            mEventHandler.sendMessageDelayed(
671c3c4babf8424f65b3d3d2700f60fae6e94e9cd00Jean-Michel Trivi                    mEventHandler.obtainMessage(MSG_POSITION_DRIFT_CHECK),
672c3c4babf8424f65b3d3d2700f60fae6e94e9cd00Jean-Michel Trivi                    getCheckPeriodFromSpeed(mPlaybackSpeed));
673c3c4babf8424f65b3d3d2700f60fae6e94e9cd00Jean-Michel Trivi        }
674c3c4babf8424f65b3d3d2700f60fae6e94e9cd00Jean-Michel Trivi    }
675c3c4babf8424f65b3d3d2700f60fae6e94e9cd00Jean-Michel Trivi
676521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi    private void onPositionDriftCheck() {
677521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi        if (DEBUG) { Log.d(TAG, "onPositionDriftCheck()"); }
678521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi        synchronized(mCacheLock) {
679c3c4babf8424f65b3d3d2700f60fae6e94e9cd00Jean-Michel Trivi            if ((mEventHandler == null) || (mPositionProvider == null) || !mNeedsPositionSync) {
680521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi                return;
681521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi            }
682c3c4babf8424f65b3d3d2700f60fae6e94e9cd00Jean-Michel Trivi            if ((mPlaybackPositionMs < 0) || (mPlaybackSpeed == 0.0f)) {
683c3c4babf8424f65b3d3d2700f60fae6e94e9cd00Jean-Michel Trivi                if (DEBUG) { Log.d(TAG, " no valid position or 0 speed, no check needed"); }
684521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi                return;
685521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi            }
686521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi            long estPos = mPlaybackPositionMs + (long)
687521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi                    ((SystemClock.elapsedRealtime() - mPlaybackStateChangeTimeMs) / mPlaybackSpeed);
688521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi            long actPos = mPositionProvider.onGetPlaybackPosition();
689521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi            if (actPos >= 0) {
690521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi                if (Math.abs(estPos - actPos) > POSITION_DRIFT_MAX_MS) {
691521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi                    // drift happened, report the new position
692521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi                    if (DEBUG) { Log.w(TAG, " drift detected: actual=" +actPos +"  est=" +estPos); }
693521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi                    setPlaybackState(mPlaybackState, actPos, mPlaybackSpeed);
694521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi                } else {
695521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi                    if (DEBUG) { Log.d(TAG, " no drift: actual=" + actPos +"  est=" + estPos); }
696521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi                    // no drift, schedule the next drift check
697521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi                    mEventHandler.sendMessageDelayed(
698521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi                            mEventHandler.obtainMessage(MSG_POSITION_DRIFT_CHECK),
699521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi                            getCheckPeriodFromSpeed(mPlaybackSpeed));
700521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi                }
701521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi            } else {
702521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi                // invalid position (negative value), can't check for drift
703521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi                mEventHandler.removeMessages(MSG_POSITION_DRIFT_CHECK);
70468622396b62f9084781add1e12f4d513b633ab54Jean-Michel Trivi            }
7054426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi        }
7064426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    }
707178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi
708178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi    /**
7094426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     * Sets the flags for the media transport control buttons that this client supports.
710466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi     * @param transportControlFlags A combination of the following flags:
7114426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     *      {@link #FLAG_KEY_MEDIA_PREVIOUS},
712178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     *      {@link #FLAG_KEY_MEDIA_REWIND},
713178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     *      {@link #FLAG_KEY_MEDIA_PLAY},
714178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     *      {@link #FLAG_KEY_MEDIA_PLAY_PAUSE},
715178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     *      {@link #FLAG_KEY_MEDIA_PAUSE},
716178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     *      {@link #FLAG_KEY_MEDIA_STOP},
717178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     *      {@link #FLAG_KEY_MEDIA_FAST_FORWARD},
718915747730060dff71b5b2ca7e4ee4073024fc24eJean-Michel Trivi     *      {@link #FLAG_KEY_MEDIA_NEXT},
719915747730060dff71b5b2ca7e4ee4073024fc24eJean-Michel Trivi     *      {@link #FLAG_KEY_MEDIA_POSITION_UPDATE}
720178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     */
7214426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    public void setTransportControlFlags(int transportControlFlags) {
7224426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi        synchronized(mCacheLock) {
7234426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi            // store locally
7244426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi            mTransportControlFlags = transportControlFlags;
7254426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi
7264426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi            // send to remote control display if conditions are met
7273261b537c5fdec824575a1f6ad6d8942715e82e2Jean-Michel Trivi            sendTransportControlInfo_syncCacheLock();
7284426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi        }
7294426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    }
730178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi
731bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi    /**
732bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi     * Interface definition for a callback to be invoked when the media playback position is
733bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi     * requested to be updated.
7343261b537c5fdec824575a1f6ad6d8942715e82e2Jean-Michel Trivi     * @see RemoteControlClient#FLAG_KEY_MEDIA_POSITION_UPDATE
735bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi     */
736bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi    public interface OnPlaybackPositionUpdateListener {
737bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi        /**
7383261b537c5fdec824575a1f6ad6d8942715e82e2Jean-Michel Trivi         * Called on the implementer to notify it that the playback head should be set at the given
739bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi         * position. If the position can be changed from its current value, the implementor of
7403fbf67e217fb489fe7318a9e43d8ae86646eb4ccJean-Michel Trivi         * the interface must also update the playback position using
741e63b0609c3b5f6c21d4e006ee9ddd3ba98a4e684Scott Main         * {@link #setPlaybackState(int, long, float)} to reflect the actual new
742bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi         * position being used, regardless of whether it differs from the requested position.
7433fbf67e217fb489fe7318a9e43d8ae86646eb4ccJean-Michel Trivi         * Failure to do so would cause the system to not know the new actual playback position,
7443fbf67e217fb489fe7318a9e43d8ae86646eb4ccJean-Michel Trivi         * and user interface components would fail to show the user where playback resumed after
7453fbf67e217fb489fe7318a9e43d8ae86646eb4ccJean-Michel Trivi         * the position was updated.
746bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi         * @param newPositionMs the new requested position in the current media, expressed in ms.
747bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi         */
748bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi        void onPlaybackPositionUpdate(long newPositionMs);
749bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi    }
750bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi
751bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi    /**
7523261b537c5fdec824575a1f6ad6d8942715e82e2Jean-Michel Trivi     * Interface definition for a callback to be invoked when the media playback position is
7533261b537c5fdec824575a1f6ad6d8942715e82e2Jean-Michel Trivi     * queried.
7543261b537c5fdec824575a1f6ad6d8942715e82e2Jean-Michel Trivi     * @see RemoteControlClient#FLAG_KEY_MEDIA_POSITION_UPDATE
7553261b537c5fdec824575a1f6ad6d8942715e82e2Jean-Michel Trivi     */
756915747730060dff71b5b2ca7e4ee4073024fc24eJean-Michel Trivi    public interface OnGetPlaybackPositionListener {
7573261b537c5fdec824575a1f6ad6d8942715e82e2Jean-Michel Trivi        /**
7583261b537c5fdec824575a1f6ad6d8942715e82e2Jean-Michel Trivi         * Called on the implementer of the interface to query the current playback position.
7593261b537c5fdec824575a1f6ad6d8942715e82e2Jean-Michel Trivi         * @return a negative value if the current playback position (or the last valid playback
7603261b537c5fdec824575a1f6ad6d8942715e82e2Jean-Michel Trivi         *     position) is not known, or a zero or positive value expressed in ms indicating the
7613261b537c5fdec824575a1f6ad6d8942715e82e2Jean-Michel Trivi         *     current position, or the last valid known position.
7623261b537c5fdec824575a1f6ad6d8942715e82e2Jean-Michel Trivi         */
763915747730060dff71b5b2ca7e4ee4073024fc24eJean-Michel Trivi        long onGetPlaybackPosition();
7643261b537c5fdec824575a1f6ad6d8942715e82e2Jean-Michel Trivi    }
7653261b537c5fdec824575a1f6ad6d8942715e82e2Jean-Michel Trivi
7663261b537c5fdec824575a1f6ad6d8942715e82e2Jean-Michel Trivi    /**
7673261b537c5fdec824575a1f6ad6d8942715e82e2Jean-Michel Trivi     * Sets the listener to be called whenever the media playback position is requested
768bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi     * to be updated.
769bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi     * Notifications will be received in the same thread as the one in which RemoteControlClient
770bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi     * was created.
771915747730060dff71b5b2ca7e4ee4073024fc24eJean-Michel Trivi     * @param l the position update listener to be called
772bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi     */
773bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi    public void setPlaybackPositionUpdateListener(OnPlaybackPositionUpdateListener l) {
774bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi        synchronized(mCacheLock) {
7753261b537c5fdec824575a1f6ad6d8942715e82e2Jean-Michel Trivi            int oldCapa = mPlaybackPositionCapabilities;
7763261b537c5fdec824575a1f6ad6d8942715e82e2Jean-Michel Trivi            if (l != null) {
777bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi                mPlaybackPositionCapabilities |= MEDIA_POSITION_WRITABLE;
7783261b537c5fdec824575a1f6ad6d8942715e82e2Jean-Michel Trivi            } else {
779bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi                mPlaybackPositionCapabilities &= ~MEDIA_POSITION_WRITABLE;
780bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi            }
781bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi            mPositionUpdateListener = l;
7823261b537c5fdec824575a1f6ad6d8942715e82e2Jean-Michel Trivi            if (oldCapa != mPlaybackPositionCapabilities) {
7833261b537c5fdec824575a1f6ad6d8942715e82e2Jean-Michel Trivi                // tell RCDs that this RCC's playback position capabilities have changed
7843261b537c5fdec824575a1f6ad6d8942715e82e2Jean-Michel Trivi                sendTransportControlInfo_syncCacheLock();
7853261b537c5fdec824575a1f6ad6d8942715e82e2Jean-Michel Trivi            }
7863261b537c5fdec824575a1f6ad6d8942715e82e2Jean-Michel Trivi        }
7873261b537c5fdec824575a1f6ad6d8942715e82e2Jean-Michel Trivi    }
7883261b537c5fdec824575a1f6ad6d8942715e82e2Jean-Michel Trivi
7893261b537c5fdec824575a1f6ad6d8942715e82e2Jean-Michel Trivi    /**
7903261b537c5fdec824575a1f6ad6d8942715e82e2Jean-Michel Trivi     * Sets the listener to be called whenever the media current playback position is needed.
7913261b537c5fdec824575a1f6ad6d8942715e82e2Jean-Michel Trivi     * Queries will be received in the same thread as the one in which RemoteControlClient
7923261b537c5fdec824575a1f6ad6d8942715e82e2Jean-Michel Trivi     * was created.
793915747730060dff71b5b2ca7e4ee4073024fc24eJean-Michel Trivi     * @param l the listener to be called to retrieve the playback position
7943261b537c5fdec824575a1f6ad6d8942715e82e2Jean-Michel Trivi     */
795915747730060dff71b5b2ca7e4ee4073024fc24eJean-Michel Trivi    public void setOnGetPlaybackPositionListener(OnGetPlaybackPositionListener l) {
7963261b537c5fdec824575a1f6ad6d8942715e82e2Jean-Michel Trivi        synchronized(mCacheLock) {
7973261b537c5fdec824575a1f6ad6d8942715e82e2Jean-Michel Trivi            int oldCapa = mPlaybackPositionCapabilities;
7983261b537c5fdec824575a1f6ad6d8942715e82e2Jean-Michel Trivi            if (l != null) {
7993261b537c5fdec824575a1f6ad6d8942715e82e2Jean-Michel Trivi                mPlaybackPositionCapabilities |= MEDIA_POSITION_READABLE;
8003261b537c5fdec824575a1f6ad6d8942715e82e2Jean-Michel Trivi            } else {
8013261b537c5fdec824575a1f6ad6d8942715e82e2Jean-Michel Trivi                mPlaybackPositionCapabilities &= ~MEDIA_POSITION_READABLE;
8023261b537c5fdec824575a1f6ad6d8942715e82e2Jean-Michel Trivi            }
8033261b537c5fdec824575a1f6ad6d8942715e82e2Jean-Michel Trivi            mPositionProvider = l;
8043261b537c5fdec824575a1f6ad6d8942715e82e2Jean-Michel Trivi            if (oldCapa != mPlaybackPositionCapabilities) {
8053261b537c5fdec824575a1f6ad6d8942715e82e2Jean-Michel Trivi                // tell RCDs that this RCC's playback position capabilities have changed
8063261b537c5fdec824575a1f6ad6d8942715e82e2Jean-Michel Trivi                sendTransportControlInfo_syncCacheLock();
8073261b537c5fdec824575a1f6ad6d8942715e82e2Jean-Michel Trivi            }
808521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi            if ((mPositionProvider != null) && (mEventHandler != null)
809521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi                    && playbackPositionShouldMove(mPlaybackState)) {
810521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi                // playback position is already moving, but now we have a position provider,
811521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi                // so schedule a drift check right now
812521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi                mEventHandler.sendMessageDelayed(
813521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi                        mEventHandler.obtainMessage(MSG_POSITION_DRIFT_CHECK),
814521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi                        0 /*check now*/);
815521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi            }
816bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi        }
817bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi    }
818bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi
819bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi    /**
820bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi     * @hide
821bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi     * Flag to reflect that the application controlling this RemoteControlClient sends playback
822bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi     * position updates. The playback position being "readable" is considered from the application's
823bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi     * point of view.
824bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi     */
825bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi    public static int MEDIA_POSITION_READABLE = 1 << 0;
826bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi    /**
827bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi     * @hide
828bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi     * Flag to reflect that the application controlling this RemoteControlClient can receive
829bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi     * playback position updates. The playback position being "writable"
830bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi     * is considered from the application's point of view.
831bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi     */
832bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi    public static int MEDIA_POSITION_WRITABLE = 1 << 1;
833bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi
834bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi    private int mPlaybackPositionCapabilities = 0;
835bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi
8363114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    /** @hide */
8373114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    public final static int DEFAULT_PLAYBACK_VOLUME_HANDLING = PLAYBACK_VOLUME_VARIABLE;
8383114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    /** @hide */
8393114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    // hard-coded to the same number of steps as AudioService.MAX_STREAM_VOLUME[STREAM_MUSIC]
8403114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    public final static int DEFAULT_PLAYBACK_VOLUME = 15;
8413114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi
8423114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    private int mPlaybackType = PLAYBACK_TYPE_LOCAL;
8433114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    private int mPlaybackVolumeMax = DEFAULT_PLAYBACK_VOLUME;
8443114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    private int mPlaybackVolume = DEFAULT_PLAYBACK_VOLUME;
8453114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    private int mPlaybackVolumeHandling = DEFAULT_PLAYBACK_VOLUME_HANDLING;
8463114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    private int mPlaybackStream = AudioManager.STREAM_MUSIC;
8473114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi
8483114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    /**
8491357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi     * @hide
8503114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     * Set information describing information related to the playback of media so the system
8513114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     * can implement additional behavior to handle non-local playback usecases.
8523114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     * @param what a key to specify the type of information to set. Valid keys are
8533114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     *        {@link #PLAYBACKINFO_PLAYBACK_TYPE},
8543114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     *        {@link #PLAYBACKINFO_USES_STREAM},
8553114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     *        {@link #PLAYBACKINFO_VOLUME},
8563114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     *        {@link #PLAYBACKINFO_VOLUME_MAX},
8573114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     *        and {@link #PLAYBACKINFO_VOLUME_HANDLING}.
8583114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     * @param value the value for the supplied information to set.
8593114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     */
8603114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    public void setPlaybackInformation(int what, int value) {
8613114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        synchronized(mCacheLock) {
8623114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi            switch (what) {
8633114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                case PLAYBACKINFO_PLAYBACK_TYPE:
8643114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                    if ((value >= PLAYBACK_TYPE_MIN) && (value <= PLAYBACK_TYPE_MAX)) {
8653114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                        if (mPlaybackType != value) {
8663114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                            mPlaybackType = value;
8673114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                            sendAudioServiceNewPlaybackInfo_syncCacheLock(what, value);
8683114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                        }
8693114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                    } else {
8703114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                        Log.w(TAG, "using invalid value for PLAYBACKINFO_PLAYBACK_TYPE");
8713114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                    }
8723114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                    break;
8733114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                case PLAYBACKINFO_VOLUME:
8743114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                    if ((value > -1) && (value <= mPlaybackVolumeMax)) {
8753114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                        if (mPlaybackVolume != value) {
8763114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                            mPlaybackVolume = value;
8773114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                            sendAudioServiceNewPlaybackInfo_syncCacheLock(what, value);
8783114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                        }
8793114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                    } else {
8803114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                        Log.w(TAG, "using invalid value for PLAYBACKINFO_VOLUME");
8813114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                    }
8823114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                    break;
8833114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                case PLAYBACKINFO_VOLUME_MAX:
8843114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                    if (value > 0) {
8853114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                        if (mPlaybackVolumeMax != value) {
8863114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                            mPlaybackVolumeMax = value;
8873114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                            sendAudioServiceNewPlaybackInfo_syncCacheLock(what, value);
8883114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                        }
8893114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                    } else {
8903114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                        Log.w(TAG, "using invalid value for PLAYBACKINFO_VOLUME_MAX");
8913114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                    }
8923114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                    break;
8933114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                case PLAYBACKINFO_USES_STREAM:
8943114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                    if ((value >= 0) && (value < AudioSystem.getNumStreamTypes())) {
8953114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                        mPlaybackStream = value;
8963114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                    } else {
8973114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                        Log.w(TAG, "using invalid value for PLAYBACKINFO_USES_STREAM");
8983114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                    }
8993114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                    break;
9003114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                case PLAYBACKINFO_VOLUME_HANDLING:
9013114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                    if ((value >= PLAYBACK_VOLUME_FIXED) && (value <= PLAYBACK_VOLUME_VARIABLE)) {
9023114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                        if (mPlaybackVolumeHandling != value) {
9033114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                            mPlaybackVolumeHandling = value;
9043114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                            sendAudioServiceNewPlaybackInfo_syncCacheLock(what, value);
9053114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                        }
9063114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                    } else {
9073114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                        Log.w(TAG, "using invalid value for PLAYBACKINFO_VOLUME_HANDLING");
9083114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                    }
9093114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                    break;
9103114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                default:
9113114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                    // not throwing an exception or returning an error if more keys are to be
9123114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                    // supported in the future
9133114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                    Log.w(TAG, "setPlaybackInformation() ignoring unknown key " + what);
9143114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                    break;
9153114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi            }
9163114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        }
9173114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    }
9183114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi
9193114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    /**
9201357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi     * @hide
9213114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     * Return playback information represented as an integer value.
9223114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     * @param what a key to specify the type of information to retrieve. Valid keys are
9233114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     *        {@link #PLAYBACKINFO_PLAYBACK_TYPE},
9243114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     *        {@link #PLAYBACKINFO_USES_STREAM},
9253114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     *        {@link #PLAYBACKINFO_VOLUME},
9263114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     *        {@link #PLAYBACKINFO_VOLUME_MAX},
9273114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     *        and {@link #PLAYBACKINFO_VOLUME_HANDLING}.
9283114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     * @return the current value for the given information type, or
9293114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     *   {@link #PLAYBACKINFO_INVALID_VALUE} if an error occurred or the request is invalid, or
9303114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     *   the value is unknown.
9313114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     */
9323114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    public int getIntPlaybackInformation(int what) {
9333114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        synchronized(mCacheLock) {
9343114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi            switch (what) {
9353114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                case PLAYBACKINFO_PLAYBACK_TYPE:
9363114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                    return mPlaybackType;
9373114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                case PLAYBACKINFO_VOLUME:
9383114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                    return mPlaybackVolume;
9393114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                case PLAYBACKINFO_VOLUME_MAX:
9403114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                    return mPlaybackVolumeMax;
9413114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                case PLAYBACKINFO_USES_STREAM:
9423114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                    return mPlaybackStream;
9433114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                case PLAYBACKINFO_VOLUME_HANDLING:
9443114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                    return mPlaybackVolumeHandling;
9453114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                default:
9463114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                    Log.e(TAG, "getIntPlaybackInformation() unknown key " + what);
9473114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                    return PLAYBACKINFO_INVALID_VALUE;
9483114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi            }
9493114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        }
9503114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    }
9513114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi
952178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi    /**
9534426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     * Lock for all cached data
9544426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     */
9554426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    private final Object mCacheLock = new Object();
9564426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    /**
9574426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     * Cache for the playback state.
9584426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     * Access synchronized on mCacheLock
959178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     */
9604426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    private int mPlaybackState = PLAYSTATE_NONE;
9614426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    /**
96268622396b62f9084781add1e12f4d513b633ab54Jean-Michel Trivi     * Time of last play state change
96368622396b62f9084781add1e12f4d513b633ab54Jean-Michel Trivi     * Access synchronized on mCacheLock
96468622396b62f9084781add1e12f4d513b633ab54Jean-Michel Trivi     */
96568622396b62f9084781add1e12f4d513b633ab54Jean-Michel Trivi    private long mPlaybackStateChangeTimeMs = 0;
96668622396b62f9084781add1e12f4d513b633ab54Jean-Michel Trivi    /**
967bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi     * Last playback position in ms reported by the user
968bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi     */
969bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi    private long mPlaybackPositionMs = PLAYBACK_POSITION_INVALID;
970bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi    /**
971bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi     * Last playback speed reported by the user
972bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi     */
973bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi    private float mPlaybackSpeed = PLAYBACK_SPEED_1X;
974bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi    /**
9754426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     * Cache for the artwork bitmap.
9764426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     * Access synchronized on mCacheLock
9774da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi     * Artwork and metadata are not kept in one Bundle because the bitmap sometimes needs to be
9784da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi     * accessed to be resized, in which case a copy will be made. This would add overhead in
9794da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi     * Bundle operations.
9804426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     */
9814a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi    private Bitmap mOriginalArtwork;
9824426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    /**
9834426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     * Cache for the transport control mask.
9844426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     * Access synchronized on mCacheLock
9854426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     */
9864426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    private int mTransportControlFlags = FLAGS_KEY_MEDIA_NONE;
9874426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    /**
9884426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     * Cache for the metadata strings.
9894426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     * Access synchronized on mCacheLock
99030c918ce7fbe171944b28fc91b3f22b3d631872dGlenn Kasten     * This is re-initialized in apply() and so cannot be final.
9914426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     */
9924426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    private Bundle mMetadata = new Bundle();
9934426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    /**
994bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi     * Listener registered by user of RemoteControlClient to receive requests for playback position
995bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi     * update requests.
996bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi     */
997bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi    private OnPlaybackPositionUpdateListener mPositionUpdateListener;
998bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi    /**
9993261b537c5fdec824575a1f6ad6d8942715e82e2Jean-Michel Trivi     * Provider registered by user of RemoteControlClient to provide the current playback position.
10003261b537c5fdec824575a1f6ad6d8942715e82e2Jean-Michel Trivi     */
1001915747730060dff71b5b2ca7e4ee4073024fc24eJean-Michel Trivi    private OnGetPlaybackPositionListener mPositionProvider;
10023261b537c5fdec824575a1f6ad6d8942715e82e2Jean-Michel Trivi    /**
1003bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi     * The current remote control client generation ID across the system, as known by this object
10044426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     */
10054426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    private int mCurrentClientGenId = -1;
10064426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    /**
10074426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     * The remote control client generation ID, the last time it was told it was the current RC.
10084426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     * If (mCurrentClientGenId == mInternalClientGenId) is true, it means that this remote control
10094426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     * client is the "focused" one, and that whenever this client's info is updated, it needs to
10104426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     * send it to the known IRemoteControlDisplay interfaces.
10114426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     */
10124426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    private int mInternalClientGenId = -2;
10134426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi
10144426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    /**
1015f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi     * The media button intent description associated with this remote control client
1016bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi     * (can / should include target component for intent handling, used when persisting media
1017bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi     *    button event receiver across reboots).
10184426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     */
1019f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi    private final PendingIntent mRcMediaIntent;
10204426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi
10214426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    /**
1022c3c4babf8424f65b3d3d2700f60fae6e94e9cd00Jean-Michel Trivi     * Reflects whether any "plugged in" IRemoteControlDisplay has mWantsPositonSync set to true.
1023c3c4babf8424f65b3d3d2700f60fae6e94e9cd00Jean-Michel Trivi     */
1024c3c4babf8424f65b3d3d2700f60fae6e94e9cd00Jean-Michel Trivi    // TODO consider using a ref count for IRemoteControlDisplay requiring sync instead
1025c3c4babf8424f65b3d3d2700f60fae6e94e9cd00Jean-Michel Trivi    private boolean mNeedsPositionSync = false;
1026c3c4babf8424f65b3d3d2700f60fae6e94e9cd00Jean-Michel Trivi
1027c3c4babf8424f65b3d3d2700f60fae6e94e9cd00Jean-Michel Trivi    /**
10284a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi     * A class to encapsulate all the information about a remote control display.
10294a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi     * A RemoteControlClient's metadata and state may be displayed on multiple IRemoteControlDisplay
10304a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi     */
10314a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi    private class DisplayInfoForClient {
10324a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi        /** may never be null */
10334a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi        private IRemoteControlDisplay mRcDisplay;
10344a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi        private int mArtworkExpectedWidth;
10354a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi        private int mArtworkExpectedHeight;
1036c3c4babf8424f65b3d3d2700f60fae6e94e9cd00Jean-Michel Trivi        private boolean mWantsPositionSync = false;
10374a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi
10384a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi        DisplayInfoForClient(IRemoteControlDisplay rcd, int w, int h) {
10394a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi            mRcDisplay = rcd;
10404a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi            mArtworkExpectedWidth = w;
10414a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi            mArtworkExpectedHeight = h;
10424a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi        }
10434a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi    }
10444a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi
10454a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi    /**
10464a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi     * The list of remote control displays to which this client will send information.
10474a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi     * Accessed and modified synchronized on mCacheLock
10484426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     */
10494a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi    private ArrayList<DisplayInfoForClient> mRcDisplays = new ArrayList<DisplayInfoForClient>(1);
10504426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi
10514426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    /**
10524426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     * @hide
1053f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi     * Accessor to media button intent description (includes target component)
10544426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     */
1055f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi    public PendingIntent getRcMediaIntent() {
1056f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi        return mRcMediaIntent;
10574426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    }
10584426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    /**
10594426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     * @hide
10604426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     * Accessor to IRemoteControlClient
10614426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     */
10624426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    public IRemoteControlClient getIRemoteControlClient() {
10634426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi        return mIRCC;
10644426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    }
10654426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi
10664426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    /**
10674426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     * The IRemoteControlClient implementation
10684426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     */
106930c918ce7fbe171944b28fc91b3f22b3d631872dGlenn Kasten    private final IRemoteControlClient mIRCC = new IRemoteControlClient.Stub() {
10704426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi
10713261b537c5fdec824575a1f6ad6d8942715e82e2Jean-Michel Trivi        public void onInformationRequested(int generationId, int infoFlags) {
10724426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi            // only post messages, we can't block here
10734426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi            if (mEventHandler != null) {
10744426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi                // signal new client
10754426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi                mEventHandler.removeMessages(MSG_NEW_INTERNAL_CLIENT_GEN);
107605e7c2ff8cd6b6386d8c553995c2d12075833e4aJean-Michel Trivi                mEventHandler.sendMessage(
10774a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi                        mEventHandler.obtainMessage(MSG_NEW_INTERNAL_CLIENT_GEN,
10783261b537c5fdec824575a1f6ad6d8942715e82e2Jean-Michel Trivi                                /*arg1*/ generationId, /*arg2, ignored*/ 0));
10794426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi                // send the information
10804426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi                mEventHandler.removeMessages(MSG_REQUEST_PLAYBACK_STATE);
10814426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi                mEventHandler.removeMessages(MSG_REQUEST_METADATA);
10824426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi                mEventHandler.removeMessages(MSG_REQUEST_TRANSPORTCONTROL);
10834426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi                mEventHandler.removeMessages(MSG_REQUEST_ARTWORK);
108405e7c2ff8cd6b6386d8c553995c2d12075833e4aJean-Michel Trivi                mEventHandler.sendMessage(
10854426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi                        mEventHandler.obtainMessage(MSG_REQUEST_PLAYBACK_STATE));
108605e7c2ff8cd6b6386d8c553995c2d12075833e4aJean-Michel Trivi                mEventHandler.sendMessage(
10874426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi                        mEventHandler.obtainMessage(MSG_REQUEST_TRANSPORTCONTROL));
108805e7c2ff8cd6b6386d8c553995c2d12075833e4aJean-Michel Trivi                mEventHandler.sendMessage(mEventHandler.obtainMessage(MSG_REQUEST_METADATA));
108905e7c2ff8cd6b6386d8c553995c2d12075833e4aJean-Michel Trivi                mEventHandler.sendMessage(mEventHandler.obtainMessage(MSG_REQUEST_ARTWORK));
10904426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi            }
10914426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi        }
10924426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi
10934426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi        public void setCurrentClientGenerationId(int clientGeneration) {
10944426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi            // only post messages, we can't block here
10954426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi            if (mEventHandler != null) {
10964426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi                mEventHandler.removeMessages(MSG_NEW_CURRENT_CLIENT_GEN);
109705e7c2ff8cd6b6386d8c553995c2d12075833e4aJean-Michel Trivi                mEventHandler.sendMessage(mEventHandler.obtainMessage(
10984426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi                        MSG_NEW_CURRENT_CLIENT_GEN, clientGeneration, 0/*ignored*/));
10994426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi            }
11004426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi        }
11014426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi
11024a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi        public void plugRemoteControlDisplay(IRemoteControlDisplay rcd, int w, int h) {
11034426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi            // only post messages, we can't block here
11044a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi            if ((mEventHandler != null) && (rcd != null)) {
110505e7c2ff8cd6b6386d8c553995c2d12075833e4aJean-Michel Trivi                mEventHandler.sendMessage(mEventHandler.obtainMessage(
11064a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi                        MSG_PLUG_DISPLAY, w, h, rcd));
11074426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi            }
11084426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi        }
11094426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi
11104426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi        public void unplugRemoteControlDisplay(IRemoteControlDisplay rcd) {
11114426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi            // only post messages, we can't block here
11124a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi            if ((mEventHandler != null) && (rcd != null)) {
111305e7c2ff8cd6b6386d8c553995c2d12075833e4aJean-Michel Trivi                mEventHandler.sendMessage(mEventHandler.obtainMessage(
11144426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi                        MSG_UNPLUG_DISPLAY, rcd));
11154426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi            }
11164426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi        }
11174a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi
11184a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi        public void setBitmapSizeForDisplay(IRemoteControlDisplay rcd, int w, int h) {
11194a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi            // only post messages, we can't block here
11204a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi            if ((mEventHandler != null) && (rcd != null)) {
112105e7c2ff8cd6b6386d8c553995c2d12075833e4aJean-Michel Trivi                mEventHandler.sendMessage(mEventHandler.obtainMessage(
11224a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi                        MSG_UPDATE_DISPLAY_ARTWORK_SIZE, w, h, rcd));
11234a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi            }
11244a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi        }
11253261b537c5fdec824575a1f6ad6d8942715e82e2Jean-Michel Trivi
1126c3c4babf8424f65b3d3d2700f60fae6e94e9cd00Jean-Michel Trivi        public void setWantsSyncForDisplay(IRemoteControlDisplay rcd, boolean wantsSync) {
1127c3c4babf8424f65b3d3d2700f60fae6e94e9cd00Jean-Michel Trivi            // only post messages, we can't block here
1128c3c4babf8424f65b3d3d2700f60fae6e94e9cd00Jean-Michel Trivi            if ((mEventHandler != null) && (rcd != null)) {
1129c3c4babf8424f65b3d3d2700f60fae6e94e9cd00Jean-Michel Trivi                mEventHandler.sendMessage(mEventHandler.obtainMessage(
1130c3c4babf8424f65b3d3d2700f60fae6e94e9cd00Jean-Michel Trivi                        MSG_DISPLAY_WANTS_POS_SYNC, wantsSync ? 1 : 0, 0/*arg2 ignored*/, rcd));
1131c3c4babf8424f65b3d3d2700f60fae6e94e9cd00Jean-Michel Trivi            }
1132c3c4babf8424f65b3d3d2700f60fae6e94e9cd00Jean-Michel Trivi        }
1133c3c4babf8424f65b3d3d2700f60fae6e94e9cd00Jean-Michel Trivi
11343261b537c5fdec824575a1f6ad6d8942715e82e2Jean-Michel Trivi        public void seekTo(int generationId, long timeMs) {
11353261b537c5fdec824575a1f6ad6d8942715e82e2Jean-Michel Trivi            // only post messages, we can't block here
11363261b537c5fdec824575a1f6ad6d8942715e82e2Jean-Michel Trivi            if (mEventHandler != null) {
11373261b537c5fdec824575a1f6ad6d8942715e82e2Jean-Michel Trivi                mEventHandler.removeMessages(MSG_SEEK_TO);
113805e7c2ff8cd6b6386d8c553995c2d12075833e4aJean-Michel Trivi                mEventHandler.sendMessage(mEventHandler.obtainMessage(
11393261b537c5fdec824575a1f6ad6d8942715e82e2Jean-Michel Trivi                        MSG_SEEK_TO, generationId /* arg1 */, 0 /* arg2, ignored */,
11403261b537c5fdec824575a1f6ad6d8942715e82e2Jean-Michel Trivi                        new Long(timeMs)));
11413261b537c5fdec824575a1f6ad6d8942715e82e2Jean-Michel Trivi            }
11423261b537c5fdec824575a1f6ad6d8942715e82e2Jean-Michel Trivi        }
11434426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    };
11444426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi
11453114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    /**
11463114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     * @hide
11473114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     * Default value for the unique identifier
11483114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     */
11493114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    public final static int RCSE_ID_UNREGISTERED = -1;
11503114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    /**
11513114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     * Unique identifier of the RemoteControlStackEntry in AudioService with which
11523114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     * this RemoteControlClient is associated.
11533114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     */
11543114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    private int mRcseId = RCSE_ID_UNREGISTERED;
11553114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    /**
11563114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     * @hide
11573114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     * To be only used by AudioManager after it has received the unique id from
11583114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     * IAudioService.registerRemoteControlClient()
11593114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     * @param id the unique identifier of the RemoteControlStackEntry in AudioService with which
11603114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     *              this RemoteControlClient is associated.
11613114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     */
11623114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    public void setRcseId(int id) {
11633114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        mRcseId = id;
11643114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    }
11653114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi
11661357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi    /**
11671357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi     * @hide
11681357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi     */
11691357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi    public int getRcseId() {
11701357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi        return mRcseId;
11711357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi    }
11721357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi
11734426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    private EventHandler mEventHandler;
11744426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    private final static int MSG_REQUEST_PLAYBACK_STATE = 1;
11754426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    private final static int MSG_REQUEST_METADATA = 2;
11764426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    private final static int MSG_REQUEST_TRANSPORTCONTROL = 3;
11774426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    private final static int MSG_REQUEST_ARTWORK = 4;
11784426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    private final static int MSG_NEW_INTERNAL_CLIENT_GEN = 5;
11794426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    private final static int MSG_NEW_CURRENT_CLIENT_GEN = 6;
11804426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    private final static int MSG_PLUG_DISPLAY = 7;
11814426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    private final static int MSG_UNPLUG_DISPLAY = 8;
11824a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi    private final static int MSG_UPDATE_DISPLAY_ARTWORK_SIZE = 9;
11833261b537c5fdec824575a1f6ad6d8942715e82e2Jean-Michel Trivi    private final static int MSG_SEEK_TO = 10;
1184521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi    private final static int MSG_POSITION_DRIFT_CHECK = 11;
1185c3c4babf8424f65b3d3d2700f60fae6e94e9cd00Jean-Michel Trivi    private final static int MSG_DISPLAY_WANTS_POS_SYNC = 12;
11864426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi
11874426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    private class EventHandler extends Handler {
11884426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi        public EventHandler(RemoteControlClient rcc, Looper looper) {
11894426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi            super(looper);
11904426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi        }
11914426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi
11924426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi        @Override
11934426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi        public void handleMessage(Message msg) {
11944426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi            switch(msg.what) {
11954426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi                case MSG_REQUEST_PLAYBACK_STATE:
11964426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi                    synchronized (mCacheLock) {
11974426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi                        sendPlaybackState_syncCacheLock();
11984426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi                    }
11994426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi                    break;
12004426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi                case MSG_REQUEST_METADATA:
12014426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi                    synchronized (mCacheLock) {
12024426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi                        sendMetadata_syncCacheLock();
12034426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi                    }
12044426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi                    break;
12054426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi                case MSG_REQUEST_TRANSPORTCONTROL:
12064426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi                    synchronized (mCacheLock) {
12073261b537c5fdec824575a1f6ad6d8942715e82e2Jean-Michel Trivi                        sendTransportControlInfo_syncCacheLock();
12084426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi                    }
12094426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi                    break;
12104426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi                case MSG_REQUEST_ARTWORK:
12114426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi                    synchronized (mCacheLock) {
12124426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi                        sendArtwork_syncCacheLock();
12134426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi                    }
12144426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi                    break;
12154426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi                case MSG_NEW_INTERNAL_CLIENT_GEN:
12164a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi                    onNewInternalClientGen(msg.arg1);
12174426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi                    break;
12184426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi                case MSG_NEW_CURRENT_CLIENT_GEN:
12194426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi                    onNewCurrentClientGen(msg.arg1);
12204426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi                    break;
12214426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi                case MSG_PLUG_DISPLAY:
12224a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi                    onPlugDisplay((IRemoteControlDisplay)msg.obj, msg.arg1, msg.arg2);
12234426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi                    break;
12244426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi                case MSG_UNPLUG_DISPLAY:
12254426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi                    onUnplugDisplay((IRemoteControlDisplay)msg.obj);
12264426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi                    break;
12274a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi                case MSG_UPDATE_DISPLAY_ARTWORK_SIZE:
12284a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi                    onUpdateDisplayArtworkSize((IRemoteControlDisplay)msg.obj, msg.arg1, msg.arg2);
12294a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi                    break;
12303261b537c5fdec824575a1f6ad6d8942715e82e2Jean-Michel Trivi                case MSG_SEEK_TO:
12313261b537c5fdec824575a1f6ad6d8942715e82e2Jean-Michel Trivi                    onSeekTo(msg.arg1, ((Long)msg.obj).longValue());
123205e7c2ff8cd6b6386d8c553995c2d12075833e4aJean-Michel Trivi                    break;
1233521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi                case MSG_POSITION_DRIFT_CHECK:
1234521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi                    onPositionDriftCheck();
1235521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi                    break;
1236c3c4babf8424f65b3d3d2700f60fae6e94e9cd00Jean-Michel Trivi                case MSG_DISPLAY_WANTS_POS_SYNC:
1237c3c4babf8424f65b3d3d2700f60fae6e94e9cd00Jean-Michel Trivi                    onDisplayWantsSync((IRemoteControlDisplay)msg.obj, msg.arg1 == 1);
1238c3c4babf8424f65b3d3d2700f60fae6e94e9cd00Jean-Michel Trivi                    break;
12394426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi                default:
12404426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi                    Log.e(TAG, "Unknown event " + msg.what + " in RemoteControlClient handler");
12414426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi            }
12424426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi        }
12434426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    }
12444426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi
12453114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    //===========================================================
12464a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi    // Communication with the IRemoteControlDisplay (the displays known to the system)
124744413e5b514a91806a4bb4c7780029ea43be6f81Jean-Michel Trivi
12484426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    private void sendPlaybackState_syncCacheLock() {
12494a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi        if (mCurrentClientGenId == mInternalClientGenId) {
12504a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi            final Iterator<DisplayInfoForClient> displayIterator = mRcDisplays.iterator();
12514a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi            while (displayIterator.hasNext()) {
12524a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi                final DisplayInfoForClient di = (DisplayInfoForClient) displayIterator.next();
12534a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi                try {
12544a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi                    di.mRcDisplay.setPlaybackState(mInternalClientGenId,
1255bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi                            mPlaybackState, mPlaybackStateChangeTimeMs, mPlaybackPositionMs,
1256bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi                            mPlaybackSpeed);
12574a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi                } catch (RemoteException e) {
12584a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi                    Log.e(TAG, "Error in setPlaybackState(), dead display " + di.mRcDisplay, e);
12594a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi                    displayIterator.remove();
12604a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi                }
12614426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi            }
12624426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi        }
12634426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    }
12644426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi
12654426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    private void sendMetadata_syncCacheLock() {
12664a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi        if (mCurrentClientGenId == mInternalClientGenId) {
12674a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi            final Iterator<DisplayInfoForClient> displayIterator = mRcDisplays.iterator();
12684a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi            while (displayIterator.hasNext()) {
12694a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi                final DisplayInfoForClient di = (DisplayInfoForClient) displayIterator.next();
12704a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi                try {
12714a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi                    di.mRcDisplay.setMetadata(mInternalClientGenId, mMetadata);
12724a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi                } catch (RemoteException e) {
12734a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi                    Log.e(TAG, "Error in setMetadata(), dead display " + di.mRcDisplay, e);
12744a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi                    displayIterator.remove();
12754a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi                }
12764426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi            }
12774426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi        }
12784426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    }
12794426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi
12803261b537c5fdec824575a1f6ad6d8942715e82e2Jean-Michel Trivi    private void sendTransportControlInfo_syncCacheLock() {
12814a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi        if (mCurrentClientGenId == mInternalClientGenId) {
12824a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi            final Iterator<DisplayInfoForClient> displayIterator = mRcDisplays.iterator();
12834a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi            while (displayIterator.hasNext()) {
12844a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi                final DisplayInfoForClient di = (DisplayInfoForClient) displayIterator.next();
12854a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi                try {
12863261b537c5fdec824575a1f6ad6d8942715e82e2Jean-Michel Trivi                    di.mRcDisplay.setTransportControlInfo(mInternalClientGenId,
12873261b537c5fdec824575a1f6ad6d8942715e82e2Jean-Michel Trivi                            mTransportControlFlags, mPlaybackPositionCapabilities);
12884a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi                } catch (RemoteException e) {
12894a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi                    Log.e(TAG, "Error in setTransportControlFlags(), dead display " + di.mRcDisplay,
12904a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi                            e);
12914a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi                    displayIterator.remove();
12924a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi                }
12934426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi            }
12944426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi        }
12954426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    }
12964426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi
12974426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    private void sendArtwork_syncCacheLock() {
12984a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi        // FIXME modify to cache all requested sizes?
12994a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi        if (mCurrentClientGenId == mInternalClientGenId) {
13004a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi            final Iterator<DisplayInfoForClient> displayIterator = mRcDisplays.iterator();
13014a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi            while (displayIterator.hasNext()) {
13024a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi                if (!sendArtworkToDisplay((DisplayInfoForClient) displayIterator.next())) {
13034a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi                    displayIterator.remove();
13044a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi                }
13054a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi            }
13064a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi        }
13074a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi    }
13084a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi
13094a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi    /**
13104a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi     * Send artwork to an IRemoteControlDisplay.
13114a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi     * @param di encapsulates the IRemoteControlDisplay that will receive the artwork, and its
13124a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi     *    dimension requirements.
13134a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi     * @return false if there was an error communicating with the IRemoteControlDisplay.
13144a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi     */
13154a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi    private boolean sendArtworkToDisplay(DisplayInfoForClient di) {
13164a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi        if ((di.mArtworkExpectedWidth > 0) && (di.mArtworkExpectedHeight > 0)) {
13174a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi            Bitmap artwork = scaleBitmapIfTooBig(mOriginalArtwork,
13184a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi                    di.mArtworkExpectedWidth, di.mArtworkExpectedHeight);
13194426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi            try {
13204a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi                di.mRcDisplay.setArtwork(mInternalClientGenId, artwork);
13214426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi            } catch (RemoteException e) {
13224a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi                Log.e(TAG, "Error in sendArtworkToDisplay(), dead display " + di.mRcDisplay, e);
13234a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi                return false;
132444413e5b514a91806a4bb4c7780029ea43be6f81Jean-Michel Trivi            }
132544413e5b514a91806a4bb4c7780029ea43be6f81Jean-Michel Trivi        }
13264a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi        return true;
132744413e5b514a91806a4bb4c7780029ea43be6f81Jean-Michel Trivi    }
132844413e5b514a91806a4bb4c7780029ea43be6f81Jean-Michel Trivi
132944413e5b514a91806a4bb4c7780029ea43be6f81Jean-Michel Trivi    private void sendMetadataWithArtwork_syncCacheLock() {
13304a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi        // FIXME modify to cache all requested sizes?
13314a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi        if (mCurrentClientGenId == mInternalClientGenId) {
13324a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi            final Iterator<DisplayInfoForClient> displayIterator = mRcDisplays.iterator();
13334a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi            while (displayIterator.hasNext()) {
13344a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi                final DisplayInfoForClient di = (DisplayInfoForClient) displayIterator.next();
13354a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi                try {
13364a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi                    if ((di.mArtworkExpectedWidth > 0) && (di.mArtworkExpectedHeight > 0)) {
13374a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi                        Bitmap artwork = scaleBitmapIfTooBig(mOriginalArtwork,
13384a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi                                di.mArtworkExpectedWidth, di.mArtworkExpectedHeight);
13394a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi                        di.mRcDisplay.setAllMetadata(mInternalClientGenId, mMetadata, artwork);
13404a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi                    } else {
13414a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi                        di.mRcDisplay.setMetadata(mInternalClientGenId, mMetadata);
13424a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi                    }
13434a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi                } catch (RemoteException e) {
13444a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi                    Log.e(TAG, "Error when setting metadata, dead display " + di.mRcDisplay, e);
13454a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi                    displayIterator.remove();
13464a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi                }
13474426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi            }
13484426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi        }
13494426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    }
13504426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi
13513114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    //===========================================================
13523114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    // Communication with AudioService
13533114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi
13543114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    private static IAudioService sService;
13553114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi
13563114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    private static IAudioService getService()
13573114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    {
13583114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        if (sService != null) {
13593114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi            return sService;
13603114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        }
13613114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        IBinder b = ServiceManager.getService(Context.AUDIO_SERVICE);
13623114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        sService = IAudioService.Stub.asInterface(b);
13633114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        return sService;
13643114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    }
13653114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi
13663114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    private void sendAudioServiceNewPlaybackInfo_syncCacheLock(int what, int value) {
13673114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        if (mRcseId == RCSE_ID_UNREGISTERED) {
13683114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi            return;
13693114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        }
1370f98de1e8dd6dcbd191921b4aa07a1d41b0b9db91Jean-Michel Trivi        //Log.d(TAG, "sending to AudioService key=" + what + ", value=" + value);
13713114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        IAudioService service = getService();
13723114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        try {
13733114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi            service.setPlaybackInfoForRcc(mRcseId, what, value);
13743114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        } catch (RemoteException e) {
1375bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi            Log.e(TAG, "Dead object in setPlaybackInfoForRcc", e);
1376bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi        }
1377bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi    }
1378bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi
1379bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi    private void sendAudioServiceNewPlaybackState_syncCacheLock() {
1380bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi        if (mRcseId == RCSE_ID_UNREGISTERED) {
1381bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi            return;
1382bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi        }
1383bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi        IAudioService service = getService();
1384bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi        try {
1385bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi            service.setPlaybackStateForRcc(mRcseId,
1386bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi                    mPlaybackState, mPlaybackPositionMs, mPlaybackSpeed);
1387bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi        } catch (RemoteException e) {
1388bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi            Log.e(TAG, "Dead object in setPlaybackStateForRcc", e);
13893114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        }
13903114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    }
13913114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi
13923114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    //===========================================================
13933114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    // Message handlers
13943114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi
13954a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi    private void onNewInternalClientGen(int clientGeneration) {
13964426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi        synchronized (mCacheLock) {
13974426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi            // this remote control client is told it is the "focused" one:
13984426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi            // it implies that now (mCurrentClientGenId == mInternalClientGenId) is true
13994a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi            mInternalClientGenId = clientGeneration;
14004426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi        }
14014426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    }
14024426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi
14034426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    private void onNewCurrentClientGen(int clientGeneration) {
14044426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi        synchronized (mCacheLock) {
14054426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi            mCurrentClientGenId = clientGeneration;
14064426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi        }
14074426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    }
14084426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi
14094a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi    /** pre-condition rcd != null */
14104a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi    private void onPlugDisplay(IRemoteControlDisplay rcd, int w, int h) {
14114426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi        synchronized(mCacheLock) {
14124a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi            // do we have this display already?
14134a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi            boolean displayKnown = false;
14144a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi            final Iterator<DisplayInfoForClient> displayIterator = mRcDisplays.iterator();
14154a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi            while (displayIterator.hasNext() && !displayKnown) {
14164a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi                final DisplayInfoForClient di = (DisplayInfoForClient) displayIterator.next();
14174a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi                displayKnown = di.mRcDisplay.asBinder().equals(rcd.asBinder());
14184a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi                if (displayKnown) {
14194a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi                    // this display was known but the change in artwork size will cause the
14204a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi                    // artwork to be refreshed
14214a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi                    if ((di.mArtworkExpectedWidth != w) || (di.mArtworkExpectedHeight != h)) {
14224a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi                        di.mArtworkExpectedWidth = w;
14234a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi                        di.mArtworkExpectedHeight = h;
14244a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi                        if (!sendArtworkToDisplay(di)) {
14254a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi                            displayIterator.remove();
14264a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi                        }
14274a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi                    }
14284a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi                }
14294a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi            }
14304a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi            if (!displayKnown) {
14314a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi                mRcDisplays.add(new DisplayInfoForClient(rcd, w, h));
14324a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi            }
14334426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi        }
14344426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    }
14354426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi
14364a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi    /** pre-condition rcd != null */
14374426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    private void onUnplugDisplay(IRemoteControlDisplay rcd) {
14384426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi        synchronized(mCacheLock) {
1439c3c4babf8424f65b3d3d2700f60fae6e94e9cd00Jean-Michel Trivi            Iterator<DisplayInfoForClient> displayIterator = mRcDisplays.iterator();
14404a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi            while (displayIterator.hasNext()) {
14414a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi                final DisplayInfoForClient di = (DisplayInfoForClient) displayIterator.next();
14424a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi                if (di.mRcDisplay.asBinder().equals(rcd.asBinder())) {
14434a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi                    displayIterator.remove();
1444c3c4babf8424f65b3d3d2700f60fae6e94e9cd00Jean-Michel Trivi                    break;
1445c3c4babf8424f65b3d3d2700f60fae6e94e9cd00Jean-Michel Trivi                }
1446c3c4babf8424f65b3d3d2700f60fae6e94e9cd00Jean-Michel Trivi            }
1447c3c4babf8424f65b3d3d2700f60fae6e94e9cd00Jean-Michel Trivi            // list of RCDs has changed, reevaluate whether position check is still needed
1448c3c4babf8424f65b3d3d2700f60fae6e94e9cd00Jean-Michel Trivi            boolean oldNeedsPositionSync = mNeedsPositionSync;
1449c3c4babf8424f65b3d3d2700f60fae6e94e9cd00Jean-Michel Trivi            boolean newNeedsPositionSync = false;
1450c3c4babf8424f65b3d3d2700f60fae6e94e9cd00Jean-Michel Trivi            displayIterator = mRcDisplays.iterator();
1451c3c4babf8424f65b3d3d2700f60fae6e94e9cd00Jean-Michel Trivi            while (displayIterator.hasNext()) {
1452c3c4babf8424f65b3d3d2700f60fae6e94e9cd00Jean-Michel Trivi                final DisplayInfoForClient di = (DisplayInfoForClient) displayIterator.next();
1453c3c4babf8424f65b3d3d2700f60fae6e94e9cd00Jean-Michel Trivi                if (di.mWantsPositionSync) {
1454c3c4babf8424f65b3d3d2700f60fae6e94e9cd00Jean-Michel Trivi                    newNeedsPositionSync = true;
1455c3c4babf8424f65b3d3d2700f60fae6e94e9cd00Jean-Michel Trivi                    break;
14564a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi                }
14574a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi            }
1458c3c4babf8424f65b3d3d2700f60fae6e94e9cd00Jean-Michel Trivi            mNeedsPositionSync = newNeedsPositionSync;
1459c3c4babf8424f65b3d3d2700f60fae6e94e9cd00Jean-Michel Trivi            if (oldNeedsPositionSync != mNeedsPositionSync) {
1460c3c4babf8424f65b3d3d2700f60fae6e94e9cd00Jean-Michel Trivi                // update needed?
1461c3c4babf8424f65b3d3d2700f60fae6e94e9cd00Jean-Michel Trivi                initiateCheckForDrift_syncCacheLock();
1462c3c4babf8424f65b3d3d2700f60fae6e94e9cd00Jean-Michel Trivi            }
14634a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi        }
14644a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi    }
14654a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi
14664a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi    /** pre-condition rcd != null */
14674a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi    private void onUpdateDisplayArtworkSize(IRemoteControlDisplay rcd, int w, int h) {
14684a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi        synchronized(mCacheLock) {
14694a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi            final Iterator<DisplayInfoForClient> displayIterator = mRcDisplays.iterator();
14704a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi            while (displayIterator.hasNext()) {
14714a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi                final DisplayInfoForClient di = (DisplayInfoForClient) displayIterator.next();
14724a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi                if (di.mRcDisplay.asBinder().equals(rcd.asBinder()) &&
14734a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi                        ((di.mArtworkExpectedWidth != w) || (di.mArtworkExpectedHeight != h))) {
14744a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi                    di.mArtworkExpectedWidth = w;
14754a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi                    di.mArtworkExpectedHeight = h;
14764a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi                    if (!sendArtworkToDisplay(di)) {
14774a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi                        displayIterator.remove();
14784a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi                    }
14794a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi                    break;
14804a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi                }
14814426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi            }
14824426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi        }
14834426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    }
14844426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi
1485c3c4babf8424f65b3d3d2700f60fae6e94e9cd00Jean-Michel Trivi    /** pre-condition rcd != null */
1486c3c4babf8424f65b3d3d2700f60fae6e94e9cd00Jean-Michel Trivi    private void onDisplayWantsSync(IRemoteControlDisplay rcd, boolean wantsSync) {
1487c3c4babf8424f65b3d3d2700f60fae6e94e9cd00Jean-Michel Trivi        synchronized(mCacheLock) {
1488c3c4babf8424f65b3d3d2700f60fae6e94e9cd00Jean-Michel Trivi            boolean oldNeedsPositionSync = mNeedsPositionSync;
1489c3c4babf8424f65b3d3d2700f60fae6e94e9cd00Jean-Michel Trivi            boolean newNeedsPositionSync = false;
1490c3c4babf8424f65b3d3d2700f60fae6e94e9cd00Jean-Michel Trivi            final Iterator<DisplayInfoForClient> displayIterator = mRcDisplays.iterator();
1491c3c4babf8424f65b3d3d2700f60fae6e94e9cd00Jean-Michel Trivi            // go through the list of RCDs and for each entry, check both whether this is the RCD
1492c3c4babf8424f65b3d3d2700f60fae6e94e9cd00Jean-Michel Trivi            //  that gets upated, and whether the list has one entry that wants position sync
1493c3c4babf8424f65b3d3d2700f60fae6e94e9cd00Jean-Michel Trivi            while (displayIterator.hasNext()) {
1494c3c4babf8424f65b3d3d2700f60fae6e94e9cd00Jean-Michel Trivi                final DisplayInfoForClient di = (DisplayInfoForClient) displayIterator.next();
1495c3c4babf8424f65b3d3d2700f60fae6e94e9cd00Jean-Michel Trivi                if (di.mRcDisplay.asBinder().equals(rcd.asBinder())) {
1496c3c4babf8424f65b3d3d2700f60fae6e94e9cd00Jean-Michel Trivi                    di.mWantsPositionSync = wantsSync;
1497c3c4babf8424f65b3d3d2700f60fae6e94e9cd00Jean-Michel Trivi                }
1498c3c4babf8424f65b3d3d2700f60fae6e94e9cd00Jean-Michel Trivi                if (di.mWantsPositionSync) {
1499c3c4babf8424f65b3d3d2700f60fae6e94e9cd00Jean-Michel Trivi                    newNeedsPositionSync = true;
1500c3c4babf8424f65b3d3d2700f60fae6e94e9cd00Jean-Michel Trivi                }
1501c3c4babf8424f65b3d3d2700f60fae6e94e9cd00Jean-Michel Trivi            }
1502c3c4babf8424f65b3d3d2700f60fae6e94e9cd00Jean-Michel Trivi            mNeedsPositionSync = newNeedsPositionSync;
1503c3c4babf8424f65b3d3d2700f60fae6e94e9cd00Jean-Michel Trivi            if (oldNeedsPositionSync != mNeedsPositionSync) {
1504c3c4babf8424f65b3d3d2700f60fae6e94e9cd00Jean-Michel Trivi                // update needed?
1505c3c4babf8424f65b3d3d2700f60fae6e94e9cd00Jean-Michel Trivi                initiateCheckForDrift_syncCacheLock();
1506c3c4babf8424f65b3d3d2700f60fae6e94e9cd00Jean-Michel Trivi            }
1507c3c4babf8424f65b3d3d2700f60fae6e94e9cd00Jean-Michel Trivi        }
1508c3c4babf8424f65b3d3d2700f60fae6e94e9cd00Jean-Michel Trivi    }
1509c3c4babf8424f65b3d3d2700f60fae6e94e9cd00Jean-Michel Trivi
15103261b537c5fdec824575a1f6ad6d8942715e82e2Jean-Michel Trivi    private void onSeekTo(int generationId, long timeMs) {
15113261b537c5fdec824575a1f6ad6d8942715e82e2Jean-Michel Trivi        synchronized (mCacheLock) {
15123261b537c5fdec824575a1f6ad6d8942715e82e2Jean-Michel Trivi            if ((mCurrentClientGenId == generationId) && (mPositionUpdateListener != null)) {
15133261b537c5fdec824575a1f6ad6d8942715e82e2Jean-Michel Trivi                mPositionUpdateListener.onPlaybackPositionUpdate(timeMs);
15143261b537c5fdec824575a1f6ad6d8942715e82e2Jean-Michel Trivi            }
15153261b537c5fdec824575a1f6ad6d8942715e82e2Jean-Michel Trivi        }
15163261b537c5fdec824575a1f6ad6d8942715e82e2Jean-Michel Trivi    }
15173261b537c5fdec824575a1f6ad6d8942715e82e2Jean-Michel Trivi
15183114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    //===========================================================
15193114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    // Internal utilities
15203114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi
15214426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    /**
15224426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     * Scale a bitmap to fit the smallest dimension by uniformly scaling the incoming bitmap.
15234426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     * If the bitmap fits, then do nothing and return the original.
15244426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     *
15254426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     * @param bitmap
15264426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     * @param maxWidth
15274426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     * @param maxHeight
15284426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     * @return
15294426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     */
15304426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi
15314426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    private Bitmap scaleBitmapIfTooBig(Bitmap bitmap, int maxWidth, int maxHeight) {
15326e679d5a53091b348a2cdc0c76f4e8fa4ac52d4bJean-Michel Trivi        if (bitmap != null) {
15336e679d5a53091b348a2cdc0c76f4e8fa4ac52d4bJean-Michel Trivi            final int width = bitmap.getWidth();
15346e679d5a53091b348a2cdc0c76f4e8fa4ac52d4bJean-Michel Trivi            final int height = bitmap.getHeight();
15356e679d5a53091b348a2cdc0c76f4e8fa4ac52d4bJean-Michel Trivi            if (width > maxWidth || height > maxHeight) {
15366e679d5a53091b348a2cdc0c76f4e8fa4ac52d4bJean-Michel Trivi                float scale = Math.min((float) maxWidth / width, (float) maxHeight / height);
15376e679d5a53091b348a2cdc0c76f4e8fa4ac52d4bJean-Michel Trivi                int newWidth = Math.round(scale * width);
15386e679d5a53091b348a2cdc0c76f4e8fa4ac52d4bJean-Michel Trivi                int newHeight = Math.round(scale * height);
153905c66cc5cc6357be19fdef0fc131731368c38646Jack Palevich                Bitmap.Config newConfig = bitmap.getConfig();
154005c66cc5cc6357be19fdef0fc131731368c38646Jack Palevich                if (newConfig == null) {
154105c66cc5cc6357be19fdef0fc131731368c38646Jack Palevich                    newConfig = Bitmap.Config.ARGB_8888;
154205c66cc5cc6357be19fdef0fc131731368c38646Jack Palevich                }
154305c66cc5cc6357be19fdef0fc131731368c38646Jack Palevich                Bitmap outBitmap = Bitmap.createBitmap(newWidth, newHeight, newConfig);
15446e679d5a53091b348a2cdc0c76f4e8fa4ac52d4bJean-Michel Trivi                Canvas canvas = new Canvas(outBitmap);
15456e679d5a53091b348a2cdc0c76f4e8fa4ac52d4bJean-Michel Trivi                Paint paint = new Paint();
15466e679d5a53091b348a2cdc0c76f4e8fa4ac52d4bJean-Michel Trivi                paint.setAntiAlias(true);
15476e679d5a53091b348a2cdc0c76f4e8fa4ac52d4bJean-Michel Trivi                paint.setFilterBitmap(true);
15486e679d5a53091b348a2cdc0c76f4e8fa4ac52d4bJean-Michel Trivi                canvas.drawBitmap(bitmap, null,
15496e679d5a53091b348a2cdc0c76f4e8fa4ac52d4bJean-Michel Trivi                        new RectF(0, 0, outBitmap.getWidth(), outBitmap.getHeight()), paint);
15506e679d5a53091b348a2cdc0c76f4e8fa4ac52d4bJean-Michel Trivi                bitmap = outBitmap;
15516e679d5a53091b348a2cdc0c76f4e8fa4ac52d4bJean-Michel Trivi            }
15524426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi        }
15534426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi        return bitmap;
15545ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Trivi    }
15554426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi
15565ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Trivi    /**
15575ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Trivi     *  Fast routine to go through an array of allowed keys and return whether the key is part
15585ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Trivi     *  of that array
15595ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Trivi     * @param key the key value
15605ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Trivi     * @param validKeys the array of valid keys for a given type
15615ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Trivi     * @return true if the key is part of the array, false otherwise
15625ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Trivi     */
15635ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Trivi    private static boolean validTypeForKey(int key, int[] validKeys) {
15645ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Trivi        try {
15655ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Trivi            for (int i = 0 ; ; i++) {
15665ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Trivi                if (key == validKeys[i]) {
15675ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Trivi                    return true;
15685ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Trivi                }
15695ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Trivi            }
15705ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Trivi        } catch (ArrayIndexOutOfBoundsException e) {
15715ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Trivi            return false;
15725ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Trivi        }
15734426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    }
1574521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi
1575521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi    /**
1576521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi     * Returns whether, for the given playback state, the playback position is expected to
1577521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi     * be changing.
1578521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi     * @param playstate the playback state to evaluate
1579521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi     * @return true during any form of playback, false if it's not playing anything while in this
1580521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi     *     playback state
1581521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi     */
1582521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi    private static boolean playbackPositionShouldMove(int playstate) {
1583521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi        switch(playstate) {
1584521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi            case PLAYSTATE_STOPPED:
1585521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi            case PLAYSTATE_PAUSED:
1586521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi            case PLAYSTATE_BUFFERING:
1587521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi            case PLAYSTATE_ERROR:
1588521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi            case PLAYSTATE_SKIPPING_FORWARDS:
1589521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi            case PLAYSTATE_SKIPPING_BACKWARDS:
1590521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi                return false;
1591521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi            case PLAYSTATE_PLAYING:
1592521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi            case PLAYSTATE_FAST_FORWARDING:
1593521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi            case PLAYSTATE_REWINDING:
1594521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi            default:
1595521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi                return true;
1596521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi        }
1597521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi    }
1598521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi
1599521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi    /**
1600521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi     * Period for playback position drift checks, 15s when playing at 1x or slower.
1601521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi     */
1602521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi    private final static long POSITION_REFRESH_PERIOD_PLAYING_MS = 15000;
1603521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi    /**
1604521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi     * Minimum period for playback position drift checks, never more often when every 2s, when
1605521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi     * fast forwarding or rewinding.
1606521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi     */
1607521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi    private final static long POSITION_REFRESH_PERIOD_MIN_MS = 2000;
1608521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi    /**
1609521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi     * The value above which the difference between client-reported playback position and
1610521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi     * estimated position is considered a drift.
1611521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi     */
1612521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi    private final static long POSITION_DRIFT_MAX_MS = 500;
1613521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi    /**
1614521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi     * Compute the period at which the estimated playback position should be compared against the
1615521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi     * actual playback position. Is a funciton of playback speed.
1616521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi     * @param speed 1.0f is normal playback speed
1617521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi     * @return the period in ms
1618521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi     */
1619521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi    private static long getCheckPeriodFromSpeed(float speed) {
1620521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi        if (Math.abs(speed) <= 1.0f) {
1621521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi            return POSITION_REFRESH_PERIOD_PLAYING_MS;
1622521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi        } else {
1623521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi            return Math.max((long)(POSITION_REFRESH_PERIOD_PLAYING_MS / Math.abs(speed)),
1624521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi                    POSITION_REFRESH_PERIOD_MIN_MS);
1625521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi        }
1626521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi    }
1627178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi}
1628