19066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/* 29066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Copyright (C) 2006 The Android Open Source Project 39066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 49066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License"); 59066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * you may not use this file except in compliance with the License. 69066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * You may obtain a copy of the License at 79066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 89066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * http://www.apache.org/licenses/LICENSE-2.0 99066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Unless required by applicable law or agreed to in writing, software 119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS, 129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * See the License for the specific language governing permissions and 149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * limitations under the License. 159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectpackage android.media; 189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 19098d580cc2bb6c0891c756a4e5230c6c6b0d2376Jeff Sharkeyimport static android.Manifest.permission.REMOTE_AUDIO_PLAYBACK; 20c696a53d1fe4d61373c5dc64dd057d322da90c8fAmith Yamasaniimport static android.media.AudioManager.RINGER_MODE_NORMAL; 21c696a53d1fe4d61373c5dc64dd057d322da90c8fAmith Yamasaniimport static android.media.AudioManager.RINGER_MODE_SILENT; 22c696a53d1fe4d61373c5dc64dd057d322da90c8fAmith Yamasaniimport static android.media.AudioManager.RINGER_MODE_VIBRATE; 23c696a53d1fe4d61373c5dc64dd057d322da90c8fAmith Yamasani 24c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Triviimport android.app.Activity; 259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.app.ActivityManagerNative; 266243edd818b84adfbe712d5d233d6414b33653acAmith Yamasaniimport android.app.KeyguardManager; 27f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Triviimport android.app.PendingIntent; 28f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Triviimport android.app.PendingIntent.CanceledException; 29c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Triviimport android.app.PendingIntent.OnFinished; 3082aa7f017daaaeb96c13e6e3491d5037ab471085Jaikumar Ganeshimport android.bluetooth.BluetoothA2dp; 3182aa7f017daaaeb96c13e6e3491d5037ab471085Jaikumar Ganeshimport android.bluetooth.BluetoothAdapter; 3282aa7f017daaaeb96c13e6e3491d5037ab471085Jaikumar Ganeshimport android.bluetooth.BluetoothClass; 3382aa7f017daaaeb96c13e6e3491d5037ab471085Jaikumar Ganeshimport android.bluetooth.BluetoothDevice; 3482aa7f017daaaeb96c13e6e3491d5037ab471085Jaikumar Ganeshimport android.bluetooth.BluetoothHeadset; 3582aa7f017daaaeb96c13e6e3491d5037ab471085Jaikumar Ganeshimport android.bluetooth.BluetoothProfile; 364294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Triviimport android.content.ActivityNotFoundException; 37bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pellyimport android.content.BroadcastReceiver; 38d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Triviimport android.content.ComponentName; 399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.ContentResolver; 409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.Context; 419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.Intent; 42a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurentimport android.content.IntentFilter; 439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.pm.PackageManager; 44f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Triviimport android.content.res.Configuration; 45b109615ebebd6f3b9ae789412279f576c3ace46bJason Parekhimport android.database.ContentObserver; 469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.media.MediaPlayer.OnCompletionListener; 479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.media.MediaPlayer.OnErrorListener; 489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.Binder; 49f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Triviimport android.os.Bundle; 509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.Environment; 519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.Handler; 529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.IBinder; 539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.Looper; 549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.Message; 55c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Triviimport android.os.PowerManager; 56632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackbornimport android.os.RemoteCallbackList; 579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.RemoteException; 589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.ServiceManager; 5982aa7f017daaaeb96c13e6e3491d5037ab471085Jaikumar Ganeshimport android.os.SystemProperties; 60bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurentimport android.os.Vibrator; 619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.provider.Settings; 629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.provider.Settings.System; 633c2711fc2853394324b044632b79ca67388df8f4Jean-Michel Triviimport android.speech.RecognizerIntent; 64b4bccb6d8df16a2c5235cead187156bc721cf074Jean-Michel Triviimport android.telephony.PhoneStateListener; 65b4bccb6d8df16a2c5235cead187156bc721cf074Jean-Michel Triviimport android.telephony.TelephonyManager; 66632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackbornimport android.text.TextUtils; 679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.util.Log; 68d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Triviimport android.view.KeyEvent; 699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.view.VolumePanel; 709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport com.android.internal.telephony.ITelephony; 729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 73d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Triviimport java.io.FileDescriptor; 749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.io.IOException; 75d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Triviimport java.io.PrintWriter; 769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.ArrayList; 773172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurentimport java.util.concurrent.ConcurrentHashMap; 78c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurentimport java.util.HashMap; 79c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurentimport java.util.Iterator; 805a1e4cf83f5be1b5d79e2643fa791aa269b6a4bcJaikumar Ganeshimport java.util.List; 81c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurentimport java.util.Map; 8282aa7f017daaaeb96c13e6e3491d5037ab471085Jaikumar Ganeshimport java.util.NoSuchElementException; 83c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurentimport java.util.Set; 84d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Triviimport java.util.Stack; 859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/** 879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * The implementation of the volume manager service. 889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * <p> 899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * This implementation focuses on delivering a responsive UI. Most methods are 909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * asynchronous to external calls. For example, the task of setting a volume 919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * will update our internal state, but in a separate thread will set the system 929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * volume and later persist to the database. Similarly, setting the ringer mode 939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * will update the state and broadcast a change and in a separate thread later 949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * persist the ringer mode. 959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @hide 979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 98c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivipublic class AudioService extends IAudioService.Stub implements OnFinished { 999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final String TAG = "AudioService"; 1019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 10218e7bce52318f00b5023f33933a571c477f2b61cJean-Michel Trivi /** Debug remote control client/display feature */ 1037ff866e8cf43afc64111e98863dab549b57447b4Jean-Michel Trivi protected static final boolean DEBUG_RC = false; 1043114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi /** Debug volumes */ 1053114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi protected static final boolean DEBUG_VOL = false; 10618e7bce52318f00b5023f33933a571c477f2b61cJean-Michel Trivi 1079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** How long to delay before persisting a change in volume/ringer mode. */ 10845edba1b8b0377dfe70a4f2b0afb0f04dd8e1ee9RoboErik private static final int PERSIST_DELAY = 500; 1099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private Context mContext; 1119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private ContentResolver mContentResolver; 112c7fcba4b7bd3d78e7cfe975a3f8e4dde2f6738b7Joe Onorato private boolean mVoiceCapable; 113d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi 1149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** The UI */ 1159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private VolumePanel mVolumePanel; 1169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // sendMsg() flags 1189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** If the msg is already queued, replace it with this one. */ 1199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final int SENDMSG_REPLACE = 0; 1209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** If the msg is already queued, ignore this one and leave the old. */ 1219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final int SENDMSG_NOOP = 1; 1229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** If the msg is already queued, queue this one and leave the old. */ 1239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final int SENDMSG_QUEUE = 2; 1249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1253114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi // AudioHandler messages 1269bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent private static final int MSG_SET_DEVICE_VOLUME = 0; 1279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final int MSG_PERSIST_VOLUME = 1; 1285c55a051ad7d86a464fb91426f1ea3c0250e38b3Mike Lockwood private static final int MSG_PERSIST_MASTER_VOLUME = 2; 1299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final int MSG_PERSIST_RINGER_MODE = 3; 130bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent private static final int MSG_MEDIA_SERVER_DIED = 4; 131bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent private static final int MSG_MEDIA_SERVER_STARTED = 5; 132bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent private static final int MSG_PLAY_SOUND_EFFECT = 6; 133bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent private static final int MSG_BTA2DP_DOCK_TIMEOUT = 7; 134bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent private static final int MSG_LOAD_SOUND_EFFECTS = 8; 135bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent private static final int MSG_SET_FORCE_USE = 9; 136bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent private static final int MSG_PERSIST_MEDIABUTTONRECEIVER = 10; 137bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent private static final int MSG_BT_HEADSET_CNCT_FAILED = 11; 138bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent private static final int MSG_RCDISPLAY_CLEAR = 12; 139bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent private static final int MSG_RCDISPLAY_UPDATE = 13; 140bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent private static final int MSG_SET_ALL_VOLUMES = 14; 141bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent private static final int MSG_PERSIST_MASTER_VOLUME_MUTE = 15; 142632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn private static final int MSG_REPORT_NEW_ROUTES = 16; 1433114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi private static final int MSG_REEVALUATE_REMOTE = 17; 144f98de1e8dd6dcbd191921b4aa07a1d41b0b9db91Jean-Michel Trivi private static final int MSG_RCC_NEW_PLAYBACK_INFO = 18; 145f98de1e8dd6dcbd191921b4aa07a1d41b0b9db91Jean-Michel Trivi private static final int MSG_RCC_NEW_VOLUME_OBS = 19; 1463114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi // start of messages handled under wakelock 1473114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi // these messages can only be queued, i.e. sent with queueMsgUnderWakeLock(), 148e12c39bb9cedb8b363658979872694eb55b1386eJean-Michel Trivi // and not with sendMsg(..., ..., SENDMSG_QUEUE, ...) 149f98de1e8dd6dcbd191921b4aa07a1d41b0b9db91Jean-Michel Trivi private static final int MSG_SET_WIRED_DEVICE_CONNECTION_STATE = 20; 150f98de1e8dd6dcbd191921b4aa07a1d41b0b9db91Jean-Michel Trivi private static final int MSG_SET_A2DP_CONNECTION_STATE = 21; 1513114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi // end of messages handled under wakelock 152afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent 153afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent // flags for MSG_PERSIST_VOLUME indicating if current and/or last audible volume should be 154afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent // persisted 155afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent private static final int PERSIST_CURRENT = 0x1; 156afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent private static final int PERSIST_LAST_AUDIBLE = 0x2; 157afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent 1584c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi private static final int BTA2DP_DOCK_TIMEOUT_MILLIS = 8000; 159dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent // Timeout for connection to bluetooth headset service 160dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent private static final int BT_HEADSET_CNCT_TIMEOUT_MS = 3000; 161dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent 1629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** @see AudioSystemThread */ 1639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private AudioSystemThread mAudioSystemThread; 1649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** @see AudioHandler */ 1659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private AudioHandler mAudioHandler; 1669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** @see VolumeStreamState */ 1679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private VolumeStreamState[] mStreamStates; 168b109615ebebd6f3b9ae789412279f576c3ace46bJason Parekh private SettingsObserver mSettingsObserver; 169a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent 1709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private int mMode; 171ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten // protects mRingerMode 172ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten private final Object mSettingsLock = new Object(); 17345c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent 1749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private boolean mMediaServerOk; 1759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private SoundPool mSoundPool; 17730c918ce7fbe171944b28fc91b3f22b3d631872dGlenn Kasten private final Object mSoundEffectsLock = new Object(); 1789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final int NUM_SOUNDPOOL_CHANNELS = 4; 1799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1804767690f09ea3447b8c5c32fb28d27650aa18e00Mike Lockwood // Internally master volume is a float in the 0.0 - 1.0 range, 1814767690f09ea3447b8c5c32fb28d27650aa18e00Mike Lockwood // but to support integer based AudioManager API we translate it to 0 - 100 1824767690f09ea3447b8c5c32fb28d27650aa18e00Mike Lockwood private static final int MAX_MASTER_VOLUME = 100; 1834767690f09ea3447b8c5c32fb28d27650aa18e00Mike Lockwood 1846c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang // Maximum volume adjust steps allowed in a single batch call. 1856c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang private static final int MAX_BATCH_VOLUME_ADJUST_STEPS = 4; 1866c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang 1879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /* Sound effect file names */ 1889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final String SOUND_EFFECTS_PATH = "/media/audio/ui/"; 1899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final String[] SOUND_EFFECT_FILES = new String[] { 1909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Effect_Tick.ogg", 1919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "KeypressStandard.ogg", 1929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "KeypressSpacebar.ogg", 1939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "KeypressDelete.ogg", 1949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "KeypressReturn.ogg" 1959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project }; 1969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /* Sound effect file name mapping sound effect id (AudioManager.FX_xxx) to 1989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * file index in SOUND_EFFECT_FILES[] (first column) and indicating if effect 1999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * uses soundpool (second column) */ 20030c918ce7fbe171944b28fc91b3f22b3d631872dGlenn Kasten private final int[][] SOUND_EFFECT_FILES_MAP = new int[][] { 2019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project {0, -1}, // FX_KEY_CLICK 2029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project {0, -1}, // FX_FOCUS_NAVIGATION_UP 2039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project {0, -1}, // FX_FOCUS_NAVIGATION_DOWN 2049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project {0, -1}, // FX_FOCUS_NAVIGATION_LEFT 2059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project {0, -1}, // FX_FOCUS_NAVIGATION_RIGHT 2069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project {1, -1}, // FX_KEYPRESS_STANDARD 2079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project {2, -1}, // FX_KEYPRESS_SPACEBAR 2089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project {3, -1}, // FX_FOCUS_DELETE 2099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project {4, -1} // FX_FOCUS_RETURN 2109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project }; 2119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2125982013cfc8274ff0bafaba83c676b3a8890cba9Jared Suttles /** @hide Maximum volume index values for audio streams */ 21330c918ce7fbe171944b28fc91b3f22b3d631872dGlenn Kasten private final int[] MAX_STREAM_VOLUME = new int[] { 2146ee9952bc20be72b9419cb653c9e2e833889a3d3Eric Laurent 5, // STREAM_VOICE_CALL 2156ee9952bc20be72b9419cb653c9e2e833889a3d3Eric Laurent 7, // STREAM_SYSTEM 2166ee9952bc20be72b9419cb653c9e2e833889a3d3Eric Laurent 7, // STREAM_RING 2176ee9952bc20be72b9419cb653c9e2e833889a3d3Eric Laurent 15, // STREAM_MUSIC 2186ee9952bc20be72b9419cb653c9e2e833889a3d3Eric Laurent 7, // STREAM_ALARM 2196ee9952bc20be72b9419cb653c9e2e833889a3d3Eric Laurent 7, // STREAM_NOTIFICATION 2206ee9952bc20be72b9419cb653c9e2e833889a3d3Eric Laurent 15, // STREAM_BLUETOOTH_SCO 2216ee9952bc20be72b9419cb653c9e2e833889a3d3Eric Laurent 7, // STREAM_SYSTEM_ENFORCED 2226ee9952bc20be72b9419cb653c9e2e833889a3d3Eric Laurent 15, // STREAM_DTMF 2236ee9952bc20be72b9419cb653c9e2e833889a3d3Eric Laurent 15 // STREAM_TTS 2245982013cfc8274ff0bafaba83c676b3a8890cba9Jared Suttles }; 2256d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent /* mStreamVolumeAlias[] indicates for each stream if it uses the volume settings 226a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent * of another stream: This avoids multiplying the volume settings for hidden 227a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent * stream types that follow other stream behavior for volume settings 2286d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent * NOTE: do not create loops in aliases! 2296d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent * Some streams alias to different streams according to device category (phone or tablet) or 2306d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent * use case (in call s off call...).See updateStreamVolumeAlias() for more details 2316d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent * mStreamVolumeAlias contains the default aliases for a voice capable device (phone) and 2326d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent * STREAM_VOLUME_ALIAS_NON_VOICE for a non voice capable device (tablet).*/ 23330c918ce7fbe171944b28fc91b3f22b3d631872dGlenn Kasten private final int[] STREAM_VOLUME_ALIAS = new int[] { 2346d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent AudioSystem.STREAM_VOICE_CALL, // STREAM_VOICE_CALL 2356d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent AudioSystem.STREAM_RING, // STREAM_SYSTEM 2366d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent AudioSystem.STREAM_RING, // STREAM_RING 2376d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent AudioSystem.STREAM_MUSIC, // STREAM_MUSIC 2386d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent AudioSystem.STREAM_ALARM, // STREAM_ALARM 2396d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent AudioSystem.STREAM_RING, // STREAM_NOTIFICATION 2406d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent AudioSystem.STREAM_BLUETOOTH_SCO, // STREAM_BLUETOOTH_SCO 2416d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent AudioSystem.STREAM_RING, // STREAM_SYSTEM_ENFORCED 2426d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent AudioSystem.STREAM_RING, // STREAM_DTMF 2436d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent AudioSystem.STREAM_MUSIC // STREAM_TTS 244a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent }; 2456d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent private final int[] STREAM_VOLUME_ALIAS_NON_VOICE = new int[] { 2466d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent AudioSystem.STREAM_VOICE_CALL, // STREAM_VOICE_CALL 2476d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent AudioSystem.STREAM_MUSIC, // STREAM_SYSTEM 2486d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent AudioSystem.STREAM_RING, // STREAM_RING 2496d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent AudioSystem.STREAM_MUSIC, // STREAM_MUSIC 2506d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent AudioSystem.STREAM_ALARM, // STREAM_ALARM 2516d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent AudioSystem.STREAM_RING, // STREAM_NOTIFICATION 2526d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent AudioSystem.STREAM_BLUETOOTH_SCO, // STREAM_BLUETOOTH_SCO 2536d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent AudioSystem.STREAM_MUSIC, // STREAM_SYSTEM_ENFORCED 2546d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent AudioSystem.STREAM_MUSIC, // STREAM_DTMF 2556d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent AudioSystem.STREAM_MUSIC // STREAM_TTS 2566d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent }; 2576d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent private int[] mStreamVolumeAlias; 258a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent 259bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent // stream names used by dumpStreamStates() 260bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent private final String[] STREAM_NAMES = new String[] { 261bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent "STREAM_VOICE_CALL", 262bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent "STREAM_SYSTEM", 263bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent "STREAM_RING", 264bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent "STREAM_MUSIC", 265bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent "STREAM_ALARM", 266bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent "STREAM_NOTIFICATION", 267bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent "STREAM_BLUETOOTH_SCO", 268bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent "STREAM_SYSTEM_ENFORCED", 269bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent "STREAM_DTMF", 270bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent "STREAM_TTS" 271bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent }; 272bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent 27330c918ce7fbe171944b28fc91b3f22b3d631872dGlenn Kasten private final AudioSystem.ErrorCallback mAudioSystemCallback = new AudioSystem.ErrorCallback() { 2749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void onError(int error) { 2759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project switch (error) { 2769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project case AudioSystem.AUDIO_STATUS_SERVER_DIED: 2779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mMediaServerOk) { 278afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent sendMsg(mAudioHandler, MSG_MEDIA_SERVER_DIED, SENDMSG_NOOP, 0, 0, 2799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project null, 1500); 28089e74ba1419732dd5c7f939e48d4aa7989fd3a51Eric Laurent mMediaServerOk = false; 2819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project break; 2839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project case AudioSystem.AUDIO_STATUS_OK: 2849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (!mMediaServerOk) { 285afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent sendMsg(mAudioHandler, MSG_MEDIA_SERVER_STARTED, SENDMSG_NOOP, 0, 0, 2869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project null, 0); 28789e74ba1419732dd5c7f939e48d4aa7989fd3a51Eric Laurent mMediaServerOk = true; 2889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project break; 2909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project default: 2919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project break; 2929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project }; 2959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 2979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Current ringer mode from one of {@link AudioManager#RINGER_MODE_NORMAL}, 2989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * {@link AudioManager#RINGER_MODE_SILENT}, or 2999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * {@link AudioManager#RINGER_MODE_VIBRATE}. 3009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 301ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten // protected by mSettingsLock 3029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private int mRingerMode; 3039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3049bcf401d13d47416043a704430388abd59aef7cdEric Laurent /** @see System#MODE_RINGER_STREAMS_AFFECTED */ 3059bcf401d13d47416043a704430388abd59aef7cdEric Laurent private int mRingerModeAffectedStreams; 3069bcf401d13d47416043a704430388abd59aef7cdEric Laurent 3075b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent // Streams currently muted by ringer mode 3085b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent private int mRingerModeMutedStreams; 3095b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent 3109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** @see System#MUTE_STREAMS_AFFECTED */ 3119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private int mMuteAffectedStreams; 3129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 314bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent * NOTE: setVibrateSetting(), getVibrateSetting(), shouldVibrate() are deprecated. 315bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent * mVibrateSetting is just maintained during deprecation period but vibration policy is 316bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent * now only controlled by mHasVibrator and mRingerMode 3179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 3189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private int mVibrateSetting; 3199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 320bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent // Is there a vibrator 321bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent private final boolean mHasVibrator; 322bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent 323a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent // Broadcast receiver for device connections intent broadcasts 324a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent private final BroadcastReceiver mReceiver = new AudioServiceBroadcastReceiver(); 325a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent 326e73131a68408a0495ba96a4d5a60799ba293c176Jean-Michel Trivi // Used to alter media button redirection when the phone is ringing. 327e73131a68408a0495ba96a4d5a60799ba293c176Jean-Michel Trivi private boolean mIsRinging = false; 328e73131a68408a0495ba96a4d5a60799ba293c176Jean-Michel Trivi 329c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent // Devices currently connected 33030c918ce7fbe171944b28fc91b3f22b3d631872dGlenn Kasten private final HashMap <Integer, String> mConnectedDevices = new HashMap <Integer, String>(); 331c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent 332c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent // Forced device usage for communications 333c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent private int mForcedUseForComm; 334c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent 3350dc37cce9d564ae43883c8dc8672b9266b881e63Mike Lockwood // True if we have master volume support 3360dc37cce9d564ae43883c8dc8672b9266b881e63Mike Lockwood private final boolean mUseMasterVolume; 3370dc37cce9d564ae43883c8dc8672b9266b881e63Mike Lockwood 3389760647dd0ee67e7c20f3e9d661d2006b1df0b54Mike Lockwood private final int[] mMasterVolumeRamp; 3399760647dd0ee67e7c20f3e9d661d2006b1df0b54Mike Lockwood 3409272b4b4a44fe1f33e3030810618194f817caaecEric Laurent // List of binder death handlers for setMode() client processes. 3419272b4b4a44fe1f33e3030810618194f817caaecEric Laurent // The last process to have called setMode() is at the top of the list. 34230c918ce7fbe171944b28fc91b3f22b3d631872dGlenn Kasten private final ArrayList <SetModeDeathHandler> mSetModeDeathHandlers = new ArrayList <SetModeDeathHandler>(); 343eb14a783be073b5fd6e8c8c9bc87d2d1919f2c9eEric Laurent 3443def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent // List of clients having issued a SCO start request 34530c918ce7fbe171944b28fc91b3f22b3d631872dGlenn Kasten private final ArrayList <ScoClient> mScoClients = new ArrayList <ScoClient>(); 3463def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent 3473def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent // BluetoothHeadset API to control SCO connection 3483def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent private BluetoothHeadset mBluetoothHeadset; 3493def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent 35082aa7f017daaaeb96c13e6e3491d5037ab471085Jaikumar Ganesh // Bluetooth headset device 35182aa7f017daaaeb96c13e6e3491d5037ab471085Jaikumar Ganesh private BluetoothDevice mBluetoothHeadsetDevice; 3523def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent 35362ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent // Indicate if SCO audio connection is currently active and if the initiator is 35462ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent // audio service (internal) or bluetooth headset (external) 35562ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent private int mScoAudioState; 35662ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent // SCO audio state is not active 35762ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent private static final int SCO_STATE_INACTIVE = 0; 358dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent // SCO audio activation request waiting for headset service to connect 359dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent private static final int SCO_STATE_ACTIVATE_REQ = 1; 36062ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent // SCO audio state is active or starting due to a local request to start a virtual call 361dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent private static final int SCO_STATE_ACTIVE_INTERNAL = 3; 362dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent // SCO audio deactivation request waiting for headset service to connect 363dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent private static final int SCO_STATE_DEACTIVATE_REQ = 5; 364dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent 36562ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent // SCO audio state is active due to an action in BT handsfree (either voice recognition or 36662ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent // in call audio) 36762ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent private static final int SCO_STATE_ACTIVE_EXTERNAL = 2; 368dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent // Deactivation request for all SCO connections (initiated by audio mode change) 369dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent // waiting for headset service to connect 370dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent private static final int SCO_STATE_DEACTIVATE_EXT_REQ = 4; 371dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent 372dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent // Current connection state indicated by bluetooth headset 373dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent private int mScoConnectionState; 37462ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent 375a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent // true if boot sequence has been completed 376a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent private boolean mBootCompleted; 377a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent // listener for SoundPool sample load completion indication 378a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent private SoundPoolCallback mSoundPoolCallBack; 379a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent // thread for SoundPool listener 380a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent private SoundPoolListenerThread mSoundPoolListenerThread; 381a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent // message looper for SoundPool listener 382a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent private Looper mSoundPoolLooper = null; 383c55b393efd462490cd5e27fc373bceafdd25662eJean-Michel Trivi // volume applied to sound played with playSoundEffect() 384c55b393efd462490cd5e27fc373bceafdd25662eJean-Michel Trivi private static int SOUND_EFFECT_VOLUME_DB; 38525101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent // getActiveStreamType() will return STREAM_NOTIFICATION during this period after a notification 38625101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent // stopped 38725101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent private static final int NOTIFICATION_VOLUME_DELAY_MS = 5000; 38825101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent // previous volume adjustment direction received by checkForRingerModeChange() 38925101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent private int mPrevVolDirection = AudioManager.ADJUST_SAME; 3906243edd818b84adfbe712d5d233d6414b33653acAmith Yamasani // Keyguard manager proxy 3916243edd818b84adfbe712d5d233d6414b33653acAmith Yamasani private KeyguardManager mKeyguardManager; 39245c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent // mVolumeControlStream is set by VolumePanel to temporarily force the stream type which volume 39345c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent // is controlled by Vol keys. 39445c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent private int mVolumeControlStream = -1; 39545c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent private final Object mForceControlStreamLock = new Object(); 39645c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent // VolumePanel is currently the only client of forceVolumeControlStream() and runs in system 39745c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent // server process so in theory it is not necessary to monitor the client death. 39845c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent // However it is good to be ready for future evolutions. 39945c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent private ForceControlStreamClient mForceControlStreamClient = null; 400098d580cc2bb6c0891c756a4e5230c6c6b0d2376Jeff Sharkey // Used to play ringtones outside system_server 401098d580cc2bb6c0891c756a4e5230c6c6b0d2376Jeff Sharkey private volatile IRingtonePlayer mRingtonePlayer; 4029bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent 403f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi private int mDeviceOrientation = Configuration.ORIENTATION_UNDEFINED; 404f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi 4057847211fb4699bf6018e29d214a918ed6657319bEric Laurent // Request to override default use of A2DP for media. 4067847211fb4699bf6018e29d214a918ed6657319bEric Laurent private boolean mBluetoothA2dpEnabled; 4077847211fb4699bf6018e29d214a918ed6657319bEric Laurent private final Object mBluetoothA2dpEnabledLock = new Object(); 4087847211fb4699bf6018e29d214a918ed6657319bEric Laurent 409632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn // Monitoring of audio routes. Protected by mCurAudioRoutes. 410632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn final AudioRoutesInfo mCurAudioRoutes = new AudioRoutesInfo(); 411632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn final RemoteCallbackList<IAudioRoutesObserver> mRoutesObservers 412632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn = new RemoteCallbackList<IAudioRoutesObserver>(); 413632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn 4143114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi /** 4153114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi * A fake stream type to match the notion of remote media playback 4163114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi */ 4173114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi public final static int STREAM_REMOTE_MUSIC = -200; 4183114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi 4199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /////////////////////////////////////////////////////////////////////////// 4209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Construction 4219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /////////////////////////////////////////////////////////////////////////// 4229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** @hide */ 4249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public AudioService(Context context) { 4259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mContext = context; 4269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mContentResolver = context.getContentResolver(); 427c7fcba4b7bd3d78e7cfe975a3f8e4dde2f6738b7Joe Onorato mVoiceCapable = mContext.getResources().getBoolean( 428c7fcba4b7bd3d78e7cfe975a3f8e4dde2f6738b7Joe Onorato com.android.internal.R.bool.config_voice_capable); 4295982013cfc8274ff0bafaba83c676b3a8890cba9Jared Suttles 430c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE); 4312d8dab5a549b25b6f36df4614d7c0166d4d099e2Jean-Michel Trivi mMediaEventWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "handleMediaEvent"); 432c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi 433bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent Vibrator vibrator = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE); 434bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent mHasVibrator = vibrator == null ? false : vibrator.hasVibrator(); 435bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent 4365982013cfc8274ff0bafaba83c676b3a8890cba9Jared Suttles // Intialized volume 4375982013cfc8274ff0bafaba83c676b3a8890cba9Jared Suttles MAX_STREAM_VOLUME[AudioSystem.STREAM_VOICE_CALL] = SystemProperties.getInt( 4385982013cfc8274ff0bafaba83c676b3a8890cba9Jared Suttles "ro.config.vc_call_vol_steps", 4395982013cfc8274ff0bafaba83c676b3a8890cba9Jared Suttles MAX_STREAM_VOLUME[AudioSystem.STREAM_VOICE_CALL]); 4405982013cfc8274ff0bafaba83c676b3a8890cba9Jared Suttles 441c55b393efd462490cd5e27fc373bceafdd25662eJean-Michel Trivi SOUND_EFFECT_VOLUME_DB = context.getResources().getInteger( 442c55b393efd462490cd5e27fc373bceafdd25662eJean-Michel Trivi com.android.internal.R.integer.config_soundEffectVolumeDb); 44325101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent 4449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mVolumePanel = new VolumePanel(context, this); 4456d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent mMode = AudioSystem.MODE_NORMAL; 446c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent mForcedUseForComm = AudioSystem.FORCE_NONE; 4479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project createAudioSystemThread(); 4489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project readPersistedSettings(); 449c1d4166289ce016965d1147f7e8d37862ee347ecEric Laurent mSettingsObserver = new SettingsObserver(); 4506d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent updateStreamVolumeAlias(false /*updateVolumes*/); 451a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent createStreamStates(); 4529f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent 4539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mMediaServerOk = true; 4543891c4cc918e8062abb97c542a8625d556dccc59Eric Laurent 4553891c4cc918e8062abb97c542a8625d556dccc59Eric Laurent // Call setRingerModeInt() to apply correct mute 4563891c4cc918e8062abb97c542a8625d556dccc59Eric Laurent // state on streams affected by ringer mode. 4573891c4cc918e8062abb97c542a8625d556dccc59Eric Laurent mRingerModeMutedStreams = 0; 4583891c4cc918e8062abb97c542a8625d556dccc59Eric Laurent setRingerModeInt(getRingerMode(), false); 4593891c4cc918e8062abb97c542a8625d556dccc59Eric Laurent 4609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project AudioSystem.setErrorCallback(mAudioSystemCallback); 461a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent 462a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent // Register for device connection intent broadcasts. 463a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent IntentFilter intentFilter = 464b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent new IntentFilter(BluetoothHeadset.ACTION_AUDIO_STATE_CHANGED); 46582aa7f017daaaeb96c13e6e3491d5037ab471085Jaikumar Ganesh intentFilter.addAction(BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED); 46682aa7f017daaaeb96c13e6e3491d5037ab471085Jaikumar Ganesh intentFilter.addAction(Intent.ACTION_DOCK_EVENT); 46759f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent intentFilter.addAction(Intent.ACTION_USB_AUDIO_ACCESSORY_PLUG); 46859f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent intentFilter.addAction(Intent.ACTION_USB_AUDIO_DEVICE_PLUG); 46962ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent intentFilter.addAction(Intent.ACTION_BOOT_COMPLETED); 470950e8cb40a6d826af4cc2eef9d3908c1b70486e6Eric Laurent intentFilter.addAction(Intent.ACTION_SCREEN_ON); 471950e8cb40a6d826af4cc2eef9d3908c1b70486e6Eric Laurent intentFilter.addAction(Intent.ACTION_SCREEN_OFF); 472f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi 473f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi // Register a configuration change listener only if requested by system properties 474f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi // to monitor orientation changes (off by default) 475f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi if (SystemProperties.getBoolean("ro.audio.monitorOrientation", false)) { 476f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi Log.v(TAG, "monitoring device orientation"); 477f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi intentFilter.addAction(Intent.ACTION_CONFIGURATION_CHANGED); 478f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi // initialize orientation in AudioSystem 479f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi setOrientationForAudioSystem(); 480f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi } 481f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi 482a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent context.registerReceiver(mReceiver, intentFilter); 4835982013cfc8274ff0bafaba83c676b3a8890cba9Jared Suttles 484d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi // Register for package removal intent broadcasts for media button receiver persistence 485d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi IntentFilter pkgFilter = new IntentFilter(); 486d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi pkgFilter.addAction(Intent.ACTION_PACKAGE_REMOVED); 487d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi pkgFilter.addDataScheme("package"); 488d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi context.registerReceiver(mReceiver, pkgFilter); 489d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi 490b4bccb6d8df16a2c5235cead187156bc721cf074Jean-Michel Trivi // Register for phone state monitoring 491b4bccb6d8df16a2c5235cead187156bc721cf074Jean-Michel Trivi TelephonyManager tmgr = (TelephonyManager) 492b4bccb6d8df16a2c5235cead187156bc721cf074Jean-Michel Trivi context.getSystemService(Context.TELEPHONY_SERVICE); 493b4bccb6d8df16a2c5235cead187156bc721cf074Jean-Michel Trivi tmgr.listen(mPhoneStateListener, PhoneStateListener.LISTEN_CALL_STATE); 4948517e46f3d3c2ce11de09aa849a8533ffc1a2026Mike Lockwood 4950dc37cce9d564ae43883c8dc8672b9266b881e63Mike Lockwood mUseMasterVolume = context.getResources().getBoolean( 4960dc37cce9d564ae43883c8dc8672b9266b881e63Mike Lockwood com.android.internal.R.bool.config_useMasterVolume); 4979063154a793b0ab38b3c5992cbaed046427b4a82Mike Lockwood restoreMasterVolume(); 4989760647dd0ee67e7c20f3e9d661d2006b1df0b54Mike Lockwood 4999760647dd0ee67e7c20f3e9d661d2006b1df0b54Mike Lockwood mMasterVolumeRamp = context.getResources().getIntArray( 5009760647dd0ee67e7c20f3e9d661d2006b1df0b54Mike Lockwood com.android.internal.R.array.config_masterVolumeRamp); 5017847211fb4699bf6018e29d214a918ed6657319bEric Laurent 5023114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi mMainRemote = new RemotePlaybackState(-1, MAX_STREAM_VOLUME[AudioManager.STREAM_MUSIC], 5033114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi MAX_STREAM_VOLUME[AudioManager.STREAM_MUSIC]); 5043114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi mHasRemotePlayback = false; 5053114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi mMainRemoteIsActive = false; 5063114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi postReevaluateRemote(); 5079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private void createAudioSystemThread() { 5109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mAudioSystemThread = new AudioSystemThread(); 5119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mAudioSystemThread.start(); 5129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project waitForAudioHandlerCreation(); 5139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** Waits for the volume handler to be created by the other thread. */ 5169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private void waitForAudioHandlerCreation() { 5179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project synchronized(this) { 5189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project while (mAudioHandler == null) { 5199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project try { 5209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Wait for mAudioHandler to be set by the other thread 5219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project wait(); 5229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } catch (InterruptedException e) { 5239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Log.e(TAG, "Interrupted while waiting on volume handler."); 5249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 529244820185269991186d07068b92985624cede4a5Eric Laurent private void checkAllAliasStreamVolumes() { 530244820185269991186d07068b92985624cede4a5Eric Laurent int numStreamTypes = AudioSystem.getNumStreamTypes(); 531244820185269991186d07068b92985624cede4a5Eric Laurent for (int streamType = 0; streamType < numStreamTypes; streamType++) { 532244820185269991186d07068b92985624cede4a5Eric Laurent if (streamType != mStreamVolumeAlias[streamType]) { 533244820185269991186d07068b92985624cede4a5Eric Laurent mStreamStates[streamType]. 534244820185269991186d07068b92985624cede4a5Eric Laurent setAllIndexes(mStreamStates[mStreamVolumeAlias[streamType]], 535244820185269991186d07068b92985624cede4a5Eric Laurent false /*lastAudible*/); 536244820185269991186d07068b92985624cede4a5Eric Laurent mStreamStates[streamType]. 537244820185269991186d07068b92985624cede4a5Eric Laurent setAllIndexes(mStreamStates[mStreamVolumeAlias[streamType]], 538244820185269991186d07068b92985624cede4a5Eric Laurent true /*lastAudible*/); 539244820185269991186d07068b92985624cede4a5Eric Laurent } 540244820185269991186d07068b92985624cede4a5Eric Laurent // apply stream volume 541244820185269991186d07068b92985624cede4a5Eric Laurent if (mStreamStates[streamType].muteCount() == 0) { 542244820185269991186d07068b92985624cede4a5Eric Laurent mStreamStates[streamType].applyAllVolumes(); 543244820185269991186d07068b92985624cede4a5Eric Laurent } 544244820185269991186d07068b92985624cede4a5Eric Laurent } 545244820185269991186d07068b92985624cede4a5Eric Laurent } 546244820185269991186d07068b92985624cede4a5Eric Laurent 5479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private void createStreamStates() { 5489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int numStreamTypes = AudioSystem.getNumStreamTypes(); 5499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project VolumeStreamState[] streams = mStreamStates = new VolumeStreamState[numStreamTypes]; 5509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (int i = 0; i < numStreamTypes; i++) { 5526d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent streams[i] = new VolumeStreamState(System.VOLUME_SETTINGS[mStreamVolumeAlias[i]], i); 5539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 555244820185269991186d07068b92985624cede4a5Eric Laurent checkAllAliasStreamVolumes(); 5569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 558bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent private void dumpStreamStates(PrintWriter pw) { 559bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent pw.println("\nStream volumes (device: index)"); 560bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent int numStreamTypes = AudioSystem.getNumStreamTypes(); 561bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent for (int i = 0; i < numStreamTypes; i++) { 562bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent pw.println("- "+STREAM_NAMES[i]+":"); 563bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent mStreamStates[i].dump(pw); 564bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent pw.println(""); 565bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent } 566bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent } 567bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent 5686d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent 5696d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent private void updateStreamVolumeAlias(boolean updateVolumes) { 5706d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent int dtmfStreamAlias; 5716d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent if (mVoiceCapable) { 5726d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent mStreamVolumeAlias = STREAM_VOLUME_ALIAS; 5736d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent dtmfStreamAlias = AudioSystem.STREAM_RING; 5746d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent } else { 5756d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent mStreamVolumeAlias = STREAM_VOLUME_ALIAS_NON_VOICE; 5766d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent dtmfStreamAlias = AudioSystem.STREAM_MUSIC; 5776d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent } 5786d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent if (isInCommunication()) { 5796d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent dtmfStreamAlias = AudioSystem.STREAM_VOICE_CALL; 5806d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent } 5816d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent mStreamVolumeAlias[AudioSystem.STREAM_DTMF] = dtmfStreamAlias; 5826d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent if (updateVolumes) { 5836d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent mStreamStates[AudioSystem.STREAM_DTMF].setAllIndexes(mStreamStates[dtmfStreamAlias], 5846d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent false /*lastAudible*/); 5856d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent mStreamStates[AudioSystem.STREAM_DTMF].setAllIndexes(mStreamStates[dtmfStreamAlias], 5866d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent true /*lastAudible*/); 5876d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent sendMsg(mAudioHandler, 5886d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent MSG_SET_ALL_VOLUMES, 5896d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent SENDMSG_QUEUE, 5906d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent 0, 5916d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent 0, 5926d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent mStreamStates[AudioSystem.STREAM_DTMF], 0); 5936d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent } 5946d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent } 5956d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent 5969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private void readPersistedSettings() { 5979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final ContentResolver cr = mContentResolver; 5989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 599bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent int ringerModeFromSettings = 600bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent System.getInt(cr, System.MODE_RINGER, AudioManager.RINGER_MODE_NORMAL); 601bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent int ringerMode = ringerModeFromSettings; 60272668b2c040b581b298b069f3b5af5ed7f212d89Eric Laurent // sanity check in case the settings are restored from a device with incompatible 60372668b2c040b581b298b069f3b5af5ed7f212d89Eric Laurent // ringer modes 604ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten if (!AudioManager.isValidRingerMode(ringerMode)) { 605ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten ringerMode = AudioManager.RINGER_MODE_NORMAL; 606bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent } 607bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent if ((ringerMode == AudioManager.RINGER_MODE_VIBRATE) && !mHasVibrator) { 608bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent ringerMode = AudioManager.RINGER_MODE_SILENT; 609bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent } 610bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent if (ringerMode != ringerModeFromSettings) { 611ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten System.putInt(cr, System.MODE_RINGER, ringerMode); 612ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten } 613ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten synchronized(mSettingsLock) { 614ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten mRingerMode = ringerMode; 61572668b2c040b581b298b069f3b5af5ed7f212d89Eric Laurent } 6169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 617bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent // System.VIBRATE_ON is not used any more but defaults for mVibrateSetting 618bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent // are still needed while setVibrateSetting() and getVibrateSetting() are being deprecated. 619bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent mVibrateSetting = getValueForVibrateSetting(0, 620bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent AudioManager.VIBRATE_TYPE_NOTIFICATION, 621bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent mHasVibrator ? AudioManager.VIBRATE_SETTING_ONLY_SILENT 622bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent : AudioManager.VIBRATE_SETTING_OFF); 623bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent mVibrateSetting = getValueForVibrateSetting(mVibrateSetting, 624bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent AudioManager.VIBRATE_TYPE_RINGER, 625bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent mHasVibrator ? AudioManager.VIBRATE_SETTING_ONLY_SILENT 626bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent : AudioManager.VIBRATE_SETTING_OFF); 6279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 628c1d4166289ce016965d1147f7e8d37862ee347ecEric Laurent // make sure settings for ringer mode are consistent with device type: non voice capable 629c1d4166289ce016965d1147f7e8d37862ee347ecEric Laurent // devices (tablets) include media stream in silent mode whereas phones don't. 6309bcf401d13d47416043a704430388abd59aef7cdEric Laurent mRingerModeAffectedStreams = Settings.System.getInt(cr, 6319bcf401d13d47416043a704430388abd59aef7cdEric Laurent Settings.System.MODE_RINGER_STREAMS_AFFECTED, 632a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent ((1 << AudioSystem.STREAM_RING)|(1 << AudioSystem.STREAM_NOTIFICATION)| 633c1d4166289ce016965d1147f7e8d37862ee347ecEric Laurent (1 << AudioSystem.STREAM_SYSTEM)|(1 << AudioSystem.STREAM_SYSTEM_ENFORCED))); 634c1d4166289ce016965d1147f7e8d37862ee347ecEric Laurent if (mVoiceCapable) { 635c1d4166289ce016965d1147f7e8d37862ee347ecEric Laurent mRingerModeAffectedStreams &= ~(1 << AudioSystem.STREAM_MUSIC); 636c1d4166289ce016965d1147f7e8d37862ee347ecEric Laurent } else { 637402f7f29634a9f68e7929be828a927a3e2f5efe9Eric Laurent mRingerModeAffectedStreams |= (1 << AudioSystem.STREAM_MUSIC); 638402f7f29634a9f68e7929be828a927a3e2f5efe9Eric Laurent } 639c1d4166289ce016965d1147f7e8d37862ee347ecEric Laurent Settings.System.putInt(cr, 640c1d4166289ce016965d1147f7e8d37862ee347ecEric Laurent Settings.System.MODE_RINGER_STREAMS_AFFECTED, mRingerModeAffectedStreams); 641c1d4166289ce016965d1147f7e8d37862ee347ecEric Laurent 6429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mMuteAffectedStreams = System.getInt(cr, 6439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project System.MUTE_STREAMS_AFFECTED, 6449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ((1 << AudioSystem.STREAM_MUSIC)|(1 << AudioSystem.STREAM_RING)|(1 << AudioSystem.STREAM_SYSTEM))); 6459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 64657978ed86286a33d5b1a0fd000ca3406ba9d87b3Justin Koh boolean masterMute = System.getInt(cr, System.VOLUME_MASTER_MUTE, 0) == 1; 64757978ed86286a33d5b1a0fd000ca3406ba9d87b3Justin Koh AudioSystem.setMasterMute(masterMute); 64857978ed86286a33d5b1a0fd000ca3406ba9d87b3Justin Koh broadcastMasterMuteStatus(masterMute); 64957978ed86286a33d5b1a0fd000ca3406ba9d87b3Justin Koh 6509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Each stream will read its own persisted settings 6519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Broadcast the sticky intent 653ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten broadcastRingerMode(ringerMode); 6549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Broadcast vibrate settings 6569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project broadcastVibrateSetting(AudioManager.VIBRATE_TYPE_RINGER); 6579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project broadcastVibrateSetting(AudioManager.VIBRATE_TYPE_NOTIFICATION); 658d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi 659d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi // Restore the default media button receiver from the system settings 660d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi restoreMediaButtonReceiver(); 6619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 663a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent private int rescaleIndex(int index, int srcStream, int dstStream) { 664a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent return (index * mStreamStates[dstStream].getMaxIndex() + mStreamStates[srcStream].getMaxIndex() / 2) / mStreamStates[srcStream].getMaxIndex(); 665a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent } 6669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /////////////////////////////////////////////////////////////////////////// 6689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // IPC methods 6699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /////////////////////////////////////////////////////////////////////////// 6709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** @see AudioManager#adjustVolume(int, int) */ 6729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void adjustVolume(int direction, int flags) { 6739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project adjustSuggestedStreamVolume(direction, AudioManager.USE_DEFAULT_STREAM_TYPE, flags); 6749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6763114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi /** @see AudioManager#adjustLocalOrRemoteStreamVolume(int, int) with current assumption 6773114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi * on streamType: fixed to STREAM_MUSIC */ 6783114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi public void adjustLocalOrRemoteStreamVolume(int streamType, int direction) { 6793114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi if (DEBUG_VOL) Log.d(TAG, "adjustLocalOrRemoteStreamVolume(dir="+direction+")"); 6803114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi if (checkUpdateRemoteStateIfActive(AudioSystem.STREAM_MUSIC)) { 6813114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi adjustRemoteVolume(AudioSystem.STREAM_MUSIC, direction, 0); 6823114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi } else if (AudioSystem.isStreamActive(AudioSystem.STREAM_MUSIC, 0)) { 6833114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi adjustStreamVolume(AudioSystem.STREAM_MUSIC, direction, 0); 6843114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi } 6853114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi } 6863114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi 6879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** @see AudioManager#adjustVolume(int, int, int) */ 6889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void adjustSuggestedStreamVolume(int direction, int suggestedStreamType, int flags) { 6893114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi if (DEBUG_VOL) Log.d(TAG, "adjustSuggestedStreamVolume() stream="+suggestedStreamType); 690402f7f29634a9f68e7929be828a927a3e2f5efe9Eric Laurent int streamType; 69145c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent if (mVolumeControlStream != -1) { 69245c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent streamType = mVolumeControlStream; 693402f7f29634a9f68e7929be828a927a3e2f5efe9Eric Laurent } else { 694402f7f29634a9f68e7929be828a927a3e2f5efe9Eric Laurent streamType = getActiveStreamType(suggestedStreamType); 695402f7f29634a9f68e7929be828a927a3e2f5efe9Eric Laurent } 6969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6976243edd818b84adfbe712d5d233d6414b33653acAmith Yamasani // Play sounds on STREAM_RING only and if lock screen is not on. 6983114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi if ((streamType != STREAM_REMOTE_MUSIC) && 6993114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi (flags & AudioManager.FLAG_PLAY_SOUND) != 0 && 7006d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent ((mStreamVolumeAlias[streamType] != AudioSystem.STREAM_RING) 7016243edd818b84adfbe712d5d233d6414b33653acAmith Yamasani || (mKeyguardManager != null && mKeyguardManager.isKeyguardLocked()))) { 7029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project flags &= ~AudioManager.FLAG_PLAY_SOUND; 7039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 7053114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi if (streamType == STREAM_REMOTE_MUSIC) { 7063114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi // don't play sounds for remote 7073114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi flags &= ~AudioManager.FLAG_PLAY_SOUND; 7083114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi //if (DEBUG_VOL) Log.i(TAG, "Need to adjust remote volume: calling adjustRemoteVolume()"); 7093114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi adjustRemoteVolume(AudioSystem.STREAM_MUSIC, direction, flags); 7103114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi } else { 7113114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi adjustStreamVolume(streamType, direction, flags); 7123114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi } 7139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 7159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** @see AudioManager#adjustStreamVolume(int, int, int) */ 7169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void adjustStreamVolume(int streamType, int direction, int flags) { 7173114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi if (DEBUG_VOL) Log.d(TAG, "adjustStreamVolume() stream="+streamType+", dir="+direction); 7183114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi 7199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ensureValidDirection(direction); 7209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ensureValidStreamType(streamType); 7219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 72296a33d1caad2fab0bc28891cfbf553f4b050bf0bEric Laurent // use stream type alias here so that streams with same alias have the same behavior, 72396a33d1caad2fab0bc28891cfbf553f4b050bf0bEric Laurent // including with regard to silent mode control (e.g the use of STREAM_RING below and in 72496a33d1caad2fab0bc28891cfbf553f4b050bf0bEric Laurent // checkForRingerModeChange() in place of STREAM_RING or STREAM_NOTIFICATION) 7256d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent int streamTypeAlias = mStreamVolumeAlias[streamType]; 726b024c30a80684ac08daef3137b7ba0d347fe3ce5Eric Laurent VolumeStreamState streamState = mStreamStates[streamTypeAlias]; 7279bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent 7289bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent final int device = getDeviceForStream(streamTypeAlias); 7299bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent // get last audible index if stream is muted, current index otherwise 730244820185269991186d07068b92985624cede4a5Eric Laurent final int aliasIndex = streamState.getIndex(device, 7319bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent (streamState.muteCount() != 0) /* lastAudible */); 7329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project boolean adjustVolume = true; 7339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 734244820185269991186d07068b92985624cede4a5Eric Laurent // convert one UI step (+/-1) into a number of internal units on the stream alias 735244820185269991186d07068b92985624cede4a5Eric Laurent int step = rescaleIndex(10, streamType, streamTypeAlias); 736244820185269991186d07068b92985624cede4a5Eric Laurent 7379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // If either the client forces allowing ringer modes for this adjustment, 7389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // or the stream type is one that is affected by ringer modes 73925101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent if (((flags & AudioManager.FLAG_ALLOW_RINGER_MODES) != 0) || 740bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent (streamTypeAlias == getMasterStreamType())) { 741ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten int ringerMode = getRingerMode(); 742c696a53d1fe4d61373c5dc64dd057d322da90c8fAmith Yamasani // do not vibrate if already in vibrate mode 743ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten if (ringerMode == AudioManager.RINGER_MODE_VIBRATE) { 744cc11b1b8bb47aa6be23ff5c4caf683ff90074121Eric Laurent flags &= ~AudioManager.FLAG_VIBRATE; 745cc11b1b8bb47aa6be23ff5c4caf683ff90074121Eric Laurent } 7469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Check if the ringer mode changes with this volume adjustment. If 7479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // it does, it will handle adjusting the volume, so we won't below 748244820185269991186d07068b92985624cede4a5Eric Laurent adjustVolume = checkForRingerModeChange(aliasIndex, direction, step); 7498c78752f2bf786ca3e6f45b9dc6955d3b4bba59cEric Laurent if ((streamTypeAlias == getMasterStreamType()) && 7508c78752f2bf786ca3e6f45b9dc6955d3b4bba59cEric Laurent (mRingerMode == AudioManager.RINGER_MODE_SILENT)) { 7518c78752f2bf786ca3e6f45b9dc6955d3b4bba59cEric Laurent streamState.setLastAudibleIndex(0, device); 7528c78752f2bf786ca3e6f45b9dc6955d3b4bba59cEric Laurent } 7539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 7555b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent // If stream is muted, adjust last audible index only 7565b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent int index; 757244820185269991186d07068b92985624cede4a5Eric Laurent final int oldIndex = mStreamStates[streamType].getIndex(device, 758244820185269991186d07068b92985624cede4a5Eric Laurent (mStreamStates[streamType].muteCount() != 0) /* lastAudible */); 759244820185269991186d07068b92985624cede4a5Eric Laurent 7605b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent if (streamState.muteCount() != 0) { 7615b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent if (adjustVolume) { 762244820185269991186d07068b92985624cede4a5Eric Laurent // Post a persist volume msg 763244820185269991186d07068b92985624cede4a5Eric Laurent // no need to persist volume on all streams sharing the same alias 764244820185269991186d07068b92985624cede4a5Eric Laurent streamState.adjustLastAudibleIndex(direction * step, device); 765244820185269991186d07068b92985624cede4a5Eric Laurent sendMsg(mAudioHandler, 766244820185269991186d07068b92985624cede4a5Eric Laurent MSG_PERSIST_VOLUME, 767244820185269991186d07068b92985624cede4a5Eric Laurent SENDMSG_QUEUE, 768244820185269991186d07068b92985624cede4a5Eric Laurent PERSIST_LAST_AUDIBLE, 769244820185269991186d07068b92985624cede4a5Eric Laurent device, 770244820185269991186d07068b92985624cede4a5Eric Laurent streamState, 771244820185269991186d07068b92985624cede4a5Eric Laurent PERSIST_DELAY); 7725b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent } 773244820185269991186d07068b92985624cede4a5Eric Laurent index = mStreamStates[streamType].getIndex(device, true /* lastAudible */); 7745b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent } else { 775244820185269991186d07068b92985624cede4a5Eric Laurent if (adjustVolume && streamState.adjustIndex(direction * step, device)) { 7765b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent // Post message to set system volume (it in turn will post a message 7775b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent // to persist). Do not change volume if stream is muted. 778afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent sendMsg(mAudioHandler, 7799bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent MSG_SET_DEVICE_VOLUME, 78098ad9b9d6fd34aad487933170f50b5519313df61Eric Laurent SENDMSG_QUEUE, 7819bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent device, 782afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent 0, 783afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent streamState, 784afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent 0); 7859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 786244820185269991186d07068b92985624cede4a5Eric Laurent index = mStreamStates[streamType].getIndex(device, false /* lastAudible */); 7879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 78825101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent 78925101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent sendVolumeUpdate(streamType, oldIndex, index, flags); 7909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 792cbdb49dc5e1b993a0bc5c68dbfb9486bfa0cd762Mike Lockwood /** @see AudioManager#adjustMasterVolume(int) */ 7936c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang public void adjustMasterVolume(int steps, int flags) { 7946c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang ensureValidSteps(steps); 7959760647dd0ee67e7c20f3e9d661d2006b1df0b54Mike Lockwood int volume = Math.round(AudioSystem.getMasterVolume() * MAX_MASTER_VOLUME); 7969760647dd0ee67e7c20f3e9d661d2006b1df0b54Mike Lockwood int delta = 0; 7976c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang int numSteps = Math.abs(steps); 7986c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang int direction = steps > 0 ? AudioManager.ADJUST_RAISE : AudioManager.ADJUST_LOWER; 7996c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang for (int i = 0; i < numSteps; ++i) { 8006c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang delta = findVolumeDelta(direction, volume); 8016c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang volume += delta; 802cbdb49dc5e1b993a0bc5c68dbfb9486bfa0cd762Mike Lockwood } 80324b082f87e96c00d5c17d60c735423900be40e70RoboErik 8046c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang //Log.d(TAG, "adjustMasterVolume volume: " + volume + " steps: " + steps); 8056c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang setMasterVolume(volume, flags); 806cbdb49dc5e1b993a0bc5c68dbfb9486bfa0cd762Mike Lockwood } 807cbdb49dc5e1b993a0bc5c68dbfb9486bfa0cd762Mike Lockwood 8089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** @see AudioManager#setStreamVolume(int, int, int) */ 8099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void setStreamVolume(int streamType, int index, int flags) { 8109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ensureValidStreamType(streamType); 8116d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent VolumeStreamState streamState = mStreamStates[mStreamVolumeAlias[streamType]]; 8129ce379aef155e0c21b5d82d8dc713c62792e4f30Eric Laurent 8139bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent final int device = getDeviceForStream(streamType); 8149bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent // get last audible index if stream is muted, current index otherwise 8159bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent final int oldIndex = streamState.getIndex(device, 8169bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent (streamState.muteCount() != 0) /* lastAudible */); 8179ce379aef155e0c21b5d82d8dc713c62792e4f30Eric Laurent 818244820185269991186d07068b92985624cede4a5Eric Laurent index = rescaleIndex(index * 10, streamType, mStreamVolumeAlias[streamType]); 819244820185269991186d07068b92985624cede4a5Eric Laurent 820f740664cd808bebfc35ded46da6002bdc97a1a16Eric Laurent // setting volume on master stream type also controls silent mode 821f740664cd808bebfc35ded46da6002bdc97a1a16Eric Laurent if (((flags & AudioManager.FLAG_ALLOW_RINGER_MODES) != 0) || 822f740664cd808bebfc35ded46da6002bdc97a1a16Eric Laurent (mStreamVolumeAlias[streamType] == getMasterStreamType())) { 823ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten int newRingerMode; 824b024c30a80684ac08daef3137b7ba0d347fe3ce5Eric Laurent if (index == 0) { 825bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent newRingerMode = mHasVibrator ? AudioManager.RINGER_MODE_VIBRATE 826bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent : AudioManager.RINGER_MODE_SILENT; 8276d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent setStreamVolumeInt(mStreamVolumeAlias[streamType], 8289bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent index, 8299bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent device, 8309bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent false, 8319bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent true); 832b024c30a80684ac08daef3137b7ba0d347fe3ce5Eric Laurent } else { 833b024c30a80684ac08daef3137b7ba0d347fe3ce5Eric Laurent newRingerMode = AudioManager.RINGER_MODE_NORMAL; 834b024c30a80684ac08daef3137b7ba0d347fe3ce5Eric Laurent } 835ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten setRingerMode(newRingerMode); 836b024c30a80684ac08daef3137b7ba0d347fe3ce5Eric Laurent } 837b024c30a80684ac08daef3137b7ba0d347fe3ce5Eric Laurent 8386d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent setStreamVolumeInt(mStreamVolumeAlias[streamType], index, device, false, true); 8399bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent // get last audible index if stream is muted, current index otherwise 840244820185269991186d07068b92985624cede4a5Eric Laurent index = mStreamStates[streamType].getIndex(device, 841244820185269991186d07068b92985624cede4a5Eric Laurent (mStreamStates[streamType].muteCount() != 0) /* lastAudible */); 8425b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent 84325101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent sendVolumeUpdate(streamType, oldIndex, index, flags); 8449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 84645c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent /** @see AudioManager#forceVolumeControlStream(int) */ 84745c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent public void forceVolumeControlStream(int streamType, IBinder cb) { 84845c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent synchronized(mForceControlStreamLock) { 84945c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent mVolumeControlStream = streamType; 85045c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent if (mVolumeControlStream == -1) { 85145c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent if (mForceControlStreamClient != null) { 85245c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent mForceControlStreamClient.release(); 85345c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent mForceControlStreamClient = null; 85445c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent } 85545c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent } else { 85645c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent mForceControlStreamClient = new ForceControlStreamClient(cb); 85745c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent } 85845c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent } 85945c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent } 86045c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent 86145c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent private class ForceControlStreamClient implements IBinder.DeathRecipient { 86245c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent private IBinder mCb; // To be notified of client's death 86345c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent 86445c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent ForceControlStreamClient(IBinder cb) { 86545c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent if (cb != null) { 86645c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent try { 86745c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent cb.linkToDeath(this, 0); 86845c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent } catch (RemoteException e) { 86945c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent // Client has died! 87045c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent Log.w(TAG, "ForceControlStreamClient() could not link to "+cb+" binder death"); 87145c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent cb = null; 87245c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent } 87345c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent } 87445c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent mCb = cb; 87545c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent } 87645c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent 87745c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent public void binderDied() { 87845c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent synchronized(mForceControlStreamLock) { 87945c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent Log.w(TAG, "SCO client died"); 88045c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent if (mForceControlStreamClient != this) { 88145c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent Log.w(TAG, "unregistered control stream client died"); 88245c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent } else { 88345c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent mForceControlStreamClient = null; 88445c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent mVolumeControlStream = -1; 88545c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent } 88645c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent } 88745c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent } 88845c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent 88945c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent public void release() { 89045c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent if (mCb != null) { 89145c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent mCb.unlinkToDeath(this, 0); 89245c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent mCb = null; 89345c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent } 89445c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent } 89545c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent } 89645c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent 8976c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang private int findVolumeDelta(int direction, int volume) { 8986c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang int delta = 0; 8996c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang if (direction == AudioManager.ADJUST_RAISE) { 9006c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang if (volume == MAX_MASTER_VOLUME) { 9016c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang return 0; 9026c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang } 9036c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang // This is the default value if we make it to the end 9046c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang delta = mMasterVolumeRamp[1]; 9056c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang // If we're raising the volume move down the ramp array until we 9066c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang // find the volume we're above and use that groups delta. 9076c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang for (int i = mMasterVolumeRamp.length - 1; i > 1; i -= 2) { 9086c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang if (volume >= mMasterVolumeRamp[i - 1]) { 9096c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang delta = mMasterVolumeRamp[i]; 9106c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang break; 9116c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang } 9126c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang } 9136c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang } else if (direction == AudioManager.ADJUST_LOWER){ 9146c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang if (volume == 0) { 9156c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang return 0; 9166c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang } 9176c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang int length = mMasterVolumeRamp.length; 9186c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang // This is the default value if we make it to the end 9196c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang delta = -mMasterVolumeRamp[length - 1]; 9206c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang // If we're lowering the volume move up the ramp array until we 9216c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang // find the volume we're below and use the group below it's delta 9226c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang for (int i = 2; i < length; i += 2) { 9236c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang if (volume <= mMasterVolumeRamp[i]) { 9246c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang delta = -mMasterVolumeRamp[i - 1]; 9256c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang break; 9266c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang } 9276c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang } 9286c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang } 9296c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang return delta; 9306c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang } 9316c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang 93225101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent // UI update and Broadcast Intent 93325101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent private void sendVolumeUpdate(int streamType, int oldIndex, int index, int flags) { 93425101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent if (!mVoiceCapable && (streamType == AudioSystem.STREAM_RING)) { 93525101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent streamType = AudioSystem.STREAM_NOTIFICATION; 93625101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent } 93725101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent 93825101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent mVolumePanel.postVolumeChanged(streamType, flags); 93925101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent 9409ce379aef155e0c21b5d82d8dc713c62792e4f30Eric Laurent oldIndex = (oldIndex + 5) / 10; 9419ce379aef155e0c21b5d82d8dc713c62792e4f30Eric Laurent index = (index + 5) / 10; 9429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Intent intent = new Intent(AudioManager.VOLUME_CHANGED_ACTION); 9439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project intent.putExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, streamType); 9449ce379aef155e0c21b5d82d8dc713c62792e4f30Eric Laurent intent.putExtra(AudioManager.EXTRA_VOLUME_STREAM_VALUE, index); 9459ce379aef155e0c21b5d82d8dc713c62792e4f30Eric Laurent intent.putExtra(AudioManager.EXTRA_PREV_VOLUME_STREAM_VALUE, oldIndex); 9469ce379aef155e0c21b5d82d8dc713c62792e4f30Eric Laurent mContext.sendBroadcast(intent); 9479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 9490dc37cce9d564ae43883c8dc8672b9266b881e63Mike Lockwood // UI update and Broadcast Intent 9500dc37cce9d564ae43883c8dc8672b9266b881e63Mike Lockwood private void sendMasterVolumeUpdate(int flags, int oldVolume, int newVolume) { 9510dc37cce9d564ae43883c8dc8672b9266b881e63Mike Lockwood mVolumePanel.postMasterVolumeChanged(flags); 9520dc37cce9d564ae43883c8dc8672b9266b881e63Mike Lockwood 9530dc37cce9d564ae43883c8dc8672b9266b881e63Mike Lockwood Intent intent = new Intent(AudioManager.MASTER_VOLUME_CHANGED_ACTION); 9540dc37cce9d564ae43883c8dc8672b9266b881e63Mike Lockwood intent.putExtra(AudioManager.EXTRA_PREV_MASTER_VOLUME_VALUE, oldVolume); 9550dc37cce9d564ae43883c8dc8672b9266b881e63Mike Lockwood intent.putExtra(AudioManager.EXTRA_MASTER_VOLUME_VALUE, newVolume); 9560dc37cce9d564ae43883c8dc8672b9266b881e63Mike Lockwood mContext.sendBroadcast(intent); 9570dc37cce9d564ae43883c8dc8672b9266b881e63Mike Lockwood } 9580dc37cce9d564ae43883c8dc8672b9266b881e63Mike Lockwood 9590dc37cce9d564ae43883c8dc8672b9266b881e63Mike Lockwood // UI update and Broadcast Intent 9600dc37cce9d564ae43883c8dc8672b9266b881e63Mike Lockwood private void sendMasterMuteUpdate(boolean muted, int flags) { 9610dc37cce9d564ae43883c8dc8672b9266b881e63Mike Lockwood mVolumePanel.postMasterMuteChanged(flags); 96257978ed86286a33d5b1a0fd000ca3406ba9d87b3Justin Koh broadcastMasterMuteStatus(muted); 96357978ed86286a33d5b1a0fd000ca3406ba9d87b3Justin Koh } 9640dc37cce9d564ae43883c8dc8672b9266b881e63Mike Lockwood 96557978ed86286a33d5b1a0fd000ca3406ba9d87b3Justin Koh private void broadcastMasterMuteStatus(boolean muted) { 9660dc37cce9d564ae43883c8dc8672b9266b881e63Mike Lockwood Intent intent = new Intent(AudioManager.MASTER_MUTE_CHANGED_ACTION); 9670dc37cce9d564ae43883c8dc8672b9266b881e63Mike Lockwood intent.putExtra(AudioManager.EXTRA_MASTER_VOLUME_MUTED, muted); 96857978ed86286a33d5b1a0fd000ca3406ba9d87b3Justin Koh intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT 96957978ed86286a33d5b1a0fd000ca3406ba9d87b3Justin Koh | Intent.FLAG_RECEIVER_REPLACE_PENDING); 9700dc37cce9d564ae43883c8dc8672b9266b881e63Mike Lockwood long origCallerIdentityToken = Binder.clearCallingIdentity(); 9710dc37cce9d564ae43883c8dc8672b9266b881e63Mike Lockwood mContext.sendStickyBroadcast(intent); 9720dc37cce9d564ae43883c8dc8672b9266b881e63Mike Lockwood Binder.restoreCallingIdentity(origCallerIdentityToken); 9730dc37cce9d564ae43883c8dc8672b9266b881e63Mike Lockwood } 9740dc37cce9d564ae43883c8dc8672b9266b881e63Mike Lockwood 9759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 9769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Sets the stream state's index, and posts a message to set system volume. 9779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * This will not call out to the UI. Assumes a valid stream type. 9789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 9799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param streamType Type of the stream 9809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param index Desired volume index of the stream 9819bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent * @param device the device whose volume must be changed 9829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param force If true, set the volume even if the desired volume is same 9839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * as the current volume. 9849bcf401d13d47416043a704430388abd59aef7cdEric Laurent * @param lastAudible If true, stores new index as last audible one 9859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 9869bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent private void setStreamVolumeInt(int streamType, 9879bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent int index, 9889bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent int device, 9899bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent boolean force, 9909bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent boolean lastAudible) { 9919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project VolumeStreamState streamState = mStreamStates[streamType]; 9925b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent 9935b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent // If stream is muted, set last audible index only 9945b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent if (streamState.muteCount() != 0) { 995758dd527f64f1e827adfe09f0141ab213733ca22Eric Laurent // Do not allow last audible index to be 0 996758dd527f64f1e827adfe09f0141ab213733ca22Eric Laurent if (index != 0) { 9979bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent streamState.setLastAudibleIndex(index, device); 998758dd527f64f1e827adfe09f0141ab213733ca22Eric Laurent // Post a persist volume msg 999afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent sendMsg(mAudioHandler, 1000afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent MSG_PERSIST_VOLUME, 100198ad9b9d6fd34aad487933170f50b5519313df61Eric Laurent SENDMSG_QUEUE, 1002afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent PERSIST_LAST_AUDIBLE, 10039bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent device, 1004afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent streamState, 1005afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent PERSIST_DELAY); 1006758dd527f64f1e827adfe09f0141ab213733ca22Eric Laurent } 10075b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent } else { 10089bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent if (streamState.setIndex(index, device, lastAudible) || force) { 10095b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent // Post message to set system volume (it in turn will post a message 10105b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent // to persist). 1011afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent sendMsg(mAudioHandler, 10129bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent MSG_SET_DEVICE_VOLUME, 101398ad9b9d6fd34aad487933170f50b5519313df61Eric Laurent SENDMSG_QUEUE, 10149bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent device, 1015afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent 0, 1016afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent streamState, 1017afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent 0); 10189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 10229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** @see AudioManager#setStreamSolo(int, boolean) */ 10239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void setStreamSolo(int streamType, boolean state, IBinder cb) { 10249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (int stream = 0; stream < mStreamStates.length; stream++) { 10259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (!isStreamAffectedByMute(stream) || stream == streamType) continue; 10269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Bring back last audible volume 10279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mStreamStates[stream].mute(cb, state); 10289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 10319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** @see AudioManager#setStreamMute(int, boolean) */ 10329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void setStreamMute(int streamType, boolean state, IBinder cb) { 10339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (isStreamAffectedByMute(streamType)) { 10349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mStreamStates[streamType].mute(cb, state); 10359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 103825101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent /** get stream mute state. */ 103925101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent public boolean isStreamMute(int streamType) { 104025101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent return (mStreamStates[streamType].muteCount() != 0); 104125101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent } 104225101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent 1043ce952c8e13c535bedde77bcdb94dfcc7508475aaMike Lockwood /** @see AudioManager#setMasterMute(boolean, IBinder) */ 10440273af55cf68d54d26d154b44d105d40fed79701Justin Koh public void setMasterMute(boolean state, int flags, IBinder cb) { 10451ce5b26d707e0086e09af3cd0428f1b441145261Jason Simmons if (state != AudioSystem.getMasterMute()) { 10461ce5b26d707e0086e09af3cd0428f1b441145261Jason Simmons AudioSystem.setMasterMute(state); 104757978ed86286a33d5b1a0fd000ca3406ba9d87b3Justin Koh // Post a persist master volume msg 104875cf9e19a575c28c200c02c0ab6f83bb79f5c50dJustin Koh sendMsg(mAudioHandler, MSG_PERSIST_MASTER_VOLUME_MUTE, SENDMSG_REPLACE, state ? 1 104957978ed86286a33d5b1a0fd000ca3406ba9d87b3Justin Koh : 0, 0, null, PERSIST_DELAY); 10500273af55cf68d54d26d154b44d105d40fed79701Justin Koh sendMasterMuteUpdate(state, flags); 10511ce5b26d707e0086e09af3cd0428f1b441145261Jason Simmons } 1052ce952c8e13c535bedde77bcdb94dfcc7508475aaMike Lockwood } 1053ce952c8e13c535bedde77bcdb94dfcc7508475aaMike Lockwood 1054ce952c8e13c535bedde77bcdb94dfcc7508475aaMike Lockwood /** get master mute state. */ 1055ce952c8e13c535bedde77bcdb94dfcc7508475aaMike Lockwood public boolean isMasterMute() { 10563194ea94348bce8e7ee9f803698d877f46f8279aMike Lockwood return AudioSystem.getMasterMute(); 1057ce952c8e13c535bedde77bcdb94dfcc7508475aaMike Lockwood } 1058ce952c8e13c535bedde77bcdb94dfcc7508475aaMike Lockwood 10599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** @see AudioManager#getStreamVolume(int) */ 10609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public int getStreamVolume(int streamType) { 10619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ensureValidStreamType(streamType); 10629bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent int device = getDeviceForStream(streamType); 10639bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent return (mStreamStates[streamType].getIndex(device, false /* lastAudible */) + 5) / 10; 10649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 10664767690f09ea3447b8c5c32fb28d27650aa18e00Mike Lockwood public int getMasterVolume() { 1067ce952c8e13c535bedde77bcdb94dfcc7508475aaMike Lockwood if (isMasterMute()) return 0; 1068ce952c8e13c535bedde77bcdb94dfcc7508475aaMike Lockwood return getLastAudibleMasterVolume(); 10698dc1dabd254249b7ddb8743e88fdb96580ffc585Mike Lockwood } 10708dc1dabd254249b7ddb8743e88fdb96580ffc585Mike Lockwood 10714767690f09ea3447b8c5c32fb28d27650aa18e00Mike Lockwood public void setMasterVolume(int volume, int flags) { 10729760647dd0ee67e7c20f3e9d661d2006b1df0b54Mike Lockwood if (volume < 0) { 10739760647dd0ee67e7c20f3e9d661d2006b1df0b54Mike Lockwood volume = 0; 10749760647dd0ee67e7c20f3e9d661d2006b1df0b54Mike Lockwood } else if (volume > MAX_MASTER_VOLUME) { 10759760647dd0ee67e7c20f3e9d661d2006b1df0b54Mike Lockwood volume = MAX_MASTER_VOLUME; 10769760647dd0ee67e7c20f3e9d661d2006b1df0b54Mike Lockwood } 10775c55a051ad7d86a464fb91426f1ea3c0250e38b3Mike Lockwood doSetMasterVolume((float)volume / MAX_MASTER_VOLUME, flags); 10785c55a051ad7d86a464fb91426f1ea3c0250e38b3Mike Lockwood } 10795c55a051ad7d86a464fb91426f1ea3c0250e38b3Mike Lockwood 10805c55a051ad7d86a464fb91426f1ea3c0250e38b3Mike Lockwood private void doSetMasterVolume(float volume, int flags) { 10815c55a051ad7d86a464fb91426f1ea3c0250e38b3Mike Lockwood // don't allow changing master volume when muted 10825c55a051ad7d86a464fb91426f1ea3c0250e38b3Mike Lockwood if (!AudioSystem.getMasterMute()) { 10835c55a051ad7d86a464fb91426f1ea3c0250e38b3Mike Lockwood int oldVolume = getMasterVolume(); 10845c55a051ad7d86a464fb91426f1ea3c0250e38b3Mike Lockwood AudioSystem.setMasterVolume(volume); 10855c55a051ad7d86a464fb91426f1ea3c0250e38b3Mike Lockwood 10865c55a051ad7d86a464fb91426f1ea3c0250e38b3Mike Lockwood int newVolume = getMasterVolume(); 10875c55a051ad7d86a464fb91426f1ea3c0250e38b3Mike Lockwood if (newVolume != oldVolume) { 10885c55a051ad7d86a464fb91426f1ea3c0250e38b3Mike Lockwood // Post a persist master volume msg 10895c55a051ad7d86a464fb91426f1ea3c0250e38b3Mike Lockwood sendMsg(mAudioHandler, MSG_PERSIST_MASTER_VOLUME, SENDMSG_REPLACE, 10905c55a051ad7d86a464fb91426f1ea3c0250e38b3Mike Lockwood Math.round(volume * (float)1000.0), 0, null, PERSIST_DELAY); 10915c55a051ad7d86a464fb91426f1ea3c0250e38b3Mike Lockwood } 10923caba517253d1703fc29b50740c4567b932279fbJustin Koh // Send the volume update regardless whether there was a change. 10933caba517253d1703fc29b50740c4567b932279fbJustin Koh sendMasterVolumeUpdate(flags, oldVolume, newVolume); 10945c55a051ad7d86a464fb91426f1ea3c0250e38b3Mike Lockwood } 10958dc1dabd254249b7ddb8743e88fdb96580ffc585Mike Lockwood } 10968dc1dabd254249b7ddb8743e88fdb96580ffc585Mike Lockwood 10979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** @see AudioManager#getStreamMaxVolume(int) */ 10989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public int getStreamMaxVolume(int streamType) { 10999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ensureValidStreamType(streamType); 1100a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent return (mStreamStates[streamType].getMaxIndex() + 5) / 10; 11019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 11029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 11034767690f09ea3447b8c5c32fb28d27650aa18e00Mike Lockwood public int getMasterMaxVolume() { 11044767690f09ea3447b8c5c32fb28d27650aa18e00Mike Lockwood return MAX_MASTER_VOLUME; 11054767690f09ea3447b8c5c32fb28d27650aa18e00Mike Lockwood } 110625101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent 110725101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent /** Get last audible volume before stream was muted. */ 110825101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent public int getLastAudibleStreamVolume(int streamType) { 110925101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent ensureValidStreamType(streamType); 11109bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent int device = getDeviceForStream(streamType); 11119bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent return (mStreamStates[streamType].getIndex(device, true /* lastAudible */) + 5) / 10; 111225101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent } 111325101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent 1114ce952c8e13c535bedde77bcdb94dfcc7508475aaMike Lockwood /** Get last audible master volume before it was muted. */ 1115ce952c8e13c535bedde77bcdb94dfcc7508475aaMike Lockwood public int getLastAudibleMasterVolume() { 1116ce952c8e13c535bedde77bcdb94dfcc7508475aaMike Lockwood return Math.round(AudioSystem.getMasterVolume() * MAX_MASTER_VOLUME); 1117ce952c8e13c535bedde77bcdb94dfcc7508475aaMike Lockwood } 1118ce952c8e13c535bedde77bcdb94dfcc7508475aaMike Lockwood 11196d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent /** @see AudioManager#getMasterStreamType(int) */ 11206d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent public int getMasterStreamType() { 11216d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent if (mVoiceCapable) { 11226d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent return AudioSystem.STREAM_RING; 11236d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent } else { 11246d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent return AudioSystem.STREAM_MUSIC; 11256d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent } 11266d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent } 11276d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent 11289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** @see AudioManager#getRingerMode() */ 11299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public int getRingerMode() { 1130ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten synchronized(mSettingsLock) { 1131ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten return mRingerMode; 1132ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten } 1133ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten } 1134ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten 1135ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten private void ensureValidRingerMode(int ringerMode) { 1136ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten if (!AudioManager.isValidRingerMode(ringerMode)) { 1137ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten throw new IllegalArgumentException("Bad ringer mode " + ringerMode); 1138ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten } 11399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 11409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 11419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** @see AudioManager#setRingerMode(int) */ 11429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void setRingerMode(int ringerMode) { 1143244820185269991186d07068b92985624cede4a5Eric Laurent if ((ringerMode == AudioManager.RINGER_MODE_VIBRATE) && !mHasVibrator) { 1144244820185269991186d07068b92985624cede4a5Eric Laurent ringerMode = AudioManager.RINGER_MODE_SILENT; 1145244820185269991186d07068b92985624cede4a5Eric Laurent } 1146ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten if (ringerMode != getRingerMode()) { 1147ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten setRingerModeInt(ringerMode, true); 1148ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten // Send sticky broadcast 1149ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten broadcastRingerMode(ringerMode); 1150b109615ebebd6f3b9ae789412279f576c3ace46bJason Parekh } 1151b109615ebebd6f3b9ae789412279f576c3ace46bJason Parekh } 11529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 11534050c93601b3c3609b21cc1e18a29b64747e7fa9Eric Laurent private void setRingerModeInt(int ringerMode, boolean persist) { 1154ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten synchronized(mSettingsLock) { 1155ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten mRingerMode = ringerMode; 1156ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten } 1157b109615ebebd6f3b9ae789412279f576c3ace46bJason Parekh 11585b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent // Mute stream if not previously muted by ringer mode and ringer mode 11595b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent // is not RINGER_MODE_NORMAL and stream is affected by ringer mode. 11605b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent // Unmute stream if previously muted by ringer mode and ringer mode 11615b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent // is RINGER_MODE_NORMAL or stream is not affected by ringer mode. 1162b109615ebebd6f3b9ae789412279f576c3ace46bJason Parekh int numStreamTypes = AudioSystem.getNumStreamTypes(); 11635b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) { 11645b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent if (isStreamMutedByRingerMode(streamType)) { 11655b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent if (!isStreamAffectedByRingerMode(streamType) || 1166ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten ringerMode == AudioManager.RINGER_MODE_NORMAL) { 1167b024c30a80684ac08daef3137b7ba0d347fe3ce5Eric Laurent // ring and notifications volume should never be 0 when not silenced 1168b024c30a80684ac08daef3137b7ba0d347fe3ce5Eric Laurent // on voice capable devices 1169b024c30a80684ac08daef3137b7ba0d347fe3ce5Eric Laurent if (mVoiceCapable && 11706d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent mStreamVolumeAlias[streamType] == AudioSystem.STREAM_RING) { 11713172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent synchronized (mStreamStates[streamType]) { 11723172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent Set set = mStreamStates[streamType].mLastAudibleIndex.entrySet(); 11733172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent Iterator i = set.iterator(); 11743172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent while (i.hasNext()) { 11753172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent Map.Entry entry = (Map.Entry)i.next(); 11763172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent if ((Integer)entry.getValue() == 0) { 11773172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent entry.setValue(10); 11783172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent } 11799bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent } 11809bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent } 1181b024c30a80684ac08daef3137b7ba0d347fe3ce5Eric Laurent } 11825b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent mStreamStates[streamType].mute(null, false); 11835b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent mRingerModeMutedStreams &= ~(1 << streamType); 11849bcf401d13d47416043a704430388abd59aef7cdEric Laurent } 11855b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent } else { 11865b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent if (isStreamAffectedByRingerMode(streamType) && 1187ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten ringerMode != AudioManager.RINGER_MODE_NORMAL) { 11885b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent mStreamStates[streamType].mute(null, true); 11895b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent mRingerModeMutedStreams |= (1 << streamType); 11905b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent } 1191b109615ebebd6f3b9ae789412279f576c3ace46bJason Parekh } 11929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1193a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent 1194b109615ebebd6f3b9ae789412279f576c3ace46bJason Parekh // Post a persist ringer mode msg 11954050c93601b3c3609b21cc1e18a29b64747e7fa9Eric Laurent if (persist) { 1196afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent sendMsg(mAudioHandler, MSG_PERSIST_RINGER_MODE, 11974050c93601b3c3609b21cc1e18a29b64747e7fa9Eric Laurent SENDMSG_REPLACE, 0, 0, null, PERSIST_DELAY); 11984050c93601b3c3609b21cc1e18a29b64747e7fa9Eric Laurent } 11999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 12009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 12019063154a793b0ab38b3c5992cbaed046427b4a82Mike Lockwood private void restoreMasterVolume() { 12029063154a793b0ab38b3c5992cbaed046427b4a82Mike Lockwood if (mUseMasterVolume) { 12039063154a793b0ab38b3c5992cbaed046427b4a82Mike Lockwood float volume = Settings.System.getFloat(mContentResolver, 12049063154a793b0ab38b3c5992cbaed046427b4a82Mike Lockwood Settings.System.VOLUME_MASTER, -1.0f); 12059063154a793b0ab38b3c5992cbaed046427b4a82Mike Lockwood if (volume >= 0.0f) { 12069063154a793b0ab38b3c5992cbaed046427b4a82Mike Lockwood AudioSystem.setMasterVolume(volume); 12079063154a793b0ab38b3c5992cbaed046427b4a82Mike Lockwood } 12089063154a793b0ab38b3c5992cbaed046427b4a82Mike Lockwood } 12099063154a793b0ab38b3c5992cbaed046427b4a82Mike Lockwood } 12109063154a793b0ab38b3c5992cbaed046427b4a82Mike Lockwood 12119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** @see AudioManager#shouldVibrate(int) */ 12129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public boolean shouldVibrate(int vibrateType) { 1213bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent if (!mHasVibrator) return false; 12149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 12159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project switch (getVibrateSetting(vibrateType)) { 12169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 12179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project case AudioManager.VIBRATE_SETTING_ON: 1218ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten return getRingerMode() != AudioManager.RINGER_MODE_SILENT; 12199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 12209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project case AudioManager.VIBRATE_SETTING_ONLY_SILENT: 1221ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten return getRingerMode() == AudioManager.RINGER_MODE_VIBRATE; 12229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 12239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project case AudioManager.VIBRATE_SETTING_OFF: 1224bcac496076ef6f439147e7a2be71e8a2b76ddedeDaniel Sandler // return false, even for incoming calls 1225bcac496076ef6f439147e7a2be71e8a2b76ddedeDaniel Sandler return false; 12269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 12279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project default: 12289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return false; 12299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 12309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 12319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 12329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** @see AudioManager#getVibrateSetting(int) */ 12339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public int getVibrateSetting(int vibrateType) { 1234bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent if (!mHasVibrator) return AudioManager.VIBRATE_SETTING_OFF; 12359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return (mVibrateSetting >> (vibrateType * 2)) & 3; 12369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 12379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 12389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** @see AudioManager#setVibrateSetting(int, int) */ 12399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void setVibrateSetting(int vibrateType, int vibrateSetting) { 12409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1241bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent if (!mHasVibrator) return; 1242bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent 12439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mVibrateSetting = getValueForVibrateSetting(mVibrateSetting, vibrateType, vibrateSetting); 12449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 12459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Broadcast change 12469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project broadcastVibrateSetting(vibrateType); 12479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 12489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 12499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 12509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 12519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @see #setVibrateSetting(int, int) 12529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 12539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public static int getValueForVibrateSetting(int existingValue, int vibrateType, 12549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int vibrateSetting) { 12559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 12569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // First clear the existing setting. Each vibrate type has two bits in 12579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // the value. Note '3' is '11' in binary. 12589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project existingValue &= ~(3 << (vibrateType * 2)); 12599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 12609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Set into the old value 12619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project existingValue |= (vibrateSetting & 3) << (vibrateType * 2); 12629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 12639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return existingValue; 12649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 12659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 12669272b4b4a44fe1f33e3030810618194f817caaecEric Laurent private class SetModeDeathHandler implements IBinder.DeathRecipient { 12679272b4b4a44fe1f33e3030810618194f817caaecEric Laurent private IBinder mCb; // To be notified of client's death 1268f1ddd51f9cd2f92b922bc636c307210a8d587c25Marco Nelissen private int mPid; 12699272b4b4a44fe1f33e3030810618194f817caaecEric Laurent private int mMode = AudioSystem.MODE_NORMAL; // Current mode set by this client 12709272b4b4a44fe1f33e3030810618194f817caaecEric Laurent 12719f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent SetModeDeathHandler(IBinder cb, int pid) { 12729272b4b4a44fe1f33e3030810618194f817caaecEric Laurent mCb = cb; 12739f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent mPid = pid; 12749272b4b4a44fe1f33e3030810618194f817caaecEric Laurent } 12759272b4b4a44fe1f33e3030810618194f817caaecEric Laurent 12769272b4b4a44fe1f33e3030810618194f817caaecEric Laurent public void binderDied() { 1277d7454be47f4111c0478a502353e11dea401378bdEric Laurent int newModeOwnerPid = 0; 12789272b4b4a44fe1f33e3030810618194f817caaecEric Laurent synchronized(mSetModeDeathHandlers) { 12799272b4b4a44fe1f33e3030810618194f817caaecEric Laurent Log.w(TAG, "setMode() client died"); 12809272b4b4a44fe1f33e3030810618194f817caaecEric Laurent int index = mSetModeDeathHandlers.indexOf(this); 12819272b4b4a44fe1f33e3030810618194f817caaecEric Laurent if (index < 0) { 12829272b4b4a44fe1f33e3030810618194f817caaecEric Laurent Log.w(TAG, "unregistered setMode() client died"); 12839272b4b4a44fe1f33e3030810618194f817caaecEric Laurent } else { 1284d7454be47f4111c0478a502353e11dea401378bdEric Laurent newModeOwnerPid = setModeInt(AudioSystem.MODE_NORMAL, mCb, mPid); 12859272b4b4a44fe1f33e3030810618194f817caaecEric Laurent } 12869272b4b4a44fe1f33e3030810618194f817caaecEric Laurent } 12879f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent // when entering RINGTONE, IN_CALL or IN_COMMUNICATION mode, clear all 12889f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent // SCO connections not started by the application changing the mode 1289d7454be47f4111c0478a502353e11dea401378bdEric Laurent if (newModeOwnerPid != 0) { 1290d7454be47f4111c0478a502353e11dea401378bdEric Laurent disconnectBluetoothSco(newModeOwnerPid); 12919f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent } 12929272b4b4a44fe1f33e3030810618194f817caaecEric Laurent } 12939272b4b4a44fe1f33e3030810618194f817caaecEric Laurent 1294f1ddd51f9cd2f92b922bc636c307210a8d587c25Marco Nelissen public int getPid() { 1295f1ddd51f9cd2f92b922bc636c307210a8d587c25Marco Nelissen return mPid; 1296f1ddd51f9cd2f92b922bc636c307210a8d587c25Marco Nelissen } 1297f1ddd51f9cd2f92b922bc636c307210a8d587c25Marco Nelissen 12989272b4b4a44fe1f33e3030810618194f817caaecEric Laurent public void setMode(int mode) { 12999272b4b4a44fe1f33e3030810618194f817caaecEric Laurent mMode = mode; 13009272b4b4a44fe1f33e3030810618194f817caaecEric Laurent } 13019272b4b4a44fe1f33e3030810618194f817caaecEric Laurent 13029272b4b4a44fe1f33e3030810618194f817caaecEric Laurent public int getMode() { 13039272b4b4a44fe1f33e3030810618194f817caaecEric Laurent return mMode; 13049272b4b4a44fe1f33e3030810618194f817caaecEric Laurent } 13059272b4b4a44fe1f33e3030810618194f817caaecEric Laurent 13069272b4b4a44fe1f33e3030810618194f817caaecEric Laurent public IBinder getBinder() { 13079272b4b4a44fe1f33e3030810618194f817caaecEric Laurent return mCb; 13089272b4b4a44fe1f33e3030810618194f817caaecEric Laurent } 13099272b4b4a44fe1f33e3030810618194f817caaecEric Laurent } 13109272b4b4a44fe1f33e3030810618194f817caaecEric Laurent 13119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** @see AudioManager#setMode(int) */ 13129272b4b4a44fe1f33e3030810618194f817caaecEric Laurent public void setMode(int mode, IBinder cb) { 13139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (!checkAudioSettingsPermission("setMode()")) { 13149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return; 13159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1316a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent 13178f677d66d9c3ba34c97e69b2bb9e161f129af0eeJean-Michel Trivi if (mode < AudioSystem.MODE_CURRENT || mode >= AudioSystem.NUM_MODES) { 1318a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent return; 1319a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent } 1320a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent 1321d7454be47f4111c0478a502353e11dea401378bdEric Laurent int newModeOwnerPid = 0; 13229f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent synchronized(mSetModeDeathHandlers) { 1323a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent if (mode == AudioSystem.MODE_CURRENT) { 1324a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent mode = mMode; 1325a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent } 1326d7454be47f4111c0478a502353e11dea401378bdEric Laurent newModeOwnerPid = setModeInt(mode, cb, Binder.getCallingPid()); 13279f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent } 13289f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent // when entering RINGTONE, IN_CALL or IN_COMMUNICATION mode, clear all 13299f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent // SCO connections not started by the application changing the mode 1330d7454be47f4111c0478a502353e11dea401378bdEric Laurent if (newModeOwnerPid != 0) { 1331d7454be47f4111c0478a502353e11dea401378bdEric Laurent disconnectBluetoothSco(newModeOwnerPid); 13329f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent } 13339f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent } 13342ade576148fe33c5ff6098d30ccfbcf28df70e8eJean-Michel Trivi 13359f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent // must be called synchronized on mSetModeDeathHandlers 1336d7454be47f4111c0478a502353e11dea401378bdEric Laurent // setModeInt() returns a valid PID if the audio mode was successfully set to 13379f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent // any mode other than NORMAL. 1338d7454be47f4111c0478a502353e11dea401378bdEric Laurent int setModeInt(int mode, IBinder cb, int pid) { 1339d7454be47f4111c0478a502353e11dea401378bdEric Laurent int newModeOwnerPid = 0; 13409f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent if (cb == null) { 13419f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent Log.e(TAG, "setModeInt() called with null binder"); 1342d7454be47f4111c0478a502353e11dea401378bdEric Laurent return newModeOwnerPid; 13439f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent } 13442ade576148fe33c5ff6098d30ccfbcf28df70e8eJean-Michel Trivi 13459f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent SetModeDeathHandler hdlr = null; 13469f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent Iterator iter = mSetModeDeathHandlers.iterator(); 13479f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent while (iter.hasNext()) { 13489f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent SetModeDeathHandler h = (SetModeDeathHandler)iter.next(); 13499f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent if (h.getPid() == pid) { 13509f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent hdlr = h; 13519f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent // Remove from client list so that it is re-inserted at top of list 13529f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent iter.remove(); 13539f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent hdlr.getBinder().unlinkToDeath(hdlr, 0); 13549f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent break; 13559f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent } 13569f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent } 13579f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent int status = AudioSystem.AUDIO_STATUS_OK; 13589f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent do { 13599f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent if (mode == AudioSystem.MODE_NORMAL) { 13609f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent // get new mode from client at top the list if any 13619f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent if (!mSetModeDeathHandlers.isEmpty()) { 13629f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent hdlr = mSetModeDeathHandlers.get(0); 13639f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent cb = hdlr.getBinder(); 13649f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent mode = hdlr.getMode(); 13659f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent } 13669f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent } else { 13679f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent if (hdlr == null) { 13689f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent hdlr = new SetModeDeathHandler(cb, pid); 13699f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent } 13709f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent // Register for client death notification 13719f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent try { 13729f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent cb.linkToDeath(hdlr, 0); 13739f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent } catch (RemoteException e) { 13749f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent // Client has died! 13759f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent Log.w(TAG, "setMode() could not link to "+cb+" binder death"); 13769f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent } 13779272b4b4a44fe1f33e3030810618194f817caaecEric Laurent 13789f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent // Last client to call setMode() is always at top of client list 13799f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent // as required by SetModeDeathHandler.binderDied() 13809f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent mSetModeDeathHandlers.add(0, hdlr); 13819f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent hdlr.setMode(mode); 13829f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent } 13833def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent 13849f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent if (mode != mMode) { 13859f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent status = AudioSystem.setPhoneState(mode); 13869f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent if (status == AudioSystem.AUDIO_STATUS_OK) { 13879f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent mMode = mode; 13889f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent } else { 13899f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent if (hdlr != null) { 13909f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent mSetModeDeathHandlers.remove(hdlr); 13919f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent cb.unlinkToDeath(hdlr, 0); 13923def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent } 13939f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent // force reading new top of mSetModeDeathHandlers stack 13949f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent mode = AudioSystem.MODE_NORMAL; 1395b9c9d260f21b321527c4622a123af9767630d94dEric Laurent } 13969f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent } else { 13979f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent status = AudioSystem.AUDIO_STATUS_OK; 13989f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent } 13999f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent } while (status != AudioSystem.AUDIO_STATUS_OK && !mSetModeDeathHandlers.isEmpty()); 14009f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent 14019f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent if (status == AudioSystem.AUDIO_STATUS_OK) { 14029f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent if (mode != AudioSystem.MODE_NORMAL) { 1403d7454be47f4111c0478a502353e11dea401378bdEric Laurent if (mSetModeDeathHandlers.isEmpty()) { 1404d7454be47f4111c0478a502353e11dea401378bdEric Laurent Log.e(TAG, "setMode() different from MODE_NORMAL with empty mode client stack"); 1405d7454be47f4111c0478a502353e11dea401378bdEric Laurent } else { 1406d7454be47f4111c0478a502353e11dea401378bdEric Laurent newModeOwnerPid = mSetModeDeathHandlers.get(0).getPid(); 1407d7454be47f4111c0478a502353e11dea401378bdEric Laurent } 14089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 14099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int streamType = getActiveStreamType(AudioManager.USE_DEFAULT_STREAM_TYPE); 14103114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi if (streamType == STREAM_REMOTE_MUSIC) { 14113114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi // here handle remote media playback the same way as local playback 14123114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi streamType = AudioManager.STREAM_MUSIC; 14133114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi } 14149bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent int device = getDeviceForStream(streamType); 14156d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent int index = mStreamStates[mStreamVolumeAlias[streamType]].getIndex(device, false); 14166d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent setStreamVolumeInt(mStreamVolumeAlias[streamType], index, device, true, false); 14176d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent 14186d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent updateStreamVolumeAlias(true /*updateVolumes*/); 14199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1420d7454be47f4111c0478a502353e11dea401378bdEric Laurent return newModeOwnerPid; 14219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 14229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 14239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** @see AudioManager#getMode() */ 14249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public int getMode() { 14259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return mMode; 14269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 14279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 14289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** @see AudioManager#playSoundEffect(int) */ 14299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void playSoundEffect(int effectType) { 1430afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent sendMsg(mAudioHandler, MSG_PLAY_SOUND_EFFECT, SENDMSG_NOOP, 1431a2ef57dba9ac77d8eccacd646b2b8a8d99fe9d8bEric Laurent effectType, -1, null, 0); 14329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 14339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 14349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** @see AudioManager#playSoundEffect(int, float) */ 14359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void playSoundEffectVolume(int effectType, float volume) { 1436a2ef57dba9ac77d8eccacd646b2b8a8d99fe9d8bEric Laurent loadSoundEffects(); 1437afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent sendMsg(mAudioHandler, MSG_PLAY_SOUND_EFFECT, SENDMSG_NOOP, 14389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project effectType, (int) (volume * 1000), null, 0); 14399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 14409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 14419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 14429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Loads samples into the soundpool. 14435c17a820f9e46e0756c11795b3e6f89105f2f539Glenn Kasten * This method must be called at first when sound effects are enabled 14449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 14459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public boolean loadSoundEffects() { 1446a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent int status; 1447a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent 14489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project synchronized (mSoundEffectsLock) { 1449a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent if (!mBootCompleted) { 1450a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent Log.w(TAG, "loadSoundEffects() called before boot complete"); 1451a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent return false; 1452a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent } 1453a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent 1454a2ef57dba9ac77d8eccacd646b2b8a8d99fe9d8bEric Laurent if (mSoundPool != null) { 1455a2ef57dba9ac77d8eccacd646b2b8a8d99fe9d8bEric Laurent return true; 1456a2ef57dba9ac77d8eccacd646b2b8a8d99fe9d8bEric Laurent } 14579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mSoundPool = new SoundPool(NUM_SOUNDPOOL_CHANNELS, AudioSystem.STREAM_SYSTEM, 0); 1458a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent 1459a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent try { 1460a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent mSoundPoolCallBack = null; 1461a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent mSoundPoolListenerThread = new SoundPoolListenerThread(); 1462a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent mSoundPoolListenerThread.start(); 1463a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent // Wait for mSoundPoolCallBack to be set by the other thread 1464a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent mSoundEffectsLock.wait(); 1465a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent } catch (InterruptedException e) { 1466a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent Log.w(TAG, "Interrupted while waiting sound pool listener thread."); 1467a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent } 1468a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent 1469a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent if (mSoundPoolCallBack == null) { 1470a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent Log.w(TAG, "loadSoundEffects() could not create SoundPool listener or thread"); 1471a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent if (mSoundPoolLooper != null) { 1472a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent mSoundPoolLooper.quit(); 1473a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent mSoundPoolLooper = null; 1474a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent } 1475a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent mSoundPoolListenerThread = null; 1476a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent mSoundPool.release(); 1477a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent mSoundPool = null; 14789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return false; 14799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 14809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /* 14819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * poolId table: The value -1 in this table indicates that corresponding 14829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * file (same index in SOUND_EFFECT_FILES[] has not been loaded. 14839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Once loaded, the value in poolId is the sample ID and the same 14849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * sample can be reused for another effect using the same file. 14859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 14869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int[] poolId = new int[SOUND_EFFECT_FILES.length]; 14879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (int fileIdx = 0; fileIdx < SOUND_EFFECT_FILES.length; fileIdx++) { 14889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project poolId[fileIdx] = -1; 14899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 14909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /* 14919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Effects whose value in SOUND_EFFECT_FILES_MAP[effect][1] is -1 must be loaded. 14929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * If load succeeds, value in SOUND_EFFECT_FILES_MAP[effect][1] is > 0: 14939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * this indicates we have a valid sample loaded for this effect. 14949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 1495a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent 1496117b7bb5b5a4457711f59bde3dcc83d8f111c524Eric Laurent int lastSample = 0; 14979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (int effect = 0; effect < AudioManager.NUM_SOUND_EFFECTS; effect++) { 14989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Do not load sample if this effect uses the MediaPlayer 14999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (SOUND_EFFECT_FILES_MAP[effect][1] == 0) { 15009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project continue; 15019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 15029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (poolId[SOUND_EFFECT_FILES_MAP[effect][0]] == -1) { 1503a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent String filePath = Environment.getRootDirectory() 1504a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent + SOUND_EFFECTS_PATH 1505a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent + SOUND_EFFECT_FILES[SOUND_EFFECT_FILES_MAP[effect][0]]; 15069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int sampleId = mSoundPool.load(filePath, 0); 15079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (sampleId <= 0) { 15089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Log.w(TAG, "Soundpool could not load file: "+filePath); 1509117b7bb5b5a4457711f59bde3dcc83d8f111c524Eric Laurent } else { 1510117b7bb5b5a4457711f59bde3dcc83d8f111c524Eric Laurent SOUND_EFFECT_FILES_MAP[effect][1] = sampleId; 1511117b7bb5b5a4457711f59bde3dcc83d8f111c524Eric Laurent poolId[SOUND_EFFECT_FILES_MAP[effect][0]] = sampleId; 1512117b7bb5b5a4457711f59bde3dcc83d8f111c524Eric Laurent lastSample = sampleId; 15139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 15149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 15159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project SOUND_EFFECT_FILES_MAP[effect][1] = poolId[SOUND_EFFECT_FILES_MAP[effect][0]]; 15169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 15179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1518a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent // wait for all samples to be loaded 1519117b7bb5b5a4457711f59bde3dcc83d8f111c524Eric Laurent if (lastSample != 0) { 1520117b7bb5b5a4457711f59bde3dcc83d8f111c524Eric Laurent mSoundPoolCallBack.setLastSample(lastSample); 1521117b7bb5b5a4457711f59bde3dcc83d8f111c524Eric Laurent 1522117b7bb5b5a4457711f59bde3dcc83d8f111c524Eric Laurent try { 1523117b7bb5b5a4457711f59bde3dcc83d8f111c524Eric Laurent mSoundEffectsLock.wait(); 1524117b7bb5b5a4457711f59bde3dcc83d8f111c524Eric Laurent status = mSoundPoolCallBack.status(); 1525117b7bb5b5a4457711f59bde3dcc83d8f111c524Eric Laurent } catch (java.lang.InterruptedException e) { 1526117b7bb5b5a4457711f59bde3dcc83d8f111c524Eric Laurent Log.w(TAG, "Interrupted while waiting sound pool callback."); 1527117b7bb5b5a4457711f59bde3dcc83d8f111c524Eric Laurent status = -1; 1528117b7bb5b5a4457711f59bde3dcc83d8f111c524Eric Laurent } 1529117b7bb5b5a4457711f59bde3dcc83d8f111c524Eric Laurent } else { 1530a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent status = -1; 1531a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent } 1532117b7bb5b5a4457711f59bde3dcc83d8f111c524Eric Laurent 1533a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent if (mSoundPoolLooper != null) { 1534a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent mSoundPoolLooper.quit(); 1535a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent mSoundPoolLooper = null; 1536a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent } 1537a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent mSoundPoolListenerThread = null; 1538a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent if (status != 0) { 1539a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent Log.w(TAG, 1540a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent "loadSoundEffects(), Error " 1541117b7bb5b5a4457711f59bde3dcc83d8f111c524Eric Laurent + ((lastSample != 0) ? mSoundPoolCallBack.status() : -1) 1542a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent + " while loading samples"); 1543117b7bb5b5a4457711f59bde3dcc83d8f111c524Eric Laurent for (int effect = 0; effect < AudioManager.NUM_SOUND_EFFECTS; effect++) { 1544117b7bb5b5a4457711f59bde3dcc83d8f111c524Eric Laurent if (SOUND_EFFECT_FILES_MAP[effect][1] > 0) { 1545117b7bb5b5a4457711f59bde3dcc83d8f111c524Eric Laurent SOUND_EFFECT_FILES_MAP[effect][1] = -1; 1546117b7bb5b5a4457711f59bde3dcc83d8f111c524Eric Laurent } 1547117b7bb5b5a4457711f59bde3dcc83d8f111c524Eric Laurent } 1548117b7bb5b5a4457711f59bde3dcc83d8f111c524Eric Laurent 1549a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent mSoundPool.release(); 1550a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent mSoundPool = null; 1551a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent } 15529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1553a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent return (status == 0); 15549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 15559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 15569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 15579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Unloads samples from the sound pool. 15589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * This method can be called to free some memory when 15599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * sound effects are disabled. 15609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 15619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void unloadSoundEffects() { 15629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project synchronized (mSoundEffectsLock) { 15639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mSoundPool == null) { 15649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return; 15659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1566a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent 1567117b7bb5b5a4457711f59bde3dcc83d8f111c524Eric Laurent mAudioHandler.removeMessages(MSG_LOAD_SOUND_EFFECTS); 1568a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent mAudioHandler.removeMessages(MSG_PLAY_SOUND_EFFECT); 1569a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent 15709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int[] poolId = new int[SOUND_EFFECT_FILES.length]; 15719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (int fileIdx = 0; fileIdx < SOUND_EFFECT_FILES.length; fileIdx++) { 15729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project poolId[fileIdx] = 0; 15739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 15749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 15759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (int effect = 0; effect < AudioManager.NUM_SOUND_EFFECTS; effect++) { 15769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (SOUND_EFFECT_FILES_MAP[effect][1] <= 0) { 15779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project continue; 15789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 15799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (poolId[SOUND_EFFECT_FILES_MAP[effect][0]] == 0) { 15809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mSoundPool.unload(SOUND_EFFECT_FILES_MAP[effect][1]); 15819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project SOUND_EFFECT_FILES_MAP[effect][1] = -1; 15829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project poolId[SOUND_EFFECT_FILES_MAP[effect][0]] = -1; 15839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 15849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1585a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent mSoundPool.release(); 15869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mSoundPool = null; 15879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 15889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 15899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1590a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent class SoundPoolListenerThread extends Thread { 1591a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent public SoundPoolListenerThread() { 1592a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent super("SoundPoolListenerThread"); 1593a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent } 1594a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent 1595a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent @Override 1596a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent public void run() { 1597a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent 1598a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent Looper.prepare(); 1599a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent mSoundPoolLooper = Looper.myLooper(); 1600a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent 1601a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent synchronized (mSoundEffectsLock) { 1602a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent if (mSoundPool != null) { 1603a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent mSoundPoolCallBack = new SoundPoolCallback(); 1604a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent mSoundPool.setOnLoadCompleteListener(mSoundPoolCallBack); 1605a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent } 1606a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent mSoundEffectsLock.notify(); 1607a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent } 1608a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent Looper.loop(); 1609a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent } 1610a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent } 1611a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent 1612a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent private final class SoundPoolCallback implements 1613a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent android.media.SoundPool.OnLoadCompleteListener { 1614a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent 1615a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent int mStatus; 1616a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent int mLastSample; 1617a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent 1618a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent public int status() { 1619a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent return mStatus; 1620a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent } 1621a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent 1622a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent public void setLastSample(int sample) { 1623a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent mLastSample = sample; 1624a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent } 1625a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent 1626a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent public void onLoadComplete(SoundPool soundPool, int sampleId, int status) { 1627a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent synchronized (mSoundEffectsLock) { 1628a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent if (status != 0) { 1629a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent mStatus = status; 1630a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent } 1631a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent if (sampleId == mLastSample) { 1632a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent mSoundEffectsLock.notify(); 1633a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent } 1634a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent } 1635a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent } 1636a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent } 1637a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent 16384050c93601b3c3609b21cc1e18a29b64747e7fa9Eric Laurent /** @see AudioManager#reloadAudioSettings() */ 16394050c93601b3c3609b21cc1e18a29b64747e7fa9Eric Laurent public void reloadAudioSettings() { 16404050c93601b3c3609b21cc1e18a29b64747e7fa9Eric Laurent // restore ringer mode, ringer mode affected streams, mute affected streams and vibrate settings 16414050c93601b3c3609b21cc1e18a29b64747e7fa9Eric Laurent readPersistedSettings(); 16424050c93601b3c3609b21cc1e18a29b64747e7fa9Eric Laurent 16434050c93601b3c3609b21cc1e18a29b64747e7fa9Eric Laurent // restore volume settings 16444050c93601b3c3609b21cc1e18a29b64747e7fa9Eric Laurent int numStreamTypes = AudioSystem.getNumStreamTypes(); 16454050c93601b3c3609b21cc1e18a29b64747e7fa9Eric Laurent for (int streamType = 0; streamType < numStreamTypes; streamType++) { 16464050c93601b3c3609b21cc1e18a29b64747e7fa9Eric Laurent VolumeStreamState streamState = mStreamStates[streamType]; 16474050c93601b3c3609b21cc1e18a29b64747e7fa9Eric Laurent 16483172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent synchronized (streamState) { 16493172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent streamState.readSettings(); 1650a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent 16513172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent // unmute stream that was muted but is not affect by mute anymore 16523172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent if (streamState.muteCount() != 0 && !isStreamAffectedByMute(streamType)) { 16533172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent int size = streamState.mDeathHandlers.size(); 16543172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent for (int i = 0; i < size; i++) { 16553172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent streamState.mDeathHandlers.get(i).mMuteCount = 1; 16563172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent streamState.mDeathHandlers.get(i).mute(false); 16573172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent } 16583172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent } 16594050c93601b3c3609b21cc1e18a29b64747e7fa9Eric Laurent } 16604050c93601b3c3609b21cc1e18a29b64747e7fa9Eric Laurent } 16614050c93601b3c3609b21cc1e18a29b64747e7fa9Eric Laurent 1662244820185269991186d07068b92985624cede4a5Eric Laurent checkAllAliasStreamVolumes(); 1663244820185269991186d07068b92985624cede4a5Eric Laurent 16644050c93601b3c3609b21cc1e18a29b64747e7fa9Eric Laurent // apply new ringer mode 16654050c93601b3c3609b21cc1e18a29b64747e7fa9Eric Laurent setRingerModeInt(getRingerMode(), false); 16664050c93601b3c3609b21cc1e18a29b64747e7fa9Eric Laurent } 16674050c93601b3c3609b21cc1e18a29b64747e7fa9Eric Laurent 1668c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent /** @see AudioManager#setSpeakerphoneOn() */ 1669c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent public void setSpeakerphoneOn(boolean on){ 1670dc1d17a1dbfc2ae01c20012133a836b62f5b6930Eric Laurent if (!checkAudioSettingsPermission("setSpeakerphoneOn()")) { 1671dc1d17a1dbfc2ae01c20012133a836b62f5b6930Eric Laurent return; 1672dc1d17a1dbfc2ae01c20012133a836b62f5b6930Eric Laurent } 1673fa640154f1f42121d81242b2f1a10f03e52f0014Eric Laurent mForcedUseForComm = on ? AudioSystem.FORCE_SPEAKER : AudioSystem.FORCE_NONE; 1674fa640154f1f42121d81242b2f1a10f03e52f0014Eric Laurent 1675afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent sendMsg(mAudioHandler, MSG_SET_FORCE_USE, SENDMSG_QUEUE, 1676fa640154f1f42121d81242b2f1a10f03e52f0014Eric Laurent AudioSystem.FOR_COMMUNICATION, mForcedUseForComm, null, 0); 1677c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent } 1678c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent 1679c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent /** @see AudioManager#isSpeakerphoneOn() */ 1680c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent public boolean isSpeakerphoneOn() { 1681fa640154f1f42121d81242b2f1a10f03e52f0014Eric Laurent return (mForcedUseForComm == AudioSystem.FORCE_SPEAKER); 1682c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent } 1683c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent 1684c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent /** @see AudioManager#setBluetoothScoOn() */ 1685c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent public void setBluetoothScoOn(boolean on){ 1686dc1d17a1dbfc2ae01c20012133a836b62f5b6930Eric Laurent if (!checkAudioSettingsPermission("setBluetoothScoOn()")) { 1687dc1d17a1dbfc2ae01c20012133a836b62f5b6930Eric Laurent return; 1688dc1d17a1dbfc2ae01c20012133a836b62f5b6930Eric Laurent } 1689fa640154f1f42121d81242b2f1a10f03e52f0014Eric Laurent mForcedUseForComm = on ? AudioSystem.FORCE_BT_SCO : AudioSystem.FORCE_NONE; 1690fa640154f1f42121d81242b2f1a10f03e52f0014Eric Laurent 1691afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent sendMsg(mAudioHandler, MSG_SET_FORCE_USE, SENDMSG_QUEUE, 1692fa640154f1f42121d81242b2f1a10f03e52f0014Eric Laurent AudioSystem.FOR_COMMUNICATION, mForcedUseForComm, null, 0); 1693afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent sendMsg(mAudioHandler, MSG_SET_FORCE_USE, SENDMSG_QUEUE, 1694fa640154f1f42121d81242b2f1a10f03e52f0014Eric Laurent AudioSystem.FOR_RECORD, mForcedUseForComm, null, 0); 1695c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent } 1696c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent 1697c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent /** @see AudioManager#isBluetoothScoOn() */ 1698c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent public boolean isBluetoothScoOn() { 1699fa640154f1f42121d81242b2f1a10f03e52f0014Eric Laurent return (mForcedUseForComm == AudioSystem.FORCE_BT_SCO); 1700c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent } 1701c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent 17027847211fb4699bf6018e29d214a918ed6657319bEric Laurent /** @see AudioManager#setBluetoothA2dpOn() */ 17037847211fb4699bf6018e29d214a918ed6657319bEric Laurent public void setBluetoothA2dpOn(boolean on) { 17047847211fb4699bf6018e29d214a918ed6657319bEric Laurent setBluetoothA2dpOnInt(on); 17057847211fb4699bf6018e29d214a918ed6657319bEric Laurent } 17067847211fb4699bf6018e29d214a918ed6657319bEric Laurent 17077847211fb4699bf6018e29d214a918ed6657319bEric Laurent /** @see AudioManager#isBluetoothA2dpOn() */ 17087847211fb4699bf6018e29d214a918ed6657319bEric Laurent public boolean isBluetoothA2dpOn() { 17097847211fb4699bf6018e29d214a918ed6657319bEric Laurent synchronized (mBluetoothA2dpEnabledLock) { 17107847211fb4699bf6018e29d214a918ed6657319bEric Laurent return mBluetoothA2dpEnabled; 17117847211fb4699bf6018e29d214a918ed6657319bEric Laurent } 17127847211fb4699bf6018e29d214a918ed6657319bEric Laurent } 17137847211fb4699bf6018e29d214a918ed6657319bEric Laurent 17143def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent /** @see AudioManager#startBluetoothSco() */ 17153def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent public void startBluetoothSco(IBinder cb){ 1716dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent if (!checkAudioSettingsPermission("startBluetoothSco()") || 1717dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent !mBootCompleted) { 17183def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent return; 17193def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent } 1720854938a72d968c1bc0de4e2b0ea87777cfebc045Eric Laurent ScoClient client = getScoClient(cb, true); 17213def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent client.incCount(); 17223def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent } 17233def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent 17243def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent /** @see AudioManager#stopBluetoothSco() */ 17253def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent public void stopBluetoothSco(IBinder cb){ 1726dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent if (!checkAudioSettingsPermission("stopBluetoothSco()") || 1727dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent !mBootCompleted) { 17283def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent return; 17293def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent } 1730854938a72d968c1bc0de4e2b0ea87777cfebc045Eric Laurent ScoClient client = getScoClient(cb, false); 1731854938a72d968c1bc0de4e2b0ea87777cfebc045Eric Laurent if (client != null) { 1732854938a72d968c1bc0de4e2b0ea87777cfebc045Eric Laurent client.decCount(); 1733854938a72d968c1bc0de4e2b0ea87777cfebc045Eric Laurent } 17343def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent } 17353def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent 17367847211fb4699bf6018e29d214a918ed6657319bEric Laurent 17373def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent private class ScoClient implements IBinder.DeathRecipient { 17383def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent private IBinder mCb; // To be notified of client's death 1739f1ddd51f9cd2f92b922bc636c307210a8d587c25Marco Nelissen private int mCreatorPid; 17403def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent private int mStartcount; // number of SCO connections started by this client 17413def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent 17423def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent ScoClient(IBinder cb) { 17433def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent mCb = cb; 1744f1ddd51f9cd2f92b922bc636c307210a8d587c25Marco Nelissen mCreatorPid = Binder.getCallingPid(); 17453def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent mStartcount = 0; 17463def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent } 17473def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent 17483def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent public void binderDied() { 17493def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent synchronized(mScoClients) { 17503def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent Log.w(TAG, "SCO client died"); 17513def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent int index = mScoClients.indexOf(this); 17523def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent if (index < 0) { 17533def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent Log.w(TAG, "unregistered SCO client died"); 17543def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent } else { 17553def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent clearCount(true); 17563def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent mScoClients.remove(this); 17573def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent } 17583def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent } 17593def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent } 17603def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent 17613def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent public void incCount() { 17623def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent synchronized(mScoClients) { 176382aa7f017daaaeb96c13e6e3491d5037ab471085Jaikumar Ganesh requestScoState(BluetoothHeadset.STATE_AUDIO_CONNECTED); 17643def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent if (mStartcount == 0) { 17653def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent try { 17663def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent mCb.linkToDeath(this, 0); 17673def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent } catch (RemoteException e) { 17683def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent // client has already died! 17693def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent Log.w(TAG, "ScoClient incCount() could not link to "+mCb+" binder death"); 17703def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent } 17713def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent } 17723def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent mStartcount++; 17733def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent } 17743def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent } 17753def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent 17763def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent public void decCount() { 17773def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent synchronized(mScoClients) { 17783def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent if (mStartcount == 0) { 17793def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent Log.w(TAG, "ScoClient.decCount() already 0"); 17803def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent } else { 17813def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent mStartcount--; 17823def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent if (mStartcount == 0) { 1783e2dd8c4592762414c2c27e4589be7edc91a5ecaeEric Laurent try { 1784e2dd8c4592762414c2c27e4589be7edc91a5ecaeEric Laurent mCb.unlinkToDeath(this, 0); 1785e2dd8c4592762414c2c27e4589be7edc91a5ecaeEric Laurent } catch (NoSuchElementException e) { 1786e2dd8c4592762414c2c27e4589be7edc91a5ecaeEric Laurent Log.w(TAG, "decCount() going to 0 but not registered to binder"); 1787e2dd8c4592762414c2c27e4589be7edc91a5ecaeEric Laurent } 17883def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent } 178982aa7f017daaaeb96c13e6e3491d5037ab471085Jaikumar Ganesh requestScoState(BluetoothHeadset.STATE_AUDIO_DISCONNECTED); 17903def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent } 17913def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent } 17923def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent } 17933def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent 17943def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent public void clearCount(boolean stopSco) { 17953def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent synchronized(mScoClients) { 1796e2dd8c4592762414c2c27e4589be7edc91a5ecaeEric Laurent if (mStartcount != 0) { 1797e2dd8c4592762414c2c27e4589be7edc91a5ecaeEric Laurent try { 1798e2dd8c4592762414c2c27e4589be7edc91a5ecaeEric Laurent mCb.unlinkToDeath(this, 0); 1799e2dd8c4592762414c2c27e4589be7edc91a5ecaeEric Laurent } catch (NoSuchElementException e) { 1800e2dd8c4592762414c2c27e4589be7edc91a5ecaeEric Laurent Log.w(TAG, "clearCount() mStartcount: "+mStartcount+" != 0 but not registered to binder"); 1801e2dd8c4592762414c2c27e4589be7edc91a5ecaeEric Laurent } 1802e2dd8c4592762414c2c27e4589be7edc91a5ecaeEric Laurent } 18033def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent mStartcount = 0; 18043def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent if (stopSco) { 180582aa7f017daaaeb96c13e6e3491d5037ab471085Jaikumar Ganesh requestScoState(BluetoothHeadset.STATE_AUDIO_DISCONNECTED); 18063def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent } 18073def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent } 18083def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent } 18093def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent 18103def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent public int getCount() { 18113def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent return mStartcount; 18123def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent } 18133def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent 18143def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent public IBinder getBinder() { 18153def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent return mCb; 18163def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent } 18173def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent 1818d7454be47f4111c0478a502353e11dea401378bdEric Laurent public int getPid() { 1819d7454be47f4111c0478a502353e11dea401378bdEric Laurent return mCreatorPid; 1820d7454be47f4111c0478a502353e11dea401378bdEric Laurent } 1821d7454be47f4111c0478a502353e11dea401378bdEric Laurent 18223def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent public int totalCount() { 18233def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent synchronized(mScoClients) { 18243def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent int count = 0; 18253def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent int size = mScoClients.size(); 18263def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent for (int i = 0; i < size; i++) { 18273def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent count += mScoClients.get(i).getCount(); 18283def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent } 18293def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent return count; 18303def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent } 18313def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent } 18323def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent 18333def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent private void requestScoState(int state) { 183462ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent checkScoAudioState(); 1835dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent if (totalCount() == 0) { 1836dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent if (state == BluetoothHeadset.STATE_AUDIO_CONNECTED) { 1837dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent // Make sure that the state transitions to CONNECTING even if we cannot initiate 1838dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent // the connection. 1839dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_CONNECTING); 1840dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent // Accept SCO audio activation only in NORMAL audio mode or if the mode is 1841f1ddd51f9cd2f92b922bc636c307210a8d587c25Marco Nelissen // currently controlled by the same client process. 18429f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent synchronized(mSetModeDeathHandlers) { 18439f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent if ((mSetModeDeathHandlers.isEmpty() || 18449f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent mSetModeDeathHandlers.get(0).getPid() == mCreatorPid) && 18459f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent (mScoAudioState == SCO_STATE_INACTIVE || 18469f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent mScoAudioState == SCO_STATE_DEACTIVATE_REQ)) { 18479f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent if (mScoAudioState == SCO_STATE_INACTIVE) { 18489f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent if (mBluetoothHeadset != null && mBluetoothHeadsetDevice != null) { 18499f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent if (mBluetoothHeadset.startScoUsingVirtualVoiceCall( 18509f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent mBluetoothHeadsetDevice)) { 18519f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent mScoAudioState = SCO_STATE_ACTIVE_INTERNAL; 18529f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent } else { 18539f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent broadcastScoConnectionState( 18549f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent AudioManager.SCO_AUDIO_STATE_DISCONNECTED); 18559f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent } 18569f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent } else if (getBluetoothHeadset()) { 18579f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent mScoAudioState = SCO_STATE_ACTIVATE_REQ; 1858dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent } 18599f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent } else { 18609f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent mScoAudioState = SCO_STATE_ACTIVE_INTERNAL; 18619f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_CONNECTED); 1862dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent } 1863dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent } else { 18649f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_DISCONNECTED); 1865dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent } 1866dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent } 186762ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent } else if (state == BluetoothHeadset.STATE_AUDIO_DISCONNECTED && 1868dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent (mScoAudioState == SCO_STATE_ACTIVE_INTERNAL || 1869dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent mScoAudioState == SCO_STATE_ACTIVATE_REQ)) { 1870dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent if (mScoAudioState == SCO_STATE_ACTIVE_INTERNAL) { 1871671db6f3ba1fdb3c907e0735fe6d0d284f5c34deMarco Nelissen if (mBluetoothHeadset != null && mBluetoothHeadsetDevice != null) { 1872dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent if (!mBluetoothHeadset.stopScoUsingVirtualVoiceCall( 1873dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent mBluetoothHeadsetDevice)) { 1874dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent mScoAudioState = SCO_STATE_INACTIVE; 1875dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent broadcastScoConnectionState( 1876dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent AudioManager.SCO_AUDIO_STATE_DISCONNECTED); 1877dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent } 1878dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent } else if (getBluetoothHeadset()) { 1879dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent mScoAudioState = SCO_STATE_DEACTIVATE_REQ; 1880dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent } 1881dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent } else { 1882dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent mScoAudioState = SCO_STATE_INACTIVE; 1883dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_DISCONNECTED); 1884dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent } 18853def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent } 18863def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent } 18873def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent } 18883def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent } 18893def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent 189062ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent private void checkScoAudioState() { 189162ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent if (mBluetoothHeadset != null && mBluetoothHeadsetDevice != null && 1892dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent mScoAudioState == SCO_STATE_INACTIVE && 189362ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent mBluetoothHeadset.getAudioState(mBluetoothHeadsetDevice) 189462ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent != BluetoothHeadset.STATE_AUDIO_DISCONNECTED) { 189562ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent mScoAudioState = SCO_STATE_ACTIVE_EXTERNAL; 189662ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent } 189762ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent } 189862ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent 1899854938a72d968c1bc0de4e2b0ea87777cfebc045Eric Laurent private ScoClient getScoClient(IBinder cb, boolean create) { 19003def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent synchronized(mScoClients) { 1901854938a72d968c1bc0de4e2b0ea87777cfebc045Eric Laurent ScoClient client = null; 19023def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent int size = mScoClients.size(); 19033def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent for (int i = 0; i < size; i++) { 19043def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent client = mScoClients.get(i); 19053def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent if (client.getBinder() == cb) 19063def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent return client; 19073def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent } 1908854938a72d968c1bc0de4e2b0ea87777cfebc045Eric Laurent if (create) { 1909854938a72d968c1bc0de4e2b0ea87777cfebc045Eric Laurent client = new ScoClient(cb); 1910854938a72d968c1bc0de4e2b0ea87777cfebc045Eric Laurent mScoClients.add(client); 1911854938a72d968c1bc0de4e2b0ea87777cfebc045Eric Laurent } 19123def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent return client; 19133def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent } 19143def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent } 19153def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent 1916d7454be47f4111c0478a502353e11dea401378bdEric Laurent public void clearAllScoClients(int exceptPid, boolean stopSco) { 19173def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent synchronized(mScoClients) { 1918854938a72d968c1bc0de4e2b0ea87777cfebc045Eric Laurent ScoClient savedClient = null; 19193def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent int size = mScoClients.size(); 19203def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent for (int i = 0; i < size; i++) { 1921854938a72d968c1bc0de4e2b0ea87777cfebc045Eric Laurent ScoClient cl = mScoClients.get(i); 1922d7454be47f4111c0478a502353e11dea401378bdEric Laurent if (cl.getPid() != exceptPid) { 1923854938a72d968c1bc0de4e2b0ea87777cfebc045Eric Laurent cl.clearCount(stopSco); 1924854938a72d968c1bc0de4e2b0ea87777cfebc045Eric Laurent } else { 1925854938a72d968c1bc0de4e2b0ea87777cfebc045Eric Laurent savedClient = cl; 1926854938a72d968c1bc0de4e2b0ea87777cfebc045Eric Laurent } 1927854938a72d968c1bc0de4e2b0ea87777cfebc045Eric Laurent } 1928854938a72d968c1bc0de4e2b0ea87777cfebc045Eric Laurent mScoClients.clear(); 1929854938a72d968c1bc0de4e2b0ea87777cfebc045Eric Laurent if (savedClient != null) { 1930854938a72d968c1bc0de4e2b0ea87777cfebc045Eric Laurent mScoClients.add(savedClient); 19313def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent } 19323def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent } 19333def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent } 19343def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent 1935dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent private boolean getBluetoothHeadset() { 1936dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent boolean result = false; 1937dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter(); 1938dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent if (adapter != null) { 1939dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent result = adapter.getProfileProxy(mContext, mBluetoothProfileServiceListener, 1940dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent BluetoothProfile.HEADSET); 1941dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent } 1942dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent // If we could not get a bluetooth headset proxy, send a failure message 1943dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent // without delay to reset the SCO audio state and clear SCO clients. 1944dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent // If we could get a proxy, send a delayed failure message that will reset our state 1945dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent // in case we don't receive onServiceConnected(). 1946afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent sendMsg(mAudioHandler, MSG_BT_HEADSET_CNCT_FAILED, 1947dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent SENDMSG_REPLACE, 0, 0, null, result ? BT_HEADSET_CNCT_TIMEOUT_MS : 0); 1948dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent return result; 1949dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent } 1950dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent 1951d7454be47f4111c0478a502353e11dea401378bdEric Laurent private void disconnectBluetoothSco(int exceptPid) { 1952dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent synchronized(mScoClients) { 1953dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent checkScoAudioState(); 1954dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent if (mScoAudioState == SCO_STATE_ACTIVE_EXTERNAL || 1955dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent mScoAudioState == SCO_STATE_DEACTIVATE_EXT_REQ) { 1956dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent if (mBluetoothHeadsetDevice != null) { 1957dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent if (mBluetoothHeadset != null) { 1958dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent if (!mBluetoothHeadset.stopVoiceRecognition( 1959b06ac839dd2d0437fc8314f6deb7233af5af521eEric Laurent mBluetoothHeadsetDevice)) { 1960afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent sendMsg(mAudioHandler, MSG_BT_HEADSET_CNCT_FAILED, 1961dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent SENDMSG_REPLACE, 0, 0, null, 0); 1962dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent } 1963dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent } else if (mScoAudioState == SCO_STATE_ACTIVE_EXTERNAL && 1964dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent getBluetoothHeadset()) { 1965dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent mScoAudioState = SCO_STATE_DEACTIVATE_EXT_REQ; 1966dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent } 1967dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent } 1968dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent } else { 1969d7454be47f4111c0478a502353e11dea401378bdEric Laurent clearAllScoClients(exceptPid, true); 1970dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent } 1971dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent } 1972dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent } 1973dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent 1974dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent private void resetBluetoothSco() { 1975dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent synchronized(mScoClients) { 1976d7454be47f4111c0478a502353e11dea401378bdEric Laurent clearAllScoClients(0, false); 1977dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent mScoAudioState = SCO_STATE_INACTIVE; 1978dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_DISCONNECTED); 1979dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent } 1980dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent } 1981dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent 1982dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent private void broadcastScoConnectionState(int state) { 1983dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent if (state != mScoConnectionState) { 1984dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent Intent newIntent = new Intent(AudioManager.ACTION_SCO_AUDIO_STATE_UPDATED); 1985dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent newIntent.putExtra(AudioManager.EXTRA_SCO_AUDIO_STATE, state); 1986dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent newIntent.putExtra(AudioManager.EXTRA_SCO_AUDIO_PREVIOUS_STATE, 1987dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent mScoConnectionState); 1988dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent mContext.sendStickyBroadcast(newIntent); 1989dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent mScoConnectionState = state; 1990dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent } 1991dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent } 1992dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent 199382aa7f017daaaeb96c13e6e3491d5037ab471085Jaikumar Ganesh private BluetoothProfile.ServiceListener mBluetoothProfileServiceListener = 199482aa7f017daaaeb96c13e6e3491d5037ab471085Jaikumar Ganesh new BluetoothProfile.ServiceListener() { 199582aa7f017daaaeb96c13e6e3491d5037ab471085Jaikumar Ganesh public void onServiceConnected(int profile, BluetoothProfile proxy) { 19966bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent BluetoothDevice btDevice; 19976bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent List<BluetoothDevice> deviceList; 19986bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent switch(profile) { 19996bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent case BluetoothProfile.A2DP: 20006bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent BluetoothA2dp a2dp = (BluetoothA2dp) proxy; 20016bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent deviceList = a2dp.getConnectedDevices(); 200262ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent if (deviceList.size() > 0) { 20036bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent btDevice = deviceList.get(0); 2004b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent synchronized (mConnectedDevices) { 2005b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent int state = a2dp.getConnectionState(btDevice); 2006b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent int delay = checkSendBecomingNoisyIntent( 2007b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, 2008b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent (state == BluetoothA2dp.STATE_CONNECTED) ? 1 : 0); 2009e12c39bb9cedb8b363658979872694eb55b1386eJean-Michel Trivi queueMsgUnderWakeLock(mAudioHandler, 2010b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent MSG_SET_A2DP_CONNECTION_STATE, 2011b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent state, 2012b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent 0, 2013b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent btDevice, 2014b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent delay); 2015b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent } 20166bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent } 20176bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent break; 20186bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent 20196bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent case BluetoothProfile.HEADSET: 20206bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent synchronized (mScoClients) { 20216bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent // Discard timeout message 20226bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent mAudioHandler.removeMessages(MSG_BT_HEADSET_CNCT_FAILED); 20236bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent mBluetoothHeadset = (BluetoothHeadset) proxy; 20246bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent deviceList = mBluetoothHeadset.getConnectedDevices(); 20256bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent if (deviceList.size() > 0) { 20266bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent mBluetoothHeadsetDevice = deviceList.get(0); 20276bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent } else { 20286bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent mBluetoothHeadsetDevice = null; 2029dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent } 20306bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent // Refresh SCO audio state 20316bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent checkScoAudioState(); 20326bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent // Continue pending action if any 20336bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent if (mScoAudioState == SCO_STATE_ACTIVATE_REQ || 20346bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent mScoAudioState == SCO_STATE_DEACTIVATE_REQ || 20356bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent mScoAudioState == SCO_STATE_DEACTIVATE_EXT_REQ) { 20366bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent boolean status = false; 20376bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent if (mBluetoothHeadsetDevice != null) { 20386bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent switch (mScoAudioState) { 20396bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent case SCO_STATE_ACTIVATE_REQ: 20406bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent mScoAudioState = SCO_STATE_ACTIVE_INTERNAL; 20416bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent status = mBluetoothHeadset.startScoUsingVirtualVoiceCall( 20426bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent mBluetoothHeadsetDevice); 20436bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent break; 20446bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent case SCO_STATE_DEACTIVATE_REQ: 20456bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent status = mBluetoothHeadset.stopScoUsingVirtualVoiceCall( 20466bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent mBluetoothHeadsetDevice); 20476bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent break; 20486bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent case SCO_STATE_DEACTIVATE_EXT_REQ: 20496bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent status = mBluetoothHeadset.stopVoiceRecognition( 20506bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent mBluetoothHeadsetDevice); 20516bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent } 20526bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent } 20536bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent if (!status) { 2054afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent sendMsg(mAudioHandler, MSG_BT_HEADSET_CNCT_FAILED, 20556bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent SENDMSG_REPLACE, 0, 0, null, 0); 20566bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent } 2057dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent } 2058dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent } 20596bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent break; 20606bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent 20616bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent default: 20626bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent break; 20633def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent } 20643def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent } 206582aa7f017daaaeb96c13e6e3491d5037ab471085Jaikumar Ganesh public void onServiceDisconnected(int profile) { 20666bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent switch(profile) { 20676bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent case BluetoothProfile.A2DP: 20686bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent synchronized (mConnectedDevices) { 20696bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent if (mConnectedDevices.containsKey(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP)) { 20706bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent makeA2dpDeviceUnavailableNow( 20716bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent mConnectedDevices.get(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP)); 20726bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent } 20736bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent } 20746bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent break; 20756bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent 20766bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent case BluetoothProfile.HEADSET: 20776bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent synchronized (mScoClients) { 20786bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent mBluetoothHeadset = null; 20796bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent } 20806bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent break; 20816bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent 20826bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent default: 20836bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent break; 20843def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent } 20853def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent } 20863def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent }; 2087d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi 20889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /////////////////////////////////////////////////////////////////////////// 20899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Internal methods 20909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /////////////////////////////////////////////////////////////////////////// 20919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 20929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 20939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Checks if the adjustment should change ringer mode instead of just 20949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * adjusting volume. If so, this will set the proper ringer mode and volume 20959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * indices on the stream states. 20969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 2097244820185269991186d07068b92985624cede4a5Eric Laurent private boolean checkForRingerModeChange(int oldIndex, int direction, int step) { 20989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project boolean adjustVolumeIndex = true; 2099ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten int ringerMode = getRingerMode(); 2100bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent 2101bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent switch (ringerMode) { 2102bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent case RINGER_MODE_NORMAL: 2103bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent if (direction == AudioManager.ADJUST_LOWER) { 2104bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent if (mHasVibrator) { 2105244820185269991186d07068b92985624cede4a5Eric Laurent // "step" is the delta in internal index units corresponding to a 2106244820185269991186d07068b92985624cede4a5Eric Laurent // change of 1 in UI index units. 2107244820185269991186d07068b92985624cede4a5Eric Laurent // Because of rounding when rescaling from one stream index range to its alias 2108244820185269991186d07068b92985624cede4a5Eric Laurent // index range, we cannot simply test oldIndex == step: 2109244820185269991186d07068b92985624cede4a5Eric Laurent // (step <= oldIndex < 2 * step) is equivalent to: (old UI index == 1) 2110244820185269991186d07068b92985624cede4a5Eric Laurent if (step <= oldIndex && oldIndex < 2 * step) { 2111bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent ringerMode = RINGER_MODE_VIBRATE; 2112bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent } 2113bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent } else { 2114244820185269991186d07068b92985624cede4a5Eric Laurent // (oldIndex < step) is equivalent to (old UI index == 0) 2115244820185269991186d07068b92985624cede4a5Eric Laurent if ((oldIndex < step) && mPrevVolDirection != AudioManager.ADJUST_LOWER) { 2116bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent ringerMode = RINGER_MODE_SILENT; 2117bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent } 21183d4c06f90726a85e89dab13c41ddc15b9c912a3fEric Laurent } 21196329bf7b1e2217c6c9477bd57349a1edade18417Daniel Sandler } 2120bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent break; 2121bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent case RINGER_MODE_VIBRATE: 2122bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent if (!mHasVibrator) { 2123bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent Log.e(TAG, "checkForRingerModeChange() current ringer mode is vibrate" + 2124bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent "but no vibrator is present"); 2125bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent break; 2126bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent } 2127c696a53d1fe4d61373c5dc64dd057d322da90c8fAmith Yamasani if ((direction == AudioManager.ADJUST_LOWER)) { 2128c696a53d1fe4d61373c5dc64dd057d322da90c8fAmith Yamasani if (mPrevVolDirection != AudioManager.ADJUST_LOWER) { 2129bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent ringerMode = RINGER_MODE_SILENT; 2130c696a53d1fe4d61373c5dc64dd057d322da90c8fAmith Yamasani } 2131c696a53d1fe4d61373c5dc64dd057d322da90c8fAmith Yamasani } else if (direction == AudioManager.ADJUST_RAISE) { 2132bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent ringerMode = RINGER_MODE_NORMAL; 2133c696a53d1fe4d61373c5dc64dd057d322da90c8fAmith Yamasani } 2134c696a53d1fe4d61373c5dc64dd057d322da90c8fAmith Yamasani adjustVolumeIndex = false; 2135bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent break; 2136bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent case RINGER_MODE_SILENT: 21379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (direction == AudioManager.ADJUST_RAISE) { 2138bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent if (mHasVibrator) { 2139bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent ringerMode = RINGER_MODE_VIBRATE; 2140bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent } else { 2141bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent ringerMode = RINGER_MODE_NORMAL; 2142bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent } 21439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2144b024c30a80684ac08daef3137b7ba0d347fe3ce5Eric Laurent adjustVolumeIndex = false; 2145bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent break; 2146bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent default: 2147bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent Log.e(TAG, "checkForRingerModeChange() wrong ringer mode: "+ringerMode); 2148bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent break; 21499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 21509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2151bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent setRingerMode(ringerMode); 21529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 215325101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent mPrevVolDirection = direction; 215425101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent 21559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return adjustVolumeIndex; 21569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 21579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 21589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public boolean isStreamAffectedByRingerMode(int streamType) { 21599bcf401d13d47416043a704430388abd59aef7cdEric Laurent return (mRingerModeAffectedStreams & (1 << streamType)) != 0; 21609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 21619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 21625b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent private boolean isStreamMutedByRingerMode(int streamType) { 21635b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent return (mRingerModeMutedStreams & (1 << streamType)) != 0; 21645b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent } 21655b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent 21669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public boolean isStreamAffectedByMute(int streamType) { 21679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return (mMuteAffectedStreams & (1 << streamType)) != 0; 21689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 21699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 21709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private void ensureValidDirection(int direction) { 21719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (direction < AudioManager.ADJUST_LOWER || direction > AudioManager.ADJUST_RAISE) { 21729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project throw new IllegalArgumentException("Bad direction " + direction); 21739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 21749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 21759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 21766c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang private void ensureValidSteps(int steps) { 21776c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang if (Math.abs(steps) > MAX_BATCH_VOLUME_ADJUST_STEPS) { 21786c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang throw new IllegalArgumentException("Bad volume adjust steps " + steps); 21796c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang } 21806c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang } 21816c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang 21829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private void ensureValidStreamType(int streamType) { 21839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (streamType < 0 || streamType >= mStreamStates.length) { 21849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project throw new IllegalArgumentException("Bad stream type " + streamType); 21859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 21869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 21879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 21886d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent private boolean isInCommunication() { 21896d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent boolean isOffhook = false; 219025101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent 219125101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent if (mVoiceCapable) { 219225101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent try { 219325101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent ITelephony phone = ITelephony.Stub.asInterface(ServiceManager.checkService("phone")); 219425101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent if (phone != null) isOffhook = phone.isOffhook(); 219525101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent } catch (RemoteException e) { 219625101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent Log.w(TAG, "Couldn't connect to phone service", e); 219725101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent } 21986d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent } 21996d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent return (isOffhook || getMode() == AudioManager.MODE_IN_COMMUNICATION); 22006d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent } 220125101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent 22026d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent private int getActiveStreamType(int suggestedStreamType) { 22036d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent if (mVoiceCapable) { 22046d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent if (isInCommunication()) { 220525101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent if (AudioSystem.getForceUse(AudioSystem.FOR_COMMUNICATION) 220625101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent == AudioSystem.FORCE_BT_SCO) { 220725101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent // Log.v(TAG, "getActiveStreamType: Forcing STREAM_BLUETOOTH_SCO..."); 220825101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent return AudioSystem.STREAM_BLUETOOTH_SCO; 220925101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent } else { 221025101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent // Log.v(TAG, "getActiveStreamType: Forcing STREAM_VOICE_CALL..."); 221125101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent return AudioSystem.STREAM_VOICE_CALL; 221225101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent } 22133114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi } else if (suggestedStreamType == AudioManager.USE_DEFAULT_STREAM_TYPE) { 22143114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi // Having the suggested stream be USE_DEFAULT_STREAM_TYPE is how remote control 22153114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi // volume can have priority over STREAM_MUSIC 22163114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi if (checkUpdateRemoteStateIfActive(AudioSystem.STREAM_MUSIC)) { 22173114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi if (DEBUG_VOL) 22183114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi Log.v(TAG, "getActiveStreamType: Forcing STREAM_REMOTE_MUSIC"); 22193114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi return STREAM_REMOTE_MUSIC; 22203114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi } else if (AudioSystem.isStreamActive(AudioSystem.STREAM_MUSIC, 0)) { 22213114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi if (DEBUG_VOL) 22223114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi Log.v(TAG, "getActiveStreamType: Forcing STREAM_MUSIC stream active"); 22233114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi return AudioSystem.STREAM_MUSIC; 22243114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi } else { 22253114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi if (DEBUG_VOL) 22263114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi Log.v(TAG, "getActiveStreamType: Forcing STREAM_RING b/c default"); 22273114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi return AudioSystem.STREAM_RING; 22283114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi } 222925101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent } else if (AudioSystem.isStreamActive(AudioSystem.STREAM_MUSIC, 0)) { 22303114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi if (DEBUG_VOL) 22313114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi Log.v(TAG, "getActiveStreamType: Forcing STREAM_MUSIC stream active"); 223225101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent return AudioSystem.STREAM_MUSIC; 2233c7fcba4b7bd3d78e7cfe975a3f8e4dde2f6738b7Joe Onorato } else { 22343114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: Returning suggested type " 22353114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi + suggestedStreamType); 223625101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent return suggestedStreamType; 223725101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent } 223825101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent } else { 22396d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent if (isInCommunication()) { 224025101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent if (AudioSystem.getForceUse(AudioSystem.FOR_COMMUNICATION) 224125101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent == AudioSystem.FORCE_BT_SCO) { 22423114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: Forcing STREAM_BLUETOOTH_SCO"); 224325101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent return AudioSystem.STREAM_BLUETOOTH_SCO; 224425101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent } else { 22453114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: Forcing STREAM_VOICE_CALL"); 224625101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent return AudioSystem.STREAM_VOICE_CALL; 224725101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent } 224825101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent } else if (AudioSystem.isStreamActive(AudioSystem.STREAM_NOTIFICATION, 22493114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi NOTIFICATION_VOLUME_DELAY_MS) || 22503114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi AudioSystem.isStreamActive(AudioSystem.STREAM_RING, 225125101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent NOTIFICATION_VOLUME_DELAY_MS)) { 22523114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: Forcing STREAM_NOTIFICATION"); 225325101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent return AudioSystem.STREAM_NOTIFICATION; 22543114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi } else if (suggestedStreamType == AudioManager.USE_DEFAULT_STREAM_TYPE) { 22553114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi if (checkUpdateRemoteStateIfActive(AudioSystem.STREAM_MUSIC)) { 22563114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi // Having the suggested stream be USE_DEFAULT_STREAM_TYPE is how remote control 22573114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi // volume can have priority over STREAM_MUSIC 22583114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: Forcing STREAM_REMOTE_MUSIC"); 22593114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi return STREAM_REMOTE_MUSIC; 22603114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi } else { 22613114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi if (DEBUG_VOL) 22623114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi Log.v(TAG, "getActiveStreamType: using STREAM_MUSIC as default"); 22633114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi return AudioSystem.STREAM_MUSIC; 22643114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi } 226525101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent } else { 22663114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: Returning suggested type " 22673114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi + suggestedStreamType); 226825101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent return suggestedStreamType; 2269c7fcba4b7bd3d78e7cfe975a3f8e4dde2f6738b7Joe Onorato } 22709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 22719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 22729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2273ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten private void broadcastRingerMode(int ringerMode) { 22749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Send sticky broadcast 22751c633fc89bae9bf0af6fe643ac7ad2e744f27bedDianne Hackborn Intent broadcast = new Intent(AudioManager.RINGER_MODE_CHANGED_ACTION); 2276ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten broadcast.putExtra(AudioManager.EXTRA_RINGER_MODE, ringerMode); 22771c633fc89bae9bf0af6fe643ac7ad2e744f27bedDianne Hackborn broadcast.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT 22781c633fc89bae9bf0af6fe643ac7ad2e744f27bedDianne Hackborn | Intent.FLAG_RECEIVER_REPLACE_PENDING); 22791c633fc89bae9bf0af6fe643ac7ad2e744f27bedDianne Hackborn long origCallerIdentityToken = Binder.clearCallingIdentity(); 22801c633fc89bae9bf0af6fe643ac7ad2e744f27bedDianne Hackborn mContext.sendStickyBroadcast(broadcast); 22811c633fc89bae9bf0af6fe643ac7ad2e744f27bedDianne Hackborn Binder.restoreCallingIdentity(origCallerIdentityToken); 22829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 22839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 22849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private void broadcastVibrateSetting(int vibrateType) { 22859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Send broadcast 22869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (ActivityManagerNative.isSystemReady()) { 22879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Intent broadcast = new Intent(AudioManager.VIBRATE_SETTING_CHANGED_ACTION); 22889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project broadcast.putExtra(AudioManager.EXTRA_VIBRATE_TYPE, vibrateType); 22899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project broadcast.putExtra(AudioManager.EXTRA_VIBRATE_SETTING, getVibrateSetting(vibrateType)); 22909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mContext.sendBroadcast(broadcast); 22919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 22929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 22939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 22949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Message helper methods 22952d8dab5a549b25b6f36df4614d7c0166d4d099e2Jean-Michel Trivi /** 22962d8dab5a549b25b6f36df4614d7c0166d4d099e2Jean-Michel Trivi * Queue a message on the given handler's message queue, after acquiring the service wake lock. 22972d8dab5a549b25b6f36df4614d7c0166d4d099e2Jean-Michel Trivi * Note that the wake lock needs to be released after the message has been handled. 22982d8dab5a549b25b6f36df4614d7c0166d4d099e2Jean-Michel Trivi */ 22992d8dab5a549b25b6f36df4614d7c0166d4d099e2Jean-Michel Trivi private void queueMsgUnderWakeLock(Handler handler, int msg, 23002d8dab5a549b25b6f36df4614d7c0166d4d099e2Jean-Michel Trivi int arg1, int arg2, Object obj, int delay) { 23012d8dab5a549b25b6f36df4614d7c0166d4d099e2Jean-Michel Trivi mMediaEventWakeLock.acquire(); 23022d8dab5a549b25b6f36df4614d7c0166d4d099e2Jean-Michel Trivi sendMsg(handler, msg, SENDMSG_QUEUE, arg1, arg2, obj, delay); 23032d8dab5a549b25b6f36df4614d7c0166d4d099e2Jean-Michel Trivi } 23049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2305afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent private static void sendMsg(Handler handler, int msg, 23069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int existingMsgPolicy, int arg1, int arg2, Object obj, int delay) { 23079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 23089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (existingMsgPolicy == SENDMSG_REPLACE) { 23099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project handler.removeMessages(msg); 23109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else if (existingMsgPolicy == SENDMSG_NOOP && handler.hasMessages(msg)) { 23119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return; 23129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 23139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2314afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent handler.sendMessageDelayed(handler.obtainMessage(msg, arg1, arg2, obj), delay); 23159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 23169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 23179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project boolean checkAudioSettingsPermission(String method) { 23189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mContext.checkCallingOrSelfPermission("android.permission.MODIFY_AUDIO_SETTINGS") 23199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project == PackageManager.PERMISSION_GRANTED) { 23209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return true; 23219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 23229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project String msg = "Audio Settings Permission Denial: " + method + " from pid=" 23239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project + Binder.getCallingPid() 23249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project + ", uid=" + Binder.getCallingUid(); 23259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Log.w(TAG, msg); 23269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return false; 23279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 23289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 23299bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent private int getDeviceForStream(int stream) { 23309bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent int device = AudioSystem.getDevicesForStream(stream); 23319bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent if ((device & (device - 1)) != 0) { 23329bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent // Multiple device selection is either: 23339bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent // - speaker + one other device: give priority to speaker in this case. 23349bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent // - one A2DP device + another device: happens with duplicated output. In this case 23359bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent // retain the device on the A2DP output as the other must not correspond to an active 23369bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent // selection if not the speaker. 23379bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent if ((device & AudioSystem.DEVICE_OUT_SPEAKER) != 0) { 23389bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent device = AudioSystem.DEVICE_OUT_SPEAKER; 23399bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent } else { 23409bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent device &= AudioSystem.DEVICE_OUT_ALL_A2DP; 23419bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent } 23429bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent } 23439bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent return device; 23449bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent } 23459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2346b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent public void setWiredDeviceConnectionState(int device, int state, String name) { 2347b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent synchronized (mConnectedDevices) { 2348b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent int delay = checkSendBecomingNoisyIntent(device, state); 23492d8dab5a549b25b6f36df4614d7c0166d4d099e2Jean-Michel Trivi queueMsgUnderWakeLock(mAudioHandler, 2350b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent MSG_SET_WIRED_DEVICE_CONNECTION_STATE, 2351b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent device, 2352b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent state, 2353b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent name, 2354b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent delay); 2355b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent } 2356b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent } 2357b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent 2358b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent public int setBluetoothA2dpDeviceConnectionState(BluetoothDevice device, int state) 2359b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent { 2360b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent int delay; 2361b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent synchronized (mConnectedDevices) { 2362b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent delay = checkSendBecomingNoisyIntent(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, 2363b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent (state == BluetoothA2dp.STATE_CONNECTED) ? 1 : 0); 23642d8dab5a549b25b6f36df4614d7c0166d4d099e2Jean-Michel Trivi queueMsgUnderWakeLock(mAudioHandler, 2365b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent MSG_SET_A2DP_CONNECTION_STATE, 2366b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent state, 2367b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent 0, 2368b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent device, 2369b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent delay); 2370b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent } 2371b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent return delay; 2372b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent } 2373b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent 23749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /////////////////////////////////////////////////////////////////////////// 23759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Inner classes 23769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /////////////////////////////////////////////////////////////////////////// 23779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 23789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public class VolumeStreamState { 23799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private final int mStreamType; 23809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 238111a74a75653197a3d31fe91590cd8312f5270c44Jean-Michel Trivi private String mVolumeIndexSettingName; 238211a74a75653197a3d31fe91590cd8312f5270c44Jean-Michel Trivi private String mLastAudibleVolumeIndexSettingName; 2383a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent private int mIndexMax; 23843172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent private final ConcurrentHashMap<Integer, Integer> mIndex = 23853172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent new ConcurrentHashMap<Integer, Integer>(8, 0.75f, 4); 23863172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent private final ConcurrentHashMap<Integer, Integer> mLastAudibleIndex = 23873172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent new ConcurrentHashMap<Integer, Integer>(8, 0.75f, 4); 23889bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent private ArrayList<VolumeDeathHandler> mDeathHandlers; //handles mute/solo clients death 23899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2390a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent private VolumeStreamState(String settingName, int streamType) { 23919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 23929bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent mVolumeIndexSettingName = settingName; 23939bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent mLastAudibleVolumeIndexSettingName = settingName + System.APPEND_FOR_LAST_AUDIBLE; 23949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 23959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mStreamType = streamType; 23965982013cfc8274ff0bafaba83c676b3a8890cba9Jared Suttles mIndexMax = MAX_STREAM_VOLUME[streamType]; 2397a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent AudioSystem.initStreamVolume(streamType, 0, mIndexMax); 2398a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent mIndexMax *= 10; 23999bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent 24009bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent readSettings(); 24019bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent 24029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mDeathHandlers = new ArrayList<VolumeDeathHandler>(); 24039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 24049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 24059bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent public String getSettingNameForDevice(boolean lastAudible, int device) { 24069bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent String name = lastAudible ? 24079bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent mLastAudibleVolumeIndexSettingName : 24089bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent mVolumeIndexSettingName; 24099bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent String suffix = AudioSystem.getDeviceName(device); 24109bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent if (suffix.isEmpty()) { 24119bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent return name; 24129bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent } 24139bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent return name + "_" + suffix; 24149bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent } 24159bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent 24163172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent public synchronized void readSettings() { 24179bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent int remainingDevices = AudioSystem.DEVICE_OUT_ALL; 24189ac8d0c445a3ccde40c05f0f3ad0ec4e8265d4c6Eric Laurent 24199bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent for (int i = 0; remainingDevices != 0; i++) { 24209bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent int device = (1 << i); 24219bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent if ((device & remainingDevices) == 0) { 24229bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent continue; 24239bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent } 24249bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent remainingDevices &= ~device; 24259bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent 24269bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent // retrieve current volume for device 24279ac8d0c445a3ccde40c05f0f3ad0ec4e8265d4c6Eric Laurent String name = getSettingNameForDevice(false /* lastAudible */, device); 24289ac8d0c445a3ccde40c05f0f3ad0ec4e8265d4c6Eric Laurent // if no volume stored for current stream and device, use default volume if default 24299ac8d0c445a3ccde40c05f0f3ad0ec4e8265d4c6Eric Laurent // device, continue otherwise 24309ac8d0c445a3ccde40c05f0f3ad0ec4e8265d4c6Eric Laurent int defaultIndex = (device == AudioSystem.DEVICE_OUT_DEFAULT) ? 24319ac8d0c445a3ccde40c05f0f3ad0ec4e8265d4c6Eric Laurent AudioManager.DEFAULT_STREAM_VOLUME[mStreamType] : -1; 24329ac8d0c445a3ccde40c05f0f3ad0ec4e8265d4c6Eric Laurent int index = Settings.System.getInt(mContentResolver, name, defaultIndex); 24339bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent if (index == -1) { 24349bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent continue; 24359bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent } 24369bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent 24379bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent // retrieve last audible volume for device 24389ac8d0c445a3ccde40c05f0f3ad0ec4e8265d4c6Eric Laurent name = getSettingNameForDevice(true /* lastAudible */, device); 24399ac8d0c445a3ccde40c05f0f3ad0ec4e8265d4c6Eric Laurent // use stored last audible index if present, otherwise use current index if not 0 24409ac8d0c445a3ccde40c05f0f3ad0ec4e8265d4c6Eric Laurent // or default index 24419ac8d0c445a3ccde40c05f0f3ad0ec4e8265d4c6Eric Laurent defaultIndex = (index > 0) ? 24429ac8d0c445a3ccde40c05f0f3ad0ec4e8265d4c6Eric Laurent index : AudioManager.DEFAULT_STREAM_VOLUME[mStreamType]; 24439ac8d0c445a3ccde40c05f0f3ad0ec4e8265d4c6Eric Laurent int lastAudibleIndex = Settings.System.getInt(mContentResolver, name, defaultIndex); 24449ac8d0c445a3ccde40c05f0f3ad0ec4e8265d4c6Eric Laurent 2445bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent // a last audible index of 0 should never be stored for ring and notification 2446bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent // streams on phones (voice capable devices). 2447bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent // same for system stream on phones and tablets 24489ac8d0c445a3ccde40c05f0f3ad0ec4e8265d4c6Eric Laurent if ((lastAudibleIndex == 0) && 2449bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent ((mVoiceCapable && 2450bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent (mStreamVolumeAlias[mStreamType] == AudioSystem.STREAM_RING)) || 2451bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent (mStreamVolumeAlias[mStreamType] == AudioSystem.STREAM_SYSTEM))) { 24529ac8d0c445a3ccde40c05f0f3ad0ec4e8265d4c6Eric Laurent lastAudibleIndex = AudioManager.DEFAULT_STREAM_VOLUME[mStreamType]; 24539ac8d0c445a3ccde40c05f0f3ad0ec4e8265d4c6Eric Laurent // Correct the data base 24549ac8d0c445a3ccde40c05f0f3ad0ec4e8265d4c6Eric Laurent sendMsg(mAudioHandler, 24559ac8d0c445a3ccde40c05f0f3ad0ec4e8265d4c6Eric Laurent MSG_PERSIST_VOLUME, 24569ac8d0c445a3ccde40c05f0f3ad0ec4e8265d4c6Eric Laurent SENDMSG_QUEUE, 24579ac8d0c445a3ccde40c05f0f3ad0ec4e8265d4c6Eric Laurent PERSIST_LAST_AUDIBLE, 24589ac8d0c445a3ccde40c05f0f3ad0ec4e8265d4c6Eric Laurent device, 24599ac8d0c445a3ccde40c05f0f3ad0ec4e8265d4c6Eric Laurent this, 24609ac8d0c445a3ccde40c05f0f3ad0ec4e8265d4c6Eric Laurent PERSIST_DELAY); 24619ac8d0c445a3ccde40c05f0f3ad0ec4e8265d4c6Eric Laurent } 24629ac8d0c445a3ccde40c05f0f3ad0ec4e8265d4c6Eric Laurent mLastAudibleIndex.put(device, getValidIndex(10 * lastAudibleIndex)); 2463bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent // the initial index should never be 0 for ring and notification streams on phones 2464bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent // (voice capable devices) if not in silent or vibrate mode. 2465bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent // same for system stream on phones and tablets 2466bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent if ((index == 0) && (mRingerMode == AudioManager.RINGER_MODE_NORMAL) && 2467bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent ((mVoiceCapable && 2468bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent (mStreamVolumeAlias[mStreamType] == AudioSystem.STREAM_RING)) || 2469bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent (mStreamVolumeAlias[mStreamType] == AudioSystem.STREAM_SYSTEM))) { 24709ac8d0c445a3ccde40c05f0f3ad0ec4e8265d4c6Eric Laurent index = lastAudibleIndex; 24719ac8d0c445a3ccde40c05f0f3ad0ec4e8265d4c6Eric Laurent // Correct the data base 24729ac8d0c445a3ccde40c05f0f3ad0ec4e8265d4c6Eric Laurent sendMsg(mAudioHandler, 24739ac8d0c445a3ccde40c05f0f3ad0ec4e8265d4c6Eric Laurent MSG_PERSIST_VOLUME, 24749ac8d0c445a3ccde40c05f0f3ad0ec4e8265d4c6Eric Laurent SENDMSG_QUEUE, 24759ac8d0c445a3ccde40c05f0f3ad0ec4e8265d4c6Eric Laurent PERSIST_CURRENT, 24769ac8d0c445a3ccde40c05f0f3ad0ec4e8265d4c6Eric Laurent device, 24779ac8d0c445a3ccde40c05f0f3ad0ec4e8265d4c6Eric Laurent this, 24789ac8d0c445a3ccde40c05f0f3ad0ec4e8265d4c6Eric Laurent PERSIST_DELAY); 24799ac8d0c445a3ccde40c05f0f3ad0ec4e8265d4c6Eric Laurent } 24809ac8d0c445a3ccde40c05f0f3ad0ec4e8265d4c6Eric Laurent mIndex.put(device, getValidIndex(10 * index)); 24819bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent } 24829bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent } 24839bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent 24849bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent public void applyDeviceVolume(int device) { 24859bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent AudioSystem.setStreamVolumeIndex(mStreamType, 24869bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent (getIndex(device, false /* lastAudible */) + 5)/10, 24879bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent device); 24889bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent } 24899bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent 24903172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent public synchronized void applyAllVolumes() { 24919bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent // apply default volume first: by convention this will reset all 24929bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent // devices volumes in audio policy manager to the supplied value 24939bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent AudioSystem.setStreamVolumeIndex(mStreamType, 24949bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent (getIndex(AudioSystem.DEVICE_OUT_DEFAULT, false /* lastAudible */) + 5)/10, 24959bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent AudioSystem.DEVICE_OUT_DEFAULT); 24969bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent // then apply device specific volumes 24979bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent Set set = mIndex.entrySet(); 24989bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent Iterator i = set.iterator(); 24999bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent while (i.hasNext()) { 25009bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent Map.Entry entry = (Map.Entry)i.next(); 25019bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent int device = ((Integer)entry.getKey()).intValue(); 25029bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent if (device != AudioSystem.DEVICE_OUT_DEFAULT) { 25039bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent AudioSystem.setStreamVolumeIndex(mStreamType, 25049bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent ((Integer)entry.getValue() + 5)/10, 25059bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent device); 25069bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent } 25079bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent } 250811a74a75653197a3d31fe91590cd8312f5270c44Jean-Michel Trivi } 250911a74a75653197a3d31fe91590cd8312f5270c44Jean-Michel Trivi 25109bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent public boolean adjustIndex(int deltaIndex, int device) { 25119bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent return setIndex(getIndex(device, 2512244820185269991186d07068b92985624cede4a5Eric Laurent false /* lastAudible */) + deltaIndex, 25139bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent device, 25149bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent true /* lastAudible */); 25159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 25169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 25173172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent public synchronized boolean setIndex(int index, int device, boolean lastAudible) { 25189bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent int oldIndex = getIndex(device, false /* lastAudible */); 25199bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent index = getValidIndex(index); 25209bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent mIndex.put(device, getValidIndex(index)); 25219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 25229bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent if (oldIndex != index) { 25239bcf401d13d47416043a704430388abd59aef7cdEric Laurent if (lastAudible) { 25249bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent mLastAudibleIndex.put(device, index); 25259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2526a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent // Apply change to all streams using this one as alias 2527bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent // if changing volume of current device, also change volume of current 2528bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent // device on aliased stream 2529bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent boolean currentDevice = (device == getDeviceForStream(mStreamType)); 2530a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent int numStreamTypes = AudioSystem.getNumStreamTypes(); 2531a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) { 2532bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent if (streamType != mStreamType && 2533bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent mStreamVolumeAlias[streamType] == mStreamType) { 2534bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent int scaledIndex = rescaleIndex(index, mStreamType, streamType); 2535bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent mStreamStates[streamType].setIndex(scaledIndex, 2536bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent device, 25379bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent lastAudible); 2538bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent if (currentDevice) { 2539bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent mStreamStates[streamType].setIndex(scaledIndex, 2540bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent getDeviceForStream(streamType), 2541bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent lastAudible); 2542bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent } 2543a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent } 2544a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent } 25459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return true; 25469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 25479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return false; 25489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 25499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 25509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 25513172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent public synchronized int getIndex(int device, boolean lastAudible) { 25523172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent ConcurrentHashMap <Integer, Integer> indexes; 25539bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent if (lastAudible) { 25549bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent indexes = mLastAudibleIndex; 25559bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent } else { 25569bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent indexes = mIndex; 25579bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent } 25589bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent Integer index = indexes.get(device); 25599bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent if (index == null) { 25609bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent // there is always an entry for AudioSystem.DEVICE_OUT_DEFAULT 25619bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent index = indexes.get(AudioSystem.DEVICE_OUT_DEFAULT); 25629bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent } 25639bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent return index.intValue(); 25649bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent } 25659bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent 25663172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent public synchronized void setLastAudibleIndex(int index, int device) { 2567244820185269991186d07068b92985624cede4a5Eric Laurent // Apply change to all streams using this one as alias 2568244820185269991186d07068b92985624cede4a5Eric Laurent // if changing volume of current device, also change volume of current 2569244820185269991186d07068b92985624cede4a5Eric Laurent // device on aliased stream 2570244820185269991186d07068b92985624cede4a5Eric Laurent boolean currentDevice = (device == getDeviceForStream(mStreamType)); 2571244820185269991186d07068b92985624cede4a5Eric Laurent int numStreamTypes = AudioSystem.getNumStreamTypes(); 2572244820185269991186d07068b92985624cede4a5Eric Laurent for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) { 2573244820185269991186d07068b92985624cede4a5Eric Laurent if (streamType != mStreamType && 2574244820185269991186d07068b92985624cede4a5Eric Laurent mStreamVolumeAlias[streamType] == mStreamType) { 2575244820185269991186d07068b92985624cede4a5Eric Laurent int scaledIndex = rescaleIndex(index, mStreamType, streamType); 2576244820185269991186d07068b92985624cede4a5Eric Laurent mStreamStates[streamType].setLastAudibleIndex(scaledIndex, device); 2577244820185269991186d07068b92985624cede4a5Eric Laurent if (currentDevice) { 2578244820185269991186d07068b92985624cede4a5Eric Laurent mStreamStates[streamType].setLastAudibleIndex(scaledIndex, 2579244820185269991186d07068b92985624cede4a5Eric Laurent getDeviceForStream(streamType)); 2580244820185269991186d07068b92985624cede4a5Eric Laurent } 2581244820185269991186d07068b92985624cede4a5Eric Laurent } 2582244820185269991186d07068b92985624cede4a5Eric Laurent } 25839bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent mLastAudibleIndex.put(device, getValidIndex(index)); 25845b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent } 25855b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent 25863172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent public synchronized void adjustLastAudibleIndex(int deltaIndex, int device) { 25879bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent setLastAudibleIndex(getIndex(device, 2588244820185269991186d07068b92985624cede4a5Eric Laurent true /* lastAudible */) + deltaIndex, 25899bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent device); 25905b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent } 25915b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent 25929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public int getMaxIndex() { 2593a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent return mIndexMax; 25949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 25959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 25963172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent // only called by setAllIndexes() which is already synchronized 25973172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent public ConcurrentHashMap <Integer, Integer> getAllIndexes(boolean lastAudible) { 25986d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent if (lastAudible) { 25996d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent return mLastAudibleIndex; 26006d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent } else { 26016d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent return mIndex; 26026d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent } 26036d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent } 26046d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent 26053172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent public synchronized void setAllIndexes(VolumeStreamState srcStream, boolean lastAudible) { 26063172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent ConcurrentHashMap <Integer, Integer> indexes = srcStream.getAllIndexes(lastAudible); 26076d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent Set set = indexes.entrySet(); 26086d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent Iterator i = set.iterator(); 26096d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent while (i.hasNext()) { 26106d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent Map.Entry entry = (Map.Entry)i.next(); 26116d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent int device = ((Integer)entry.getKey()).intValue(); 26126d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent int index = ((Integer)entry.getValue()).intValue(); 26136d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent index = rescaleIndex(index, srcStream.getStreamType(), mStreamType); 26146d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent setIndex(index, device, lastAudible); 26156d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent } 26166d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent } 26176d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent 26183172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent public synchronized void mute(IBinder cb, boolean state) { 26199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project VolumeDeathHandler handler = getDeathHandler(cb, state); 26209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (handler == null) { 26219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Log.e(TAG, "Could not get client death handler for stream: "+mStreamType); 26229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return; 26239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 26249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project handler.mute(state); 26259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 26269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 26276d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent public int getStreamType() { 26286d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent return mStreamType; 26296d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent } 26306d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent 26319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private int getValidIndex(int index) { 26329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (index < 0) { 26339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return 0; 2634a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent } else if (index > mIndexMax) { 2635a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent return mIndexMax; 26369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 26379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 26389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return index; 26399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 26409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 26419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private class VolumeDeathHandler implements IBinder.DeathRecipient { 26429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private IBinder mICallback; // To be notified of client's death 26439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private int mMuteCount; // Number of active mutes for this client 26449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 26459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project VolumeDeathHandler(IBinder cb) { 26469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mICallback = cb; 26479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 26489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 26493172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent // must be called while synchronized on parent VolumeStreamState 26509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void mute(boolean state) { 26513172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent if (state) { 26523172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent if (mMuteCount == 0) { 26533172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent // Register for client death notification 26543172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent try { 26553172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent // mICallback can be 0 if muted by AudioService 26563172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent if (mICallback != null) { 26573172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent mICallback.linkToDeath(this, 0); 26583172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent } 26593172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent mDeathHandlers.add(this); 26603172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent // If the stream is not yet muted by any client, set level to 0 26613172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent if (muteCount() == 0) { 26623172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent Set set = mIndex.entrySet(); 26633172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent Iterator i = set.iterator(); 26643172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent while (i.hasNext()) { 26653172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent Map.Entry entry = (Map.Entry)i.next(); 26663172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent int device = ((Integer)entry.getKey()).intValue(); 26673172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent setIndex(0, device, false /* lastAudible */); 26685b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent } 26693172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent sendMsg(mAudioHandler, 26703172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent MSG_SET_ALL_VOLUMES, 26713172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent SENDMSG_QUEUE, 26723172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent 0, 26733172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent 0, 26743172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent VolumeStreamState.this, 0); 26753172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent } 26763172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent } catch (RemoteException e) { 26773172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent // Client has died! 26783172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent binderDied(); 26793172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent return; 26803172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent } 26813172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent } else { 26823172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent Log.w(TAG, "stream: "+mStreamType+" was already muted by this client"); 26833172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent } 26843172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent mMuteCount++; 26853172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent } else { 26863172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent if (mMuteCount == 0) { 26873172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent Log.e(TAG, "unexpected unmute for stream: "+mStreamType); 26883172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent } else { 26893172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent mMuteCount--; 26903172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent if (mMuteCount == 0) { 26913172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent // Unregister from client death notification 26923172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent mDeathHandlers.remove(this); 26933172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent // mICallback can be 0 if muted by AudioService 26943172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent if (mICallback != null) { 26953172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent mICallback.unlinkToDeath(this, 0); 26963172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent } 26973172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent if (muteCount() == 0) { 26983172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent // If the stream is not muted any more, restore its volume if 26993172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent // ringer mode allows it 27003172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent if (!isStreamAffectedByRingerMode(mStreamType) || 27013172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent mRingerMode == AudioManager.RINGER_MODE_NORMAL) { 27029bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent Set set = mIndex.entrySet(); 27039bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent Iterator i = set.iterator(); 27049bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent while (i.hasNext()) { 27059bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent Map.Entry entry = (Map.Entry)i.next(); 27069bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent int device = ((Integer)entry.getKey()).intValue(); 27073172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent setIndex(getIndex(device, 27083172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent true /* lastAudible */), 27093172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent device, 27103172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent false /* lastAudible */); 27119bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent } 27129bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent sendMsg(mAudioHandler, 27139bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent MSG_SET_ALL_VOLUMES, 271498ad9b9d6fd34aad487933170f50b5519313df61Eric Laurent SENDMSG_QUEUE, 27159bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent 0, 27169bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent 0, 27179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project VolumeStreamState.this, 0); 27189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 27199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 27209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 27219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 27229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 27239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 27249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 27259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void binderDied() { 27269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Log.w(TAG, "Volume service client died for stream: "+mStreamType); 27279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mMuteCount != 0) { 27289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Reset all active mute requests from this client. 27299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mMuteCount = 1; 27309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mute(false); 27319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 27329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 27339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 27349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 27353172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent private synchronized int muteCount() { 27369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int count = 0; 27379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int size = mDeathHandlers.size(); 27389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (int i = 0; i < size; i++) { 27399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project count += mDeathHandlers.get(i).mMuteCount; 27409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 27419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return count; 27429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 27439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 27443172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent // only called by mute() which is already synchronized 27459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private VolumeDeathHandler getDeathHandler(IBinder cb, boolean state) { 27463172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent VolumeDeathHandler handler; 27473172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent int size = mDeathHandlers.size(); 27483172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent for (int i = 0; i < size; i++) { 27493172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent handler = mDeathHandlers.get(i); 27503172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent if (cb == handler.mICallback) { 27513172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent return handler; 2752ce952c8e13c535bedde77bcdb94dfcc7508475aaMike Lockwood } 2753ce952c8e13c535bedde77bcdb94dfcc7508475aaMike Lockwood } 27543172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent // If this is the first mute request for this client, create a new 27553172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent // client death handler. Otherwise, it is an out of sequence unmute request. 27563172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent if (state) { 27573172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent handler = new VolumeDeathHandler(cb); 27583172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent } else { 27593172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent Log.w(TAG, "stream was not muted by this client"); 27603172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent handler = null; 27613172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent } 27623172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent return handler; 2763ce952c8e13c535bedde77bcdb94dfcc7508475aaMike Lockwood } 2764bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent 2765bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent private void dump(PrintWriter pw) { 2766bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent pw.print(" Current: "); 2767bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent Set set = mIndex.entrySet(); 2768bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent Iterator i = set.iterator(); 2769bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent while (i.hasNext()) { 2770bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent Map.Entry entry = (Map.Entry)i.next(); 2771bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent pw.print(Integer.toHexString(((Integer)entry.getKey()).intValue()) 2772bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent + ": " + ((((Integer)entry.getValue()).intValue() + 5) / 10)+", "); 2773bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent } 2774bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent pw.print("\n Last audible: "); 2775bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent set = mLastAudibleIndex.entrySet(); 2776bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent i = set.iterator(); 2777bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent while (i.hasNext()) { 2778bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent Map.Entry entry = (Map.Entry)i.next(); 2779bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent pw.print(Integer.toHexString(((Integer)entry.getKey()).intValue()) 2780bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent + ": " + ((((Integer)entry.getValue()).intValue() + 5) / 10)+", "); 2781bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent } 2782bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent } 2783ce952c8e13c535bedde77bcdb94dfcc7508475aaMike Lockwood } 2784ce952c8e13c535bedde77bcdb94dfcc7508475aaMike Lockwood 27859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** Thread that handles native AudioSystem control. */ 27869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private class AudioSystemThread extends Thread { 27879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project AudioSystemThread() { 27889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project super("AudioService"); 27899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 27909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 27919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @Override 27929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void run() { 27939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Set this thread up so the handler will work on it 27949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Looper.prepare(); 27959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 27969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project synchronized(AudioService.this) { 27979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mAudioHandler = new AudioHandler(); 27989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 27999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Notify that the handler has been created 28009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project AudioService.this.notify(); 28019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 28029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 28039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Listen for volume change requests that are set by VolumePanel 28049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Looper.loop(); 28059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 28069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 28079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 28089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** Handles internal volume messages in separate volume thread. */ 28099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private class AudioHandler extends Handler { 28109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 28119bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent private void setDeviceVolume(VolumeStreamState streamState, int device) { 28129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 28139bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent // Apply volume 28149bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent streamState.applyDeviceVolume(device); 2815a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent 2816a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent // Apply change to all streams using this one as alias 2817a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent int numStreamTypes = AudioSystem.getNumStreamTypes(); 2818a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) { 2819a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent if (streamType != streamState.mStreamType && 28206d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent mStreamVolumeAlias[streamType] == streamState.mStreamType) { 28216d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent mStreamStates[streamType].applyDeviceVolume(getDeviceForStream(streamType)); 2822a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent } 2823a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent } 28249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 28259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Post a persist volume msg 2826afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent sendMsg(mAudioHandler, 2827afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent MSG_PERSIST_VOLUME, 282898ad9b9d6fd34aad487933170f50b5519313df61Eric Laurent SENDMSG_QUEUE, 2829afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent PERSIST_CURRENT|PERSIST_LAST_AUDIBLE, 28309bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent device, 2831afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent streamState, 2832afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent PERSIST_DELAY); 2833afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent 28349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 28359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 28369bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent private void setAllVolumes(VolumeStreamState streamState) { 28379bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent 28389bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent // Apply volume 28399bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent streamState.applyAllVolumes(); 28409bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent 28419bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent // Apply change to all streams using this one as alias 28429bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent int numStreamTypes = AudioSystem.getNumStreamTypes(); 28439bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) { 28449bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent if (streamType != streamState.mStreamType && 28456d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent mStreamVolumeAlias[streamType] == streamState.mStreamType) { 28469bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent mStreamStates[streamType].applyAllVolumes(); 28479bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent } 28489bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent } 28499bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent } 28509bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent 2851afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent private void persistVolume(VolumeStreamState streamState, 28529bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent int persistType, 28539bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent int device) { 2854afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent if ((persistType & PERSIST_CURRENT) != 0) { 28559bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent System.putInt(mContentResolver, 28569bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent streamState.getSettingNameForDevice(false /* lastAudible */, device), 28579bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent (streamState.getIndex(device, false /* lastAudible */) + 5)/ 10); 285831951ca52aa007891b0be975318199e207c70e02Eric Laurent } 2859afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent if ((persistType & PERSIST_LAST_AUDIBLE) != 0) { 28609bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent System.putInt(mContentResolver, 28619bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent streamState.getSettingNameForDevice(true /* lastAudible */, device), 28629bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent (streamState.getIndex(device, true /* lastAudible */) + 5) / 10); 286331951ca52aa007891b0be975318199e207c70e02Eric Laurent } 28649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 28659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2866ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten private void persistRingerMode(int ringerMode) { 2867ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten System.putInt(mContentResolver, System.MODE_RINGER, ringerMode); 28689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 28699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 28709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private void playSoundEffect(int effectType, int volume) { 28719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project synchronized (mSoundEffectsLock) { 28729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mSoundPool == null) { 28739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return; 28749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2875a2ef57dba9ac77d8eccacd646b2b8a8d99fe9d8bEric Laurent float volFloat; 287625101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent // use default if volume is not specified by caller 2877a2ef57dba9ac77d8eccacd646b2b8a8d99fe9d8bEric Laurent if (volume < 0) { 287825101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent volFloat = (float)Math.pow(10, SOUND_EFFECT_VOLUME_DB/20); 2879a2ef57dba9ac77d8eccacd646b2b8a8d99fe9d8bEric Laurent } else { 2880a2ef57dba9ac77d8eccacd646b2b8a8d99fe9d8bEric Laurent volFloat = (float) volume / 1000.0f; 2881a2ef57dba9ac77d8eccacd646b2b8a8d99fe9d8bEric Laurent } 28829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 28839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (SOUND_EFFECT_FILES_MAP[effectType][1] > 0) { 2884a2ef57dba9ac77d8eccacd646b2b8a8d99fe9d8bEric Laurent mSoundPool.play(SOUND_EFFECT_FILES_MAP[effectType][1], volFloat, volFloat, 0, 0, 1.0f); 28859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 28869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project MediaPlayer mediaPlayer = new MediaPlayer(); 288762b9aec7a0a4e1cf8cfec7e39ea3103ab510d72eGlenn Kasten try { 288862b9aec7a0a4e1cf8cfec7e39ea3103ab510d72eGlenn Kasten String filePath = Environment.getRootDirectory() + SOUND_EFFECTS_PATH + SOUND_EFFECT_FILES[SOUND_EFFECT_FILES_MAP[effectType][0]]; 288962b9aec7a0a4e1cf8cfec7e39ea3103ab510d72eGlenn Kasten mediaPlayer.setDataSource(filePath); 289062b9aec7a0a4e1cf8cfec7e39ea3103ab510d72eGlenn Kasten mediaPlayer.setAudioStreamType(AudioSystem.STREAM_SYSTEM); 289162b9aec7a0a4e1cf8cfec7e39ea3103ab510d72eGlenn Kasten mediaPlayer.prepare(); 289262b9aec7a0a4e1cf8cfec7e39ea3103ab510d72eGlenn Kasten mediaPlayer.setVolume(volFloat, volFloat); 289362b9aec7a0a4e1cf8cfec7e39ea3103ab510d72eGlenn Kasten mediaPlayer.setOnCompletionListener(new OnCompletionListener() { 289462b9aec7a0a4e1cf8cfec7e39ea3103ab510d72eGlenn Kasten public void onCompletion(MediaPlayer mp) { 289562b9aec7a0a4e1cf8cfec7e39ea3103ab510d72eGlenn Kasten cleanupPlayer(mp); 289662b9aec7a0a4e1cf8cfec7e39ea3103ab510d72eGlenn Kasten } 289762b9aec7a0a4e1cf8cfec7e39ea3103ab510d72eGlenn Kasten }); 289862b9aec7a0a4e1cf8cfec7e39ea3103ab510d72eGlenn Kasten mediaPlayer.setOnErrorListener(new OnErrorListener() { 289962b9aec7a0a4e1cf8cfec7e39ea3103ab510d72eGlenn Kasten public boolean onError(MediaPlayer mp, int what, int extra) { 290062b9aec7a0a4e1cf8cfec7e39ea3103ab510d72eGlenn Kasten cleanupPlayer(mp); 290162b9aec7a0a4e1cf8cfec7e39ea3103ab510d72eGlenn Kasten return true; 290262b9aec7a0a4e1cf8cfec7e39ea3103ab510d72eGlenn Kasten } 290362b9aec7a0a4e1cf8cfec7e39ea3103ab510d72eGlenn Kasten }); 290462b9aec7a0a4e1cf8cfec7e39ea3103ab510d72eGlenn Kasten mediaPlayer.start(); 290562b9aec7a0a4e1cf8cfec7e39ea3103ab510d72eGlenn Kasten } catch (IOException ex) { 290662b9aec7a0a4e1cf8cfec7e39ea3103ab510d72eGlenn Kasten Log.w(TAG, "MediaPlayer IOException: "+ex); 290762b9aec7a0a4e1cf8cfec7e39ea3103ab510d72eGlenn Kasten } catch (IllegalArgumentException ex) { 290862b9aec7a0a4e1cf8cfec7e39ea3103ab510d72eGlenn Kasten Log.w(TAG, "MediaPlayer IllegalArgumentException: "+ex); 290962b9aec7a0a4e1cf8cfec7e39ea3103ab510d72eGlenn Kasten } catch (IllegalStateException ex) { 291062b9aec7a0a4e1cf8cfec7e39ea3103ab510d72eGlenn Kasten Log.w(TAG, "MediaPlayer IllegalStateException: "+ex); 29119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 29129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 29139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 29149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 29159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2916f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi private void onHandlePersistMediaButtonReceiver(ComponentName receiver) { 2917d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi Settings.System.putString(mContentResolver, Settings.System.MEDIA_BUTTON_RECEIVER, 2918d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi receiver == null ? "" : receiver.flattenToString()); 2919d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi } 2920d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi 29219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private void cleanupPlayer(MediaPlayer mp) { 29229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mp != null) { 29239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project try { 29249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mp.stop(); 29259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mp.release(); 29269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } catch (IllegalStateException ex) { 29279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Log.w(TAG, "MediaPlayer IllegalStateException: "+ex); 29289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 29299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 29309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 29319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2932fa640154f1f42121d81242b2f1a10f03e52f0014Eric Laurent private void setForceUse(int usage, int config) { 2933fa640154f1f42121d81242b2f1a10f03e52f0014Eric Laurent AudioSystem.setForceUse(usage, config); 2934fa640154f1f42121d81242b2f1a10f03e52f0014Eric Laurent } 2935fa640154f1f42121d81242b2f1a10f03e52f0014Eric Laurent 29369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @Override 29379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void handleMessage(Message msg) { 29389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2939afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent switch (msg.what) { 29409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 29419bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent case MSG_SET_DEVICE_VOLUME: 29429bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent setDeviceVolume((VolumeStreamState) msg.obj, msg.arg1); 29439bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent break; 29449bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent 29459bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent case MSG_SET_ALL_VOLUMES: 29469bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent setAllVolumes((VolumeStreamState) msg.obj); 29479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project break; 29489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 29499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project case MSG_PERSIST_VOLUME: 29509bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent persistVolume((VolumeStreamState) msg.obj, msg.arg1, msg.arg2); 29519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project break; 29529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 29535c55a051ad7d86a464fb91426f1ea3c0250e38b3Mike Lockwood case MSG_PERSIST_MASTER_VOLUME: 29545c55a051ad7d86a464fb91426f1ea3c0250e38b3Mike Lockwood Settings.System.putFloat(mContentResolver, Settings.System.VOLUME_MASTER, 29555c55a051ad7d86a464fb91426f1ea3c0250e38b3Mike Lockwood (float)msg.arg1 / (float)1000.0); 29565c55a051ad7d86a464fb91426f1ea3c0250e38b3Mike Lockwood break; 29575c55a051ad7d86a464fb91426f1ea3c0250e38b3Mike Lockwood 295857978ed86286a33d5b1a0fd000ca3406ba9d87b3Justin Koh case MSG_PERSIST_MASTER_VOLUME_MUTE: 295957978ed86286a33d5b1a0fd000ca3406ba9d87b3Justin Koh Settings.System.putInt(mContentResolver, Settings.System.VOLUME_MASTER_MUTE, 296057978ed86286a33d5b1a0fd000ca3406ba9d87b3Justin Koh msg.arg1); 296157978ed86286a33d5b1a0fd000ca3406ba9d87b3Justin Koh break; 296257978ed86286a33d5b1a0fd000ca3406ba9d87b3Justin Koh 29639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project case MSG_PERSIST_RINGER_MODE: 2964ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten // note that the value persisted is the current ringer mode, not the 2965ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten // value of ringer mode as of the time the request was made to persist 2966ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten persistRingerMode(getRingerMode()); 29679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project break; 29689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 29699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project case MSG_MEDIA_SERVER_DIED: 297089e74ba1419732dd5c7f939e48d4aa7989fd3a51Eric Laurent if (!mMediaServerOk) { 297189e74ba1419732dd5c7f939e48d4aa7989fd3a51Eric Laurent Log.e(TAG, "Media server died."); 2972a25c5d88d17f251262307ce31e799c9cf361d145Eric Laurent // Force creation of new IAudioFlinger interface so that we are notified 2973a25c5d88d17f251262307ce31e799c9cf361d145Eric Laurent // when new media_server process is back to life. 2974a25c5d88d17f251262307ce31e799c9cf361d145Eric Laurent AudioSystem.setErrorCallback(mAudioSystemCallback); 2975afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent sendMsg(mAudioHandler, MSG_MEDIA_SERVER_DIED, SENDMSG_NOOP, 0, 0, 297689e74ba1419732dd5c7f939e48d4aa7989fd3a51Eric Laurent null, 500); 297789e74ba1419732dd5c7f939e48d4aa7989fd3a51Eric Laurent } 29789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project break; 29799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 29809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project case MSG_MEDIA_SERVER_STARTED: 29819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Log.e(TAG, "Media server started."); 29823c652ca5a546e7227a5f4bdbf0f81552b2c91383Eric Laurent // indicate to audio HAL that we start the reconfiguration phase after a media 29833c652ca5a546e7227a5f4bdbf0f81552b2c91383Eric Laurent // server crash 29843c652ca5a546e7227a5f4bdbf0f81552b2c91383Eric Laurent // Note that MSG_MEDIA_SERVER_STARTED message is only received when the media server 29853c652ca5a546e7227a5f4bdbf0f81552b2c91383Eric Laurent // process restarts after a crash, not the first time it is started. 29863c652ca5a546e7227a5f4bdbf0f81552b2c91383Eric Laurent AudioSystem.setParameters("restarting=true"); 29873c652ca5a546e7227a5f4bdbf0f81552b2c91383Eric Laurent 2988c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent // Restore device connection states 29896bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent synchronized (mConnectedDevices) { 29906bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent Set set = mConnectedDevices.entrySet(); 29916bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent Iterator i = set.iterator(); 29929bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent while (i.hasNext()) { 29936bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent Map.Entry device = (Map.Entry)i.next(); 29946bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent AudioSystem.setDeviceConnectionState( 29956bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent ((Integer)device.getKey()).intValue(), 29966bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent AudioSystem.DEVICE_STATE_AVAILABLE, 29976bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent (String)device.getValue()); 29986bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent } 2999c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent } 3000c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent // Restore call state 3001c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent AudioSystem.setPhoneState(mMode); 3002c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent 3003d5603c126acdd94d9f7400bb1d04188020a425b4Eric Laurent // Restore forced usage for communcations and record 3004c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent AudioSystem.setForceUse(AudioSystem.FOR_COMMUNICATION, mForcedUseForComm); 3005d5603c126acdd94d9f7400bb1d04188020a425b4Eric Laurent AudioSystem.setForceUse(AudioSystem.FOR_RECORD, mForcedUseForComm); 3006c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent 3007a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent // Restore stream volumes 30089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int numStreamTypes = AudioSystem.getNumStreamTypes(); 30099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) { 30109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project VolumeStreamState streamState = mStreamStates[streamType]; 3011c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent AudioSystem.initStreamVolume(streamType, 0, (streamState.mIndexMax + 5) / 10); 30129bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent 30139bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent streamState.applyAllVolumes(); 30149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3015c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent 3016c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent // Restore ringer mode 3017c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent setRingerModeInt(getRingerMode(), false); 30183c652ca5a546e7227a5f4bdbf0f81552b2c91383Eric Laurent 30199063154a793b0ab38b3c5992cbaed046427b4a82Mike Lockwood // Restore master volume 30209063154a793b0ab38b3c5992cbaed046427b4a82Mike Lockwood restoreMasterVolume(); 30219063154a793b0ab38b3c5992cbaed046427b4a82Mike Lockwood 3022f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi // Reset device orientation (if monitored for this device) 3023f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi if (SystemProperties.getBoolean("ro.audio.monitorOrientation", false)) { 3024f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi setOrientationForAudioSystem(); 3025f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi } 3026f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi 30277847211fb4699bf6018e29d214a918ed6657319bEric Laurent synchronized (mBluetoothA2dpEnabledLock) { 30287847211fb4699bf6018e29d214a918ed6657319bEric Laurent AudioSystem.setForceUse(AudioSystem.FOR_MEDIA, 30297847211fb4699bf6018e29d214a918ed6657319bEric Laurent mBluetoothA2dpEnabled ? 30307847211fb4699bf6018e29d214a918ed6657319bEric Laurent AudioSystem.FORCE_NONE : AudioSystem.FORCE_NO_BT_A2DP); 30317847211fb4699bf6018e29d214a918ed6657319bEric Laurent } 30323c652ca5a546e7227a5f4bdbf0f81552b2c91383Eric Laurent // indicate the end of reconfiguration phase to audio HAL 30333c652ca5a546e7227a5f4bdbf0f81552b2c91383Eric Laurent AudioSystem.setParameters("restarting=false"); 30349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project break; 30359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3036117b7bb5b5a4457711f59bde3dcc83d8f111c524Eric Laurent case MSG_LOAD_SOUND_EFFECTS: 3037117b7bb5b5a4457711f59bde3dcc83d8f111c524Eric Laurent loadSoundEffects(); 3038117b7bb5b5a4457711f59bde3dcc83d8f111c524Eric Laurent break; 3039117b7bb5b5a4457711f59bde3dcc83d8f111c524Eric Laurent 30409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project case MSG_PLAY_SOUND_EFFECT: 30419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project playSoundEffect(msg.arg1, msg.arg2); 30429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project break; 30434c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi 30444c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi case MSG_BTA2DP_DOCK_TIMEOUT: 30454c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi // msg.obj == address of BTA2DP device 30466bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent synchronized (mConnectedDevices) { 30476bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent makeA2dpDeviceUnavailableNow( (String) msg.obj ); 30486bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent } 30494c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi break; 3050fa640154f1f42121d81242b2f1a10f03e52f0014Eric Laurent 3051fa640154f1f42121d81242b2f1a10f03e52f0014Eric Laurent case MSG_SET_FORCE_USE: 3052fa640154f1f42121d81242b2f1a10f03e52f0014Eric Laurent setForceUse(msg.arg1, msg.arg2); 3053fa640154f1f42121d81242b2f1a10f03e52f0014Eric Laurent break; 3054d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi 3055d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi case MSG_PERSIST_MEDIABUTTONRECEIVER: 3056f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi onHandlePersistMediaButtonReceiver( (ComponentName) msg.obj ); 3057d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi break; 3058dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent 30598f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi case MSG_RCDISPLAY_CLEAR: 30604426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi onRcDisplayClear(); 30618f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi break; 30628f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi 30638f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi case MSG_RCDISPLAY_UPDATE: 30644426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi // msg.obj is guaranteed to be non null 30654426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi onRcDisplayUpdate( (RemoteControlStackEntry) msg.obj, msg.arg1); 30668f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi break; 30678f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi 3068dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent case MSG_BT_HEADSET_CNCT_FAILED: 3069dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent resetBluetoothSco(); 3070dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent break; 3071b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent 3072b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent case MSG_SET_WIRED_DEVICE_CONNECTION_STATE: 3073b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent onSetWiredDeviceConnectionState(msg.arg1, msg.arg2, (String)msg.obj); 30742d8dab5a549b25b6f36df4614d7c0166d4d099e2Jean-Michel Trivi mMediaEventWakeLock.release(); 3075b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent break; 3076b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent 3077b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent case MSG_SET_A2DP_CONNECTION_STATE: 3078b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent onSetA2dpConnectionState((BluetoothDevice)msg.obj, msg.arg1); 30792d8dab5a549b25b6f36df4614d7c0166d4d099e2Jean-Michel Trivi mMediaEventWakeLock.release(); 3080b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent break; 3081632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn 3082632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn case MSG_REPORT_NEW_ROUTES: { 3083632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn int N = mRoutesObservers.beginBroadcast(); 3084632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn if (N > 0) { 3085632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn AudioRoutesInfo routes; 3086632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn synchronized (mCurAudioRoutes) { 3087632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn routes = new AudioRoutesInfo(mCurAudioRoutes); 3088632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn } 3089632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn while (N > 0) { 3090632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn N--; 3091632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn IAudioRoutesObserver obs = mRoutesObservers.getBroadcastItem(N); 3092632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn try { 3093632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn obs.dispatchAudioRoutesChanged(routes); 3094632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn } catch (RemoteException e) { 3095632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn } 3096632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn } 3097632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn } 3098632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn mRoutesObservers.finishBroadcast(); 3099632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn break; 3100632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn } 31013114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi 31023114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi case MSG_REEVALUATE_REMOTE: 31033114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi onReevaluateRemote(); 31043114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi break; 3105f98de1e8dd6dcbd191921b4aa07a1d41b0b9db91Jean-Michel Trivi 3106f98de1e8dd6dcbd191921b4aa07a1d41b0b9db91Jean-Michel Trivi case MSG_RCC_NEW_PLAYBACK_INFO: 3107f98de1e8dd6dcbd191921b4aa07a1d41b0b9db91Jean-Michel Trivi onNewPlaybackInfoForRcc(msg.arg1 /* rccId */, msg.arg2 /* key */, 3108f98de1e8dd6dcbd191921b4aa07a1d41b0b9db91Jean-Michel Trivi ((Integer)msg.obj).intValue() /* value */); 3109f98de1e8dd6dcbd191921b4aa07a1d41b0b9db91Jean-Michel Trivi break; 3110f98de1e8dd6dcbd191921b4aa07a1d41b0b9db91Jean-Michel Trivi case MSG_RCC_NEW_VOLUME_OBS: 3111f98de1e8dd6dcbd191921b4aa07a1d41b0b9db91Jean-Michel Trivi onRegisterVolumeObserverForRcc(msg.arg1 /* rccId */, 3112f98de1e8dd6dcbd191921b4aa07a1d41b0b9db91Jean-Michel Trivi (IRemoteVolumeObserver)msg.obj /* rvo */); 3113f98de1e8dd6dcbd191921b4aa07a1d41b0b9db91Jean-Michel Trivi break; 31149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 31159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 31169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 31179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3118b109615ebebd6f3b9ae789412279f576c3ace46bJason Parekh private class SettingsObserver extends ContentObserver { 3119a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent 3120b109615ebebd6f3b9ae789412279f576c3ace46bJason Parekh SettingsObserver() { 3121b109615ebebd6f3b9ae789412279f576c3ace46bJason Parekh super(new Handler()); 3122b109615ebebd6f3b9ae789412279f576c3ace46bJason Parekh mContentResolver.registerContentObserver(Settings.System.getUriFor( 3123b109615ebebd6f3b9ae789412279f576c3ace46bJason Parekh Settings.System.MODE_RINGER_STREAMS_AFFECTED), false, this); 3124b109615ebebd6f3b9ae789412279f576c3ace46bJason Parekh } 3125b109615ebebd6f3b9ae789412279f576c3ace46bJason Parekh 3126b109615ebebd6f3b9ae789412279f576c3ace46bJason Parekh @Override 3127b109615ebebd6f3b9ae789412279f576c3ace46bJason Parekh public void onChange(boolean selfChange) { 3128b109615ebebd6f3b9ae789412279f576c3ace46bJason Parekh super.onChange(selfChange); 3129ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten // FIXME This synchronized is not necessary if mSettingsLock only protects mRingerMode. 3130ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten // However there appear to be some missing locks around mRingerModeMutedStreams 3131ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten // and mRingerModeAffectedStreams, so will leave this synchronized for now. 3132ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten // mRingerModeMutedStreams and mMuteAffectedStreams are safe (only accessed once). 3133a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent synchronized (mSettingsLock) { 3134a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent int ringerModeAffectedStreams = Settings.System.getInt(mContentResolver, 3135c1d4166289ce016965d1147f7e8d37862ee347ecEric Laurent Settings.System.MODE_RINGER_STREAMS_AFFECTED, 3136c1d4166289ce016965d1147f7e8d37862ee347ecEric Laurent ((1 << AudioSystem.STREAM_RING)|(1 << AudioSystem.STREAM_NOTIFICATION)| 3137c1d4166289ce016965d1147f7e8d37862ee347ecEric Laurent (1 << AudioSystem.STREAM_SYSTEM)|(1 << AudioSystem.STREAM_SYSTEM_ENFORCED))); 3138c1d4166289ce016965d1147f7e8d37862ee347ecEric Laurent if (mVoiceCapable) { 3139c1d4166289ce016965d1147f7e8d37862ee347ecEric Laurent ringerModeAffectedStreams &= ~(1 << AudioSystem.STREAM_MUSIC); 3140c1d4166289ce016965d1147f7e8d37862ee347ecEric Laurent } else { 3141402f7f29634a9f68e7929be828a927a3e2f5efe9Eric Laurent ringerModeAffectedStreams |= (1 << AudioSystem.STREAM_MUSIC); 3142402f7f29634a9f68e7929be828a927a3e2f5efe9Eric Laurent } 3143a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent if (ringerModeAffectedStreams != mRingerModeAffectedStreams) { 3144a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent /* 3145a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent * Ensure all stream types that should be affected by ringer mode 3146a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent * are in the proper state. 3147a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent */ 3148a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent mRingerModeAffectedStreams = ringerModeAffectedStreams; 3149a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent setRingerModeInt(getRingerMode(), false); 3150a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent } 3151a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent } 3152b109615ebebd6f3b9ae789412279f576c3ace46bJason Parekh } 3153b109615ebebd6f3b9ae789412279f576c3ace46bJason Parekh } 3154a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent 31556bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent // must be called synchronized on mConnectedDevices 31564c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi private void makeA2dpDeviceAvailable(String address) { 31577847211fb4699bf6018e29d214a918ed6657319bEric Laurent // enable A2DP before notifying A2DP connection to avoid unecessary processing in 31587847211fb4699bf6018e29d214a918ed6657319bEric Laurent // audio policy manager 31597847211fb4699bf6018e29d214a918ed6657319bEric Laurent setBluetoothA2dpOnInt(true); 31604c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, 31614c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi AudioSystem.DEVICE_STATE_AVAILABLE, 31624c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi address); 31634c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi // Reset A2DP suspend state each time a new sink is connected 31644c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi AudioSystem.setParameters("A2dpSuspended=false"); 31654c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi mConnectedDevices.put( new Integer(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP), 31664c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi address); 31674c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi } 31684c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi 31699841818b9a0280abf59343c9e00a2976dbc084faMike Lockwood private void sendBecomingNoisyIntent() { 31709841818b9a0280abf59343c9e00a2976dbc084faMike Lockwood mContext.sendBroadcast(new Intent(AudioManager.ACTION_AUDIO_BECOMING_NOISY)); 31719841818b9a0280abf59343c9e00a2976dbc084faMike Lockwood } 31729841818b9a0280abf59343c9e00a2976dbc084faMike Lockwood 31736bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent // must be called synchronized on mConnectedDevices 31744c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi private void makeA2dpDeviceUnavailableNow(String address) { 31754c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, 31764c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi AudioSystem.DEVICE_STATE_UNAVAILABLE, 31774c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi address); 31784c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi mConnectedDevices.remove(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP); 31794c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi } 31804c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi 31816bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent // must be called synchronized on mConnectedDevices 31824c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi private void makeA2dpDeviceUnavailableLater(String address) { 31833b5912602bec6ccbe8eef8a576730b1565f0067cEric Laurent // prevent any activity on the A2DP audio output to avoid unwanted 31843b5912602bec6ccbe8eef8a576730b1565f0067cEric Laurent // reconnection of the sink. 31853b5912602bec6ccbe8eef8a576730b1565f0067cEric Laurent AudioSystem.setParameters("A2dpSuspended=true"); 31864c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi // the device will be made unavailable later, so consider it disconnected right away 31874c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi mConnectedDevices.remove(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP); 31884c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi // send the delayed message to make the device unavailable later 31894c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi Message msg = mAudioHandler.obtainMessage(MSG_BTA2DP_DOCK_TIMEOUT, address); 31904c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi mAudioHandler.sendMessageDelayed(msg, BTA2DP_DOCK_TIMEOUT_MILLIS); 31914c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi 31924c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi } 31934c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi 31946bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent // must be called synchronized on mConnectedDevices 3195a847ba4080675d395de725cfac5dfd9d5a993d4eJean-Michel Trivi private void cancelA2dpDeviceTimeout() { 31964c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi mAudioHandler.removeMessages(MSG_BTA2DP_DOCK_TIMEOUT); 31974c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi } 31984c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi 31996bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent // must be called synchronized on mConnectedDevices 3200a847ba4080675d395de725cfac5dfd9d5a993d4eJean-Michel Trivi private boolean hasScheduledA2dpDockTimeout() { 3201a847ba4080675d395de725cfac5dfd9d5a993d4eJean-Michel Trivi return mAudioHandler.hasMessages(MSG_BTA2DP_DOCK_TIMEOUT); 3202a847ba4080675d395de725cfac5dfd9d5a993d4eJean-Michel Trivi } 3203a847ba4080675d395de725cfac5dfd9d5a993d4eJean-Michel Trivi 3204b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent private void onSetA2dpConnectionState(BluetoothDevice btDevice, int state) 32056bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent { 32066bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent if (btDevice == null) { 32076bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent return; 32086bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent } 32096bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent String address = btDevice.getAddress(); 32106bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent if (!BluetoothAdapter.checkBluetoothAddress(address)) { 32116bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent address = ""; 32126bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent } 32136bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent synchronized (mConnectedDevices) { 32146bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent boolean isConnected = 32156bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent (mConnectedDevices.containsKey(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP) && 32166bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent mConnectedDevices.get(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP).equals(address)); 32176bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent 32186bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent if (isConnected && state != BluetoothProfile.STATE_CONNECTED) { 32196bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent if (btDevice.isBluetoothDock()) { 32206bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent if (state == BluetoothProfile.STATE_DISCONNECTED) { 32216bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent // introduction of a delay for transient disconnections of docks when 32226bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent // power is rapidly turned off/on, this message will be canceled if 32236bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent // we reconnect the dock under a preset delay 32246bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent makeA2dpDeviceUnavailableLater(address); 32256bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent // the next time isConnected is evaluated, it will be false for the dock 32266bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent } 32276bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent } else { 32286bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent makeA2dpDeviceUnavailableNow(address); 32296bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent } 3230632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn synchronized (mCurAudioRoutes) { 3231632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn if (mCurAudioRoutes.mBluetoothName != null) { 3232632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn mCurAudioRoutes.mBluetoothName = null; 3233632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn sendMsg(mAudioHandler, MSG_REPORT_NEW_ROUTES, 3234632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn SENDMSG_NOOP, 0, 0, null, 0); 3235632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn } 3236632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn } 32376bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent } else if (!isConnected && state == BluetoothProfile.STATE_CONNECTED) { 32386bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent if (btDevice.isBluetoothDock()) { 32396bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent // this could be a reconnection after a transient disconnection 32406bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent cancelA2dpDeviceTimeout(); 32416bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent mDockAddress = address; 32426bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent } else { 32436bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent // this could be a connection of another A2DP device before the timeout of 32446bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent // a dock: cancel the dock timeout, and make the dock unavailable now 32456bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent if(hasScheduledA2dpDockTimeout()) { 32466bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent cancelA2dpDeviceTimeout(); 32476bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent makeA2dpDeviceUnavailableNow(mDockAddress); 32486bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent } 32496bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent } 32506bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent makeA2dpDeviceAvailable(address); 3251632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn synchronized (mCurAudioRoutes) { 3252632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn String name = btDevice.getAliasName(); 3253632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn if (!TextUtils.equals(mCurAudioRoutes.mBluetoothName, name)) { 3254632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn mCurAudioRoutes.mBluetoothName = name; 3255632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn sendMsg(mAudioHandler, MSG_REPORT_NEW_ROUTES, 3256632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn SENDMSG_NOOP, 0, 0, null, 0); 3257632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn } 3258632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn } 32596bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent } 32606bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent } 32616bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent } 32626bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent 326359f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent private boolean handleDeviceConnection(boolean connected, int device, String params) { 326459f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent synchronized (mConnectedDevices) { 326559f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent boolean isConnected = (mConnectedDevices.containsKey(device) && 32669841818b9a0280abf59343c9e00a2976dbc084faMike Lockwood (params.isEmpty() || mConnectedDevices.get(device).equals(params))); 326759f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent 326859f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent if (isConnected && !connected) { 326959f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent AudioSystem.setDeviceConnectionState(device, 327059f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent AudioSystem.DEVICE_STATE_UNAVAILABLE, 32719841818b9a0280abf59343c9e00a2976dbc084faMike Lockwood mConnectedDevices.get(device)); 327259f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent mConnectedDevices.remove(device); 327359f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent return true; 327459f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent } else if (!isConnected && connected) { 327559f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent AudioSystem.setDeviceConnectionState(device, 327659f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent AudioSystem.DEVICE_STATE_AVAILABLE, 327759f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent params); 327859f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent mConnectedDevices.put(new Integer(device), params); 327959f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent return true; 328059f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent } 328159f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent } 328259f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent return false; 328359f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent } 328459f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent 3285b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent // Devices which removal triggers intent ACTION_AUDIO_BECOMING_NOISY. The intent is only 3286b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent // sent if none of these devices is connected. 3287b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent int mBecomingNoisyIntentDevices = 3288b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent AudioSystem.DEVICE_OUT_WIRED_HEADSET | AudioSystem.DEVICE_OUT_WIRED_HEADPHONE | 3289b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent AudioSystem.DEVICE_OUT_ALL_A2DP; 3290b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent 3291b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent // must be called before removing the device from mConnectedDevices 3292b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent private int checkSendBecomingNoisyIntent(int device, int state) { 3293b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent int delay = 0; 3294b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent if ((state == 0) && ((device & mBecomingNoisyIntentDevices) != 0)) { 3295b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent int devices = 0; 3296b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent for (int dev : mConnectedDevices.keySet()) { 3297b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent if ((dev & mBecomingNoisyIntentDevices) != 0) { 3298b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent devices |= dev; 3299b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent } 3300b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent } 3301b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent if (devices == device) { 3302b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent delay = 1000; 3303b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent sendBecomingNoisyIntent(); 3304b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent } 3305b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent } 3306b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent 3307b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent if (mAudioHandler.hasMessages(MSG_SET_A2DP_CONNECTION_STATE) || 3308b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent mAudioHandler.hasMessages(MSG_SET_WIRED_DEVICE_CONNECTION_STATE)) { 3309b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent delay = 1000; 3310b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent } 3311b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent return delay; 3312b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent } 3313b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent 3314b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent private void sendDeviceConnectionIntent(int device, int state, String name) 3315b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent { 3316b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent Intent intent = new Intent(); 3317b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent 3318b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent intent.putExtra("state", state); 3319b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent intent.putExtra("name", name); 3320b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY); 3321b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent 3322632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn int connType = 0; 3323632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn 3324b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent if (device == AudioSystem.DEVICE_OUT_WIRED_HEADSET) { 3325632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn connType = AudioRoutesInfo.MAIN_HEADSET; 3326b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent intent.setAction(Intent.ACTION_HEADSET_PLUG); 3327b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent intent.putExtra("microphone", 1); 3328b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent } else if (device == AudioSystem.DEVICE_OUT_WIRED_HEADPHONE) { 3329632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn connType = AudioRoutesInfo.MAIN_HEADPHONES; 3330b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent intent.setAction(Intent.ACTION_HEADSET_PLUG); 3331b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent intent.putExtra("microphone", 0); 3332b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent } else if (device == AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET) { 3333632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn connType = AudioRoutesInfo.MAIN_DOCK_SPEAKERS; 3334b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent intent.setAction(Intent.ACTION_ANALOG_AUDIO_DOCK_PLUG); 3335b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent } else if (device == AudioSystem.DEVICE_OUT_DGTL_DOCK_HEADSET) { 3336632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn connType = AudioRoutesInfo.MAIN_DOCK_SPEAKERS; 3337b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent intent.setAction(Intent.ACTION_DIGITAL_AUDIO_DOCK_PLUG); 3338b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent } else if (device == AudioSystem.DEVICE_OUT_AUX_DIGITAL) { 3339632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn connType = AudioRoutesInfo.MAIN_HDMI; 3340b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent intent.setAction(Intent.ACTION_HDMI_AUDIO_PLUG); 3341b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent } 3342b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent 3343632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn synchronized (mCurAudioRoutes) { 3344632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn if (connType != 0) { 3345632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn int newConn = mCurAudioRoutes.mMainType; 3346632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn if (state != 0) { 3347632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn newConn |= connType; 3348632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn } else { 3349632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn newConn &= ~connType; 3350632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn } 3351632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn if (newConn != mCurAudioRoutes.mMainType) { 3352632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn mCurAudioRoutes.mMainType = newConn; 3353632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn sendMsg(mAudioHandler, MSG_REPORT_NEW_ROUTES, 3354632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn SENDMSG_NOOP, 0, 0, null, 0); 3355632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn } 3356632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn } 3357632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn } 3358632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn 3359b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent ActivityManagerNative.broadcastStickyIntent(intent, null); 3360b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent } 3361b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent 3362b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent private void onSetWiredDeviceConnectionState(int device, int state, String name) 3363b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent { 3364b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent synchronized (mConnectedDevices) { 3365b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent if ((state == 0) && ((device == AudioSystem.DEVICE_OUT_WIRED_HEADSET) || 3366b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent (device == AudioSystem.DEVICE_OUT_WIRED_HEADPHONE))) { 3367b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent setBluetoothA2dpOnInt(true); 3368b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent } 3369b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent handleDeviceConnection((state == 1), device, ""); 3370b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent if ((state != 0) && ((device == AudioSystem.DEVICE_OUT_WIRED_HEADSET) || 3371b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent (device == AudioSystem.DEVICE_OUT_WIRED_HEADPHONE))) { 3372b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent setBluetoothA2dpOnInt(false); 3373b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent } 3374b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent sendDeviceConnectionIntent(device, state, name); 3375b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent } 3376b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent } 3377b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent 3378a847ba4080675d395de725cfac5dfd9d5a993d4eJean-Michel Trivi /* cache of the address of the last dock the device was connected to */ 3379a847ba4080675d395de725cfac5dfd9d5a993d4eJean-Michel Trivi private String mDockAddress; 3380a847ba4080675d395de725cfac5dfd9d5a993d4eJean-Michel Trivi 3381a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent /** 3382a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent * Receiver for misc intent broadcasts the Phone app cares about. 3383a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent */ 3384a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent private class AudioServiceBroadcastReceiver extends BroadcastReceiver { 3385a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent @Override 3386a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent public void onReceive(Context context, Intent intent) { 3387a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent String action = intent.getAction(); 338859f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent int device; 338959f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent int state; 3390a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent 3391758559e6b7e310cf46cc269437f44decd58d68d6Jean-Michel Trivi if (action.equals(Intent.ACTION_DOCK_EVENT)) { 3392758559e6b7e310cf46cc269437f44decd58d68d6Jean-Michel Trivi int dockState = intent.getIntExtra(Intent.EXTRA_DOCK_STATE, 3393758559e6b7e310cf46cc269437f44decd58d68d6Jean-Michel Trivi Intent.EXTRA_DOCK_STATE_UNDOCKED); 3394758559e6b7e310cf46cc269437f44decd58d68d6Jean-Michel Trivi int config; 3395758559e6b7e310cf46cc269437f44decd58d68d6Jean-Michel Trivi switch (dockState) { 3396758559e6b7e310cf46cc269437f44decd58d68d6Jean-Michel Trivi case Intent.EXTRA_DOCK_STATE_DESK: 3397758559e6b7e310cf46cc269437f44decd58d68d6Jean-Michel Trivi config = AudioSystem.FORCE_BT_DESK_DOCK; 3398758559e6b7e310cf46cc269437f44decd58d68d6Jean-Michel Trivi break; 3399758559e6b7e310cf46cc269437f44decd58d68d6Jean-Michel Trivi case Intent.EXTRA_DOCK_STATE_CAR: 3400758559e6b7e310cf46cc269437f44decd58d68d6Jean-Michel Trivi config = AudioSystem.FORCE_BT_CAR_DOCK; 3401758559e6b7e310cf46cc269437f44decd58d68d6Jean-Michel Trivi break; 340221e941bf43362ddc6639a9f2d0828053360f53d7Praveen Bharathi case Intent.EXTRA_DOCK_STATE_LE_DESK: 340321e941bf43362ddc6639a9f2d0828053360f53d7Praveen Bharathi config = AudioSystem.FORCE_ANALOG_DOCK; 340421e941bf43362ddc6639a9f2d0828053360f53d7Praveen Bharathi break; 340521e941bf43362ddc6639a9f2d0828053360f53d7Praveen Bharathi case Intent.EXTRA_DOCK_STATE_HE_DESK: 340621e941bf43362ddc6639a9f2d0828053360f53d7Praveen Bharathi config = AudioSystem.FORCE_DIGITAL_DOCK; 340721e941bf43362ddc6639a9f2d0828053360f53d7Praveen Bharathi break; 3408758559e6b7e310cf46cc269437f44decd58d68d6Jean-Michel Trivi case Intent.EXTRA_DOCK_STATE_UNDOCKED: 3409758559e6b7e310cf46cc269437f44decd58d68d6Jean-Michel Trivi default: 3410758559e6b7e310cf46cc269437f44decd58d68d6Jean-Michel Trivi config = AudioSystem.FORCE_NONE; 3411758559e6b7e310cf46cc269437f44decd58d68d6Jean-Michel Trivi } 3412758559e6b7e310cf46cc269437f44decd58d68d6Jean-Michel Trivi AudioSystem.setForceUse(AudioSystem.FOR_DOCK, config); 341382aa7f017daaaeb96c13e6e3491d5037ab471085Jaikumar Ganesh } else if (action.equals(BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED)) { 341459f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent state = intent.getIntExtra(BluetoothProfile.EXTRA_STATE, 341582aa7f017daaaeb96c13e6e3491d5037ab471085Jaikumar Ganesh BluetoothProfile.STATE_DISCONNECTED); 341659f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent device = AudioSystem.DEVICE_OUT_BLUETOOTH_SCO; 3417a56d1c72190462aa9e377906583eceb58e0efcddNick Pelly String address = null; 3418dca56b9432e2cc851d1a58920071fed2e1e3d142Eric Laurent 3419dca56b9432e2cc851d1a58920071fed2e1e3d142Eric Laurent BluetoothDevice btDevice = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); 3420dca56b9432e2cc851d1a58920071fed2e1e3d142Eric Laurent if (btDevice == null) { 3421dca56b9432e2cc851d1a58920071fed2e1e3d142Eric Laurent return; 3422dca56b9432e2cc851d1a58920071fed2e1e3d142Eric Laurent } 3423dca56b9432e2cc851d1a58920071fed2e1e3d142Eric Laurent 3424dca56b9432e2cc851d1a58920071fed2e1e3d142Eric Laurent address = btDevice.getAddress(); 3425dca56b9432e2cc851d1a58920071fed2e1e3d142Eric Laurent BluetoothClass btClass = btDevice.getBluetoothClass(); 3426dca56b9432e2cc851d1a58920071fed2e1e3d142Eric Laurent if (btClass != null) { 3427dca56b9432e2cc851d1a58920071fed2e1e3d142Eric Laurent switch (btClass.getDeviceClass()) { 3428dca56b9432e2cc851d1a58920071fed2e1e3d142Eric Laurent case BluetoothClass.Device.AUDIO_VIDEO_WEARABLE_HEADSET: 3429dca56b9432e2cc851d1a58920071fed2e1e3d142Eric Laurent case BluetoothClass.Device.AUDIO_VIDEO_HANDSFREE: 3430dca56b9432e2cc851d1a58920071fed2e1e3d142Eric Laurent device = AudioSystem.DEVICE_OUT_BLUETOOTH_SCO_HEADSET; 3431dca56b9432e2cc851d1a58920071fed2e1e3d142Eric Laurent break; 3432dca56b9432e2cc851d1a58920071fed2e1e3d142Eric Laurent case BluetoothClass.Device.AUDIO_VIDEO_CAR_AUDIO: 3433dca56b9432e2cc851d1a58920071fed2e1e3d142Eric Laurent device = AudioSystem.DEVICE_OUT_BLUETOOTH_SCO_CARKIT; 3434dca56b9432e2cc851d1a58920071fed2e1e3d142Eric Laurent break; 3435d5603c126acdd94d9f7400bb1d04188020a425b4Eric Laurent } 3436d5603c126acdd94d9f7400bb1d04188020a425b4Eric Laurent } 3437d5603c126acdd94d9f7400bb1d04188020a425b4Eric Laurent 3438dca56b9432e2cc851d1a58920071fed2e1e3d142Eric Laurent if (!BluetoothAdapter.checkBluetoothAddress(address)) { 3439dca56b9432e2cc851d1a58920071fed2e1e3d142Eric Laurent address = ""; 3440dca56b9432e2cc851d1a58920071fed2e1e3d142Eric Laurent } 3441d5603c126acdd94d9f7400bb1d04188020a425b4Eric Laurent 344259f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent boolean connected = (state == BluetoothProfile.STATE_CONNECTED); 344359f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent if (handleDeviceConnection(connected, device, address)) { 34446bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent synchronized (mScoClients) { 344559f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent if (connected) { 344659f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent mBluetoothHeadsetDevice = btDevice; 344759f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent } else { 34486bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent mBluetoothHeadsetDevice = null; 34496bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent resetBluetoothSco(); 34506bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent } 345162ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent } 3452a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent } 345359f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent } else if (action.equals(Intent.ACTION_USB_AUDIO_ACCESSORY_PLUG) || 345459f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent action.equals(Intent.ACTION_USB_AUDIO_DEVICE_PLUG)) { 345559f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent state = intent.getIntExtra("state", 0); 345659f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent int alsaCard = intent.getIntExtra("card", -1); 345759f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent int alsaDevice = intent.getIntExtra("device", -1); 34589841818b9a0280abf59343c9e00a2976dbc084faMike Lockwood String params = (alsaCard == -1 && alsaDevice == -1 ? "" 34599841818b9a0280abf59343c9e00a2976dbc084faMike Lockwood : "card=" + alsaCard + ";device=" + alsaDevice); 346059f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent device = action.equals(Intent.ACTION_USB_AUDIO_ACCESSORY_PLUG) ? 346159f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent AudioSystem.DEVICE_OUT_USB_ACCESSORY : AudioSystem.DEVICE_OUT_USB_DEVICE; 346259f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent Log.v(TAG, "Broadcast Receiver: Got " 346359f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent + (action.equals(Intent.ACTION_USB_AUDIO_ACCESSORY_PLUG) ? 346459f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent "ACTION_USB_AUDIO_ACCESSORY_PLUG" : "ACTION_USB_AUDIO_DEVICE_PLUG") 346559f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent + ", state = " + state + ", card: " + alsaCard + ", device: " + alsaDevice); 346659f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent handleDeviceConnection((state == 1), device, params); 34673def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent } else if (action.equals(BluetoothHeadset.ACTION_AUDIO_STATE_CHANGED)) { 346862ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent boolean broadcast = false; 346959f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent int scoAudioState = AudioManager.SCO_AUDIO_STATE_ERROR; 34703def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent synchronized (mScoClients) { 347162ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent int btState = intent.getIntExtra(BluetoothProfile.EXTRA_STATE, -1); 3472dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent // broadcast intent if the connection was initated by AudioService 3473dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent if (!mScoClients.isEmpty() && 3474dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent (mScoAudioState == SCO_STATE_ACTIVE_INTERNAL || 3475dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent mScoAudioState == SCO_STATE_ACTIVATE_REQ || 3476dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent mScoAudioState == SCO_STATE_DEACTIVATE_REQ)) { 347762ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent broadcast = true; 347862ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent } 347962ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent switch (btState) { 348062ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent case BluetoothHeadset.STATE_AUDIO_CONNECTED: 348159f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent scoAudioState = AudioManager.SCO_AUDIO_STATE_CONNECTED; 3482dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent if (mScoAudioState != SCO_STATE_ACTIVE_INTERNAL && 3483dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent mScoAudioState != SCO_STATE_DEACTIVATE_REQ && 3484dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent mScoAudioState != SCO_STATE_DEACTIVATE_EXT_REQ) { 348562ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent mScoAudioState = SCO_STATE_ACTIVE_EXTERNAL; 34863def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent } 348762ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent break; 348862ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent case BluetoothHeadset.STATE_AUDIO_DISCONNECTED: 348959f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent scoAudioState = AudioManager.SCO_AUDIO_STATE_DISCONNECTED; 349062ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent mScoAudioState = SCO_STATE_INACTIVE; 3491d7454be47f4111c0478a502353e11dea401378bdEric Laurent clearAllScoClients(0, false); 349262ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent break; 349362ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent case BluetoothHeadset.STATE_AUDIO_CONNECTING: 3494dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent if (mScoAudioState != SCO_STATE_ACTIVE_INTERNAL && 3495dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent mScoAudioState != SCO_STATE_DEACTIVATE_REQ && 3496dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent mScoAudioState != SCO_STATE_DEACTIVATE_EXT_REQ) { 349762ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent mScoAudioState = SCO_STATE_ACTIVE_EXTERNAL; 34983def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent } 349962ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent default: 350062ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent // do not broadcast CONNECTING or invalid state 350162ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent broadcast = false; 350262ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent break; 35033def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent } 35043def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent } 350562ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent if (broadcast) { 350659f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent broadcastScoConnectionState(scoAudioState); 3507dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent //FIXME: this is to maintain compatibility with deprecated intent 3508dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent // AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED. Remove when appropriate. 350962ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent Intent newIntent = new Intent(AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED); 351059f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent newIntent.putExtra(AudioManager.EXTRA_SCO_AUDIO_STATE, scoAudioState); 351162ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent mContext.sendStickyBroadcast(newIntent); 351262ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent } 351362ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent } else if (action.equals(Intent.ACTION_BOOT_COMPLETED)) { 3514a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent mBootCompleted = true; 3515afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent sendMsg(mAudioHandler, MSG_LOAD_SOUND_EFFECTS, SENDMSG_NOOP, 3516117b7bb5b5a4457711f59bde3dcc83d8f111c524Eric Laurent 0, 0, null, 0); 3517dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent 35186243edd818b84adfbe712d5d233d6414b33653acAmith Yamasani mKeyguardManager = 35196243edd818b84adfbe712d5d233d6414b33653acAmith Yamasani (KeyguardManager) mContext.getSystemService(Context.KEYGUARD_SERVICE); 3520dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent mScoConnectionState = AudioManager.SCO_AUDIO_STATE_ERROR; 3521dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent resetBluetoothSco(); 3522dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent getBluetoothHeadset(); 3523dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent //FIXME: this is to maintain compatibility with deprecated intent 3524dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent // AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED. Remove when appropriate. 352562ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent Intent newIntent = new Intent(AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED); 352662ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent newIntent.putExtra(AudioManager.EXTRA_SCO_AUDIO_STATE, 352762ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent AudioManager.SCO_AUDIO_STATE_DISCONNECTED); 352862ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent mContext.sendStickyBroadcast(newIntent); 35296bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent 35306bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter(); 35316bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent if (adapter != null) { 35326bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent adapter.getProfileProxy(mContext, mBluetoothProfileServiceListener, 35336bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent BluetoothProfile.A2DP); 35346bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent } 3535d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi } else if (action.equals(Intent.ACTION_PACKAGE_REMOVED)) { 3536d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi if (!intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) { 3537d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi // a package is being removed, not replaced 3538d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi String packageName = intent.getData().getSchemeSpecificPart(); 3539d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi if (packageName != null) { 3540d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi removeMediaButtonReceiverForPackage(packageName); 3541d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi } 3542d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi } 3543950e8cb40a6d826af4cc2eef9d3908c1b70486e6Eric Laurent } else if (action.equals(Intent.ACTION_SCREEN_ON)) { 3544950e8cb40a6d826af4cc2eef9d3908c1b70486e6Eric Laurent AudioSystem.setParameters("screen_state=on"); 3545950e8cb40a6d826af4cc2eef9d3908c1b70486e6Eric Laurent } else if (action.equals(Intent.ACTION_SCREEN_OFF)) { 3546950e8cb40a6d826af4cc2eef9d3908c1b70486e6Eric Laurent AudioSystem.setParameters("screen_state=off"); 3547f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi } else if (action.equalsIgnoreCase(Intent.ACTION_CONFIGURATION_CHANGED)) { 3548f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi handleConfigurationChanged(context); 3549a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent } 3550a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent } 3551a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent } 3552d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi 3553d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi //========================================================================================== 3554d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi // AudioFocus 3555d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi //========================================================================================== 3556b4bccb6d8df16a2c5235cead187156bc721cf074Jean-Michel Trivi 3557b4bccb6d8df16a2c5235cead187156bc721cf074Jean-Michel Trivi /* constant to identify focus stack entry that is used to hold the focus while the phone 35584dd3674e517051f130fef36d2eb201c68ff61094Jean-Michel Trivi * is ringing or during a call. Used by com.android.internal.telephony.CallManager when 35594dd3674e517051f130fef36d2eb201c68ff61094Jean-Michel Trivi * entering and exiting calls. 3560e5e1e870fdb35f5291790e6d178bde7126f6fe35Jean-Michel Trivi */ 35614dd3674e517051f130fef36d2eb201c68ff61094Jean-Michel Trivi public final static String IN_VOICE_COMM_FOCUS_ID = "AudioFocus_For_Phone_Ring_And_Calls"; 3562e5e1e870fdb35f5291790e6d178bde7126f6fe35Jean-Michel Trivi 3563392a2bbb52688ebd25768a7784d9edca7f498110Jean-Michel Trivi private final static Object mAudioFocusLock = new Object(); 3564392a2bbb52688ebd25768a7784d9edca7f498110Jean-Michel Trivi 3565e73131a68408a0495ba96a4d5a60799ba293c176Jean-Michel Trivi private final static Object mRingingLock = new Object(); 3566e73131a68408a0495ba96a4d5a60799ba293c176Jean-Michel Trivi 3567b4bccb6d8df16a2c5235cead187156bc721cf074Jean-Michel Trivi private PhoneStateListener mPhoneStateListener = new PhoneStateListener() { 3568b4bccb6d8df16a2c5235cead187156bc721cf074Jean-Michel Trivi @Override 3569b4bccb6d8df16a2c5235cead187156bc721cf074Jean-Michel Trivi public void onCallStateChanged(int state, String incomingNumber) { 3570b4bccb6d8df16a2c5235cead187156bc721cf074Jean-Michel Trivi if (state == TelephonyManager.CALL_STATE_RINGING) { 3571b4bccb6d8df16a2c5235cead187156bc721cf074Jean-Michel Trivi //Log.v(TAG, " CALL_STATE_RINGING"); 3572e73131a68408a0495ba96a4d5a60799ba293c176Jean-Michel Trivi synchronized(mRingingLock) { 3573e73131a68408a0495ba96a4d5a60799ba293c176Jean-Michel Trivi mIsRinging = true; 3574e73131a68408a0495ba96a4d5a60799ba293c176Jean-Michel Trivi } 35752ade576148fe33c5ff6098d30ccfbcf28df70e8eJean-Michel Trivi } else if ((state == TelephonyManager.CALL_STATE_OFFHOOK) 35762ade576148fe33c5ff6098d30ccfbcf28df70e8eJean-Michel Trivi || (state == TelephonyManager.CALL_STATE_IDLE)) { 3577e73131a68408a0495ba96a4d5a60799ba293c176Jean-Michel Trivi synchronized(mRingingLock) { 3578e73131a68408a0495ba96a4d5a60799ba293c176Jean-Michel Trivi mIsRinging = false; 3579e73131a68408a0495ba96a4d5a60799ba293c176Jean-Michel Trivi } 3580e5e1e870fdb35f5291790e6d178bde7126f6fe35Jean-Michel Trivi } 3581e5e1e870fdb35f5291790e6d178bde7126f6fe35Jean-Michel Trivi } 3582b4bccb6d8df16a2c5235cead187156bc721cf074Jean-Michel Trivi }; 3583e5e1e870fdb35f5291790e6d178bde7126f6fe35Jean-Michel Trivi 3584e5e1e870fdb35f5291790e6d178bde7126f6fe35Jean-Michel Trivi private void notifyTopOfAudioFocusStack() { 3585e5e1e870fdb35f5291790e6d178bde7126f6fe35Jean-Michel Trivi // notify the top of the stack it gained focus 3586e5e1e870fdb35f5291790e6d178bde7126f6fe35Jean-Michel Trivi if (!mFocusStack.empty() && (mFocusStack.peek().mFocusDispatcher != null)) { 3587e5e1e870fdb35f5291790e6d178bde7126f6fe35Jean-Michel Trivi if (canReassignAudioFocus()) { 3588e5e1e870fdb35f5291790e6d178bde7126f6fe35Jean-Michel Trivi try { 3589e5e1e870fdb35f5291790e6d178bde7126f6fe35Jean-Michel Trivi mFocusStack.peek().mFocusDispatcher.dispatchAudioFocusChange( 3590e5e1e870fdb35f5291790e6d178bde7126f6fe35Jean-Michel Trivi AudioManager.AUDIOFOCUS_GAIN, mFocusStack.peek().mClientId); 3591e5e1e870fdb35f5291790e6d178bde7126f6fe35Jean-Michel Trivi } catch (RemoteException e) { 3592e5e1e870fdb35f5291790e6d178bde7126f6fe35Jean-Michel Trivi Log.e(TAG, "Failure to signal gain of audio control focus due to "+ e); 3593e5e1e870fdb35f5291790e6d178bde7126f6fe35Jean-Michel Trivi e.printStackTrace(); 3594e5e1e870fdb35f5291790e6d178bde7126f6fe35Jean-Michel Trivi } 3595e5e1e870fdb35f5291790e6d178bde7126f6fe35Jean-Michel Trivi } 3596e5e1e870fdb35f5291790e6d178bde7126f6fe35Jean-Michel Trivi } 3597e5e1e870fdb35f5291790e6d178bde7126f6fe35Jean-Michel Trivi } 3598e5e1e870fdb35f5291790e6d178bde7126f6fe35Jean-Michel Trivi 3599d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi private static class FocusStackEntry { 3600d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi public int mStreamType = -1;// no stream type 3601d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi public IAudioFocusDispatcher mFocusDispatcher = null; 3602d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi public IBinder mSourceRef = null; 3603d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi public String mClientId; 3604078fd47e91d495175927d1a4a8b9aad039a7ba4eJean-Michel Trivi public int mFocusChangeType; 3605061214bb71a4a4211e670001226c68f5e8036b84Jean-Michel Trivi public AudioFocusDeathHandler mHandler; 36068f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi public String mPackageName; 36078f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi public int mCallingUid; 3608d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi 3609d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi public FocusStackEntry() { 3610d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi } 3611d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi 36128f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi public FocusStackEntry(int streamType, int duration, 3613061214bb71a4a4211e670001226c68f5e8036b84Jean-Michel Trivi IAudioFocusDispatcher afl, IBinder source, String id, AudioFocusDeathHandler hdlr, 3614061214bb71a4a4211e670001226c68f5e8036b84Jean-Michel Trivi String pn, int uid) { 3615d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi mStreamType = streamType; 3616d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi mFocusDispatcher = afl; 3617d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi mSourceRef = source; 3618d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi mClientId = id; 3619078fd47e91d495175927d1a4a8b9aad039a7ba4eJean-Michel Trivi mFocusChangeType = duration; 3620061214bb71a4a4211e670001226c68f5e8036b84Jean-Michel Trivi mHandler = hdlr; 36218f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi mPackageName = pn; 36228f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi mCallingUid = uid; 3623d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi } 3624061214bb71a4a4211e670001226c68f5e8036b84Jean-Michel Trivi 3625e7edc868538e83152e7bc35c830fee0d629baefcJean-Michel Trivi public void unlinkToDeath() { 3626e7edc868538e83152e7bc35c830fee0d629baefcJean-Michel Trivi try { 3627e7edc868538e83152e7bc35c830fee0d629baefcJean-Michel Trivi if (mSourceRef != null && mHandler != null) { 3628e7edc868538e83152e7bc35c830fee0d629baefcJean-Michel Trivi mSourceRef.unlinkToDeath(mHandler, 0); 3629e7edc868538e83152e7bc35c830fee0d629baefcJean-Michel Trivi mHandler = null; 3630e7edc868538e83152e7bc35c830fee0d629baefcJean-Michel Trivi } 3631e7edc868538e83152e7bc35c830fee0d629baefcJean-Michel Trivi } catch (java.util.NoSuchElementException e) { 3632e7edc868538e83152e7bc35c830fee0d629baefcJean-Michel Trivi Log.e(TAG, "Encountered " + e + " in FocusStackEntry.unlinkToDeath()"); 3633061214bb71a4a4211e670001226c68f5e8036b84Jean-Michel Trivi } 3634061214bb71a4a4211e670001226c68f5e8036b84Jean-Michel Trivi } 3635de1f065be109e1c313d8330c8e34210fedaac74eJean-Michel Trivi 3636de1f065be109e1c313d8330c8e34210fedaac74eJean-Michel Trivi @Override 3637de1f065be109e1c313d8330c8e34210fedaac74eJean-Michel Trivi protected void finalize() throws Throwable { 3638e7edc868538e83152e7bc35c830fee0d629baefcJean-Michel Trivi unlinkToDeath(); // unlink exception handled inside method 3639e7edc868538e83152e7bc35c830fee0d629baefcJean-Michel Trivi super.finalize(); 3640de1f065be109e1c313d8330c8e34210fedaac74eJean-Michel Trivi } 3641d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi } 3642d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi 364330c918ce7fbe171944b28fc91b3f22b3d631872dGlenn Kasten private final Stack<FocusStackEntry> mFocusStack = new Stack<FocusStackEntry>(); 3644d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi 3645d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi /** 3646d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi * Helper function: 3647d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi * Display in the log the current entries in the audio focus stack 3648d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi */ 3649d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi private void dumpFocusStack(PrintWriter pw) { 3650b4bccb6d8df16a2c5235cead187156bc721cf074Jean-Michel Trivi pw.println("\nAudio Focus stack entries:"); 3651392a2bbb52688ebd25768a7784d9edca7f498110Jean-Michel Trivi synchronized(mAudioFocusLock) { 3652d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi Iterator<FocusStackEntry> stackIterator = mFocusStack.iterator(); 3653d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi while(stackIterator.hasNext()) { 3654d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi FocusStackEntry fse = stackIterator.next(); 3655d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi pw.println(" source:" + fse.mSourceRef + " -- client: " + fse.mClientId 36568f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi + " -- duration: " + fse.mFocusChangeType 36578f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi + " -- uid: " + fse.mCallingUid); 3658d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi } 3659d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi } 3660d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi } 3661d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi 3662d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi /** 3663d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi * Helper function: 36648f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi * Called synchronized on mAudioFocusLock 3665d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi * Remove a focus listener from the focus stack. 3666d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi * @param focusListenerToRemove the focus listener 3667d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi * @param signal if true and the listener was at the top of the focus stack, i.e. it was holding 3668d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi * focus, notify the next item in the stack it gained focus. 3669d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi */ 3670d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi private void removeFocusStackEntry(String clientToRemove, boolean signal) { 3671e7edc868538e83152e7bc35c830fee0d629baefcJean-Michel Trivi // is the current top of the focus stack abandoning focus? (because of request, not death) 3672d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi if (!mFocusStack.empty() && mFocusStack.peek().mClientId.equals(clientToRemove)) 3673d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi { 3674d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi //Log.i(TAG, " removeFocusStackEntry() removing top of stack"); 3675e7edc868538e83152e7bc35c830fee0d629baefcJean-Michel Trivi FocusStackEntry fse = mFocusStack.pop(); 3676e7edc868538e83152e7bc35c830fee0d629baefcJean-Michel Trivi fse.unlinkToDeath(); 3677d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi if (signal) { 3678d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi // notify the new top of the stack it gained focus 3679e5e1e870fdb35f5291790e6d178bde7126f6fe35Jean-Michel Trivi notifyTopOfAudioFocusStack(); 36808f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi // there's a new top of the stack, let the remote control know 36818f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi synchronized(mRCStack) { 3682b716f0b7b2d8e4b045843fc6a7004910eb344c19Jean-Michel Trivi checkUpdateRemoteControlDisplay_syncAfRcs(RC_INFO_ALL); 36838f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi } 3684d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi } 3685d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi } else { 3686d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi // focus is abandoned by a client that's not at the top of the stack, 3687d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi // no need to update focus. 3688d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi Iterator<FocusStackEntry> stackIterator = mFocusStack.iterator(); 3689d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi while(stackIterator.hasNext()) { 3690d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi FocusStackEntry fse = (FocusStackEntry)stackIterator.next(); 3691d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi if(fse.mClientId.equals(clientToRemove)) { 3692d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi Log.i(TAG, " AudioFocus abandonAudioFocus(): removing entry for " 3693d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi + fse.mClientId); 369472843377d50a8f95cceaf33d316ab68d9b47f2ebJean-Michel Trivi stackIterator.remove(); 3695e7edc868538e83152e7bc35c830fee0d629baefcJean-Michel Trivi fse.unlinkToDeath(); 3696d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi } 3697d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi } 3698d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi } 3699d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi } 3700d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi 3701d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi /** 3702d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi * Helper function: 37038f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi * Called synchronized on mAudioFocusLock 3704e7edc868538e83152e7bc35c830fee0d629baefcJean-Michel Trivi * Remove focus listeners from the focus stack for a particular client when it has died. 3705d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi */ 3706d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi private void removeFocusStackEntryForClient(IBinder cb) { 3707e5e1e870fdb35f5291790e6d178bde7126f6fe35Jean-Michel Trivi // is the owner of the audio focus part of the client to remove? 3708e5e1e870fdb35f5291790e6d178bde7126f6fe35Jean-Michel Trivi boolean isTopOfStackForClientToRemove = !mFocusStack.isEmpty() && 3709e5e1e870fdb35f5291790e6d178bde7126f6fe35Jean-Michel Trivi mFocusStack.peek().mSourceRef.equals(cb); 3710d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi Iterator<FocusStackEntry> stackIterator = mFocusStack.iterator(); 3711d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi while(stackIterator.hasNext()) { 3712d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi FocusStackEntry fse = (FocusStackEntry)stackIterator.next(); 3713d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi if(fse.mSourceRef.equals(cb)) { 3714d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi Log.i(TAG, " AudioFocus abandonAudioFocus(): removing entry for " 3715d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi + fse.mClientId); 371672843377d50a8f95cceaf33d316ab68d9b47f2ebJean-Michel Trivi stackIterator.remove(); 3717e7edc868538e83152e7bc35c830fee0d629baefcJean-Michel Trivi // the client just died, no need to unlink to its death 3718d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi } 3719d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi } 3720e5e1e870fdb35f5291790e6d178bde7126f6fe35Jean-Michel Trivi if (isTopOfStackForClientToRemove) { 3721e5e1e870fdb35f5291790e6d178bde7126f6fe35Jean-Michel Trivi // we removed an entry at the top of the stack: 3722e5e1e870fdb35f5291790e6d178bde7126f6fe35Jean-Michel Trivi // notify the new top of the stack it gained focus. 3723e5e1e870fdb35f5291790e6d178bde7126f6fe35Jean-Michel Trivi notifyTopOfAudioFocusStack(); 37248f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi // there's a new top of the stack, let the remote control know 37258f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi synchronized(mRCStack) { 3726b716f0b7b2d8e4b045843fc6a7004910eb344c19Jean-Michel Trivi checkUpdateRemoteControlDisplay_syncAfRcs(RC_INFO_ALL); 37278f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi } 3728e5e1e870fdb35f5291790e6d178bde7126f6fe35Jean-Michel Trivi } 3729d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi } 3730d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi 3731d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi /** 3732d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi * Helper function: 3733d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi * Returns true if the system is in a state where the focus can be reevaluated, false otherwise. 3734d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi */ 3735d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi private boolean canReassignAudioFocus() { 3736b4bccb6d8df16a2c5235cead187156bc721cf074Jean-Michel Trivi // focus requests are rejected during a phone call or when the phone is ringing 3737b4bccb6d8df16a2c5235cead187156bc721cf074Jean-Michel Trivi // this is equivalent to IN_VOICE_COMM_FOCUS_ID having the focus 3738b4bccb6d8df16a2c5235cead187156bc721cf074Jean-Michel Trivi if (!mFocusStack.isEmpty() && IN_VOICE_COMM_FOCUS_ID.equals(mFocusStack.peek().mClientId)) { 3739d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi return false; 3740d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi } 3741d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi return true; 3742d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi } 3743d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi 3744d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi /** 3745d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi * Inner class to monitor audio focus client deaths, and remove them from the audio focus 3746d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi * stack if necessary. 3747d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi */ 3748d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi private class AudioFocusDeathHandler implements IBinder.DeathRecipient { 3749d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi private IBinder mCb; // To be notified of client's death 3750d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi 3751d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi AudioFocusDeathHandler(IBinder cb) { 3752d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi mCb = cb; 3753d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi } 3754d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi 3755d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi public void binderDied() { 3756392a2bbb52688ebd25768a7784d9edca7f498110Jean-Michel Trivi synchronized(mAudioFocusLock) { 3757d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi Log.w(TAG, " AudioFocus audio focus client died"); 3758d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi removeFocusStackEntryForClient(mCb); 3759d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi } 3760d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi } 3761d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi 3762d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi public IBinder getBinder() { 3763d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi return mCb; 3764d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi } 3765d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi } 3766d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi 3767d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi 3768d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi /** @see AudioManager#requestAudioFocus(IAudioFocusDispatcher, int, int) */ 3769078fd47e91d495175927d1a4a8b9aad039a7ba4eJean-Michel Trivi public int requestAudioFocus(int mainStreamType, int focusChangeHint, IBinder cb, 37708f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi IAudioFocusDispatcher fd, String clientId, String callingPackageName) { 3771d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi Log.i(TAG, " AudioFocus requestAudioFocus() from " + clientId); 3772d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi // the main stream type for the audio focus request is currently not used. It may 3773d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi // potentially be used to handle multiple stream type-dependent audio focuses. 3774d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi 3775382f4e6ea4dcf39105b36364582ed01642daa93cJean-Michel Trivi // we need a valid binder callback for clients 3776382f4e6ea4dcf39105b36364582ed01642daa93cJean-Michel Trivi if (!cb.pingBinder()) { 3777382f4e6ea4dcf39105b36364582ed01642daa93cJean-Michel Trivi Log.e(TAG, " AudioFocus DOA client for requestAudioFocus(), aborting."); 3778d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi return AudioManager.AUDIOFOCUS_REQUEST_FAILED; 3779d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi } 3780d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi 3781392a2bbb52688ebd25768a7784d9edca7f498110Jean-Michel Trivi synchronized(mAudioFocusLock) { 3782392a2bbb52688ebd25768a7784d9edca7f498110Jean-Michel Trivi if (!canReassignAudioFocus()) { 3783392a2bbb52688ebd25768a7784d9edca7f498110Jean-Michel Trivi return AudioManager.AUDIOFOCUS_REQUEST_FAILED; 3784392a2bbb52688ebd25768a7784d9edca7f498110Jean-Michel Trivi } 3785d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi 3786baf674eedd5ecff9da0cf8cabe9868f7699b1695Jean-Michel Trivi // handle the potential premature death of the new holder of the focus 3787baf674eedd5ecff9da0cf8cabe9868f7699b1695Jean-Michel Trivi // (premature death == death before abandoning focus) 3788baf674eedd5ecff9da0cf8cabe9868f7699b1695Jean-Michel Trivi // Register for client death notification 3789baf674eedd5ecff9da0cf8cabe9868f7699b1695Jean-Michel Trivi AudioFocusDeathHandler afdh = new AudioFocusDeathHandler(cb); 3790baf674eedd5ecff9da0cf8cabe9868f7699b1695Jean-Michel Trivi try { 3791baf674eedd5ecff9da0cf8cabe9868f7699b1695Jean-Michel Trivi cb.linkToDeath(afdh, 0); 3792baf674eedd5ecff9da0cf8cabe9868f7699b1695Jean-Michel Trivi } catch (RemoteException e) { 3793baf674eedd5ecff9da0cf8cabe9868f7699b1695Jean-Michel Trivi // client has already died! 3794baf674eedd5ecff9da0cf8cabe9868f7699b1695Jean-Michel Trivi Log.w(TAG, "AudioFocus requestAudioFocus() could not link to "+cb+" binder death"); 3795baf674eedd5ecff9da0cf8cabe9868f7699b1695Jean-Michel Trivi return AudioManager.AUDIOFOCUS_REQUEST_FAILED; 3796baf674eedd5ecff9da0cf8cabe9868f7699b1695Jean-Michel Trivi } 3797baf674eedd5ecff9da0cf8cabe9868f7699b1695Jean-Michel Trivi 3798d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi if (!mFocusStack.empty() && mFocusStack.peek().mClientId.equals(clientId)) { 3799e5e1e870fdb35f5291790e6d178bde7126f6fe35Jean-Michel Trivi // if focus is already owned by this client and the reason for acquiring the focus 3800e5e1e870fdb35f5291790e6d178bde7126f6fe35Jean-Michel Trivi // hasn't changed, don't do anything 3801e5e1e870fdb35f5291790e6d178bde7126f6fe35Jean-Michel Trivi if (mFocusStack.peek().mFocusChangeType == focusChangeHint) { 3802de1f065be109e1c313d8330c8e34210fedaac74eJean-Michel Trivi // unlink death handler so it can be gc'ed. 3803de1f065be109e1c313d8330c8e34210fedaac74eJean-Michel Trivi // linkToDeath() creates a JNI global reference preventing collection. 3804de1f065be109e1c313d8330c8e34210fedaac74eJean-Michel Trivi cb.unlinkToDeath(afdh, 0); 3805e5e1e870fdb35f5291790e6d178bde7126f6fe35Jean-Michel Trivi return AudioManager.AUDIOFOCUS_REQUEST_GRANTED; 3806e5e1e870fdb35f5291790e6d178bde7126f6fe35Jean-Michel Trivi } 3807e5e1e870fdb35f5291790e6d178bde7126f6fe35Jean-Michel Trivi // the reason for the audio focus request has changed: remove the current top of 3808e5e1e870fdb35f5291790e6d178bde7126f6fe35Jean-Michel Trivi // stack and respond as if we had a new focus owner 3809e7edc868538e83152e7bc35c830fee0d629baefcJean-Michel Trivi FocusStackEntry fse = mFocusStack.pop(); 3810e7edc868538e83152e7bc35c830fee0d629baefcJean-Michel Trivi fse.unlinkToDeath(); 3811d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi } 3812d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi 3813d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi // notify current top of stack it is losing focus 3814d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi if (!mFocusStack.empty() && (mFocusStack.peek().mFocusDispatcher != null)) { 3815d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi try { 3816d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi mFocusStack.peek().mFocusDispatcher.dispatchAudioFocusChange( 3817078fd47e91d495175927d1a4a8b9aad039a7ba4eJean-Michel Trivi -1 * focusChangeHint, // loss and gain codes are inverse of each other 3818d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi mFocusStack.peek().mClientId); 3819d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi } catch (RemoteException e) { 3820d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi Log.e(TAG, " Failure to signal loss of focus due to "+ e); 3821d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi e.printStackTrace(); 3822d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi } 3823d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi } 3824d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi 382555d1bb3483e17a11d122e68044e552d96ab55ff4Jean-Michel Trivi // focus requester might already be somewhere below in the stack, remove it 3826baf674eedd5ecff9da0cf8cabe9868f7699b1695Jean-Michel Trivi removeFocusStackEntry(clientId, false /* signal */); 3827061214bb71a4a4211e670001226c68f5e8036b84Jean-Michel Trivi 3828d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi // push focus requester at the top of the audio focus stack 38298f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi mFocusStack.push(new FocusStackEntry(mainStreamType, focusChangeHint, fd, cb, 3830061214bb71a4a4211e670001226c68f5e8036b84Jean-Michel Trivi clientId, afdh, callingPackageName, Binder.getCallingUid())); 38318f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi 38328f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi // there's a new top of the stack, let the remote control know 38338f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi synchronized(mRCStack) { 3834b716f0b7b2d8e4b045843fc6a7004910eb344c19Jean-Michel Trivi checkUpdateRemoteControlDisplay_syncAfRcs(RC_INFO_ALL); 38358f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi } 3836392a2bbb52688ebd25768a7784d9edca7f498110Jean-Michel Trivi }//synchronized(mAudioFocusLock) 3837d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi 3838d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi return AudioManager.AUDIOFOCUS_REQUEST_GRANTED; 3839d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi } 3840d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi 3841d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi /** @see AudioManager#abandonAudioFocus(IAudioFocusDispatcher) */ 3842d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi public int abandonAudioFocus(IAudioFocusDispatcher fl, String clientId) { 3843d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi Log.i(TAG, " AudioFocus abandonAudioFocus() from " + clientId); 3844392a2bbb52688ebd25768a7784d9edca7f498110Jean-Michel Trivi try { 3845392a2bbb52688ebd25768a7784d9edca7f498110Jean-Michel Trivi // this will take care of notifying the new focus owner if needed 3846392a2bbb52688ebd25768a7784d9edca7f498110Jean-Michel Trivi synchronized(mAudioFocusLock) { 3847392a2bbb52688ebd25768a7784d9edca7f498110Jean-Michel Trivi removeFocusStackEntry(clientId, true); 3848392a2bbb52688ebd25768a7784d9edca7f498110Jean-Michel Trivi } 3849392a2bbb52688ebd25768a7784d9edca7f498110Jean-Michel Trivi } catch (java.util.ConcurrentModificationException cme) { 3850392a2bbb52688ebd25768a7784d9edca7f498110Jean-Michel Trivi // Catching this exception here is temporary. It is here just to prevent 3851392a2bbb52688ebd25768a7784d9edca7f498110Jean-Michel Trivi // a crash seen when the "Silent" notification is played. This is believed to be fixed 3852392a2bbb52688ebd25768a7784d9edca7f498110Jean-Michel Trivi // but this try catch block is left just to be safe. 3853392a2bbb52688ebd25768a7784d9edca7f498110Jean-Michel Trivi Log.e(TAG, "FATAL EXCEPTION AudioFocus abandonAudioFocus() caused " + cme); 3854392a2bbb52688ebd25768a7784d9edca7f498110Jean-Michel Trivi cme.printStackTrace(); 38552930bb2d47be279dd228ba8c749c1e39e5da8be1Jean-Michel Trivi } 3856d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi 3857d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi return AudioManager.AUDIOFOCUS_REQUEST_GRANTED; 3858d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi } 3859d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi 3860d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi 3861d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi public void unregisterAudioFocusClient(String clientId) { 3862392a2bbb52688ebd25768a7784d9edca7f498110Jean-Michel Trivi synchronized(mAudioFocusLock) { 38632930bb2d47be279dd228ba8c749c1e39e5da8be1Jean-Michel Trivi removeFocusStackEntry(clientId, false); 38642930bb2d47be279dd228ba8c749c1e39e5da8be1Jean-Michel Trivi } 3865d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi } 3866d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi 3867d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi 3868d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi //========================================================================================== 3869d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi // RemoteControl 3870d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi //========================================================================================== 3871c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi public void dispatchMediaKeyEvent(KeyEvent keyEvent) { 38724294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi filterMediaKeyEvent(keyEvent, false /*needWakeLock*/); 3873c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi } 3874c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi 3875c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi public void dispatchMediaKeyEventUnderWakelock(KeyEvent keyEvent) { 38764294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi filterMediaKeyEvent(keyEvent, true /*needWakeLock*/); 3877c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi } 3878c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi 38794294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi private void filterMediaKeyEvent(KeyEvent keyEvent, boolean needWakeLock) { 3880c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi // sanity check on the incoming key event 3881c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi if (!isValidMediaKeyEvent(keyEvent)) { 3882c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi Log.e(TAG, "not dispatching invalid media key event " + keyEvent); 3883c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi return; 3884c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi } 3885722b808662eb20fa91151f1e3aa05fd911d1d226Jean-Michel Trivi // event filtering for telephony 3886c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi synchronized(mRingingLock) { 3887722b808662eb20fa91151f1e3aa05fd911d1d226Jean-Michel Trivi synchronized(mRCStack) { 3888722b808662eb20fa91151f1e3aa05fd911d1d226Jean-Michel Trivi if ((mMediaReceiverForCalls != null) && 3889722b808662eb20fa91151f1e3aa05fd911d1d226Jean-Michel Trivi (mIsRinging || (getMode() == AudioSystem.MODE_IN_CALL))) { 3890722b808662eb20fa91151f1e3aa05fd911d1d226Jean-Michel Trivi dispatchMediaKeyEventForCalls(keyEvent, needWakeLock); 3891722b808662eb20fa91151f1e3aa05fd911d1d226Jean-Michel Trivi return; 3892722b808662eb20fa91151f1e3aa05fd911d1d226Jean-Michel Trivi } 3893d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi } 3894c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi } 38954294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi // event filtering based on voice-based interactions 38964294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi if (isValidVoiceInputKeyCode(keyEvent.getKeyCode())) { 38974294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi filterVoiceInputKeyEvent(keyEvent, needWakeLock); 38984294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi } else { 38994294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi dispatchMediaKeyEvent(keyEvent, needWakeLock); 39004294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi } 39014294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi } 39024294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi 39034294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi /** 3904722b808662eb20fa91151f1e3aa05fd911d1d226Jean-Michel Trivi * Handles the dispatching of the media button events to the telephony package. 3905722b808662eb20fa91151f1e3aa05fd911d1d226Jean-Michel Trivi * Precondition: mMediaReceiverForCalls != null 3906722b808662eb20fa91151f1e3aa05fd911d1d226Jean-Michel Trivi * @param keyEvent a non-null KeyEvent whose key code is one of the supported media buttons 3907722b808662eb20fa91151f1e3aa05fd911d1d226Jean-Michel Trivi * @param needWakeLock true if a PARTIAL_WAKE_LOCK needs to be held while this key event 3908722b808662eb20fa91151f1e3aa05fd911d1d226Jean-Michel Trivi * is dispatched. 3909722b808662eb20fa91151f1e3aa05fd911d1d226Jean-Michel Trivi */ 3910722b808662eb20fa91151f1e3aa05fd911d1d226Jean-Michel Trivi private void dispatchMediaKeyEventForCalls(KeyEvent keyEvent, boolean needWakeLock) { 3911722b808662eb20fa91151f1e3aa05fd911d1d226Jean-Michel Trivi Intent keyIntent = new Intent(Intent.ACTION_MEDIA_BUTTON, null); 3912722b808662eb20fa91151f1e3aa05fd911d1d226Jean-Michel Trivi keyIntent.putExtra(Intent.EXTRA_KEY_EVENT, keyEvent); 3913722b808662eb20fa91151f1e3aa05fd911d1d226Jean-Michel Trivi keyIntent.setPackage(mMediaReceiverForCalls.getPackageName()); 3914722b808662eb20fa91151f1e3aa05fd911d1d226Jean-Michel Trivi if (needWakeLock) { 3915722b808662eb20fa91151f1e3aa05fd911d1d226Jean-Michel Trivi mMediaEventWakeLock.acquire(); 3916722b808662eb20fa91151f1e3aa05fd911d1d226Jean-Michel Trivi keyIntent.putExtra(EXTRA_WAKELOCK_ACQUIRED, WAKELOCK_RELEASE_ON_FINISHED); 3917722b808662eb20fa91151f1e3aa05fd911d1d226Jean-Michel Trivi } 3918722b808662eb20fa91151f1e3aa05fd911d1d226Jean-Michel Trivi mContext.sendOrderedBroadcast(keyIntent, null, mKeyEventDone, 3919722b808662eb20fa91151f1e3aa05fd911d1d226Jean-Michel Trivi mAudioHandler, Activity.RESULT_OK, null, null); 3920722b808662eb20fa91151f1e3aa05fd911d1d226Jean-Michel Trivi } 3921722b808662eb20fa91151f1e3aa05fd911d1d226Jean-Michel Trivi 3922722b808662eb20fa91151f1e3aa05fd911d1d226Jean-Michel Trivi /** 39234294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi * Handles the dispatching of the media button events to one of the registered listeners, 39244294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi * or if there was none, broadcast an ACTION_MEDIA_BUTTON intent to the rest of the system. 39254294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi * @param keyEvent a non-null KeyEvent whose key code is one of the supported media buttons 39264294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi * @param needWakeLock true if a PARTIAL_WAKE_LOCK needs to be held while this key event 39274294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi * is dispatched. 39284294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi */ 39294294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi private void dispatchMediaKeyEvent(KeyEvent keyEvent, boolean needWakeLock) { 3930c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi if (needWakeLock) { 3931c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi mMediaEventWakeLock.acquire(); 3932c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi } 3933c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi Intent keyIntent = new Intent(Intent.ACTION_MEDIA_BUTTON, null); 3934c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi keyIntent.putExtra(Intent.EXTRA_KEY_EVENT, keyEvent); 3935c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi synchronized(mRCStack) { 3936c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi if (!mRCStack.empty()) { 3937c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi // send the intent that was registered by the client 3938c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi try { 3939c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi mRCStack.peek().mMediaIntent.send(mContext, 3940c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi needWakeLock ? WAKELOCK_RELEASE_ON_FINISHED : 0 /*code*/, 3941c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi keyIntent, AudioService.this, mAudioHandler); 3942c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi } catch (CanceledException e) { 3943c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi Log.e(TAG, "Error sending pending intent " + mRCStack.peek()); 3944c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi e.printStackTrace(); 3945d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi } 3946c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi } else { 3947c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi // legacy behavior when nobody registered their media button event receiver 3948c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi // through AudioManager 3949c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi if (needWakeLock) { 3950c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi keyIntent.putExtra(EXTRA_WAKELOCK_ACQUIRED, WAKELOCK_RELEASE_ON_FINISHED); 3951d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi } 3952c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi mContext.sendOrderedBroadcast(keyIntent, null, mKeyEventDone, 3953c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi mAudioHandler, Activity.RESULT_OK, null, null); 3954d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi } 3955d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi } 3956d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi } 3957d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi 39584294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi /** 3959ab624c2fd4f0fad6ba7f422a960942e5a7035ceaJeff Brown * The different actions performed in response to a voice button key event. 39604294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi */ 39614294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi private final static int VOICEBUTTON_ACTION_DISCARD_CURRENT_KEY_PRESS = 1; 39624294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi private final static int VOICEBUTTON_ACTION_START_VOICE_INPUT = 2; 39634294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi private final static int VOICEBUTTON_ACTION_SIMULATE_KEY_PRESS = 3; 39644294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi 39654294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi private final Object mVoiceEventLock = new Object(); 3966ab624c2fd4f0fad6ba7f422a960942e5a7035ceaJeff Brown private boolean mVoiceButtonDown; 3967ab624c2fd4f0fad6ba7f422a960942e5a7035ceaJeff Brown private boolean mVoiceButtonHandled; 39684294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi 39694294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi /** 39704294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi * Filter key events that may be used for voice-based interactions 39714294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi * @param keyEvent a non-null KeyEvent whose key code is that of one of the supported 39724294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi * media buttons that can be used to trigger voice-based interactions. 39734294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi * @param needWakeLock true if a PARTIAL_WAKE_LOCK needs to be held while this key event 39744294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi * is dispatched. 39754294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi */ 39764294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi private void filterVoiceInputKeyEvent(KeyEvent keyEvent, boolean needWakeLock) { 3977ab624c2fd4f0fad6ba7f422a960942e5a7035ceaJeff Brown if (DEBUG_RC) { 3978ab624c2fd4f0fad6ba7f422a960942e5a7035ceaJeff Brown Log.v(TAG, "voice input key event: " + keyEvent + ", needWakeLock=" + needWakeLock); 3979ab624c2fd4f0fad6ba7f422a960942e5a7035ceaJeff Brown } 3980ab624c2fd4f0fad6ba7f422a960942e5a7035ceaJeff Brown 39814294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi int voiceButtonAction = VOICEBUTTON_ACTION_DISCARD_CURRENT_KEY_PRESS; 39824294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi int keyAction = keyEvent.getAction(); 39834294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi synchronized (mVoiceEventLock) { 3984ab624c2fd4f0fad6ba7f422a960942e5a7035ceaJeff Brown if (keyAction == KeyEvent.ACTION_DOWN) { 3985ab624c2fd4f0fad6ba7f422a960942e5a7035ceaJeff Brown if (keyEvent.getRepeatCount() == 0) { 3986ab624c2fd4f0fad6ba7f422a960942e5a7035ceaJeff Brown // initial down 3987ab624c2fd4f0fad6ba7f422a960942e5a7035ceaJeff Brown mVoiceButtonDown = true; 3988ab624c2fd4f0fad6ba7f422a960942e5a7035ceaJeff Brown mVoiceButtonHandled = false; 3989ab624c2fd4f0fad6ba7f422a960942e5a7035ceaJeff Brown } else if (mVoiceButtonDown && !mVoiceButtonHandled 3990ab624c2fd4f0fad6ba7f422a960942e5a7035ceaJeff Brown && (keyEvent.getFlags() & KeyEvent.FLAG_LONG_PRESS) != 0) { 3991ab624c2fd4f0fad6ba7f422a960942e5a7035ceaJeff Brown // long-press, start voice-based interactions 3992ab624c2fd4f0fad6ba7f422a960942e5a7035ceaJeff Brown mVoiceButtonHandled = true; 3993ab624c2fd4f0fad6ba7f422a960942e5a7035ceaJeff Brown voiceButtonAction = VOICEBUTTON_ACTION_START_VOICE_INPUT; 3994ab624c2fd4f0fad6ba7f422a960942e5a7035ceaJeff Brown } 3995ab624c2fd4f0fad6ba7f422a960942e5a7035ceaJeff Brown } else if (keyAction == KeyEvent.ACTION_UP) { 3996ab624c2fd4f0fad6ba7f422a960942e5a7035ceaJeff Brown if (mVoiceButtonDown) { 3997ab624c2fd4f0fad6ba7f422a960942e5a7035ceaJeff Brown // voice button up 3998ab624c2fd4f0fad6ba7f422a960942e5a7035ceaJeff Brown mVoiceButtonDown = false; 3999ab624c2fd4f0fad6ba7f422a960942e5a7035ceaJeff Brown if (!mVoiceButtonHandled && !keyEvent.isCanceled()) { 4000ab624c2fd4f0fad6ba7f422a960942e5a7035ceaJeff Brown voiceButtonAction = VOICEBUTTON_ACTION_SIMULATE_KEY_PRESS; 40014294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi } 4002ab624c2fd4f0fad6ba7f422a960942e5a7035ceaJeff Brown } 40034294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi } 40044294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi }//synchronized (mVoiceEventLock) 40054294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi 40064294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi // take action after media button event filtering for voice-based interactions 40074294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi switch (voiceButtonAction) { 40084294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi case VOICEBUTTON_ACTION_DISCARD_CURRENT_KEY_PRESS: 40094294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi if (DEBUG_RC) Log.v(TAG, " ignore key event"); 40104294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi break; 40114294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi case VOICEBUTTON_ACTION_START_VOICE_INPUT: 40124294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi if (DEBUG_RC) Log.v(TAG, " start voice-based interactions"); 40134294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi // then start the voice-based interactions 40144294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi startVoiceBasedInteractions(needWakeLock); 40154294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi break; 40164294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi case VOICEBUTTON_ACTION_SIMULATE_KEY_PRESS: 40174294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi if (DEBUG_RC) Log.v(TAG, " send simulated key event"); 40184294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi sendSimulatedMediaButtonEvent(keyEvent, needWakeLock); 40194294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi break; 40204294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi } 40214294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi } 40224294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi 40234294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi private void sendSimulatedMediaButtonEvent(KeyEvent originalKeyEvent, boolean needWakeLock) { 40244294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi // send DOWN event 40254294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi KeyEvent keyEvent = KeyEvent.changeAction(originalKeyEvent, KeyEvent.ACTION_DOWN); 40264294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi dispatchMediaKeyEvent(keyEvent, needWakeLock); 40274294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi // send UP event 40284294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi keyEvent = KeyEvent.changeAction(originalKeyEvent, KeyEvent.ACTION_UP); 40294294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi dispatchMediaKeyEvent(keyEvent, needWakeLock); 40304294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi 40314294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi } 40324294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi 40334294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi 4034c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi private static boolean isValidMediaKeyEvent(KeyEvent keyEvent) { 4035c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi if (keyEvent == null) { 4036c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi return false; 4037c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi } 4038c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi final int keyCode = keyEvent.getKeyCode(); 4039c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi switch (keyCode) { 4040c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi case KeyEvent.KEYCODE_MUTE: 4041c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi case KeyEvent.KEYCODE_HEADSETHOOK: 4042c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi case KeyEvent.KEYCODE_MEDIA_PLAY: 4043c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi case KeyEvent.KEYCODE_MEDIA_PAUSE: 4044c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE: 4045c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi case KeyEvent.KEYCODE_MEDIA_STOP: 4046c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi case KeyEvent.KEYCODE_MEDIA_NEXT: 4047c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi case KeyEvent.KEYCODE_MEDIA_PREVIOUS: 4048c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi case KeyEvent.KEYCODE_MEDIA_REWIND: 4049c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi case KeyEvent.KEYCODE_MEDIA_RECORD: 4050c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi case KeyEvent.KEYCODE_MEDIA_FAST_FORWARD: 4051c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi case KeyEvent.KEYCODE_MEDIA_CLOSE: 4052c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi case KeyEvent.KEYCODE_MEDIA_EJECT: 4053c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi break; 4054c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi default: 4055c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi return false; 4056c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi } 4057c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi return true; 4058c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi } 4059c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi 40604294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi /** 40614294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi * Checks whether the given key code is one that can trigger the launch of voice-based 40624294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi * interactions. 40634294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi * @param keyCode the key code associated with the key event 40644294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi * @return true if the key is one of the supported voice-based interaction triggers 40654294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi */ 40664294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi private static boolean isValidVoiceInputKeyCode(int keyCode) { 40674294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi if (keyCode == KeyEvent.KEYCODE_HEADSETHOOK) { 40684294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi return true; 40694294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi } else { 40704294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi return false; 40714294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi } 40724294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi } 40734294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi 40744294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi /** 40754294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi * Tell the system to start voice-based interactions / voice commands 40764294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi */ 40774294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi private void startVoiceBasedInteractions(boolean needWakeLock) { 40783c2711fc2853394324b044632b79ca67388df8f4Jean-Michel Trivi Intent voiceIntent = null; 40793c2711fc2853394324b044632b79ca67388df8f4Jean-Michel Trivi // select which type of search to launch: 40803c2711fc2853394324b044632b79ca67388df8f4Jean-Michel Trivi // - screen on and device unlocked: action is ACTION_WEB_SEARCH 40813c2711fc2853394324b044632b79ca67388df8f4Jean-Michel Trivi // - device locked or screen off: action is ACTION_VOICE_SEARCH_HANDS_FREE 40823c2711fc2853394324b044632b79ca67388df8f4Jean-Michel Trivi // with EXTRA_SECURE set to true if the device is securely locked 40833c2711fc2853394324b044632b79ca67388df8f4Jean-Michel Trivi PowerManager pm = (PowerManager)mContext.getSystemService(Context.POWER_SERVICE); 40843c2711fc2853394324b044632b79ca67388df8f4Jean-Michel Trivi boolean isLocked = mKeyguardManager != null && mKeyguardManager.isKeyguardLocked(); 40853c2711fc2853394324b044632b79ca67388df8f4Jean-Michel Trivi if (!isLocked && pm.isScreenOn()) { 40863c2711fc2853394324b044632b79ca67388df8f4Jean-Michel Trivi voiceIntent = new Intent(android.speech.RecognizerIntent.ACTION_WEB_SEARCH); 40873c2711fc2853394324b044632b79ca67388df8f4Jean-Michel Trivi } else { 40883c2711fc2853394324b044632b79ca67388df8f4Jean-Michel Trivi voiceIntent = new Intent(RecognizerIntent.ACTION_VOICE_SEARCH_HANDS_FREE); 40893c2711fc2853394324b044632b79ca67388df8f4Jean-Michel Trivi voiceIntent.putExtra(RecognizerIntent.EXTRA_SECURE, 40903c2711fc2853394324b044632b79ca67388df8f4Jean-Michel Trivi isLocked && mKeyguardManager.isKeyguardSecure()); 40913c2711fc2853394324b044632b79ca67388df8f4Jean-Michel Trivi } 40923c2711fc2853394324b044632b79ca67388df8f4Jean-Michel Trivi // start the search activity 40934294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi if (needWakeLock) { 40944294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi mMediaEventWakeLock.acquire(); 40954294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi } 40964294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi try { 40973c2711fc2853394324b044632b79ca67388df8f4Jean-Michel Trivi if (voiceIntent != null) { 40983c2711fc2853394324b044632b79ca67388df8f4Jean-Michel Trivi voiceIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK 40993c2711fc2853394324b044632b79ca67388df8f4Jean-Michel Trivi | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS); 41003c2711fc2853394324b044632b79ca67388df8f4Jean-Michel Trivi mContext.startActivity(voiceIntent); 41014294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi } 41024294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi } catch (ActivityNotFoundException e) { 41033c2711fc2853394324b044632b79ca67388df8f4Jean-Michel Trivi Log.w(TAG, "No activity for search: " + e); 41044294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi } finally { 41054294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi if (needWakeLock) { 41064294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi mMediaEventWakeLock.release(); 41074294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi } 41084294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi } 41094294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi } 41104294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi 4111c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi private PowerManager.WakeLock mMediaEventWakeLock; 4112c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi 4113c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi private static final int WAKELOCK_RELEASE_ON_FINISHED = 1980; //magic number 4114c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi 4115c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi // only set when wakelock was acquired, no need to check value when received 4116c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi private static final String EXTRA_WAKELOCK_ACQUIRED = 4117c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi "android.media.AudioService.WAKELOCK_ACQUIRED"; 4118c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi 4119c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi public void onSendFinished(PendingIntent pendingIntent, Intent intent, 4120c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi int resultCode, String resultData, Bundle resultExtras) { 4121c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi if (resultCode == WAKELOCK_RELEASE_ON_FINISHED) { 4122c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi mMediaEventWakeLock.release(); 4123c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi } 4124c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi } 4125c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi 4126c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi BroadcastReceiver mKeyEventDone = new BroadcastReceiver() { 4127c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi public void onReceive(Context context, Intent intent) { 41284294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi if (intent == null) { 41294294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi return; 41304294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi } 41314294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi Bundle extras = intent.getExtras(); 41324294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi if (extras == null) { 41334294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi return; 41344294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi } 41354294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi if (extras.containsKey(EXTRA_WAKELOCK_ACQUIRED)) { 4136c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi mMediaEventWakeLock.release(); 4137c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi } 4138c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi } 4139c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi }; 4140c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi 4141ced110ec5970c632f523dfc0350b6071461ea9bcNeel Parekh private final Object mCurrentRcLock = new Object(); 41428f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi /** 41434426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi * The one remote control client which will receive a request for display information. 414417da769e987de40e113c5b2a3b867b25ba7ac0a2Jean-Michel Trivi * This object may be null. 41458f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi * Access protected by mCurrentRcLock. 41468f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi */ 41474426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi private IRemoteControlClient mCurrentRcClient = null; 41488f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi 41497b6198cacc3e7dd31ef91537d809857d826fb7faJean-Michel Trivi private final static int RC_INFO_NONE = 0; 41507b6198cacc3e7dd31ef91537d809857d826fb7faJean-Michel Trivi private final static int RC_INFO_ALL = 41514426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi RemoteControlClient.FLAG_INFORMATION_REQUEST_ALBUM_ART | 41524426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi RemoteControlClient.FLAG_INFORMATION_REQUEST_KEY_MEDIA | 41534426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi RemoteControlClient.FLAG_INFORMATION_REQUEST_METADATA | 41544426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi RemoteControlClient.FLAG_INFORMATION_REQUEST_PLAYSTATE; 41557b6198cacc3e7dd31ef91537d809857d826fb7faJean-Michel Trivi 41567b6198cacc3e7dd31ef91537d809857d826fb7faJean-Michel Trivi /** 415717da769e987de40e113c5b2a3b867b25ba7ac0a2Jean-Michel Trivi * A monotonically increasing generation counter for mCurrentRcClient. 41588f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi * Only accessed with a lock on mCurrentRcLock. 415917da769e987de40e113c5b2a3b867b25ba7ac0a2Jean-Michel Trivi * No value wrap-around issues as we only act on equal values. 41608f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi */ 4161ced110ec5970c632f523dfc0350b6071461ea9bcNeel Parekh private int mCurrentRcClientGen = 0; 41628f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi 41638f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi /** 41648f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi * Inner class to monitor remote control client deaths, and remove the client for the 41658f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi * remote control stack if necessary. 41668f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi */ 41678f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi private class RcClientDeathHandler implements IBinder.DeathRecipient { 41688f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi private IBinder mCb; // To be notified of client's death 4169f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi private PendingIntent mMediaIntent; 41708f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi 4171f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi RcClientDeathHandler(IBinder cb, PendingIntent pi) { 41728f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi mCb = cb; 4173f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi mMediaIntent = pi; 41748f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi } 41758f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi 41768f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi public void binderDied() { 41778f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi Log.w(TAG, " RemoteControlClient died"); 41788f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi // remote control client died, make sure the displays don't use it anymore 41798f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi // by setting its remote control client to null 418026b3d1ff38998c7cb80a2950da0589ebd8510897Jean-Michel Trivi registerRemoteControlClient(mMediaIntent, null/*rcClient*/, null/*ignored*/); 41813114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi // the dead client was maybe handling remote playback, reevaluate 41823114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi postReevaluateRemote(); 41838f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi } 41848f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi 41858f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi public IBinder getBinder() { 41868f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi return mCb; 41878f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi } 41888f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi } 41898f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi 41903114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi /** 41913114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi * A global counter for RemoteControlClient identifiers 41923114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi */ 41933114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi private static int sLastRccId = 0; 41943114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi 41953114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi private class RemotePlaybackState { 41963114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi int mRccId; 41973114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi int mVolume; 41983114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi int mVolumeMax; 41993114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi int mVolumeHandling; 42003114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi 42013114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi private RemotePlaybackState(int id, int vol, int volMax) { 42023114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi mRccId = id; 42033114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi mVolume = vol; 42043114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi mVolumeMax = volMax; 42053114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi mVolumeHandling = RemoteControlClient.DEFAULT_PLAYBACK_VOLUME_HANDLING; 42063114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi } 42073114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi } 42083114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi 42093114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi /** 42103114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi * Internal cache for the playback information of the RemoteControlClient whose volume gets to 42113114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi * be controlled by the volume keys ("main"), so we don't have to iterate over the RC stack 42123114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi * every time we need this info. 42133114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi */ 42143114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi private RemotePlaybackState mMainRemote; 42153114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi /** 42163114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi * Indicates whether the "main" RemoteControlClient is considered active. 42173114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi * Use synchronized on mMainRemote. 42183114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi */ 42193114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi private boolean mMainRemoteIsActive; 42203114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi /** 42213114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi * Indicates whether there is remote playback going on. True even if there is no "active" 42223114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi * remote playback (mMainRemoteIsActive is false), but a RemoteControlClient has declared it 42233114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi * handles remote playback. 42243114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi * Use synchronized on mMainRemote. 42253114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi */ 42263114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi private boolean mHasRemotePlayback; 42273114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi 4228d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi private static class RemoteControlStackEntry { 42293114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi public int mRccId = RemoteControlClient.RCSE_ID_UNREGISTERED; 4230f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi /** 4231f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi * The target for the ACTION_MEDIA_BUTTON events. 4232f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi * Always non null. 4233f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi */ 4234f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi public PendingIntent mMediaIntent; 4235f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi /** 4236f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi * The registered media button event receiver. 4237f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi * Always non null. 4238f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi */ 4239f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi public ComponentName mReceiverComponent; 42408f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi public String mCallingPackageName; 42418f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi public int mCallingUid; 4242f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi /** 4243f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi * Provides access to the information to display on the remote control. 4244f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi * May be null (when a media button event receiver is registered, 4245f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi * but no remote control client has been registered) */ 42464426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi public IRemoteControlClient mRcClient; 42478f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi public RcClientDeathHandler mRcClientDeathHandler; 42483114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi /** 42493114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi * Information only used for non-local playback 42503114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi */ 42513114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi public int mPlaybackType; 42523114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi public int mPlaybackVolume; 42533114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi public int mPlaybackVolumeMax; 42543114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi public int mPlaybackVolumeHandling; 42553114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi public int mPlaybackStream; 42563114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi public int mPlaybackState; 42571357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi public IRemoteVolumeObserver mRemoteVolumeObs; 42583114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi 42593114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi public void resetPlaybackInfo() { 42603114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi mPlaybackType = RemoteControlClient.PLAYBACK_TYPE_LOCAL; 42613114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi mPlaybackVolume = RemoteControlClient.DEFAULT_PLAYBACK_VOLUME; 42623114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi mPlaybackVolumeMax = RemoteControlClient.DEFAULT_PLAYBACK_VOLUME; 42633114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi mPlaybackVolumeHandling = RemoteControlClient.DEFAULT_PLAYBACK_VOLUME_HANDLING; 42643114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi mPlaybackStream = AudioManager.STREAM_MUSIC; 42653114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi mPlaybackState = RemoteControlClient.PLAYSTATE_STOPPED; 42661357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi mRemoteVolumeObs = null; 42673114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi } 4268d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi 4269f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi /** precondition: mediaIntent != null, eventReceiver != null */ 4270f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi public RemoteControlStackEntry(PendingIntent mediaIntent, ComponentName eventReceiver) { 4271f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi mMediaIntent = mediaIntent; 4272f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi mReceiverComponent = eventReceiver; 42738f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi mCallingUid = -1; 427417da769e987de40e113c5b2a3b867b25ba7ac0a2Jean-Michel Trivi mRcClient = null; 42753114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi mRccId = ++sLastRccId; 42763114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi 42773114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi resetPlaybackInfo(); 42788f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi } 42798f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi 42808f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi public void unlinkToRcClientDeath() { 42818f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi if ((mRcClientDeathHandler != null) && (mRcClientDeathHandler.mCb != null)) { 42828f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi try { 42838f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi mRcClientDeathHandler.mCb.unlinkToDeath(mRcClientDeathHandler, 0); 4284a9509736c85c19fe4ad4ba97a0545f0422a3dfc1Jean-Michel Trivi mRcClientDeathHandler = null; 42858f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi } catch (java.util.NoSuchElementException e) { 42868f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi // not much we can do here 42878f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi Log.e(TAG, "Encountered " + e + " in unlinkToRcClientDeath()"); 42888f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi e.printStackTrace(); 42898f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi } 42908f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi } 4291d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi } 4292a9509736c85c19fe4ad4ba97a0545f0422a3dfc1Jean-Michel Trivi 4293a9509736c85c19fe4ad4ba97a0545f0422a3dfc1Jean-Michel Trivi @Override 4294a9509736c85c19fe4ad4ba97a0545f0422a3dfc1Jean-Michel Trivi protected void finalize() throws Throwable { 4295a9509736c85c19fe4ad4ba97a0545f0422a3dfc1Jean-Michel Trivi unlinkToRcClientDeath();// unlink exception handled inside method 4296a9509736c85c19fe4ad4ba97a0545f0422a3dfc1Jean-Michel Trivi super.finalize(); 4297a9509736c85c19fe4ad4ba97a0545f0422a3dfc1Jean-Michel Trivi } 4298d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi } 4299d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi 43008f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi /** 43018f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi * The stack of remote control event receivers. 43028f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi * Code sections and methods that modify the remote control event receiver stack are 43038f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi * synchronized on mRCStack, but also BEFORE on mFocusLock as any change in either 43048f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi * stack, audio focus or RC, can lead to a change in the remote control display 43058f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi */ 430630c918ce7fbe171944b28fc91b3f22b3d631872dGlenn Kasten private final Stack<RemoteControlStackEntry> mRCStack = new Stack<RemoteControlStackEntry>(); 4307d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi 4308d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi /** 4309722b808662eb20fa91151f1e3aa05fd911d1d226Jean-Michel Trivi * The component the telephony package can register so telephony calls have priority to 4310722b808662eb20fa91151f1e3aa05fd911d1d226Jean-Michel Trivi * handle media button events 4311722b808662eb20fa91151f1e3aa05fd911d1d226Jean-Michel Trivi */ 4312722b808662eb20fa91151f1e3aa05fd911d1d226Jean-Michel Trivi private ComponentName mMediaReceiverForCalls = null; 4313722b808662eb20fa91151f1e3aa05fd911d1d226Jean-Michel Trivi 4314722b808662eb20fa91151f1e3aa05fd911d1d226Jean-Michel Trivi /** 4315d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi * Helper function: 4316d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi * Display in the log the current entries in the remote control focus stack 4317d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi */ 4318d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi private void dumpRCStack(PrintWriter pw) { 4319b4bccb6d8df16a2c5235cead187156bc721cf074Jean-Michel Trivi pw.println("\nRemote Control stack entries:"); 4320d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi synchronized(mRCStack) { 4321d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator(); 4322d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi while(stackIterator.hasNext()) { 43238f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi RemoteControlStackEntry rcse = stackIterator.next(); 4324f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi pw.println(" pi: " + rcse.mMediaIntent + 4325f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi " -- ercvr: " + rcse.mReceiverComponent + 432617da769e987de40e113c5b2a3b867b25ba7ac0a2Jean-Michel Trivi " -- client: " + rcse.mRcClient + 43273114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi " -- uid: " + rcse.mCallingUid + 43283114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi " -- type: " + rcse.mPlaybackType + 43293114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi " state: " + rcse.mPlaybackState); 43303114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi } 43313114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi } 43323114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi } 43333114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi 43343114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi /** 43353114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi * Helper function: 43363114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi * Display in the log the current entries in the remote control stack, focusing 43373114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi * on RemoteControlClient data 43383114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi */ 43393114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi private void dumpRCCStack(PrintWriter pw) { 43403114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi pw.println("\nRemote Control Client stack entries:"); 43413114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi synchronized(mRCStack) { 43423114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator(); 43433114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi while(stackIterator.hasNext()) { 43443114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi RemoteControlStackEntry rcse = stackIterator.next(); 43453114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi pw.println(" uid: " + rcse.mCallingUid + 43463114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi " -- id: " + rcse.mRccId + 43473114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi " -- type: " + rcse.mPlaybackType + 43483114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi " -- state: " + rcse.mPlaybackState + 43493114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi " -- vol handling: " + rcse.mPlaybackVolumeHandling + 43503114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi " -- vol: " + rcse.mPlaybackVolume + 43511357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi " -- volMax: " + rcse.mPlaybackVolumeMax + 43521357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi " -- volObs: " + rcse.mRemoteVolumeObs); 43531357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi 4354d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi } 4355d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi } 43563114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi synchronized (mMainRemote) { 43573114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi pw.println("\nRemote Volume State:"); 43583114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi pw.println(" has remote: " + mHasRemotePlayback); 43593114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi pw.println(" is remote active: " + mMainRemoteIsActive); 43603114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi pw.println(" rccId: " + mMainRemote.mRccId); 43613114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi pw.println(" volume handling: " 43623114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi + ((mMainRemote.mVolumeHandling == RemoteControlClient.PLAYBACK_VOLUME_FIXED) ? 43633114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi "PLAYBACK_VOLUME_FIXED(0)" : "PLAYBACK_VOLUME_VARIABLE(1)")); 43643114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi pw.println(" volume: " + mMainRemote.mVolume); 43653114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi pw.println(" volume steps: " + mMainRemote.mVolumeMax); 43663114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi } 4367d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi } 4368d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi 4369d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi /** 4370d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi * Helper function: 4371d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi * Remove any entry in the remote control stack that has the same package name as packageName 4372d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi * Pre-condition: packageName != null 4373d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi */ 4374d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi private void removeMediaButtonReceiverForPackage(String packageName) { 4375d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi synchronized(mRCStack) { 4376d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi if (mRCStack.empty()) { 4377d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi return; 4378d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi } else { 4379d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi RemoteControlStackEntry oldTop = mRCStack.peek(); 4380d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator(); 4381d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi // iterate over the stack entries 4382d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi while(stackIterator.hasNext()) { 4383d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi RemoteControlStackEntry rcse = (RemoteControlStackEntry)stackIterator.next(); 4384d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi if (packageName.equalsIgnoreCase(rcse.mReceiverComponent.getPackageName())) { 4385d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi // a stack entry is from the package being removed, remove it from the stack 4386d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi stackIterator.remove(); 4387a9509736c85c19fe4ad4ba97a0545f0422a3dfc1Jean-Michel Trivi rcse.unlinkToRcClientDeath(); 4388d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi } 4389d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi } 4390d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi if (mRCStack.empty()) { 4391d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi // no saved media button receiver 4392d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi mAudioHandler.sendMessage( 4393d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi mAudioHandler.obtainMessage(MSG_PERSIST_MEDIABUTTONRECEIVER, 0, 0, 4394d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi null)); 4395d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi } else if (oldTop != mRCStack.peek()) { 4396d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi // the top of the stack has changed, save it in the system settings 4397d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi // by posting a message to persist it 4398d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi mAudioHandler.sendMessage( 4399d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi mAudioHandler.obtainMessage(MSG_PERSIST_MEDIABUTTONRECEIVER, 0, 0, 4400d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi mRCStack.peek().mReceiverComponent)); 4401d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi } 4402d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi } 4403d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi } 4404d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi } 4405d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi 4406d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi /** 4407d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi * Helper function: 4408f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi * Restore remote control receiver from the system settings. 4409d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi */ 4410d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi private void restoreMediaButtonReceiver() { 4411d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi String receiverName = Settings.System.getString(mContentResolver, 4412d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi Settings.System.MEDIA_BUTTON_RECEIVER); 4413d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi if ((null != receiverName) && !receiverName.isEmpty()) { 4414f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi ComponentName eventReceiver = ComponentName.unflattenFromString(receiverName); 4415f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi // construct a PendingIntent targeted to the restored component name 4416f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi // for the media button and register it 4417f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi Intent mediaButtonIntent = new Intent(Intent.ACTION_MEDIA_BUTTON); 4418f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi // the associated intent will be handled by the component being registered 4419f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi mediaButtonIntent.setComponent(eventReceiver); 4420f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi PendingIntent pi = PendingIntent.getBroadcast(mContext, 4421f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi 0/*requestCode, ignored*/, mediaButtonIntent, 0/*flags*/); 4422f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi registerMediaButtonIntent(pi, eventReceiver); 4423d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi } 4424d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi } 4425d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi 4426d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi /** 4427d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi * Helper function: 4428f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi * Set the new remote control receiver at the top of the RC focus stack. 4429f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi * precondition: mediaIntent != null, target != null 4430d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi */ 4431f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi private void pushMediaButtonReceiver(PendingIntent mediaIntent, ComponentName target) { 4432d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi // already at top of stack? 4433f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi if (!mRCStack.empty() && mRCStack.peek().mMediaIntent.equals(mediaIntent)) { 4434d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi return; 4435d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi } 4436d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator(); 44378f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi RemoteControlStackEntry rcse = null; 44388f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi boolean wasInsideStack = false; 4439d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi while(stackIterator.hasNext()) { 44408f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi rcse = (RemoteControlStackEntry)stackIterator.next(); 4441f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi if(rcse.mMediaIntent.equals(mediaIntent)) { 44428f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi wasInsideStack = true; 444372843377d50a8f95cceaf33d316ab68d9b47f2ebJean-Michel Trivi stackIterator.remove(); 4444d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi break; 4445d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi } 4446d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi } 44478f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi if (!wasInsideStack) { 4448f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi rcse = new RemoteControlStackEntry(mediaIntent, target); 44498f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi } 44508f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi mRCStack.push(rcse); 4451d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi 4452d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi // post message to persist the default media button receiver 4453d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi mAudioHandler.sendMessage( mAudioHandler.obtainMessage( 4454f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi MSG_PERSIST_MEDIABUTTONRECEIVER, 0, 0, target/*obj*/) ); 4455d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi } 4456d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi 4457d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi /** 4458d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi * Helper function: 4459f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi * Remove the remote control receiver from the RC focus stack. 4460f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi * precondition: pi != null 4461d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi */ 4462f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi private void removeMediaButtonReceiver(PendingIntent pi) { 4463d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator(); 4464d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi while(stackIterator.hasNext()) { 4465d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi RemoteControlStackEntry rcse = (RemoteControlStackEntry)stackIterator.next(); 4466f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi if(rcse.mMediaIntent.equals(pi)) { 446772843377d50a8f95cceaf33d316ab68d9b47f2ebJean-Michel Trivi stackIterator.remove(); 4468a9509736c85c19fe4ad4ba97a0545f0422a3dfc1Jean-Michel Trivi rcse.unlinkToRcClientDeath(); 4469d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi break; 4470d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi } 4471d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi } 4472d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi } 4473d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi 44748f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi /** 44758f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi * Helper function: 44768f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi * Called synchronized on mRCStack 44778f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi */ 4478f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi private boolean isCurrentRcController(PendingIntent pi) { 4479f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi if (!mRCStack.empty() && mRCStack.peek().mMediaIntent.equals(pi)) { 44808f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi return true; 44818f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi } 44828f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi return false; 44838f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi } 44848f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi 44854426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi //========================================================================================== 44864426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi // Remote control display / client 44874426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi //========================================================================================== 44884426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi /** 44894426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi * Update the remote control displays with the new "focused" client generation 44904426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi */ 449118e7bce52318f00b5023f33933a571c477f2b61cJean-Michel Trivi private void setNewRcClientOnDisplays_syncRcsCurrc(int newClientGeneration, 4492f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi PendingIntent newMediaIntent, boolean clearing) { 44934426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi // NOTE: Only one IRemoteControlDisplay supported in this implementation 44944426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi if (mRcDisplay != null) { 44954426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi try { 44964b6df6a3dcbd9990e36438c529fa8c16b2580df9Jean-Michel Trivi mRcDisplay.setCurrentClientId( 4497f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi newClientGeneration, newMediaIntent, clearing); 44984426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi } catch (RemoteException e) { 4499db8a361629f06f62b9e1c40d4413b3b5099bd124Jean-Michel Trivi Log.e(TAG, "Dead display in setNewRcClientOnDisplays_syncRcsCurrc() "+e); 45004426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi // if we had a display before, stop monitoring its death 45014426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi rcDisplay_stopDeathMonitor_syncRcStack(); 45024426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi mRcDisplay = null; 45034426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi } 45044426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi } 45054426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi } 45064426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi 45074426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi /** 45084426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi * Update the remote control clients with the new "focused" client generation 45094426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi */ 451018e7bce52318f00b5023f33933a571c477f2b61cJean-Michel Trivi private void setNewRcClientGenerationOnClients_syncRcsCurrc(int newClientGeneration) { 45114426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator(); 45124426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi while(stackIterator.hasNext()) { 45134426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi RemoteControlStackEntry se = stackIterator.next(); 45144426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi if ((se != null) && (se.mRcClient != null)) { 45154426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi try { 45164426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi se.mRcClient.setCurrentClientGenerationId(newClientGeneration); 45174426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi } catch (RemoteException e) { 4518db8a361629f06f62b9e1c40d4413b3b5099bd124Jean-Michel Trivi Log.w(TAG, "Dead client in setNewRcClientGenerationOnClients_syncRcsCurrc()"+e); 45194426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi stackIterator.remove(); 45204426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi se.unlinkToRcClientDeath(); 45214426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi } 45224426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi } 45234426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi } 45244426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi } 45254426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi 45264426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi /** 45274b6df6a3dcbd9990e36438c529fa8c16b2580df9Jean-Michel Trivi * Update the displays and clients with the new "focused" client generation and name 45284b6df6a3dcbd9990e36438c529fa8c16b2580df9Jean-Michel Trivi * @param newClientGeneration the new generation value matching a client update 45294b6df6a3dcbd9990e36438c529fa8c16b2580df9Jean-Michel Trivi * @param newClientEventReceiver the media button event receiver associated with the client. 45304b6df6a3dcbd9990e36438c529fa8c16b2580df9Jean-Michel Trivi * May be null, which implies there is no registered media button event receiver. 45314b6df6a3dcbd9990e36438c529fa8c16b2580df9Jean-Michel Trivi * @param clearing true if the new client generation value maps to a remote control update 45324b6df6a3dcbd9990e36438c529fa8c16b2580df9Jean-Michel Trivi * where the display should be cleared. 45334426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi */ 453418e7bce52318f00b5023f33933a571c477f2b61cJean-Michel Trivi private void setNewRcClient_syncRcsCurrc(int newClientGeneration, 4535f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi PendingIntent newMediaIntent, boolean clearing) { 45363094d955b8321f01e50cb0c448ae1c4c461f41c9Jean-Michel Trivi // send the new valid client generation ID to all displays 4537f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi setNewRcClientOnDisplays_syncRcsCurrc(newClientGeneration, newMediaIntent, clearing); 45383094d955b8321f01e50cb0c448ae1c4c461f41c9Jean-Michel Trivi // send the new valid client generation ID to all clients 453918e7bce52318f00b5023f33933a571c477f2b61cJean-Michel Trivi setNewRcClientGenerationOnClients_syncRcsCurrc(newClientGeneration); 45404426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi } 45414426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi 45424426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi /** 45434426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi * Called when processing MSG_RCDISPLAY_CLEAR event 45444426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi */ 45454426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi private void onRcDisplayClear() { 454618e7bce52318f00b5023f33933a571c477f2b61cJean-Michel Trivi if (DEBUG_RC) Log.i(TAG, "Clear remote control display"); 45474426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi 45483094d955b8321f01e50cb0c448ae1c4c461f41c9Jean-Michel Trivi synchronized(mRCStack) { 45493094d955b8321f01e50cb0c448ae1c4c461f41c9Jean-Michel Trivi synchronized(mCurrentRcLock) { 45503094d955b8321f01e50cb0c448ae1c4c461f41c9Jean-Michel Trivi mCurrentRcClientGen++; 45513094d955b8321f01e50cb0c448ae1c4c461f41c9Jean-Michel Trivi // synchronously update the displays and clients with the new client generation 455218e7bce52318f00b5023f33933a571c477f2b61cJean-Michel Trivi setNewRcClient_syncRcsCurrc(mCurrentRcClientGen, 4553f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi null /*newMediaIntent*/, true /*clearing*/); 45543094d955b8321f01e50cb0c448ae1c4c461f41c9Jean-Michel Trivi } 45554426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi } 45564426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi } 45574426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi 45584426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi /** 45594426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi * Called when processing MSG_RCDISPLAY_UPDATE event 45604426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi */ 45614426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi private void onRcDisplayUpdate(RemoteControlStackEntry rcse, int flags /* USED ?*/) { 45623094d955b8321f01e50cb0c448ae1c4c461f41c9Jean-Michel Trivi synchronized(mRCStack) { 45633094d955b8321f01e50cb0c448ae1c4c461f41c9Jean-Michel Trivi synchronized(mCurrentRcLock) { 45643094d955b8321f01e50cb0c448ae1c4c461f41c9Jean-Michel Trivi if ((mCurrentRcClient != null) && (mCurrentRcClient.equals(rcse.mRcClient))) { 456518e7bce52318f00b5023f33933a571c477f2b61cJean-Michel Trivi if (DEBUG_RC) Log.i(TAG, "Display/update remote control "); 45663094d955b8321f01e50cb0c448ae1c4c461f41c9Jean-Michel Trivi 45673094d955b8321f01e50cb0c448ae1c4c461f41c9Jean-Michel Trivi mCurrentRcClientGen++; 45683094d955b8321f01e50cb0c448ae1c4c461f41c9Jean-Michel Trivi // synchronously update the displays and clients with 45693094d955b8321f01e50cb0c448ae1c4c461f41c9Jean-Michel Trivi // the new client generation 457018e7bce52318f00b5023f33933a571c477f2b61cJean-Michel Trivi setNewRcClient_syncRcsCurrc(mCurrentRcClientGen, 4571f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi rcse.mMediaIntent /*newMediaIntent*/, 45723094d955b8321f01e50cb0c448ae1c4c461f41c9Jean-Michel Trivi false /*clearing*/); 45733094d955b8321f01e50cb0c448ae1c4c461f41c9Jean-Michel Trivi 4574db8a361629f06f62b9e1c40d4413b3b5099bd124Jean-Michel Trivi // tell the current client that it needs to send info 45753094d955b8321f01e50cb0c448ae1c4c461f41c9Jean-Michel Trivi try { 45763094d955b8321f01e50cb0c448ae1c4c461f41c9Jean-Michel Trivi mCurrentRcClient.onInformationRequested(mCurrentRcClientGen, 45773094d955b8321f01e50cb0c448ae1c4c461f41c9Jean-Michel Trivi flags, mArtworkExpectedWidth, mArtworkExpectedHeight); 45783094d955b8321f01e50cb0c448ae1c4c461f41c9Jean-Michel Trivi } catch (RemoteException e) { 45793094d955b8321f01e50cb0c448ae1c4c461f41c9Jean-Michel Trivi Log.e(TAG, "Current valid remote client is dead: "+e); 45803094d955b8321f01e50cb0c448ae1c4c461f41c9Jean-Michel Trivi mCurrentRcClient = null; 45813094d955b8321f01e50cb0c448ae1c4c461f41c9Jean-Michel Trivi } 45823094d955b8321f01e50cb0c448ae1c4c461f41c9Jean-Michel Trivi } else { 45833094d955b8321f01e50cb0c448ae1c4c461f41c9Jean-Michel Trivi // the remote control display owner has changed between the 45843094d955b8321f01e50cb0c448ae1c4c461f41c9Jean-Michel Trivi // the message to update the display was sent, and the time it 45853094d955b8321f01e50cb0c448ae1c4c461f41c9Jean-Michel Trivi // gets to be processed (now) 45864426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi } 45874426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi } 45884426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi } 45894426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi } 45904426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi 45914426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi 45928f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi /** 45938f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi * Helper function: 45948f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi * Called synchronized on mRCStack 45958f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi */ 4596b716f0b7b2d8e4b045843fc6a7004910eb344c19Jean-Michel Trivi private void clearRemoteControlDisplay_syncAfRcs() { 45978f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi synchronized(mCurrentRcLock) { 459817da769e987de40e113c5b2a3b867b25ba7ac0a2Jean-Michel Trivi mCurrentRcClient = null; 45998f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi } 46004426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi // will cause onRcDisplayClear() to be called in AudioService's handler thread 46018f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi mAudioHandler.sendMessage( mAudioHandler.obtainMessage(MSG_RCDISPLAY_CLEAR) ); 46028f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi } 46038f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi 46048f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi /** 4605b716f0b7b2d8e4b045843fc6a7004910eb344c19Jean-Michel Trivi * Helper function for code readability: only to be called from 4606b716f0b7b2d8e4b045843fc6a7004910eb344c19Jean-Michel Trivi * checkUpdateRemoteControlDisplay_syncAfRcs() which checks the preconditions for 4607b716f0b7b2d8e4b045843fc6a7004910eb344c19Jean-Michel Trivi * this method. 4608b716f0b7b2d8e4b045843fc6a7004910eb344c19Jean-Michel Trivi * Preconditions: 4609b716f0b7b2d8e4b045843fc6a7004910eb344c19Jean-Michel Trivi * - called synchronized mAudioFocusLock then on mRCStack 4610b716f0b7b2d8e4b045843fc6a7004910eb344c19Jean-Michel Trivi * - mRCStack.isEmpty() is false 46118f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi */ 4612b716f0b7b2d8e4b045843fc6a7004910eb344c19Jean-Michel Trivi private void updateRemoteControlDisplay_syncAfRcs(int infoChangedFlags) { 46138f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi RemoteControlStackEntry rcse = mRCStack.peek(); 4614b5f04d6dbf5106140df367ae07f0e7708e1b650eJean-Michel Trivi int infoFlagsAboutToBeUsed = infoChangedFlags; 46158f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi // this is where we enforce opt-in for information display on the remote controls 46168f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi // with the new AudioManager.registerRemoteControlClient() API 461717da769e987de40e113c5b2a3b867b25ba7ac0a2Jean-Michel Trivi if (rcse.mRcClient == null) { 461817da769e987de40e113c5b2a3b867b25ba7ac0a2Jean-Michel Trivi //Log.w(TAG, "Can't update remote control display with null remote control client"); 4619b716f0b7b2d8e4b045843fc6a7004910eb344c19Jean-Michel Trivi clearRemoteControlDisplay_syncAfRcs(); 46208f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi return; 46218f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi } 46228f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi synchronized(mCurrentRcLock) { 462317da769e987de40e113c5b2a3b867b25ba7ac0a2Jean-Michel Trivi if (!rcse.mRcClient.equals(mCurrentRcClient)) { 46247b6198cacc3e7dd31ef91537d809857d826fb7faJean-Michel Trivi // new RC client, assume every type of information shall be queried 4625b5f04d6dbf5106140df367ae07f0e7708e1b650eJean-Michel Trivi infoFlagsAboutToBeUsed = RC_INFO_ALL; 46267b6198cacc3e7dd31ef91537d809857d826fb7faJean-Michel Trivi } 462717da769e987de40e113c5b2a3b867b25ba7ac0a2Jean-Michel Trivi mCurrentRcClient = rcse.mRcClient; 46288f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi } 46294426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi // will cause onRcDisplayUpdate() to be called in AudioService's handler thread 4630b5f04d6dbf5106140df367ae07f0e7708e1b650eJean-Michel Trivi mAudioHandler.sendMessage( mAudioHandler.obtainMessage(MSG_RCDISPLAY_UPDATE, 46310a9faa8cf934ef38319cd945b600825c6bb88b9cJean-Michel Trivi infoFlagsAboutToBeUsed /* arg1 */, 0, rcse /* obj, != null */) ); 46328f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi } 46338f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi 46348f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi /** 46358f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi * Helper function: 4636b716f0b7b2d8e4b045843fc6a7004910eb344c19Jean-Michel Trivi * Called synchronized on mAudioFocusLock, then mRCStack 46378f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi * Check whether the remote control display should be updated, triggers the update if required 4638b5f04d6dbf5106140df367ae07f0e7708e1b650eJean-Michel Trivi * @param infoChangedFlags the flags corresponding to the remote control client information 4639b5f04d6dbf5106140df367ae07f0e7708e1b650eJean-Michel Trivi * that has changed, if applicable (checking for the update conditions might trigger a 4640b5f04d6dbf5106140df367ae07f0e7708e1b650eJean-Michel Trivi * clear, rather than an update event). 46418f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi */ 4642b716f0b7b2d8e4b045843fc6a7004910eb344c19Jean-Michel Trivi private void checkUpdateRemoteControlDisplay_syncAfRcs(int infoChangedFlags) { 46438f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi // determine whether the remote control display should be refreshed 46448f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi // if either stack is empty, there is a mismatch, so clear the RC display 46458f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi if (mRCStack.isEmpty() || mFocusStack.isEmpty()) { 4646b716f0b7b2d8e4b045843fc6a7004910eb344c19Jean-Michel Trivi clearRemoteControlDisplay_syncAfRcs(); 46478f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi return; 46488f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi } 46498f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi // if the top of the two stacks belong to different packages, there is a mismatch, clear 46508f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi if ((mRCStack.peek().mCallingPackageName != null) 46518f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi && (mFocusStack.peek().mPackageName != null) 46528f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi && !(mRCStack.peek().mCallingPackageName.compareTo( 46538f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi mFocusStack.peek().mPackageName) == 0)) { 4654b716f0b7b2d8e4b045843fc6a7004910eb344c19Jean-Michel Trivi clearRemoteControlDisplay_syncAfRcs(); 46558f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi return; 46568f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi } 46578f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi // if the audio focus didn't originate from the same Uid as the one in which the remote 46588f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi // control information will be retrieved, clear 46598f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi if (mRCStack.peek().mCallingUid != mFocusStack.peek().mCallingUid) { 4660b716f0b7b2d8e4b045843fc6a7004910eb344c19Jean-Michel Trivi clearRemoteControlDisplay_syncAfRcs(); 46618f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi return; 46628f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi } 46638f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi // refresh conditions were verified: update the remote controls 4664b716f0b7b2d8e4b045843fc6a7004910eb344c19Jean-Michel Trivi // ok to call: synchronized mAudioFocusLock then on mRCStack, mRCStack is not empty 4665b716f0b7b2d8e4b045843fc6a7004910eb344c19Jean-Michel Trivi updateRemoteControlDisplay_syncAfRcs(infoChangedFlags); 46668f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi } 4667d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi 46686bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent /** 4669f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi * see AudioManager.registerMediaButtonIntent(PendingIntent pi, ComponentName c) 4670f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi * precondition: mediaIntent != null, target != null 4671f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi */ 4672f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi public void registerMediaButtonIntent(PendingIntent mediaIntent, ComponentName eventReceiver) { 4673f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi Log.i(TAG, " Remote Control registerMediaButtonIntent() for " + mediaIntent); 4674d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi 46758f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi synchronized(mAudioFocusLock) { 46768f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi synchronized(mRCStack) { 4677f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi pushMediaButtonReceiver(mediaIntent, eventReceiver); 4678b5f04d6dbf5106140df367ae07f0e7708e1b650eJean-Michel Trivi // new RC client, assume every type of information shall be queried 4679b716f0b7b2d8e4b045843fc6a7004910eb344c19Jean-Michel Trivi checkUpdateRemoteControlDisplay_syncAfRcs(RC_INFO_ALL); 46808f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi } 4681d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi } 4682d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi } 4683d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi 46846bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent /** 4685f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi * see AudioManager.unregisterMediaButtonIntent(PendingIntent mediaIntent) 4686f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi * precondition: mediaIntent != null, eventReceiver != null 4687f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi */ 4688f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi public void unregisterMediaButtonIntent(PendingIntent mediaIntent, ComponentName eventReceiver) 4689f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi { 4690f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi Log.i(TAG, " Remote Control unregisterMediaButtonIntent() for " + mediaIntent); 4691d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi 46928f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi synchronized(mAudioFocusLock) { 46938f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi synchronized(mRCStack) { 4694f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi boolean topOfStackWillChange = isCurrentRcController(mediaIntent); 4695f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi removeMediaButtonReceiver(mediaIntent); 46968f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi if (topOfStackWillChange) { 4697b5f04d6dbf5106140df367ae07f0e7708e1b650eJean-Michel Trivi // current RC client will change, assume every type of info needs to be queried 4698b716f0b7b2d8e4b045843fc6a7004910eb344c19Jean-Michel Trivi checkUpdateRemoteControlDisplay_syncAfRcs(RC_INFO_ALL); 46998f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi } 47008f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi } 4701d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi } 4702d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi } 4703d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi 470426b3d1ff38998c7cb80a2950da0589ebd8510897Jean-Michel Trivi /** 4705722b808662eb20fa91151f1e3aa05fd911d1d226Jean-Michel Trivi * see AudioManager.registerMediaButtonEventReceiverForCalls(ComponentName c) 4706722b808662eb20fa91151f1e3aa05fd911d1d226Jean-Michel Trivi * precondition: c != null 4707722b808662eb20fa91151f1e3aa05fd911d1d226Jean-Michel Trivi */ 4708722b808662eb20fa91151f1e3aa05fd911d1d226Jean-Michel Trivi public void registerMediaButtonEventReceiverForCalls(ComponentName c) { 4709722b808662eb20fa91151f1e3aa05fd911d1d226Jean-Michel Trivi if (mContext.checkCallingPermission("android.permission.MODIFY_PHONE_STATE") 4710722b808662eb20fa91151f1e3aa05fd911d1d226Jean-Michel Trivi != PackageManager.PERMISSION_GRANTED) { 4711722b808662eb20fa91151f1e3aa05fd911d1d226Jean-Michel Trivi Log.e(TAG, "Invalid permissions to register media button receiver for calls"); 4712722b808662eb20fa91151f1e3aa05fd911d1d226Jean-Michel Trivi return; 4713722b808662eb20fa91151f1e3aa05fd911d1d226Jean-Michel Trivi } 4714722b808662eb20fa91151f1e3aa05fd911d1d226Jean-Michel Trivi synchronized(mRCStack) { 4715722b808662eb20fa91151f1e3aa05fd911d1d226Jean-Michel Trivi mMediaReceiverForCalls = c; 4716722b808662eb20fa91151f1e3aa05fd911d1d226Jean-Michel Trivi } 4717722b808662eb20fa91151f1e3aa05fd911d1d226Jean-Michel Trivi } 4718722b808662eb20fa91151f1e3aa05fd911d1d226Jean-Michel Trivi 4719722b808662eb20fa91151f1e3aa05fd911d1d226Jean-Michel Trivi /** 4720722b808662eb20fa91151f1e3aa05fd911d1d226Jean-Michel Trivi * see AudioManager.unregisterMediaButtonEventReceiverForCalls() 4721722b808662eb20fa91151f1e3aa05fd911d1d226Jean-Michel Trivi */ 4722722b808662eb20fa91151f1e3aa05fd911d1d226Jean-Michel Trivi public void unregisterMediaButtonEventReceiverForCalls() { 4723722b808662eb20fa91151f1e3aa05fd911d1d226Jean-Michel Trivi if (mContext.checkCallingPermission("android.permission.MODIFY_PHONE_STATE") 4724722b808662eb20fa91151f1e3aa05fd911d1d226Jean-Michel Trivi != PackageManager.PERMISSION_GRANTED) { 4725722b808662eb20fa91151f1e3aa05fd911d1d226Jean-Michel Trivi Log.e(TAG, "Invalid permissions to unregister media button receiver for calls"); 4726722b808662eb20fa91151f1e3aa05fd911d1d226Jean-Michel Trivi return; 4727722b808662eb20fa91151f1e3aa05fd911d1d226Jean-Michel Trivi } 4728722b808662eb20fa91151f1e3aa05fd911d1d226Jean-Michel Trivi synchronized(mRCStack) { 4729722b808662eb20fa91151f1e3aa05fd911d1d226Jean-Michel Trivi mMediaReceiverForCalls = null; 4730722b808662eb20fa91151f1e3aa05fd911d1d226Jean-Michel Trivi } 4731722b808662eb20fa91151f1e3aa05fd911d1d226Jean-Michel Trivi } 4732722b808662eb20fa91151f1e3aa05fd911d1d226Jean-Michel Trivi 4733722b808662eb20fa91151f1e3aa05fd911d1d226Jean-Michel Trivi /** 473426b3d1ff38998c7cb80a2950da0589ebd8510897Jean-Michel Trivi * see AudioManager.registerRemoteControlClient(ComponentName eventReceiver, ...) 47353114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi * @return the unique ID of the RemoteControlStackEntry associated with the RemoteControlClient 473626b3d1ff38998c7cb80a2950da0589ebd8510897Jean-Michel Trivi * Note: using this method with rcClient == null is a way to "disable" the IRemoteControlClient 473726b3d1ff38998c7cb80a2950da0589ebd8510897Jean-Michel Trivi * without modifying the RC stack, but while still causing the display to refresh (will 473826b3d1ff38998c7cb80a2950da0589ebd8510897Jean-Michel Trivi * become blank as a result of this) 473926b3d1ff38998c7cb80a2950da0589ebd8510897Jean-Michel Trivi */ 47403114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi public int registerRemoteControlClient(PendingIntent mediaIntent, 4741f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi IRemoteControlClient rcClient, String callingPackageName) { 4742b716f0b7b2d8e4b045843fc6a7004910eb344c19Jean-Michel Trivi if (DEBUG_RC) Log.i(TAG, "Register remote control client rcClient="+rcClient); 47433114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi int rccId = RemoteControlClient.RCSE_ID_UNREGISTERED; 47448f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi synchronized(mAudioFocusLock) { 47458f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi synchronized(mRCStack) { 47468f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi // store the new display information 47478f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator(); 47488f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi while(stackIterator.hasNext()) { 47498f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi RemoteControlStackEntry rcse = stackIterator.next(); 4750f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi if(rcse.mMediaIntent.equals(mediaIntent)) { 47518f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi // already had a remote control client? 47528f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi if (rcse.mRcClientDeathHandler != null) { 47538f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi // stop monitoring the old client's death 47548f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi rcse.unlinkToRcClientDeath(); 47558f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi } 47568f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi // save the new remote control client 475717da769e987de40e113c5b2a3b867b25ba7ac0a2Jean-Michel Trivi rcse.mRcClient = rcClient; 475826b3d1ff38998c7cb80a2950da0589ebd8510897Jean-Michel Trivi rcse.mCallingPackageName = callingPackageName; 475926b3d1ff38998c7cb80a2950da0589ebd8510897Jean-Michel Trivi rcse.mCallingUid = Binder.getCallingUid(); 476026b3d1ff38998c7cb80a2950da0589ebd8510897Jean-Michel Trivi if (rcClient == null) { 4761a9509736c85c19fe4ad4ba97a0545f0422a3dfc1Jean-Michel Trivi // here rcse.mRcClientDeathHandler is null; 47623114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi rcse.resetPlaybackInfo(); 476326b3d1ff38998c7cb80a2950da0589ebd8510897Jean-Michel Trivi break; 476426b3d1ff38998c7cb80a2950da0589ebd8510897Jean-Michel Trivi } 47653114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi rccId = rcse.mRccId; 476626b3d1ff38998c7cb80a2950da0589ebd8510897Jean-Michel Trivi 476726b3d1ff38998c7cb80a2950da0589ebd8510897Jean-Michel Trivi // there is a new (non-null) client: 476826b3d1ff38998c7cb80a2950da0589ebd8510897Jean-Michel Trivi // 1/ give the new client the current display (if any) 47694426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi if (mRcDisplay != null) { 47704426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi try { 47714426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi rcse.mRcClient.plugRemoteControlDisplay(mRcDisplay); 47724426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi } catch (RemoteException e) { 47734426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi Log.e(TAG, "Error connecting remote control display to client: "+e); 47744426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi e.printStackTrace(); 47754426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi } 47764426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi } 477726b3d1ff38998c7cb80a2950da0589ebd8510897Jean-Michel Trivi // 2/ monitor the new client's death 477826b3d1ff38998c7cb80a2950da0589ebd8510897Jean-Michel Trivi IBinder b = rcse.mRcClient.asBinder(); 47798f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi RcClientDeathHandler rcdh = 4780f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi new RcClientDeathHandler(b, rcse.mMediaIntent); 47818f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi try { 47828f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi b.linkToDeath(rcdh, 0); 47838f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi } catch (RemoteException e) { 47848f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi // remote control client is DOA, disqualify it 47858f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi Log.w(TAG, "registerRemoteControlClient() has a dead client " + b); 478617da769e987de40e113c5b2a3b867b25ba7ac0a2Jean-Michel Trivi rcse.mRcClient = null; 47878f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi } 47888f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi rcse.mRcClientDeathHandler = rcdh; 47898f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi break; 47908f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi } 47918f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi } 47928f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi // if the eventReceiver is at the top of the stack 47938f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi // then check for potential refresh of the remote controls 4794f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi if (isCurrentRcController(mediaIntent)) { 4795b716f0b7b2d8e4b045843fc6a7004910eb344c19Jean-Michel Trivi checkUpdateRemoteControlDisplay_syncAfRcs(RC_INFO_ALL); 47968f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi } 47978f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi } 47988f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi } 47993114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi return rccId; 48008f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi } 48018f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi 48024b6df6a3dcbd9990e36438c529fa8c16b2580df9Jean-Michel Trivi /** 4803f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi * see AudioManager.unregisterRemoteControlClient(PendingIntent pi, ...) 48044b6df6a3dcbd9990e36438c529fa8c16b2580df9Jean-Michel Trivi * rcClient is guaranteed non-null 48054b6df6a3dcbd9990e36438c529fa8c16b2580df9Jean-Michel Trivi */ 4806f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi public void unregisterRemoteControlClient(PendingIntent mediaIntent, 48074426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi IRemoteControlClient rcClient) { 48084b6df6a3dcbd9990e36438c529fa8c16b2580df9Jean-Michel Trivi synchronized(mAudioFocusLock) { 48094b6df6a3dcbd9990e36438c529fa8c16b2580df9Jean-Michel Trivi synchronized(mRCStack) { 48104b6df6a3dcbd9990e36438c529fa8c16b2580df9Jean-Michel Trivi Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator(); 48114b6df6a3dcbd9990e36438c529fa8c16b2580df9Jean-Michel Trivi while(stackIterator.hasNext()) { 48124b6df6a3dcbd9990e36438c529fa8c16b2580df9Jean-Michel Trivi RemoteControlStackEntry rcse = stackIterator.next(); 4813f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi if ((rcse.mMediaIntent.equals(mediaIntent)) 48144b6df6a3dcbd9990e36438c529fa8c16b2580df9Jean-Michel Trivi && rcClient.equals(rcse.mRcClient)) { 48154b6df6a3dcbd9990e36438c529fa8c16b2580df9Jean-Michel Trivi // we found the IRemoteControlClient to unregister 48164b6df6a3dcbd9990e36438c529fa8c16b2580df9Jean-Michel Trivi // stop monitoring its death 48174b6df6a3dcbd9990e36438c529fa8c16b2580df9Jean-Michel Trivi rcse.unlinkToRcClientDeath(); 48184b6df6a3dcbd9990e36438c529fa8c16b2580df9Jean-Michel Trivi // reset the client-related fields 48194b6df6a3dcbd9990e36438c529fa8c16b2580df9Jean-Michel Trivi rcse.mRcClient = null; 48204b6df6a3dcbd9990e36438c529fa8c16b2580df9Jean-Michel Trivi rcse.mCallingPackageName = null; 48214b6df6a3dcbd9990e36438c529fa8c16b2580df9Jean-Michel Trivi } 48224b6df6a3dcbd9990e36438c529fa8c16b2580df9Jean-Michel Trivi } 48234b6df6a3dcbd9990e36438c529fa8c16b2580df9Jean-Michel Trivi } 48244b6df6a3dcbd9990e36438c529fa8c16b2580df9Jean-Michel Trivi } 48254426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi } 48264426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi 48274426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi /** 48284426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi * The remote control displays. 48294426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi * Access synchronized on mRCStack 48304426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi * NOTE: Only one IRemoteControlDisplay supported in this implementation 48314426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi */ 48324426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi private IRemoteControlDisplay mRcDisplay; 48334426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi private RcDisplayDeathHandler mRcDisplayDeathHandler; 48344426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi private int mArtworkExpectedWidth = -1; 48354426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi private int mArtworkExpectedHeight = -1; 48364426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi /** 48374426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi * Inner class to monitor remote control display deaths, and unregister them from the list 48384426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi * of displays if necessary. 48394426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi */ 48404426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi private class RcDisplayDeathHandler implements IBinder.DeathRecipient { 484118e7bce52318f00b5023f33933a571c477f2b61cJean-Michel Trivi private IBinder mCb; // To be notified of client's death 484218e7bce52318f00b5023f33933a571c477f2b61cJean-Michel Trivi 484318e7bce52318f00b5023f33933a571c477f2b61cJean-Michel Trivi public RcDisplayDeathHandler(IBinder b) { 484418e7bce52318f00b5023f33933a571c477f2b61cJean-Michel Trivi if (DEBUG_RC) Log.i(TAG, "new RcDisplayDeathHandler for "+b); 484518e7bce52318f00b5023f33933a571c477f2b61cJean-Michel Trivi mCb = b; 484618e7bce52318f00b5023f33933a571c477f2b61cJean-Michel Trivi } 484718e7bce52318f00b5023f33933a571c477f2b61cJean-Michel Trivi 48484426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi public void binderDied() { 48498f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi synchronized(mRCStack) { 485018e7bce52318f00b5023f33933a571c477f2b61cJean-Michel Trivi Log.w(TAG, "RemoteControl: display died"); 48514426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi mRcDisplay = null; 48524426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi } 48534426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi } 48544426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi 485518e7bce52318f00b5023f33933a571c477f2b61cJean-Michel Trivi public void unlinkToRcDisplayDeath() { 485618e7bce52318f00b5023f33933a571c477f2b61cJean-Michel Trivi if (DEBUG_RC) Log.i(TAG, "unlinkToRcDisplayDeath for "+mCb); 48574426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi try { 485818e7bce52318f00b5023f33933a571c477f2b61cJean-Michel Trivi mCb.unlinkToDeath(this, 0); 48594426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi } catch (java.util.NoSuchElementException e) { 486018e7bce52318f00b5023f33933a571c477f2b61cJean-Michel Trivi // not much we can do here, the display was being unregistered anyway 486118e7bce52318f00b5023f33933a571c477f2b61cJean-Michel Trivi Log.e(TAG, "Encountered " + e + " in unlinkToRcDisplayDeath()"); 48624426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi e.printStackTrace(); 48634426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi } 48644426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi } 486518e7bce52318f00b5023f33933a571c477f2b61cJean-Michel Trivi 486618e7bce52318f00b5023f33933a571c477f2b61cJean-Michel Trivi } 486718e7bce52318f00b5023f33933a571c477f2b61cJean-Michel Trivi 486818e7bce52318f00b5023f33933a571c477f2b61cJean-Michel Trivi private void rcDisplay_stopDeathMonitor_syncRcStack() { 486918e7bce52318f00b5023f33933a571c477f2b61cJean-Michel Trivi if (mRcDisplay != null) { // implies (mRcDisplayDeathHandler != null) 487018e7bce52318f00b5023f33933a571c477f2b61cJean-Michel Trivi // we had a display before, stop monitoring its death 487118e7bce52318f00b5023f33933a571c477f2b61cJean-Michel Trivi mRcDisplayDeathHandler.unlinkToRcDisplayDeath(); 487218e7bce52318f00b5023f33933a571c477f2b61cJean-Michel Trivi } 48734426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi } 48744426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi 48754426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi private void rcDisplay_startDeathMonitor_syncRcStack() { 48764426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi if (mRcDisplay != null) { 48774426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi // new non-null display, monitor its death 48784426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi IBinder b = mRcDisplay.asBinder(); 487918e7bce52318f00b5023f33933a571c477f2b61cJean-Michel Trivi mRcDisplayDeathHandler = new RcDisplayDeathHandler(b); 48804426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi try { 48814426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi b.linkToDeath(mRcDisplayDeathHandler, 0); 48824426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi } catch (RemoteException e) { 48834426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi // remote control display is DOA, disqualify it 48844426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi Log.w(TAG, "registerRemoteControlDisplay() has a dead client " + b); 48854426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi mRcDisplay = null; 48864426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi } 48874426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi } 48884426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi } 48894426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi 489018e7bce52318f00b5023f33933a571c477f2b61cJean-Michel Trivi /** 4891958bba6862c9540c528263686b0de044b4a7a5f6Jean-Michel Trivi * Register an IRemoteControlDisplay. 4892958bba6862c9540c528263686b0de044b4a7a5f6Jean-Michel Trivi * Notify all IRemoteControlClient of the new display and cause the RemoteControlClient 4893958bba6862c9540c528263686b0de044b4a7a5f6Jean-Michel Trivi * at the top of the stack to update the new display with its information. 489418e7bce52318f00b5023f33933a571c477f2b61cJean-Michel Trivi * Since only one IRemoteControlDisplay is supported, this will unregister the previous display. 489518e7bce52318f00b5023f33933a571c477f2b61cJean-Michel Trivi * @param rcd the IRemoteControlDisplay to register. No effect if null. 489618e7bce52318f00b5023f33933a571c477f2b61cJean-Michel Trivi */ 48974426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi public void registerRemoteControlDisplay(IRemoteControlDisplay rcd) { 489818e7bce52318f00b5023f33933a571c477f2b61cJean-Michel Trivi if (DEBUG_RC) Log.d(TAG, ">>> registerRemoteControlDisplay("+rcd+")"); 4899b716f0b7b2d8e4b045843fc6a7004910eb344c19Jean-Michel Trivi synchronized(mAudioFocusLock) { 4900b716f0b7b2d8e4b045843fc6a7004910eb344c19Jean-Michel Trivi synchronized(mRCStack) { 4901b716f0b7b2d8e4b045843fc6a7004910eb344c19Jean-Michel Trivi if ((mRcDisplay == rcd) || (rcd == null)) { 4902b716f0b7b2d8e4b045843fc6a7004910eb344c19Jean-Michel Trivi return; 4903b716f0b7b2d8e4b045843fc6a7004910eb344c19Jean-Michel Trivi } 4904b716f0b7b2d8e4b045843fc6a7004910eb344c19Jean-Michel Trivi // if we had a display before, stop monitoring its death 4905b716f0b7b2d8e4b045843fc6a7004910eb344c19Jean-Michel Trivi rcDisplay_stopDeathMonitor_syncRcStack(); 4906b716f0b7b2d8e4b045843fc6a7004910eb344c19Jean-Michel Trivi mRcDisplay = rcd; 4907b716f0b7b2d8e4b045843fc6a7004910eb344c19Jean-Michel Trivi // new display, start monitoring its death 4908b716f0b7b2d8e4b045843fc6a7004910eb344c19Jean-Michel Trivi rcDisplay_startDeathMonitor_syncRcStack(); 49094426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi 4910b716f0b7b2d8e4b045843fc6a7004910eb344c19Jean-Michel Trivi // let all the remote control clients there is a new display 4911b716f0b7b2d8e4b045843fc6a7004910eb344c19Jean-Michel Trivi // no need to unplug the previous because we only support one display 4912b716f0b7b2d8e4b045843fc6a7004910eb344c19Jean-Michel Trivi // and the clients don't track the death of the display 4913b716f0b7b2d8e4b045843fc6a7004910eb344c19Jean-Michel Trivi Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator(); 4914b716f0b7b2d8e4b045843fc6a7004910eb344c19Jean-Michel Trivi while(stackIterator.hasNext()) { 4915b716f0b7b2d8e4b045843fc6a7004910eb344c19Jean-Michel Trivi RemoteControlStackEntry rcse = stackIterator.next(); 4916b716f0b7b2d8e4b045843fc6a7004910eb344c19Jean-Michel Trivi if(rcse.mRcClient != null) { 4917b716f0b7b2d8e4b045843fc6a7004910eb344c19Jean-Michel Trivi try { 4918b716f0b7b2d8e4b045843fc6a7004910eb344c19Jean-Michel Trivi rcse.mRcClient.plugRemoteControlDisplay(mRcDisplay); 4919b716f0b7b2d8e4b045843fc6a7004910eb344c19Jean-Michel Trivi } catch (RemoteException e) { 4920b716f0b7b2d8e4b045843fc6a7004910eb344c19Jean-Michel Trivi Log.e(TAG, "Error connecting remote control display to client: " + e); 4921b716f0b7b2d8e4b045843fc6a7004910eb344c19Jean-Michel Trivi e.printStackTrace(); 4922b716f0b7b2d8e4b045843fc6a7004910eb344c19Jean-Michel Trivi } 49234426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi } 49248f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi } 4925db8a361629f06f62b9e1c40d4413b3b5099bd124Jean-Michel Trivi 4926338794576667745b060ac269b2c2b36e0c6964f2Jean-Michel Trivi // we have a new display, of which all the clients are now aware: have it be updated 4927b716f0b7b2d8e4b045843fc6a7004910eb344c19Jean-Michel Trivi checkUpdateRemoteControlDisplay_syncAfRcs(RC_INFO_ALL); 4928338794576667745b060ac269b2c2b36e0c6964f2Jean-Michel Trivi } 49298f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi } 49308f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi } 4931d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi 493218e7bce52318f00b5023f33933a571c477f2b61cJean-Michel Trivi /** 493318e7bce52318f00b5023f33933a571c477f2b61cJean-Michel Trivi * Unregister an IRemoteControlDisplay. 493418e7bce52318f00b5023f33933a571c477f2b61cJean-Michel Trivi * Since only one IRemoteControlDisplay is supported, this has no effect if the one to 493518e7bce52318f00b5023f33933a571c477f2b61cJean-Michel Trivi * unregister is not the current one. 493618e7bce52318f00b5023f33933a571c477f2b61cJean-Michel Trivi * @param rcd the IRemoteControlDisplay to unregister. No effect if null. 493718e7bce52318f00b5023f33933a571c477f2b61cJean-Michel Trivi */ 49384426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi public void unregisterRemoteControlDisplay(IRemoteControlDisplay rcd) { 493918e7bce52318f00b5023f33933a571c477f2b61cJean-Michel Trivi if (DEBUG_RC) Log.d(TAG, "<<< unregisterRemoteControlDisplay("+rcd+")"); 49404426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi synchronized(mRCStack) { 494118e7bce52318f00b5023f33933a571c477f2b61cJean-Michel Trivi // only one display here, so you can only unregister the current display 494218e7bce52318f00b5023f33933a571c477f2b61cJean-Michel Trivi if ((rcd == null) || (rcd != mRcDisplay)) { 494318e7bce52318f00b5023f33933a571c477f2b61cJean-Michel Trivi if (DEBUG_RC) Log.w(TAG, " trying to unregister unregistered RCD"); 494418e7bce52318f00b5023f33933a571c477f2b61cJean-Michel Trivi return; 494518e7bce52318f00b5023f33933a571c477f2b61cJean-Michel Trivi } 49464426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi // if we had a display before, stop monitoring its death 49474426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi rcDisplay_stopDeathMonitor_syncRcStack(); 49484426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi mRcDisplay = null; 49494426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi 49504426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi // disconnect this remote control display from all the clients 49514426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator(); 49524426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi while(stackIterator.hasNext()) { 49534426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi RemoteControlStackEntry rcse = stackIterator.next(); 49544426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi if(rcse.mRcClient != null) { 49554426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi try { 49564426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi rcse.mRcClient.unplugRemoteControlDisplay(rcd); 49574426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi } catch (RemoteException e) { 49584426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi Log.e(TAG, "Error disconnecting remote control display to client: " + e); 49594426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi e.printStackTrace(); 49604426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi } 49614426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi } 49624426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi } 49634426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi } 49644426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi } 49654426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi 49664426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi public void remoteControlDisplayUsesBitmapSize(IRemoteControlDisplay rcd, int w, int h) { 49674426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi synchronized(mRCStack) { 49684426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi // NOTE: Only one IRemoteControlDisplay supported in this implementation 49694426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi mArtworkExpectedWidth = w; 49704426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi mArtworkExpectedHeight = h; 49714426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi } 49724426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi } 49734426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi 49743114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi public void setPlaybackInfoForRcc(int rccId, int what, int value) { 4975f98de1e8dd6dcbd191921b4aa07a1d41b0b9db91Jean-Michel Trivi sendMsg(mAudioHandler, MSG_RCC_NEW_PLAYBACK_INFO, SENDMSG_QUEUE, 4976f98de1e8dd6dcbd191921b4aa07a1d41b0b9db91Jean-Michel Trivi rccId /* arg1 */, what /* arg2 */, Integer.valueOf(value) /* obj */, 0 /* delay */); 4977f98de1e8dd6dcbd191921b4aa07a1d41b0b9db91Jean-Michel Trivi } 4978f98de1e8dd6dcbd191921b4aa07a1d41b0b9db91Jean-Michel Trivi 4979f98de1e8dd6dcbd191921b4aa07a1d41b0b9db91Jean-Michel Trivi // handler for MSG_RCC_NEW_PLAYBACK_INFO 4980f98de1e8dd6dcbd191921b4aa07a1d41b0b9db91Jean-Michel Trivi private void onNewPlaybackInfoForRcc(int rccId, int key, int value) { 4981f98de1e8dd6dcbd191921b4aa07a1d41b0b9db91Jean-Michel Trivi if(DEBUG_RC) Log.d(TAG, "onNewPlaybackInfoForRcc(id=" + rccId + 4982f98de1e8dd6dcbd191921b4aa07a1d41b0b9db91Jean-Michel Trivi ", what=" + key + ",val=" + value + ")"); 49833114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi synchronized(mRCStack) { 49843114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator(); 49853114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi while(stackIterator.hasNext()) { 49863114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi RemoteControlStackEntry rcse = stackIterator.next(); 49873114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi if (rcse.mRccId == rccId) { 4988f98de1e8dd6dcbd191921b4aa07a1d41b0b9db91Jean-Michel Trivi switch (key) { 49893114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi case RemoteControlClient.PLAYBACKINFO_PLAYBACK_TYPE: 49903114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi rcse.mPlaybackType = value; 49913114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi postReevaluateRemote(); 49923114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi break; 49933114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi case RemoteControlClient.PLAYBACKINFO_VOLUME: 49943114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi rcse.mPlaybackVolume = value; 49953114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi synchronized (mMainRemote) { 49963114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi if (rccId == mMainRemote.mRccId) { 49973114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi mMainRemote.mVolume = value; 49983114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi mVolumePanel.postHasNewRemotePlaybackInfo(); 49993114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi } 50003114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi } 50013114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi break; 50023114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi case RemoteControlClient.PLAYBACKINFO_VOLUME_MAX: 50033114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi rcse.mPlaybackVolumeMax = value; 50043114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi synchronized (mMainRemote) { 50053114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi if (rccId == mMainRemote.mRccId) { 50063114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi mMainRemote.mVolumeMax = value; 50073114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi mVolumePanel.postHasNewRemotePlaybackInfo(); 50083114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi } 50093114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi } 50103114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi break; 50113114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi case RemoteControlClient.PLAYBACKINFO_VOLUME_HANDLING: 50123114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi rcse.mPlaybackVolumeHandling = value; 50133114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi synchronized (mMainRemote) { 50143114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi if (rccId == mMainRemote.mRccId) { 50153114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi mMainRemote.mVolumeHandling = value; 50163114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi mVolumePanel.postHasNewRemotePlaybackInfo(); 50173114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi } 50183114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi } 50193114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi break; 50203114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi case RemoteControlClient.PLAYBACKINFO_USES_STREAM: 50213114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi rcse.mPlaybackStream = value; 50223114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi break; 50233114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi case RemoteControlClient.PLAYBACKINFO_PLAYSTATE: 50243114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi rcse.mPlaybackState = value; 50253114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi synchronized (mMainRemote) { 50263114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi if (rccId == mMainRemote.mRccId) { 50273114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi mMainRemoteIsActive = isPlaystateActive(value); 50283114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi postReevaluateRemote(); 50293114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi } 50303114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi } 50313114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi break; 50323114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi default: 5033f98de1e8dd6dcbd191921b4aa07a1d41b0b9db91Jean-Michel Trivi Log.e(TAG, "unhandled key " + key + " for RCC " + rccId); 50343114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi break; 50353114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi } 50363114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi return; 50373114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi } 50383114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi } 50393114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi } 50403114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi } 50413114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi 50421357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi public void registerRemoteVolumeObserverForRcc(int rccId, IRemoteVolumeObserver rvo) { 5043f98de1e8dd6dcbd191921b4aa07a1d41b0b9db91Jean-Michel Trivi sendMsg(mAudioHandler, MSG_RCC_NEW_VOLUME_OBS, SENDMSG_QUEUE, 5044f98de1e8dd6dcbd191921b4aa07a1d41b0b9db91Jean-Michel Trivi rccId /* arg1 */, 0, rvo /* obj */, 0 /* delay */); 5045f98de1e8dd6dcbd191921b4aa07a1d41b0b9db91Jean-Michel Trivi } 5046f98de1e8dd6dcbd191921b4aa07a1d41b0b9db91Jean-Michel Trivi 5047f98de1e8dd6dcbd191921b4aa07a1d41b0b9db91Jean-Michel Trivi // handler for MSG_RCC_NEW_VOLUME_OBS 5048f98de1e8dd6dcbd191921b4aa07a1d41b0b9db91Jean-Michel Trivi private void onRegisterVolumeObserverForRcc(int rccId, IRemoteVolumeObserver rvo) { 50491357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi synchronized(mRCStack) { 50501357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator(); 50511357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi while(stackIterator.hasNext()) { 50521357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi RemoteControlStackEntry rcse = stackIterator.next(); 50531357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi if (rcse.mRccId == rccId) { 50541357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi rcse.mRemoteVolumeObs = rvo; 50551357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi break; 50561357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 50571357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 50581357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 50591357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 50601357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi 50613114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi /** 50623114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi * Checks if a remote client is active on the supplied stream type. Update the remote stream 50633114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi * volume state if found and playing 50643114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi * @param streamType 50653114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi * @return false if no remote playing is currently playing 50663114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi */ 50673114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi private boolean checkUpdateRemoteStateIfActive(int streamType) { 50683114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi synchronized(mRCStack) { 50693114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator(); 50703114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi while(stackIterator.hasNext()) { 50713114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi RemoteControlStackEntry rcse = stackIterator.next(); 50723114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi if ((rcse.mPlaybackType == RemoteControlClient.PLAYBACK_TYPE_REMOTE) 50733114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi && isPlaystateActive(rcse.mPlaybackState) 50743114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi && (rcse.mPlaybackStream == streamType)) { 50753114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi if (DEBUG_RC) Log.d(TAG, "remote playback active on stream " + streamType 50763114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi + ", vol =" + rcse.mPlaybackVolume); 50773114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi synchronized (mMainRemote) { 50783114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi mMainRemote.mRccId = rcse.mRccId; 50793114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi mMainRemote.mVolume = rcse.mPlaybackVolume; 50803114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi mMainRemote.mVolumeMax = rcse.mPlaybackVolumeMax; 50813114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi mMainRemote.mVolumeHandling = rcse.mPlaybackVolumeHandling; 50823114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi mMainRemoteIsActive = true; 50833114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi } 50843114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi return true; 50853114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi } 50863114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi } 50873114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi } 50883114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi synchronized (mMainRemote) { 50893114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi mMainRemoteIsActive = false; 50903114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi } 50913114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi return false; 50923114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi } 50933114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi 50943114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi /** 50953114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi * Returns true if the given playback state is considered "active", i.e. it describes a state 50963114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi * where playback is happening, or about to 50973114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi * @param playState the playback state to evaluate 50983114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi * @return true if active, false otherwise (inactive or unknown) 50993114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi */ 51003114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi private static boolean isPlaystateActive(int playState) { 51013114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi switch (playState) { 51023114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi case RemoteControlClient.PLAYSTATE_PLAYING: 51033114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi case RemoteControlClient.PLAYSTATE_BUFFERING: 51043114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi case RemoteControlClient.PLAYSTATE_FAST_FORWARDING: 51053114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi case RemoteControlClient.PLAYSTATE_REWINDING: 51063114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi case RemoteControlClient.PLAYSTATE_SKIPPING_BACKWARDS: 51073114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi case RemoteControlClient.PLAYSTATE_SKIPPING_FORWARDS: 51083114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi return true; 51093114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi default: 51103114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi return false; 51113114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi } 51123114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi } 51133114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi 51143114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi private void adjustRemoteVolume(int streamType, int direction, int flags) { 51153114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi int rccId = RemoteControlClient.RCSE_ID_UNREGISTERED; 51163114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi boolean volFixed = false; 51173114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi synchronized (mMainRemote) { 51183114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi if (!mMainRemoteIsActive) { 51193114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi if (DEBUG_VOL) Log.w(TAG, "adjustRemoteVolume didn't find an active client"); 51203114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi return; 51213114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi } 51223114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi rccId = mMainRemote.mRccId; 51233114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi volFixed = (mMainRemote.mVolumeHandling == 51243114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi RemoteControlClient.PLAYBACK_VOLUME_FIXED); 51253114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi } 51263114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi // unlike "local" stream volumes, we can't compute the new volume based on the direction, 51273114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi // we can only notify the remote that volume needs to be updated, and we'll get an async' 51283114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi // update through setPlaybackInfoForRcc() 51293114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi if (!volFixed) { 51303114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi sendVolumeUpdateToRemote(rccId, direction); 51313114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi } 51323114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi 51333114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi // fire up the UI 51343114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi mVolumePanel.postRemoteVolumeChanged(streamType, flags); 51353114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi } 51363114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi 51373114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi private void sendVolumeUpdateToRemote(int rccId, int direction) { 51383114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi if (DEBUG_VOL) { Log.d(TAG, "sendVolumeUpdateToRemote(rccId="+rccId+" , dir="+direction); } 51393114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi if (direction == 0) { 51403114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi // only handling discrete events 51413114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi return; 51423114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi } 51431357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi IRemoteVolumeObserver rvo = null; 51443114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi synchronized (mRCStack) { 51453114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator(); 51463114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi while(stackIterator.hasNext()) { 51473114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi RemoteControlStackEntry rcse = stackIterator.next(); 51483114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi //FIXME OPTIMIZE store this info in mMainRemote so we don't have to iterate? 51493114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi if (rcse.mRccId == rccId) { 51501357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi rvo = rcse.mRemoteVolumeObs; 51513114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi break; 51523114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi } 51533114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi } 51543114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi } 51551357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi if (rvo != null) { 51561357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi try { 51571357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi rvo.dispatchRemoteVolumeUpdate(direction, -1); 51581357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } catch (RemoteException e) { 51591357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi Log.e(TAG, "Error dispatching relative volume update", e); 51601357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 51613114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi } 51623114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi } 51633114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi 51643114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi public int getRemoteStreamMaxVolume() { 51653114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi synchronized (mMainRemote) { 51663114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi if (mMainRemote.mRccId == RemoteControlClient.RCSE_ID_UNREGISTERED) { 51673114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi return 0; 51683114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi } 51693114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi return mMainRemote.mVolumeMax; 51703114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi } 51713114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi } 51723114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi 51733114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi public int getRemoteStreamVolume() { 51743114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi synchronized (mMainRemote) { 51753114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi if (mMainRemote.mRccId == RemoteControlClient.RCSE_ID_UNREGISTERED) { 51763114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi return 0; 51773114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi } 51783114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi return mMainRemote.mVolume; 51793114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi } 51803114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi } 51813114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi 51823114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi public void setRemoteStreamVolume(int vol) { 51833114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi if (DEBUG_VOL) { Log.d(TAG, "setRemoteStreamVolume(vol="+vol+")"); } 51843114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi int rccId = RemoteControlClient.RCSE_ID_UNREGISTERED; 51853114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi synchronized (mMainRemote) { 51863114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi if (mMainRemote.mRccId == RemoteControlClient.RCSE_ID_UNREGISTERED) { 51873114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi return; 51883114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi } 51893114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi rccId = mMainRemote.mRccId; 51903114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi } 51911357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi IRemoteVolumeObserver rvo = null; 51923114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi synchronized (mRCStack) { 51933114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator(); 51943114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi while(stackIterator.hasNext()) { 51953114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi RemoteControlStackEntry rcse = stackIterator.next(); 51963114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi if (rcse.mRccId == rccId) { 51973114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi //FIXME OPTIMIZE store this info in mMainRemote so we don't have to iterate? 51981357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi rvo = rcse.mRemoteVolumeObs; 51993114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi break; 52003114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi } 52013114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi } 52023114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi } 52031357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi if (rvo != null) { 52041357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi try { 52051357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi rvo.dispatchRemoteVolumeUpdate(0, vol); 52061357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } catch (RemoteException e) { 52071357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi Log.e(TAG, "Error dispatching absolute volume update", e); 52081357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 52093114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi } 52103114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi } 52113114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi 52123114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi /** 52133114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi * Call to make AudioService reevaluate whether it's in a mode where remote players should 52143114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi * have their volume controlled. In this implementation this is only to reset whether 52153114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi * VolumePanel should display remote volumes 52163114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi */ 52173114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi private void postReevaluateRemote() { 52183114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi sendMsg(mAudioHandler, MSG_REEVALUATE_REMOTE, SENDMSG_QUEUE, 0, 0, null, 0); 52193114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi } 52203114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi 52213114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi private void onReevaluateRemote() { 52223114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi if (DEBUG_VOL) { Log.w(TAG, "onReevaluateRemote()"); } 52233114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi // is there a registered RemoteControlClient that is handling remote playback 52243114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi boolean hasRemotePlayback = false; 52253114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi synchronized (mRCStack) { 52263114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator(); 52273114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi while(stackIterator.hasNext()) { 52283114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi RemoteControlStackEntry rcse = stackIterator.next(); 52293114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi if (rcse.mPlaybackType == RemoteControlClient.PLAYBACK_TYPE_REMOTE) { 52303114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi hasRemotePlayback = true; 52313114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi break; 52323114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi } 52333114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi } 52343114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi } 52353114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi synchronized (mMainRemote) { 52363114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi if (mHasRemotePlayback != hasRemotePlayback) { 52373114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi mHasRemotePlayback = hasRemotePlayback; 52383114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi mVolumePanel.postRemoteSliderVisibility(hasRemotePlayback); 52393114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi } 52403114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi } 52413114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi } 52423114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi 5243f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi //========================================================================================== 5244f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi // Device orientation 5245f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi //========================================================================================== 5246f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi /** 5247f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi * Handles device configuration changes that may map to a change in the orientation. 5248f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi * This feature is optional, and is defined by the definition and value of the 5249f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi * "ro.audio.monitorOrientation" system property. 5250f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi */ 5251f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi private void handleConfigurationChanged(Context context) { 5252f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi try { 5253f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi // reading new orientation "safely" (i.e. under try catch) in case anything 5254f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi // goes wrong when obtaining resources and configuration 5255f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi int newOrientation = context.getResources().getConfiguration().orientation; 5256f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi if (newOrientation != mDeviceOrientation) { 5257f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi mDeviceOrientation = newOrientation; 5258f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi setOrientationForAudioSystem(); 5259f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi } 5260f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi } catch (Exception e) { 5261f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi Log.e(TAG, "Error retrieving device orientation: " + e); 5262f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi } 5263f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi } 5264f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi 5265f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi private void setOrientationForAudioSystem() { 5266f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi switch (mDeviceOrientation) { 5267f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi case Configuration.ORIENTATION_LANDSCAPE: 5268f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi //Log.i(TAG, "orientation is landscape"); 5269f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi AudioSystem.setParameters("orientation=landscape"); 5270f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi break; 5271f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi case Configuration.ORIENTATION_PORTRAIT: 5272f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi //Log.i(TAG, "orientation is portrait"); 5273f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi AudioSystem.setParameters("orientation=portrait"); 5274f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi break; 5275f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi case Configuration.ORIENTATION_SQUARE: 5276f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi //Log.i(TAG, "orientation is square"); 5277f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi AudioSystem.setParameters("orientation=square"); 5278f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi break; 5279f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi case Configuration.ORIENTATION_UNDEFINED: 5280f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi //Log.i(TAG, "orientation is undefined"); 5281f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi AudioSystem.setParameters("orientation=undefined"); 5282f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi break; 5283f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi default: 5284f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi Log.e(TAG, "Unknown orientation"); 5285f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi } 5286f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi } 5287f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi 5288f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi 52897847211fb4699bf6018e29d214a918ed6657319bEric Laurent // Handles request to override default use of A2DP for media. 52907847211fb4699bf6018e29d214a918ed6657319bEric Laurent public void setBluetoothA2dpOnInt(boolean on) { 52917847211fb4699bf6018e29d214a918ed6657319bEric Laurent synchronized (mBluetoothA2dpEnabledLock) { 52927847211fb4699bf6018e29d214a918ed6657319bEric Laurent mBluetoothA2dpEnabled = on; 52937847211fb4699bf6018e29d214a918ed6657319bEric Laurent sendMsg(mAudioHandler, MSG_SET_FORCE_USE, SENDMSG_QUEUE, 52947847211fb4699bf6018e29d214a918ed6657319bEric Laurent AudioSystem.FOR_MEDIA, 52957847211fb4699bf6018e29d214a918ed6657319bEric Laurent mBluetoothA2dpEnabled ? AudioSystem.FORCE_NONE : AudioSystem.FORCE_NO_BT_A2DP, 52967847211fb4699bf6018e29d214a918ed6657319bEric Laurent null, 0); 52977847211fb4699bf6018e29d214a918ed6657319bEric Laurent } 52987847211fb4699bf6018e29d214a918ed6657319bEric Laurent } 52997847211fb4699bf6018e29d214a918ed6657319bEric Laurent 5300d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi @Override 5301098d580cc2bb6c0891c756a4e5230c6c6b0d2376Jeff Sharkey public void setRingtonePlayer(IRingtonePlayer player) { 5302098d580cc2bb6c0891c756a4e5230c6c6b0d2376Jeff Sharkey mContext.enforceCallingOrSelfPermission(REMOTE_AUDIO_PLAYBACK, null); 5303098d580cc2bb6c0891c756a4e5230c6c6b0d2376Jeff Sharkey mRingtonePlayer = player; 5304098d580cc2bb6c0891c756a4e5230c6c6b0d2376Jeff Sharkey } 5305098d580cc2bb6c0891c756a4e5230c6c6b0d2376Jeff Sharkey 5306098d580cc2bb6c0891c756a4e5230c6c6b0d2376Jeff Sharkey @Override 5307098d580cc2bb6c0891c756a4e5230c6c6b0d2376Jeff Sharkey public IRingtonePlayer getRingtonePlayer() { 5308098d580cc2bb6c0891c756a4e5230c6c6b0d2376Jeff Sharkey return mRingtonePlayer; 5309098d580cc2bb6c0891c756a4e5230c6c6b0d2376Jeff Sharkey } 5310098d580cc2bb6c0891c756a4e5230c6c6b0d2376Jeff Sharkey 5311098d580cc2bb6c0891c756a4e5230c6c6b0d2376Jeff Sharkey @Override 5312632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn public AudioRoutesInfo startWatchingRoutes(IAudioRoutesObserver observer) { 5313632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn synchronized (mCurAudioRoutes) { 5314632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn AudioRoutesInfo routes = new AudioRoutesInfo(mCurAudioRoutes); 5315632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn mRoutesObservers.register(observer); 5316632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn return routes; 5317632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn } 5318632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn } 5319632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn 5320632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn @Override 5321d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 5322eb4cc492c93ab9635dde78b958a834120412e72aJeff Sharkey mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DUMP, TAG); 5323eb4cc492c93ab9635dde78b958a834120412e72aJeff Sharkey 5324d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi dumpFocusStack(pw); 5325d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi dumpRCStack(pw); 53263114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi dumpRCCStack(pw); 5327bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent dumpStreamStates(pw); 5328632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn pw.println("\nAudio routes:"); 5329632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn pw.print(" mMainType=0x"); pw.println(Integer.toHexString(mCurAudioRoutes.mMainType)); 5330632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn pw.print(" mBluetoothName="); pw.println(mCurAudioRoutes.mBluetoothName); 5331d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi } 53329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project} 5333