RemoteControlClient.java revision 5f31737c68f7709cb75a8fefb7536daa77812cc3
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;
27f1372428f2df781c71c71caa2f6a4db6f847cf10RoboErikimport android.media.session.MediaSessionLegacyHelper;
28f1372428f2df781c71c71caa2f6a4db6f847cf10RoboErikimport android.media.session.PlaybackState;
2942ea7eecd149161ed192d3029f0d77d1d08a4aa5RoboErikimport android.media.session.MediaSession;
30f1372428f2df781c71c71caa2f6a4db6f847cf10RoboErikimport android.media.session.TransportPerformer;
314426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Triviimport android.os.Bundle;
324426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Triviimport android.os.Handler;
333114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Triviimport android.os.IBinder;
344426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Triviimport android.os.Looper;
354426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Triviimport android.os.Message;
364426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Triviimport android.os.RemoteException;
373114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Triviimport android.os.ServiceManager;
3868622396b62f9084781add1e12f4d513b633ab54Jean-Michel Triviimport android.os.SystemClock;
394426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Triviimport android.util.Log;
404426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi
415ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Triviimport java.lang.IllegalArgumentException;
424a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Triviimport java.util.ArrayList;
434a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Triviimport java.util.Iterator;
44178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi
45178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi/**
464426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi * RemoteControlClient enables exposing information meant to be consumed by remote controls
47466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi * capable of displaying metadata, artwork and media transport control buttons.
48ad87f5b40f2a3fd2d506dc15e00b8af28a8fa2baJean-Michel Trivi *
49ad87f5b40f2a3fd2d506dc15e00b8af28a8fa2baJean-Michel Trivi * <p>A remote control client object is associated with a media button event receiver. This
50466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi * event receiver must have been previously registered with
51466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi * {@link AudioManager#registerMediaButtonEventReceiver(ComponentName)} before the
52466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi * RemoteControlClient can be registered through
534426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi * {@link AudioManager#registerRemoteControlClient(RemoteControlClient)}.
54ad87f5b40f2a3fd2d506dc15e00b8af28a8fa2baJean-Michel Trivi *
55ad87f5b40f2a3fd2d506dc15e00b8af28a8fa2baJean-Michel Trivi * <p>Here is an example of creating a RemoteControlClient instance after registering a media
56ad87f5b40f2a3fd2d506dc15e00b8af28a8fa2baJean-Michel Trivi * button event receiver:
57ad87f5b40f2a3fd2d506dc15e00b8af28a8fa2baJean-Michel Trivi * <pre>ComponentName myEventReceiver = new ComponentName(getPackageName(), MyRemoteControlEventReceiver.class.getName());
58ad87f5b40f2a3fd2d506dc15e00b8af28a8fa2baJean-Michel Trivi * AudioManager myAudioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
59ad87f5b40f2a3fd2d506dc15e00b8af28a8fa2baJean-Michel Trivi * myAudioManager.registerMediaButtonEventReceiver(myEventReceiver);
60ad87f5b40f2a3fd2d506dc15e00b8af28a8fa2baJean-Michel Trivi * // build the PendingIntent for the remote control client
61ad87f5b40f2a3fd2d506dc15e00b8af28a8fa2baJean-Michel Trivi * Intent mediaButtonIntent = new Intent(Intent.ACTION_MEDIA_BUTTON);
62ad87f5b40f2a3fd2d506dc15e00b8af28a8fa2baJean-Michel Trivi * mediaButtonIntent.setComponent(myEventReceiver);
63ad87f5b40f2a3fd2d506dc15e00b8af28a8fa2baJean-Michel Trivi * PendingIntent mediaPendingIntent = PendingIntent.getBroadcast(getApplicationContext(), 0, mediaButtonIntent, 0);
64ad87f5b40f2a3fd2d506dc15e00b8af28a8fa2baJean-Michel Trivi * // create and register the remote control client
65ad87f5b40f2a3fd2d506dc15e00b8af28a8fa2baJean-Michel Trivi * RemoteControlClient myRemoteControlClient = new RemoteControlClient(mediaPendingIntent);
66ad87f5b40f2a3fd2d506dc15e00b8af28a8fa2baJean-Michel Trivi * myAudioManager.registerRemoteControlClient(myRemoteControlClient);</pre>
67178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi */
684426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivipublic class RemoteControlClient
69178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi{
704426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    private final static String TAG = "RemoteControlClient";
71521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi    private final static boolean DEBUG = false;
724426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi
73178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi    /**
74178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     * Playback state of a RemoteControlClient which is stopped.
75178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     *
764426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     * @see #setPlaybackState(int)
77178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     */
78178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi    public final static int PLAYSTATE_STOPPED            = 1;
79178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi    /**
80178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     * Playback state of a RemoteControlClient which is paused.
81178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     *
824426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     * @see #setPlaybackState(int)
83178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     */
84178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi    public final static int PLAYSTATE_PAUSED             = 2;
85178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi    /**
86178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     * Playback state of a RemoteControlClient which is playing media.
87178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     *
884426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     * @see #setPlaybackState(int)
89178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     */
90178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi    public final static int PLAYSTATE_PLAYING            = 3;
91178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi    /**
92178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     * Playback state of a RemoteControlClient which is fast forwarding in the media
93178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     *    it is currently playing.
94178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     *
954426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     * @see #setPlaybackState(int)
96178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     */
97178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi    public final static int PLAYSTATE_FAST_FORWARDING    = 4;
98178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi    /**
99178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     * Playback state of a RemoteControlClient which is fast rewinding in the media
100178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     *    it is currently playing.
101178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     *
1024426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     * @see #setPlaybackState(int)
103178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     */
104178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi    public final static int PLAYSTATE_REWINDING          = 5;
105178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi    /**
106178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     * Playback state of a RemoteControlClient which is skipping to the next
107178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     *    logical chapter (such as a song in a playlist) in the media it is currently playing.
108178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     *
1094426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     * @see #setPlaybackState(int)
110178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     */
111178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi    public final static int PLAYSTATE_SKIPPING_FORWARDS  = 6;
112178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi    /**
113178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     * Playback state of a RemoteControlClient which is skipping back to the previous
114178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     *    logical chapter (such as a song in a playlist) in the media it is currently playing.
115178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     *
1164426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     * @see #setPlaybackState(int)
117178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     */
118178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi    public final static int PLAYSTATE_SKIPPING_BACKWARDS = 7;
119178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi    /**
120178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     * Playback state of a RemoteControlClient which is buffering data to play before it can
121178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     *    start or resume playback.
122178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     *
1234426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     * @see #setPlaybackState(int)
124178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     */
125178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi    public final static int PLAYSTATE_BUFFERING          = 8;
126178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi    /**
127178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     * Playback state of a RemoteControlClient which cannot perform any playback related
128178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     *    operation because of an internal error. Examples of such situations are no network
129178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     *    connectivity when attempting to stream data from a server, or expired user credentials
130178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     *    when trying to play subscription-based content.
131178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     *
1324426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     * @see #setPlaybackState(int)
133178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     */
134178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi    public final static int PLAYSTATE_ERROR              = 9;
1354426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    /**
1364426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     * @hide
137466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi     * The value of a playback state when none has been declared.
138466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi     * Intentionally hidden as an application shouldn't set such a playback state value.
1394426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     */
1404426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    public final static int PLAYSTATE_NONE               = 0;
141178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi
142178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi    /**
1431357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi     * @hide
1443114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     * The default playback type, "local", indicating the presentation of the media is happening on
1453114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     * the same device (e.g. a phone, a tablet) as where it is controlled from.
1463114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     */
1473114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    public final static int PLAYBACK_TYPE_LOCAL = 0;
1483114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    /**
1491357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi     * @hide
1503114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     * A playback type indicating the presentation of the media is happening on
1513114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     * a different device (i.e. the remote device) than where it is controlled from.
1523114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     */
1533114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    public final static int PLAYBACK_TYPE_REMOTE = 1;
1543114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    private final static int PLAYBACK_TYPE_MIN = PLAYBACK_TYPE_LOCAL;
1553114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    private final static int PLAYBACK_TYPE_MAX = PLAYBACK_TYPE_REMOTE;
1563114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    /**
1571357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi     * @hide
1583114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     * Playback information indicating the playback volume is fixed, i.e. it cannot be controlled
1593114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     * from this object. An example of fixed playback volume is a remote player, playing over HDMI
1603114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     * where the user prefer to control the volume on the HDMI sink, rather than attenuate at the
1613114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     * source.
1623114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     * @see #PLAYBACKINFO_VOLUME_HANDLING.
1633114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     */
1643114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    public final static int PLAYBACK_VOLUME_FIXED = 0;
1653114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    /**
1661357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi     * @hide
1673114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     * Playback information indicating the playback volume is variable and can be controlled from
1683114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     * this object.
1693114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     * @see #PLAYBACKINFO_VOLUME_HANDLING.
1703114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     */
1713114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    public final static int PLAYBACK_VOLUME_VARIABLE = 1;
1723114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    /**
1733114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     * @hide (to be un-hidden)
1743114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     * The playback information value indicating the value of a given information type is invalid.
1753114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     * @see #PLAYBACKINFO_VOLUME_HANDLING.
1763114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     */
1773114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    public final static int PLAYBACKINFO_INVALID_VALUE = Integer.MIN_VALUE;
1783114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi
179bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi    /**
180bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi     * @hide
181bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi     * An unknown or invalid playback position value.
182bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi     */
183bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi    public final static long PLAYBACK_POSITION_INVALID = -1;
184bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi    /**
185bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi     * @hide
1861b16cc3de51d69c8027cefcc70a084a5b2d7a3d0Jean-Michel Trivi     * An invalid playback position value associated with the use of {@link #setPlaybackState(int)}
1871b16cc3de51d69c8027cefcc70a084a5b2d7a3d0Jean-Michel Trivi     * used to indicate that playback position will remain unknown.
1881b16cc3de51d69c8027cefcc70a084a5b2d7a3d0Jean-Michel Trivi     */
1891b16cc3de51d69c8027cefcc70a084a5b2d7a3d0Jean-Michel Trivi    public final static long PLAYBACK_POSITION_ALWAYS_UNKNOWN = 0x8019771980198300L;
1901b16cc3de51d69c8027cefcc70a084a5b2d7a3d0Jean-Michel Trivi    /**
1911b16cc3de51d69c8027cefcc70a084a5b2d7a3d0Jean-Michel Trivi     * @hide
192bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi     * The default playback speed, 1x.
193bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi     */
194bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi    public final static float PLAYBACK_SPEED_1X = 1.0f;
195bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi
1963114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    //==========================================
1973114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    // Public keys for playback information
1983114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    /**
1991357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi     * @hide
2003114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     * Playback information that defines the type of playback associated with this
2013114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     * RemoteControlClient. See {@link #PLAYBACK_TYPE_LOCAL} and {@link #PLAYBACK_TYPE_REMOTE}.
2023114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     */
2033114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    public final static int PLAYBACKINFO_PLAYBACK_TYPE = 1;
2043114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    /**
2051357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi     * @hide
2063114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     * Playback information that defines at what volume the playback associated with this
2073114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     * RemoteControlClient is performed. This information is only used when the playback type is not
2083114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     * local (see {@link #PLAYBACKINFO_PLAYBACK_TYPE}).
2093114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     */
2103114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    public final static int PLAYBACKINFO_VOLUME = 2;
2113114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    /**
2121357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi     * @hide
2133114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     * Playback information that defines the maximum volume volume value that is supported
2143114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     * by the playback associated with this RemoteControlClient. This information is only used
2153114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     * when the playback type is not local (see {@link #PLAYBACKINFO_PLAYBACK_TYPE}).
2163114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     */
2173114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    public final static int PLAYBACKINFO_VOLUME_MAX = 3;
2183114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    /**
2191357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi     * @hide
2203114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     * Playback information that defines how volume is handled for the presentation of the media.
2213114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     * @see #PLAYBACK_VOLUME_FIXED
2223114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     * @see #PLAYBACK_VOLUME_VARIABLE
2233114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     */
2243114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    public final static int PLAYBACKINFO_VOLUME_HANDLING = 4;
2253114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    /**
2261357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi     * @hide
2273114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     * Playback information that defines over what stream type the media is presented.
2283114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     */
2293114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    public final static int PLAYBACKINFO_USES_STREAM = 5;
2303114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi
2313114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    //==========================================
232521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi    // Public flags for the supported transport control capabilities
2333114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    /**
234178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     * Flag indicating a RemoteControlClient makes use of the "previous" media key.
235178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     *
2364426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     * @see #setTransportControlFlags(int)
237178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     * @see android.view.KeyEvent#KEYCODE_MEDIA_PREVIOUS
238178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     */
239178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi    public final static int FLAG_KEY_MEDIA_PREVIOUS = 1 << 0;
240178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi    /**
241466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi     * Flag indicating a RemoteControlClient makes use of the "rewind" media key.
242178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     *
2434426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     * @see #setTransportControlFlags(int)
244178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     * @see android.view.KeyEvent#KEYCODE_MEDIA_REWIND
245178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     */
246178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi    public final static int FLAG_KEY_MEDIA_REWIND = 1 << 1;
247178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi    /**
248178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     * Flag indicating a RemoteControlClient makes use of the "play" media key.
249178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     *
2504426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     * @see #setTransportControlFlags(int)
251178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     * @see android.view.KeyEvent#KEYCODE_MEDIA_PLAY
252178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     */
253178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi    public final static int FLAG_KEY_MEDIA_PLAY = 1 << 2;
254178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi    /**
255178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     * Flag indicating a RemoteControlClient makes use of the "play/pause" media key.
256178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     *
2574426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     * @see #setTransportControlFlags(int)
258178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     * @see android.view.KeyEvent#KEYCODE_MEDIA_PLAY_PAUSE
259178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     */
260178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi    public final static int FLAG_KEY_MEDIA_PLAY_PAUSE = 1 << 3;
261178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi    /**
262178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     * Flag indicating a RemoteControlClient makes use of the "pause" media key.
263178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     *
2644426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     * @see #setTransportControlFlags(int)
265178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     * @see android.view.KeyEvent#KEYCODE_MEDIA_PAUSE
266178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     */
267178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi    public final static int FLAG_KEY_MEDIA_PAUSE = 1 << 4;
268178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi    /**
269178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     * Flag indicating a RemoteControlClient makes use of the "stop" media key.
270178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     *
2714426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     * @see #setTransportControlFlags(int)
272178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     * @see android.view.KeyEvent#KEYCODE_MEDIA_STOP
273178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     */
274178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi    public final static int FLAG_KEY_MEDIA_STOP = 1 << 5;
275178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi    /**
276178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     * Flag indicating a RemoteControlClient makes use of the "fast forward" media key.
277178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     *
2784426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     * @see #setTransportControlFlags(int)
279178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     * @see android.view.KeyEvent#KEYCODE_MEDIA_FAST_FORWARD
280178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     */
281178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi    public final static int FLAG_KEY_MEDIA_FAST_FORWARD = 1 << 6;
282178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi    /**
283178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     * Flag indicating a RemoteControlClient makes use of the "next" media key.
284178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     *
2854426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     * @see #setTransportControlFlags(int)
286178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     * @see android.view.KeyEvent#KEYCODE_MEDIA_NEXT
287178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     */
288178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi    public final static int FLAG_KEY_MEDIA_NEXT = 1 << 7;
289bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi    /**
290bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi     * Flag indicating a RemoteControlClient can receive changes in the media playback position
291e63b0609c3b5f6c21d4e006ee9ddd3ba98a4e684Scott Main     * through the {@link OnPlaybackPositionUpdateListener} interface. This flag must be set
2923261b537c5fdec824575a1f6ad6d8942715e82e2Jean-Michel Trivi     * in order for components that display the RemoteControlClient information, to display and
2933261b537c5fdec824575a1f6ad6d8942715e82e2Jean-Michel Trivi     * let the user control media playback position.
294bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi     * @see #setTransportControlFlags(int)
295915747730060dff71b5b2ca7e4ee4073024fc24eJean-Michel Trivi     * @see #setOnGetPlaybackPositionListener(OnGetPlaybackPositionListener)
2963261b537c5fdec824575a1f6ad6d8942715e82e2Jean-Michel Trivi     * @see #setPlaybackPositionUpdateListener(OnPlaybackPositionUpdateListener)
297bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi     */
298bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi    public final static int FLAG_KEY_MEDIA_POSITION_UPDATE = 1 << 8;
299f823fc4dba2df5cf5f00e13361f2db93c81f6961Jean-Michel Trivi    /**
300f823fc4dba2df5cf5f00e13361f2db93c81f6961Jean-Michel Trivi     * Flag indicating a RemoteControlClient supports ratings.
301f823fc4dba2df5cf5f00e13361f2db93c81f6961Jean-Michel Trivi     * This flag must be set in order for components that display the RemoteControlClient
302f823fc4dba2df5cf5f00e13361f2db93c81f6961Jean-Michel Trivi     * information, to display ratings information, and, if ratings are declared editable
303f841d70155c991b6cf728dd41e6d37e051be453dJean-Michel Trivi     * (by calling {@link MediaMetadataEditor#addEditableKey(int)} with the
304f841d70155c991b6cf728dd41e6d37e051be453dJean-Michel Trivi     * {@link MediaMetadataEditor#RATING_KEY_BY_USER} key), it will enable the user to rate
305b23cd118ce3339589fffd40ecf1aa9c5816b3438Jean-Michel Trivi     * the media, with values being received through the interface set with
306b23cd118ce3339589fffd40ecf1aa9c5816b3438Jean-Michel Trivi     * {@link #setMetadataUpdateListener(OnMetadataUpdateListener)}.
307f823fc4dba2df5cf5f00e13361f2db93c81f6961Jean-Michel Trivi     * @see #setTransportControlFlags(int)
308f823fc4dba2df5cf5f00e13361f2db93c81f6961Jean-Michel Trivi     */
309f823fc4dba2df5cf5f00e13361f2db93c81f6961Jean-Michel Trivi    public final static int FLAG_KEY_MEDIA_RATING = 1 << 9;
310178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi
311178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi    /**
3124426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     * @hide
313466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi     * The flags for when no media keys are declared supported.
314466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi     * Intentionally hidden as an application shouldn't set the transport control flags
315466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi     *     to this value.
3164426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     */
3174426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    public final static int FLAGS_KEY_MEDIA_NONE = 0;
3184426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi
3194426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    /**
3204426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     * @hide
3214426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     * Flag used to signal some type of metadata exposed by the RemoteControlClient is requested.
322178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     */
3234426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    public final static int FLAG_INFORMATION_REQUEST_METADATA = 1 << 0;
324178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi    /**
3254426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     * @hide
326178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     * Flag used to signal that the transport control buttons supported by the
327466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi     *     RemoteControlClient are requested.
328178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     * This can for instance happen when playback is at the end of a playlist, and the "next"
329178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     * operation is not supported anymore.
330178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     */
3314426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    public final static int FLAG_INFORMATION_REQUEST_KEY_MEDIA = 1 << 1;
332178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi    /**
3334426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     * @hide
334466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi     * Flag used to signal that the playback state of the RemoteControlClient is requested.
335178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     */
3364426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    public final static int FLAG_INFORMATION_REQUEST_PLAYSTATE = 1 << 2;
337178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi    /**
3384426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     * @hide
339466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi     * Flag used to signal that the album art for the RemoteControlClient is requested.
340178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     */
3414426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    public final static int FLAG_INFORMATION_REQUEST_ALBUM_ART = 1 << 3;
3424426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi
34342ea7eecd149161ed192d3029f0d77d1d08a4aa5RoboErik    private MediaSession mSession;
344f1372428f2df781c71c71caa2f6a4db6f847cf10RoboErik
3454426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    /**
3466e920e6dac11c3ebf6c0c19402934834e9e491bfJean-Michel Trivi     * Class constructor.
3476e920e6dac11c3ebf6c0c19402934834e9e491bfJean-Michel Trivi     * @param mediaButtonIntent The intent that will be sent for the media button events sent
3486e920e6dac11c3ebf6c0c19402934834e9e491bfJean-Michel Trivi     *     by remote controls.
3496e920e6dac11c3ebf6c0c19402934834e9e491bfJean-Michel Trivi     *     This intent needs to have been constructed with the {@link Intent#ACTION_MEDIA_BUTTON}
3506e920e6dac11c3ebf6c0c19402934834e9e491bfJean-Michel Trivi     *     action, and have a component that will handle the intent (set with
3516e920e6dac11c3ebf6c0c19402934834e9e491bfJean-Michel Trivi     *     {@link Intent#setComponent(ComponentName)}) registered with
3526e920e6dac11c3ebf6c0c19402934834e9e491bfJean-Michel Trivi     *     {@link AudioManager#registerMediaButtonEventReceiver(ComponentName)}
3536e920e6dac11c3ebf6c0c19402934834e9e491bfJean-Michel Trivi     *     before this new RemoteControlClient can itself be registered with
3546e920e6dac11c3ebf6c0c19402934834e9e491bfJean-Michel Trivi     *     {@link AudioManager#registerRemoteControlClient(RemoteControlClient)}.
3556e920e6dac11c3ebf6c0c19402934834e9e491bfJean-Michel Trivi     * @see AudioManager#registerMediaButtonEventReceiver(ComponentName)
3566e920e6dac11c3ebf6c0c19402934834e9e491bfJean-Michel Trivi     * @see AudioManager#registerRemoteControlClient(RemoteControlClient)
3576e920e6dac11c3ebf6c0c19402934834e9e491bfJean-Michel Trivi     */
3586e920e6dac11c3ebf6c0c19402934834e9e491bfJean-Michel Trivi    public RemoteControlClient(PendingIntent mediaButtonIntent) {
359f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi        mRcMediaIntent = mediaButtonIntent;
3606e920e6dac11c3ebf6c0c19402934834e9e491bfJean-Michel Trivi
3616e920e6dac11c3ebf6c0c19402934834e9e491bfJean-Michel Trivi        Looper looper;
3626e920e6dac11c3ebf6c0c19402934834e9e491bfJean-Michel Trivi        if ((looper = Looper.myLooper()) != null) {
3636e920e6dac11c3ebf6c0c19402934834e9e491bfJean-Michel Trivi            mEventHandler = new EventHandler(this, looper);
3646e920e6dac11c3ebf6c0c19402934834e9e491bfJean-Michel Trivi        } else if ((looper = Looper.getMainLooper()) != null) {
3656e920e6dac11c3ebf6c0c19402934834e9e491bfJean-Michel Trivi            mEventHandler = new EventHandler(this, looper);
3666e920e6dac11c3ebf6c0c19402934834e9e491bfJean-Michel Trivi        } else {
3676e920e6dac11c3ebf6c0c19402934834e9e491bfJean-Michel Trivi            mEventHandler = null;
3686e920e6dac11c3ebf6c0c19402934834e9e491bfJean-Michel Trivi            Log.e(TAG, "RemoteControlClient() couldn't find main application thread");
3696e920e6dac11c3ebf6c0c19402934834e9e491bfJean-Michel Trivi        }
3706e920e6dac11c3ebf6c0c19402934834e9e491bfJean-Michel Trivi    }
3716e920e6dac11c3ebf6c0c19402934834e9e491bfJean-Michel Trivi
3726e920e6dac11c3ebf6c0c19402934834e9e491bfJean-Michel Trivi    /**
3736e920e6dac11c3ebf6c0c19402934834e9e491bfJean-Michel Trivi     * Class constructor for a remote control client whose internal event handling
3746e920e6dac11c3ebf6c0c19402934834e9e491bfJean-Michel Trivi     * happens on a user-provided Looper.
3756e920e6dac11c3ebf6c0c19402934834e9e491bfJean-Michel Trivi     * @param mediaButtonIntent The intent that will be sent for the media button events sent
3766e920e6dac11c3ebf6c0c19402934834e9e491bfJean-Michel Trivi     *     by remote controls.
3776e920e6dac11c3ebf6c0c19402934834e9e491bfJean-Michel Trivi     *     This intent needs to have been constructed with the {@link Intent#ACTION_MEDIA_BUTTON}
3786e920e6dac11c3ebf6c0c19402934834e9e491bfJean-Michel Trivi     *     action, and have a component that will handle the intent (set with
3796e920e6dac11c3ebf6c0c19402934834e9e491bfJean-Michel Trivi     *     {@link Intent#setComponent(ComponentName)}) registered with
3806e920e6dac11c3ebf6c0c19402934834e9e491bfJean-Michel Trivi     *     {@link AudioManager#registerMediaButtonEventReceiver(ComponentName)}
3816e920e6dac11c3ebf6c0c19402934834e9e491bfJean-Michel Trivi     *     before this new RemoteControlClient can itself be registered with
3826e920e6dac11c3ebf6c0c19402934834e9e491bfJean-Michel Trivi     *     {@link AudioManager#registerRemoteControlClient(RemoteControlClient)}.
3836e920e6dac11c3ebf6c0c19402934834e9e491bfJean-Michel Trivi     * @param looper The Looper running the event loop.
3846e920e6dac11c3ebf6c0c19402934834e9e491bfJean-Michel Trivi     * @see AudioManager#registerMediaButtonEventReceiver(ComponentName)
3856e920e6dac11c3ebf6c0c19402934834e9e491bfJean-Michel Trivi     * @see AudioManager#registerRemoteControlClient(RemoteControlClient)
3866e920e6dac11c3ebf6c0c19402934834e9e491bfJean-Michel Trivi     */
3876e920e6dac11c3ebf6c0c19402934834e9e491bfJean-Michel Trivi    public RemoteControlClient(PendingIntent mediaButtonIntent, Looper looper) {
388f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi        mRcMediaIntent = mediaButtonIntent;
3896e920e6dac11c3ebf6c0c19402934834e9e491bfJean-Michel Trivi
3906e920e6dac11c3ebf6c0c19402934834e9e491bfJean-Michel Trivi        mEventHandler = new EventHandler(this, looper);
3916e920e6dac11c3ebf6c0c19402934834e9e491bfJean-Michel Trivi    }
3926e920e6dac11c3ebf6c0c19402934834e9e491bfJean-Michel Trivi
3934426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    /**
394f1372428f2df781c71c71caa2f6a4db6f847cf10RoboErik     * @hide
395f1372428f2df781c71c71caa2f6a4db6f847cf10RoboErik     */
396f1372428f2df781c71c71caa2f6a4db6f847cf10RoboErik    public void registerWithSession(MediaSessionLegacyHelper helper) {
397f1372428f2df781c71c71caa2f6a4db6f847cf10RoboErik        helper.addRccListener(mRcMediaIntent, mTransportListener);
398f1372428f2df781c71c71caa2f6a4db6f847cf10RoboErik        mSession = helper.getSession(mRcMediaIntent);
399f1372428f2df781c71c71caa2f6a4db6f847cf10RoboErik    }
400f1372428f2df781c71c71caa2f6a4db6f847cf10RoboErik
401f1372428f2df781c71c71caa2f6a4db6f847cf10RoboErik    /**
402f1372428f2df781c71c71caa2f6a4db6f847cf10RoboErik     * @hide
403f1372428f2df781c71c71caa2f6a4db6f847cf10RoboErik     */
404f1372428f2df781c71c71caa2f6a4db6f847cf10RoboErik    public void unregisterWithSession(MediaSessionLegacyHelper helper) {
405f1372428f2df781c71c71caa2f6a4db6f847cf10RoboErik        helper.removeRccListener(mRcMediaIntent);
406f1372428f2df781c71c71caa2f6a4db6f847cf10RoboErik        mSession = null;
407f1372428f2df781c71c71caa2f6a4db6f847cf10RoboErik    }
408f1372428f2df781c71c71caa2f6a4db6f847cf10RoboErik
409f1372428f2df781c71c71caa2f6a4db6f847cf10RoboErik    /**
4105f31737c68f7709cb75a8fefb7536daa77812cc3RoboErik     * Get a {@link MediaSession} associated with this RCC. It will only have a
4115f31737c68f7709cb75a8fefb7536daa77812cc3RoboErik     * session while it is registered with
4125f31737c68f7709cb75a8fefb7536daa77812cc3RoboErik     * {@link AudioManager#registerRemoteControlClient}. The session returned
4135f31737c68f7709cb75a8fefb7536daa77812cc3RoboErik     * should not be modified directly by the application but may be used with
4145f31737c68f7709cb75a8fefb7536daa77812cc3RoboErik     * other APIs that require a session.
4155f31737c68f7709cb75a8fefb7536daa77812cc3RoboErik     *
4165f31737c68f7709cb75a8fefb7536daa77812cc3RoboErik     * @return A media session object or null.
4175f31737c68f7709cb75a8fefb7536daa77812cc3RoboErik     */
4185f31737c68f7709cb75a8fefb7536daa77812cc3RoboErik    public MediaSession getMediaSession() {
4195f31737c68f7709cb75a8fefb7536daa77812cc3RoboErik        return mSession;
4205f31737c68f7709cb75a8fefb7536daa77812cc3RoboErik    }
4215f31737c68f7709cb75a8fefb7536daa77812cc3RoboErik
4225f31737c68f7709cb75a8fefb7536daa77812cc3RoboErik    /**
4234426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     * Class used to modify metadata in a {@link RemoteControlClient} object.
424466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi     * Use {@link RemoteControlClient#editMetadata(boolean)} to create an instance of an editor,
425466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi     * on which you set the metadata for the RemoteControlClient instance. Once all the information
426466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi     * has been set, use {@link #apply()} to make it the new metadata that should be displayed
427466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi     * for the associated client. Once the metadata has been "applied", you cannot reuse this
428466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi     * instance of the MetadataEditor.
4294426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     */
43088183e67d4628e8c8a3310af0076b6f33f955cb2Jean-Michel Trivi    public class MetadataEditor extends MediaMetadataEditor {
4314da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi
4324da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi        // only use RemoteControlClient.editMetadata() to get a MetadataEditor instance
4334da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi        private MetadataEditor() { }
4344da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi        /**
4354da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi         * @hide
4364da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi         */
4374da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi        public Object clone() throws CloneNotSupportedException {
4384da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi            throw new CloneNotSupportedException();
4394426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi        }
4404426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi
4414da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi        /**
4425ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Trivi         * The metadata key for the content artwork / album art.
4435ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Trivi         */
444466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi        public final static int BITMAP_KEY_ARTWORK = 100;
445f823fc4dba2df5cf5f00e13361f2db93c81f6961Jean-Michel Trivi
446f823fc4dba2df5cf5f00e13361f2db93c81f6961Jean-Michel Trivi        /**
447f823fc4dba2df5cf5f00e13361f2db93c81f6961Jean-Michel Trivi         * @hide
44888183e67d4628e8c8a3310af0076b6f33f955cb2Jean-Michel Trivi         * TODO(jmtrivi) have lockscreen move to the new key name and remove
449466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi         */
450466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi        public final static int METADATA_KEY_ARTWORK = BITMAP_KEY_ARTWORK;
4515ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Trivi
4525ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Trivi        /**
4534da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi         * Adds textual information to be displayed.
4544da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi         * Note that none of the information added after {@link #apply()} has been called,
4554da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi         * will be displayed.
456466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi         * @param key The identifier of a the metadata field to set. Valid values are
4574da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi         *      {@link android.media.MediaMetadataRetriever#METADATA_KEY_ALBUM},
4584da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi         *      {@link android.media.MediaMetadataRetriever#METADATA_KEY_ALBUMARTIST},
4594da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi         *      {@link android.media.MediaMetadataRetriever#METADATA_KEY_TITLE},
4604da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi         *      {@link android.media.MediaMetadataRetriever#METADATA_KEY_ARTIST},
4614da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi         *      {@link android.media.MediaMetadataRetriever#METADATA_KEY_AUTHOR},
4624da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi         *      {@link android.media.MediaMetadataRetriever#METADATA_KEY_COMPILATION},
4634da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi         *      {@link android.media.MediaMetadataRetriever#METADATA_KEY_COMPOSER},
4644da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi         *      {@link android.media.MediaMetadataRetriever#METADATA_KEY_DATE},
4654da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi         *      {@link android.media.MediaMetadataRetriever#METADATA_KEY_GENRE},
4664da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi         *      {@link android.media.MediaMetadataRetriever#METADATA_KEY_TITLE},
467466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi         *      {@link android.media.MediaMetadataRetriever#METADATA_KEY_WRITER}.
468466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi         * @param value The text for the given key, or {@code null} to signify there is no valid
4694da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi         *      information for the field.
470466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi         * @return Returns a reference to the same MetadataEditor object, so you can chain put
471466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi         *      calls together.
4724da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi         */
4735ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Trivi        public synchronized MetadataEditor putString(int key, String value)
4745ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Trivi                throws IllegalArgumentException {
47588183e67d4628e8c8a3310af0076b6f33f955cb2Jean-Michel Trivi            super.putString(key, value);
476f1372428f2df781c71c71caa2f6a4db6f847cf10RoboErik            if (mMetadataBuilder != null) {
477f1372428f2df781c71c71caa2f6a4db6f847cf10RoboErik                // MediaMetadata supports all the same fields as MetadataEditor
478f1372428f2df781c71c71caa2f6a4db6f847cf10RoboErik                String metadataKey = MediaMetadata.getKeyFromMetadataEditorKey(key);
479f1372428f2df781c71c71caa2f6a4db6f847cf10RoboErik                // But just in case, don't add things we don't understand
480f1372428f2df781c71c71caa2f6a4db6f847cf10RoboErik                if (metadataKey != null) {
481f1372428f2df781c71c71caa2f6a4db6f847cf10RoboErik                    mMetadataBuilder.putString(metadataKey, value);
482f1372428f2df781c71c71caa2f6a4db6f847cf10RoboErik                }
483f1372428f2df781c71c71caa2f6a4db6f847cf10RoboErik            }
484f1372428f2df781c71c71caa2f6a4db6f847cf10RoboErik
4854426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi            return this;
4864426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi        }
4874426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi
4884da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi        /**
489466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi         * Adds numerical information to be displayed.
490466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi         * Note that none of the information added after {@link #apply()} has been called,
491466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi         * will be displayed.
4925ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Trivi         * @param key the identifier of a the metadata field to set. Valid values are
4935ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Trivi         *      {@link android.media.MediaMetadataRetriever#METADATA_KEY_CD_TRACK_NUMBER},
4945ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Trivi         *      {@link android.media.MediaMetadataRetriever#METADATA_KEY_DISC_NUMBER},
4955ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Trivi         *      {@link android.media.MediaMetadataRetriever#METADATA_KEY_DURATION} (with a value
4965ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Trivi         *      expressed in milliseconds),
49788183e67d4628e8c8a3310af0076b6f33f955cb2Jean-Michel Trivi         *      {@link android.media.MediaMetadataRetriever#METADATA_KEY_YEAR}.
498466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi         * @param value The long value for the given key
499466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi         * @return Returns a reference to the same MetadataEditor object, so you can chain put
500466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi         *      calls together.
5015ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Trivi         * @throws IllegalArgumentException
5024da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi         */
5035ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Trivi        public synchronized MetadataEditor putLong(int key, long value)
5045ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Trivi                throws IllegalArgumentException {
50588183e67d4628e8c8a3310af0076b6f33f955cb2Jean-Michel Trivi            super.putLong(key, value);
506f1372428f2df781c71c71caa2f6a4db6f847cf10RoboErik            if (mMetadataBuilder != null) {
507f1372428f2df781c71c71caa2f6a4db6f847cf10RoboErik                // MediaMetadata supports all the same fields as MetadataEditor
508f1372428f2df781c71c71caa2f6a4db6f847cf10RoboErik                String metadataKey = MediaMetadata.getKeyFromMetadataEditorKey(key);
509f1372428f2df781c71c71caa2f6a4db6f847cf10RoboErik                // But just in case, don't add things we don't understand
510f1372428f2df781c71c71caa2f6a4db6f847cf10RoboErik                if (metadataKey != null) {
511f1372428f2df781c71c71caa2f6a4db6f847cf10RoboErik                    mMetadataBuilder.putLong(metadataKey, value);
512f1372428f2df781c71c71caa2f6a4db6f847cf10RoboErik                }
513f1372428f2df781c71c71caa2f6a4db6f847cf10RoboErik            }
5145ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Trivi            return this;
5155ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Trivi        }
5164da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi
5174da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi        /**
5184da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi         * Sets the album / artwork picture to be displayed on the remote control.
519466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi         * @param key the identifier of the bitmap to set. The only valid value is
520466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi         *      {@link #BITMAP_KEY_ARTWORK}
521466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi         * @param bitmap The bitmap for the artwork, or null if there isn't any.
522466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi         * @return Returns a reference to the same MetadataEditor object, so you can chain put
523466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi         *      calls together.
5245ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Trivi         * @throws IllegalArgumentException
5254da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi         * @see android.graphics.Bitmap
5264da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi         */
52788183e67d4628e8c8a3310af0076b6f33f955cb2Jean-Michel Trivi        @Override
5285ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Trivi        public synchronized MetadataEditor putBitmap(int key, Bitmap bitmap)
5295ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Trivi                throws IllegalArgumentException {
53088183e67d4628e8c8a3310af0076b6f33f955cb2Jean-Michel Trivi            super.putBitmap(key, bitmap);
531f1372428f2df781c71c71caa2f6a4db6f847cf10RoboErik            if (mMetadataBuilder != null) {
532f1372428f2df781c71c71caa2f6a4db6f847cf10RoboErik                // MediaMetadata supports all the same fields as MetadataEditor
533f1372428f2df781c71c71caa2f6a4db6f847cf10RoboErik                String metadataKey = MediaMetadata.getKeyFromMetadataEditorKey(key);
534f1372428f2df781c71c71caa2f6a4db6f847cf10RoboErik                // But just in case, don't add things we don't understand
535f1372428f2df781c71c71caa2f6a4db6f847cf10RoboErik                if (metadataKey != null) {
536f1372428f2df781c71c71caa2f6a4db6f847cf10RoboErik                    mMetadataBuilder.putBitmap(metadataKey, bitmap);
537f1372428f2df781c71c71caa2f6a4db6f847cf10RoboErik                }
538f1372428f2df781c71c71caa2f6a4db6f847cf10RoboErik            }
5394da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi            return this;
5404426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi        }
541178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi
5424da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi        /**
54388183e67d4628e8c8a3310af0076b6f33f955cb2Jean-Michel Trivi         * Clears all the metadata that has been set since the MetadataEditor instance was created
54488183e67d4628e8c8a3310af0076b6f33f955cb2Jean-Michel Trivi         * (with {@link RemoteControlClient#editMetadata(boolean)}).
545b23cd118ce3339589fffd40ecf1aa9c5816b3438Jean-Michel Trivi         * Note that clearing the metadata doesn't reset the editable keys
54688183e67d4628e8c8a3310af0076b6f33f955cb2Jean-Michel Trivi         * (use {@link MediaMetadataEditor#removeEditableKeys()} instead).
5474da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi         */
54888183e67d4628e8c8a3310af0076b6f33f955cb2Jean-Michel Trivi        @Override
5494da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi        public synchronized void clear() {
55088183e67d4628e8c8a3310af0076b6f33f955cb2Jean-Michel Trivi            super.clear();
551f823fc4dba2df5cf5f00e13361f2db93c81f6961Jean-Michel Trivi        }
552f823fc4dba2df5cf5f00e13361f2db93c81f6961Jean-Michel Trivi
553f823fc4dba2df5cf5f00e13361f2db93c81f6961Jean-Michel Trivi        /**
554466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi         * Associates all the metadata that has been set since the MetadataEditor instance was
555466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi         *     created with {@link RemoteControlClient#editMetadata(boolean)}, or since
556466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi         *     {@link #clear()} was called, with the RemoteControlClient. Once "applied",
557466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi         *     this MetadataEditor cannot be reused to edit the RemoteControlClient's metadata.
5584da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi         */
5594da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi        public synchronized void apply() {
5604da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi            if (mApplied) {
5614da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi                Log.e(TAG, "Can't apply a previously applied MetadataEditor");
5624da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi                return;
5634da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi            }
564f1372428f2df781c71c71caa2f6a4db6f847cf10RoboErik            synchronized (mCacheLock) {
5654da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi                // assign the edited data
5664da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi                mMetadata = new Bundle(mEditorMetadata);
567f823fc4dba2df5cf5f00e13361f2db93c81f6961Jean-Michel Trivi                // add the information about editable keys
568f823fc4dba2df5cf5f00e13361f2db93c81f6961Jean-Michel Trivi                mMetadata.putLong(String.valueOf(KEY_EDITABLE_MASK), mEditableKeys);
5694a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi                if ((mOriginalArtwork != null) && (!mOriginalArtwork.equals(mEditorArtwork))) {
5704a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi                    mOriginalArtwork.recycle();
57134d0d300cac645b48cce5a1735f45e1102d4ef0eJean-Michel Trivi                }
5724a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi                mOriginalArtwork = mEditorArtwork;
57334d0d300cac645b48cce5a1735f45e1102d4ef0eJean-Michel Trivi                mEditorArtwork = null;
5744da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi                if (mMetadataChanged & mArtworkChanged) {
5754da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi                    // send to remote control display if conditions are met
57686142da1ce8c1341404a9f9e21be8acbcba69ab3Jean-Michel Trivi                    sendMetadataWithArtwork_syncCacheLock(null, 0, 0);
5774da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi                } else if (mMetadataChanged) {
5784da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi                    // send to remote control display if conditions are met
57986142da1ce8c1341404a9f9e21be8acbcba69ab3Jean-Michel Trivi                    sendMetadata_syncCacheLock(null);
5804da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi                } else if (mArtworkChanged) {
5814da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi                    // send to remote control display if conditions are met
58286142da1ce8c1341404a9f9e21be8acbcba69ab3Jean-Michel Trivi                    sendArtwork_syncCacheLock(null, 0, 0);
5834da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi                }
584f1372428f2df781c71c71caa2f6a4db6f847cf10RoboErik
585f1372428f2df781c71c71caa2f6a4db6f847cf10RoboErik                // USE_SESSIONS
586f1372428f2df781c71c71caa2f6a4db6f847cf10RoboErik                if (mSession != null && mMetadataBuilder != null) {
587f1372428f2df781c71c71caa2f6a4db6f847cf10RoboErik                    mSession.getTransportPerformer().setMetadata(mMetadataBuilder.build());
588f1372428f2df781c71c71caa2f6a4db6f847cf10RoboErik                }
5894da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi                mApplied = true;
5904da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi            }
5914426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi        }
5924426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    }
5934426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi
5944426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    /**
595466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi     * Creates a {@link MetadataEditor}.
596466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi     * @param startEmpty Set to false if you want the MetadataEditor to contain the metadata that
597466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi     *     was previously applied to the RemoteControlClient, or true if it is to be created empty.
598466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi     * @return a new MetadataEditor instance.
5994426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     */
6004da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi    public MetadataEditor editMetadata(boolean startEmpty) {
6014da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi        MetadataEditor editor = new MetadataEditor();
6024da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi        if (startEmpty) {
6034da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi            editor.mEditorMetadata = new Bundle();
6044da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi            editor.mEditorArtwork = null;
6054da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi            editor.mMetadataChanged = true;
6064da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi            editor.mArtworkChanged = true;
607f823fc4dba2df5cf5f00e13361f2db93c81f6961Jean-Michel Trivi            editor.mEditableKeys = 0;
6084da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi        } else {
6094da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi            editor.mEditorMetadata = new Bundle(mMetadata);
6104a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi            editor.mEditorArtwork = mOriginalArtwork;
6114da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi            editor.mMetadataChanged = false;
6124da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi            editor.mArtworkChanged = false;
6134426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi        }
614f1372428f2df781c71c71caa2f6a4db6f847cf10RoboErik        // USE_SESSIONS
615f1372428f2df781c71c71caa2f6a4db6f847cf10RoboErik        if (startEmpty || mMediaMetadata == null) {
616f1372428f2df781c71c71caa2f6a4db6f847cf10RoboErik            editor.mMetadataBuilder = new MediaMetadata.Builder();
617f1372428f2df781c71c71caa2f6a4db6f847cf10RoboErik        } else {
618f1372428f2df781c71c71caa2f6a4db6f847cf10RoboErik            editor.mMetadataBuilder = new MediaMetadata.Builder(mMediaMetadata);
619f1372428f2df781c71c71caa2f6a4db6f847cf10RoboErik        }
6204da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi        return editor;
6214426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    }
6224426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi
6234426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    /**
6244426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     * Sets the current playback state.
625466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi     * @param state The current playback state, one of the following values:
626178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     *       {@link #PLAYSTATE_STOPPED},
627178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     *       {@link #PLAYSTATE_PAUSED},
628178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     *       {@link #PLAYSTATE_PLAYING},
629178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     *       {@link #PLAYSTATE_FAST_FORWARDING},
630178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     *       {@link #PLAYSTATE_REWINDING},
631178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     *       {@link #PLAYSTATE_SKIPPING_FORWARDS},
632178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     *       {@link #PLAYSTATE_SKIPPING_BACKWARDS},
633178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     *       {@link #PLAYSTATE_BUFFERING},
634178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     *       {@link #PLAYSTATE_ERROR}.
635178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     */
6364426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    public void setPlaybackState(int state) {
6371b16cc3de51d69c8027cefcc70a084a5b2d7a3d0Jean-Michel Trivi        setPlaybackStateInt(state, PLAYBACK_POSITION_ALWAYS_UNKNOWN, PLAYBACK_SPEED_1X,
6381b16cc3de51d69c8027cefcc70a084a5b2d7a3d0Jean-Michel Trivi                false /* legacy API, converting to method with position and speed */);
639bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi    }
640bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi
641bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi    /**
642bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi     * Sets the current playback state and the matching media position for the current playback
643bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi     *   speed.
644bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi     * @param state The current playback state, one of the following values:
645bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi     *       {@link #PLAYSTATE_STOPPED},
646bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi     *       {@link #PLAYSTATE_PAUSED},
647bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi     *       {@link #PLAYSTATE_PLAYING},
648bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi     *       {@link #PLAYSTATE_FAST_FORWARDING},
649bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi     *       {@link #PLAYSTATE_REWINDING},
650bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi     *       {@link #PLAYSTATE_SKIPPING_FORWARDS},
651bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi     *       {@link #PLAYSTATE_SKIPPING_BACKWARDS},
652bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi     *       {@link #PLAYSTATE_BUFFERING},
653bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi     *       {@link #PLAYSTATE_ERROR}.
654bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi     * @param timeInMs a 0 or positive value for the current media position expressed in ms
655bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi     *    (same unit as for when sending the media duration, if applicable, with
656bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi     *    {@link android.media.MediaMetadataRetriever#METADATA_KEY_DURATION} in the
657bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi     *    {@link RemoteControlClient.MetadataEditor}). Negative values imply that position is not
658bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi     *    known (e.g. listening to a live stream of a radio) or not applicable (e.g. when state
659bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi     *    is {@link #PLAYSTATE_BUFFERING} and nothing had played yet).
660bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi     * @param playbackSpeed a value expressed as a ratio of 1x playback: 1.0f is normal playback,
661bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi     *    2.0f is 2x, 0.5f is half-speed, -2.0f is rewind at 2x speed. 0.0f means nothing is
662bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi     *    playing (e.g. when state is {@link #PLAYSTATE_ERROR}).
663bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi     */
664bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi    public void setPlaybackState(int state, long timeInMs, float playbackSpeed) {
6651b16cc3de51d69c8027cefcc70a084a5b2d7a3d0Jean-Michel Trivi        setPlaybackStateInt(state, timeInMs, playbackSpeed, true);
6661b16cc3de51d69c8027cefcc70a084a5b2d7a3d0Jean-Michel Trivi    }
6671b16cc3de51d69c8027cefcc70a084a5b2d7a3d0Jean-Michel Trivi
6681b16cc3de51d69c8027cefcc70a084a5b2d7a3d0Jean-Michel Trivi    private void setPlaybackStateInt(int state, long timeInMs, float playbackSpeed,
6691b16cc3de51d69c8027cefcc70a084a5b2d7a3d0Jean-Michel Trivi            boolean hasPosition) {
6704426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi        synchronized(mCacheLock) {
671bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi            if ((mPlaybackState != state) || (mPlaybackPositionMs != timeInMs)
672bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi                    || (mPlaybackSpeed != playbackSpeed)) {
67368622396b62f9084781add1e12f4d513b633ab54Jean-Michel Trivi                // store locally
67468622396b62f9084781add1e12f4d513b633ab54Jean-Michel Trivi                mPlaybackState = state;
6751b16cc3de51d69c8027cefcc70a084a5b2d7a3d0Jean-Michel Trivi                // distinguish between an application not knowing the current playback position
6761b16cc3de51d69c8027cefcc70a084a5b2d7a3d0Jean-Michel Trivi                // at the moment and an application using the API where only the playback state
6771b16cc3de51d69c8027cefcc70a084a5b2d7a3d0Jean-Michel Trivi                // is passed, not the playback position.
6781b16cc3de51d69c8027cefcc70a084a5b2d7a3d0Jean-Michel Trivi                if (hasPosition) {
6791b16cc3de51d69c8027cefcc70a084a5b2d7a3d0Jean-Michel Trivi                    if (timeInMs < 0) {
6801b16cc3de51d69c8027cefcc70a084a5b2d7a3d0Jean-Michel Trivi                        mPlaybackPositionMs = PLAYBACK_POSITION_INVALID;
6811b16cc3de51d69c8027cefcc70a084a5b2d7a3d0Jean-Michel Trivi                    } else {
6821b16cc3de51d69c8027cefcc70a084a5b2d7a3d0Jean-Michel Trivi                        mPlaybackPositionMs = timeInMs;
6831b16cc3de51d69c8027cefcc70a084a5b2d7a3d0Jean-Michel Trivi                    }
6841b16cc3de51d69c8027cefcc70a084a5b2d7a3d0Jean-Michel Trivi                } else {
6851b16cc3de51d69c8027cefcc70a084a5b2d7a3d0Jean-Michel Trivi                    mPlaybackPositionMs = PLAYBACK_POSITION_ALWAYS_UNKNOWN;
6861b16cc3de51d69c8027cefcc70a084a5b2d7a3d0Jean-Michel Trivi                }
687bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi                mPlaybackSpeed = playbackSpeed;
68868622396b62f9084781add1e12f4d513b633ab54Jean-Michel Trivi                // keep track of when the state change occurred
68968622396b62f9084781add1e12f4d513b633ab54Jean-Michel Trivi                mPlaybackStateChangeTimeMs = SystemClock.elapsedRealtime();
69068622396b62f9084781add1e12f4d513b633ab54Jean-Michel Trivi
69168622396b62f9084781add1e12f4d513b633ab54Jean-Michel Trivi                // send to remote control display if conditions are met
69286142da1ce8c1341404a9f9e21be8acbcba69ab3Jean-Michel Trivi                sendPlaybackState_syncCacheLock(null);
6933114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                // update AudioService
694bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi                sendAudioServiceNewPlaybackState_syncCacheLock();
695521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi
696521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi                // handle automatic playback position refreshes
697c3c4babf8424f65b3d3d2700f60fae6e94e9cd00Jean-Michel Trivi                initiateCheckForDrift_syncCacheLock();
698f1372428f2df781c71c71caa2f6a4db6f847cf10RoboErik
699f1372428f2df781c71c71caa2f6a4db6f847cf10RoboErik                // USE_SESSIONS
700f1372428f2df781c71c71caa2f6a4db6f847cf10RoboErik                if (mSession != null) {
701f1372428f2df781c71c71caa2f6a4db6f847cf10RoboErik                    int pbState = PlaybackState.getStateFromRccState(state);
702f1372428f2df781c71c71caa2f6a4db6f847cf10RoboErik                    mSessionPlaybackState.setState(pbState, hasPosition ?
703f1372428f2df781c71c71caa2f6a4db6f847cf10RoboErik                            mPlaybackPositionMs : PlaybackState.PLAYBACK_POSITION_UNKNOWN,
704f1372428f2df781c71c71caa2f6a4db6f847cf10RoboErik                            playbackSpeed);
705f1372428f2df781c71c71caa2f6a4db6f847cf10RoboErik                    mSession.getTransportPerformer().setPlaybackState(mSessionPlaybackState);
706f1372428f2df781c71c71caa2f6a4db6f847cf10RoboErik                }
707521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi            }
708521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi        }
709521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi    }
710521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi
711c3c4babf8424f65b3d3d2700f60fae6e94e9cd00Jean-Michel Trivi    private void initiateCheckForDrift_syncCacheLock() {
712c3c4babf8424f65b3d3d2700f60fae6e94e9cd00Jean-Michel Trivi        if (mEventHandler == null) {
713c3c4babf8424f65b3d3d2700f60fae6e94e9cd00Jean-Michel Trivi            return;
714c3c4babf8424f65b3d3d2700f60fae6e94e9cd00Jean-Michel Trivi        }
715c3c4babf8424f65b3d3d2700f60fae6e94e9cd00Jean-Michel Trivi        mEventHandler.removeMessages(MSG_POSITION_DRIFT_CHECK);
716c3c4babf8424f65b3d3d2700f60fae6e94e9cd00Jean-Michel Trivi        if (!mNeedsPositionSync) {
717c3c4babf8424f65b3d3d2700f60fae6e94e9cd00Jean-Michel Trivi            return;
718c3c4babf8424f65b3d3d2700f60fae6e94e9cd00Jean-Michel Trivi        }
719c3c4babf8424f65b3d3d2700f60fae6e94e9cd00Jean-Michel Trivi        if (mPlaybackPositionMs < 0) {
720c3c4babf8424f65b3d3d2700f60fae6e94e9cd00Jean-Michel Trivi            // the current playback state has no known playback position, it's no use
721c3c4babf8424f65b3d3d2700f60fae6e94e9cd00Jean-Michel Trivi            // trying to see if there is any drift at this point
722c3c4babf8424f65b3d3d2700f60fae6e94e9cd00Jean-Michel Trivi            // (this also bypasses this mechanism for older apps that use the old
723c3c4babf8424f65b3d3d2700f60fae6e94e9cd00Jean-Michel Trivi            //  setPlaybackState(int) API)
724c3c4babf8424f65b3d3d2700f60fae6e94e9cd00Jean-Michel Trivi            return;
725c3c4babf8424f65b3d3d2700f60fae6e94e9cd00Jean-Michel Trivi        }
726c3c4babf8424f65b3d3d2700f60fae6e94e9cd00Jean-Michel Trivi        if (playbackPositionShouldMove(mPlaybackState)) {
727c3c4babf8424f65b3d3d2700f60fae6e94e9cd00Jean-Michel Trivi            // playback position moving, schedule next position drift check
728c3c4babf8424f65b3d3d2700f60fae6e94e9cd00Jean-Michel Trivi            mEventHandler.sendMessageDelayed(
729c3c4babf8424f65b3d3d2700f60fae6e94e9cd00Jean-Michel Trivi                    mEventHandler.obtainMessage(MSG_POSITION_DRIFT_CHECK),
730c3c4babf8424f65b3d3d2700f60fae6e94e9cd00Jean-Michel Trivi                    getCheckPeriodFromSpeed(mPlaybackSpeed));
731c3c4babf8424f65b3d3d2700f60fae6e94e9cd00Jean-Michel Trivi        }
732c3c4babf8424f65b3d3d2700f60fae6e94e9cd00Jean-Michel Trivi    }
733c3c4babf8424f65b3d3d2700f60fae6e94e9cd00Jean-Michel Trivi
734521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi    private void onPositionDriftCheck() {
735521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi        if (DEBUG) { Log.d(TAG, "onPositionDriftCheck()"); }
736521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi        synchronized(mCacheLock) {
737c3c4babf8424f65b3d3d2700f60fae6e94e9cd00Jean-Michel Trivi            if ((mEventHandler == null) || (mPositionProvider == null) || !mNeedsPositionSync) {
738521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi                return;
739521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi            }
740c3c4babf8424f65b3d3d2700f60fae6e94e9cd00Jean-Michel Trivi            if ((mPlaybackPositionMs < 0) || (mPlaybackSpeed == 0.0f)) {
741c3c4babf8424f65b3d3d2700f60fae6e94e9cd00Jean-Michel Trivi                if (DEBUG) { Log.d(TAG, " no valid position or 0 speed, no check needed"); }
742521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi                return;
743521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi            }
744521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi            long estPos = mPlaybackPositionMs + (long)
745521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi                    ((SystemClock.elapsedRealtime() - mPlaybackStateChangeTimeMs) / mPlaybackSpeed);
746521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi            long actPos = mPositionProvider.onGetPlaybackPosition();
747521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi            if (actPos >= 0) {
748521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi                if (Math.abs(estPos - actPos) > POSITION_DRIFT_MAX_MS) {
749521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi                    // drift happened, report the new position
750521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi                    if (DEBUG) { Log.w(TAG, " drift detected: actual=" +actPos +"  est=" +estPos); }
751521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi                    setPlaybackState(mPlaybackState, actPos, mPlaybackSpeed);
752521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi                } else {
753521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi                    if (DEBUG) { Log.d(TAG, " no drift: actual=" + actPos +"  est=" + estPos); }
754521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi                    // no drift, schedule the next drift check
755521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi                    mEventHandler.sendMessageDelayed(
756521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi                            mEventHandler.obtainMessage(MSG_POSITION_DRIFT_CHECK),
757521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi                            getCheckPeriodFromSpeed(mPlaybackSpeed));
758521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi                }
759521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi            } else {
760521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi                // invalid position (negative value), can't check for drift
761521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi                mEventHandler.removeMessages(MSG_POSITION_DRIFT_CHECK);
76268622396b62f9084781add1e12f4d513b633ab54Jean-Michel Trivi            }
7634426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi        }
7644426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    }
765178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi
766178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi    /**
7674426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     * Sets the flags for the media transport control buttons that this client supports.
768466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi     * @param transportControlFlags A combination of the following flags:
7694426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     *      {@link #FLAG_KEY_MEDIA_PREVIOUS},
770178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     *      {@link #FLAG_KEY_MEDIA_REWIND},
771178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     *      {@link #FLAG_KEY_MEDIA_PLAY},
772178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     *      {@link #FLAG_KEY_MEDIA_PLAY_PAUSE},
773178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     *      {@link #FLAG_KEY_MEDIA_PAUSE},
774178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     *      {@link #FLAG_KEY_MEDIA_STOP},
775178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     *      {@link #FLAG_KEY_MEDIA_FAST_FORWARD},
776915747730060dff71b5b2ca7e4ee4073024fc24eJean-Michel Trivi     *      {@link #FLAG_KEY_MEDIA_NEXT},
777b23cd118ce3339589fffd40ecf1aa9c5816b3438Jean-Michel Trivi     *      {@link #FLAG_KEY_MEDIA_POSITION_UPDATE},
778b23cd118ce3339589fffd40ecf1aa9c5816b3438Jean-Michel Trivi     *      {@link #FLAG_KEY_MEDIA_RATING}.
779178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     */
7804426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    public void setTransportControlFlags(int transportControlFlags) {
7814426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi        synchronized(mCacheLock) {
7824426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi            // store locally
7834426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi            mTransportControlFlags = transportControlFlags;
7844426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi
7854426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi            // send to remote control display if conditions are met
78686142da1ce8c1341404a9f9e21be8acbcba69ab3Jean-Michel Trivi            sendTransportControlInfo_syncCacheLock(null);
787f1372428f2df781c71c71caa2f6a4db6f847cf10RoboErik
788f1372428f2df781c71c71caa2f6a4db6f847cf10RoboErik            // USE_SESSIONS
789f1372428f2df781c71c71caa2f6a4db6f847cf10RoboErik            if (mSession != null) {
790f1372428f2df781c71c71caa2f6a4db6f847cf10RoboErik                mSessionPlaybackState.setActions(PlaybackState
791f1372428f2df781c71c71caa2f6a4db6f847cf10RoboErik                        .getActionsFromRccControlFlags(transportControlFlags));
792f1372428f2df781c71c71caa2f6a4db6f847cf10RoboErik                mSession.getTransportPerformer().setPlaybackState(mSessionPlaybackState);
793f1372428f2df781c71c71caa2f6a4db6f847cf10RoboErik            }
7944426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi        }
7954426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    }
796178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi
797bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi    /**
798b23cd118ce3339589fffd40ecf1aa9c5816b3438Jean-Michel Trivi     * Interface definition for a callback to be invoked when one of the metadata values has
799b23cd118ce3339589fffd40ecf1aa9c5816b3438Jean-Michel Trivi     * been updated.
80088183e67d4628e8c8a3310af0076b6f33f955cb2Jean-Michel Trivi     * Implement this interface to receive metadata updates after registering your listener
80188183e67d4628e8c8a3310af0076b6f33f955cb2Jean-Michel Trivi     * through {@link RemoteControlClient#setMetadataUpdateListener(OnMetadataUpdateListener)}.
802f823fc4dba2df5cf5f00e13361f2db93c81f6961Jean-Michel Trivi     */
8037ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi    public interface OnMetadataUpdateListener {
804f823fc4dba2df5cf5f00e13361f2db93c81f6961Jean-Michel Trivi        /**
805b23cd118ce3339589fffd40ecf1aa9c5816b3438Jean-Michel Trivi         * Called on the implementer to notify that the metadata field for the given key has
80688183e67d4628e8c8a3310af0076b6f33f955cb2Jean-Michel Trivi         * been updated to the new value.
80788183e67d4628e8c8a3310af0076b6f33f955cb2Jean-Michel Trivi         * @param key the identifier of the updated metadata field.
80888183e67d4628e8c8a3310af0076b6f33f955cb2Jean-Michel Trivi         * @param newValue the Object storing the new value for the key.
809f823fc4dba2df5cf5f00e13361f2db93c81f6961Jean-Michel Trivi         */
81088183e67d4628e8c8a3310af0076b6f33f955cb2Jean-Michel Trivi        public abstract void onMetadataUpdate(int key, Object newValue);
811f823fc4dba2df5cf5f00e13361f2db93c81f6961Jean-Michel Trivi    }
812f823fc4dba2df5cf5f00e13361f2db93c81f6961Jean-Michel Trivi
813f823fc4dba2df5cf5f00e13361f2db93c81f6961Jean-Michel Trivi    /**
814b23cd118ce3339589fffd40ecf1aa9c5816b3438Jean-Michel Trivi     * Sets the listener to be called whenever the metadata is updated.
815b23cd118ce3339589fffd40ecf1aa9c5816b3438Jean-Michel Trivi     * New metadata values will be received in the same thread as the one in which
816b23cd118ce3339589fffd40ecf1aa9c5816b3438Jean-Michel Trivi     * RemoteControlClient was created.
817b23cd118ce3339589fffd40ecf1aa9c5816b3438Jean-Michel Trivi     * @param l the metadata update listener
818f823fc4dba2df5cf5f00e13361f2db93c81f6961Jean-Michel Trivi     */
819f823fc4dba2df5cf5f00e13361f2db93c81f6961Jean-Michel Trivi    public void setMetadataUpdateListener(OnMetadataUpdateListener l) {
820f823fc4dba2df5cf5f00e13361f2db93c81f6961Jean-Michel Trivi        synchronized(mCacheLock) {
821f823fc4dba2df5cf5f00e13361f2db93c81f6961Jean-Michel Trivi            mMetadataUpdateListener = l;
822f823fc4dba2df5cf5f00e13361f2db93c81f6961Jean-Michel Trivi        }
823f823fc4dba2df5cf5f00e13361f2db93c81f6961Jean-Michel Trivi    }
824f823fc4dba2df5cf5f00e13361f2db93c81f6961Jean-Michel Trivi
825f823fc4dba2df5cf5f00e13361f2db93c81f6961Jean-Michel Trivi
826f823fc4dba2df5cf5f00e13361f2db93c81f6961Jean-Michel Trivi    /**
827bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi     * Interface definition for a callback to be invoked when the media playback position is
828bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi     * requested to be updated.
8293261b537c5fdec824575a1f6ad6d8942715e82e2Jean-Michel Trivi     * @see RemoteControlClient#FLAG_KEY_MEDIA_POSITION_UPDATE
830bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi     */
831bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi    public interface OnPlaybackPositionUpdateListener {
832bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi        /**
8333261b537c5fdec824575a1f6ad6d8942715e82e2Jean-Michel Trivi         * Called on the implementer to notify it that the playback head should be set at the given
834bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi         * position. If the position can be changed from its current value, the implementor of
8353fbf67e217fb489fe7318a9e43d8ae86646eb4ccJean-Michel Trivi         * the interface must also update the playback position using
836e63b0609c3b5f6c21d4e006ee9ddd3ba98a4e684Scott Main         * {@link #setPlaybackState(int, long, float)} to reflect the actual new
837bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi         * position being used, regardless of whether it differs from the requested position.
8383fbf67e217fb489fe7318a9e43d8ae86646eb4ccJean-Michel Trivi         * Failure to do so would cause the system to not know the new actual playback position,
8393fbf67e217fb489fe7318a9e43d8ae86646eb4ccJean-Michel Trivi         * and user interface components would fail to show the user where playback resumed after
8403fbf67e217fb489fe7318a9e43d8ae86646eb4ccJean-Michel Trivi         * the position was updated.
841bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi         * @param newPositionMs the new requested position in the current media, expressed in ms.
842bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi         */
843bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi        void onPlaybackPositionUpdate(long newPositionMs);
844bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi    }
845bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi
846bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi    /**
8473261b537c5fdec824575a1f6ad6d8942715e82e2Jean-Michel Trivi     * Interface definition for a callback to be invoked when the media playback position is
8483261b537c5fdec824575a1f6ad6d8942715e82e2Jean-Michel Trivi     * queried.
8493261b537c5fdec824575a1f6ad6d8942715e82e2Jean-Michel Trivi     * @see RemoteControlClient#FLAG_KEY_MEDIA_POSITION_UPDATE
8503261b537c5fdec824575a1f6ad6d8942715e82e2Jean-Michel Trivi     */
851915747730060dff71b5b2ca7e4ee4073024fc24eJean-Michel Trivi    public interface OnGetPlaybackPositionListener {
8523261b537c5fdec824575a1f6ad6d8942715e82e2Jean-Michel Trivi        /**
8533261b537c5fdec824575a1f6ad6d8942715e82e2Jean-Michel Trivi         * Called on the implementer of the interface to query the current playback position.
8543261b537c5fdec824575a1f6ad6d8942715e82e2Jean-Michel Trivi         * @return a negative value if the current playback position (or the last valid playback
8553261b537c5fdec824575a1f6ad6d8942715e82e2Jean-Michel Trivi         *     position) is not known, or a zero or positive value expressed in ms indicating the
8563261b537c5fdec824575a1f6ad6d8942715e82e2Jean-Michel Trivi         *     current position, or the last valid known position.
8573261b537c5fdec824575a1f6ad6d8942715e82e2Jean-Michel Trivi         */
858915747730060dff71b5b2ca7e4ee4073024fc24eJean-Michel Trivi        long onGetPlaybackPosition();
8593261b537c5fdec824575a1f6ad6d8942715e82e2Jean-Michel Trivi    }
8603261b537c5fdec824575a1f6ad6d8942715e82e2Jean-Michel Trivi
8613261b537c5fdec824575a1f6ad6d8942715e82e2Jean-Michel Trivi    /**
8623261b537c5fdec824575a1f6ad6d8942715e82e2Jean-Michel Trivi     * Sets the listener to be called whenever the media playback position is requested
863bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi     * to be updated.
864bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi     * Notifications will be received in the same thread as the one in which RemoteControlClient
865bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi     * was created.
866915747730060dff71b5b2ca7e4ee4073024fc24eJean-Michel Trivi     * @param l the position update listener to be called
867bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi     */
868bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi    public void setPlaybackPositionUpdateListener(OnPlaybackPositionUpdateListener l) {
869bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi        synchronized(mCacheLock) {
8703261b537c5fdec824575a1f6ad6d8942715e82e2Jean-Michel Trivi            int oldCapa = mPlaybackPositionCapabilities;
8713261b537c5fdec824575a1f6ad6d8942715e82e2Jean-Michel Trivi            if (l != null) {
872bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi                mPlaybackPositionCapabilities |= MEDIA_POSITION_WRITABLE;
8733261b537c5fdec824575a1f6ad6d8942715e82e2Jean-Michel Trivi            } else {
874bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi                mPlaybackPositionCapabilities &= ~MEDIA_POSITION_WRITABLE;
875bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi            }
876bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi            mPositionUpdateListener = l;
8773261b537c5fdec824575a1f6ad6d8942715e82e2Jean-Michel Trivi            if (oldCapa != mPlaybackPositionCapabilities) {
8783261b537c5fdec824575a1f6ad6d8942715e82e2Jean-Michel Trivi                // tell RCDs that this RCC's playback position capabilities have changed
87986142da1ce8c1341404a9f9e21be8acbcba69ab3Jean-Michel Trivi                sendTransportControlInfo_syncCacheLock(null);
8803261b537c5fdec824575a1f6ad6d8942715e82e2Jean-Michel Trivi            }
8813261b537c5fdec824575a1f6ad6d8942715e82e2Jean-Michel Trivi        }
8823261b537c5fdec824575a1f6ad6d8942715e82e2Jean-Michel Trivi    }
8833261b537c5fdec824575a1f6ad6d8942715e82e2Jean-Michel Trivi
8843261b537c5fdec824575a1f6ad6d8942715e82e2Jean-Michel Trivi    /**
8853261b537c5fdec824575a1f6ad6d8942715e82e2Jean-Michel Trivi     * Sets the listener to be called whenever the media current playback position is needed.
8863261b537c5fdec824575a1f6ad6d8942715e82e2Jean-Michel Trivi     * Queries will be received in the same thread as the one in which RemoteControlClient
8873261b537c5fdec824575a1f6ad6d8942715e82e2Jean-Michel Trivi     * was created.
888915747730060dff71b5b2ca7e4ee4073024fc24eJean-Michel Trivi     * @param l the listener to be called to retrieve the playback position
8893261b537c5fdec824575a1f6ad6d8942715e82e2Jean-Michel Trivi     */
890915747730060dff71b5b2ca7e4ee4073024fc24eJean-Michel Trivi    public void setOnGetPlaybackPositionListener(OnGetPlaybackPositionListener l) {
8913261b537c5fdec824575a1f6ad6d8942715e82e2Jean-Michel Trivi        synchronized(mCacheLock) {
8923261b537c5fdec824575a1f6ad6d8942715e82e2Jean-Michel Trivi            int oldCapa = mPlaybackPositionCapabilities;
8933261b537c5fdec824575a1f6ad6d8942715e82e2Jean-Michel Trivi            if (l != null) {
8943261b537c5fdec824575a1f6ad6d8942715e82e2Jean-Michel Trivi                mPlaybackPositionCapabilities |= MEDIA_POSITION_READABLE;
8953261b537c5fdec824575a1f6ad6d8942715e82e2Jean-Michel Trivi            } else {
8963261b537c5fdec824575a1f6ad6d8942715e82e2Jean-Michel Trivi                mPlaybackPositionCapabilities &= ~MEDIA_POSITION_READABLE;
8973261b537c5fdec824575a1f6ad6d8942715e82e2Jean-Michel Trivi            }
8983261b537c5fdec824575a1f6ad6d8942715e82e2Jean-Michel Trivi            mPositionProvider = l;
8993261b537c5fdec824575a1f6ad6d8942715e82e2Jean-Michel Trivi            if (oldCapa != mPlaybackPositionCapabilities) {
9003261b537c5fdec824575a1f6ad6d8942715e82e2Jean-Michel Trivi                // tell RCDs that this RCC's playback position capabilities have changed
90186142da1ce8c1341404a9f9e21be8acbcba69ab3Jean-Michel Trivi                sendTransportControlInfo_syncCacheLock(null);
9023261b537c5fdec824575a1f6ad6d8942715e82e2Jean-Michel Trivi            }
903521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi            if ((mPositionProvider != null) && (mEventHandler != null)
904521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi                    && playbackPositionShouldMove(mPlaybackState)) {
905521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi                // playback position is already moving, but now we have a position provider,
906521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi                // so schedule a drift check right now
907521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi                mEventHandler.sendMessageDelayed(
908521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi                        mEventHandler.obtainMessage(MSG_POSITION_DRIFT_CHECK),
909521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi                        0 /*check now*/);
910521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi            }
911bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi        }
912bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi    }
913bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi
914bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi    /**
915bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi     * @hide
916bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi     * Flag to reflect that the application controlling this RemoteControlClient sends playback
917bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi     * position updates. The playback position being "readable" is considered from the application's
918bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi     * point of view.
919bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi     */
920bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi    public static int MEDIA_POSITION_READABLE = 1 << 0;
921bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi    /**
922bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi     * @hide
923bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi     * Flag to reflect that the application controlling this RemoteControlClient can receive
924bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi     * playback position updates. The playback position being "writable"
925bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi     * is considered from the application's point of view.
926bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi     */
927bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi    public static int MEDIA_POSITION_WRITABLE = 1 << 1;
928bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi
929bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi    private int mPlaybackPositionCapabilities = 0;
930bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi
9313114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    /** @hide */
9323114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    public final static int DEFAULT_PLAYBACK_VOLUME_HANDLING = PLAYBACK_VOLUME_VARIABLE;
9333114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    /** @hide */
9343114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    // hard-coded to the same number of steps as AudioService.MAX_STREAM_VOLUME[STREAM_MUSIC]
9353114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    public final static int DEFAULT_PLAYBACK_VOLUME = 15;
9363114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi
9373114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    private int mPlaybackType = PLAYBACK_TYPE_LOCAL;
9383114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    private int mPlaybackVolumeMax = DEFAULT_PLAYBACK_VOLUME;
9393114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    private int mPlaybackVolume = DEFAULT_PLAYBACK_VOLUME;
9403114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    private int mPlaybackVolumeHandling = DEFAULT_PLAYBACK_VOLUME_HANDLING;
9413114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    private int mPlaybackStream = AudioManager.STREAM_MUSIC;
9423114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi
9433114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    /**
9441357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi     * @hide
9453114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     * Set information describing information related to the playback of media so the system
9463114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     * can implement additional behavior to handle non-local playback usecases.
9473114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     * @param what a key to specify the type of information to set. Valid keys are
9483114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     *        {@link #PLAYBACKINFO_PLAYBACK_TYPE},
9493114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     *        {@link #PLAYBACKINFO_USES_STREAM},
9503114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     *        {@link #PLAYBACKINFO_VOLUME},
9513114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     *        {@link #PLAYBACKINFO_VOLUME_MAX},
9523114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     *        and {@link #PLAYBACKINFO_VOLUME_HANDLING}.
9533114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     * @param value the value for the supplied information to set.
9543114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     */
9553114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    public void setPlaybackInformation(int what, int value) {
9563114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        synchronized(mCacheLock) {
9573114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi            switch (what) {
9583114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                case PLAYBACKINFO_PLAYBACK_TYPE:
9593114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                    if ((value >= PLAYBACK_TYPE_MIN) && (value <= PLAYBACK_TYPE_MAX)) {
9603114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                        if (mPlaybackType != value) {
9613114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                            mPlaybackType = value;
9623114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                            sendAudioServiceNewPlaybackInfo_syncCacheLock(what, value);
9633114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                        }
9643114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                    } else {
9653114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                        Log.w(TAG, "using invalid value for PLAYBACKINFO_PLAYBACK_TYPE");
9663114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                    }
9673114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                    break;
9683114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                case PLAYBACKINFO_VOLUME:
9693114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                    if ((value > -1) && (value <= mPlaybackVolumeMax)) {
9703114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                        if (mPlaybackVolume != value) {
9713114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                            mPlaybackVolume = value;
9723114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                            sendAudioServiceNewPlaybackInfo_syncCacheLock(what, value);
9733114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                        }
9743114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                    } else {
9753114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                        Log.w(TAG, "using invalid value for PLAYBACKINFO_VOLUME");
9763114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                    }
9773114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                    break;
9783114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                case PLAYBACKINFO_VOLUME_MAX:
9793114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                    if (value > 0) {
9803114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                        if (mPlaybackVolumeMax != value) {
9813114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                            mPlaybackVolumeMax = value;
9823114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                            sendAudioServiceNewPlaybackInfo_syncCacheLock(what, value);
9833114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                        }
9843114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                    } else {
9853114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                        Log.w(TAG, "using invalid value for PLAYBACKINFO_VOLUME_MAX");
9863114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                    }
9873114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                    break;
9883114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                case PLAYBACKINFO_USES_STREAM:
9893114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                    if ((value >= 0) && (value < AudioSystem.getNumStreamTypes())) {
9903114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                        mPlaybackStream = value;
9913114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                    } else {
9923114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                        Log.w(TAG, "using invalid value for PLAYBACKINFO_USES_STREAM");
9933114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                    }
9943114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                    break;
9953114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                case PLAYBACKINFO_VOLUME_HANDLING:
9963114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                    if ((value >= PLAYBACK_VOLUME_FIXED) && (value <= PLAYBACK_VOLUME_VARIABLE)) {
9973114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                        if (mPlaybackVolumeHandling != value) {
9983114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                            mPlaybackVolumeHandling = value;
9993114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                            sendAudioServiceNewPlaybackInfo_syncCacheLock(what, value);
10003114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                        }
10013114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                    } else {
10023114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                        Log.w(TAG, "using invalid value for PLAYBACKINFO_VOLUME_HANDLING");
10033114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                    }
10043114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                    break;
10053114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                default:
10063114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                    // not throwing an exception or returning an error if more keys are to be
10073114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                    // supported in the future
10083114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                    Log.w(TAG, "setPlaybackInformation() ignoring unknown key " + what);
10093114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                    break;
10103114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi            }
10113114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        }
10123114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    }
10133114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi
10143114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    /**
10151357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi     * @hide
10163114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     * Return playback information represented as an integer value.
10173114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     * @param what a key to specify the type of information to retrieve. Valid keys are
10183114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     *        {@link #PLAYBACKINFO_PLAYBACK_TYPE},
10193114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     *        {@link #PLAYBACKINFO_USES_STREAM},
10203114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     *        {@link #PLAYBACKINFO_VOLUME},
10213114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     *        {@link #PLAYBACKINFO_VOLUME_MAX},
10223114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     *        and {@link #PLAYBACKINFO_VOLUME_HANDLING}.
10233114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     * @return the current value for the given information type, or
10243114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     *   {@link #PLAYBACKINFO_INVALID_VALUE} if an error occurred or the request is invalid, or
10253114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     *   the value is unknown.
10263114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     */
10273114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    public int getIntPlaybackInformation(int what) {
10283114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        synchronized(mCacheLock) {
10293114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi            switch (what) {
10303114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                case PLAYBACKINFO_PLAYBACK_TYPE:
10313114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                    return mPlaybackType;
10323114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                case PLAYBACKINFO_VOLUME:
10333114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                    return mPlaybackVolume;
10343114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                case PLAYBACKINFO_VOLUME_MAX:
10353114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                    return mPlaybackVolumeMax;
10363114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                case PLAYBACKINFO_USES_STREAM:
10373114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                    return mPlaybackStream;
10383114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                case PLAYBACKINFO_VOLUME_HANDLING:
10393114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                    return mPlaybackVolumeHandling;
10403114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                default:
10413114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                    Log.e(TAG, "getIntPlaybackInformation() unknown key " + what);
10423114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                    return PLAYBACKINFO_INVALID_VALUE;
10433114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi            }
10443114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        }
10453114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    }
10463114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi
1047178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi    /**
10484426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     * Lock for all cached data
10494426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     */
10504426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    private final Object mCacheLock = new Object();
10514426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    /**
10524426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     * Cache for the playback state.
10534426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     * Access synchronized on mCacheLock
1054178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     */
10554426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    private int mPlaybackState = PLAYSTATE_NONE;
10564426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    /**
105768622396b62f9084781add1e12f4d513b633ab54Jean-Michel Trivi     * Time of last play state change
105868622396b62f9084781add1e12f4d513b633ab54Jean-Michel Trivi     * Access synchronized on mCacheLock
105968622396b62f9084781add1e12f4d513b633ab54Jean-Michel Trivi     */
106068622396b62f9084781add1e12f4d513b633ab54Jean-Michel Trivi    private long mPlaybackStateChangeTimeMs = 0;
106168622396b62f9084781add1e12f4d513b633ab54Jean-Michel Trivi    /**
1062bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi     * Last playback position in ms reported by the user
1063bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi     */
1064bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi    private long mPlaybackPositionMs = PLAYBACK_POSITION_INVALID;
1065bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi    /**
1066bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi     * Last playback speed reported by the user
1067bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi     */
1068bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi    private float mPlaybackSpeed = PLAYBACK_SPEED_1X;
1069bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi    /**
10704426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     * Cache for the artwork bitmap.
10714426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     * Access synchronized on mCacheLock
10724da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi     * Artwork and metadata are not kept in one Bundle because the bitmap sometimes needs to be
10734da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi     * accessed to be resized, in which case a copy will be made. This would add overhead in
10744da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi     * Bundle operations.
10754426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     */
10764a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi    private Bitmap mOriginalArtwork;
10774426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    /**
10784426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     * Cache for the transport control mask.
10794426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     * Access synchronized on mCacheLock
10804426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     */
10814426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    private int mTransportControlFlags = FLAGS_KEY_MEDIA_NONE;
10824426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    /**
10834426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     * Cache for the metadata strings.
10844426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     * Access synchronized on mCacheLock
108530c918ce7fbe171944b28fc91b3f22b3d631872dGlenn Kasten     * This is re-initialized in apply() and so cannot be final.
10864426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     */
10874426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    private Bundle mMetadata = new Bundle();
10884426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    /**
1089bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi     * Listener registered by user of RemoteControlClient to receive requests for playback position
1090bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi     * update requests.
1091bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi     */
1092bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi    private OnPlaybackPositionUpdateListener mPositionUpdateListener;
1093bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi    /**
10943261b537c5fdec824575a1f6ad6d8942715e82e2Jean-Michel Trivi     * Provider registered by user of RemoteControlClient to provide the current playback position.
10953261b537c5fdec824575a1f6ad6d8942715e82e2Jean-Michel Trivi     */
1096915747730060dff71b5b2ca7e4ee4073024fc24eJean-Michel Trivi    private OnGetPlaybackPositionListener mPositionProvider;
10973261b537c5fdec824575a1f6ad6d8942715e82e2Jean-Michel Trivi    /**
1098f823fc4dba2df5cf5f00e13361f2db93c81f6961Jean-Michel Trivi     * Listener registered by user of RemoteControlClient to receive edit changes to metadata
1099f823fc4dba2df5cf5f00e13361f2db93c81f6961Jean-Michel Trivi     * it exposes.
1100f823fc4dba2df5cf5f00e13361f2db93c81f6961Jean-Michel Trivi     */
1101f823fc4dba2df5cf5f00e13361f2db93c81f6961Jean-Michel Trivi    private OnMetadataUpdateListener mMetadataUpdateListener;
1102f823fc4dba2df5cf5f00e13361f2db93c81f6961Jean-Michel Trivi    /**
1103bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi     * The current remote control client generation ID across the system, as known by this object
11044426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     */
11054426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    private int mCurrentClientGenId = -1;
11064426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    /**
11074426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     * The remote control client generation ID, the last time it was told it was the current RC.
11084426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     * If (mCurrentClientGenId == mInternalClientGenId) is true, it means that this remote control
11094426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     * client is the "focused" one, and that whenever this client's info is updated, it needs to
11104426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     * send it to the known IRemoteControlDisplay interfaces.
11114426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     */
11124426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    private int mInternalClientGenId = -2;
11134426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi
11144426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    /**
1115f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi     * The media button intent description associated with this remote control client
1116bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi     * (can / should include target component for intent handling, used when persisting media
1117bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi     *    button event receiver across reboots).
11184426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     */
1119f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi    private final PendingIntent mRcMediaIntent;
11204426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi
11214426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    /**
1122c3c4babf8424f65b3d3d2700f60fae6e94e9cd00Jean-Michel Trivi     * Reflects whether any "plugged in" IRemoteControlDisplay has mWantsPositonSync set to true.
1123c3c4babf8424f65b3d3d2700f60fae6e94e9cd00Jean-Michel Trivi     */
1124c3c4babf8424f65b3d3d2700f60fae6e94e9cd00Jean-Michel Trivi    // TODO consider using a ref count for IRemoteControlDisplay requiring sync instead
1125c3c4babf8424f65b3d3d2700f60fae6e94e9cd00Jean-Michel Trivi    private boolean mNeedsPositionSync = false;
1126c3c4babf8424f65b3d3d2700f60fae6e94e9cd00Jean-Michel Trivi
1127c3c4babf8424f65b3d3d2700f60fae6e94e9cd00Jean-Michel Trivi    /**
1128f1372428f2df781c71c71caa2f6a4db6f847cf10RoboErik     * Cache for the current playback state using Session APIs.
1129f1372428f2df781c71c71caa2f6a4db6f847cf10RoboErik     */
1130f1372428f2df781c71c71caa2f6a4db6f847cf10RoboErik    private final PlaybackState mSessionPlaybackState = new PlaybackState();
1131f1372428f2df781c71c71caa2f6a4db6f847cf10RoboErik
1132f1372428f2df781c71c71caa2f6a4db6f847cf10RoboErik    /**
1133f1372428f2df781c71c71caa2f6a4db6f847cf10RoboErik     * Cache for metadata using Session APIs. This is re-initialized in apply().
1134f1372428f2df781c71c71caa2f6a4db6f847cf10RoboErik     */
1135f1372428f2df781c71c71caa2f6a4db6f847cf10RoboErik    private MediaMetadata mMediaMetadata;
1136f1372428f2df781c71c71caa2f6a4db6f847cf10RoboErik
1137f1372428f2df781c71c71caa2f6a4db6f847cf10RoboErik    /**
11384a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi     * A class to encapsulate all the information about a remote control display.
11394a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi     * A RemoteControlClient's metadata and state may be displayed on multiple IRemoteControlDisplay
11404a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi     */
11414a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi    private class DisplayInfoForClient {
11424a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi        /** may never be null */
11434a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi        private IRemoteControlDisplay mRcDisplay;
11444a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi        private int mArtworkExpectedWidth;
11454a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi        private int mArtworkExpectedHeight;
1146c3c4babf8424f65b3d3d2700f60fae6e94e9cd00Jean-Michel Trivi        private boolean mWantsPositionSync = false;
1147f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi        private boolean mEnabled = true;
11484a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi
11494a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi        DisplayInfoForClient(IRemoteControlDisplay rcd, int w, int h) {
11504a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi            mRcDisplay = rcd;
11514a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi            mArtworkExpectedWidth = w;
11524a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi            mArtworkExpectedHeight = h;
11534a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi        }
11544a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi    }
11554a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi
11564a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi    /**
11574a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi     * The list of remote control displays to which this client will send information.
11584a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi     * Accessed and modified synchronized on mCacheLock
11594426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     */
11604a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi    private ArrayList<DisplayInfoForClient> mRcDisplays = new ArrayList<DisplayInfoForClient>(1);
11614426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi
11624426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    /**
11634426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     * @hide
1164f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi     * Accessor to media button intent description (includes target component)
11654426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     */
1166f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi    public PendingIntent getRcMediaIntent() {
1167f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi        return mRcMediaIntent;
11684426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    }
11694426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    /**
11704426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     * @hide
11714426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     * Accessor to IRemoteControlClient
11724426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     */
11734426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    public IRemoteControlClient getIRemoteControlClient() {
11744426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi        return mIRCC;
11754426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    }
11764426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi
11774426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    /**
11784426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     * The IRemoteControlClient implementation
11794426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     */
118030c918ce7fbe171944b28fc91b3f22b3d631872dGlenn Kasten    private final IRemoteControlClient mIRCC = new IRemoteControlClient.Stub() {
11814426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi
118286142da1ce8c1341404a9f9e21be8acbcba69ab3Jean-Michel Trivi        //TODO change name to informationRequestForAllDisplays()
11833261b537c5fdec824575a1f6ad6d8942715e82e2Jean-Michel Trivi        public void onInformationRequested(int generationId, int infoFlags) {
11844426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi            // only post messages, we can't block here
11854426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi            if (mEventHandler != null) {
11864426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi                // signal new client
11874426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi                mEventHandler.removeMessages(MSG_NEW_INTERNAL_CLIENT_GEN);
118805e7c2ff8cd6b6386d8c553995c2d12075833e4aJean-Michel Trivi                mEventHandler.sendMessage(
11894a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi                        mEventHandler.obtainMessage(MSG_NEW_INTERNAL_CLIENT_GEN,
11903261b537c5fdec824575a1f6ad6d8942715e82e2Jean-Michel Trivi                                /*arg1*/ generationId, /*arg2, ignored*/ 0));
11914426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi                // send the information
11924426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi                mEventHandler.removeMessages(MSG_REQUEST_PLAYBACK_STATE);
11934426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi                mEventHandler.removeMessages(MSG_REQUEST_METADATA);
11944426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi                mEventHandler.removeMessages(MSG_REQUEST_TRANSPORTCONTROL);
11954426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi                mEventHandler.removeMessages(MSG_REQUEST_ARTWORK);
119686142da1ce8c1341404a9f9e21be8acbcba69ab3Jean-Michel Trivi                mEventHandler.removeMessages(MSG_REQUEST_METADATA_ARTWORK);
119705e7c2ff8cd6b6386d8c553995c2d12075833e4aJean-Michel Trivi                mEventHandler.sendMessage(
119886142da1ce8c1341404a9f9e21be8acbcba69ab3Jean-Michel Trivi                        mEventHandler.obtainMessage(MSG_REQUEST_PLAYBACK_STATE, null));
119905e7c2ff8cd6b6386d8c553995c2d12075833e4aJean-Michel Trivi                mEventHandler.sendMessage(
120086142da1ce8c1341404a9f9e21be8acbcba69ab3Jean-Michel Trivi                        mEventHandler.obtainMessage(MSG_REQUEST_TRANSPORTCONTROL, null));
120186142da1ce8c1341404a9f9e21be8acbcba69ab3Jean-Michel Trivi                mEventHandler.sendMessage(mEventHandler.obtainMessage(MSG_REQUEST_METADATA_ARTWORK,
120286142da1ce8c1341404a9f9e21be8acbcba69ab3Jean-Michel Trivi                        0, 0, null));
120386142da1ce8c1341404a9f9e21be8acbcba69ab3Jean-Michel Trivi            }
120486142da1ce8c1341404a9f9e21be8acbcba69ab3Jean-Michel Trivi        }
120586142da1ce8c1341404a9f9e21be8acbcba69ab3Jean-Michel Trivi
120686142da1ce8c1341404a9f9e21be8acbcba69ab3Jean-Michel Trivi        public void informationRequestForDisplay(IRemoteControlDisplay rcd, int w, int h) {
120786142da1ce8c1341404a9f9e21be8acbcba69ab3Jean-Michel Trivi            // only post messages, we can't block here
120886142da1ce8c1341404a9f9e21be8acbcba69ab3Jean-Michel Trivi            if (mEventHandler != null) {
120986142da1ce8c1341404a9f9e21be8acbcba69ab3Jean-Michel Trivi                mEventHandler.sendMessage(
121086142da1ce8c1341404a9f9e21be8acbcba69ab3Jean-Michel Trivi                        mEventHandler.obtainMessage(MSG_REQUEST_TRANSPORTCONTROL, rcd));
121186142da1ce8c1341404a9f9e21be8acbcba69ab3Jean-Michel Trivi                mEventHandler.sendMessage(
121286142da1ce8c1341404a9f9e21be8acbcba69ab3Jean-Michel Trivi                        mEventHandler.obtainMessage(MSG_REQUEST_PLAYBACK_STATE, rcd));
121386142da1ce8c1341404a9f9e21be8acbcba69ab3Jean-Michel Trivi                if ((w > 0) && (h > 0)) {
121486142da1ce8c1341404a9f9e21be8acbcba69ab3Jean-Michel Trivi                    mEventHandler.sendMessage(
121586142da1ce8c1341404a9f9e21be8acbcba69ab3Jean-Michel Trivi                            mEventHandler.obtainMessage(MSG_REQUEST_METADATA_ARTWORK, w, h, rcd));
121686142da1ce8c1341404a9f9e21be8acbcba69ab3Jean-Michel Trivi                } else {
121786142da1ce8c1341404a9f9e21be8acbcba69ab3Jean-Michel Trivi                    mEventHandler.sendMessage(
121886142da1ce8c1341404a9f9e21be8acbcba69ab3Jean-Michel Trivi                            mEventHandler.obtainMessage(MSG_REQUEST_METADATA, rcd));
121986142da1ce8c1341404a9f9e21be8acbcba69ab3Jean-Michel Trivi                }
12204426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi            }
12214426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi        }
12224426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi
12234426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi        public void setCurrentClientGenerationId(int clientGeneration) {
12244426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi            // only post messages, we can't block here
12254426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi            if (mEventHandler != null) {
12264426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi                mEventHandler.removeMessages(MSG_NEW_CURRENT_CLIENT_GEN);
122705e7c2ff8cd6b6386d8c553995c2d12075833e4aJean-Michel Trivi                mEventHandler.sendMessage(mEventHandler.obtainMessage(
12284426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi                        MSG_NEW_CURRENT_CLIENT_GEN, clientGeneration, 0/*ignored*/));
12294426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi            }
12304426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi        }
12314426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi
12324a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi        public void plugRemoteControlDisplay(IRemoteControlDisplay rcd, int w, int h) {
12334426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi            // only post messages, we can't block here
12344a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi            if ((mEventHandler != null) && (rcd != null)) {
123505e7c2ff8cd6b6386d8c553995c2d12075833e4aJean-Michel Trivi                mEventHandler.sendMessage(mEventHandler.obtainMessage(
12364a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi                        MSG_PLUG_DISPLAY, w, h, rcd));
12374426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi            }
12384426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi        }
12394426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi
12404426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi        public void unplugRemoteControlDisplay(IRemoteControlDisplay rcd) {
12414426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi            // only post messages, we can't block here
12424a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi            if ((mEventHandler != null) && (rcd != null)) {
124305e7c2ff8cd6b6386d8c553995c2d12075833e4aJean-Michel Trivi                mEventHandler.sendMessage(mEventHandler.obtainMessage(
12444426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi                        MSG_UNPLUG_DISPLAY, rcd));
12454426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi            }
12464426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi        }
12474a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi
12484a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi        public void setBitmapSizeForDisplay(IRemoteControlDisplay rcd, int w, int h) {
12494a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi            // only post messages, we can't block here
12504a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi            if ((mEventHandler != null) && (rcd != null)) {
125105e7c2ff8cd6b6386d8c553995c2d12075833e4aJean-Michel Trivi                mEventHandler.sendMessage(mEventHandler.obtainMessage(
12524a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi                        MSG_UPDATE_DISPLAY_ARTWORK_SIZE, w, h, rcd));
12534a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi            }
12544a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi        }
12553261b537c5fdec824575a1f6ad6d8942715e82e2Jean-Michel Trivi
1256c3c4babf8424f65b3d3d2700f60fae6e94e9cd00Jean-Michel Trivi        public void setWantsSyncForDisplay(IRemoteControlDisplay rcd, boolean wantsSync) {
1257c3c4babf8424f65b3d3d2700f60fae6e94e9cd00Jean-Michel Trivi            // only post messages, we can't block here
1258c3c4babf8424f65b3d3d2700f60fae6e94e9cd00Jean-Michel Trivi            if ((mEventHandler != null) && (rcd != null)) {
1259c3c4babf8424f65b3d3d2700f60fae6e94e9cd00Jean-Michel Trivi                mEventHandler.sendMessage(mEventHandler.obtainMessage(
1260c3c4babf8424f65b3d3d2700f60fae6e94e9cd00Jean-Michel Trivi                        MSG_DISPLAY_WANTS_POS_SYNC, wantsSync ? 1 : 0, 0/*arg2 ignored*/, rcd));
1261c3c4babf8424f65b3d3d2700f60fae6e94e9cd00Jean-Michel Trivi            }
1262c3c4babf8424f65b3d3d2700f60fae6e94e9cd00Jean-Michel Trivi        }
1263c3c4babf8424f65b3d3d2700f60fae6e94e9cd00Jean-Michel Trivi
1264f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi        public void enableRemoteControlDisplay(IRemoteControlDisplay rcd, boolean enabled) {
1265f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi            // only post messages, we can't block here
1266f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi            if ((mEventHandler != null) && (rcd != null)) {
1267f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi                mEventHandler.sendMessage(mEventHandler.obtainMessage(
1268f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi                        MSG_DISPLAY_ENABLE, enabled ? 1 : 0, 0/*arg2 ignored*/, rcd));
1269f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi            }
1270f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi        }
1271f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi
12723261b537c5fdec824575a1f6ad6d8942715e82e2Jean-Michel Trivi        public void seekTo(int generationId, long timeMs) {
12733261b537c5fdec824575a1f6ad6d8942715e82e2Jean-Michel Trivi            // only post messages, we can't block here
12743261b537c5fdec824575a1f6ad6d8942715e82e2Jean-Michel Trivi            if (mEventHandler != null) {
12753261b537c5fdec824575a1f6ad6d8942715e82e2Jean-Michel Trivi                mEventHandler.removeMessages(MSG_SEEK_TO);
127605e7c2ff8cd6b6386d8c553995c2d12075833e4aJean-Michel Trivi                mEventHandler.sendMessage(mEventHandler.obtainMessage(
12773261b537c5fdec824575a1f6ad6d8942715e82e2Jean-Michel Trivi                        MSG_SEEK_TO, generationId /* arg1 */, 0 /* arg2, ignored */,
12783261b537c5fdec824575a1f6ad6d8942715e82e2Jean-Michel Trivi                        new Long(timeMs)));
12793261b537c5fdec824575a1f6ad6d8942715e82e2Jean-Michel Trivi            }
12803261b537c5fdec824575a1f6ad6d8942715e82e2Jean-Michel Trivi        }
1281f823fc4dba2df5cf5f00e13361f2db93c81f6961Jean-Michel Trivi
128288183e67d4628e8c8a3310af0076b6f33f955cb2Jean-Michel Trivi        public void updateMetadata(int generationId, int key, Rating value) {
1283f823fc4dba2df5cf5f00e13361f2db93c81f6961Jean-Michel Trivi            // only post messages, we can't block here
1284f823fc4dba2df5cf5f00e13361f2db93c81f6961Jean-Michel Trivi            if (mEventHandler != null) {
1285f823fc4dba2df5cf5f00e13361f2db93c81f6961Jean-Michel Trivi                mEventHandler.sendMessage(mEventHandler.obtainMessage(
128688183e67d4628e8c8a3310af0076b6f33f955cb2Jean-Michel Trivi                        MSG_UPDATE_METADATA, generationId /* arg1 */, key /* arg2*/, value));
1287f823fc4dba2df5cf5f00e13361f2db93c81f6961Jean-Michel Trivi            }
1288f823fc4dba2df5cf5f00e13361f2db93c81f6961Jean-Michel Trivi        }
12894426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    };
12904426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi
12913114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    /**
12923114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     * @hide
12933114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     * Default value for the unique identifier
12943114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     */
12953114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    public final static int RCSE_ID_UNREGISTERED = -1;
12963114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    /**
12973114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     * Unique identifier of the RemoteControlStackEntry in AudioService with which
12983114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     * this RemoteControlClient is associated.
12993114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     */
13003114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    private int mRcseId = RCSE_ID_UNREGISTERED;
13013114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    /**
13023114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     * @hide
13033114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     * To be only used by AudioManager after it has received the unique id from
13043114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     * IAudioService.registerRemoteControlClient()
13053114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     * @param id the unique identifier of the RemoteControlStackEntry in AudioService with which
13063114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     *              this RemoteControlClient is associated.
13073114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     */
13083114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    public void setRcseId(int id) {
13093114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        mRcseId = id;
13103114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    }
13113114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi
13121357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi    /**
13131357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi     * @hide
13141357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi     */
13151357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi    public int getRcseId() {
13161357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi        return mRcseId;
13171357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi    }
13181357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi
1319f1372428f2df781c71c71caa2f6a4db6f847cf10RoboErik    // USE_SESSIONS
1320f1372428f2df781c71c71caa2f6a4db6f847cf10RoboErik    private TransportPerformer.Listener mTransportListener = new TransportPerformer.Listener() {
1321f1372428f2df781c71c71caa2f6a4db6f847cf10RoboErik
1322f1372428f2df781c71c71caa2f6a4db6f847cf10RoboErik        @Override
1323f1372428f2df781c71c71caa2f6a4db6f847cf10RoboErik        public void onSeekTo(long pos) {
1324f1372428f2df781c71c71caa2f6a4db6f847cf10RoboErik            RemoteControlClient.this.onSeekTo(mCurrentClientGenId, pos);
1325f1372428f2df781c71c71caa2f6a4db6f847cf10RoboErik        }
1326f1372428f2df781c71c71caa2f6a4db6f847cf10RoboErik
1327f1372428f2df781c71c71caa2f6a4db6f847cf10RoboErik        @Override
1328f1372428f2df781c71c71caa2f6a4db6f847cf10RoboErik        public void onRate(Rating rating) {
1329f1372428f2df781c71c71caa2f6a4db6f847cf10RoboErik            if ((mTransportControlFlags & FLAG_KEY_MEDIA_RATING) != 0) {
1330f1372428f2df781c71c71caa2f6a4db6f847cf10RoboErik                if (mEventHandler != null) {
1331f1372428f2df781c71c71caa2f6a4db6f847cf10RoboErik                    mEventHandler.sendMessage(mEventHandler.obtainMessage(
1332f1372428f2df781c71c71caa2f6a4db6f847cf10RoboErik                            MSG_UPDATE_METADATA, mCurrentClientGenId,
1333f1372428f2df781c71c71caa2f6a4db6f847cf10RoboErik                            MetadataEditor.RATING_KEY_BY_USER, rating));
1334f1372428f2df781c71c71caa2f6a4db6f847cf10RoboErik                }
1335f1372428f2df781c71c71caa2f6a4db6f847cf10RoboErik            }
1336f1372428f2df781c71c71caa2f6a4db6f847cf10RoboErik        }
1337f1372428f2df781c71c71caa2f6a4db6f847cf10RoboErik    };
1338f1372428f2df781c71c71caa2f6a4db6f847cf10RoboErik
13394426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    private EventHandler mEventHandler;
13404426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    private final static int MSG_REQUEST_PLAYBACK_STATE = 1;
13414426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    private final static int MSG_REQUEST_METADATA = 2;
13424426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    private final static int MSG_REQUEST_TRANSPORTCONTROL = 3;
13434426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    private final static int MSG_REQUEST_ARTWORK = 4;
13444426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    private final static int MSG_NEW_INTERNAL_CLIENT_GEN = 5;
13454426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    private final static int MSG_NEW_CURRENT_CLIENT_GEN = 6;
13464426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    private final static int MSG_PLUG_DISPLAY = 7;
13474426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    private final static int MSG_UNPLUG_DISPLAY = 8;
13484a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi    private final static int MSG_UPDATE_DISPLAY_ARTWORK_SIZE = 9;
13493261b537c5fdec824575a1f6ad6d8942715e82e2Jean-Michel Trivi    private final static int MSG_SEEK_TO = 10;
1350521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi    private final static int MSG_POSITION_DRIFT_CHECK = 11;
1351c3c4babf8424f65b3d3d2700f60fae6e94e9cd00Jean-Michel Trivi    private final static int MSG_DISPLAY_WANTS_POS_SYNC = 12;
135288183e67d4628e8c8a3310af0076b6f33f955cb2Jean-Michel Trivi    private final static int MSG_UPDATE_METADATA = 13;
135386142da1ce8c1341404a9f9e21be8acbcba69ab3Jean-Michel Trivi    private final static int MSG_REQUEST_METADATA_ARTWORK = 14;
1354f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi    private final static int MSG_DISPLAY_ENABLE = 15;
13554426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi
13564426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    private class EventHandler extends Handler {
13574426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi        public EventHandler(RemoteControlClient rcc, Looper looper) {
13584426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi            super(looper);
13594426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi        }
13604426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi
13614426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi        @Override
13624426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi        public void handleMessage(Message msg) {
13634426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi            switch(msg.what) {
13644426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi                case MSG_REQUEST_PLAYBACK_STATE:
13654426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi                    synchronized (mCacheLock) {
136686142da1ce8c1341404a9f9e21be8acbcba69ab3Jean-Michel Trivi                        sendPlaybackState_syncCacheLock((IRemoteControlDisplay)msg.obj);
13674426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi                    }
13684426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi                    break;
13694426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi                case MSG_REQUEST_METADATA:
13704426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi                    synchronized (mCacheLock) {
137186142da1ce8c1341404a9f9e21be8acbcba69ab3Jean-Michel Trivi                        sendMetadata_syncCacheLock((IRemoteControlDisplay)msg.obj);
13724426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi                    }
13734426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi                    break;
13744426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi                case MSG_REQUEST_TRANSPORTCONTROL:
13754426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi                    synchronized (mCacheLock) {
137686142da1ce8c1341404a9f9e21be8acbcba69ab3Jean-Michel Trivi                        sendTransportControlInfo_syncCacheLock((IRemoteControlDisplay)msg.obj);
13774426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi                    }
13784426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi                    break;
13794426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi                case MSG_REQUEST_ARTWORK:
13804426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi                    synchronized (mCacheLock) {
138186142da1ce8c1341404a9f9e21be8acbcba69ab3Jean-Michel Trivi                        sendArtwork_syncCacheLock((IRemoteControlDisplay)msg.obj,
138286142da1ce8c1341404a9f9e21be8acbcba69ab3Jean-Michel Trivi                                msg.arg1, msg.arg2);
138386142da1ce8c1341404a9f9e21be8acbcba69ab3Jean-Michel Trivi                    }
138486142da1ce8c1341404a9f9e21be8acbcba69ab3Jean-Michel Trivi                    break;
138586142da1ce8c1341404a9f9e21be8acbcba69ab3Jean-Michel Trivi                case MSG_REQUEST_METADATA_ARTWORK:
138686142da1ce8c1341404a9f9e21be8acbcba69ab3Jean-Michel Trivi                    synchronized (mCacheLock) {
138786142da1ce8c1341404a9f9e21be8acbcba69ab3Jean-Michel Trivi                        sendMetadataWithArtwork_syncCacheLock((IRemoteControlDisplay)msg.obj,
138886142da1ce8c1341404a9f9e21be8acbcba69ab3Jean-Michel Trivi                                msg.arg1, msg.arg2);
13894426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi                    }
13904426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi                    break;
13914426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi                case MSG_NEW_INTERNAL_CLIENT_GEN:
13924a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi                    onNewInternalClientGen(msg.arg1);
13934426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi                    break;
13944426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi                case MSG_NEW_CURRENT_CLIENT_GEN:
13954426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi                    onNewCurrentClientGen(msg.arg1);
13964426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi                    break;
13974426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi                case MSG_PLUG_DISPLAY:
13984a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi                    onPlugDisplay((IRemoteControlDisplay)msg.obj, msg.arg1, msg.arg2);
13994426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi                    break;
14004426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi                case MSG_UNPLUG_DISPLAY:
14014426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi                    onUnplugDisplay((IRemoteControlDisplay)msg.obj);
14024426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi                    break;
14034a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi                case MSG_UPDATE_DISPLAY_ARTWORK_SIZE:
14044a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi                    onUpdateDisplayArtworkSize((IRemoteControlDisplay)msg.obj, msg.arg1, msg.arg2);
14054a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi                    break;
14063261b537c5fdec824575a1f6ad6d8942715e82e2Jean-Michel Trivi                case MSG_SEEK_TO:
14073261b537c5fdec824575a1f6ad6d8942715e82e2Jean-Michel Trivi                    onSeekTo(msg.arg1, ((Long)msg.obj).longValue());
140805e7c2ff8cd6b6386d8c553995c2d12075833e4aJean-Michel Trivi                    break;
1409521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi                case MSG_POSITION_DRIFT_CHECK:
1410521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi                    onPositionDriftCheck();
1411521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi                    break;
1412c3c4babf8424f65b3d3d2700f60fae6e94e9cd00Jean-Michel Trivi                case MSG_DISPLAY_WANTS_POS_SYNC:
1413c3c4babf8424f65b3d3d2700f60fae6e94e9cd00Jean-Michel Trivi                    onDisplayWantsSync((IRemoteControlDisplay)msg.obj, msg.arg1 == 1);
1414c3c4babf8424f65b3d3d2700f60fae6e94e9cd00Jean-Michel Trivi                    break;
141588183e67d4628e8c8a3310af0076b6f33f955cb2Jean-Michel Trivi                case MSG_UPDATE_METADATA:
141688183e67d4628e8c8a3310af0076b6f33f955cb2Jean-Michel Trivi                    onUpdateMetadata(msg.arg1, msg.arg2, msg.obj);
1417f823fc4dba2df5cf5f00e13361f2db93c81f6961Jean-Michel Trivi                    break;
1418f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi                case MSG_DISPLAY_ENABLE:
1419f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi                    onDisplayEnable((IRemoteControlDisplay)msg.obj, msg.arg1 == 1);
1420f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi                    break;
14214426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi                default:
14224426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi                    Log.e(TAG, "Unknown event " + msg.what + " in RemoteControlClient handler");
14234426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi            }
14244426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi        }
14254426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    }
14264426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi
14273114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    //===========================================================
14284a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi    // Communication with the IRemoteControlDisplay (the displays known to the system)
142944413e5b514a91806a4bb4c7780029ea43be6f81Jean-Michel Trivi
143086142da1ce8c1341404a9f9e21be8acbcba69ab3Jean-Michel Trivi    private void sendPlaybackState_syncCacheLock(IRemoteControlDisplay target) {
14314a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi        if (mCurrentClientGenId == mInternalClientGenId) {
143286142da1ce8c1341404a9f9e21be8acbcba69ab3Jean-Michel Trivi            if (target != null) {
143386142da1ce8c1341404a9f9e21be8acbcba69ab3Jean-Michel Trivi                try {
143486142da1ce8c1341404a9f9e21be8acbcba69ab3Jean-Michel Trivi                    target.setPlaybackState(mInternalClientGenId,
143586142da1ce8c1341404a9f9e21be8acbcba69ab3Jean-Michel Trivi                            mPlaybackState, mPlaybackStateChangeTimeMs, mPlaybackPositionMs,
143686142da1ce8c1341404a9f9e21be8acbcba69ab3Jean-Michel Trivi                            mPlaybackSpeed);
143786142da1ce8c1341404a9f9e21be8acbcba69ab3Jean-Michel Trivi                } catch (RemoteException e) {
143886142da1ce8c1341404a9f9e21be8acbcba69ab3Jean-Michel Trivi                    Log.e(TAG, "Error in setPlaybackState() for dead display " + target, e);
143986142da1ce8c1341404a9f9e21be8acbcba69ab3Jean-Michel Trivi                }
144086142da1ce8c1341404a9f9e21be8acbcba69ab3Jean-Michel Trivi                return;
144186142da1ce8c1341404a9f9e21be8acbcba69ab3Jean-Michel Trivi            }
144286142da1ce8c1341404a9f9e21be8acbcba69ab3Jean-Michel Trivi            // target == null implies all displays must be updated
14434a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi            final Iterator<DisplayInfoForClient> displayIterator = mRcDisplays.iterator();
14444a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi            while (displayIterator.hasNext()) {
1445f1372428f2df781c71c71caa2f6a4db6f847cf10RoboErik                final DisplayInfoForClient di = displayIterator.next();
1446f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi                if (di.mEnabled) {
1447f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi                    try {
1448f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi                        di.mRcDisplay.setPlaybackState(mInternalClientGenId,
1449f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi                                mPlaybackState, mPlaybackStateChangeTimeMs, mPlaybackPositionMs,
1450f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi                                mPlaybackSpeed);
1451f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi                    } catch (RemoteException e) {
1452f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi                        Log.e(TAG, "Error in setPlaybackState(), dead display " + di.mRcDisplay, e);
1453f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi                        displayIterator.remove();
1454f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi                    }
14554a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi                }
14564426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi            }
14574426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi        }
14584426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    }
14594426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi
146086142da1ce8c1341404a9f9e21be8acbcba69ab3Jean-Michel Trivi    private void sendMetadata_syncCacheLock(IRemoteControlDisplay target) {
14614a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi        if (mCurrentClientGenId == mInternalClientGenId) {
146286142da1ce8c1341404a9f9e21be8acbcba69ab3Jean-Michel Trivi            if (target != null) {
146386142da1ce8c1341404a9f9e21be8acbcba69ab3Jean-Michel Trivi                try {
146486142da1ce8c1341404a9f9e21be8acbcba69ab3Jean-Michel Trivi                    target.setMetadata(mInternalClientGenId, mMetadata);
146586142da1ce8c1341404a9f9e21be8acbcba69ab3Jean-Michel Trivi                } catch (RemoteException e) {
146686142da1ce8c1341404a9f9e21be8acbcba69ab3Jean-Michel Trivi                    Log.e(TAG, "Error in setMetadata() for dead display " + target, e);
146786142da1ce8c1341404a9f9e21be8acbcba69ab3Jean-Michel Trivi                }
146886142da1ce8c1341404a9f9e21be8acbcba69ab3Jean-Michel Trivi                return;
146986142da1ce8c1341404a9f9e21be8acbcba69ab3Jean-Michel Trivi            }
147086142da1ce8c1341404a9f9e21be8acbcba69ab3Jean-Michel Trivi            // target == null implies all displays must be updated
14714a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi            final Iterator<DisplayInfoForClient> displayIterator = mRcDisplays.iterator();
14724a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi            while (displayIterator.hasNext()) {
1473f1372428f2df781c71c71caa2f6a4db6f847cf10RoboErik                final DisplayInfoForClient di = displayIterator.next();
1474f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi                if (di.mEnabled) {
1475f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi                    try {
1476f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi                        di.mRcDisplay.setMetadata(mInternalClientGenId, mMetadata);
1477f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi                    } catch (RemoteException e) {
1478f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi                        Log.e(TAG, "Error in setMetadata(), dead display " + di.mRcDisplay, e);
1479f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi                        displayIterator.remove();
1480f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi                    }
14814a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi                }
14824426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi            }
14834426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi        }
14844426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    }
14854426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi
148686142da1ce8c1341404a9f9e21be8acbcba69ab3Jean-Michel Trivi    private void sendTransportControlInfo_syncCacheLock(IRemoteControlDisplay target) {
14874a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi        if (mCurrentClientGenId == mInternalClientGenId) {
148886142da1ce8c1341404a9f9e21be8acbcba69ab3Jean-Michel Trivi            if (target != null) {
148986142da1ce8c1341404a9f9e21be8acbcba69ab3Jean-Michel Trivi                try {
149086142da1ce8c1341404a9f9e21be8acbcba69ab3Jean-Michel Trivi                    target.setTransportControlInfo(mInternalClientGenId,
149186142da1ce8c1341404a9f9e21be8acbcba69ab3Jean-Michel Trivi                            mTransportControlFlags, mPlaybackPositionCapabilities);
149286142da1ce8c1341404a9f9e21be8acbcba69ab3Jean-Michel Trivi                } catch (RemoteException e) {
149386142da1ce8c1341404a9f9e21be8acbcba69ab3Jean-Michel Trivi                    Log.e(TAG, "Error in setTransportControlFlags() for dead display " + target,
149486142da1ce8c1341404a9f9e21be8acbcba69ab3Jean-Michel Trivi                            e);
149586142da1ce8c1341404a9f9e21be8acbcba69ab3Jean-Michel Trivi                }
149686142da1ce8c1341404a9f9e21be8acbcba69ab3Jean-Michel Trivi                return;
149786142da1ce8c1341404a9f9e21be8acbcba69ab3Jean-Michel Trivi            }
149886142da1ce8c1341404a9f9e21be8acbcba69ab3Jean-Michel Trivi            // target == null implies all displays must be updated
14994a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi            final Iterator<DisplayInfoForClient> displayIterator = mRcDisplays.iterator();
15004a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi            while (displayIterator.hasNext()) {
1501f1372428f2df781c71c71caa2f6a4db6f847cf10RoboErik                final DisplayInfoForClient di = displayIterator.next();
1502f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi                if (di.mEnabled) {
1503f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi                    try {
1504f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi                        di.mRcDisplay.setTransportControlInfo(mInternalClientGenId,
1505f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi                                mTransportControlFlags, mPlaybackPositionCapabilities);
1506f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi                    } catch (RemoteException e) {
1507f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi                        Log.e(TAG, "Error in setTransportControlFlags(), dead display " + di.mRcDisplay,
1508f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi                                e);
1509f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi                        displayIterator.remove();
1510f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi                    }
15114a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi                }
15124426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi            }
15134426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi        }
15144426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    }
15154426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi
151686142da1ce8c1341404a9f9e21be8acbcba69ab3Jean-Michel Trivi    private void sendArtwork_syncCacheLock(IRemoteControlDisplay target, int w, int h) {
15174a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi        // FIXME modify to cache all requested sizes?
15184a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi        if (mCurrentClientGenId == mInternalClientGenId) {
151986142da1ce8c1341404a9f9e21be8acbcba69ab3Jean-Michel Trivi            if (target != null) {
152086142da1ce8c1341404a9f9e21be8acbcba69ab3Jean-Michel Trivi                final DisplayInfoForClient di = new DisplayInfoForClient(target, w, h);
152186142da1ce8c1341404a9f9e21be8acbcba69ab3Jean-Michel Trivi                sendArtworkToDisplay(di);
152286142da1ce8c1341404a9f9e21be8acbcba69ab3Jean-Michel Trivi                return;
152386142da1ce8c1341404a9f9e21be8acbcba69ab3Jean-Michel Trivi            }
152486142da1ce8c1341404a9f9e21be8acbcba69ab3Jean-Michel Trivi            // target == null implies all displays must be updated
15254a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi            final Iterator<DisplayInfoForClient> displayIterator = mRcDisplays.iterator();
15264a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi            while (displayIterator.hasNext()) {
1527f1372428f2df781c71c71caa2f6a4db6f847cf10RoboErik                if (!sendArtworkToDisplay(displayIterator.next())) {
15284a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi                    displayIterator.remove();
15294a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi                }
15304a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi            }
15314a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi        }
15324a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi    }
15334a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi
15344a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi    /**
15354a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi     * Send artwork to an IRemoteControlDisplay.
15364a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi     * @param di encapsulates the IRemoteControlDisplay that will receive the artwork, and its
15374a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi     *    dimension requirements.
15384a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi     * @return false if there was an error communicating with the IRemoteControlDisplay.
15394a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi     */
15404a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi    private boolean sendArtworkToDisplay(DisplayInfoForClient di) {
15414a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi        if ((di.mArtworkExpectedWidth > 0) && (di.mArtworkExpectedHeight > 0)) {
15424a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi            Bitmap artwork = scaleBitmapIfTooBig(mOriginalArtwork,
15434a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi                    di.mArtworkExpectedWidth, di.mArtworkExpectedHeight);
15444426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi            try {
15454a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi                di.mRcDisplay.setArtwork(mInternalClientGenId, artwork);
15464426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi            } catch (RemoteException e) {
15474a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi                Log.e(TAG, "Error in sendArtworkToDisplay(), dead display " + di.mRcDisplay, e);
15484a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi                return false;
154944413e5b514a91806a4bb4c7780029ea43be6f81Jean-Michel Trivi            }
155044413e5b514a91806a4bb4c7780029ea43be6f81Jean-Michel Trivi        }
15514a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi        return true;
155244413e5b514a91806a4bb4c7780029ea43be6f81Jean-Michel Trivi    }
155344413e5b514a91806a4bb4c7780029ea43be6f81Jean-Michel Trivi
155486142da1ce8c1341404a9f9e21be8acbcba69ab3Jean-Michel Trivi    private void sendMetadataWithArtwork_syncCacheLock(IRemoteControlDisplay target, int w, int h) {
15554a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi        // FIXME modify to cache all requested sizes?
15564a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi        if (mCurrentClientGenId == mInternalClientGenId) {
155786142da1ce8c1341404a9f9e21be8acbcba69ab3Jean-Michel Trivi            if (target != null) {
155886142da1ce8c1341404a9f9e21be8acbcba69ab3Jean-Michel Trivi                try {
155986142da1ce8c1341404a9f9e21be8acbcba69ab3Jean-Michel Trivi                    if ((w > 0) && (h > 0)) {
156086142da1ce8c1341404a9f9e21be8acbcba69ab3Jean-Michel Trivi                        Bitmap artwork = scaleBitmapIfTooBig(mOriginalArtwork, w, h);
156186142da1ce8c1341404a9f9e21be8acbcba69ab3Jean-Michel Trivi                        target.setAllMetadata(mInternalClientGenId, mMetadata, artwork);
156286142da1ce8c1341404a9f9e21be8acbcba69ab3Jean-Michel Trivi                    } else {
156386142da1ce8c1341404a9f9e21be8acbcba69ab3Jean-Michel Trivi                        target.setMetadata(mInternalClientGenId, mMetadata);
156486142da1ce8c1341404a9f9e21be8acbcba69ab3Jean-Michel Trivi                    }
156586142da1ce8c1341404a9f9e21be8acbcba69ab3Jean-Michel Trivi                } catch (RemoteException e) {
156686142da1ce8c1341404a9f9e21be8acbcba69ab3Jean-Michel Trivi                    Log.e(TAG, "Error in set(All)Metadata() for dead display " + target, e);
156786142da1ce8c1341404a9f9e21be8acbcba69ab3Jean-Michel Trivi                }
156886142da1ce8c1341404a9f9e21be8acbcba69ab3Jean-Michel Trivi                return;
156986142da1ce8c1341404a9f9e21be8acbcba69ab3Jean-Michel Trivi            }
157086142da1ce8c1341404a9f9e21be8acbcba69ab3Jean-Michel Trivi            // target == null implies all displays must be updated
15714a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi            final Iterator<DisplayInfoForClient> displayIterator = mRcDisplays.iterator();
15724a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi            while (displayIterator.hasNext()) {
1573f1372428f2df781c71c71caa2f6a4db6f847cf10RoboErik                final DisplayInfoForClient di = displayIterator.next();
15744a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi                try {
1575f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi                    if (di.mEnabled) {
1576f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi                        if ((di.mArtworkExpectedWidth > 0) && (di.mArtworkExpectedHeight > 0)) {
1577f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi                            Bitmap artwork = scaleBitmapIfTooBig(mOriginalArtwork,
1578f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi                                    di.mArtworkExpectedWidth, di.mArtworkExpectedHeight);
1579f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi                            di.mRcDisplay.setAllMetadata(mInternalClientGenId, mMetadata, artwork);
1580f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi                        } else {
1581f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi                            di.mRcDisplay.setMetadata(mInternalClientGenId, mMetadata);
1582f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi                        }
15834a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi                    }
15844a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi                } catch (RemoteException e) {
15854a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi                    Log.e(TAG, "Error when setting metadata, dead display " + di.mRcDisplay, e);
15864a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi                    displayIterator.remove();
15874a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi                }
15884426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi            }
15894426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi        }
15904426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    }
15914426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi
15923114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    //===========================================================
15933114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    // Communication with AudioService
15943114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi
15953114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    private static IAudioService sService;
15963114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi
15973114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    private static IAudioService getService()
15983114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    {
15993114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        if (sService != null) {
16003114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi            return sService;
16013114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        }
16023114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        IBinder b = ServiceManager.getService(Context.AUDIO_SERVICE);
16033114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        sService = IAudioService.Stub.asInterface(b);
16043114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        return sService;
16053114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    }
16063114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi
16073114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    private void sendAudioServiceNewPlaybackInfo_syncCacheLock(int what, int value) {
16083114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        if (mRcseId == RCSE_ID_UNREGISTERED) {
16093114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi            return;
16103114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        }
1611f98de1e8dd6dcbd191921b4aa07a1d41b0b9db91Jean-Michel Trivi        //Log.d(TAG, "sending to AudioService key=" + what + ", value=" + value);
16123114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        IAudioService service = getService();
16133114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        try {
16143114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi            service.setPlaybackInfoForRcc(mRcseId, what, value);
16153114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        } catch (RemoteException e) {
1616bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi            Log.e(TAG, "Dead object in setPlaybackInfoForRcc", e);
1617bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi        }
1618bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi    }
1619bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi
1620bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi    private void sendAudioServiceNewPlaybackState_syncCacheLock() {
1621bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi        if (mRcseId == RCSE_ID_UNREGISTERED) {
1622bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi            return;
1623bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi        }
1624bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi        IAudioService service = getService();
1625bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi        try {
1626bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi            service.setPlaybackStateForRcc(mRcseId,
1627bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi                    mPlaybackState, mPlaybackPositionMs, mPlaybackSpeed);
1628bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi        } catch (RemoteException e) {
1629bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi            Log.e(TAG, "Dead object in setPlaybackStateForRcc", e);
16303114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        }
16313114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    }
16323114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi
16333114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    //===========================================================
16343114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    // Message handlers
16353114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi
16364a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi    private void onNewInternalClientGen(int clientGeneration) {
16374426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi        synchronized (mCacheLock) {
16384426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi            // this remote control client is told it is the "focused" one:
16394426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi            // it implies that now (mCurrentClientGenId == mInternalClientGenId) is true
16404a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi            mInternalClientGenId = clientGeneration;
16414426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi        }
16424426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    }
16434426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi
16444426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    private void onNewCurrentClientGen(int clientGeneration) {
16454426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi        synchronized (mCacheLock) {
16464426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi            mCurrentClientGenId = clientGeneration;
16474426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi        }
16484426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    }
16494426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi
16504a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi    /** pre-condition rcd != null */
16514a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi    private void onPlugDisplay(IRemoteControlDisplay rcd, int w, int h) {
16524426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi        synchronized(mCacheLock) {
16534a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi            // do we have this display already?
16544a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi            boolean displayKnown = false;
16554a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi            final Iterator<DisplayInfoForClient> displayIterator = mRcDisplays.iterator();
16564a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi            while (displayIterator.hasNext() && !displayKnown) {
1657f1372428f2df781c71c71caa2f6a4db6f847cf10RoboErik                final DisplayInfoForClient di = displayIterator.next();
16584a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi                displayKnown = di.mRcDisplay.asBinder().equals(rcd.asBinder());
16594a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi                if (displayKnown) {
16604a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi                    // this display was known but the change in artwork size will cause the
16614a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi                    // artwork to be refreshed
16624a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi                    if ((di.mArtworkExpectedWidth != w) || (di.mArtworkExpectedHeight != h)) {
16634a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi                        di.mArtworkExpectedWidth = w;
16644a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi                        di.mArtworkExpectedHeight = h;
16654a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi                        if (!sendArtworkToDisplay(di)) {
16664a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi                            displayIterator.remove();
16674a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi                        }
16684a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi                    }
16694a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi                }
16704a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi            }
16714a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi            if (!displayKnown) {
16724a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi                mRcDisplays.add(new DisplayInfoForClient(rcd, w, h));
16734a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi            }
16744426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi        }
16754426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    }
16764426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi
16774a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi    /** pre-condition rcd != null */
16784426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    private void onUnplugDisplay(IRemoteControlDisplay rcd) {
16794426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi        synchronized(mCacheLock) {
1680c3c4babf8424f65b3d3d2700f60fae6e94e9cd00Jean-Michel Trivi            Iterator<DisplayInfoForClient> displayIterator = mRcDisplays.iterator();
16814a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi            while (displayIterator.hasNext()) {
1682f1372428f2df781c71c71caa2f6a4db6f847cf10RoboErik                final DisplayInfoForClient di = displayIterator.next();
16834a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi                if (di.mRcDisplay.asBinder().equals(rcd.asBinder())) {
16844a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi                    displayIterator.remove();
1685c3c4babf8424f65b3d3d2700f60fae6e94e9cd00Jean-Michel Trivi                    break;
1686c3c4babf8424f65b3d3d2700f60fae6e94e9cd00Jean-Michel Trivi                }
1687c3c4babf8424f65b3d3d2700f60fae6e94e9cd00Jean-Michel Trivi            }
1688c3c4babf8424f65b3d3d2700f60fae6e94e9cd00Jean-Michel Trivi            // list of RCDs has changed, reevaluate whether position check is still needed
1689c3c4babf8424f65b3d3d2700f60fae6e94e9cd00Jean-Michel Trivi            boolean oldNeedsPositionSync = mNeedsPositionSync;
1690c3c4babf8424f65b3d3d2700f60fae6e94e9cd00Jean-Michel Trivi            boolean newNeedsPositionSync = false;
1691c3c4babf8424f65b3d3d2700f60fae6e94e9cd00Jean-Michel Trivi            displayIterator = mRcDisplays.iterator();
1692c3c4babf8424f65b3d3d2700f60fae6e94e9cd00Jean-Michel Trivi            while (displayIterator.hasNext()) {
1693f1372428f2df781c71c71caa2f6a4db6f847cf10RoboErik                final DisplayInfoForClient di = displayIterator.next();
1694c3c4babf8424f65b3d3d2700f60fae6e94e9cd00Jean-Michel Trivi                if (di.mWantsPositionSync) {
1695c3c4babf8424f65b3d3d2700f60fae6e94e9cd00Jean-Michel Trivi                    newNeedsPositionSync = true;
1696c3c4babf8424f65b3d3d2700f60fae6e94e9cd00Jean-Michel Trivi                    break;
16974a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi                }
16984a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi            }
1699c3c4babf8424f65b3d3d2700f60fae6e94e9cd00Jean-Michel Trivi            mNeedsPositionSync = newNeedsPositionSync;
1700c3c4babf8424f65b3d3d2700f60fae6e94e9cd00Jean-Michel Trivi            if (oldNeedsPositionSync != mNeedsPositionSync) {
1701c3c4babf8424f65b3d3d2700f60fae6e94e9cd00Jean-Michel Trivi                // update needed?
1702c3c4babf8424f65b3d3d2700f60fae6e94e9cd00Jean-Michel Trivi                initiateCheckForDrift_syncCacheLock();
1703c3c4babf8424f65b3d3d2700f60fae6e94e9cd00Jean-Michel Trivi            }
17044a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi        }
17054a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi    }
17064a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi
17074a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi    /** pre-condition rcd != null */
17084a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi    private void onUpdateDisplayArtworkSize(IRemoteControlDisplay rcd, int w, int h) {
17094a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi        synchronized(mCacheLock) {
17104a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi            final Iterator<DisplayInfoForClient> displayIterator = mRcDisplays.iterator();
17114a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi            while (displayIterator.hasNext()) {
1712f1372428f2df781c71c71caa2f6a4db6f847cf10RoboErik                final DisplayInfoForClient di = displayIterator.next();
17134a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi                if (di.mRcDisplay.asBinder().equals(rcd.asBinder()) &&
17144a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi                        ((di.mArtworkExpectedWidth != w) || (di.mArtworkExpectedHeight != h))) {
17154a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi                    di.mArtworkExpectedWidth = w;
17164a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi                    di.mArtworkExpectedHeight = h;
1717f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi                    if (di.mEnabled) {
1718f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi                        if (!sendArtworkToDisplay(di)) {
1719f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi                            displayIterator.remove();
1720f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi                        }
17214a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi                    }
17224a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi                    break;
17234a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi                }
17244426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi            }
17254426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi        }
17264426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    }
17274426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi
1728c3c4babf8424f65b3d3d2700f60fae6e94e9cd00Jean-Michel Trivi    /** pre-condition rcd != null */
1729c3c4babf8424f65b3d3d2700f60fae6e94e9cd00Jean-Michel Trivi    private void onDisplayWantsSync(IRemoteControlDisplay rcd, boolean wantsSync) {
1730c3c4babf8424f65b3d3d2700f60fae6e94e9cd00Jean-Michel Trivi        synchronized(mCacheLock) {
1731c3c4babf8424f65b3d3d2700f60fae6e94e9cd00Jean-Michel Trivi            boolean oldNeedsPositionSync = mNeedsPositionSync;
1732c3c4babf8424f65b3d3d2700f60fae6e94e9cd00Jean-Michel Trivi            boolean newNeedsPositionSync = false;
1733c3c4babf8424f65b3d3d2700f60fae6e94e9cd00Jean-Michel Trivi            final Iterator<DisplayInfoForClient> displayIterator = mRcDisplays.iterator();
1734c3c4babf8424f65b3d3d2700f60fae6e94e9cd00Jean-Michel Trivi            // go through the list of RCDs and for each entry, check both whether this is the RCD
1735c3c4babf8424f65b3d3d2700f60fae6e94e9cd00Jean-Michel Trivi            //  that gets upated, and whether the list has one entry that wants position sync
1736c3c4babf8424f65b3d3d2700f60fae6e94e9cd00Jean-Michel Trivi            while (displayIterator.hasNext()) {
1737f1372428f2df781c71c71caa2f6a4db6f847cf10RoboErik                final DisplayInfoForClient di = displayIterator.next();
1738f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi                if (di.mEnabled) {
1739f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi                    if (di.mRcDisplay.asBinder().equals(rcd.asBinder())) {
1740f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi                        di.mWantsPositionSync = wantsSync;
1741f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi                    }
1742f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi                    if (di.mWantsPositionSync) {
1743f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi                        newNeedsPositionSync = true;
1744f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi                    }
1745c3c4babf8424f65b3d3d2700f60fae6e94e9cd00Jean-Michel Trivi                }
1746c3c4babf8424f65b3d3d2700f60fae6e94e9cd00Jean-Michel Trivi            }
1747c3c4babf8424f65b3d3d2700f60fae6e94e9cd00Jean-Michel Trivi            mNeedsPositionSync = newNeedsPositionSync;
1748c3c4babf8424f65b3d3d2700f60fae6e94e9cd00Jean-Michel Trivi            if (oldNeedsPositionSync != mNeedsPositionSync) {
1749c3c4babf8424f65b3d3d2700f60fae6e94e9cd00Jean-Michel Trivi                // update needed?
1750c3c4babf8424f65b3d3d2700f60fae6e94e9cd00Jean-Michel Trivi                initiateCheckForDrift_syncCacheLock();
1751c3c4babf8424f65b3d3d2700f60fae6e94e9cd00Jean-Michel Trivi            }
1752c3c4babf8424f65b3d3d2700f60fae6e94e9cd00Jean-Michel Trivi        }
1753c3c4babf8424f65b3d3d2700f60fae6e94e9cd00Jean-Michel Trivi    }
1754c3c4babf8424f65b3d3d2700f60fae6e94e9cd00Jean-Michel Trivi
1755f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi    /** pre-condition rcd != null */
1756f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi    private void onDisplayEnable(IRemoteControlDisplay rcd, boolean enable) {
1757f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi        synchronized(mCacheLock) {
1758f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi            final Iterator<DisplayInfoForClient> displayIterator = mRcDisplays.iterator();
1759f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi            while (displayIterator.hasNext()) {
1760f1372428f2df781c71c71caa2f6a4db6f847cf10RoboErik                final DisplayInfoForClient di = displayIterator.next();
1761f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi                if (di.mRcDisplay.asBinder().equals(rcd.asBinder())) {
1762f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi                    di.mEnabled = enable;
1763f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi                }
1764f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi            }
1765f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi        }
1766f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi    }
1767f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi
17683261b537c5fdec824575a1f6ad6d8942715e82e2Jean-Michel Trivi    private void onSeekTo(int generationId, long timeMs) {
17693261b537c5fdec824575a1f6ad6d8942715e82e2Jean-Michel Trivi        synchronized (mCacheLock) {
17703261b537c5fdec824575a1f6ad6d8942715e82e2Jean-Michel Trivi            if ((mCurrentClientGenId == generationId) && (mPositionUpdateListener != null)) {
17713261b537c5fdec824575a1f6ad6d8942715e82e2Jean-Michel Trivi                mPositionUpdateListener.onPlaybackPositionUpdate(timeMs);
17723261b537c5fdec824575a1f6ad6d8942715e82e2Jean-Michel Trivi            }
17733261b537c5fdec824575a1f6ad6d8942715e82e2Jean-Michel Trivi        }
17743261b537c5fdec824575a1f6ad6d8942715e82e2Jean-Michel Trivi    }
17753261b537c5fdec824575a1f6ad6d8942715e82e2Jean-Michel Trivi
177688183e67d4628e8c8a3310af0076b6f33f955cb2Jean-Michel Trivi    private void onUpdateMetadata(int generationId, int key, Object value) {
1777f823fc4dba2df5cf5f00e13361f2db93c81f6961Jean-Michel Trivi        synchronized (mCacheLock) {
1778f823fc4dba2df5cf5f00e13361f2db93c81f6961Jean-Michel Trivi            if ((mCurrentClientGenId == generationId) && (mMetadataUpdateListener != null)) {
177988183e67d4628e8c8a3310af0076b6f33f955cb2Jean-Michel Trivi                mMetadataUpdateListener.onMetadataUpdate(key, value);
1780f823fc4dba2df5cf5f00e13361f2db93c81f6961Jean-Michel Trivi            }
1781f823fc4dba2df5cf5f00e13361f2db93c81f6961Jean-Michel Trivi        }
1782f823fc4dba2df5cf5f00e13361f2db93c81f6961Jean-Michel Trivi    }
1783f823fc4dba2df5cf5f00e13361f2db93c81f6961Jean-Michel Trivi
17843114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    //===========================================================
17853114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    // Internal utilities
17863114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi
17874426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    /**
17884426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     * Scale a bitmap to fit the smallest dimension by uniformly scaling the incoming bitmap.
17894426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     * If the bitmap fits, then do nothing and return the original.
17904426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     *
17914426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     * @param bitmap
17924426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     * @param maxWidth
17934426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     * @param maxHeight
17944426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     * @return
17954426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     */
17964426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi
17974426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    private Bitmap scaleBitmapIfTooBig(Bitmap bitmap, int maxWidth, int maxHeight) {
17986e679d5a53091b348a2cdc0c76f4e8fa4ac52d4bJean-Michel Trivi        if (bitmap != null) {
17996e679d5a53091b348a2cdc0c76f4e8fa4ac52d4bJean-Michel Trivi            final int width = bitmap.getWidth();
18006e679d5a53091b348a2cdc0c76f4e8fa4ac52d4bJean-Michel Trivi            final int height = bitmap.getHeight();
18016e679d5a53091b348a2cdc0c76f4e8fa4ac52d4bJean-Michel Trivi            if (width > maxWidth || height > maxHeight) {
18026e679d5a53091b348a2cdc0c76f4e8fa4ac52d4bJean-Michel Trivi                float scale = Math.min((float) maxWidth / width, (float) maxHeight / height);
18036e679d5a53091b348a2cdc0c76f4e8fa4ac52d4bJean-Michel Trivi                int newWidth = Math.round(scale * width);
18046e679d5a53091b348a2cdc0c76f4e8fa4ac52d4bJean-Michel Trivi                int newHeight = Math.round(scale * height);
180505c66cc5cc6357be19fdef0fc131731368c38646Jack Palevich                Bitmap.Config newConfig = bitmap.getConfig();
180605c66cc5cc6357be19fdef0fc131731368c38646Jack Palevich                if (newConfig == null) {
180705c66cc5cc6357be19fdef0fc131731368c38646Jack Palevich                    newConfig = Bitmap.Config.ARGB_8888;
180805c66cc5cc6357be19fdef0fc131731368c38646Jack Palevich                }
180905c66cc5cc6357be19fdef0fc131731368c38646Jack Palevich                Bitmap outBitmap = Bitmap.createBitmap(newWidth, newHeight, newConfig);
18106e679d5a53091b348a2cdc0c76f4e8fa4ac52d4bJean-Michel Trivi                Canvas canvas = new Canvas(outBitmap);
18116e679d5a53091b348a2cdc0c76f4e8fa4ac52d4bJean-Michel Trivi                Paint paint = new Paint();
18126e679d5a53091b348a2cdc0c76f4e8fa4ac52d4bJean-Michel Trivi                paint.setAntiAlias(true);
18136e679d5a53091b348a2cdc0c76f4e8fa4ac52d4bJean-Michel Trivi                paint.setFilterBitmap(true);
18146e679d5a53091b348a2cdc0c76f4e8fa4ac52d4bJean-Michel Trivi                canvas.drawBitmap(bitmap, null,
18156e679d5a53091b348a2cdc0c76f4e8fa4ac52d4bJean-Michel Trivi                        new RectF(0, 0, outBitmap.getWidth(), outBitmap.getHeight()), paint);
18166e679d5a53091b348a2cdc0c76f4e8fa4ac52d4bJean-Michel Trivi                bitmap = outBitmap;
18176e679d5a53091b348a2cdc0c76f4e8fa4ac52d4bJean-Michel Trivi            }
18184426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi        }
18194426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi        return bitmap;
18205ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Trivi    }
18214426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi
1822521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi
1823521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi    /**
1824521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi     * Returns whether, for the given playback state, the playback position is expected to
1825521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi     * be changing.
1826521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi     * @param playstate the playback state to evaluate
1827521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi     * @return true during any form of playback, false if it's not playing anything while in this
1828521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi     *     playback state
1829521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi     */
1830f8895248e2ac4dbb46622f3e04c7256f03175b4fAdam Powell    static boolean playbackPositionShouldMove(int playstate) {
1831521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi        switch(playstate) {
1832521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi            case PLAYSTATE_STOPPED:
1833521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi            case PLAYSTATE_PAUSED:
1834521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi            case PLAYSTATE_BUFFERING:
1835521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi            case PLAYSTATE_ERROR:
1836521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi            case PLAYSTATE_SKIPPING_FORWARDS:
1837521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi            case PLAYSTATE_SKIPPING_BACKWARDS:
1838521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi                return false;
1839521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi            case PLAYSTATE_PLAYING:
1840521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi            case PLAYSTATE_FAST_FORWARDING:
1841521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi            case PLAYSTATE_REWINDING:
1842521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi            default:
1843521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi                return true;
1844521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi        }
1845521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi    }
1846521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi
1847521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi    /**
1848521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi     * Period for playback position drift checks, 15s when playing at 1x or slower.
1849521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi     */
1850521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi    private final static long POSITION_REFRESH_PERIOD_PLAYING_MS = 15000;
1851521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi    /**
1852521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi     * Minimum period for playback position drift checks, never more often when every 2s, when
1853521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi     * fast forwarding or rewinding.
1854521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi     */
1855521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi    private final static long POSITION_REFRESH_PERIOD_MIN_MS = 2000;
1856521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi    /**
1857521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi     * The value above which the difference between client-reported playback position and
1858521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi     * estimated position is considered a drift.
1859521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi     */
1860521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi    private final static long POSITION_DRIFT_MAX_MS = 500;
1861521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi    /**
1862521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi     * Compute the period at which the estimated playback position should be compared against the
1863521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi     * actual playback position. Is a funciton of playback speed.
1864521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi     * @param speed 1.0f is normal playback speed
1865521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi     * @return the period in ms
1866521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi     */
1867521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi    private static long getCheckPeriodFromSpeed(float speed) {
1868521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi        if (Math.abs(speed) <= 1.0f) {
1869521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi            return POSITION_REFRESH_PERIOD_PLAYING_MS;
1870521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi        } else {
1871521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi            return Math.max((long)(POSITION_REFRESH_PERIOD_PLAYING_MS / Math.abs(speed)),
1872521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi                    POSITION_REFRESH_PERIOD_MIN_MS);
1873521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi        }
1874521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi    }
1875178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi}
1876