1fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi/*
2fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi * Copyright (C) 2013 The Android Open Source Project
3fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi *
4fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi * Licensed under the Apache License, Version 2.0 (the "License");
5fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi * you may not use this file except in compliance with the License.
6fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi * You may obtain a copy of the License at
7fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi *
8fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi *      http://www.apache.org/licenses/LICENSE-2.0
9fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi *
10fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi * Unless required by applicable law or agreed to in writing, software
11fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi * distributed under the License is distributed on an "AS IS" BASIS,
12fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi * See the License for the specific language governing permissions and
14fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi * limitations under the License.
15fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi */
16fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi
17fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivipackage android.media;
18fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi
19fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Triviimport android.app.Activity;
20f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Triviimport android.app.ActivityManager;
21fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Triviimport android.app.AppOpsManager;
22fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Triviimport android.app.KeyguardManager;
23fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Triviimport android.app.PendingIntent;
24fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Triviimport android.app.PendingIntent.CanceledException;
25fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Triviimport android.app.PendingIntent.OnFinished;
26fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Triviimport android.content.ActivityNotFoundException;
27fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Triviimport android.content.BroadcastReceiver;
28fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Triviimport android.content.ComponentName;
29fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Triviimport android.content.ContentResolver;
30fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Triviimport android.content.Context;
31fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Triviimport android.content.Intent;
32fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Triviimport android.content.IntentFilter;
33fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Triviimport android.content.pm.PackageManager;
34f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Triviimport android.database.ContentObserver;
35f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Triviimport android.net.Uri;
36fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Triviimport android.os.Binder;
37fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Triviimport android.os.Bundle;
38fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Triviimport android.os.Handler;
39fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Triviimport android.os.IBinder;
40fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Triviimport android.os.Looper;
41fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Triviimport android.os.Message;
42fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Triviimport android.os.PowerManager;
43fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Triviimport android.os.RemoteException;
44fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Triviimport android.os.UserHandle;
45fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Triviimport android.os.IBinder.DeathRecipient;
46fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Triviimport android.provider.Settings;
47fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Triviimport android.speech.RecognizerIntent;
48fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Triviimport android.telephony.PhoneStateListener;
49fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Triviimport android.telephony.TelephonyManager;
50fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Triviimport android.util.Log;
51f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Triviimport android.util.Slog;
52fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Triviimport android.view.KeyEvent;
53fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi
54fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Triviimport java.io.FileDescriptor;
55fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Triviimport java.io.PrintWriter;
56fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Triviimport java.util.ArrayList;
57fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Triviimport java.util.Iterator;
58fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Triviimport java.util.Stack;
59fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi
60fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi/**
61fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi * @hide
62fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi *
63fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi */
64fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivipublic class MediaFocusControl implements OnFinished {
65fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi
66fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    private static final String TAG = "MediaFocusControl";
67fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi
68fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    /** Debug remote control client/display feature */
69fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    protected static final boolean DEBUG_RC = false;
70fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    /** Debug volumes */
71fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    protected static final boolean DEBUG_VOL = false;
72fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi
73fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    /** Used to alter media button redirection when the phone is ringing. */
74fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    private boolean mIsRinging = false;
75fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi
76fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    private final PowerManager.WakeLock mMediaEventWakeLock;
77fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    private final MediaEventHandler mEventHandler;
78fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    private final Context mContext;
79fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    private final ContentResolver mContentResolver;
80fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    private final VolumeController mVolumeController;
81fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    private final BroadcastReceiver mReceiver = new PackageIntentsReceiver();
82fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    private final AppOpsManager mAppOps;
83fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    private final KeyguardManager mKeyguardManager;
84fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    private final AudioService mAudioService;
85f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi    private final NotificationListenerObserver mNotifListenerObserver;
86fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi
87fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    protected MediaFocusControl(Looper looper, Context cntxt,
88fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            VolumeController volumeCtrl, AudioService as) {
89fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        mEventHandler = new MediaEventHandler(looper);
90fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        mContext = cntxt;
91fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        mContentResolver = mContext.getContentResolver();
92fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        mVolumeController = volumeCtrl;
93fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        mAudioService = as;
94fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi
95fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        PowerManager pm = (PowerManager)mContext.getSystemService(Context.POWER_SERVICE);
96fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        mMediaEventWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "handleMediaEvent");
97fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        mMainRemote = new RemotePlaybackState(-1,
98fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                AudioService.getMaxStreamVolume(AudioManager.STREAM_MUSIC),
99fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                AudioService.getMaxStreamVolume(AudioManager.STREAM_MUSIC));
100fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi
101fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        // Register for phone state monitoring
102fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        TelephonyManager tmgr = (TelephonyManager)
103fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                mContext.getSystemService(Context.TELEPHONY_SERVICE);
104fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        tmgr.listen(mPhoneStateListener, PhoneStateListener.LISTEN_CALL_STATE);
105fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi
106fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        // Register for package addition/removal/change intent broadcasts
107fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        //    for media button receiver persistence
108fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        IntentFilter pkgFilter = new IntentFilter();
109fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        pkgFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
110fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        pkgFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
111fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        pkgFilter.addAction(Intent.ACTION_PACKAGE_CHANGED);
112fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        pkgFilter.addAction(Intent.ACTION_PACKAGE_DATA_CLEARED);
113fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        pkgFilter.addDataScheme("package");
114fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        mContext.registerReceiver(mReceiver, pkgFilter);
115fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi
116fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        mAppOps = (AppOpsManager)mContext.getSystemService(Context.APP_OPS_SERVICE);
117fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        mKeyguardManager =
118fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                (KeyguardManager) mContext.getSystemService(Context.KEYGUARD_SERVICE);
119f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi        mNotifListenerObserver = new NotificationListenerObserver();
120fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi
121fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        mHasRemotePlayback = false;
122fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        mMainRemoteIsActive = false;
123fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        postReevaluateRemote();
124fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    }
125fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi
12673673ab7988adc80fc179e9910c7a19fcabef884Jean-Michel Trivi    protected void dump(PrintWriter pw) {
12773673ab7988adc80fc179e9910c7a19fcabef884Jean-Michel Trivi        dumpFocusStack(pw);
12873673ab7988adc80fc179e9910c7a19fcabef884Jean-Michel Trivi        dumpRCStack(pw);
12973673ab7988adc80fc179e9910c7a19fcabef884Jean-Michel Trivi        dumpRCCStack(pw);
13073673ab7988adc80fc179e9910c7a19fcabef884Jean-Michel Trivi        dumpRCDList(pw);
13173673ab7988adc80fc179e9910c7a19fcabef884Jean-Michel Trivi    }
13273673ab7988adc80fc179e9910c7a19fcabef884Jean-Michel Trivi
13373673ab7988adc80fc179e9910c7a19fcabef884Jean-Michel Trivi    //==========================================================================================
134f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi    // Management of RemoteControlDisplay registration permissions
135f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi    //==========================================================================================
136f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi    private final static Uri ENABLED_NOTIFICATION_LISTENERS_URI =
137f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi            Settings.Secure.getUriFor(Settings.Secure.ENABLED_NOTIFICATION_LISTENERS);
138f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi
139f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi    private class NotificationListenerObserver extends ContentObserver {
140f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi
141f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi        NotificationListenerObserver() {
142f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi            super(mEventHandler);
143f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi            mContentResolver.registerContentObserver(Settings.Secure.getUriFor(
144f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi                    Settings.Secure.ENABLED_NOTIFICATION_LISTENERS), false, this);
145f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi        }
146f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi
147f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi        @Override
148f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi        public void onChange(boolean selfChange, Uri uri) {
149f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi            if (!ENABLED_NOTIFICATION_LISTENERS_URI.equals(uri) || selfChange) {
150f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi                return;
151f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi            }
152f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi            if (DEBUG_RC) { Log.d(TAG, "NotificationListenerObserver.onChange()"); }
153f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi            postReevaluateRemoteControlDisplays();
154f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi        }
155f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi    }
156f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi
157f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi    private final static int RCD_REG_FAILURE = 0;
158f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi    private final static int RCD_REG_SUCCESS_PERMISSION = 1;
159f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi    private final static int RCD_REG_SUCCESS_ENABLED_NOTIF = 2;
160f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi
161f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi    /**
162f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi     * Checks a caller's authorization to register an IRemoteControlDisplay.
163f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi     * Authorization is granted if one of the following is true:
164f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi     * <ul>
165f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi     * <li>the caller has android.Manifest.permission.MEDIA_CONTENT_CONTROL permission</li>
166f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi     * <li>the caller's listener is one of the enabled notification listeners</li>
167f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi     * </ul>
168f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi     * @return RCD_REG_FAILURE if it's not safe to proceed with the IRemoteControlDisplay
169f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi     *     registration.
170f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi     */
171f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi    private int checkRcdRegistrationAuthorization(ComponentName listenerComp) {
172f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi        // MEDIA_CONTENT_CONTROL permission check
173f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi        if (PackageManager.PERMISSION_GRANTED == mContext.checkCallingOrSelfPermission(
174f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi                android.Manifest.permission.MEDIA_CONTENT_CONTROL)) {
175f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi            if (DEBUG_RC) { Log.d(TAG, "ok to register Rcd: has MEDIA_CONTENT_CONTROL permission");}
176f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi            return RCD_REG_SUCCESS_PERMISSION;
177f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi        }
178f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi
179f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi        // ENABLED_NOTIFICATION_LISTENERS settings check
180f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi        if (listenerComp != null) {
181f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi            // this call is coming from an app, can't use its identity to read secure settings
182f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi            final long ident = Binder.clearCallingIdentity();
183f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi            try {
184f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi                final int currentUser = ActivityManager.getCurrentUser();
185f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi                final String enabledNotifListeners = Settings.Secure.getStringForUser(
186f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi                        mContext.getContentResolver(),
187f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi                        Settings.Secure.ENABLED_NOTIFICATION_LISTENERS,
188f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi                        currentUser);
189f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi                if (enabledNotifListeners != null) {
190f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi                    final String[] components = enabledNotifListeners.split(":");
191f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi                    for (int i=0; i<components.length; i++) {
192f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi                        final ComponentName component =
193f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi                                ComponentName.unflattenFromString(components[i]);
194f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi                        if (component != null) {
195f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi                            if (listenerComp.equals(component)) {
196f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi                                if (DEBUG_RC) { Log.d(TAG, "ok to register RCC: " + component +
197f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi                                        " is authorized notification listener"); }
198f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi                                return RCD_REG_SUCCESS_ENABLED_NOTIF;
199f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi                            }
200f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi                        }
201f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi                    }
202f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi                }
203f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi                if (DEBUG_RC) { Log.d(TAG, "not ok to register RCD, " + listenerComp +
204f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi                        " is not in list of ENABLED_NOTIFICATION_LISTENERS"); }
205f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi            } finally {
206f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi                Binder.restoreCallingIdentity(ident);
207f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi            }
208f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi        }
209f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi
210f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi        return RCD_REG_FAILURE;
211f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi    }
212f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi
213f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi    protected boolean registerRemoteController(IRemoteControlDisplay rcd, int w, int h,
214f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi            ComponentName listenerComp) {
215f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi        int reg = checkRcdRegistrationAuthorization(listenerComp);
216f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi        if (reg != RCD_REG_FAILURE) {
217f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi            registerRemoteControlDisplay_int(rcd, w, h, listenerComp);
218f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi            return true;
219f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi        } else {
220f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi            Slog.w(TAG, "Access denied to process: " + Binder.getCallingPid() +
221f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi                    ", must have permission " + android.Manifest.permission.MEDIA_CONTENT_CONTROL +
222f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi                    " or be an enabled NotificationListenerService for registerRemoteController");
223f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi            return false;
224f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi        }
225f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi    }
226f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi
227f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi    protected boolean registerRemoteControlDisplay(IRemoteControlDisplay rcd, int w, int h) {
228f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi        int reg = checkRcdRegistrationAuthorization(null);
229f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi        if (reg != RCD_REG_FAILURE) {
230f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi            registerRemoteControlDisplay_int(rcd, w, h, null);
231f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi            return true;
232f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi        } else {
233f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi            Slog.w(TAG, "Access denied to process: " + Binder.getCallingPid() +
234f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi                    ", must have permission " + android.Manifest.permission.MEDIA_CONTENT_CONTROL +
235f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi                    " to register IRemoteControlDisplay");
236f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi            return false;
237f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi        }
238f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi    }
239f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi
240f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi    private void postReevaluateRemoteControlDisplays() {
241f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi        sendMsg(mEventHandler, MSG_REEVALUATE_RCD, SENDMSG_QUEUE, 0, 0, null, 0);
242f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi    }
243f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi
244f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi    private void onReevaluateRemoteControlDisplays() {
245f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi        if (DEBUG_RC) { Log.d(TAG, "onReevaluateRemoteControlDisplays()"); }
246f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi        // read which components are enabled notification listeners
247f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi        final int currentUser = ActivityManager.getCurrentUser();
248f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi        final String enabledNotifListeners = Settings.Secure.getStringForUser(
249f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi                mContext.getContentResolver(),
250f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi                Settings.Secure.ENABLED_NOTIFICATION_LISTENERS,
251f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi                currentUser);
252f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi        if (DEBUG_RC) { Log.d(TAG, " > enabled list: " + enabledNotifListeners); }
253f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi        synchronized(mAudioFocusLock) {
254f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi            synchronized(mRCStack) {
255f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi                // check whether the "enable" status of each RCD with a notification listener
256f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi                // has changed
257f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi                final String[] enabledComponents;
258f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi                if (enabledNotifListeners == null) {
259f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi                    enabledComponents = null;
260f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi                } else {
261f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi                    enabledComponents = enabledNotifListeners.split(":");
262f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi                }
263f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi                final Iterator<DisplayInfoForServer> displayIterator = mRcDisplays.iterator();
264f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi                while (displayIterator.hasNext()) {
265f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi                    final DisplayInfoForServer di =
266f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi                            (DisplayInfoForServer) displayIterator.next();
267f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi                    if (di.mClientNotifListComp != null) {
268f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi                        boolean wasEnabled = di.mEnabled;
269f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi                        di.mEnabled = isComponentInStringArray(di.mClientNotifListComp,
270f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi                                enabledComponents);
271f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi                        if (wasEnabled != di.mEnabled){
272f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi                            try {
273f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi                                // tell the RCD whether it's enabled
274f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi                                di.mRcDisplay.setEnabled(di.mEnabled);
275f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi                                // tell the RCCs about the change for this RCD
276f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi                                enableRemoteControlDisplayForClient_syncRcStack(
277f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi                                        di.mRcDisplay, di.mEnabled);
27819566543c4833f50e7c22aff0c707388f8a338d2Jean-Michel Trivi                                // when enabling, refresh the information on the display
27919566543c4833f50e7c22aff0c707388f8a338d2Jean-Michel Trivi                                if (di.mEnabled) {
28019566543c4833f50e7c22aff0c707388f8a338d2Jean-Michel Trivi                                    sendMsg(mEventHandler, MSG_RCDISPLAY_INIT_INFO, SENDMSG_QUEUE,
28119566543c4833f50e7c22aff0c707388f8a338d2Jean-Michel Trivi                                            di.mArtworkExpectedWidth /*arg1*/,
28219566543c4833f50e7c22aff0c707388f8a338d2Jean-Michel Trivi                                            di.mArtworkExpectedHeight/*arg2*/,
28319566543c4833f50e7c22aff0c707388f8a338d2Jean-Michel Trivi                                            di.mRcDisplay /*obj*/, 0/*delay*/);
28419566543c4833f50e7c22aff0c707388f8a338d2Jean-Michel Trivi                                }
285f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi                            } catch (RemoteException e) {
286f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi                                Log.e(TAG, "Error en/disabling RCD: ", e);
287f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi                            }
288f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi                        }
289f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi                    }
290f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi                }
291f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi            }
292f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi        }
293f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi    }
294f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi
295f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi    /**
296f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi     * @param comp a non-null ComponentName
297f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi     * @param enabledArray may be null
298f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi     * @return
299f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi     */
300f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi    private boolean isComponentInStringArray(ComponentName comp, String[] enabledArray) {
301f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi        if (enabledArray == null || enabledArray.length == 0) {
302f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi            if (DEBUG_RC) { Log.d(TAG, " > " + comp + " is NOT enabled"); }
303f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi            return false;
304f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi        }
305f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi        final String compString = comp.flattenToString();
306f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi        for (int i=0; i<enabledArray.length; i++) {
307f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi            if (compString.equals(enabledArray[i])) {
308f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi                if (DEBUG_RC) { Log.d(TAG, " > " + compString + " is enabled"); }
309f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi                return true;
310f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi            }
311f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi        }
312f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi        if (DEBUG_RC) { Log.d(TAG, " > " + compString + " is NOT enabled"); }
313f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi        return false;
314f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi    }
315f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi
316f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi    //==========================================================================================
31773673ab7988adc80fc179e9910c7a19fcabef884Jean-Michel Trivi    // Internal event handling
31873673ab7988adc80fc179e9910c7a19fcabef884Jean-Michel Trivi    //==========================================================================================
31973673ab7988adc80fc179e9910c7a19fcabef884Jean-Michel Trivi
320fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    // event handler messages
321fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    private static final int MSG_PERSIST_MEDIABUTTONRECEIVER = 0;
322fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    private static final int MSG_RCDISPLAY_CLEAR = 1;
323fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    private static final int MSG_RCDISPLAY_UPDATE = 2;
324fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    private static final int MSG_REEVALUATE_REMOTE = 3;
325fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    private static final int MSG_RCC_NEW_PLAYBACK_INFO = 4;
326fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    private static final int MSG_RCC_NEW_VOLUME_OBS = 5;
327fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    private static final int MSG_PROMOTE_RCC = 6;
328fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    private static final int MSG_RCC_NEW_PLAYBACK_STATE = 7;
329fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    private static final int MSG_RCC_SEEK_REQUEST = 8;
3307ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi    private static final int MSG_RCC_UPDATE_METADATA = 9;
33186142da1ce8c1341404a9f9e21be8acbcba69ab3Jean-Michel Trivi    private static final int MSG_RCDISPLAY_INIT_INFO = 10;
332f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi    private static final int MSG_REEVALUATE_RCD = 11;
333fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi
334fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    // sendMsg() flags
335fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    /** If the msg is already queued, replace it with this one. */
336fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    private static final int SENDMSG_REPLACE = 0;
337fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    /** If the msg is already queued, ignore this one and leave the old. */
338fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    private static final int SENDMSG_NOOP = 1;
339fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    /** If the msg is already queued, queue this one and leave the old. */
340fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    private static final int SENDMSG_QUEUE = 2;
341fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi
342fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    private static void sendMsg(Handler handler, int msg,
343fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            int existingMsgPolicy, int arg1, int arg2, Object obj, int delay) {
344fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi
345fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        if (existingMsgPolicy == SENDMSG_REPLACE) {
346fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            handler.removeMessages(msg);
347fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        } else if (existingMsgPolicy == SENDMSG_NOOP && handler.hasMessages(msg)) {
348fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            return;
349fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        }
350fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi
351fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        handler.sendMessageDelayed(handler.obtainMessage(msg, arg1, arg2, obj), delay);
352fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    }
353fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi
354fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    private class MediaEventHandler extends Handler {
355fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        MediaEventHandler(Looper looper) {
356fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            super(looper);
357fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        }
358fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi
359fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        @Override
360fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        public void handleMessage(Message msg) {
361fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            switch(msg.what) {
362fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                case MSG_PERSIST_MEDIABUTTONRECEIVER:
363fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                    onHandlePersistMediaButtonReceiver( (ComponentName) msg.obj );
364fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                    break;
365fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi
366fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                case MSG_RCDISPLAY_CLEAR:
367fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                    onRcDisplayClear();
368fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                    break;
369fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi
370fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                case MSG_RCDISPLAY_UPDATE:
371fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                    // msg.obj is guaranteed to be non null
372fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                    onRcDisplayUpdate( (RemoteControlStackEntry) msg.obj, msg.arg1);
373fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                    break;
374fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi
375fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                case MSG_REEVALUATE_REMOTE:
376fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                    onReevaluateRemote();
377fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                    break;
378fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi
379fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                case MSG_RCC_NEW_PLAYBACK_INFO:
380fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                    onNewPlaybackInfoForRcc(msg.arg1 /* rccId */, msg.arg2 /* key */,
381fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                            ((Integer)msg.obj).intValue() /* value */);
382fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                    break;
383f823fc4dba2df5cf5f00e13361f2db93c81f6961Jean-Michel Trivi
384fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                case MSG_RCC_NEW_VOLUME_OBS:
385fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                    onRegisterVolumeObserverForRcc(msg.arg1 /* rccId */,
386fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                            (IRemoteVolumeObserver)msg.obj /* rvo */);
387fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                    break;
388f823fc4dba2df5cf5f00e13361f2db93c81f6961Jean-Michel Trivi
389fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                case MSG_RCC_NEW_PLAYBACK_STATE:
390fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                    onNewPlaybackStateForRcc(msg.arg1 /* rccId */,
391fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                            msg.arg2 /* state */,
392fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                            (RccPlaybackState)msg.obj /* newState */);
393fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                    break;
394f823fc4dba2df5cf5f00e13361f2db93c81f6961Jean-Michel Trivi
395fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                case MSG_RCC_SEEK_REQUEST:
396fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                    onSetRemoteControlClientPlaybackPosition(
397fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                            msg.arg1 /* generationId */, ((Long)msg.obj).longValue() /* timeMs */);
398f823fc4dba2df5cf5f00e13361f2db93c81f6961Jean-Michel Trivi                    break;
399f823fc4dba2df5cf5f00e13361f2db93c81f6961Jean-Michel Trivi
4007ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi                case MSG_RCC_UPDATE_METADATA:
4017ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi                    onUpdateRemoteControlClientMetadata(msg.arg1 /*genId*/, msg.arg2 /*key*/,
4027ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi                            (Rating) msg.obj /* value */);
403f823fc4dba2df5cf5f00e13361f2db93c81f6961Jean-Michel Trivi                    break;
404fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi
405fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                case MSG_PROMOTE_RCC:
406fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                    onPromoteRcc(msg.arg1);
407fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                    break;
40886142da1ce8c1341404a9f9e21be8acbcba69ab3Jean-Michel Trivi
40986142da1ce8c1341404a9f9e21be8acbcba69ab3Jean-Michel Trivi                case MSG_RCDISPLAY_INIT_INFO:
41086142da1ce8c1341404a9f9e21be8acbcba69ab3Jean-Michel Trivi                    // msg.obj is guaranteed to be non null
41186142da1ce8c1341404a9f9e21be8acbcba69ab3Jean-Michel Trivi                    onRcDisplayInitInfo((IRemoteControlDisplay)msg.obj /*newRcd*/,
41286142da1ce8c1341404a9f9e21be8acbcba69ab3Jean-Michel Trivi                            msg.arg1/*w*/, msg.arg2/*h*/);
41386142da1ce8c1341404a9f9e21be8acbcba69ab3Jean-Michel Trivi                    break;
414f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi
415f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi                case MSG_REEVALUATE_RCD:
416f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi                    onReevaluateRemoteControlDisplays();
417f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi                    break;
418fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            }
419fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        }
420fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    }
421fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi
422fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi
423fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    //==========================================================================================
424fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    // AudioFocus
425fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    //==========================================================================================
426fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi
427fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    /* constant to identify focus stack entry that is used to hold the focus while the phone
428fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi     * is ringing or during a call. Used by com.android.internal.telephony.CallManager when
429fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi     * entering and exiting calls.
430fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi     */
431fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    protected final static String IN_VOICE_COMM_FOCUS_ID = "AudioFocus_For_Phone_Ring_And_Calls";
432fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi
433fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    private final static Object mAudioFocusLock = new Object();
434fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi
435fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    private final static Object mRingingLock = new Object();
436fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi
437fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    private PhoneStateListener mPhoneStateListener = new PhoneStateListener() {
438fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        @Override
439fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        public void onCallStateChanged(int state, String incomingNumber) {
440fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            if (state == TelephonyManager.CALL_STATE_RINGING) {
441fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                //Log.v(TAG, " CALL_STATE_RINGING");
442fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                synchronized(mRingingLock) {
443fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                    mIsRinging = true;
444fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                }
445fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            } else if ((state == TelephonyManager.CALL_STATE_OFFHOOK)
446fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                    || (state == TelephonyManager.CALL_STATE_IDLE)) {
447fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                synchronized(mRingingLock) {
448fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                    mIsRinging = false;
449fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                }
450fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            }
451fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        }
452fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    };
453fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi
454fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    /**
455fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi     * Discard the current audio focus owner.
456fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi     * Notify top of audio focus stack that it lost focus (regardless of possibility to reassign
457fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi     * focus), remove it from the stack, and clear the remote control display.
458fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi     */
459fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    protected void discardAudioFocusOwner() {
460fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        synchronized(mAudioFocusLock) {
461cbb212ff6f06b004ae19dfb6958ee3852716bbdcJean-Michel Trivi            if (!mFocusStack.empty()) {
462fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                // notify the current focus owner it lost focus after removing it from stack
46383283f23eb1b7c1576e253c644b8aade6f657d0aJean-Michel Trivi                final FocusRequester exFocusOwner = mFocusStack.pop();
46400bf4b18173b8921d7a5cecbd8b8d3745470b5d0Jean-Michel Trivi                exFocusOwner.handleFocusLoss(AudioManager.AUDIOFOCUS_LOSS);
46583283f23eb1b7c1576e253c644b8aade6f657d0aJean-Michel Trivi                exFocusOwner.release();
466fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                // clear RCD
467fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                synchronized(mRCStack) {
468fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                    clearRemoteControlDisplay_syncAfRcs();
469fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                }
470fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            }
471fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        }
472fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    }
473fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi
474fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    private void notifyTopOfAudioFocusStack() {
475fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        // notify the top of the stack it gained focus
476cbb212ff6f06b004ae19dfb6958ee3852716bbdcJean-Michel Trivi        if (!mFocusStack.empty()) {
477fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            if (canReassignAudioFocus()) {
47800bf4b18173b8921d7a5cecbd8b8d3745470b5d0Jean-Michel Trivi                mFocusStack.peek().handleFocusGain(AudioManager.AUDIOFOCUS_GAIN);
479fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            }
480fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        }
481fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    }
482fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi
483cbb212ff6f06b004ae19dfb6958ee3852716bbdcJean-Michel Trivi    /**
484cbb212ff6f06b004ae19dfb6958ee3852716bbdcJean-Michel Trivi     * Focus is requested, propagate the associated loss throughout the stack.
485cbb212ff6f06b004ae19dfb6958ee3852716bbdcJean-Michel Trivi     * @param focusGain the new focus gain that will later be added at the top of the stack
486cbb212ff6f06b004ae19dfb6958ee3852716bbdcJean-Michel Trivi     */
487cbb212ff6f06b004ae19dfb6958ee3852716bbdcJean-Michel Trivi    private void propagateFocusLossFromGain_syncAf(int focusGain) {
488cbb212ff6f06b004ae19dfb6958ee3852716bbdcJean-Michel Trivi        // going through the audio focus stack to signal new focus, traversing order doesn't
489cbb212ff6f06b004ae19dfb6958ee3852716bbdcJean-Michel Trivi        // matter as all entries respond to the same external focus gain
490cbb212ff6f06b004ae19dfb6958ee3852716bbdcJean-Michel Trivi        Iterator<FocusRequester> stackIterator = mFocusStack.iterator();
491cbb212ff6f06b004ae19dfb6958ee3852716bbdcJean-Michel Trivi        while(stackIterator.hasNext()) {
492cbb212ff6f06b004ae19dfb6958ee3852716bbdcJean-Michel Trivi            stackIterator.next().handleExternalFocusGain(focusGain);
493cbb212ff6f06b004ae19dfb6958ee3852716bbdcJean-Michel Trivi        }
494cbb212ff6f06b004ae19dfb6958ee3852716bbdcJean-Michel Trivi    }
495cbb212ff6f06b004ae19dfb6958ee3852716bbdcJean-Michel Trivi
49683283f23eb1b7c1576e253c644b8aade6f657d0aJean-Michel Trivi    private final Stack<FocusRequester> mFocusStack = new Stack<FocusRequester>();
497fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi
498fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    /**
499fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi     * Helper function:
500fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi     * Display in the log the current entries in the audio focus stack
501fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi     */
502fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    private void dumpFocusStack(PrintWriter pw) {
503fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        pw.println("\nAudio Focus stack entries (last is top of stack):");
504fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        synchronized(mAudioFocusLock) {
50583283f23eb1b7c1576e253c644b8aade6f657d0aJean-Michel Trivi            Iterator<FocusRequester> stackIterator = mFocusStack.iterator();
506fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            while(stackIterator.hasNext()) {
50783283f23eb1b7c1576e253c644b8aade6f657d0aJean-Michel Trivi                stackIterator.next().dump(pw);
508fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            }
509fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        }
510fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    }
511fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi
512fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    /**
513fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi     * Helper function:
514fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi     * Called synchronized on mAudioFocusLock
515fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi     * Remove a focus listener from the focus stack.
516fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi     * @param clientToRemove the focus listener
517fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi     * @param signal if true and the listener was at the top of the focus stack, i.e. it was holding
518fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi     *   focus, notify the next item in the stack it gained focus.
519fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi     */
520fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    private void removeFocusStackEntry(String clientToRemove, boolean signal) {
521fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        // is the current top of the focus stack abandoning focus? (because of request, not death)
52283283f23eb1b7c1576e253c644b8aade6f657d0aJean-Michel Trivi        if (!mFocusStack.empty() && mFocusStack.peek().hasSameClient(clientToRemove))
523fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        {
524fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            //Log.i(TAG, "   removeFocusStackEntry() removing top of stack");
52583283f23eb1b7c1576e253c644b8aade6f657d0aJean-Michel Trivi            FocusRequester fr = mFocusStack.pop();
52683283f23eb1b7c1576e253c644b8aade6f657d0aJean-Michel Trivi            fr.release();
527fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            if (signal) {
528fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                // notify the new top of the stack it gained focus
529fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                notifyTopOfAudioFocusStack();
530fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                // there's a new top of the stack, let the remote control know
531fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                synchronized(mRCStack) {
532fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                    checkUpdateRemoteControlDisplay_syncAfRcs(RC_INFO_ALL);
533fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                }
534fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            }
535fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        } else {
536fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            // focus is abandoned by a client that's not at the top of the stack,
537fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            // no need to update focus.
538fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            // (using an iterator on the stack so we can safely remove an entry after having
539fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            //  evaluated it, traversal order doesn't matter here)
54083283f23eb1b7c1576e253c644b8aade6f657d0aJean-Michel Trivi            Iterator<FocusRequester> stackIterator = mFocusStack.iterator();
541fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            while(stackIterator.hasNext()) {
54283283f23eb1b7c1576e253c644b8aade6f657d0aJean-Michel Trivi                FocusRequester fr = (FocusRequester)stackIterator.next();
54383283f23eb1b7c1576e253c644b8aade6f657d0aJean-Michel Trivi                if(fr.hasSameClient(clientToRemove)) {
54400bf4b18173b8921d7a5cecbd8b8d3745470b5d0Jean-Michel Trivi                    Log.i(TAG, "AudioFocus  removeFocusStackEntry(): removing entry for "
54583283f23eb1b7c1576e253c644b8aade6f657d0aJean-Michel Trivi                            + clientToRemove);
546fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                    stackIterator.remove();
54783283f23eb1b7c1576e253c644b8aade6f657d0aJean-Michel Trivi                    fr.release();
548fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                }
549fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            }
550fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        }
551fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    }
552fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi
553fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    /**
554fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi     * Helper function:
555fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi     * Called synchronized on mAudioFocusLock
556fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi     * Remove focus listeners from the focus stack for a particular client when it has died.
557fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi     */
558fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    private void removeFocusStackEntryForClient(IBinder cb) {
559fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        // is the owner of the audio focus part of the client to remove?
560fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        boolean isTopOfStackForClientToRemove = !mFocusStack.isEmpty() &&
56183283f23eb1b7c1576e253c644b8aade6f657d0aJean-Michel Trivi                mFocusStack.peek().hasSameBinder(cb);
562fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        // (using an iterator on the stack so we can safely remove an entry after having
563fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        //  evaluated it, traversal order doesn't matter here)
56483283f23eb1b7c1576e253c644b8aade6f657d0aJean-Michel Trivi        Iterator<FocusRequester> stackIterator = mFocusStack.iterator();
565fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        while(stackIterator.hasNext()) {
56683283f23eb1b7c1576e253c644b8aade6f657d0aJean-Michel Trivi            FocusRequester fr = (FocusRequester)stackIterator.next();
56783283f23eb1b7c1576e253c644b8aade6f657d0aJean-Michel Trivi            if(fr.hasSameBinder(cb)) {
56883283f23eb1b7c1576e253c644b8aade6f657d0aJean-Michel Trivi                Log.i(TAG, "AudioFocus  removeFocusStackEntry(): removing entry for " + cb);
569fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                stackIterator.remove();
570fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                // the client just died, no need to unlink to its death
571fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            }
572fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        }
573fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        if (isTopOfStackForClientToRemove) {
574fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            // we removed an entry at the top of the stack:
575fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            //  notify the new top of the stack it gained focus.
576fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            notifyTopOfAudioFocusStack();
577fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            // there's a new top of the stack, let the remote control know
578fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            synchronized(mRCStack) {
579fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                checkUpdateRemoteControlDisplay_syncAfRcs(RC_INFO_ALL);
580fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            }
581fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        }
582fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    }
583fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi
584fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    /**
585fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi     * Helper function:
586fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi     * Returns true if the system is in a state where the focus can be reevaluated, false otherwise.
587fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi     */
588fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    private boolean canReassignAudioFocus() {
589fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        // focus requests are rejected during a phone call or when the phone is ringing
590fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        // this is equivalent to IN_VOICE_COMM_FOCUS_ID having the focus
59183283f23eb1b7c1576e253c644b8aade6f657d0aJean-Michel Trivi        if (!mFocusStack.isEmpty() && mFocusStack.peek().hasSameClient(IN_VOICE_COMM_FOCUS_ID)) {
592fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            return false;
593fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        }
594fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        return true;
595fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    }
596fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi
597fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    /**
598fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi     * Inner class to monitor audio focus client deaths, and remove them from the audio focus
599fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi     * stack if necessary.
600fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi     */
60183283f23eb1b7c1576e253c644b8aade6f657d0aJean-Michel Trivi    protected class AudioFocusDeathHandler implements IBinder.DeathRecipient {
602fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        private IBinder mCb; // To be notified of client's death
603fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi
604fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        AudioFocusDeathHandler(IBinder cb) {
605fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            mCb = cb;
606fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        }
607fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi
608fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        public void binderDied() {
609fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            synchronized(mAudioFocusLock) {
610fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                Log.w(TAG, "  AudioFocus   audio focus client died");
611fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                removeFocusStackEntryForClient(mCb);
612fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            }
613fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        }
614fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi
615fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        public IBinder getBinder() {
616fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            return mCb;
617fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        }
618fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    }
619fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi
6202380566debfc57eb1cc07db1306ccee23b84ddd4Jean-Michel Trivi    protected int getCurrentAudioFocus() {
6212380566debfc57eb1cc07db1306ccee23b84ddd4Jean-Michel Trivi        synchronized(mAudioFocusLock) {
6222380566debfc57eb1cc07db1306ccee23b84ddd4Jean-Michel Trivi            if (mFocusStack.empty()) {
6232380566debfc57eb1cc07db1306ccee23b84ddd4Jean-Michel Trivi                return AudioManager.AUDIOFOCUS_NONE;
6242380566debfc57eb1cc07db1306ccee23b84ddd4Jean-Michel Trivi            } else {
6252380566debfc57eb1cc07db1306ccee23b84ddd4Jean-Michel Trivi                return mFocusStack.peek().getGainRequest();
6262380566debfc57eb1cc07db1306ccee23b84ddd4Jean-Michel Trivi            }
6272380566debfc57eb1cc07db1306ccee23b84ddd4Jean-Michel Trivi        }
6282380566debfc57eb1cc07db1306ccee23b84ddd4Jean-Michel Trivi    }
629fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi
630fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    /** @see AudioManager#requestAudioFocus(AudioManager.OnAudioFocusChangeListener, int, int)  */
631fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    protected int requestAudioFocus(int mainStreamType, int focusChangeHint, IBinder cb,
632fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            IAudioFocusDispatcher fd, String clientId, String callingPackageName) {
633fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        Log.i(TAG, " AudioFocus  requestAudioFocus() from " + clientId);
634fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        // we need a valid binder callback for clients
635fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        if (!cb.pingBinder()) {
636fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            Log.e(TAG, " AudioFocus DOA client for requestAudioFocus(), aborting.");
637fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            return AudioManager.AUDIOFOCUS_REQUEST_FAILED;
638fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        }
639fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi
640fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        if (mAppOps.noteOp(AppOpsManager.OP_TAKE_AUDIO_FOCUS, Binder.getCallingUid(),
641fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                callingPackageName) != AppOpsManager.MODE_ALLOWED) {
642fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            return AudioManager.AUDIOFOCUS_REQUEST_FAILED;
643fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        }
644fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi
645fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        synchronized(mAudioFocusLock) {
646fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            if (!canReassignAudioFocus()) {
647fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                return AudioManager.AUDIOFOCUS_REQUEST_FAILED;
648fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            }
649fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi
650fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            // handle the potential premature death of the new holder of the focus
651fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            // (premature death == death before abandoning focus)
652fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            // Register for client death notification
653fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            AudioFocusDeathHandler afdh = new AudioFocusDeathHandler(cb);
654fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            try {
655fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                cb.linkToDeath(afdh, 0);
656fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            } catch (RemoteException e) {
657fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                // client has already died!
658fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                Log.w(TAG, "AudioFocus  requestAudioFocus() could not link to "+cb+" binder death");
659fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                return AudioManager.AUDIOFOCUS_REQUEST_FAILED;
660fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            }
661fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi
66283283f23eb1b7c1576e253c644b8aade6f657d0aJean-Michel Trivi            if (!mFocusStack.empty() && mFocusStack.peek().hasSameClient(clientId)) {
663fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                // if focus is already owned by this client and the reason for acquiring the focus
664fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                // hasn't changed, don't do anything
66583283f23eb1b7c1576e253c644b8aade6f657d0aJean-Michel Trivi                if (mFocusStack.peek().getGainRequest() == focusChangeHint) {
666fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                    // unlink death handler so it can be gc'ed.
667fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                    // linkToDeath() creates a JNI global reference preventing collection.
668fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                    cb.unlinkToDeath(afdh, 0);
669fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                    return AudioManager.AUDIOFOCUS_REQUEST_GRANTED;
670fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                }
671fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                // the reason for the audio focus request has changed: remove the current top of
672fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                // stack and respond as if we had a new focus owner
67383283f23eb1b7c1576e253c644b8aade6f657d0aJean-Michel Trivi                FocusRequester fr = mFocusStack.pop();
67483283f23eb1b7c1576e253c644b8aade6f657d0aJean-Michel Trivi                fr.release();
675fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            }
676fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi
677fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            // focus requester might already be somewhere below in the stack, remove it
678fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            removeFocusStackEntry(clientId, false /* signal */);
679fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi
680cbb212ff6f06b004ae19dfb6958ee3852716bbdcJean-Michel Trivi            // propagate the focus change through the stack
681cbb212ff6f06b004ae19dfb6958ee3852716bbdcJean-Michel Trivi            if (!mFocusStack.empty()) {
682cbb212ff6f06b004ae19dfb6958ee3852716bbdcJean-Michel Trivi                propagateFocusLossFromGain_syncAf(focusChangeHint);
683cbb212ff6f06b004ae19dfb6958ee3852716bbdcJean-Michel Trivi            }
684cbb212ff6f06b004ae19dfb6958ee3852716bbdcJean-Michel Trivi
685fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            // push focus requester at the top of the audio focus stack
68683283f23eb1b7c1576e253c644b8aade6f657d0aJean-Michel Trivi            mFocusStack.push(new FocusRequester(mainStreamType, focusChangeHint, fd, cb,
687fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                    clientId, afdh, callingPackageName, Binder.getCallingUid()));
688fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi
689fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            // there's a new top of the stack, let the remote control know
690fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            synchronized(mRCStack) {
691fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                checkUpdateRemoteControlDisplay_syncAfRcs(RC_INFO_ALL);
692fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            }
693fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        }//synchronized(mAudioFocusLock)
694fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi
695fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        return AudioManager.AUDIOFOCUS_REQUEST_GRANTED;
696fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    }
697fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi
698fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    /** @see AudioManager#abandonAudioFocus(AudioManager.OnAudioFocusChangeListener)  */
699fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    protected int abandonAudioFocus(IAudioFocusDispatcher fl, String clientId) {
700fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        Log.i(TAG, " AudioFocus  abandonAudioFocus() from " + clientId);
701fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        try {
702fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            // this will take care of notifying the new focus owner if needed
703fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            synchronized(mAudioFocusLock) {
70400bf4b18173b8921d7a5cecbd8b8d3745470b5d0Jean-Michel Trivi                removeFocusStackEntry(clientId, true /*signal*/);
705fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            }
706fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        } catch (java.util.ConcurrentModificationException cme) {
707fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            // Catching this exception here is temporary. It is here just to prevent
708fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            // a crash seen when the "Silent" notification is played. This is believed to be fixed
709fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            // but this try catch block is left just to be safe.
710fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            Log.e(TAG, "FATAL EXCEPTION AudioFocus  abandonAudioFocus() caused " + cme);
711fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            cme.printStackTrace();
712fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        }
713fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi
714fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        return AudioManager.AUDIOFOCUS_REQUEST_GRANTED;
715fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    }
716fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi
717fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi
718fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    protected void unregisterAudioFocusClient(String clientId) {
719fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        synchronized(mAudioFocusLock) {
720fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            removeFocusStackEntry(clientId, false);
721fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        }
722fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    }
723fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi
724fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi
725fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    //==========================================================================================
726fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    // RemoteControl
727fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    //==========================================================================================
728a83487e8c618f3c267c3fe3a72d4eb9f1388d07eJean-Michel Trivi    /**
729a83487e8c618f3c267c3fe3a72d4eb9f1388d07eJean-Michel Trivi     * No-op if the key code for keyEvent is not a valid media key
730a83487e8c618f3c267c3fe3a72d4eb9f1388d07eJean-Michel Trivi     * (see {@link #isValidMediaKeyEvent(KeyEvent)})
731a83487e8c618f3c267c3fe3a72d4eb9f1388d07eJean-Michel Trivi     * @param keyEvent the key event to send
732a83487e8c618f3c267c3fe3a72d4eb9f1388d07eJean-Michel Trivi     */
733fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    protected void dispatchMediaKeyEvent(KeyEvent keyEvent) {
734fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        filterMediaKeyEvent(keyEvent, false /*needWakeLock*/);
735fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    }
736fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi
737a83487e8c618f3c267c3fe3a72d4eb9f1388d07eJean-Michel Trivi    /**
738a83487e8c618f3c267c3fe3a72d4eb9f1388d07eJean-Michel Trivi     * No-op if the key code for keyEvent is not a valid media key
739a83487e8c618f3c267c3fe3a72d4eb9f1388d07eJean-Michel Trivi     * (see {@link #isValidMediaKeyEvent(KeyEvent)})
740a83487e8c618f3c267c3fe3a72d4eb9f1388d07eJean-Michel Trivi     * @param keyEvent the key event to send
741a83487e8c618f3c267c3fe3a72d4eb9f1388d07eJean-Michel Trivi     */
742fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    protected void dispatchMediaKeyEventUnderWakelock(KeyEvent keyEvent) {
743fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        filterMediaKeyEvent(keyEvent, true /*needWakeLock*/);
744fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    }
745fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi
746fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    private void filterMediaKeyEvent(KeyEvent keyEvent, boolean needWakeLock) {
747fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        // sanity check on the incoming key event
748fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        if (!isValidMediaKeyEvent(keyEvent)) {
749fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            Log.e(TAG, "not dispatching invalid media key event " + keyEvent);
750fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            return;
751fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        }
752fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        // event filtering for telephony
753fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        synchronized(mRingingLock) {
754fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            synchronized(mRCStack) {
755fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                if ((mMediaReceiverForCalls != null) &&
756fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                        (mIsRinging || (mAudioService.getMode() == AudioSystem.MODE_IN_CALL))) {
757fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                    dispatchMediaKeyEventForCalls(keyEvent, needWakeLock);
758fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                    return;
759fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                }
760fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            }
761fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        }
762fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        // event filtering based on voice-based interactions
763fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        if (isValidVoiceInputKeyCode(keyEvent.getKeyCode())) {
764fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            filterVoiceInputKeyEvent(keyEvent, needWakeLock);
765fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        } else {
766fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            dispatchMediaKeyEvent(keyEvent, needWakeLock);
767fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        }
768fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    }
769fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi
770fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    /**
771fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi     * Handles the dispatching of the media button events to the telephony package.
772fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi     * Precondition: mMediaReceiverForCalls != null
773fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi     * @param keyEvent a non-null KeyEvent whose key code is one of the supported media buttons
774fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi     * @param needWakeLock true if a PARTIAL_WAKE_LOCK needs to be held while this key event
775fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi     *     is dispatched.
776fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi     */
777fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    private void dispatchMediaKeyEventForCalls(KeyEvent keyEvent, boolean needWakeLock) {
778fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        Intent keyIntent = new Intent(Intent.ACTION_MEDIA_BUTTON, null);
779fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        keyIntent.putExtra(Intent.EXTRA_KEY_EVENT, keyEvent);
780fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        keyIntent.setPackage(mMediaReceiverForCalls.getPackageName());
781fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        if (needWakeLock) {
782fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            mMediaEventWakeLock.acquire();
783fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            keyIntent.putExtra(EXTRA_WAKELOCK_ACQUIRED, WAKELOCK_RELEASE_ON_FINISHED);
784fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        }
785fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        final long ident = Binder.clearCallingIdentity();
786fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        try {
787fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            mContext.sendOrderedBroadcastAsUser(keyIntent, UserHandle.ALL,
788fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                    null, mKeyEventDone, mEventHandler, Activity.RESULT_OK, null, null);
789fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        } finally {
790fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            Binder.restoreCallingIdentity(ident);
791fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        }
792fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    }
793fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi
794fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    /**
795fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi     * Handles the dispatching of the media button events to one of the registered listeners,
796fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi     * or if there was none, broadcast an ACTION_MEDIA_BUTTON intent to the rest of the system.
797fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi     * @param keyEvent a non-null KeyEvent whose key code is one of the supported media buttons
798fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi     * @param needWakeLock true if a PARTIAL_WAKE_LOCK needs to be held while this key event
799fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi     *     is dispatched.
800fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi     */
801fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    private void dispatchMediaKeyEvent(KeyEvent keyEvent, boolean needWakeLock) {
802fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        if (needWakeLock) {
803fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            mMediaEventWakeLock.acquire();
804fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        }
805fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        Intent keyIntent = new Intent(Intent.ACTION_MEDIA_BUTTON, null);
806fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        keyIntent.putExtra(Intent.EXTRA_KEY_EVENT, keyEvent);
807fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        synchronized(mRCStack) {
808fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            if (!mRCStack.empty()) {
809fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                // send the intent that was registered by the client
810fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                try {
811fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                    mRCStack.peek().mMediaIntent.send(mContext,
812fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                            needWakeLock ? WAKELOCK_RELEASE_ON_FINISHED : 0 /*code*/,
813fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                            keyIntent, this, mEventHandler);
814fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                } catch (CanceledException e) {
815fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                    Log.e(TAG, "Error sending pending intent " + mRCStack.peek());
816fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                    e.printStackTrace();
817fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                }
818fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            } else {
819fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                // legacy behavior when nobody registered their media button event receiver
820fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                //    through AudioManager
821fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                if (needWakeLock) {
822fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                    keyIntent.putExtra(EXTRA_WAKELOCK_ACQUIRED, WAKELOCK_RELEASE_ON_FINISHED);
823fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                }
824fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                final long ident = Binder.clearCallingIdentity();
825fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                try {
826fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                    mContext.sendOrderedBroadcastAsUser(keyIntent, UserHandle.ALL,
827fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                            null, mKeyEventDone,
828fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                            mEventHandler, Activity.RESULT_OK, null, null);
829fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                } finally {
830fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                    Binder.restoreCallingIdentity(ident);
831fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                }
832fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            }
833fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        }
834fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    }
835fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi
836fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    /**
837fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi     * The different actions performed in response to a voice button key event.
838fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi     */
839fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    private final static int VOICEBUTTON_ACTION_DISCARD_CURRENT_KEY_PRESS = 1;
840fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    private final static int VOICEBUTTON_ACTION_START_VOICE_INPUT = 2;
841fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    private final static int VOICEBUTTON_ACTION_SIMULATE_KEY_PRESS = 3;
842fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi
843fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    private final Object mVoiceEventLock = new Object();
844fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    private boolean mVoiceButtonDown;
845fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    private boolean mVoiceButtonHandled;
846fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi
847fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    /**
848fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi     * Filter key events that may be used for voice-based interactions
849fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi     * @param keyEvent a non-null KeyEvent whose key code is that of one of the supported
850fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi     *    media buttons that can be used to trigger voice-based interactions.
851fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi     * @param needWakeLock true if a PARTIAL_WAKE_LOCK needs to be held while this key event
852fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi     *     is dispatched.
853fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi     */
854fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    private void filterVoiceInputKeyEvent(KeyEvent keyEvent, boolean needWakeLock) {
855fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        if (DEBUG_RC) {
856fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            Log.v(TAG, "voice input key event: " + keyEvent + ", needWakeLock=" + needWakeLock);
857fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        }
858fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi
859fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        int voiceButtonAction = VOICEBUTTON_ACTION_DISCARD_CURRENT_KEY_PRESS;
860fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        int keyAction = keyEvent.getAction();
861fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        synchronized (mVoiceEventLock) {
862fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            if (keyAction == KeyEvent.ACTION_DOWN) {
863fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                if (keyEvent.getRepeatCount() == 0) {
864fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                    // initial down
865fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                    mVoiceButtonDown = true;
866fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                    mVoiceButtonHandled = false;
867fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                } else if (mVoiceButtonDown && !mVoiceButtonHandled
868fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                        && (keyEvent.getFlags() & KeyEvent.FLAG_LONG_PRESS) != 0) {
869fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                    // long-press, start voice-based interactions
870fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                    mVoiceButtonHandled = true;
871fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                    voiceButtonAction = VOICEBUTTON_ACTION_START_VOICE_INPUT;
872fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                }
873fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            } else if (keyAction == KeyEvent.ACTION_UP) {
874fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                if (mVoiceButtonDown) {
875fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                    // voice button up
876fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                    mVoiceButtonDown = false;
877fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                    if (!mVoiceButtonHandled && !keyEvent.isCanceled()) {
878fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                        voiceButtonAction = VOICEBUTTON_ACTION_SIMULATE_KEY_PRESS;
879fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                    }
880fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                }
881fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            }
882fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        }//synchronized (mVoiceEventLock)
883fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi
884fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        // take action after media button event filtering for voice-based interactions
885fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        switch (voiceButtonAction) {
886fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            case VOICEBUTTON_ACTION_DISCARD_CURRENT_KEY_PRESS:
887fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                if (DEBUG_RC) Log.v(TAG, "   ignore key event");
888fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                break;
889fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            case VOICEBUTTON_ACTION_START_VOICE_INPUT:
890fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                if (DEBUG_RC) Log.v(TAG, "   start voice-based interactions");
891fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                // then start the voice-based interactions
892fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                startVoiceBasedInteractions(needWakeLock);
893fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                break;
894fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            case VOICEBUTTON_ACTION_SIMULATE_KEY_PRESS:
895fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                if (DEBUG_RC) Log.v(TAG, "   send simulated key event, wakelock=" + needWakeLock);
896fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                sendSimulatedMediaButtonEvent(keyEvent, needWakeLock);
897fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                break;
898fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        }
899fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    }
900fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi
901fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    private void sendSimulatedMediaButtonEvent(KeyEvent originalKeyEvent, boolean needWakeLock) {
902fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        // send DOWN event
903fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        KeyEvent keyEvent = KeyEvent.changeAction(originalKeyEvent, KeyEvent.ACTION_DOWN);
904fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        dispatchMediaKeyEvent(keyEvent, needWakeLock);
905fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        // send UP event
906fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        keyEvent = KeyEvent.changeAction(originalKeyEvent, KeyEvent.ACTION_UP);
907fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        dispatchMediaKeyEvent(keyEvent, needWakeLock);
908fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi
909fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    }
910fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi
91173673ab7988adc80fc179e9910c7a19fcabef884Jean-Michel Trivi    private class PackageIntentsReceiver extends BroadcastReceiver {
91273673ab7988adc80fc179e9910c7a19fcabef884Jean-Michel Trivi        @Override
91373673ab7988adc80fc179e9910c7a19fcabef884Jean-Michel Trivi        public void onReceive(Context context, Intent intent) {
91473673ab7988adc80fc179e9910c7a19fcabef884Jean-Michel Trivi            String action = intent.getAction();
91573673ab7988adc80fc179e9910c7a19fcabef884Jean-Michel Trivi            if (action.equals(Intent.ACTION_PACKAGE_REMOVED)
91673673ab7988adc80fc179e9910c7a19fcabef884Jean-Michel Trivi                    || action.equals(Intent.ACTION_PACKAGE_DATA_CLEARED)) {
91773673ab7988adc80fc179e9910c7a19fcabef884Jean-Michel Trivi                if (!intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) {
91873673ab7988adc80fc179e9910c7a19fcabef884Jean-Michel Trivi                    // a package is being removed, not replaced
91973673ab7988adc80fc179e9910c7a19fcabef884Jean-Michel Trivi                    String packageName = intent.getData().getSchemeSpecificPart();
92073673ab7988adc80fc179e9910c7a19fcabef884Jean-Michel Trivi                    if (packageName != null) {
92173673ab7988adc80fc179e9910c7a19fcabef884Jean-Michel Trivi                        cleanupMediaButtonReceiverForPackage(packageName, true);
92273673ab7988adc80fc179e9910c7a19fcabef884Jean-Michel Trivi                    }
92373673ab7988adc80fc179e9910c7a19fcabef884Jean-Michel Trivi                }
92473673ab7988adc80fc179e9910c7a19fcabef884Jean-Michel Trivi            } else if (action.equals(Intent.ACTION_PACKAGE_ADDED)
92573673ab7988adc80fc179e9910c7a19fcabef884Jean-Michel Trivi                    || action.equals(Intent.ACTION_PACKAGE_CHANGED)) {
92673673ab7988adc80fc179e9910c7a19fcabef884Jean-Michel Trivi                String packageName = intent.getData().getSchemeSpecificPart();
92773673ab7988adc80fc179e9910c7a19fcabef884Jean-Michel Trivi                if (packageName != null) {
92873673ab7988adc80fc179e9910c7a19fcabef884Jean-Michel Trivi                    cleanupMediaButtonReceiverForPackage(packageName, false);
92973673ab7988adc80fc179e9910c7a19fcabef884Jean-Michel Trivi                }
93073673ab7988adc80fc179e9910c7a19fcabef884Jean-Michel Trivi            }
93173673ab7988adc80fc179e9910c7a19fcabef884Jean-Michel Trivi        }
93273673ab7988adc80fc179e9910c7a19fcabef884Jean-Michel Trivi    }
933fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi
9347ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi    protected static boolean isMediaKeyCode(int keyCode) {
935fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        switch (keyCode) {
936fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            case KeyEvent.KEYCODE_MUTE:
937fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            case KeyEvent.KEYCODE_HEADSETHOOK:
938fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            case KeyEvent.KEYCODE_MEDIA_PLAY:
939fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            case KeyEvent.KEYCODE_MEDIA_PAUSE:
940fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE:
941fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            case KeyEvent.KEYCODE_MEDIA_STOP:
942fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            case KeyEvent.KEYCODE_MEDIA_NEXT:
943fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            case KeyEvent.KEYCODE_MEDIA_PREVIOUS:
944fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            case KeyEvent.KEYCODE_MEDIA_REWIND:
945fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            case KeyEvent.KEYCODE_MEDIA_RECORD:
946fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            case KeyEvent.KEYCODE_MEDIA_FAST_FORWARD:
947fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            case KeyEvent.KEYCODE_MEDIA_CLOSE:
948fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            case KeyEvent.KEYCODE_MEDIA_EJECT:
949fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            case KeyEvent.KEYCODE_MEDIA_AUDIO_TRACK:
9507ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi                return true;
951fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            default:
952fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                return false;
953fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        }
9547ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi    }
9557ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi
9567ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi    private static boolean isValidMediaKeyEvent(KeyEvent keyEvent) {
9577ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi        if (keyEvent == null) {
9587ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi            return false;
9597ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi        }
9607ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi        return MediaFocusControl.isMediaKeyCode(keyEvent.getKeyCode());
961fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    }
962fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi
963fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    /**
964fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi     * Checks whether the given key code is one that can trigger the launch of voice-based
965fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi     *   interactions.
966fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi     * @param keyCode the key code associated with the key event
967fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi     * @return true if the key is one of the supported voice-based interaction triggers
968fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi     */
969fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    private static boolean isValidVoiceInputKeyCode(int keyCode) {
970fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        if (keyCode == KeyEvent.KEYCODE_HEADSETHOOK) {
971fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            return true;
972fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        } else {
973fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            return false;
974fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        }
975fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    }
976fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi
977fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    /**
978fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi     * Tell the system to start voice-based interactions / voice commands
979fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi     */
980fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    private void startVoiceBasedInteractions(boolean needWakeLock) {
981fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        Intent voiceIntent = null;
982fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        // select which type of search to launch:
983fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        // - screen on and device unlocked: action is ACTION_WEB_SEARCH
984fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        // - device locked or screen off: action is ACTION_VOICE_SEARCH_HANDS_FREE
985fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        //    with EXTRA_SECURE set to true if the device is securely locked
986fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        PowerManager pm = (PowerManager)mContext.getSystemService(Context.POWER_SERVICE);
987fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        boolean isLocked = mKeyguardManager != null && mKeyguardManager.isKeyguardLocked();
988fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        if (!isLocked && pm.isScreenOn()) {
989fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            voiceIntent = new Intent(android.speech.RecognizerIntent.ACTION_WEB_SEARCH);
990fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            Log.i(TAG, "voice-based interactions: about to use ACTION_WEB_SEARCH");
991fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        } else {
992fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            voiceIntent = new Intent(RecognizerIntent.ACTION_VOICE_SEARCH_HANDS_FREE);
993fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            voiceIntent.putExtra(RecognizerIntent.EXTRA_SECURE,
994fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                    isLocked && mKeyguardManager.isKeyguardSecure());
995fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            Log.i(TAG, "voice-based interactions: about to use ACTION_VOICE_SEARCH_HANDS_FREE");
996fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        }
997fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        // start the search activity
998fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        if (needWakeLock) {
999fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            mMediaEventWakeLock.acquire();
1000fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        }
1001dcd40c0e57649ffbdb41c774aa6493648e1ac2b5Jean-Michel Trivi        final long identity = Binder.clearCallingIdentity();
1002fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        try {
1003fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            if (voiceIntent != null) {
1004fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                voiceIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
1005fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                        | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
1006dcd40c0e57649ffbdb41c774aa6493648e1ac2b5Jean-Michel Trivi                mContext.startActivityAsUser(voiceIntent, UserHandle.CURRENT);
1007fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            }
1008fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        } catch (ActivityNotFoundException e) {
1009fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            Log.w(TAG, "No activity for search: " + e);
1010fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        } finally {
1011dcd40c0e57649ffbdb41c774aa6493648e1ac2b5Jean-Michel Trivi            Binder.restoreCallingIdentity(identity);
1012fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            if (needWakeLock) {
1013fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                mMediaEventWakeLock.release();
1014fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            }
1015fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        }
1016fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    }
1017fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi
1018fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    private static final int WAKELOCK_RELEASE_ON_FINISHED = 1980; //magic number
1019fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi
1020fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    // only set when wakelock was acquired, no need to check value when received
1021fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    private static final String EXTRA_WAKELOCK_ACQUIRED =
1022fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            "android.media.AudioService.WAKELOCK_ACQUIRED";
1023fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi
1024fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    public void onSendFinished(PendingIntent pendingIntent, Intent intent,
1025fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            int resultCode, String resultData, Bundle resultExtras) {
1026fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        if (resultCode == WAKELOCK_RELEASE_ON_FINISHED) {
1027fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            mMediaEventWakeLock.release();
1028fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        }
1029fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    }
1030fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi
1031fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    BroadcastReceiver mKeyEventDone = new BroadcastReceiver() {
1032fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        public void onReceive(Context context, Intent intent) {
1033fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            if (intent == null) {
1034fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                return;
1035fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            }
1036fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            Bundle extras = intent.getExtras();
1037fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            if (extras == null) {
1038fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                return;
1039fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            }
1040fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            if (extras.containsKey(EXTRA_WAKELOCK_ACQUIRED)) {
1041fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                mMediaEventWakeLock.release();
1042fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            }
1043fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        }
1044fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    };
1045fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi
1046fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    /**
1047fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi     * Synchronization on mCurrentRcLock always inside a block synchronized on mRCStack
1048fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi     */
1049fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    private final Object mCurrentRcLock = new Object();
1050fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    /**
1051fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi     * The one remote control client which will receive a request for display information.
1052fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi     * This object may be null.
1053fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi     * Access protected by mCurrentRcLock.
1054fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi     */
1055fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    private IRemoteControlClient mCurrentRcClient = null;
105686142da1ce8c1341404a9f9e21be8acbcba69ab3Jean-Michel Trivi    /**
105786142da1ce8c1341404a9f9e21be8acbcba69ab3Jean-Michel Trivi     * The PendingIntent associated with mCurrentRcClient. Its value is irrelevant
105886142da1ce8c1341404a9f9e21be8acbcba69ab3Jean-Michel Trivi     * if mCurrentRcClient is null
105986142da1ce8c1341404a9f9e21be8acbcba69ab3Jean-Michel Trivi     */
106086142da1ce8c1341404a9f9e21be8acbcba69ab3Jean-Michel Trivi    private PendingIntent mCurrentRcClientIntent = null;
1061fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi
1062fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    private final static int RC_INFO_NONE = 0;
1063fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    private final static int RC_INFO_ALL =
1064fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        RemoteControlClient.FLAG_INFORMATION_REQUEST_ALBUM_ART |
1065fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        RemoteControlClient.FLAG_INFORMATION_REQUEST_KEY_MEDIA |
1066fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        RemoteControlClient.FLAG_INFORMATION_REQUEST_METADATA |
1067fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        RemoteControlClient.FLAG_INFORMATION_REQUEST_PLAYSTATE;
1068fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi
1069fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    /**
1070fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi     * A monotonically increasing generation counter for mCurrentRcClient.
1071fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi     * Only accessed with a lock on mCurrentRcLock.
1072fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi     * No value wrap-around issues as we only act on equal values.
1073fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi     */
1074fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    private int mCurrentRcClientGen = 0;
1075fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi
1076fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    /**
1077fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi     * Inner class to monitor remote control client deaths, and remove the client for the
1078fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi     * remote control stack if necessary.
1079fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi     */
1080fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    private class RcClientDeathHandler implements IBinder.DeathRecipient {
1081fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        final private IBinder mCb; // To be notified of client's death
1082fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        final private PendingIntent mMediaIntent;
1083fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi
1084fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        RcClientDeathHandler(IBinder cb, PendingIntent pi) {
1085fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            mCb = cb;
1086fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            mMediaIntent = pi;
1087fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        }
1088fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi
1089fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        public void binderDied() {
1090fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            Log.w(TAG, "  RemoteControlClient died");
1091fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            // remote control client died, make sure the displays don't use it anymore
1092fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            //  by setting its remote control client to null
1093fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            registerRemoteControlClient(mMediaIntent, null/*rcClient*/, null/*ignored*/);
1094fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            // the dead client was maybe handling remote playback, reevaluate
1095fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            postReevaluateRemote();
1096fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        }
1097fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi
1098fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        public IBinder getBinder() {
1099fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            return mCb;
1100fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        }
1101fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    }
1102fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi
1103fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    /**
1104fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi     * A global counter for RemoteControlClient identifiers
1105fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi     */
1106fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    private static int sLastRccId = 0;
1107fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi
1108fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    private class RemotePlaybackState {
1109fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        int mRccId;
1110fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        int mVolume;
1111fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        int mVolumeMax;
1112fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        int mVolumeHandling;
1113fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi
1114fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        private RemotePlaybackState(int id, int vol, int volMax) {
1115fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            mRccId = id;
1116fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            mVolume = vol;
1117fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            mVolumeMax = volMax;
1118fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            mVolumeHandling = RemoteControlClient.DEFAULT_PLAYBACK_VOLUME_HANDLING;
1119fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        }
1120fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    }
1121fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi
1122fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    /**
1123fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi     * Internal cache for the playback information of the RemoteControlClient whose volume gets to
1124fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi     * be controlled by the volume keys ("main"), so we don't have to iterate over the RC stack
1125fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi     * every time we need this info.
1126fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi     */
1127fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    private RemotePlaybackState mMainRemote;
1128fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    /**
1129fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi     * Indicates whether the "main" RemoteControlClient is considered active.
1130fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi     * Use synchronized on mMainRemote.
1131fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi     */
1132fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    private boolean mMainRemoteIsActive;
1133fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    /**
1134fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi     * Indicates whether there is remote playback going on. True even if there is no "active"
1135fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi     * remote playback (mMainRemoteIsActive is false), but a RemoteControlClient has declared it
1136fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi     * handles remote playback.
1137fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi     * Use synchronized on mMainRemote.
1138fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi     */
1139fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    private boolean mHasRemotePlayback;
1140fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi
1141fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    private static class RccPlaybackState {
1142fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        public int mState;
1143fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        public long mPositionMs;
1144fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        public float mSpeed;
1145fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi
1146fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        public RccPlaybackState(int state, long positionMs, float speed) {
1147fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            mState = state;
1148fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            mPositionMs = positionMs;
1149fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            mSpeed = speed;
1150fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        }
1151fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi
1152fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        public void reset() {
1153fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            mState = RemoteControlClient.PLAYSTATE_STOPPED;
1154fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            mPositionMs = RemoteControlClient.PLAYBACK_POSITION_INVALID;
1155fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            mSpeed = RemoteControlClient.PLAYBACK_SPEED_1X;
1156fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        }
1157fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi
1158fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        @Override
1159fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        public String toString() {
1160f47634edfe08fcebbf564a5df12a0a96906032c3Jean-Michel Trivi            return stateToString() + ", " + posToString() + ", " + mSpeed + "X";
1161f47634edfe08fcebbf564a5df12a0a96906032c3Jean-Michel Trivi        }
1162f47634edfe08fcebbf564a5df12a0a96906032c3Jean-Michel Trivi
1163f47634edfe08fcebbf564a5df12a0a96906032c3Jean-Michel Trivi        private String posToString() {
1164f47634edfe08fcebbf564a5df12a0a96906032c3Jean-Michel Trivi            if (mPositionMs == RemoteControlClient.PLAYBACK_POSITION_INVALID) {
1165f47634edfe08fcebbf564a5df12a0a96906032c3Jean-Michel Trivi                return "PLAYBACK_POSITION_INVALID";
1166f47634edfe08fcebbf564a5df12a0a96906032c3Jean-Michel Trivi            } else if (mPositionMs == RemoteControlClient.PLAYBACK_POSITION_ALWAYS_UNKNOWN) {
1167f47634edfe08fcebbf564a5df12a0a96906032c3Jean-Michel Trivi                return "PLAYBACK_POSITION_ALWAYS_UNKNOWN";
1168f47634edfe08fcebbf564a5df12a0a96906032c3Jean-Michel Trivi            } else {
1169f47634edfe08fcebbf564a5df12a0a96906032c3Jean-Michel Trivi                return (String.valueOf(mPositionMs) + "ms");
1170f47634edfe08fcebbf564a5df12a0a96906032c3Jean-Michel Trivi            }
1171fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        }
1172fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi
1173fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        private String stateToString() {
1174fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            switch (mState) {
1175fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                case RemoteControlClient.PLAYSTATE_NONE:
1176fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                    return "PLAYSTATE_NONE";
1177fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                case RemoteControlClient.PLAYSTATE_STOPPED:
1178fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                    return "PLAYSTATE_STOPPED";
1179fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                case RemoteControlClient.PLAYSTATE_PAUSED:
1180fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                    return "PLAYSTATE_PAUSED";
1181fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                case RemoteControlClient.PLAYSTATE_PLAYING:
1182fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                    return "PLAYSTATE_PLAYING";
1183fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                case RemoteControlClient.PLAYSTATE_FAST_FORWARDING:
1184fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                    return "PLAYSTATE_FAST_FORWARDING";
1185fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                case RemoteControlClient.PLAYSTATE_REWINDING:
1186fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                    return "PLAYSTATE_REWINDING";
1187fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                case RemoteControlClient.PLAYSTATE_SKIPPING_FORWARDS:
1188fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                    return "PLAYSTATE_SKIPPING_FORWARDS";
1189fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                case RemoteControlClient.PLAYSTATE_SKIPPING_BACKWARDS:
1190fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                    return "PLAYSTATE_SKIPPING_BACKWARDS";
1191fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                case RemoteControlClient.PLAYSTATE_BUFFERING:
1192fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                    return "PLAYSTATE_BUFFERING";
1193fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                case RemoteControlClient.PLAYSTATE_ERROR:
1194fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                    return "PLAYSTATE_ERROR";
1195fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                default:
1196fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                    return "[invalid playstate]";
1197fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            }
1198fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        }
1199fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    }
1200fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi
1201fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    protected static class RemoteControlStackEntry implements DeathRecipient {
1202fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        public int mRccId = RemoteControlClient.RCSE_ID_UNREGISTERED;
1203fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        final public MediaFocusControl mController;
1204fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        /**
1205fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi         * The target for the ACTION_MEDIA_BUTTON events.
1206fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi         * Always non null.
1207fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi         */
1208fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        final public PendingIntent mMediaIntent;
1209fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        /**
1210fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi         * The registered media button event receiver.
1211fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi         * Always non null.
1212fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi         */
1213fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        final public ComponentName mReceiverComponent;
1214fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        public IBinder mToken;
1215fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        public String mCallingPackageName;
1216fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        public int mCallingUid;
1217fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        /**
1218fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi         * Provides access to the information to display on the remote control.
1219fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi         * May be null (when a media button event receiver is registered,
1220fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi         *     but no remote control client has been registered) */
1221fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        public IRemoteControlClient mRcClient;
1222fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        public RcClientDeathHandler mRcClientDeathHandler;
1223fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        /**
1224fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi         * Information only used for non-local playback
1225fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi         */
1226fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        public int mPlaybackType;
1227fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        public int mPlaybackVolume;
1228fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        public int mPlaybackVolumeMax;
1229fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        public int mPlaybackVolumeHandling;
1230fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        public int mPlaybackStream;
1231fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        public RccPlaybackState mPlaybackState;
1232fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        public IRemoteVolumeObserver mRemoteVolumeObs;
1233fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi
1234fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        public void resetPlaybackInfo() {
1235fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            mPlaybackType = RemoteControlClient.PLAYBACK_TYPE_LOCAL;
1236fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            mPlaybackVolume = RemoteControlClient.DEFAULT_PLAYBACK_VOLUME;
1237fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            mPlaybackVolumeMax = RemoteControlClient.DEFAULT_PLAYBACK_VOLUME;
1238fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            mPlaybackVolumeHandling = RemoteControlClient.DEFAULT_PLAYBACK_VOLUME_HANDLING;
1239fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            mPlaybackStream = AudioManager.STREAM_MUSIC;
1240fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            mPlaybackState.reset();
1241fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            mRemoteVolumeObs = null;
1242fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        }
1243fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi
1244fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        /** precondition: mediaIntent != null */
1245fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        public RemoteControlStackEntry(MediaFocusControl controller, PendingIntent mediaIntent,
1246fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                ComponentName eventReceiver, IBinder token) {
1247fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            mController = controller;
1248fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            mMediaIntent = mediaIntent;
1249fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            mReceiverComponent = eventReceiver;
1250fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            mToken = token;
1251fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            mCallingUid = -1;
1252fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            mRcClient = null;
1253fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            mRccId = ++sLastRccId;
1254fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            mPlaybackState = new RccPlaybackState(
1255fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                    RemoteControlClient.PLAYSTATE_STOPPED,
1256fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                    RemoteControlClient.PLAYBACK_POSITION_INVALID,
1257fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                    RemoteControlClient.PLAYBACK_SPEED_1X);
1258fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi
1259fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            resetPlaybackInfo();
1260fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            if (mToken != null) {
1261fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                try {
1262fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                    mToken.linkToDeath(this, 0);
1263fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                } catch (RemoteException e) {
1264fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                    mController.mEventHandler.post(new Runnable() {
1265fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                        @Override public void run() {
1266fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                            mController.unregisterMediaButtonIntent(mMediaIntent);
1267fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                        }
1268fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                    });
1269fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                }
1270fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            }
1271fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        }
1272fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi
1273fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        public void unlinkToRcClientDeath() {
1274fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            if ((mRcClientDeathHandler != null) && (mRcClientDeathHandler.mCb != null)) {
1275fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                try {
1276fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                    mRcClientDeathHandler.mCb.unlinkToDeath(mRcClientDeathHandler, 0);
1277fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                    mRcClientDeathHandler = null;
1278fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                } catch (java.util.NoSuchElementException e) {
1279fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                    // not much we can do here
1280fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                    Log.e(TAG, "Encountered " + e + " in unlinkToRcClientDeath()");
1281fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                    e.printStackTrace();
1282fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                }
1283fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            }
1284fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        }
1285fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi
1286fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        public void destroy() {
1287fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            unlinkToRcClientDeath();
1288fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            if (mToken != null) {
1289fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                mToken.unlinkToDeath(this, 0);
1290fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                mToken = null;
1291fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            }
1292fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        }
1293fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi
1294fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        @Override
1295fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        public void binderDied() {
1296fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            mController.unregisterMediaButtonIntent(mMediaIntent);
1297fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        }
1298fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi
1299fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        @Override
1300fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        protected void finalize() throws Throwable {
1301fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            destroy(); // unlink exception handled inside method
1302fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            super.finalize();
1303fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        }
1304fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    }
1305fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi
1306fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    /**
1307fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi     *  The stack of remote control event receivers.
1308fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi     *  Code sections and methods that modify the remote control event receiver stack are
1309fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi     *  synchronized on mRCStack, but also BEFORE on mFocusLock as any change in either
1310fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi     *  stack, audio focus or RC, can lead to a change in the remote control display
1311fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi     */
1312fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    private final Stack<RemoteControlStackEntry> mRCStack = new Stack<RemoteControlStackEntry>();
1313fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi
1314fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    /**
1315fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi     * The component the telephony package can register so telephony calls have priority to
1316fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi     * handle media button events
1317fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi     */
1318fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    private ComponentName mMediaReceiverForCalls = null;
1319fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi
1320fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    /**
1321fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi     * Helper function:
1322fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi     * Display in the log the current entries in the remote control focus stack
1323fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi     */
1324fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    private void dumpRCStack(PrintWriter pw) {
1325fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        pw.println("\nRemote Control stack entries (last is top of stack):");
1326fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        synchronized(mRCStack) {
1327fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator();
1328fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            while(stackIterator.hasNext()) {
1329fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                RemoteControlStackEntry rcse = stackIterator.next();
1330fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                pw.println("  pi: " + rcse.mMediaIntent +
1331fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                        " -- pack: " + rcse.mCallingPackageName +
1332fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                        "  -- ercvr: " + rcse.mReceiverComponent +
1333fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                        "  -- client: " + rcse.mRcClient +
1334fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                        "  -- uid: " + rcse.mCallingUid +
1335fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                        "  -- type: " + rcse.mPlaybackType +
1336fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                        "  state: " + rcse.mPlaybackState);
1337fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            }
1338fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        }
1339fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    }
1340fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi
1341fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    /**
1342fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi     * Helper function:
1343fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi     * Display in the log the current entries in the remote control stack, focusing
1344fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi     * on RemoteControlClient data
1345fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi     */
1346fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    private void dumpRCCStack(PrintWriter pw) {
1347fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        pw.println("\nRemote Control Client stack entries (last is top of stack):");
1348fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        synchronized(mRCStack) {
1349fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator();
1350fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            while(stackIterator.hasNext()) {
1351fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                RemoteControlStackEntry rcse = stackIterator.next();
1352fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                pw.println("  uid: " + rcse.mCallingUid +
1353fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                        "  -- id: " + rcse.mRccId +
1354fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                        "  -- type: " + rcse.mPlaybackType +
1355fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                        "  -- state: " + rcse.mPlaybackState +
1356fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                        "  -- vol handling: " + rcse.mPlaybackVolumeHandling +
1357fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                        "  -- vol: " + rcse.mPlaybackVolume +
1358fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                        "  -- volMax: " + rcse.mPlaybackVolumeMax +
1359fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                        "  -- volObs: " + rcse.mRemoteVolumeObs);
1360fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            }
1361fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            synchronized(mCurrentRcLock) {
1362fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                pw.println("\nCurrent remote control generation ID = " + mCurrentRcClientGen);
1363fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            }
1364fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        }
1365fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        synchronized (mMainRemote) {
1366fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            pw.println("\nRemote Volume State:");
1367fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            pw.println("  has remote: " + mHasRemotePlayback);
1368fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            pw.println("  is remote active: " + mMainRemoteIsActive);
1369fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            pw.println("  rccId: " + mMainRemote.mRccId);
1370fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            pw.println("  volume handling: "
1371fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                    + ((mMainRemote.mVolumeHandling == RemoteControlClient.PLAYBACK_VOLUME_FIXED) ?
1372fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                            "PLAYBACK_VOLUME_FIXED(0)" : "PLAYBACK_VOLUME_VARIABLE(1)"));
1373fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            pw.println("  volume: " + mMainRemote.mVolume);
1374fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            pw.println("  volume steps: " + mMainRemote.mVolumeMax);
1375fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        }
1376fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    }
1377fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi
1378fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    /**
1379fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi     * Helper function:
1380fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi     * Display in the log the current entries in the list of remote control displays
1381fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi     */
1382fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    private void dumpRCDList(PrintWriter pw) {
1383fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        pw.println("\nRemote Control Display list entries:");
1384fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        synchronized(mRCStack) {
1385fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            final Iterator<DisplayInfoForServer> displayIterator = mRcDisplays.iterator();
1386fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            while (displayIterator.hasNext()) {
1387fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                final DisplayInfoForServer di = (DisplayInfoForServer) displayIterator.next();
1388fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                pw.println("  IRCD: " + di.mRcDisplay +
1389fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                        "  -- w:" + di.mArtworkExpectedWidth +
1390f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi                        "  -- h:" + di.mArtworkExpectedHeight +
1391f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi                        "  -- wantsPosSync:" + di.mWantsPositionSync +
1392f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi                        "  -- " + (di.mEnabled ? "enabled" : "disabled"));
1393fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            }
1394fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        }
1395fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    }
1396fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi
1397fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    /**
1398fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi     * Helper function:
1399fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi     * Remove any entry in the remote control stack that has the same package name as packageName
1400fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi     * Pre-condition: packageName != null
1401fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi     */
1402fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    private void cleanupMediaButtonReceiverForPackage(String packageName, boolean removeAll) {
1403fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        synchronized(mRCStack) {
1404fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            if (mRCStack.empty()) {
1405fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                return;
1406fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            } else {
1407fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                final PackageManager pm = mContext.getPackageManager();
1408fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                RemoteControlStackEntry oldTop = mRCStack.peek();
1409fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator();
1410fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                // iterate over the stack entries
1411fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                // (using an iterator on the stack so we can safely remove an entry after having
1412fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                //  evaluated it, traversal order doesn't matter here)
1413fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                while(stackIterator.hasNext()) {
1414fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                    RemoteControlStackEntry rcse = (RemoteControlStackEntry)stackIterator.next();
1415fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                    if (removeAll && packageName.equals(rcse.mMediaIntent.getCreatorPackage())) {
1416fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                        // a stack entry is from the package being removed, remove it from the stack
1417fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                        stackIterator.remove();
1418fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                        rcse.destroy();
1419fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                    } else if (rcse.mReceiverComponent != null) {
1420fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                        try {
1421fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                            // Check to see if this receiver still exists.
1422fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                            pm.getReceiverInfo(rcse.mReceiverComponent, 0);
1423fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                        } catch (PackageManager.NameNotFoundException e) {
1424fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                            // Not found -- remove it!
1425fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                            stackIterator.remove();
1426fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                            rcse.destroy();
1427fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                        }
1428fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                    }
1429fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                }
1430fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                if (mRCStack.empty()) {
1431fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                    // no saved media button receiver
1432fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                    mEventHandler.sendMessage(
1433fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                            mEventHandler.obtainMessage(MSG_PERSIST_MEDIABUTTONRECEIVER, 0, 0,
1434fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                                    null));
1435fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                } else if (oldTop != mRCStack.peek()) {
1436fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                    // the top of the stack has changed, save it in the system settings
1437fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                    // by posting a message to persist it; only do this however if it has
1438fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                    // a concrete component name (is not a transient registration)
1439fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                    RemoteControlStackEntry rcse = mRCStack.peek();
1440fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                    if (rcse.mReceiverComponent != null) {
1441fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                        mEventHandler.sendMessage(
1442fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                                mEventHandler.obtainMessage(MSG_PERSIST_MEDIABUTTONRECEIVER, 0, 0,
1443fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                                        rcse.mReceiverComponent));
1444fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                    }
1445fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                }
1446fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            }
1447fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        }
1448fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    }
1449fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi
1450fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    /**
1451fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi     * Helper function:
1452fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi     * Restore remote control receiver from the system settings.
1453fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi     */
1454fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    protected void restoreMediaButtonReceiver() {
1455fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        String receiverName = Settings.System.getStringForUser(mContentResolver,
1456fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                Settings.System.MEDIA_BUTTON_RECEIVER, UserHandle.USER_CURRENT);
1457fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        if ((null != receiverName) && !receiverName.isEmpty()) {
1458fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            ComponentName eventReceiver = ComponentName.unflattenFromString(receiverName);
1459fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            if (eventReceiver == null) {
1460fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                // an invalid name was persisted
1461fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                return;
1462fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            }
1463fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            // construct a PendingIntent targeted to the restored component name
1464fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            // for the media button and register it
1465fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            Intent mediaButtonIntent = new Intent(Intent.ACTION_MEDIA_BUTTON);
1466fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            //     the associated intent will be handled by the component being registered
1467fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            mediaButtonIntent.setComponent(eventReceiver);
1468fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            PendingIntent pi = PendingIntent.getBroadcast(mContext,
1469fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                    0/*requestCode, ignored*/, mediaButtonIntent, 0/*flags*/);
1470fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            registerMediaButtonIntent(pi, eventReceiver, null);
1471fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        }
1472fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    }
1473fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi
1474fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    /**
1475fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi     * Helper function:
1476fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi     * Set the new remote control receiver at the top of the RC focus stack.
1477fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi     * Called synchronized on mAudioFocusLock, then mRCStack
1478fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi     * precondition: mediaIntent != null
14790b605349176e8667c52cf75ccdd33ed63398c224Jean-Michel Trivi     * @return true if mRCStack was changed, false otherwise
1480fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi     */
14810b605349176e8667c52cf75ccdd33ed63398c224Jean-Michel Trivi    private boolean pushMediaButtonReceiver_syncAfRcs(PendingIntent mediaIntent,
14820b605349176e8667c52cf75ccdd33ed63398c224Jean-Michel Trivi            ComponentName target, IBinder token) {
1483fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        // already at top of stack?
1484fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        if (!mRCStack.empty() && mRCStack.peek().mMediaIntent.equals(mediaIntent)) {
14850b605349176e8667c52cf75ccdd33ed63398c224Jean-Michel Trivi            return false;
1486fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        }
1487fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        if (mAppOps.noteOp(AppOpsManager.OP_TAKE_MEDIA_BUTTONS, Binder.getCallingUid(),
1488fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                mediaIntent.getCreatorPackage()) != AppOpsManager.MODE_ALLOWED) {
14890b605349176e8667c52cf75ccdd33ed63398c224Jean-Michel Trivi            return false;
1490fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        }
1491fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        RemoteControlStackEntry rcse = null;
1492fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        boolean wasInsideStack = false;
1493fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        try {
1494fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            for (int index = mRCStack.size()-1; index >= 0; index--) {
1495fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                rcse = mRCStack.elementAt(index);
1496fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                if(rcse.mMediaIntent.equals(mediaIntent)) {
1497fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                    // ok to remove element while traversing the stack since we're leaving the loop
1498fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                    mRCStack.removeElementAt(index);
1499fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                    wasInsideStack = true;
1500fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                    break;
1501fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                }
1502fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            }
1503fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        } catch (ArrayIndexOutOfBoundsException e) {
1504fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            // not expected to happen, indicates improper concurrent modification
1505fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            Log.e(TAG, "Wrong index accessing media button stack, lock error? ", e);
1506fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        }
1507fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        if (!wasInsideStack) {
1508fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            rcse = new RemoteControlStackEntry(this, mediaIntent, target, token);
1509fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        }
1510fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        mRCStack.push(rcse); // rcse is never null
1511fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi
1512fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        // post message to persist the default media button receiver
1513fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        if (target != null) {
1514fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            mEventHandler.sendMessage( mEventHandler.obtainMessage(
1515fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                    MSG_PERSIST_MEDIABUTTONRECEIVER, 0, 0, target/*obj*/) );
1516fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        }
15170b605349176e8667c52cf75ccdd33ed63398c224Jean-Michel Trivi
15180b605349176e8667c52cf75ccdd33ed63398c224Jean-Michel Trivi        // RC stack was modified
15190b605349176e8667c52cf75ccdd33ed63398c224Jean-Michel Trivi        return true;
1520fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    }
1521fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi
1522fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    /**
1523fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi     * Helper function:
1524fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi     * Remove the remote control receiver from the RC focus stack.
1525fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi     * Called synchronized on mAudioFocusLock, then mRCStack
1526fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi     * precondition: pi != null
1527fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi     */
1528fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    private void removeMediaButtonReceiver_syncAfRcs(PendingIntent pi) {
1529fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        try {
1530fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            for (int index = mRCStack.size()-1; index >= 0; index--) {
1531fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                final RemoteControlStackEntry rcse = mRCStack.elementAt(index);
1532fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                if (rcse.mMediaIntent.equals(pi)) {
1533fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                    rcse.destroy();
1534fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                    // ok to remove element while traversing the stack since we're leaving the loop
1535fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                    mRCStack.removeElementAt(index);
1536fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                    break;
1537fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                }
1538fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            }
1539fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        } catch (ArrayIndexOutOfBoundsException e) {
1540fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            // not expected to happen, indicates improper concurrent modification
1541fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            Log.e(TAG, "Wrong index accessing media button stack, lock error? ", e);
1542fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        }
1543fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    }
1544fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi
1545fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    /**
1546fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi     * Helper function:
1547fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi     * Called synchronized on mRCStack
1548fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi     */
1549fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    private boolean isCurrentRcController(PendingIntent pi) {
1550fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        if (!mRCStack.empty() && mRCStack.peek().mMediaIntent.equals(pi)) {
1551fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            return true;
1552fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        }
1553fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        return false;
1554fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    }
1555fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi
1556fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    private void onHandlePersistMediaButtonReceiver(ComponentName receiver) {
1557fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        Settings.System.putStringForUser(mContentResolver,
1558fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                                         Settings.System.MEDIA_BUTTON_RECEIVER,
1559fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                                         receiver == null ? "" : receiver.flattenToString(),
1560fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                                         UserHandle.USER_CURRENT);
1561fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    }
1562fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi
1563fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    //==========================================================================================
1564fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    // Remote control display / client
1565fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    //==========================================================================================
1566fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    /**
1567fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi     * Update the remote control displays with the new "focused" client generation
1568fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi     */
1569fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    private void setNewRcClientOnDisplays_syncRcsCurrc(int newClientGeneration,
1570fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            PendingIntent newMediaIntent, boolean clearing) {
1571fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        synchronized(mRCStack) {
1572fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            if (mRcDisplays.size() > 0) {
1573fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                final Iterator<DisplayInfoForServer> displayIterator = mRcDisplays.iterator();
1574fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                while (displayIterator.hasNext()) {
1575fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                    final DisplayInfoForServer di = displayIterator.next();
1576fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                    try {
1577fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                        di.mRcDisplay.setCurrentClientId(
1578fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                                newClientGeneration, newMediaIntent, clearing);
1579fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                    } catch (RemoteException e) {
1580fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                        Log.e(TAG, "Dead display in setNewRcClientOnDisplays_syncRcsCurrc()",e);
1581fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                        di.release();
1582fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                        displayIterator.remove();
1583fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                    }
1584fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                }
1585fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            }
1586fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        }
1587fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    }
1588fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi
1589fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    /**
1590fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi     * Update the remote control clients with the new "focused" client generation
1591fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi     */
1592fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    private void setNewRcClientGenerationOnClients_syncRcsCurrc(int newClientGeneration) {
1593fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        // (using an iterator on the stack so we can safely remove an entry if needed,
1594fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        //  traversal order doesn't matter here as we update all entries)
1595fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator();
1596fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        while(stackIterator.hasNext()) {
1597fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            RemoteControlStackEntry se = stackIterator.next();
1598fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            if ((se != null) && (se.mRcClient != null)) {
1599fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                try {
1600fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                    se.mRcClient.setCurrentClientGenerationId(newClientGeneration);
1601fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                } catch (RemoteException e) {
1602fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                    Log.w(TAG, "Dead client in setNewRcClientGenerationOnClients_syncRcsCurrc()",e);
1603fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                    stackIterator.remove();
1604fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                    se.unlinkToRcClientDeath();
1605fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                }
1606fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            }
1607fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        }
1608fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    }
1609fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi
1610fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    /**
1611fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi     * Update the displays and clients with the new "focused" client generation and name
1612fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi     * @param newClientGeneration the new generation value matching a client update
1613fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi     * @param newMediaIntent the media button event receiver associated with the client.
1614fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi     *    May be null, which implies there is no registered media button event receiver.
1615fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi     * @param clearing true if the new client generation value maps to a remote control update
1616fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi     *    where the display should be cleared.
1617fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi     */
1618fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    private void setNewRcClient_syncRcsCurrc(int newClientGeneration,
1619fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            PendingIntent newMediaIntent, boolean clearing) {
1620fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        // send the new valid client generation ID to all displays
1621fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        setNewRcClientOnDisplays_syncRcsCurrc(newClientGeneration, newMediaIntent, clearing);
1622fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        // send the new valid client generation ID to all clients
1623fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        setNewRcClientGenerationOnClients_syncRcsCurrc(newClientGeneration);
1624fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    }
1625fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi
1626fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    /**
1627fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi     * Called when processing MSG_RCDISPLAY_CLEAR event
1628fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi     */
1629fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    private void onRcDisplayClear() {
1630fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        if (DEBUG_RC) Log.i(TAG, "Clear remote control display");
1631fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi
1632fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        synchronized(mRCStack) {
1633fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            synchronized(mCurrentRcLock) {
1634fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                mCurrentRcClientGen++;
1635fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                // synchronously update the displays and clients with the new client generation
1636fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                setNewRcClient_syncRcsCurrc(mCurrentRcClientGen,
1637fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                        null /*newMediaIntent*/, true /*clearing*/);
1638fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            }
1639fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        }
1640fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    }
1641fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi
1642fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    /**
1643fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi     * Called when processing MSG_RCDISPLAY_UPDATE event
1644fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi     */
1645fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    private void onRcDisplayUpdate(RemoteControlStackEntry rcse, int flags /* USED ?*/) {
1646fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        synchronized(mRCStack) {
1647fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            synchronized(mCurrentRcLock) {
1648fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                if ((mCurrentRcClient != null) && (mCurrentRcClient.equals(rcse.mRcClient))) {
1649fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                    if (DEBUG_RC) Log.i(TAG, "Display/update remote control ");
1650fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi
1651fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                    mCurrentRcClientGen++;
1652fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                    // synchronously update the displays and clients with
1653fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                    //      the new client generation
1654fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                    setNewRcClient_syncRcsCurrc(mCurrentRcClientGen,
1655fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                            rcse.mMediaIntent /*newMediaIntent*/,
1656fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                            false /*clearing*/);
1657fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi
1658fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                    // tell the current client that it needs to send info
1659fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                    try {
166086142da1ce8c1341404a9f9e21be8acbcba69ab3Jean-Michel Trivi                        //TODO change name to informationRequestForAllDisplays()
1661fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                        mCurrentRcClient.onInformationRequested(mCurrentRcClientGen, flags);
1662fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                    } catch (RemoteException e) {
1663fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                        Log.e(TAG, "Current valid remote client is dead: "+e);
1664fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                        mCurrentRcClient = null;
1665fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                    }
1666fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                } else {
1667fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                    // the remote control display owner has changed between the
1668fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                    // the message to update the display was sent, and the time it
1669fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                    // gets to be processed (now)
1670fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                }
1671fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            }
1672fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        }
1673fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    }
1674fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi
167586142da1ce8c1341404a9f9e21be8acbcba69ab3Jean-Michel Trivi    /**
167686142da1ce8c1341404a9f9e21be8acbcba69ab3Jean-Michel Trivi     * Called when processing MSG_RCDISPLAY_INIT_INFO event
167786142da1ce8c1341404a9f9e21be8acbcba69ab3Jean-Michel Trivi     * Causes the current RemoteControlClient to send its info (metadata, playstate...) to
167886142da1ce8c1341404a9f9e21be8acbcba69ab3Jean-Michel Trivi     *   a single RemoteControlDisplay, NOT all of them, as with MSG_RCDISPLAY_UPDATE.
167986142da1ce8c1341404a9f9e21be8acbcba69ab3Jean-Michel Trivi     */
168086142da1ce8c1341404a9f9e21be8acbcba69ab3Jean-Michel Trivi    private void onRcDisplayInitInfo(IRemoteControlDisplay newRcd, int w, int h) {
168186142da1ce8c1341404a9f9e21be8acbcba69ab3Jean-Michel Trivi        synchronized(mRCStack) {
168286142da1ce8c1341404a9f9e21be8acbcba69ab3Jean-Michel Trivi            synchronized(mCurrentRcLock) {
168386142da1ce8c1341404a9f9e21be8acbcba69ab3Jean-Michel Trivi                if (mCurrentRcClient != null) {
168486142da1ce8c1341404a9f9e21be8acbcba69ab3Jean-Michel Trivi                    if (DEBUG_RC) { Log.i(TAG, "Init RCD with current info"); }
168586142da1ce8c1341404a9f9e21be8acbcba69ab3Jean-Michel Trivi                    try {
168686142da1ce8c1341404a9f9e21be8acbcba69ab3Jean-Michel Trivi                        // synchronously update the new RCD with the current client generation
168786142da1ce8c1341404a9f9e21be8acbcba69ab3Jean-Michel Trivi                        // and matching PendingIntent
168886142da1ce8c1341404a9f9e21be8acbcba69ab3Jean-Michel Trivi                        newRcd.setCurrentClientId(mCurrentRcClientGen, mCurrentRcClientIntent,
168986142da1ce8c1341404a9f9e21be8acbcba69ab3Jean-Michel Trivi                                false);
169086142da1ce8c1341404a9f9e21be8acbcba69ab3Jean-Michel Trivi
169186142da1ce8c1341404a9f9e21be8acbcba69ab3Jean-Michel Trivi                        // tell the current RCC that it needs to send info, but only to the new RCD
169286142da1ce8c1341404a9f9e21be8acbcba69ab3Jean-Michel Trivi                        try {
169386142da1ce8c1341404a9f9e21be8acbcba69ab3Jean-Michel Trivi                            mCurrentRcClient.informationRequestForDisplay(newRcd, w, h);
169486142da1ce8c1341404a9f9e21be8acbcba69ab3Jean-Michel Trivi                        } catch (RemoteException e) {
169586142da1ce8c1341404a9f9e21be8acbcba69ab3Jean-Michel Trivi                            Log.e(TAG, "Current valid remote client is dead: ", e);
169686142da1ce8c1341404a9f9e21be8acbcba69ab3Jean-Michel Trivi                            mCurrentRcClient = null;
169786142da1ce8c1341404a9f9e21be8acbcba69ab3Jean-Michel Trivi                        }
169886142da1ce8c1341404a9f9e21be8acbcba69ab3Jean-Michel Trivi                    } catch (RemoteException e) {
169986142da1ce8c1341404a9f9e21be8acbcba69ab3Jean-Michel Trivi                        Log.e(TAG, "Dead display in onRcDisplayInitInfo()", e);
170086142da1ce8c1341404a9f9e21be8acbcba69ab3Jean-Michel Trivi                    }
170186142da1ce8c1341404a9f9e21be8acbcba69ab3Jean-Michel Trivi                }
170286142da1ce8c1341404a9f9e21be8acbcba69ab3Jean-Michel Trivi            }
170386142da1ce8c1341404a9f9e21be8acbcba69ab3Jean-Michel Trivi        }
170486142da1ce8c1341404a9f9e21be8acbcba69ab3Jean-Michel Trivi    }
1705fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi
1706fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    /**
1707fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi     * Helper function:
1708fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi     * Called synchronized on mRCStack
1709fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi     */
1710fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    private void clearRemoteControlDisplay_syncAfRcs() {
1711fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        synchronized(mCurrentRcLock) {
1712fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            mCurrentRcClient = null;
1713fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        }
1714fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        // will cause onRcDisplayClear() to be called in AudioService's handler thread
1715fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        mEventHandler.sendMessage( mEventHandler.obtainMessage(MSG_RCDISPLAY_CLEAR) );
1716fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    }
1717fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi
1718fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    /**
1719fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi     * Helper function for code readability: only to be called from
1720fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi     *    checkUpdateRemoteControlDisplay_syncAfRcs() which checks the preconditions for
1721fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi     *    this method.
1722fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi     * Preconditions:
1723fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi     *    - called synchronized mAudioFocusLock then on mRCStack
1724fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi     *    - mRCStack.isEmpty() is false
1725fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi     */
1726fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    private void updateRemoteControlDisplay_syncAfRcs(int infoChangedFlags) {
1727fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        RemoteControlStackEntry rcse = mRCStack.peek();
1728fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        int infoFlagsAboutToBeUsed = infoChangedFlags;
1729fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        // this is where we enforce opt-in for information display on the remote controls
1730fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        //   with the new AudioManager.registerRemoteControlClient() API
1731fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        if (rcse.mRcClient == null) {
1732fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            //Log.w(TAG, "Can't update remote control display with null remote control client");
1733fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            clearRemoteControlDisplay_syncAfRcs();
1734fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            return;
1735fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        }
1736fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        synchronized(mCurrentRcLock) {
1737fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            if (!rcse.mRcClient.equals(mCurrentRcClient)) {
1738fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                // new RC client, assume every type of information shall be queried
1739fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                infoFlagsAboutToBeUsed = RC_INFO_ALL;
1740fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            }
1741fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            mCurrentRcClient = rcse.mRcClient;
174286142da1ce8c1341404a9f9e21be8acbcba69ab3Jean-Michel Trivi            mCurrentRcClientIntent = rcse.mMediaIntent;
1743fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        }
1744fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        // will cause onRcDisplayUpdate() to be called in AudioService's handler thread
1745fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        mEventHandler.sendMessage( mEventHandler.obtainMessage(MSG_RCDISPLAY_UPDATE,
1746fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                infoFlagsAboutToBeUsed /* arg1 */, 0, rcse /* obj, != null */) );
1747fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    }
1748fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi
1749fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    /**
1750fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi     * Helper function:
1751fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi     * Called synchronized on mAudioFocusLock, then mRCStack
1752fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi     * Check whether the remote control display should be updated, triggers the update if required
1753fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi     * @param infoChangedFlags the flags corresponding to the remote control client information
1754fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi     *     that has changed, if applicable (checking for the update conditions might trigger a
1755fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi     *     clear, rather than an update event).
1756fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi     */
1757fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    private void checkUpdateRemoteControlDisplay_syncAfRcs(int infoChangedFlags) {
1758fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        // determine whether the remote control display should be refreshed
1759fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        // if either stack is empty, there is a mismatch, so clear the RC display
1760fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        if (mRCStack.isEmpty() || mFocusStack.isEmpty()) {
1761fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            clearRemoteControlDisplay_syncAfRcs();
1762fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            return;
1763fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        }
1764fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi
1765fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        // determine which entry in the AudioFocus stack to consider, and compare against the
1766fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        // top of the stack for the media button event receivers : simply using the top of the
1767fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        // stack would make the entry disappear from the RemoteControlDisplay in conditions such as
1768fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        // notifications playing during music playback.
1769fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        // Crawl the AudioFocus stack from the top until an entry is found with the following
1770fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        // characteristics:
1771fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        // - focus gain on STREAM_MUSIC stream
1772fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        // - non-transient focus gain on a stream other than music
177383283f23eb1b7c1576e253c644b8aade6f657d0aJean-Michel Trivi        FocusRequester af = null;
1774fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        try {
1775fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            for (int index = mFocusStack.size()-1; index >= 0; index--) {
177683283f23eb1b7c1576e253c644b8aade6f657d0aJean-Michel Trivi                FocusRequester fr = mFocusStack.elementAt(index);
177783283f23eb1b7c1576e253c644b8aade6f657d0aJean-Michel Trivi                if ((fr.getStreamType() == AudioManager.STREAM_MUSIC)
177883283f23eb1b7c1576e253c644b8aade6f657d0aJean-Michel Trivi                        || (fr.getGainRequest() == AudioManager.AUDIOFOCUS_GAIN)) {
177983283f23eb1b7c1576e253c644b8aade6f657d0aJean-Michel Trivi                    af = fr;
1780fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                    break;
1781fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                }
1782fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            }
1783fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        } catch (ArrayIndexOutOfBoundsException e) {
1784fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            Log.e(TAG, "Wrong index accessing audio focus stack when updating RCD: " + e);
1785fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            af = null;
1786fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        }
1787fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        if (af == null) {
1788fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            clearRemoteControlDisplay_syncAfRcs();
1789fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            return;
1790fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        }
1791fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi
1792fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        // if the audio focus and RC owners belong to different packages, there is a mismatch, clear
179383283f23eb1b7c1576e253c644b8aade6f657d0aJean-Michel Trivi        if (!af.hasSamePackage(mRCStack.peek().mCallingPackageName)) {
1794fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            clearRemoteControlDisplay_syncAfRcs();
1795fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            return;
1796fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        }
1797fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        // if the audio focus didn't originate from the same Uid as the one in which the remote
1798fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        //   control information will be retrieved, clear
179983283f23eb1b7c1576e253c644b8aade6f657d0aJean-Michel Trivi        if (!af.hasSameUid(mRCStack.peek().mCallingUid)) {
1800fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            clearRemoteControlDisplay_syncAfRcs();
1801fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            return;
1802fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        }
1803fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi
1804fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        // refresh conditions were verified: update the remote controls
1805fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        // ok to call: synchronized mAudioFocusLock then on mRCStack, mRCStack is not empty
1806fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        updateRemoteControlDisplay_syncAfRcs(infoChangedFlags);
1807fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    }
1808fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi
1809fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    /**
1810fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi     * Helper function:
1811fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi     * Post a message to asynchronously move the media button event receiver associated with the
1812fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi     * given remote control client ID to the top of the remote control stack
1813fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi     * @param rccId
1814fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi     */
1815fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    private void postPromoteRcc(int rccId) {
1816fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        sendMsg(mEventHandler, MSG_PROMOTE_RCC, SENDMSG_REPLACE,
1817fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                rccId /*arg1*/, 0, null, 0/*delay*/);
1818fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    }
1819fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi
1820fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    private void onPromoteRcc(int rccId) {
1821fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        if (DEBUG_RC) { Log.d(TAG, "Promoting RCC " + rccId); }
1822fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        synchronized(mAudioFocusLock) {
1823fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            synchronized(mRCStack) {
1824fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                // ignore if given RCC ID is already at top of remote control stack
1825fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                if (!mRCStack.isEmpty() && (mRCStack.peek().mRccId == rccId)) {
1826fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                    return;
1827fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                }
1828fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                int indexToPromote = -1;
1829fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                try {
1830fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                    for (int index = mRCStack.size()-1; index >= 0; index--) {
1831fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                        final RemoteControlStackEntry rcse = mRCStack.elementAt(index);
1832fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                        if (rcse.mRccId == rccId) {
1833fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                            indexToPromote = index;
1834fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                            break;
1835fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                        }
1836fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                    }
1837fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                    if (indexToPromote >= 0) {
1838fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                        if (DEBUG_RC) { Log.d(TAG, "  moving RCC from index " + indexToPromote
1839fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                                + " to " + (mRCStack.size()-1)); }
1840fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                        final RemoteControlStackEntry rcse = mRCStack.remove(indexToPromote);
1841fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                        mRCStack.push(rcse);
1842fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                        // the RC stack changed, reevaluate the display
1843fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                        checkUpdateRemoteControlDisplay_syncAfRcs(RC_INFO_ALL);
1844fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                    }
1845fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                } catch (ArrayIndexOutOfBoundsException e) {
1846fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                    // not expected to happen, indicates improper concurrent modification
1847fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                    Log.e(TAG, "Wrong index accessing RC stack, lock error? ", e);
1848fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                }
1849fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            }//synchronized(mRCStack)
1850fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        }//synchronized(mAudioFocusLock)
1851fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    }
1852fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi
1853fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    /**
1854fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi     * see AudioManager.registerMediaButtonIntent(PendingIntent pi, ComponentName c)
1855fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi     * precondition: mediaIntent != null
1856fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi     */
1857fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    protected void registerMediaButtonIntent(PendingIntent mediaIntent, ComponentName eventReceiver,
1858fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            IBinder token) {
1859fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        Log.i(TAG, "  Remote Control   registerMediaButtonIntent() for " + mediaIntent);
1860fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi
1861fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        synchronized(mAudioFocusLock) {
1862fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            synchronized(mRCStack) {
18630b605349176e8667c52cf75ccdd33ed63398c224Jean-Michel Trivi                if (pushMediaButtonReceiver_syncAfRcs(mediaIntent, eventReceiver, token)) {
18640b605349176e8667c52cf75ccdd33ed63398c224Jean-Michel Trivi                    // new RC client, assume every type of information shall be queried
18650b605349176e8667c52cf75ccdd33ed63398c224Jean-Michel Trivi                    checkUpdateRemoteControlDisplay_syncAfRcs(RC_INFO_ALL);
18660b605349176e8667c52cf75ccdd33ed63398c224Jean-Michel Trivi                }
1867fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            }
1868fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        }
1869fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    }
1870fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi
1871fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    /**
1872fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi     * see AudioManager.unregisterMediaButtonIntent(PendingIntent mediaIntent)
1873fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi     * precondition: mediaIntent != null, eventReceiver != null
1874fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi     */
1875fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    protected void unregisterMediaButtonIntent(PendingIntent mediaIntent)
1876fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    {
1877fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        Log.i(TAG, "  Remote Control   unregisterMediaButtonIntent() for " + mediaIntent);
1878fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi
1879fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        synchronized(mAudioFocusLock) {
1880fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            synchronized(mRCStack) {
1881fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                boolean topOfStackWillChange = isCurrentRcController(mediaIntent);
1882fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                removeMediaButtonReceiver_syncAfRcs(mediaIntent);
1883fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                if (topOfStackWillChange) {
1884fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                    // current RC client will change, assume every type of info needs to be queried
1885fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                    checkUpdateRemoteControlDisplay_syncAfRcs(RC_INFO_ALL);
1886fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                }
1887fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            }
1888fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        }
1889fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    }
1890fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi
1891fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    /**
1892fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi     * see AudioManager.registerMediaButtonEventReceiverForCalls(ComponentName c)
1893fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi     * precondition: c != null
1894fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi     */
1895fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    protected void registerMediaButtonEventReceiverForCalls(ComponentName c) {
1896fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        if (mContext.checkCallingPermission("android.permission.MODIFY_PHONE_STATE")
1897fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                != PackageManager.PERMISSION_GRANTED) {
1898fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            Log.e(TAG, "Invalid permissions to register media button receiver for calls");
1899fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            return;
1900fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        }
1901fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        synchronized(mRCStack) {
1902fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            mMediaReceiverForCalls = c;
1903fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        }
1904fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    }
1905fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi
1906fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    /**
1907fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi     * see AudioManager.unregisterMediaButtonEventReceiverForCalls()
1908fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi     */
1909fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    protected void unregisterMediaButtonEventReceiverForCalls() {
1910fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        if (mContext.checkCallingPermission("android.permission.MODIFY_PHONE_STATE")
1911fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                != PackageManager.PERMISSION_GRANTED) {
1912fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            Log.e(TAG, "Invalid permissions to unregister media button receiver for calls");
1913fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            return;
1914fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        }
1915fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        synchronized(mRCStack) {
1916fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            mMediaReceiverForCalls = null;
1917fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        }
1918fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    }
1919fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi
1920fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    /**
1921fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi     * see AudioManager.registerRemoteControlClient(ComponentName eventReceiver, ...)
1922fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi     * @return the unique ID of the RemoteControlStackEntry associated with the RemoteControlClient
1923fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi     * Note: using this method with rcClient == null is a way to "disable" the IRemoteControlClient
1924fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi     *     without modifying the RC stack, but while still causing the display to refresh (will
1925fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi     *     become blank as a result of this)
1926fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi     */
1927fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    protected int registerRemoteControlClient(PendingIntent mediaIntent,
1928fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            IRemoteControlClient rcClient, String callingPackageName) {
1929fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        if (DEBUG_RC) Log.i(TAG, "Register remote control client rcClient="+rcClient);
1930fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        int rccId = RemoteControlClient.RCSE_ID_UNREGISTERED;
1931fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        synchronized(mAudioFocusLock) {
1932fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            synchronized(mRCStack) {
1933fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                // store the new display information
1934fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                try {
1935fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                    for (int index = mRCStack.size()-1; index >= 0; index--) {
1936fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                        final RemoteControlStackEntry rcse = mRCStack.elementAt(index);
1937fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                        if(rcse.mMediaIntent.equals(mediaIntent)) {
1938fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                            // already had a remote control client?
1939fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                            if (rcse.mRcClientDeathHandler != null) {
1940fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                                // stop monitoring the old client's death
1941fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                                rcse.unlinkToRcClientDeath();
1942fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                            }
1943fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                            // save the new remote control client
1944fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                            rcse.mRcClient = rcClient;
1945fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                            rcse.mCallingPackageName = callingPackageName;
1946fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                            rcse.mCallingUid = Binder.getCallingUid();
1947fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                            if (rcClient == null) {
1948fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                                // here rcse.mRcClientDeathHandler is null;
1949fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                                rcse.resetPlaybackInfo();
1950fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                                break;
1951fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                            }
1952fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                            rccId = rcse.mRccId;
1953fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi
1954fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                            // there is a new (non-null) client:
1955fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                            // 1/ give the new client the displays (if any)
1956fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                            if (mRcDisplays.size() > 0) {
1957fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                                plugRemoteControlDisplaysIntoClient_syncRcStack(rcse.mRcClient);
1958fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                            }
1959fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                            // 2/ monitor the new client's death
1960fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                            IBinder b = rcse.mRcClient.asBinder();
1961fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                            RcClientDeathHandler rcdh =
1962fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                                    new RcClientDeathHandler(b, rcse.mMediaIntent);
1963fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                            try {
1964fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                                b.linkToDeath(rcdh, 0);
1965fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                            } catch (RemoteException e) {
1966fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                                // remote control client is DOA, disqualify it
1967fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                                Log.w(TAG, "registerRemoteControlClient() has a dead client " + b);
1968fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                                rcse.mRcClient = null;
1969fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                            }
1970fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                            rcse.mRcClientDeathHandler = rcdh;
1971fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                            break;
1972fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                        }
1973fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                    }//for
1974fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                } catch (ArrayIndexOutOfBoundsException e) {
1975fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                    // not expected to happen, indicates improper concurrent modification
1976fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                    Log.e(TAG, "Wrong index accessing RC stack, lock error? ", e);
1977fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                }
1978fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi
1979320ad9fa1d45322e878496cc1c03137cabf20942Jean-Michel Trivi                // if the eventReceiver is at the top of the stack
1980fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                // then check for potential refresh of the remote controls
1981320ad9fa1d45322e878496cc1c03137cabf20942Jean-Michel Trivi                if (isCurrentRcController(mediaIntent)) {
1982fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                    checkUpdateRemoteControlDisplay_syncAfRcs(RC_INFO_ALL);
1983fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                }
1984fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            }//synchronized(mRCStack)
1985fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        }//synchronized(mAudioFocusLock)
1986fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        return rccId;
1987fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    }
1988fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi
1989fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    /**
1990fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi     * see AudioManager.unregisterRemoteControlClient(PendingIntent pi, ...)
1991fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi     * rcClient is guaranteed non-null
1992fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi     */
1993fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    protected void unregisterRemoteControlClient(PendingIntent mediaIntent,
1994fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            IRemoteControlClient rcClient) {
1995fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        if (DEBUG_RC) Log.i(TAG, "Unregister remote control client rcClient="+rcClient);
1996fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        synchronized(mAudioFocusLock) {
1997fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            synchronized(mRCStack) {
1998fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                boolean topRccChange = false;
1999fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                try {
2000fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                    for (int index = mRCStack.size()-1; index >= 0; index--) {
2001fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                        final RemoteControlStackEntry rcse = mRCStack.elementAt(index);
2002fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                        if ((rcse.mMediaIntent.equals(mediaIntent))
2003fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                                && rcClient.equals(rcse.mRcClient)) {
2004fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                            // we found the IRemoteControlClient to unregister
2005fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                            // stop monitoring its death
2006fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                            rcse.unlinkToRcClientDeath();
2007fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                            // reset the client-related fields
2008fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                            rcse.mRcClient = null;
2009fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                            rcse.mCallingPackageName = null;
2010fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                            topRccChange = (index == mRCStack.size()-1);
2011fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                            // there can only be one matching RCC in the RC stack, we're done
2012fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                            break;
2013fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                        }
2014fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                    }
2015fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                } catch (ArrayIndexOutOfBoundsException e) {
2016fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                    // not expected to happen, indicates improper concurrent modification
2017fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                    Log.e(TAG, "Wrong index accessing RC stack, lock error? ", e);
2018fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                }
2019fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                if (topRccChange) {
2020fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                    // no more RCC for the RCD, check for potential refresh of the remote controls
2021fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                    checkUpdateRemoteControlDisplay_syncAfRcs(RC_INFO_ALL);
2022fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                }
2023fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            }
2024fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        }
2025fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    }
2026fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi
2027fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi
2028fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    /**
2029fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi     * A class to encapsulate all the information about a remote control display.
2030fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi     * After instanciation, init() must always be called before the object is added in the list
2031fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi     * of displays.
2032fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi     * Before being removed from the list of displays, release() must always be called (otherwise
2033fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi     * it will leak death handlers).
2034fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi     */
2035fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    private class DisplayInfoForServer implements IBinder.DeathRecipient {
2036fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        /** may never be null */
2037f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi        private final IRemoteControlDisplay mRcDisplay;
2038f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi        private final IBinder mRcDisplayBinder;
2039fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        private int mArtworkExpectedWidth = -1;
2040fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        private int mArtworkExpectedHeight = -1;
2041fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        private boolean mWantsPositionSync = false;
2042f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi        private ComponentName mClientNotifListComp;
2043f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi        private boolean mEnabled = true;
2044fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi
2045fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        public DisplayInfoForServer(IRemoteControlDisplay rcd, int w, int h) {
2046fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            if (DEBUG_RC) Log.i(TAG, "new DisplayInfoForServer for " + rcd + " w=" + w + " h=" + h);
2047fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            mRcDisplay = rcd;
2048fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            mRcDisplayBinder = rcd.asBinder();
2049fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            mArtworkExpectedWidth = w;
2050fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            mArtworkExpectedHeight = h;
2051fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        }
2052fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi
2053fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        public boolean init() {
2054fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            try {
2055fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                mRcDisplayBinder.linkToDeath(this, 0);
2056fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            } catch (RemoteException e) {
2057fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                // remote control display is DOA, disqualify it
2058fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                Log.w(TAG, "registerRemoteControlDisplay() has a dead client " + mRcDisplayBinder);
2059fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                return false;
2060fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            }
2061fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            return true;
2062fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        }
2063fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi
2064fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        public void release() {
2065fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            try {
2066fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                mRcDisplayBinder.unlinkToDeath(this, 0);
2067fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            } catch (java.util.NoSuchElementException e) {
2068fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                // not much we can do here, the display should have been unregistered anyway
2069fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                Log.e(TAG, "Error in DisplaInfoForServer.relase()", e);
2070fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            }
2071fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        }
2072fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi
2073fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        public void binderDied() {
2074fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            synchronized(mRCStack) {
2075fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                Log.w(TAG, "RemoteControl: display " + mRcDisplay + " died");
2076fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                // remove the display from the list
2077fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                final Iterator<DisplayInfoForServer> displayIterator = mRcDisplays.iterator();
2078fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                while (displayIterator.hasNext()) {
2079fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                    final DisplayInfoForServer di = (DisplayInfoForServer) displayIterator.next();
2080fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                    if (di.mRcDisplay == mRcDisplay) {
2081fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                        if (DEBUG_RC) Log.w(TAG, " RCD removed from list");
2082fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                        displayIterator.remove();
2083fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                        return;
2084fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                    }
2085fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                }
2086fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            }
2087fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        }
2088fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    }
2089fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi
2090fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    /**
2091fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi     * The remote control displays.
2092fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi     * Access synchronized on mRCStack
2093fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi     */
2094fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    private ArrayList<DisplayInfoForServer> mRcDisplays = new ArrayList<DisplayInfoForServer>(1);
2095fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi
2096fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    /**
2097fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi     * Plug each registered display into the specified client
2098fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi     * @param rcc, guaranteed non null
2099fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi     */
2100fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    private void plugRemoteControlDisplaysIntoClient_syncRcStack(IRemoteControlClient rcc) {
2101fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        final Iterator<DisplayInfoForServer> displayIterator = mRcDisplays.iterator();
2102fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        while (displayIterator.hasNext()) {
2103fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            final DisplayInfoForServer di = (DisplayInfoForServer) displayIterator.next();
2104fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            try {
2105fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                rcc.plugRemoteControlDisplay(di.mRcDisplay, di.mArtworkExpectedWidth,
2106fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                        di.mArtworkExpectedHeight);
2107fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                if (di.mWantsPositionSync) {
2108fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                    rcc.setWantsSyncForDisplay(di.mRcDisplay, true);
2109fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                }
2110fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            } catch (RemoteException e) {
2111fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                Log.e(TAG, "Error connecting RCD to RCC in RCC registration",e);
2112fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            }
2113fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        }
2114fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    }
2115fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi
2116f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi    private void enableRemoteControlDisplayForClient_syncRcStack(IRemoteControlDisplay rcd,
2117f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi            boolean enabled) {
2118f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi        // let all the remote control clients know whether the given display is enabled
2119f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi        //   (so the remote control stack traversal order doesn't matter).
2120f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi        final Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator();
2121f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi        while(stackIterator.hasNext()) {
2122f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi            RemoteControlStackEntry rcse = stackIterator.next();
2123f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi            if(rcse.mRcClient != null) {
2124f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi                try {
2125f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi                    rcse.mRcClient.enableRemoteControlDisplay(rcd, enabled);
2126f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi                } catch (RemoteException e) {
2127f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi                    Log.e(TAG, "Error connecting RCD to client: ", e);
2128f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi                }
2129f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi            }
2130f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi        }
2131f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi    }
2132f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi
2133fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    /**
2134fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi     * Is the remote control display interface already registered
2135fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi     * @param rcd
2136fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi     * @return true if the IRemoteControlDisplay is already in the list of displays
2137fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi     */
2138fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    private boolean rcDisplayIsPluggedIn_syncRcStack(IRemoteControlDisplay rcd) {
2139fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        final Iterator<DisplayInfoForServer> displayIterator = mRcDisplays.iterator();
2140fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        while (displayIterator.hasNext()) {
2141fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            final DisplayInfoForServer di = (DisplayInfoForServer) displayIterator.next();
2142fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            if (di.mRcDisplay.asBinder().equals(rcd.asBinder())) {
2143fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                return true;
2144fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            }
2145fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        }
2146fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        return false;
2147fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    }
2148fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi
2149fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    /**
2150fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi     * Register an IRemoteControlDisplay.
2151fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi     * Notify all IRemoteControlClient of the new display and cause the RemoteControlClient
2152fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi     * at the top of the stack to update the new display with its information.
2153fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi     * @see android.media.IAudioService#registerRemoteControlDisplay(android.media.IRemoteControlDisplay, int, int)
2154fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi     * @param rcd the IRemoteControlDisplay to register. No effect if null.
2155fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi     * @param w the maximum width of the expected bitmap. Negative or zero values indicate this
2156fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi     *   display doesn't need to receive artwork.
2157fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi     * @param h the maximum height of the expected bitmap. Negative or zero values indicate this
2158fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi     *   display doesn't need to receive artwork.
2159f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi     * @param listenerComp the component for the listener interface, may be null if it's not needed
2160f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi     *   to verify it belongs to one of the enabled notification listeners
2161fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi     */
2162f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi    private void registerRemoteControlDisplay_int(IRemoteControlDisplay rcd, int w, int h,
2163f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi            ComponentName listenerComp) {
2164fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        if (DEBUG_RC) Log.d(TAG, ">>> registerRemoteControlDisplay("+rcd+")");
2165fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        synchronized(mAudioFocusLock) {
2166fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            synchronized(mRCStack) {
2167fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                if ((rcd == null) || rcDisplayIsPluggedIn_syncRcStack(rcd)) {
2168fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                    return;
2169fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                }
2170fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                DisplayInfoForServer di = new DisplayInfoForServer(rcd, w, h);
2171f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi                di.mEnabled = true;
2172f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi                di.mClientNotifListComp = listenerComp;
2173fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                if (!di.init()) {
2174fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                    if (DEBUG_RC) Log.e(TAG, " error registering RCD");
2175fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                    return;
2176fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                }
2177fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                // add RCD to list of displays
2178fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                mRcDisplays.add(di);
2179fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi
2180fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                // let all the remote control clients know there is a new display (so the remote
2181fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                //   control stack traversal order doesn't matter).
2182fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator();
2183fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                while(stackIterator.hasNext()) {
2184fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                    RemoteControlStackEntry rcse = stackIterator.next();
2185fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                    if(rcse.mRcClient != null) {
2186fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                        try {
2187fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                            rcse.mRcClient.plugRemoteControlDisplay(rcd, w, h);
2188fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                        } catch (RemoteException e) {
2189fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                            Log.e(TAG, "Error connecting RCD to client: ", e);
2190fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                        }
2191fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                    }
2192fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                }
2193fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi
219486142da1ce8c1341404a9f9e21be8acbcba69ab3Jean-Michel Trivi                // we have a new display, of which all the clients are now aware: have it be
219586142da1ce8c1341404a9f9e21be8acbcba69ab3Jean-Michel Trivi                // initialized wih the current gen ID and the current client info, do not
219686142da1ce8c1341404a9f9e21be8acbcba69ab3Jean-Michel Trivi                // reset the information for the other (existing) displays
219786142da1ce8c1341404a9f9e21be8acbcba69ab3Jean-Michel Trivi                sendMsg(mEventHandler, MSG_RCDISPLAY_INIT_INFO, SENDMSG_QUEUE,
219886142da1ce8c1341404a9f9e21be8acbcba69ab3Jean-Michel Trivi                        w /*arg1*/, h /*arg2*/,
219986142da1ce8c1341404a9f9e21be8acbcba69ab3Jean-Michel Trivi                        rcd /*obj*/, 0/*delay*/);
2200fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            }
2201fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        }
2202fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    }
2203fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi
2204fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    /**
2205fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi     * Unregister an IRemoteControlDisplay.
2206fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi     * No effect if the IRemoteControlDisplay hasn't been successfully registered.
2207fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi     * @see android.media.IAudioService#unregisterRemoteControlDisplay(android.media.IRemoteControlDisplay)
2208fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi     * @param rcd the IRemoteControlDisplay to unregister. No effect if null.
2209fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi     */
2210fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    protected void unregisterRemoteControlDisplay(IRemoteControlDisplay rcd) {
2211fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        if (DEBUG_RC) Log.d(TAG, "<<< unregisterRemoteControlDisplay("+rcd+")");
2212fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        synchronized(mRCStack) {
2213fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            if (rcd == null) {
2214fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                return;
2215fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            }
2216fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi
2217fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            boolean displayWasPluggedIn = false;
2218fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            final Iterator<DisplayInfoForServer> displayIterator = mRcDisplays.iterator();
2219fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            while (displayIterator.hasNext() && !displayWasPluggedIn) {
2220fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                final DisplayInfoForServer di = (DisplayInfoForServer) displayIterator.next();
2221fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                if (di.mRcDisplay.asBinder().equals(rcd.asBinder())) {
2222fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                    displayWasPluggedIn = true;
2223fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                    di.release();
2224fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                    displayIterator.remove();
2225fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                }
2226fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            }
2227fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi
2228fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            if (displayWasPluggedIn) {
2229fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                // disconnect this remote control display from all the clients, so the remote
2230fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                //   control stack traversal order doesn't matter
2231fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                final Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator();
2232fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                while(stackIterator.hasNext()) {
2233fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                    final RemoteControlStackEntry rcse = stackIterator.next();
2234fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                    if(rcse.mRcClient != null) {
2235fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                        try {
2236fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                            rcse.mRcClient.unplugRemoteControlDisplay(rcd);
2237fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                        } catch (RemoteException e) {
2238fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                            Log.e(TAG, "Error disconnecting remote control display to client: ", e);
2239fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                        }
2240fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                    }
2241fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                }
2242fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            } else {
2243fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                if (DEBUG_RC) Log.w(TAG, "  trying to unregister unregistered RCD");
2244fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            }
2245fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        }
2246fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    }
2247fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi
2248fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    /**
2249fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi     * Update the size of the artwork used by an IRemoteControlDisplay.
2250fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi     * @see android.media.IAudioService#remoteControlDisplayUsesBitmapSize(android.media.IRemoteControlDisplay, int, int)
2251fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi     * @param rcd the IRemoteControlDisplay with the new artwork size requirement
2252fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi     * @param w the maximum width of the expected bitmap. Negative or zero values indicate this
2253fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi     *   display doesn't need to receive artwork.
2254fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi     * @param h the maximum height of the expected bitmap. Negative or zero values indicate this
2255fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi     *   display doesn't need to receive artwork.
2256fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi     */
2257fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    protected void remoteControlDisplayUsesBitmapSize(IRemoteControlDisplay rcd, int w, int h) {
2258fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        synchronized(mRCStack) {
2259fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            final Iterator<DisplayInfoForServer> displayIterator = mRcDisplays.iterator();
2260fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            boolean artworkSizeUpdate = false;
2261fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            while (displayIterator.hasNext() && !artworkSizeUpdate) {
2262fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                final DisplayInfoForServer di = (DisplayInfoForServer) displayIterator.next();
2263fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                if (di.mRcDisplay.asBinder().equals(rcd.asBinder())) {
2264fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                    if ((di.mArtworkExpectedWidth != w) || (di.mArtworkExpectedHeight != h)) {
2265fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                        di.mArtworkExpectedWidth = w;
2266fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                        di.mArtworkExpectedHeight = h;
2267fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                        artworkSizeUpdate = true;
2268fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                    }
2269fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                }
2270fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            }
2271fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            if (artworkSizeUpdate) {
2272fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                // RCD is currently plugged in and its artwork size has changed, notify all RCCs,
2273fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                // stack traversal order doesn't matter
2274fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                final Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator();
2275fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                while(stackIterator.hasNext()) {
2276fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                    final RemoteControlStackEntry rcse = stackIterator.next();
2277fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                    if(rcse.mRcClient != null) {
2278fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                        try {
2279fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                            rcse.mRcClient.setBitmapSizeForDisplay(rcd, w, h);
2280fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                        } catch (RemoteException e) {
2281fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                            Log.e(TAG, "Error setting bitmap size for RCD on RCC: ", e);
2282fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                        }
2283fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                    }
2284fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                }
2285fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            }
2286fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        }
2287fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    }
2288fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi
2289fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    /**
2290fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi     * Controls whether a remote control display needs periodic checks of the RemoteControlClient
2291fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi     * playback position to verify that the estimated position has not drifted from the actual
2292fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi     * position. By default the check is not performed.
2293fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi     * The IRemoteControlDisplay must have been previously registered for this to have any effect.
2294fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi     * @param rcd the IRemoteControlDisplay for which the anti-drift mechanism will be enabled
2295fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi     *     or disabled. Not null.
2296fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi     * @param wantsSync if true, RemoteControlClient instances which expose their playback position
2297fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi     *     to the framework will regularly compare the estimated playback position with the actual
2298fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi     *     position, and will update the IRemoteControlDisplay implementation whenever a drift is
2299fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi     *     detected.
2300fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi     */
2301fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    protected void remoteControlDisplayWantsPlaybackPositionSync(IRemoteControlDisplay rcd,
2302fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            boolean wantsSync) {
2303fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        synchronized(mRCStack) {
2304fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            boolean rcdRegistered = false;
2305fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            // store the information about this display
2306fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            // (display stack traversal order doesn't matter).
2307fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            final Iterator<DisplayInfoForServer> displayIterator = mRcDisplays.iterator();
2308fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            while (displayIterator.hasNext()) {
2309fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                final DisplayInfoForServer di = (DisplayInfoForServer) displayIterator.next();
2310fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                if (di.mRcDisplay.asBinder().equals(rcd.asBinder())) {
2311fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                    di.mWantsPositionSync = wantsSync;
2312fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                    rcdRegistered = true;
2313fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                    break;
2314fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                }
2315fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            }
2316fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            if (!rcdRegistered) {
2317fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                return;
2318fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            }
2319fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            // notify all current RemoteControlClients
2320fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            // (stack traversal order doesn't matter as we notify all RCCs)
2321fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            final Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator();
2322fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            while (stackIterator.hasNext()) {
2323fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                final RemoteControlStackEntry rcse = stackIterator.next();
2324fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                if (rcse.mRcClient != null) {
2325fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                    try {
2326fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                        rcse.mRcClient.setWantsSyncForDisplay(rcd, wantsSync);
2327fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                    } catch (RemoteException e) {
2328fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                        Log.e(TAG, "Error setting position sync flag for RCD on RCC: ", e);
2329fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                    }
2330fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                }
2331fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            }
2332fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        }
2333fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    }
2334fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi
2335fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    protected void setRemoteControlClientPlaybackPosition(int generationId, long timeMs) {
2336fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        // ignore position change requests if invalid generation ID
2337fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        synchronized(mRCStack) {
2338fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            synchronized(mCurrentRcLock) {
2339fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                if (mCurrentRcClientGen != generationId) {
2340fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                    return;
2341fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                }
2342fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            }
2343fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        }
2344fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        // discard any unprocessed seek request in the message queue, and replace with latest
2345fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        sendMsg(mEventHandler, MSG_RCC_SEEK_REQUEST, SENDMSG_REPLACE, generationId /* arg1 */,
2346fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                0 /* arg2 ignored*/, new Long(timeMs) /* obj */, 0 /* delay */);
2347fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    }
2348fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi
2349fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    private void onSetRemoteControlClientPlaybackPosition(int generationId, long timeMs) {
2350fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        if(DEBUG_RC) Log.d(TAG, "onSetRemoteControlClientPlaybackPosition(genId=" + generationId +
2351fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                ", timeMs=" + timeMs + ")");
2352fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        synchronized(mRCStack) {
2353fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            synchronized(mCurrentRcLock) {
2354fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                if ((mCurrentRcClient != null) && (mCurrentRcClientGen == generationId)) {
2355fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                    // tell the current client to seek to the requested location
2356fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                    try {
2357fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                        mCurrentRcClient.seekTo(generationId, timeMs);
2358fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                    } catch (RemoteException e) {
2359fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                        Log.e(TAG, "Current valid remote client is dead: "+e);
2360fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                        mCurrentRcClient = null;
2361fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                    }
2362fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                }
2363fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            }
2364fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        }
2365fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    }
2366fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi
23677ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi    protected void updateRemoteControlClientMetadata(int genId, int key, Rating value) {
23687ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi        sendMsg(mEventHandler, MSG_RCC_UPDATE_METADATA, SENDMSG_QUEUE,
23697ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi                genId /* arg1 */, key /* arg2 */, value /* obj */, 0 /* delay */);
2370f823fc4dba2df5cf5f00e13361f2db93c81f6961Jean-Michel Trivi    }
2371f823fc4dba2df5cf5f00e13361f2db93c81f6961Jean-Michel Trivi
23727ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi    private void onUpdateRemoteControlClientMetadata(int genId, int key, Rating value) {
23737ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi        if(DEBUG_RC) Log.d(TAG, "onUpdateRemoteControlClientMetadata(genId=" + genId +
23747ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi                ", what=" + key + ",rating=" + value + ")");
2375f823fc4dba2df5cf5f00e13361f2db93c81f6961Jean-Michel Trivi        synchronized(mRCStack) {
2376f823fc4dba2df5cf5f00e13361f2db93c81f6961Jean-Michel Trivi            synchronized(mCurrentRcLock) {
2377f823fc4dba2df5cf5f00e13361f2db93c81f6961Jean-Michel Trivi                if ((mCurrentRcClient != null) && (mCurrentRcClientGen == genId)) {
2378f823fc4dba2df5cf5f00e13361f2db93c81f6961Jean-Michel Trivi                    try {
2379f823fc4dba2df5cf5f00e13361f2db93c81f6961Jean-Michel Trivi                        switch (key) {
23807ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi                            case MediaMetadataEditor.RATING_KEY_BY_USER:
23817ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi                                mCurrentRcClient.updateMetadata(genId, key, value);
2382f823fc4dba2df5cf5f00e13361f2db93c81f6961Jean-Michel Trivi                                break;
2383f823fc4dba2df5cf5f00e13361f2db93c81f6961Jean-Michel Trivi                            default:
2384f823fc4dba2df5cf5f00e13361f2db93c81f6961Jean-Michel Trivi                                Log.e(TAG, "unhandled metadata key " + key + " update for RCC "
2385f823fc4dba2df5cf5f00e13361f2db93c81f6961Jean-Michel Trivi                                        + genId);
2386f823fc4dba2df5cf5f00e13361f2db93c81f6961Jean-Michel Trivi                                break;
2387f823fc4dba2df5cf5f00e13361f2db93c81f6961Jean-Michel Trivi                        }
2388f823fc4dba2df5cf5f00e13361f2db93c81f6961Jean-Michel Trivi                    } catch (RemoteException e) {
2389f823fc4dba2df5cf5f00e13361f2db93c81f6961Jean-Michel Trivi                        Log.e(TAG, "Current valid remote client is dead", e);
2390f823fc4dba2df5cf5f00e13361f2db93c81f6961Jean-Michel Trivi                        mCurrentRcClient = null;
2391f823fc4dba2df5cf5f00e13361f2db93c81f6961Jean-Michel Trivi                    }
2392f823fc4dba2df5cf5f00e13361f2db93c81f6961Jean-Michel Trivi                }
2393f823fc4dba2df5cf5f00e13361f2db93c81f6961Jean-Michel Trivi            }
2394f823fc4dba2df5cf5f00e13361f2db93c81f6961Jean-Michel Trivi        }
2395f823fc4dba2df5cf5f00e13361f2db93c81f6961Jean-Michel Trivi    }
2396f823fc4dba2df5cf5f00e13361f2db93c81f6961Jean-Michel Trivi
2397fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    protected void setPlaybackInfoForRcc(int rccId, int what, int value) {
2398fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        sendMsg(mEventHandler, MSG_RCC_NEW_PLAYBACK_INFO, SENDMSG_QUEUE,
2399fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                rccId /* arg1 */, what /* arg2 */, Integer.valueOf(value) /* obj */, 0 /* delay */);
2400fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    }
2401fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi
2402fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    // handler for MSG_RCC_NEW_PLAYBACK_INFO
2403fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    private void onNewPlaybackInfoForRcc(int rccId, int key, int value) {
2404fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        if(DEBUG_RC) Log.d(TAG, "onNewPlaybackInfoForRcc(id=" + rccId +
2405fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                ", what=" + key + ",val=" + value + ")");
2406fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        synchronized(mRCStack) {
2407fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            // iterating from top of stack as playback information changes are more likely
2408fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            //   on entries at the top of the remote control stack
2409fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            try {
2410fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                for (int index = mRCStack.size()-1; index >= 0; index--) {
2411fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                    final RemoteControlStackEntry rcse = mRCStack.elementAt(index);
2412fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                    if (rcse.mRccId == rccId) {
2413fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                        switch (key) {
2414fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                            case RemoteControlClient.PLAYBACKINFO_PLAYBACK_TYPE:
2415fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                                rcse.mPlaybackType = value;
2416fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                                postReevaluateRemote();
2417fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                                break;
2418fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                            case RemoteControlClient.PLAYBACKINFO_VOLUME:
2419fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                                rcse.mPlaybackVolume = value;
2420fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                                synchronized (mMainRemote) {
2421fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                                    if (rccId == mMainRemote.mRccId) {
2422fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                                        mMainRemote.mVolume = value;
2423fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                                        mVolumeController.postHasNewRemotePlaybackInfo();
2424fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                                    }
2425fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                                }
2426fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                                break;
2427fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                            case RemoteControlClient.PLAYBACKINFO_VOLUME_MAX:
2428fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                                rcse.mPlaybackVolumeMax = value;
2429fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                                synchronized (mMainRemote) {
2430fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                                    if (rccId == mMainRemote.mRccId) {
2431fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                                        mMainRemote.mVolumeMax = value;
2432fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                                        mVolumeController.postHasNewRemotePlaybackInfo();
2433fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                                    }
2434fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                                }
2435fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                                break;
2436fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                            case RemoteControlClient.PLAYBACKINFO_VOLUME_HANDLING:
2437fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                                rcse.mPlaybackVolumeHandling = value;
2438fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                                synchronized (mMainRemote) {
2439fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                                    if (rccId == mMainRemote.mRccId) {
2440fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                                        mMainRemote.mVolumeHandling = value;
2441fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                                        mVolumeController.postHasNewRemotePlaybackInfo();
2442fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                                    }
2443fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                                }
2444fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                                break;
2445fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                            case RemoteControlClient.PLAYBACKINFO_USES_STREAM:
2446fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                                rcse.mPlaybackStream = value;
2447fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                                break;
2448fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                            default:
2449fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                                Log.e(TAG, "unhandled key " + key + " for RCC " + rccId);
2450fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                                break;
2451fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                        }
2452fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                        return;
2453fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                    }
2454fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                }//for
2455fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            } catch (ArrayIndexOutOfBoundsException e) {
2456fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                // not expected to happen, indicates improper concurrent modification
2457fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                Log.e(TAG, "Wrong index mRCStack on onNewPlaybackInfoForRcc, lock error? ", e);
2458fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            }
2459fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        }
2460fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    }
2461fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi
2462fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    protected void setPlaybackStateForRcc(int rccId, int state, long timeMs, float speed) {
2463fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        sendMsg(mEventHandler, MSG_RCC_NEW_PLAYBACK_STATE, SENDMSG_QUEUE,
2464fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                rccId /* arg1 */, state /* arg2 */,
2465fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                new RccPlaybackState(state, timeMs, speed) /* obj */, 0 /* delay */);
2466fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    }
2467fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi
246855e1bc6c58bbb7d08b8a197322dc1afbab9866a2Jean-Michel Trivi    private void onNewPlaybackStateForRcc(int rccId, int state, RccPlaybackState newState) {
2469fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        if(DEBUG_RC) Log.d(TAG, "onNewPlaybackStateForRcc(id=" + rccId + ", state=" + state
2470fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                + ", time=" + newState.mPositionMs + ", speed=" + newState.mSpeed + ")");
2471fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        synchronized(mRCStack) {
2472fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            // iterating from top of stack as playback information changes are more likely
2473fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            //   on entries at the top of the remote control stack
2474fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            try {
2475fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                for (int index = mRCStack.size()-1; index >= 0; index--) {
2476fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                    final RemoteControlStackEntry rcse = mRCStack.elementAt(index);
2477fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                    if (rcse.mRccId == rccId) {
2478fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                        rcse.mPlaybackState = newState;
2479fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                        synchronized (mMainRemote) {
2480fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                            if (rccId == mMainRemote.mRccId) {
2481fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                                mMainRemoteIsActive = isPlaystateActive(state);
2482fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                                postReevaluateRemote();
2483fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                            }
2484fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                        }
2485fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                        // an RCC moving to a "playing" state should become the media button
2486fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                        //   event receiver so it can be controlled, without requiring the
2487fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                        //   app to re-register its receiver
2488fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                        if (isPlaystateActive(state)) {
2489fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                            postPromoteRcc(rccId);
2490fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                        }
2491fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                    }
2492fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                }//for
2493fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            } catch (ArrayIndexOutOfBoundsException e) {
2494fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                // not expected to happen, indicates improper concurrent modification
2495fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                Log.e(TAG, "Wrong index on mRCStack in onNewPlaybackStateForRcc, lock error? ", e);
2496fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            }
2497fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        }
2498fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    }
2499fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi
2500fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    protected void registerRemoteVolumeObserverForRcc(int rccId, IRemoteVolumeObserver rvo) {
2501fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        sendMsg(mEventHandler, MSG_RCC_NEW_VOLUME_OBS, SENDMSG_QUEUE,
2502fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                rccId /* arg1 */, 0, rvo /* obj */, 0 /* delay */);
2503fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    }
2504fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi
2505fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    // handler for MSG_RCC_NEW_VOLUME_OBS
2506fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    private void onRegisterVolumeObserverForRcc(int rccId, IRemoteVolumeObserver rvo) {
2507fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        synchronized(mRCStack) {
2508fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            // The stack traversal order doesn't matter because there is only one stack entry
2509fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            //  with this RCC ID, but the matching ID is more likely at the top of the stack, so
2510fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            //  start iterating from the top.
2511fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            try {
2512fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                for (int index = mRCStack.size()-1; index >= 0; index--) {
2513fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                    final RemoteControlStackEntry rcse = mRCStack.elementAt(index);
2514fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                    if (rcse.mRccId == rccId) {
2515fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                        rcse.mRemoteVolumeObs = rvo;
2516fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                        break;
2517fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                    }
2518fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                }
2519fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            } catch (ArrayIndexOutOfBoundsException e) {
2520fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                // not expected to happen, indicates improper concurrent modification
2521fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                Log.e(TAG, "Wrong index accessing media button stack, lock error? ", e);
2522fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            }
2523fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        }
2524fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    }
2525fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi
2526fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    /**
2527fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi     * Checks if a remote client is active on the supplied stream type. Update the remote stream
2528fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi     * volume state if found and playing
2529fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi     * @param streamType
2530fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi     * @return false if no remote playing is currently playing
2531fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi     */
2532fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    protected boolean checkUpdateRemoteStateIfActive(int streamType) {
2533fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        synchronized(mRCStack) {
2534fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            // iterating from top of stack as active playback is more likely on entries at the top
2535fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            try {
2536fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                for (int index = mRCStack.size()-1; index >= 0; index--) {
2537fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                    final RemoteControlStackEntry rcse = mRCStack.elementAt(index);
2538fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                    if ((rcse.mPlaybackType == RemoteControlClient.PLAYBACK_TYPE_REMOTE)
2539fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                            && isPlaystateActive(rcse.mPlaybackState.mState)
2540fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                            && (rcse.mPlaybackStream == streamType)) {
2541fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                        if (DEBUG_RC) Log.d(TAG, "remote playback active on stream " + streamType
2542fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                                + ", vol =" + rcse.mPlaybackVolume);
2543fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                        synchronized (mMainRemote) {
2544fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                            mMainRemote.mRccId = rcse.mRccId;
2545fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                            mMainRemote.mVolume = rcse.mPlaybackVolume;
2546fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                            mMainRemote.mVolumeMax = rcse.mPlaybackVolumeMax;
2547fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                            mMainRemote.mVolumeHandling = rcse.mPlaybackVolumeHandling;
2548fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                            mMainRemoteIsActive = true;
2549fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                        }
2550fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                        return true;
2551fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                    }
2552fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                }
2553fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            } catch (ArrayIndexOutOfBoundsException e) {
2554fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                // not expected to happen, indicates improper concurrent modification
2555fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                Log.e(TAG, "Wrong index accessing RC stack, lock error? ", e);
2556fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            }
2557fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        }
2558fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        synchronized (mMainRemote) {
2559fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            mMainRemoteIsActive = false;
2560fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        }
2561fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        return false;
2562fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    }
2563fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi
2564fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    /**
2565fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi     * Returns true if the given playback state is considered "active", i.e. it describes a state
2566fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi     * where playback is happening, or about to
2567fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi     * @param playState the playback state to evaluate
2568fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi     * @return true if active, false otherwise (inactive or unknown)
2569fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi     */
2570fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    private static boolean isPlaystateActive(int playState) {
2571fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        switch (playState) {
2572fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            case RemoteControlClient.PLAYSTATE_PLAYING:
2573fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            case RemoteControlClient.PLAYSTATE_BUFFERING:
2574fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            case RemoteControlClient.PLAYSTATE_FAST_FORWARDING:
2575fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            case RemoteControlClient.PLAYSTATE_REWINDING:
2576fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            case RemoteControlClient.PLAYSTATE_SKIPPING_BACKWARDS:
2577fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            case RemoteControlClient.PLAYSTATE_SKIPPING_FORWARDS:
2578fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                return true;
2579fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            default:
2580fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                return false;
2581fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        }
2582fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    }
2583fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi
2584fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    protected void adjustRemoteVolume(int streamType, int direction, int flags) {
2585fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        int rccId = RemoteControlClient.RCSE_ID_UNREGISTERED;
2586fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        boolean volFixed = false;
2587fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        synchronized (mMainRemote) {
2588fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            if (!mMainRemoteIsActive) {
2589fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                if (DEBUG_VOL) Log.w(TAG, "adjustRemoteVolume didn't find an active client");
2590fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                return;
2591fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            }
2592fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            rccId = mMainRemote.mRccId;
2593fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            volFixed = (mMainRemote.mVolumeHandling ==
2594fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                    RemoteControlClient.PLAYBACK_VOLUME_FIXED);
2595fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        }
2596fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        // unlike "local" stream volumes, we can't compute the new volume based on the direction,
2597fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        // we can only notify the remote that volume needs to be updated, and we'll get an async'
2598fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        // update through setPlaybackInfoForRcc()
2599fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        if (!volFixed) {
2600fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            sendVolumeUpdateToRemote(rccId, direction);
2601fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        }
2602fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi
2603fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        // fire up the UI
2604fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        mVolumeController.postRemoteVolumeChanged(streamType, flags);
2605fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    }
2606fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi
2607fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    private void sendVolumeUpdateToRemote(int rccId, int direction) {
2608fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        if (DEBUG_VOL) { Log.d(TAG, "sendVolumeUpdateToRemote(rccId="+rccId+" , dir="+direction); }
2609fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        if (direction == 0) {
2610fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            // only handling discrete events
2611fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            return;
2612fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        }
2613fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        IRemoteVolumeObserver rvo = null;
2614fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        synchronized (mRCStack) {
2615fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            // The stack traversal order doesn't matter because there is only one stack entry
2616fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            //  with this RCC ID, but the matching ID is more likely at the top of the stack, so
2617fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            //  start iterating from the top.
2618fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            try {
2619fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                for (int index = mRCStack.size()-1; index >= 0; index--) {
2620fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                    final RemoteControlStackEntry rcse = mRCStack.elementAt(index);
2621fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                    //FIXME OPTIMIZE store this info in mMainRemote so we don't have to iterate?
2622fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                    if (rcse.mRccId == rccId) {
2623fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                        rvo = rcse.mRemoteVolumeObs;
2624fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                        break;
2625fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                    }
2626fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                }
2627fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            } catch (ArrayIndexOutOfBoundsException e) {
2628fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                // not expected to happen, indicates improper concurrent modification
2629fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                Log.e(TAG, "Wrong index accessing media button stack, lock error? ", e);
2630fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            }
2631fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        }
2632fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        if (rvo != null) {
2633fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            try {
2634fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                rvo.dispatchRemoteVolumeUpdate(direction, -1);
2635fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            } catch (RemoteException e) {
2636fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                Log.e(TAG, "Error dispatching relative volume update", e);
2637fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            }
2638fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        }
2639fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    }
2640fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi
2641fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    protected int getRemoteStreamMaxVolume() {
2642fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        synchronized (mMainRemote) {
2643fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            if (mMainRemote.mRccId == RemoteControlClient.RCSE_ID_UNREGISTERED) {
2644fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                return 0;
2645fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            }
2646fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            return mMainRemote.mVolumeMax;
2647fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        }
2648fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    }
2649fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi
2650fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    protected int getRemoteStreamVolume() {
2651fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        synchronized (mMainRemote) {
2652fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            if (mMainRemote.mRccId == RemoteControlClient.RCSE_ID_UNREGISTERED) {
2653fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                return 0;
2654fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            }
2655fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            return mMainRemote.mVolume;
2656fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        }
2657fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    }
2658fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi
2659fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    protected void setRemoteStreamVolume(int vol) {
2660fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        if (DEBUG_VOL) { Log.d(TAG, "setRemoteStreamVolume(vol="+vol+")"); }
2661fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        int rccId = RemoteControlClient.RCSE_ID_UNREGISTERED;
2662fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        synchronized (mMainRemote) {
2663fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            if (mMainRemote.mRccId == RemoteControlClient.RCSE_ID_UNREGISTERED) {
2664fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                return;
2665fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            }
2666fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            rccId = mMainRemote.mRccId;
2667fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        }
2668fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        IRemoteVolumeObserver rvo = null;
2669fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        synchronized (mRCStack) {
2670fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            // The stack traversal order doesn't matter because there is only one stack entry
2671fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            //  with this RCC ID, but the matching ID is more likely at the top of the stack, so
2672fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            //  start iterating from the top.
2673fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            try {
2674fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                for (int index = mRCStack.size()-1; index >= 0; index--) {
2675fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                    final RemoteControlStackEntry rcse = mRCStack.elementAt(index);
2676fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                    //FIXME OPTIMIZE store this info in mMainRemote so we don't have to iterate?
2677fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                    if (rcse.mRccId == rccId) {
2678fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                        rvo = rcse.mRemoteVolumeObs;
2679fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                        break;
2680fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                    }
2681fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                }
2682fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            } catch (ArrayIndexOutOfBoundsException e) {
2683fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                // not expected to happen, indicates improper concurrent modification
2684fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                Log.e(TAG, "Wrong index accessing media button stack, lock error? ", e);
2685fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            }
2686fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        }
2687fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        if (rvo != null) {
2688fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            try {
2689fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                rvo.dispatchRemoteVolumeUpdate(0, vol);
2690fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            } catch (RemoteException e) {
2691fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                Log.e(TAG, "Error dispatching absolute volume update", e);
2692fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            }
2693fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        }
2694fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    }
2695fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi
2696fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    /**
2697fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi     * Call to make AudioService reevaluate whether it's in a mode where remote players should
2698fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi     * have their volume controlled. In this implementation this is only to reset whether
2699fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi     * VolumePanel should display remote volumes
2700fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi     */
2701fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    private void postReevaluateRemote() {
2702fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        sendMsg(mEventHandler, MSG_REEVALUATE_REMOTE, SENDMSG_QUEUE, 0, 0, null, 0);
2703fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    }
2704fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi
2705fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    private void onReevaluateRemote() {
2706fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        if (DEBUG_VOL) { Log.w(TAG, "onReevaluateRemote()"); }
2707fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        // is there a registered RemoteControlClient that is handling remote playback
2708fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        boolean hasRemotePlayback = false;
2709fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        synchronized (mRCStack) {
2710fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            // iteration stops when PLAYBACK_TYPE_REMOTE is found, so remote control stack
2711fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            //   traversal order doesn't matter
2712fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator();
2713fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            while(stackIterator.hasNext()) {
2714fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                RemoteControlStackEntry rcse = stackIterator.next();
2715fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                if (rcse.mPlaybackType == RemoteControlClient.PLAYBACK_TYPE_REMOTE) {
2716fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                    hasRemotePlayback = true;
2717fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                    break;
2718fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                }
2719fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            }
2720fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        }
2721fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        synchronized (mMainRemote) {
2722fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            if (mHasRemotePlayback != hasRemotePlayback) {
2723fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                mHasRemotePlayback = hasRemotePlayback;
2724fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                mVolumeController.postRemoteSliderVisibility(hasRemotePlayback);
2725fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            }
2726fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        }
2727fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    }
2728fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi
2729fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi}
2730