1178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi/*
2178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi * Copyright (C) 2011 The Android Open Source Project
3178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi *
4178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi * Licensed under the Apache License, Version 2.0 (the "License");
5178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi * you may not use this file except in compliance with the License.
6178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi * You may obtain a copy of the License at
7178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi *
8178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi *      http://www.apache.org/licenses/LICENSE-2.0
9178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi *
10178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi * Unless required by applicable law or agreed to in writing, software
11178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi * distributed under the License is distributed on an "AS IS" BASIS,
12178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi * See the License for the specific language governing permissions and
14178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi * limitations under the License.
15178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi */
16178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi
17178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivipackage android.media;
18178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi
196e920e6dac11c3ebf6c0c19402934834e9e491bfJean-Michel Triviimport android.app.PendingIntent;
20178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Triviimport android.content.ComponentName;
216e920e6dac11c3ebf6c0c19402934834e9e491bfJean-Michel Triviimport android.content.Intent;
22178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Triviimport android.graphics.Bitmap;
23f1372428f2df781c71c71caa2f6a4db6f847cf10RoboErikimport android.media.session.MediaSessionLegacyHelper;
24f1372428f2df781c71c71caa2f6a4db6f847cf10RoboErikimport android.media.session.PlaybackState;
2542ea7eecd149161ed192d3029f0d77d1d08a4aa5RoboErikimport android.media.session.MediaSession;
264426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Triviimport android.os.Bundle;
274426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Triviimport android.os.Handler;
284426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Triviimport android.os.Looper;
294426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Triviimport android.os.Message;
303114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Triviimport android.os.ServiceManager;
3168622396b62f9084781add1e12f4d513b633ab54Jean-Michel Triviimport android.os.SystemClock;
324426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Triviimport android.util.Log;
334426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi
345ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Triviimport java.lang.IllegalArgumentException;
35178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi
36178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi/**
374426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi * RemoteControlClient enables exposing information meant to be consumed by remote controls
38466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi * capable of displaying metadata, artwork and media transport control buttons.
39ad87f5b40f2a3fd2d506dc15e00b8af28a8fa2baJean-Michel Trivi *
40ad87f5b40f2a3fd2d506dc15e00b8af28a8fa2baJean-Michel Trivi * <p>A remote control client object is associated with a media button event receiver. This
41466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi * event receiver must have been previously registered with
42466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi * {@link AudioManager#registerMediaButtonEventReceiver(ComponentName)} before the
43466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi * RemoteControlClient can be registered through
444426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi * {@link AudioManager#registerRemoteControlClient(RemoteControlClient)}.
45ad87f5b40f2a3fd2d506dc15e00b8af28a8fa2baJean-Michel Trivi *
46ad87f5b40f2a3fd2d506dc15e00b8af28a8fa2baJean-Michel Trivi * <p>Here is an example of creating a RemoteControlClient instance after registering a media
47ad87f5b40f2a3fd2d506dc15e00b8af28a8fa2baJean-Michel Trivi * button event receiver:
48ad87f5b40f2a3fd2d506dc15e00b8af28a8fa2baJean-Michel Trivi * <pre>ComponentName myEventReceiver = new ComponentName(getPackageName(), MyRemoteControlEventReceiver.class.getName());
49ad87f5b40f2a3fd2d506dc15e00b8af28a8fa2baJean-Michel Trivi * AudioManager myAudioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
50ad87f5b40f2a3fd2d506dc15e00b8af28a8fa2baJean-Michel Trivi * myAudioManager.registerMediaButtonEventReceiver(myEventReceiver);
51ad87f5b40f2a3fd2d506dc15e00b8af28a8fa2baJean-Michel Trivi * // build the PendingIntent for the remote control client
52ad87f5b40f2a3fd2d506dc15e00b8af28a8fa2baJean-Michel Trivi * Intent mediaButtonIntent = new Intent(Intent.ACTION_MEDIA_BUTTON);
53ad87f5b40f2a3fd2d506dc15e00b8af28a8fa2baJean-Michel Trivi * mediaButtonIntent.setComponent(myEventReceiver);
54ad87f5b40f2a3fd2d506dc15e00b8af28a8fa2baJean-Michel Trivi * PendingIntent mediaPendingIntent = PendingIntent.getBroadcast(getApplicationContext(), 0, mediaButtonIntent, 0);
55ad87f5b40f2a3fd2d506dc15e00b8af28a8fa2baJean-Michel Trivi * // create and register the remote control client
56ad87f5b40f2a3fd2d506dc15e00b8af28a8fa2baJean-Michel Trivi * RemoteControlClient myRemoteControlClient = new RemoteControlClient(mediaPendingIntent);
57ad87f5b40f2a3fd2d506dc15e00b8af28a8fa2baJean-Michel Trivi * myAudioManager.registerRemoteControlClient(myRemoteControlClient);</pre>
58edb158f55f48a1f7b2cbf30ddec9b8917dc9a619RoboErik *
59edb158f55f48a1f7b2cbf30ddec9b8917dc9a619RoboErik * @deprecated Use {@link MediaSession} instead.
60178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi */
61edb158f55f48a1f7b2cbf30ddec9b8917dc9a619RoboErik@Deprecated public class RemoteControlClient
62178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi{
634426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    private final static String TAG = "RemoteControlClient";
64521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi    private final static boolean DEBUG = false;
654426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi
66178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi    /**
67178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     * Playback state of a RemoteControlClient which is stopped.
68178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     *
694426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     * @see #setPlaybackState(int)
70178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     */
71178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi    public final static int PLAYSTATE_STOPPED            = 1;
72178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi    /**
73178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     * Playback state of a RemoteControlClient which is paused.
74178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     *
754426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     * @see #setPlaybackState(int)
76178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     */
77178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi    public final static int PLAYSTATE_PAUSED             = 2;
78178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi    /**
79178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     * Playback state of a RemoteControlClient which is playing media.
80178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     *
814426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     * @see #setPlaybackState(int)
82178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     */
83178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi    public final static int PLAYSTATE_PLAYING            = 3;
84178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi    /**
85178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     * Playback state of a RemoteControlClient which is fast forwarding in the media
86178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     *    it is currently playing.
87178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     *
884426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     * @see #setPlaybackState(int)
89178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     */
90178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi    public final static int PLAYSTATE_FAST_FORWARDING    = 4;
91178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi    /**
92178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     * Playback state of a RemoteControlClient which is fast rewinding 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_REWINDING          = 5;
98178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi    /**
99178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     * Playback state of a RemoteControlClient which is skipping to the next
100178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     *    logical chapter (such as a song in a playlist) in the media it is currently playing.
101178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     *
1024426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     * @see #setPlaybackState(int)
103178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     */
104178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi    public final static int PLAYSTATE_SKIPPING_FORWARDS  = 6;
105178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi    /**
106178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     * Playback state of a RemoteControlClient which is skipping back to the previous
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_BACKWARDS = 7;
112178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi    /**
113178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     * Playback state of a RemoteControlClient which is buffering data to play before it can
114178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     *    start or resume playback.
115178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     *
1164426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     * @see #setPlaybackState(int)
117178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     */
118178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi    public final static int PLAYSTATE_BUFFERING          = 8;
119178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi    /**
120178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     * Playback state of a RemoteControlClient which cannot perform any playback related
121178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     *    operation because of an internal error. Examples of such situations are no network
122178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     *    connectivity when attempting to stream data from a server, or expired user credentials
123178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     *    when trying to play subscription-based content.
124178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     *
1254426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     * @see #setPlaybackState(int)
126178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     */
127178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi    public final static int PLAYSTATE_ERROR              = 9;
1284426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    /**
1294426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     * @hide
130466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi     * The value of a playback state when none has been declared.
131466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi     * Intentionally hidden as an application shouldn't set such a playback state value.
1324426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     */
1334426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    public final static int PLAYSTATE_NONE               = 0;
134178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi
135178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi    /**
1361357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi     * @hide
1373114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     * The default playback type, "local", indicating the presentation of the media is happening on
1383114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     * the same device (e.g. a phone, a tablet) as where it is controlled from.
1393114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     */
1403114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    public final static int PLAYBACK_TYPE_LOCAL = 0;
1413114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    /**
1421357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi     * @hide
1433114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     * A playback type indicating the presentation of the media is happening on
1443114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     * a different device (i.e. the remote device) than where it is controlled from.
1453114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     */
1463114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    public final static int PLAYBACK_TYPE_REMOTE = 1;
1473114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    private final static int PLAYBACK_TYPE_MIN = PLAYBACK_TYPE_LOCAL;
1483114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    private final static int PLAYBACK_TYPE_MAX = PLAYBACK_TYPE_REMOTE;
1493114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    /**
1501357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi     * @hide
1513114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     * Playback information indicating the playback volume is fixed, i.e. it cannot be controlled
1523114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     * from this object. An example of fixed playback volume is a remote player, playing over HDMI
1533114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     * where the user prefer to control the volume on the HDMI sink, rather than attenuate at the
1543114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     * source.
1553114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     * @see #PLAYBACKINFO_VOLUME_HANDLING.
1563114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     */
1573114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    public final static int PLAYBACK_VOLUME_FIXED = 0;
1583114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    /**
1591357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi     * @hide
1603114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     * Playback information indicating the playback volume is variable and can be controlled from
1613114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     * this object.
1623114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     * @see #PLAYBACKINFO_VOLUME_HANDLING.
1633114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     */
1643114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    public final static int PLAYBACK_VOLUME_VARIABLE = 1;
1653114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    /**
1663114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     * @hide (to be un-hidden)
1673114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     * The playback information value indicating the value of a given information type is invalid.
1683114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     * @see #PLAYBACKINFO_VOLUME_HANDLING.
1693114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     */
1703114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    public final static int PLAYBACKINFO_INVALID_VALUE = Integer.MIN_VALUE;
1713114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi
172bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi    /**
173bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi     * @hide
174bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi     * An unknown or invalid playback position value.
175bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi     */
176bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi    public final static long PLAYBACK_POSITION_INVALID = -1;
177bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi    /**
178bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi     * @hide
1791b16cc3de51d69c8027cefcc70a084a5b2d7a3d0Jean-Michel Trivi     * An invalid playback position value associated with the use of {@link #setPlaybackState(int)}
1801b16cc3de51d69c8027cefcc70a084a5b2d7a3d0Jean-Michel Trivi     * used to indicate that playback position will remain unknown.
1811b16cc3de51d69c8027cefcc70a084a5b2d7a3d0Jean-Michel Trivi     */
1821b16cc3de51d69c8027cefcc70a084a5b2d7a3d0Jean-Michel Trivi    public final static long PLAYBACK_POSITION_ALWAYS_UNKNOWN = 0x8019771980198300L;
1831b16cc3de51d69c8027cefcc70a084a5b2d7a3d0Jean-Michel Trivi    /**
1841b16cc3de51d69c8027cefcc70a084a5b2d7a3d0Jean-Michel Trivi     * @hide
185bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi     * The default playback speed, 1x.
186bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi     */
187bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi    public final static float PLAYBACK_SPEED_1X = 1.0f;
188bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi
1893114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    //==========================================
1903114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    // Public keys for playback information
1913114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    /**
1921357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi     * @hide
1933114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     * Playback information that defines the type of playback associated with this
1943114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     * RemoteControlClient. See {@link #PLAYBACK_TYPE_LOCAL} and {@link #PLAYBACK_TYPE_REMOTE}.
1953114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     */
1963114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    public final static int PLAYBACKINFO_PLAYBACK_TYPE = 1;
1973114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    /**
1981357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi     * @hide
1993114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     * Playback information that defines at what volume the playback associated with this
2003114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     * RemoteControlClient is performed. This information is only used when the playback type is not
2013114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     * local (see {@link #PLAYBACKINFO_PLAYBACK_TYPE}).
2023114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     */
2033114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    public final static int PLAYBACKINFO_VOLUME = 2;
2043114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    /**
2051357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi     * @hide
2063114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     * Playback information that defines the maximum volume volume value that is supported
2073114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     * by the playback associated with this RemoteControlClient. This information is only used
2083114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     * when the playback type is not local (see {@link #PLAYBACKINFO_PLAYBACK_TYPE}).
2093114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     */
2103114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    public final static int PLAYBACKINFO_VOLUME_MAX = 3;
2113114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    /**
2121357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi     * @hide
2133114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     * Playback information that defines how volume is handled for the presentation of the media.
2143114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     * @see #PLAYBACK_VOLUME_FIXED
2153114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     * @see #PLAYBACK_VOLUME_VARIABLE
2163114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     */
2173114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    public final static int PLAYBACKINFO_VOLUME_HANDLING = 4;
2183114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    /**
2191357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi     * @hide
2203114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     * Playback information that defines over what stream type the media is presented.
2213114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     */
2223114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    public final static int PLAYBACKINFO_USES_STREAM = 5;
2233114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi
2243114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    //==========================================
225521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi    // Public flags for the supported transport control capabilities
2263114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    /**
227178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     * Flag indicating a RemoteControlClient makes use of the "previous" media key.
228178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     *
2294426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     * @see #setTransportControlFlags(int)
230178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     * @see android.view.KeyEvent#KEYCODE_MEDIA_PREVIOUS
231178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     */
232178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi    public final static int FLAG_KEY_MEDIA_PREVIOUS = 1 << 0;
233178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi    /**
234466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi     * Flag indicating a RemoteControlClient makes use of the "rewind" media key.
235178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     *
2364426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     * @see #setTransportControlFlags(int)
237178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     * @see android.view.KeyEvent#KEYCODE_MEDIA_REWIND
238178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     */
239178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi    public final static int FLAG_KEY_MEDIA_REWIND = 1 << 1;
240178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi    /**
241178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     * Flag indicating a RemoteControlClient makes use of the "play" media key.
242178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     *
2434426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     * @see #setTransportControlFlags(int)
244178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     * @see android.view.KeyEvent#KEYCODE_MEDIA_PLAY
245178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     */
246178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi    public final static int FLAG_KEY_MEDIA_PLAY = 1 << 2;
247178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi    /**
248178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     * Flag indicating a RemoteControlClient makes use of the "play/pause" media key.
249178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     *
2504426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     * @see #setTransportControlFlags(int)
251178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     * @see android.view.KeyEvent#KEYCODE_MEDIA_PLAY_PAUSE
252178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     */
253178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi    public final static int FLAG_KEY_MEDIA_PLAY_PAUSE = 1 << 3;
254178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi    /**
255178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     * Flag indicating a RemoteControlClient makes use of the "pause" media key.
256178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     *
2574426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     * @see #setTransportControlFlags(int)
258178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     * @see android.view.KeyEvent#KEYCODE_MEDIA_PAUSE
259178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     */
260178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi    public final static int FLAG_KEY_MEDIA_PAUSE = 1 << 4;
261178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi    /**
262178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     * Flag indicating a RemoteControlClient makes use of the "stop" media key.
263178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     *
2644426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     * @see #setTransportControlFlags(int)
265178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     * @see android.view.KeyEvent#KEYCODE_MEDIA_STOP
266178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     */
267178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi    public final static int FLAG_KEY_MEDIA_STOP = 1 << 5;
268178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi    /**
269178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     * Flag indicating a RemoteControlClient makes use of the "fast forward" media key.
270178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     *
2714426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     * @see #setTransportControlFlags(int)
272178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     * @see android.view.KeyEvent#KEYCODE_MEDIA_FAST_FORWARD
273178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     */
274178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi    public final static int FLAG_KEY_MEDIA_FAST_FORWARD = 1 << 6;
275178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi    /**
276178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     * Flag indicating a RemoteControlClient makes use of the "next" media key.
277178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     *
2784426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     * @see #setTransportControlFlags(int)
279178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     * @see android.view.KeyEvent#KEYCODE_MEDIA_NEXT
280178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     */
281178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi    public final static int FLAG_KEY_MEDIA_NEXT = 1 << 7;
282bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi    /**
283bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi     * Flag indicating a RemoteControlClient can receive changes in the media playback position
284e63b0609c3b5f6c21d4e006ee9ddd3ba98a4e684Scott Main     * through the {@link OnPlaybackPositionUpdateListener} interface. This flag must be set
2853261b537c5fdec824575a1f6ad6d8942715e82e2Jean-Michel Trivi     * in order for components that display the RemoteControlClient information, to display and
2863261b537c5fdec824575a1f6ad6d8942715e82e2Jean-Michel Trivi     * let the user control media playback position.
287bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi     * @see #setTransportControlFlags(int)
288915747730060dff71b5b2ca7e4ee4073024fc24eJean-Michel Trivi     * @see #setOnGetPlaybackPositionListener(OnGetPlaybackPositionListener)
2893261b537c5fdec824575a1f6ad6d8942715e82e2Jean-Michel Trivi     * @see #setPlaybackPositionUpdateListener(OnPlaybackPositionUpdateListener)
290bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi     */
291bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi    public final static int FLAG_KEY_MEDIA_POSITION_UPDATE = 1 << 8;
292f823fc4dba2df5cf5f00e13361f2db93c81f6961Jean-Michel Trivi    /**
293f823fc4dba2df5cf5f00e13361f2db93c81f6961Jean-Michel Trivi     * Flag indicating a RemoteControlClient supports ratings.
294f823fc4dba2df5cf5f00e13361f2db93c81f6961Jean-Michel Trivi     * This flag must be set in order for components that display the RemoteControlClient
295f823fc4dba2df5cf5f00e13361f2db93c81f6961Jean-Michel Trivi     * information, to display ratings information, and, if ratings are declared editable
296f841d70155c991b6cf728dd41e6d37e051be453dJean-Michel Trivi     * (by calling {@link MediaMetadataEditor#addEditableKey(int)} with the
297f841d70155c991b6cf728dd41e6d37e051be453dJean-Michel Trivi     * {@link MediaMetadataEditor#RATING_KEY_BY_USER} key), it will enable the user to rate
298b23cd118ce3339589fffd40ecf1aa9c5816b3438Jean-Michel Trivi     * the media, with values being received through the interface set with
299b23cd118ce3339589fffd40ecf1aa9c5816b3438Jean-Michel Trivi     * {@link #setMetadataUpdateListener(OnMetadataUpdateListener)}.
300f823fc4dba2df5cf5f00e13361f2db93c81f6961Jean-Michel Trivi     * @see #setTransportControlFlags(int)
301f823fc4dba2df5cf5f00e13361f2db93c81f6961Jean-Michel Trivi     */
302f823fc4dba2df5cf5f00e13361f2db93c81f6961Jean-Michel Trivi    public final static int FLAG_KEY_MEDIA_RATING = 1 << 9;
303178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi
304178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi    /**
3054426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     * @hide
306466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi     * The flags for when no media keys are declared supported.
307466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi     * Intentionally hidden as an application shouldn't set the transport control flags
308466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi     *     to this value.
3094426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     */
3104426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    public final static int FLAGS_KEY_MEDIA_NONE = 0;
3114426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi
3124426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    /**
3134426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     * @hide
3144426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     * Flag used to signal some type of metadata exposed by the RemoteControlClient is requested.
315178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     */
3164426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    public final static int FLAG_INFORMATION_REQUEST_METADATA = 1 << 0;
317178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi    /**
3184426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     * @hide
319178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     * Flag used to signal that the transport control buttons supported by the
320466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi     *     RemoteControlClient are requested.
321178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     * This can for instance happen when playback is at the end of a playlist, and the "next"
322178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     * operation is not supported anymore.
323178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     */
3244426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    public final static int FLAG_INFORMATION_REQUEST_KEY_MEDIA = 1 << 1;
325178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi    /**
3264426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     * @hide
327466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi     * Flag used to signal that the playback state of the RemoteControlClient is requested.
328178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     */
3294426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    public final static int FLAG_INFORMATION_REQUEST_PLAYSTATE = 1 << 2;
330178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi    /**
3314426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     * @hide
332466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi     * Flag used to signal that the album art for the RemoteControlClient is requested.
333178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     */
3344426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    public final static int FLAG_INFORMATION_REQUEST_ALBUM_ART = 1 << 3;
3354426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi
33642ea7eecd149161ed192d3029f0d77d1d08a4aa5RoboErik    private MediaSession mSession;
337f1372428f2df781c71c71caa2f6a4db6f847cf10RoboErik
3384426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    /**
3396e920e6dac11c3ebf6c0c19402934834e9e491bfJean-Michel Trivi     * Class constructor.
3406e920e6dac11c3ebf6c0c19402934834e9e491bfJean-Michel Trivi     * @param mediaButtonIntent The intent that will be sent for the media button events sent
3416e920e6dac11c3ebf6c0c19402934834e9e491bfJean-Michel Trivi     *     by remote controls.
3426e920e6dac11c3ebf6c0c19402934834e9e491bfJean-Michel Trivi     *     This intent needs to have been constructed with the {@link Intent#ACTION_MEDIA_BUTTON}
3436e920e6dac11c3ebf6c0c19402934834e9e491bfJean-Michel Trivi     *     action, and have a component that will handle the intent (set with
3446e920e6dac11c3ebf6c0c19402934834e9e491bfJean-Michel Trivi     *     {@link Intent#setComponent(ComponentName)}) registered with
3456e920e6dac11c3ebf6c0c19402934834e9e491bfJean-Michel Trivi     *     {@link AudioManager#registerMediaButtonEventReceiver(ComponentName)}
3466e920e6dac11c3ebf6c0c19402934834e9e491bfJean-Michel Trivi     *     before this new RemoteControlClient can itself be registered with
3476e920e6dac11c3ebf6c0c19402934834e9e491bfJean-Michel Trivi     *     {@link AudioManager#registerRemoteControlClient(RemoteControlClient)}.
3486e920e6dac11c3ebf6c0c19402934834e9e491bfJean-Michel Trivi     * @see AudioManager#registerMediaButtonEventReceiver(ComponentName)
3496e920e6dac11c3ebf6c0c19402934834e9e491bfJean-Michel Trivi     * @see AudioManager#registerRemoteControlClient(RemoteControlClient)
3506e920e6dac11c3ebf6c0c19402934834e9e491bfJean-Michel Trivi     */
3516e920e6dac11c3ebf6c0c19402934834e9e491bfJean-Michel Trivi    public RemoteControlClient(PendingIntent mediaButtonIntent) {
352f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi        mRcMediaIntent = mediaButtonIntent;
3536e920e6dac11c3ebf6c0c19402934834e9e491bfJean-Michel Trivi
3546e920e6dac11c3ebf6c0c19402934834e9e491bfJean-Michel Trivi        Looper looper;
3556e920e6dac11c3ebf6c0c19402934834e9e491bfJean-Michel Trivi        if ((looper = Looper.myLooper()) != null) {
3566e920e6dac11c3ebf6c0c19402934834e9e491bfJean-Michel Trivi            mEventHandler = new EventHandler(this, looper);
3576e920e6dac11c3ebf6c0c19402934834e9e491bfJean-Michel Trivi        } else if ((looper = Looper.getMainLooper()) != null) {
3586e920e6dac11c3ebf6c0c19402934834e9e491bfJean-Michel Trivi            mEventHandler = new EventHandler(this, looper);
3596e920e6dac11c3ebf6c0c19402934834e9e491bfJean-Michel Trivi        } else {
3606e920e6dac11c3ebf6c0c19402934834e9e491bfJean-Michel Trivi            mEventHandler = null;
3616e920e6dac11c3ebf6c0c19402934834e9e491bfJean-Michel Trivi            Log.e(TAG, "RemoteControlClient() couldn't find main application thread");
3626e920e6dac11c3ebf6c0c19402934834e9e491bfJean-Michel Trivi        }
3636e920e6dac11c3ebf6c0c19402934834e9e491bfJean-Michel Trivi    }
3646e920e6dac11c3ebf6c0c19402934834e9e491bfJean-Michel Trivi
3656e920e6dac11c3ebf6c0c19402934834e9e491bfJean-Michel Trivi    /**
3666e920e6dac11c3ebf6c0c19402934834e9e491bfJean-Michel Trivi     * Class constructor for a remote control client whose internal event handling
3676e920e6dac11c3ebf6c0c19402934834e9e491bfJean-Michel Trivi     * happens on a user-provided Looper.
3686e920e6dac11c3ebf6c0c19402934834e9e491bfJean-Michel Trivi     * @param mediaButtonIntent The intent that will be sent for the media button events sent
3696e920e6dac11c3ebf6c0c19402934834e9e491bfJean-Michel Trivi     *     by remote controls.
3706e920e6dac11c3ebf6c0c19402934834e9e491bfJean-Michel Trivi     *     This intent needs to have been constructed with the {@link Intent#ACTION_MEDIA_BUTTON}
3716e920e6dac11c3ebf6c0c19402934834e9e491bfJean-Michel Trivi     *     action, and have a component that will handle the intent (set with
3726e920e6dac11c3ebf6c0c19402934834e9e491bfJean-Michel Trivi     *     {@link Intent#setComponent(ComponentName)}) registered with
3736e920e6dac11c3ebf6c0c19402934834e9e491bfJean-Michel Trivi     *     {@link AudioManager#registerMediaButtonEventReceiver(ComponentName)}
3746e920e6dac11c3ebf6c0c19402934834e9e491bfJean-Michel Trivi     *     before this new RemoteControlClient can itself be registered with
3756e920e6dac11c3ebf6c0c19402934834e9e491bfJean-Michel Trivi     *     {@link AudioManager#registerRemoteControlClient(RemoteControlClient)}.
3766e920e6dac11c3ebf6c0c19402934834e9e491bfJean-Michel Trivi     * @param looper The Looper running the event loop.
3776e920e6dac11c3ebf6c0c19402934834e9e491bfJean-Michel Trivi     * @see AudioManager#registerMediaButtonEventReceiver(ComponentName)
3786e920e6dac11c3ebf6c0c19402934834e9e491bfJean-Michel Trivi     * @see AudioManager#registerRemoteControlClient(RemoteControlClient)
3796e920e6dac11c3ebf6c0c19402934834e9e491bfJean-Michel Trivi     */
3806e920e6dac11c3ebf6c0c19402934834e9e491bfJean-Michel Trivi    public RemoteControlClient(PendingIntent mediaButtonIntent, Looper looper) {
381f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi        mRcMediaIntent = mediaButtonIntent;
3826e920e6dac11c3ebf6c0c19402934834e9e491bfJean-Michel Trivi
3836e920e6dac11c3ebf6c0c19402934834e9e491bfJean-Michel Trivi        mEventHandler = new EventHandler(this, looper);
3846e920e6dac11c3ebf6c0c19402934834e9e491bfJean-Michel Trivi    }
3856e920e6dac11c3ebf6c0c19402934834e9e491bfJean-Michel Trivi
3864426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    /**
387f1372428f2df781c71c71caa2f6a4db6f847cf10RoboErik     * @hide
388f1372428f2df781c71c71caa2f6a4db6f847cf10RoboErik     */
389f1372428f2df781c71c71caa2f6a4db6f847cf10RoboErik    public void registerWithSession(MediaSessionLegacyHelper helper) {
390f1372428f2df781c71c71caa2f6a4db6f847cf10RoboErik        helper.addRccListener(mRcMediaIntent, mTransportListener);
391f1372428f2df781c71c71caa2f6a4db6f847cf10RoboErik        mSession = helper.getSession(mRcMediaIntent);
3926c30ff976dc6b49186c162ecbae08eb571a6b9f1RoboErik        setTransportControlFlags(mTransportControlFlags);
393f1372428f2df781c71c71caa2f6a4db6f847cf10RoboErik    }
394f1372428f2df781c71c71caa2f6a4db6f847cf10RoboErik
395f1372428f2df781c71c71caa2f6a4db6f847cf10RoboErik    /**
396f1372428f2df781c71c71caa2f6a4db6f847cf10RoboErik     * @hide
397f1372428f2df781c71c71caa2f6a4db6f847cf10RoboErik     */
398f1372428f2df781c71c71caa2f6a4db6f847cf10RoboErik    public void unregisterWithSession(MediaSessionLegacyHelper helper) {
399f1372428f2df781c71c71caa2f6a4db6f847cf10RoboErik        helper.removeRccListener(mRcMediaIntent);
400f1372428f2df781c71c71caa2f6a4db6f847cf10RoboErik        mSession = null;
401f1372428f2df781c71c71caa2f6a4db6f847cf10RoboErik    }
402f1372428f2df781c71c71caa2f6a4db6f847cf10RoboErik
403f1372428f2df781c71c71caa2f6a4db6f847cf10RoboErik    /**
4045f31737c68f7709cb75a8fefb7536daa77812cc3RoboErik     * Get a {@link MediaSession} associated with this RCC. It will only have a
4055f31737c68f7709cb75a8fefb7536daa77812cc3RoboErik     * session while it is registered with
4065f31737c68f7709cb75a8fefb7536daa77812cc3RoboErik     * {@link AudioManager#registerRemoteControlClient}. The session returned
4075f31737c68f7709cb75a8fefb7536daa77812cc3RoboErik     * should not be modified directly by the application but may be used with
4085f31737c68f7709cb75a8fefb7536daa77812cc3RoboErik     * other APIs that require a session.
4095f31737c68f7709cb75a8fefb7536daa77812cc3RoboErik     *
4105f31737c68f7709cb75a8fefb7536daa77812cc3RoboErik     * @return A media session object or null.
4115f31737c68f7709cb75a8fefb7536daa77812cc3RoboErik     */
4125f31737c68f7709cb75a8fefb7536daa77812cc3RoboErik    public MediaSession getMediaSession() {
4135f31737c68f7709cb75a8fefb7536daa77812cc3RoboErik        return mSession;
4145f31737c68f7709cb75a8fefb7536daa77812cc3RoboErik    }
4155f31737c68f7709cb75a8fefb7536daa77812cc3RoboErik
4165f31737c68f7709cb75a8fefb7536daa77812cc3RoboErik    /**
4174426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     * Class used to modify metadata in a {@link RemoteControlClient} object.
418466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi     * Use {@link RemoteControlClient#editMetadata(boolean)} to create an instance of an editor,
419466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi     * on which you set the metadata for the RemoteControlClient instance. Once all the information
420466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi     * has been set, use {@link #apply()} to make it the new metadata that should be displayed
421466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi     * for the associated client. Once the metadata has been "applied", you cannot reuse this
422466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi     * instance of the MetadataEditor.
423edb158f55f48a1f7b2cbf30ddec9b8917dc9a619RoboErik     *
424edb158f55f48a1f7b2cbf30ddec9b8917dc9a619RoboErik     * @deprecated Use {@link MediaMetadata} and {@link MediaSession} instead.
4254426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     */
426edb158f55f48a1f7b2cbf30ddec9b8917dc9a619RoboErik    @Deprecated public class MetadataEditor extends MediaMetadataEditor {
4274da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi
4284da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi        // only use RemoteControlClient.editMetadata() to get a MetadataEditor instance
4294da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi        private MetadataEditor() { }
4304da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi        /**
4314da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi         * @hide
4324da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi         */
4334da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi        public Object clone() throws CloneNotSupportedException {
4344da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi            throw new CloneNotSupportedException();
4354426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi        }
4364426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi
4374da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi        /**
4385ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Trivi         * The metadata key for the content artwork / album art.
4395ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Trivi         */
440466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi        public final static int BITMAP_KEY_ARTWORK = 100;
441f823fc4dba2df5cf5f00e13361f2db93c81f6961Jean-Michel Trivi
442f823fc4dba2df5cf5f00e13361f2db93c81f6961Jean-Michel Trivi        /**
443f823fc4dba2df5cf5f00e13361f2db93c81f6961Jean-Michel Trivi         * @hide
44488183e67d4628e8c8a3310af0076b6f33f955cb2Jean-Michel Trivi         * TODO(jmtrivi) have lockscreen move to the new key name and remove
445466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi         */
446466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi        public final static int METADATA_KEY_ARTWORK = BITMAP_KEY_ARTWORK;
4475ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Trivi
4485ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Trivi        /**
4494da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi         * Adds textual information to be displayed.
4504da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi         * Note that none of the information added after {@link #apply()} has been called,
4514da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi         * will be displayed.
452466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi         * @param key The identifier of a the metadata field to set. Valid values are
4534da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi         *      {@link android.media.MediaMetadataRetriever#METADATA_KEY_ALBUM},
4544da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi         *      {@link android.media.MediaMetadataRetriever#METADATA_KEY_ALBUMARTIST},
4554da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi         *      {@link android.media.MediaMetadataRetriever#METADATA_KEY_TITLE},
4564da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi         *      {@link android.media.MediaMetadataRetriever#METADATA_KEY_ARTIST},
4574da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi         *      {@link android.media.MediaMetadataRetriever#METADATA_KEY_AUTHOR},
4584da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi         *      {@link android.media.MediaMetadataRetriever#METADATA_KEY_COMPILATION},
4594da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi         *      {@link android.media.MediaMetadataRetriever#METADATA_KEY_COMPOSER},
4604da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi         *      {@link android.media.MediaMetadataRetriever#METADATA_KEY_DATE},
4614da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi         *      {@link android.media.MediaMetadataRetriever#METADATA_KEY_GENRE},
4624da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi         *      {@link android.media.MediaMetadataRetriever#METADATA_KEY_TITLE},
463466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi         *      {@link android.media.MediaMetadataRetriever#METADATA_KEY_WRITER}.
464466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi         * @param value The text for the given key, or {@code null} to signify there is no valid
4654da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi         *      information for the field.
466466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi         * @return Returns a reference to the same MetadataEditor object, so you can chain put
467466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi         *      calls together.
4684da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi         */
4695ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Trivi        public synchronized MetadataEditor putString(int key, String value)
4705ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Trivi                throws IllegalArgumentException {
47188183e67d4628e8c8a3310af0076b6f33f955cb2Jean-Michel Trivi            super.putString(key, value);
472f1372428f2df781c71c71caa2f6a4db6f847cf10RoboErik            if (mMetadataBuilder != null) {
473f1372428f2df781c71c71caa2f6a4db6f847cf10RoboErik                // MediaMetadata supports all the same fields as MetadataEditor
474f1372428f2df781c71c71caa2f6a4db6f847cf10RoboErik                String metadataKey = MediaMetadata.getKeyFromMetadataEditorKey(key);
475f1372428f2df781c71c71caa2f6a4db6f847cf10RoboErik                // But just in case, don't add things we don't understand
476f1372428f2df781c71c71caa2f6a4db6f847cf10RoboErik                if (metadataKey != null) {
47775847b98f39e521a57042c50e69be9e142788d32RoboErik                    mMetadataBuilder.putText(metadataKey, value);
478f1372428f2df781c71c71caa2f6a4db6f847cf10RoboErik                }
479f1372428f2df781c71c71caa2f6a4db6f847cf10RoboErik            }
480f1372428f2df781c71c71caa2f6a4db6f847cf10RoboErik
4814426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi            return this;
4824426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi        }
4834426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi
4844da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi        /**
485466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi         * Adds numerical information to be displayed.
486466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi         * Note that none of the information added after {@link #apply()} has been called,
487466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi         * will be displayed.
4885ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Trivi         * @param key the identifier of a the metadata field to set. Valid values are
4895ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Trivi         *      {@link android.media.MediaMetadataRetriever#METADATA_KEY_CD_TRACK_NUMBER},
4905ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Trivi         *      {@link android.media.MediaMetadataRetriever#METADATA_KEY_DISC_NUMBER},
4915ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Trivi         *      {@link android.media.MediaMetadataRetriever#METADATA_KEY_DURATION} (with a value
4925ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Trivi         *      expressed in milliseconds),
49388183e67d4628e8c8a3310af0076b6f33f955cb2Jean-Michel Trivi         *      {@link android.media.MediaMetadataRetriever#METADATA_KEY_YEAR}.
494466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi         * @param value The long value for the given key
495466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi         * @return Returns a reference to the same MetadataEditor object, so you can chain put
496466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi         *      calls together.
4975ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Trivi         * @throws IllegalArgumentException
4984da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi         */
4995ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Trivi        public synchronized MetadataEditor putLong(int key, long value)
5005ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Trivi                throws IllegalArgumentException {
50188183e67d4628e8c8a3310af0076b6f33f955cb2Jean-Michel Trivi            super.putLong(key, value);
502f1372428f2df781c71c71caa2f6a4db6f847cf10RoboErik            if (mMetadataBuilder != null) {
503f1372428f2df781c71c71caa2f6a4db6f847cf10RoboErik                // MediaMetadata supports all the same fields as MetadataEditor
504f1372428f2df781c71c71caa2f6a4db6f847cf10RoboErik                String metadataKey = MediaMetadata.getKeyFromMetadataEditorKey(key);
505f1372428f2df781c71c71caa2f6a4db6f847cf10RoboErik                // But just in case, don't add things we don't understand
506f1372428f2df781c71c71caa2f6a4db6f847cf10RoboErik                if (metadataKey != null) {
507f1372428f2df781c71c71caa2f6a4db6f847cf10RoboErik                    mMetadataBuilder.putLong(metadataKey, value);
508f1372428f2df781c71c71caa2f6a4db6f847cf10RoboErik                }
509f1372428f2df781c71c71caa2f6a4db6f847cf10RoboErik            }
5105ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Trivi            return this;
5115ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Trivi        }
5124da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi
5134da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi        /**
5144da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi         * Sets the album / artwork picture to be displayed on the remote control.
515466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi         * @param key the identifier of the bitmap to set. The only valid value is
516466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi         *      {@link #BITMAP_KEY_ARTWORK}
517466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi         * @param bitmap The bitmap for the artwork, or null if there isn't any.
518466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi         * @return Returns a reference to the same MetadataEditor object, so you can chain put
519466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi         *      calls together.
5205ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Trivi         * @throws IllegalArgumentException
5214da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi         * @see android.graphics.Bitmap
5224da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi         */
52388183e67d4628e8c8a3310af0076b6f33f955cb2Jean-Michel Trivi        @Override
5245ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Trivi        public synchronized MetadataEditor putBitmap(int key, Bitmap bitmap)
5255ad4b9fb96089e460902ffac9f3649366afd3750Jean-Michel Trivi                throws IllegalArgumentException {
52688183e67d4628e8c8a3310af0076b6f33f955cb2Jean-Michel Trivi            super.putBitmap(key, bitmap);
527f1372428f2df781c71c71caa2f6a4db6f847cf10RoboErik            if (mMetadataBuilder != null) {
528f1372428f2df781c71c71caa2f6a4db6f847cf10RoboErik                // MediaMetadata supports all the same fields as MetadataEditor
529f1372428f2df781c71c71caa2f6a4db6f847cf10RoboErik                String metadataKey = MediaMetadata.getKeyFromMetadataEditorKey(key);
530f1372428f2df781c71c71caa2f6a4db6f847cf10RoboErik                // But just in case, don't add things we don't understand
531f1372428f2df781c71c71caa2f6a4db6f847cf10RoboErik                if (metadataKey != null) {
532f1372428f2df781c71c71caa2f6a4db6f847cf10RoboErik                    mMetadataBuilder.putBitmap(metadataKey, bitmap);
533f1372428f2df781c71c71caa2f6a4db6f847cf10RoboErik                }
534f1372428f2df781c71c71caa2f6a4db6f847cf10RoboErik            }
5354da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi            return this;
5364426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi        }
537178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi
53838696ba77d7f614cb50672aaca99f7ba59b56126RoboErik        @Override
53938696ba77d7f614cb50672aaca99f7ba59b56126RoboErik        public synchronized MetadataEditor putObject(int key, Object object)
54038696ba77d7f614cb50672aaca99f7ba59b56126RoboErik                throws IllegalArgumentException {
54138696ba77d7f614cb50672aaca99f7ba59b56126RoboErik            super.putObject(key, object);
54238696ba77d7f614cb50672aaca99f7ba59b56126RoboErik            if (mMetadataBuilder != null &&
54338696ba77d7f614cb50672aaca99f7ba59b56126RoboErik                    (key == MediaMetadataEditor.RATING_KEY_BY_USER ||
54438696ba77d7f614cb50672aaca99f7ba59b56126RoboErik                    key == MediaMetadataEditor.RATING_KEY_BY_OTHERS)) {
54538696ba77d7f614cb50672aaca99f7ba59b56126RoboErik                String metadataKey = MediaMetadata.getKeyFromMetadataEditorKey(key);
54638696ba77d7f614cb50672aaca99f7ba59b56126RoboErik                if (metadataKey != null) {
54738696ba77d7f614cb50672aaca99f7ba59b56126RoboErik                    mMetadataBuilder.putRating(metadataKey, (Rating) object);
54838696ba77d7f614cb50672aaca99f7ba59b56126RoboErik                }
54938696ba77d7f614cb50672aaca99f7ba59b56126RoboErik            }
55038696ba77d7f614cb50672aaca99f7ba59b56126RoboErik            return this;
55138696ba77d7f614cb50672aaca99f7ba59b56126RoboErik        }
55238696ba77d7f614cb50672aaca99f7ba59b56126RoboErik
5534da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi        /**
55488183e67d4628e8c8a3310af0076b6f33f955cb2Jean-Michel Trivi         * Clears all the metadata that has been set since the MetadataEditor instance was created
55588183e67d4628e8c8a3310af0076b6f33f955cb2Jean-Michel Trivi         * (with {@link RemoteControlClient#editMetadata(boolean)}).
556b23cd118ce3339589fffd40ecf1aa9c5816b3438Jean-Michel Trivi         * Note that clearing the metadata doesn't reset the editable keys
55788183e67d4628e8c8a3310af0076b6f33f955cb2Jean-Michel Trivi         * (use {@link MediaMetadataEditor#removeEditableKeys()} instead).
5584da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi         */
55988183e67d4628e8c8a3310af0076b6f33f955cb2Jean-Michel Trivi        @Override
5604da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi        public synchronized void clear() {
56188183e67d4628e8c8a3310af0076b6f33f955cb2Jean-Michel Trivi            super.clear();
562f823fc4dba2df5cf5f00e13361f2db93c81f6961Jean-Michel Trivi        }
563f823fc4dba2df5cf5f00e13361f2db93c81f6961Jean-Michel Trivi
564f823fc4dba2df5cf5f00e13361f2db93c81f6961Jean-Michel Trivi        /**
565466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi         * Associates all the metadata that has been set since the MetadataEditor instance was
566466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi         *     created with {@link RemoteControlClient#editMetadata(boolean)}, or since
567466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi         *     {@link #clear()} was called, with the RemoteControlClient. Once "applied",
568466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi         *     this MetadataEditor cannot be reused to edit the RemoteControlClient's metadata.
5694da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi         */
5704da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi        public synchronized void apply() {
5714da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi            if (mApplied) {
5724da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi                Log.e(TAG, "Can't apply a previously applied MetadataEditor");
5734da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi                return;
5744da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi            }
575f1372428f2df781c71c71caa2f6a4db6f847cf10RoboErik            synchronized (mCacheLock) {
576430fc48865e5a371b08f180390946b96d73848feRoboErik                // Still build the old metadata so when creating a new editor
577430fc48865e5a371b08f180390946b96d73848feRoboErik                // you get the expected values.
5784da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi                // assign the edited data
5794da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi                mMetadata = new Bundle(mEditorMetadata);
580f823fc4dba2df5cf5f00e13361f2db93c81f6961Jean-Michel Trivi                // add the information about editable keys
581f823fc4dba2df5cf5f00e13361f2db93c81f6961Jean-Michel Trivi                mMetadata.putLong(String.valueOf(KEY_EDITABLE_MASK), mEditableKeys);
5824a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi                if ((mOriginalArtwork != null) && (!mOriginalArtwork.equals(mEditorArtwork))) {
5834a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi                    mOriginalArtwork.recycle();
58434d0d300cac645b48cce5a1735f45e1102d4ef0eJean-Michel Trivi                }
5854a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi                mOriginalArtwork = mEditorArtwork;
58634d0d300cac645b48cce5a1735f45e1102d4ef0eJean-Michel Trivi                mEditorArtwork = null;
587f1372428f2df781c71c71caa2f6a4db6f847cf10RoboErik
588f1372428f2df781c71c71caa2f6a4db6f847cf10RoboErik                // USE_SESSIONS
589f1372428f2df781c71c71caa2f6a4db6f847cf10RoboErik                if (mSession != null && mMetadataBuilder != null) {
59051c07bc0bf338c9dd9d2345fe81d2cd964d680caRoboErik                    mMediaMetadata = mMetadataBuilder.build();
59151c07bc0bf338c9dd9d2345fe81d2cd964d680caRoboErik                    mSession.setMetadata(mMediaMetadata);
592f1372428f2df781c71c71caa2f6a4db6f847cf10RoboErik                }
5934da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi                mApplied = true;
5944da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi            }
5954426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi        }
5964426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    }
5974426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi
5984426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    /**
599466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi     * Creates a {@link MetadataEditor}.
600466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi     * @param startEmpty Set to false if you want the MetadataEditor to contain the metadata that
601466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi     *     was previously applied to the RemoteControlClient, or true if it is to be created empty.
602466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi     * @return a new MetadataEditor instance.
6034426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     */
6044da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi    public MetadataEditor editMetadata(boolean startEmpty) {
6054da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi        MetadataEditor editor = new MetadataEditor();
6064da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi        if (startEmpty) {
6074da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi            editor.mEditorMetadata = new Bundle();
6084da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi            editor.mEditorArtwork = null;
6094da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi            editor.mMetadataChanged = true;
6104da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi            editor.mArtworkChanged = true;
611f823fc4dba2df5cf5f00e13361f2db93c81f6961Jean-Michel Trivi            editor.mEditableKeys = 0;
6124da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi        } else {
6134da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi            editor.mEditorMetadata = new Bundle(mMetadata);
6144a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi            editor.mEditorArtwork = mOriginalArtwork;
6154da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi            editor.mMetadataChanged = false;
6164da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi            editor.mArtworkChanged = false;
6174426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi        }
618f1372428f2df781c71c71caa2f6a4db6f847cf10RoboErik        // USE_SESSIONS
619f1372428f2df781c71c71caa2f6a4db6f847cf10RoboErik        if (startEmpty || mMediaMetadata == null) {
620f1372428f2df781c71c71caa2f6a4db6f847cf10RoboErik            editor.mMetadataBuilder = new MediaMetadata.Builder();
621f1372428f2df781c71c71caa2f6a4db6f847cf10RoboErik        } else {
622f1372428f2df781c71c71caa2f6a4db6f847cf10RoboErik            editor.mMetadataBuilder = new MediaMetadata.Builder(mMediaMetadata);
623f1372428f2df781c71c71caa2f6a4db6f847cf10RoboErik        }
6244da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi        return editor;
6254426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    }
6264426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi
6274426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    /**
6284426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     * Sets the current playback state.
629466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi     * @param state The current playback state, one of the following values:
630178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     *       {@link #PLAYSTATE_STOPPED},
631178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     *       {@link #PLAYSTATE_PAUSED},
632178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     *       {@link #PLAYSTATE_PLAYING},
633178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     *       {@link #PLAYSTATE_FAST_FORWARDING},
634178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     *       {@link #PLAYSTATE_REWINDING},
635178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     *       {@link #PLAYSTATE_SKIPPING_FORWARDS},
636178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     *       {@link #PLAYSTATE_SKIPPING_BACKWARDS},
637178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     *       {@link #PLAYSTATE_BUFFERING},
638178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     *       {@link #PLAYSTATE_ERROR}.
639178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     */
6404426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    public void setPlaybackState(int state) {
6411b16cc3de51d69c8027cefcc70a084a5b2d7a3d0Jean-Michel Trivi        setPlaybackStateInt(state, PLAYBACK_POSITION_ALWAYS_UNKNOWN, PLAYBACK_SPEED_1X,
6421b16cc3de51d69c8027cefcc70a084a5b2d7a3d0Jean-Michel Trivi                false /* legacy API, converting to method with position and speed */);
643bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi    }
644bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi
645bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi    /**
646bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi     * Sets the current playback state and the matching media position for the current playback
647bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi     *   speed.
648bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi     * @param state The current playback state, one of the following values:
649bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi     *       {@link #PLAYSTATE_STOPPED},
650bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi     *       {@link #PLAYSTATE_PAUSED},
651bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi     *       {@link #PLAYSTATE_PLAYING},
652bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi     *       {@link #PLAYSTATE_FAST_FORWARDING},
653bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi     *       {@link #PLAYSTATE_REWINDING},
654bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi     *       {@link #PLAYSTATE_SKIPPING_FORWARDS},
655bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi     *       {@link #PLAYSTATE_SKIPPING_BACKWARDS},
656bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi     *       {@link #PLAYSTATE_BUFFERING},
657bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi     *       {@link #PLAYSTATE_ERROR}.
658bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi     * @param timeInMs a 0 or positive value for the current media position expressed in ms
659bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi     *    (same unit as for when sending the media duration, if applicable, with
660bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi     *    {@link android.media.MediaMetadataRetriever#METADATA_KEY_DURATION} in the
661bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi     *    {@link RemoteControlClient.MetadataEditor}). Negative values imply that position is not
662bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi     *    known (e.g. listening to a live stream of a radio) or not applicable (e.g. when state
663bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi     *    is {@link #PLAYSTATE_BUFFERING} and nothing had played yet).
664bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi     * @param playbackSpeed a value expressed as a ratio of 1x playback: 1.0f is normal playback,
665bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi     *    2.0f is 2x, 0.5f is half-speed, -2.0f is rewind at 2x speed. 0.0f means nothing is
666bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi     *    playing (e.g. when state is {@link #PLAYSTATE_ERROR}).
667bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi     */
668bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi    public void setPlaybackState(int state, long timeInMs, float playbackSpeed) {
6691b16cc3de51d69c8027cefcc70a084a5b2d7a3d0Jean-Michel Trivi        setPlaybackStateInt(state, timeInMs, playbackSpeed, true);
6701b16cc3de51d69c8027cefcc70a084a5b2d7a3d0Jean-Michel Trivi    }
6711b16cc3de51d69c8027cefcc70a084a5b2d7a3d0Jean-Michel Trivi
6721b16cc3de51d69c8027cefcc70a084a5b2d7a3d0Jean-Michel Trivi    private void setPlaybackStateInt(int state, long timeInMs, float playbackSpeed,
6731b16cc3de51d69c8027cefcc70a084a5b2d7a3d0Jean-Michel Trivi            boolean hasPosition) {
6744426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi        synchronized(mCacheLock) {
675bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi            if ((mPlaybackState != state) || (mPlaybackPositionMs != timeInMs)
676bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi                    || (mPlaybackSpeed != playbackSpeed)) {
67768622396b62f9084781add1e12f4d513b633ab54Jean-Michel Trivi                // store locally
67868622396b62f9084781add1e12f4d513b633ab54Jean-Michel Trivi                mPlaybackState = state;
6791b16cc3de51d69c8027cefcc70a084a5b2d7a3d0Jean-Michel Trivi                // distinguish between an application not knowing the current playback position
6801b16cc3de51d69c8027cefcc70a084a5b2d7a3d0Jean-Michel Trivi                // at the moment and an application using the API where only the playback state
6811b16cc3de51d69c8027cefcc70a084a5b2d7a3d0Jean-Michel Trivi                // is passed, not the playback position.
6821b16cc3de51d69c8027cefcc70a084a5b2d7a3d0Jean-Michel Trivi                if (hasPosition) {
6831b16cc3de51d69c8027cefcc70a084a5b2d7a3d0Jean-Michel Trivi                    if (timeInMs < 0) {
6841b16cc3de51d69c8027cefcc70a084a5b2d7a3d0Jean-Michel Trivi                        mPlaybackPositionMs = PLAYBACK_POSITION_INVALID;
6851b16cc3de51d69c8027cefcc70a084a5b2d7a3d0Jean-Michel Trivi                    } else {
6861b16cc3de51d69c8027cefcc70a084a5b2d7a3d0Jean-Michel Trivi                        mPlaybackPositionMs = timeInMs;
6871b16cc3de51d69c8027cefcc70a084a5b2d7a3d0Jean-Michel Trivi                    }
6881b16cc3de51d69c8027cefcc70a084a5b2d7a3d0Jean-Michel Trivi                } else {
6891b16cc3de51d69c8027cefcc70a084a5b2d7a3d0Jean-Michel Trivi                    mPlaybackPositionMs = PLAYBACK_POSITION_ALWAYS_UNKNOWN;
6901b16cc3de51d69c8027cefcc70a084a5b2d7a3d0Jean-Michel Trivi                }
691bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi                mPlaybackSpeed = playbackSpeed;
69268622396b62f9084781add1e12f4d513b633ab54Jean-Michel Trivi                // keep track of when the state change occurred
69368622396b62f9084781add1e12f4d513b633ab54Jean-Michel Trivi                mPlaybackStateChangeTimeMs = SystemClock.elapsedRealtime();
69468622396b62f9084781add1e12f4d513b633ab54Jean-Michel Trivi
695f1372428f2df781c71c71caa2f6a4db6f847cf10RoboErik                // USE_SESSIONS
696f1372428f2df781c71c71caa2f6a4db6f847cf10RoboErik                if (mSession != null) {
697f1372428f2df781c71c71caa2f6a4db6f847cf10RoboErik                    int pbState = PlaybackState.getStateFromRccState(state);
698c785a78fb483fe54012175c53d3758b2412de7b9RoboErik                    long position = hasPosition ? mPlaybackPositionMs
699c785a78fb483fe54012175c53d3758b2412de7b9RoboErik                            : PlaybackState.PLAYBACK_POSITION_UNKNOWN;
700c785a78fb483fe54012175c53d3758b2412de7b9RoboErik
701c785a78fb483fe54012175c53d3758b2412de7b9RoboErik                    PlaybackState.Builder bob = new PlaybackState.Builder(mSessionPlaybackState);
702c785a78fb483fe54012175c53d3758b2412de7b9RoboErik                    bob.setState(pbState, position, playbackSpeed, SystemClock.elapsedRealtime());
703c785a78fb483fe54012175c53d3758b2412de7b9RoboErik                    bob.setErrorMessage(null);
704c785a78fb483fe54012175c53d3758b2412de7b9RoboErik                    mSessionPlaybackState = bob.build();
705c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik                    mSession.setPlaybackState(mSessionPlaybackState);
706f1372428f2df781c71c71caa2f6a4db6f847cf10RoboErik                }
707521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi            }
708521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi        }
709521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi    }
710521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi
711430fc48865e5a371b08f180390946b96d73848feRoboErik    // TODO investigate if we still need position drift checking
712521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi    private void onPositionDriftCheck() {
713521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi        if (DEBUG) { Log.d(TAG, "onPositionDriftCheck()"); }
714521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi        synchronized(mCacheLock) {
715c3c4babf8424f65b3d3d2700f60fae6e94e9cd00Jean-Michel Trivi            if ((mEventHandler == null) || (mPositionProvider == null) || !mNeedsPositionSync) {
716521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi                return;
717521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi            }
718c3c4babf8424f65b3d3d2700f60fae6e94e9cd00Jean-Michel Trivi            if ((mPlaybackPositionMs < 0) || (mPlaybackSpeed == 0.0f)) {
719c3c4babf8424f65b3d3d2700f60fae6e94e9cd00Jean-Michel Trivi                if (DEBUG) { Log.d(TAG, " no valid position or 0 speed, no check needed"); }
720521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi                return;
721521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi            }
722521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi            long estPos = mPlaybackPositionMs + (long)
723521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi                    ((SystemClock.elapsedRealtime() - mPlaybackStateChangeTimeMs) / mPlaybackSpeed);
724521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi            long actPos = mPositionProvider.onGetPlaybackPosition();
725521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi            if (actPos >= 0) {
726521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi                if (Math.abs(estPos - actPos) > POSITION_DRIFT_MAX_MS) {
727521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi                    // drift happened, report the new position
728521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi                    if (DEBUG) { Log.w(TAG, " drift detected: actual=" +actPos +"  est=" +estPos); }
729521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi                    setPlaybackState(mPlaybackState, actPos, mPlaybackSpeed);
730521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi                } else {
731521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi                    if (DEBUG) { Log.d(TAG, " no drift: actual=" + actPos +"  est=" + estPos); }
732521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi                    // no drift, schedule the next drift check
733521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi                    mEventHandler.sendMessageDelayed(
734521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi                            mEventHandler.obtainMessage(MSG_POSITION_DRIFT_CHECK),
735521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi                            getCheckPeriodFromSpeed(mPlaybackSpeed));
736521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi                }
737521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi            } else {
738521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi                // invalid position (negative value), can't check for drift
739521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi                mEventHandler.removeMessages(MSG_POSITION_DRIFT_CHECK);
74068622396b62f9084781add1e12f4d513b633ab54Jean-Michel Trivi            }
7414426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi        }
7424426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    }
743178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi
744178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi    /**
7454426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     * Sets the flags for the media transport control buttons that this client supports.
746466ade5ad66e7bfb1814d5e5ac76a17f8a0bcd3aJean-Michel Trivi     * @param transportControlFlags A combination of the following flags:
7474426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     *      {@link #FLAG_KEY_MEDIA_PREVIOUS},
748178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     *      {@link #FLAG_KEY_MEDIA_REWIND},
749178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     *      {@link #FLAG_KEY_MEDIA_PLAY},
750178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     *      {@link #FLAG_KEY_MEDIA_PLAY_PAUSE},
751178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     *      {@link #FLAG_KEY_MEDIA_PAUSE},
752178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     *      {@link #FLAG_KEY_MEDIA_STOP},
753178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     *      {@link #FLAG_KEY_MEDIA_FAST_FORWARD},
754915747730060dff71b5b2ca7e4ee4073024fc24eJean-Michel Trivi     *      {@link #FLAG_KEY_MEDIA_NEXT},
755b23cd118ce3339589fffd40ecf1aa9c5816b3438Jean-Michel Trivi     *      {@link #FLAG_KEY_MEDIA_POSITION_UPDATE},
756b23cd118ce3339589fffd40ecf1aa9c5816b3438Jean-Michel Trivi     *      {@link #FLAG_KEY_MEDIA_RATING}.
757178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     */
7584426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    public void setTransportControlFlags(int transportControlFlags) {
7594426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi        synchronized(mCacheLock) {
7604426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi            // store locally
7614426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi            mTransportControlFlags = transportControlFlags;
7624426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi
763f1372428f2df781c71c71caa2f6a4db6f847cf10RoboErik            // USE_SESSIONS
764f1372428f2df781c71c71caa2f6a4db6f847cf10RoboErik            if (mSession != null) {
765c785a78fb483fe54012175c53d3758b2412de7b9RoboErik                PlaybackState.Builder bob = new PlaybackState.Builder(mSessionPlaybackState);
766f364f944962c4ec66f5e5b33dafe8480f38f6db6Gabriel Peal                bob.setActions(
767f364f944962c4ec66f5e5b33dafe8480f38f6db6Gabriel Peal                        PlaybackState.getActionsFromRccControlFlags(transportControlFlags));
768c785a78fb483fe54012175c53d3758b2412de7b9RoboErik                mSessionPlaybackState = bob.build();
769c47fa84b0a6bda48c38ba8822481ce613bafd019RoboErik                mSession.setPlaybackState(mSessionPlaybackState);
770f1372428f2df781c71c71caa2f6a4db6f847cf10RoboErik            }
7714426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi        }
7724426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    }
773178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi
774bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi    /**
775b23cd118ce3339589fffd40ecf1aa9c5816b3438Jean-Michel Trivi     * Interface definition for a callback to be invoked when one of the metadata values has
776b23cd118ce3339589fffd40ecf1aa9c5816b3438Jean-Michel Trivi     * been updated.
77788183e67d4628e8c8a3310af0076b6f33f955cb2Jean-Michel Trivi     * Implement this interface to receive metadata updates after registering your listener
77888183e67d4628e8c8a3310af0076b6f33f955cb2Jean-Michel Trivi     * through {@link RemoteControlClient#setMetadataUpdateListener(OnMetadataUpdateListener)}.
779f823fc4dba2df5cf5f00e13361f2db93c81f6961Jean-Michel Trivi     */
7807ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi    public interface OnMetadataUpdateListener {
781f823fc4dba2df5cf5f00e13361f2db93c81f6961Jean-Michel Trivi        /**
782b23cd118ce3339589fffd40ecf1aa9c5816b3438Jean-Michel Trivi         * Called on the implementer to notify that the metadata field for the given key has
78388183e67d4628e8c8a3310af0076b6f33f955cb2Jean-Michel Trivi         * been updated to the new value.
78488183e67d4628e8c8a3310af0076b6f33f955cb2Jean-Michel Trivi         * @param key the identifier of the updated metadata field.
78588183e67d4628e8c8a3310af0076b6f33f955cb2Jean-Michel Trivi         * @param newValue the Object storing the new value for the key.
786f823fc4dba2df5cf5f00e13361f2db93c81f6961Jean-Michel Trivi         */
78788183e67d4628e8c8a3310af0076b6f33f955cb2Jean-Michel Trivi        public abstract void onMetadataUpdate(int key, Object newValue);
788f823fc4dba2df5cf5f00e13361f2db93c81f6961Jean-Michel Trivi    }
789f823fc4dba2df5cf5f00e13361f2db93c81f6961Jean-Michel Trivi
790f823fc4dba2df5cf5f00e13361f2db93c81f6961Jean-Michel Trivi    /**
791b23cd118ce3339589fffd40ecf1aa9c5816b3438Jean-Michel Trivi     * Sets the listener to be called whenever the metadata is updated.
792b23cd118ce3339589fffd40ecf1aa9c5816b3438Jean-Michel Trivi     * New metadata values will be received in the same thread as the one in which
793b23cd118ce3339589fffd40ecf1aa9c5816b3438Jean-Michel Trivi     * RemoteControlClient was created.
794b23cd118ce3339589fffd40ecf1aa9c5816b3438Jean-Michel Trivi     * @param l the metadata update listener
795f823fc4dba2df5cf5f00e13361f2db93c81f6961Jean-Michel Trivi     */
796f823fc4dba2df5cf5f00e13361f2db93c81f6961Jean-Michel Trivi    public void setMetadataUpdateListener(OnMetadataUpdateListener l) {
797f823fc4dba2df5cf5f00e13361f2db93c81f6961Jean-Michel Trivi        synchronized(mCacheLock) {
798f823fc4dba2df5cf5f00e13361f2db93c81f6961Jean-Michel Trivi            mMetadataUpdateListener = l;
799f823fc4dba2df5cf5f00e13361f2db93c81f6961Jean-Michel Trivi        }
800f823fc4dba2df5cf5f00e13361f2db93c81f6961Jean-Michel Trivi    }
801f823fc4dba2df5cf5f00e13361f2db93c81f6961Jean-Michel Trivi
802f823fc4dba2df5cf5f00e13361f2db93c81f6961Jean-Michel Trivi
803f823fc4dba2df5cf5f00e13361f2db93c81f6961Jean-Michel Trivi    /**
804bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi     * Interface definition for a callback to be invoked when the media playback position is
805bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi     * requested to be updated.
8063261b537c5fdec824575a1f6ad6d8942715e82e2Jean-Michel Trivi     * @see RemoteControlClient#FLAG_KEY_MEDIA_POSITION_UPDATE
807bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi     */
808bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi    public interface OnPlaybackPositionUpdateListener {
809bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi        /**
8103261b537c5fdec824575a1f6ad6d8942715e82e2Jean-Michel Trivi         * Called on the implementer to notify it that the playback head should be set at the given
811bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi         * position. If the position can be changed from its current value, the implementor of
8123fbf67e217fb489fe7318a9e43d8ae86646eb4ccJean-Michel Trivi         * the interface must also update the playback position using
813e63b0609c3b5f6c21d4e006ee9ddd3ba98a4e684Scott Main         * {@link #setPlaybackState(int, long, float)} to reflect the actual new
814bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi         * position being used, regardless of whether it differs from the requested position.
8153fbf67e217fb489fe7318a9e43d8ae86646eb4ccJean-Michel Trivi         * Failure to do so would cause the system to not know the new actual playback position,
8163fbf67e217fb489fe7318a9e43d8ae86646eb4ccJean-Michel Trivi         * and user interface components would fail to show the user where playback resumed after
8173fbf67e217fb489fe7318a9e43d8ae86646eb4ccJean-Michel Trivi         * the position was updated.
818bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi         * @param newPositionMs the new requested position in the current media, expressed in ms.
819bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi         */
820bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi        void onPlaybackPositionUpdate(long newPositionMs);
821bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi    }
822bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi
823bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi    /**
8243261b537c5fdec824575a1f6ad6d8942715e82e2Jean-Michel Trivi     * Interface definition for a callback to be invoked when the media playback position is
8253261b537c5fdec824575a1f6ad6d8942715e82e2Jean-Michel Trivi     * queried.
8263261b537c5fdec824575a1f6ad6d8942715e82e2Jean-Michel Trivi     * @see RemoteControlClient#FLAG_KEY_MEDIA_POSITION_UPDATE
8273261b537c5fdec824575a1f6ad6d8942715e82e2Jean-Michel Trivi     */
828915747730060dff71b5b2ca7e4ee4073024fc24eJean-Michel Trivi    public interface OnGetPlaybackPositionListener {
8293261b537c5fdec824575a1f6ad6d8942715e82e2Jean-Michel Trivi        /**
8303261b537c5fdec824575a1f6ad6d8942715e82e2Jean-Michel Trivi         * Called on the implementer of the interface to query the current playback position.
8313261b537c5fdec824575a1f6ad6d8942715e82e2Jean-Michel Trivi         * @return a negative value if the current playback position (or the last valid playback
8323261b537c5fdec824575a1f6ad6d8942715e82e2Jean-Michel Trivi         *     position) is not known, or a zero or positive value expressed in ms indicating the
8333261b537c5fdec824575a1f6ad6d8942715e82e2Jean-Michel Trivi         *     current position, or the last valid known position.
8343261b537c5fdec824575a1f6ad6d8942715e82e2Jean-Michel Trivi         */
835915747730060dff71b5b2ca7e4ee4073024fc24eJean-Michel Trivi        long onGetPlaybackPosition();
8363261b537c5fdec824575a1f6ad6d8942715e82e2Jean-Michel Trivi    }
8373261b537c5fdec824575a1f6ad6d8942715e82e2Jean-Michel Trivi
8383261b537c5fdec824575a1f6ad6d8942715e82e2Jean-Michel Trivi    /**
8393261b537c5fdec824575a1f6ad6d8942715e82e2Jean-Michel Trivi     * Sets the listener to be called whenever the media playback position is requested
840bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi     * to be updated.
841bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi     * Notifications will be received in the same thread as the one in which RemoteControlClient
842bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi     * was created.
843915747730060dff71b5b2ca7e4ee4073024fc24eJean-Michel Trivi     * @param l the position update listener to be called
844bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi     */
845bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi    public void setPlaybackPositionUpdateListener(OnPlaybackPositionUpdateListener l) {
846bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi        synchronized(mCacheLock) {
847bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi            mPositionUpdateListener = l;
8483261b537c5fdec824575a1f6ad6d8942715e82e2Jean-Michel Trivi        }
8493261b537c5fdec824575a1f6ad6d8942715e82e2Jean-Michel Trivi    }
8503261b537c5fdec824575a1f6ad6d8942715e82e2Jean-Michel Trivi
8513261b537c5fdec824575a1f6ad6d8942715e82e2Jean-Michel Trivi    /**
8523261b537c5fdec824575a1f6ad6d8942715e82e2Jean-Michel Trivi     * Sets the listener to be called whenever the media current playback position is needed.
8533261b537c5fdec824575a1f6ad6d8942715e82e2Jean-Michel Trivi     * Queries will be received in the same thread as the one in which RemoteControlClient
8543261b537c5fdec824575a1f6ad6d8942715e82e2Jean-Michel Trivi     * was created.
855915747730060dff71b5b2ca7e4ee4073024fc24eJean-Michel Trivi     * @param l the listener to be called to retrieve the playback position
8563261b537c5fdec824575a1f6ad6d8942715e82e2Jean-Michel Trivi     */
857915747730060dff71b5b2ca7e4ee4073024fc24eJean-Michel Trivi    public void setOnGetPlaybackPositionListener(OnGetPlaybackPositionListener l) {
8583261b537c5fdec824575a1f6ad6d8942715e82e2Jean-Michel Trivi        synchronized(mCacheLock) {
8593261b537c5fdec824575a1f6ad6d8942715e82e2Jean-Michel Trivi            mPositionProvider = l;
860521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi            if ((mPositionProvider != null) && (mEventHandler != null)
861521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi                    && playbackPositionShouldMove(mPlaybackState)) {
862521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi                // playback position is already moving, but now we have a position provider,
863521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi                // so schedule a drift check right now
864521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi                mEventHandler.sendMessageDelayed(
865521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi                        mEventHandler.obtainMessage(MSG_POSITION_DRIFT_CHECK),
866521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi                        0 /*check now*/);
867521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi            }
868bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi        }
869bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi    }
870bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi
871bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi    /**
872bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi     * @hide
873bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi     * Flag to reflect that the application controlling this RemoteControlClient sends playback
874bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi     * position updates. The playback position being "readable" is considered from the application's
875bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi     * point of view.
876bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi     */
877bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi    public static int MEDIA_POSITION_READABLE = 1 << 0;
878bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi    /**
879bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi     * @hide
880bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi     * Flag to reflect that the application controlling this RemoteControlClient can receive
881bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi     * playback position updates. The playback position being "writable"
882bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi     * is considered from the application's point of view.
883bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi     */
884bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi    public static int MEDIA_POSITION_WRITABLE = 1 << 1;
885bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi
8863114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    /** @hide */
8873114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    public final static int DEFAULT_PLAYBACK_VOLUME_HANDLING = PLAYBACK_VOLUME_VARIABLE;
8883114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    /** @hide */
8893114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    // hard-coded to the same number of steps as AudioService.MAX_STREAM_VOLUME[STREAM_MUSIC]
8903114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    public final static int DEFAULT_PLAYBACK_VOLUME = 15;
8913114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi
892178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi    /**
8934426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     * Lock for all cached data
8944426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     */
8954426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    private final Object mCacheLock = new Object();
8964426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    /**
8974426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     * Cache for the playback state.
8984426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     * Access synchronized on mCacheLock
899178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi     */
9004426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    private int mPlaybackState = PLAYSTATE_NONE;
9014426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    /**
90268622396b62f9084781add1e12f4d513b633ab54Jean-Michel Trivi     * Time of last play state change
90368622396b62f9084781add1e12f4d513b633ab54Jean-Michel Trivi     * Access synchronized on mCacheLock
90468622396b62f9084781add1e12f4d513b633ab54Jean-Michel Trivi     */
90568622396b62f9084781add1e12f4d513b633ab54Jean-Michel Trivi    private long mPlaybackStateChangeTimeMs = 0;
90668622396b62f9084781add1e12f4d513b633ab54Jean-Michel Trivi    /**
907bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi     * Last playback position in ms reported by the user
908bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi     */
909bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi    private long mPlaybackPositionMs = PLAYBACK_POSITION_INVALID;
910bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi    /**
911bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi     * Last playback speed reported by the user
912bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi     */
913bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi    private float mPlaybackSpeed = PLAYBACK_SPEED_1X;
914bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi    /**
9154426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     * Cache for the artwork bitmap.
9164426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     * Access synchronized on mCacheLock
9174da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi     * Artwork and metadata are not kept in one Bundle because the bitmap sometimes needs to be
9184da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi     * accessed to be resized, in which case a copy will be made. This would add overhead in
9194da5eeffc92331b958eeb111aa2f3d938083954eJean-Michel Trivi     * Bundle operations.
9204426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     */
9214a5700556191c835116ec2a6997a4f16f464ac9dJean-Michel Trivi    private Bitmap mOriginalArtwork;
9224426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    /**
9234426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     * Cache for the transport control mask.
9244426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     * Access synchronized on mCacheLock
9254426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     */
9264426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    private int mTransportControlFlags = FLAGS_KEY_MEDIA_NONE;
9274426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    /**
9284426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     * Cache for the metadata strings.
9294426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     * Access synchronized on mCacheLock
93030c918ce7fbe171944b28fc91b3f22b3d631872dGlenn Kasten     * This is re-initialized in apply() and so cannot be final.
9314426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     */
9324426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    private Bundle mMetadata = new Bundle();
9334426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    /**
934bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi     * Listener registered by user of RemoteControlClient to receive requests for playback position
935bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi     * update requests.
936bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi     */
937bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi    private OnPlaybackPositionUpdateListener mPositionUpdateListener;
938bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi    /**
9393261b537c5fdec824575a1f6ad6d8942715e82e2Jean-Michel Trivi     * Provider registered by user of RemoteControlClient to provide the current playback position.
9403261b537c5fdec824575a1f6ad6d8942715e82e2Jean-Michel Trivi     */
941915747730060dff71b5b2ca7e4ee4073024fc24eJean-Michel Trivi    private OnGetPlaybackPositionListener mPositionProvider;
9423261b537c5fdec824575a1f6ad6d8942715e82e2Jean-Michel Trivi    /**
943f823fc4dba2df5cf5f00e13361f2db93c81f6961Jean-Michel Trivi     * Listener registered by user of RemoteControlClient to receive edit changes to metadata
944f823fc4dba2df5cf5f00e13361f2db93c81f6961Jean-Michel Trivi     * it exposes.
945f823fc4dba2df5cf5f00e13361f2db93c81f6961Jean-Michel Trivi     */
946f823fc4dba2df5cf5f00e13361f2db93c81f6961Jean-Michel Trivi    private OnMetadataUpdateListener mMetadataUpdateListener;
947f823fc4dba2df5cf5f00e13361f2db93c81f6961Jean-Michel Trivi    /**
948bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi     * The current remote control client generation ID across the system, as known by this object
9494426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     */
9504426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    private int mCurrentClientGenId = -1;
9514426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi
9524426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    /**
953f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi     * The media button intent description associated with this remote control client
954bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi     * (can / should include target component for intent handling, used when persisting media
955bc43b4c2f24fd03c0d0546895c97918c1736d9fbJean-Michel Trivi     *    button event receiver across reboots).
9564426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     */
957f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi    private final PendingIntent mRcMediaIntent;
9584426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi
9594426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    /**
960c3c4babf8424f65b3d3d2700f60fae6e94e9cd00Jean-Michel Trivi     * Reflects whether any "plugged in" IRemoteControlDisplay has mWantsPositonSync set to true.
961c3c4babf8424f65b3d3d2700f60fae6e94e9cd00Jean-Michel Trivi     */
962c3c4babf8424f65b3d3d2700f60fae6e94e9cd00Jean-Michel Trivi    // TODO consider using a ref count for IRemoteControlDisplay requiring sync instead
963c3c4babf8424f65b3d3d2700f60fae6e94e9cd00Jean-Michel Trivi    private boolean mNeedsPositionSync = false;
964c3c4babf8424f65b3d3d2700f60fae6e94e9cd00Jean-Michel Trivi
965c3c4babf8424f65b3d3d2700f60fae6e94e9cd00Jean-Michel Trivi    /**
966f1372428f2df781c71c71caa2f6a4db6f847cf10RoboErik     * Cache for the current playback state using Session APIs.
967f1372428f2df781c71c71caa2f6a4db6f847cf10RoboErik     */
968c785a78fb483fe54012175c53d3758b2412de7b9RoboErik    private PlaybackState mSessionPlaybackState = null;
969f1372428f2df781c71c71caa2f6a4db6f847cf10RoboErik
970f1372428f2df781c71c71caa2f6a4db6f847cf10RoboErik    /**
971f1372428f2df781c71c71caa2f6a4db6f847cf10RoboErik     * Cache for metadata using Session APIs. This is re-initialized in apply().
972f1372428f2df781c71c71caa2f6a4db6f847cf10RoboErik     */
973f1372428f2df781c71c71caa2f6a4db6f847cf10RoboErik    private MediaMetadata mMediaMetadata;
974f1372428f2df781c71c71caa2f6a4db6f847cf10RoboErik
975f1372428f2df781c71c71caa2f6a4db6f847cf10RoboErik    /**
9764426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     * @hide
977f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi     * Accessor to media button intent description (includes target component)
9784426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     */
979f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi    public PendingIntent getRcMediaIntent() {
980f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi        return mRcMediaIntent;
9814426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    }
9824426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi
9833114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    /**
9843114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     * @hide
9853114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     * Default value for the unique identifier
9863114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     */
9873114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    public final static int RCSE_ID_UNREGISTERED = -1;
9881357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi
989f1372428f2df781c71c71caa2f6a4db6f847cf10RoboErik    // USE_SESSIONS
990477d1197c3c25c01ace7ea4494437c23720a2eb3RoboErik    private MediaSession.Callback mTransportListener = new MediaSession.Callback() {
991f1372428f2df781c71c71caa2f6a4db6f847cf10RoboErik
992f1372428f2df781c71c71caa2f6a4db6f847cf10RoboErik        @Override
993f1372428f2df781c71c71caa2f6a4db6f847cf10RoboErik        public void onSeekTo(long pos) {
994f1372428f2df781c71c71caa2f6a4db6f847cf10RoboErik            RemoteControlClient.this.onSeekTo(mCurrentClientGenId, pos);
995f1372428f2df781c71c71caa2f6a4db6f847cf10RoboErik        }
996f1372428f2df781c71c71caa2f6a4db6f847cf10RoboErik
997f1372428f2df781c71c71caa2f6a4db6f847cf10RoboErik        @Override
99879fa4630bbca7c6c251eea99fe8997e4b45beceeRoboErik        public void onSetRating(Rating rating) {
999f1372428f2df781c71c71caa2f6a4db6f847cf10RoboErik            if ((mTransportControlFlags & FLAG_KEY_MEDIA_RATING) != 0) {
1000430fc48865e5a371b08f180390946b96d73848feRoboErik                onUpdateMetadata(mCurrentClientGenId, MetadataEditor.RATING_KEY_BY_USER, rating);
1001f1372428f2df781c71c71caa2f6a4db6f847cf10RoboErik            }
1002f1372428f2df781c71c71caa2f6a4db6f847cf10RoboErik        }
1003f1372428f2df781c71c71caa2f6a4db6f847cf10RoboErik    };
1004f1372428f2df781c71c71caa2f6a4db6f847cf10RoboErik
10054426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    private EventHandler mEventHandler;
1006521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi    private final static int MSG_POSITION_DRIFT_CHECK = 11;
10074426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi
10084426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    private class EventHandler extends Handler {
10094426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi        public EventHandler(RemoteControlClient rcc, Looper looper) {
10104426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi            super(looper);
10114426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi        }
10124426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi
10134426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi        @Override
10144426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi        public void handleMessage(Message msg) {
10154426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi            switch(msg.what) {
1016521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi                case MSG_POSITION_DRIFT_CHECK:
1017521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi                    onPositionDriftCheck();
1018521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi                    break;
10194426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi                default:
10204426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi                    Log.e(TAG, "Unknown event " + msg.what + " in RemoteControlClient handler");
10214426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi            }
10224426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi        }
10234426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    }
10244426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi
10253114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    //===========================================================
10263114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    // Message handlers
10273114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi
10283261b537c5fdec824575a1f6ad6d8942715e82e2Jean-Michel Trivi    private void onSeekTo(int generationId, long timeMs) {
10293261b537c5fdec824575a1f6ad6d8942715e82e2Jean-Michel Trivi        synchronized (mCacheLock) {
10303261b537c5fdec824575a1f6ad6d8942715e82e2Jean-Michel Trivi            if ((mCurrentClientGenId == generationId) && (mPositionUpdateListener != null)) {
10313261b537c5fdec824575a1f6ad6d8942715e82e2Jean-Michel Trivi                mPositionUpdateListener.onPlaybackPositionUpdate(timeMs);
10323261b537c5fdec824575a1f6ad6d8942715e82e2Jean-Michel Trivi            }
10333261b537c5fdec824575a1f6ad6d8942715e82e2Jean-Michel Trivi        }
10343261b537c5fdec824575a1f6ad6d8942715e82e2Jean-Michel Trivi    }
10353261b537c5fdec824575a1f6ad6d8942715e82e2Jean-Michel Trivi
103688183e67d4628e8c8a3310af0076b6f33f955cb2Jean-Michel Trivi    private void onUpdateMetadata(int generationId, int key, Object value) {
1037f823fc4dba2df5cf5f00e13361f2db93c81f6961Jean-Michel Trivi        synchronized (mCacheLock) {
1038f823fc4dba2df5cf5f00e13361f2db93c81f6961Jean-Michel Trivi            if ((mCurrentClientGenId == generationId) && (mMetadataUpdateListener != null)) {
103988183e67d4628e8c8a3310af0076b6f33f955cb2Jean-Michel Trivi                mMetadataUpdateListener.onMetadataUpdate(key, value);
1040f823fc4dba2df5cf5f00e13361f2db93c81f6961Jean-Michel Trivi            }
1041f823fc4dba2df5cf5f00e13361f2db93c81f6961Jean-Michel Trivi        }
1042f823fc4dba2df5cf5f00e13361f2db93c81f6961Jean-Michel Trivi    }
1043f823fc4dba2df5cf5f00e13361f2db93c81f6961Jean-Michel Trivi
10443114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    //===========================================================
10453114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    // Internal utilities
10463114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi
10474426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    /**
1048521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi     * Returns whether, for the given playback state, the playback position is expected to
1049521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi     * be changing.
1050521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi     * @param playstate the playback state to evaluate
1051521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi     * @return true during any form of playback, false if it's not playing anything while in this
1052521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi     *     playback state
1053521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi     */
1054f8895248e2ac4dbb46622f3e04c7256f03175b4fAdam Powell    static boolean playbackPositionShouldMove(int playstate) {
1055521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi        switch(playstate) {
1056521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi            case PLAYSTATE_STOPPED:
1057521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi            case PLAYSTATE_PAUSED:
1058521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi            case PLAYSTATE_BUFFERING:
1059521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi            case PLAYSTATE_ERROR:
1060521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi            case PLAYSTATE_SKIPPING_FORWARDS:
1061521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi            case PLAYSTATE_SKIPPING_BACKWARDS:
1062521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi                return false;
1063521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi            case PLAYSTATE_PLAYING:
1064521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi            case PLAYSTATE_FAST_FORWARDING:
1065521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi            case PLAYSTATE_REWINDING:
1066521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi            default:
1067521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi                return true;
1068521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi        }
1069521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi    }
1070521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi
1071521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi    /**
1072521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi     * Period for playback position drift checks, 15s when playing at 1x or slower.
1073521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi     */
1074521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi    private final static long POSITION_REFRESH_PERIOD_PLAYING_MS = 15000;
1075521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi    /**
1076521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi     * Minimum period for playback position drift checks, never more often when every 2s, when
1077521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi     * fast forwarding or rewinding.
1078521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi     */
1079521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi    private final static long POSITION_REFRESH_PERIOD_MIN_MS = 2000;
1080521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi    /**
1081521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi     * The value above which the difference between client-reported playback position and
1082521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi     * estimated position is considered a drift.
1083521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi     */
1084521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi    private final static long POSITION_DRIFT_MAX_MS = 500;
1085521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi    /**
1086521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi     * Compute the period at which the estimated playback position should be compared against the
1087521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi     * actual playback position. Is a funciton of playback speed.
1088521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi     * @param speed 1.0f is normal playback speed
1089521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi     * @return the period in ms
1090521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi     */
1091521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi    private static long getCheckPeriodFromSpeed(float speed) {
1092521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi        if (Math.abs(speed) <= 1.0f) {
1093521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi            return POSITION_REFRESH_PERIOD_PLAYING_MS;
1094521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi        } else {
1095521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi            return Math.max((long)(POSITION_REFRESH_PERIOD_PLAYING_MS / Math.abs(speed)),
1096521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi                    POSITION_REFRESH_PERIOD_MIN_MS);
1097521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi        }
1098521e68e76cfdcf297d0de056032dc142d4939fa0Jean-Michel Trivi    }
1099178889eff7fa3361a5cb08d6d43846a1baf5216bJean-Michel Trivi}
1100