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