AudioService.java revision f2b0c11f4e797e183131261724d8de310dac5431
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; 146c390bed06b4a572e273ead1254da9a932e04dce3Eric Laurent private static final int MSG_SET_FORCE_BT_A2DP_USE = 20; 1473114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi // start of messages handled under wakelock 1483114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi // these messages can only be queued, i.e. sent with queueMsgUnderWakeLock(), 149e12c39bb9cedb8b363658979872694eb55b1386eJean-Michel Trivi // and not with sendMsg(..., ..., SENDMSG_QUEUE, ...) 150c390bed06b4a572e273ead1254da9a932e04dce3Eric Laurent private static final int MSG_SET_WIRED_DEVICE_CONNECTION_STATE = 21; 151c390bed06b4a572e273ead1254da9a932e04dce3Eric Laurent private static final int MSG_SET_A2DP_CONNECTION_STATE = 22; 1523114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi // end of messages handled under wakelock 153afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent 154afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent // flags for MSG_PERSIST_VOLUME indicating if current and/or last audible volume should be 155afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent // persisted 156afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent private static final int PERSIST_CURRENT = 0x1; 157afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent private static final int PERSIST_LAST_AUDIBLE = 0x2; 158afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent 1594c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi private static final int BTA2DP_DOCK_TIMEOUT_MILLIS = 8000; 160dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent // Timeout for connection to bluetooth headset service 161dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent private static final int BT_HEADSET_CNCT_TIMEOUT_MS = 3000; 162dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent 1639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** @see AudioSystemThread */ 1649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private AudioSystemThread mAudioSystemThread; 1659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** @see AudioHandler */ 1669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private AudioHandler mAudioHandler; 1679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** @see VolumeStreamState */ 1689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private VolumeStreamState[] mStreamStates; 169b109615ebebd6f3b9ae789412279f576c3ace46bJason Parekh private SettingsObserver mSettingsObserver; 170a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent 1719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private int mMode; 172ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten // protects mRingerMode 173ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten private final Object mSettingsLock = new Object(); 17445c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent 1759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private boolean mMediaServerOk; 1769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private SoundPool mSoundPool; 17830c918ce7fbe171944b28fc91b3f22b3d631872dGlenn Kasten private final Object mSoundEffectsLock = new Object(); 1799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final int NUM_SOUNDPOOL_CHANNELS = 4; 1809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1814767690f09ea3447b8c5c32fb28d27650aa18e00Mike Lockwood // Internally master volume is a float in the 0.0 - 1.0 range, 1824767690f09ea3447b8c5c32fb28d27650aa18e00Mike Lockwood // but to support integer based AudioManager API we translate it to 0 - 100 1834767690f09ea3447b8c5c32fb28d27650aa18e00Mike Lockwood private static final int MAX_MASTER_VOLUME = 100; 1844767690f09ea3447b8c5c32fb28d27650aa18e00Mike Lockwood 1856c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang // Maximum volume adjust steps allowed in a single batch call. 1866c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang private static final int MAX_BATCH_VOLUME_ADJUST_STEPS = 4; 1876c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang 1889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /* Sound effect file names */ 1899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final String SOUND_EFFECTS_PATH = "/media/audio/ui/"; 1909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final String[] SOUND_EFFECT_FILES = new String[] { 1919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "Effect_Tick.ogg", 1929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "KeypressStandard.ogg", 1939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "KeypressSpacebar.ogg", 1949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "KeypressDelete.ogg", 1959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project "KeypressReturn.ogg" 1969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project }; 1979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /* Sound effect file name mapping sound effect id (AudioManager.FX_xxx) to 1999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * file index in SOUND_EFFECT_FILES[] (first column) and indicating if effect 2009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * uses soundpool (second column) */ 20130c918ce7fbe171944b28fc91b3f22b3d631872dGlenn Kasten private final int[][] SOUND_EFFECT_FILES_MAP = new int[][] { 2029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project {0, -1}, // FX_KEY_CLICK 2039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project {0, -1}, // FX_FOCUS_NAVIGATION_UP 2049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project {0, -1}, // FX_FOCUS_NAVIGATION_DOWN 2059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project {0, -1}, // FX_FOCUS_NAVIGATION_LEFT 2069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project {0, -1}, // FX_FOCUS_NAVIGATION_RIGHT 2079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project {1, -1}, // FX_KEYPRESS_STANDARD 2089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project {2, -1}, // FX_KEYPRESS_SPACEBAR 2099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project {3, -1}, // FX_FOCUS_DELETE 2109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project {4, -1} // FX_FOCUS_RETURN 2119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project }; 2129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2135982013cfc8274ff0bafaba83c676b3a8890cba9Jared Suttles /** @hide Maximum volume index values for audio streams */ 21430c918ce7fbe171944b28fc91b3f22b3d631872dGlenn Kasten private final int[] MAX_STREAM_VOLUME = new int[] { 2156ee9952bc20be72b9419cb653c9e2e833889a3d3Eric Laurent 5, // STREAM_VOICE_CALL 2166ee9952bc20be72b9419cb653c9e2e833889a3d3Eric Laurent 7, // STREAM_SYSTEM 2176ee9952bc20be72b9419cb653c9e2e833889a3d3Eric Laurent 7, // STREAM_RING 2186ee9952bc20be72b9419cb653c9e2e833889a3d3Eric Laurent 15, // STREAM_MUSIC 2196ee9952bc20be72b9419cb653c9e2e833889a3d3Eric Laurent 7, // STREAM_ALARM 2206ee9952bc20be72b9419cb653c9e2e833889a3d3Eric Laurent 7, // STREAM_NOTIFICATION 2216ee9952bc20be72b9419cb653c9e2e833889a3d3Eric Laurent 15, // STREAM_BLUETOOTH_SCO 2226ee9952bc20be72b9419cb653c9e2e833889a3d3Eric Laurent 7, // STREAM_SYSTEM_ENFORCED 2236ee9952bc20be72b9419cb653c9e2e833889a3d3Eric Laurent 15, // STREAM_DTMF 2246ee9952bc20be72b9419cb653c9e2e833889a3d3Eric Laurent 15 // STREAM_TTS 2255982013cfc8274ff0bafaba83c676b3a8890cba9Jared Suttles }; 2266d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent /* mStreamVolumeAlias[] indicates for each stream if it uses the volume settings 227a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent * of another stream: This avoids multiplying the volume settings for hidden 228a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent * stream types that follow other stream behavior for volume settings 2296d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent * NOTE: do not create loops in aliases! 2306d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent * Some streams alias to different streams according to device category (phone or tablet) or 2316d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent * use case (in call s off call...).See updateStreamVolumeAlias() for more details 2326d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent * mStreamVolumeAlias contains the default aliases for a voice capable device (phone) and 2336d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent * STREAM_VOLUME_ALIAS_NON_VOICE for a non voice capable device (tablet).*/ 23430c918ce7fbe171944b28fc91b3f22b3d631872dGlenn Kasten private final int[] STREAM_VOLUME_ALIAS = new int[] { 2356d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent AudioSystem.STREAM_VOICE_CALL, // STREAM_VOICE_CALL 2366d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent AudioSystem.STREAM_RING, // STREAM_SYSTEM 2376d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent AudioSystem.STREAM_RING, // STREAM_RING 2386d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent AudioSystem.STREAM_MUSIC, // STREAM_MUSIC 2396d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent AudioSystem.STREAM_ALARM, // STREAM_ALARM 2406d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent AudioSystem.STREAM_RING, // STREAM_NOTIFICATION 2416d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent AudioSystem.STREAM_BLUETOOTH_SCO, // STREAM_BLUETOOTH_SCO 2426d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent AudioSystem.STREAM_RING, // STREAM_SYSTEM_ENFORCED 2436d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent AudioSystem.STREAM_RING, // STREAM_DTMF 2446d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent AudioSystem.STREAM_MUSIC // STREAM_TTS 245a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent }; 2466d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent private final int[] STREAM_VOLUME_ALIAS_NON_VOICE = new int[] { 2476d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent AudioSystem.STREAM_VOICE_CALL, // STREAM_VOICE_CALL 2486d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent AudioSystem.STREAM_MUSIC, // STREAM_SYSTEM 2496d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent AudioSystem.STREAM_RING, // STREAM_RING 2506d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent AudioSystem.STREAM_MUSIC, // STREAM_MUSIC 2516d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent AudioSystem.STREAM_ALARM, // STREAM_ALARM 2526d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent AudioSystem.STREAM_RING, // STREAM_NOTIFICATION 2536d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent AudioSystem.STREAM_BLUETOOTH_SCO, // STREAM_BLUETOOTH_SCO 2546d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent AudioSystem.STREAM_MUSIC, // STREAM_SYSTEM_ENFORCED 2556d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent AudioSystem.STREAM_MUSIC, // STREAM_DTMF 2566d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent AudioSystem.STREAM_MUSIC // STREAM_TTS 2576d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent }; 2586d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent private int[] mStreamVolumeAlias; 259a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent 260bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent // stream names used by dumpStreamStates() 261bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent private final String[] STREAM_NAMES = new String[] { 262bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent "STREAM_VOICE_CALL", 263bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent "STREAM_SYSTEM", 264bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent "STREAM_RING", 265bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent "STREAM_MUSIC", 266bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent "STREAM_ALARM", 267bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent "STREAM_NOTIFICATION", 268bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent "STREAM_BLUETOOTH_SCO", 269bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent "STREAM_SYSTEM_ENFORCED", 270bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent "STREAM_DTMF", 271bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent "STREAM_TTS" 272bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent }; 273bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent 27430c918ce7fbe171944b28fc91b3f22b3d631872dGlenn Kasten private final AudioSystem.ErrorCallback mAudioSystemCallback = new AudioSystem.ErrorCallback() { 2759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void onError(int error) { 2769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project switch (error) { 2779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project case AudioSystem.AUDIO_STATUS_SERVER_DIED: 2789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mMediaServerOk) { 279afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent sendMsg(mAudioHandler, MSG_MEDIA_SERVER_DIED, SENDMSG_NOOP, 0, 0, 2809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project null, 1500); 28189e74ba1419732dd5c7f939e48d4aa7989fd3a51Eric Laurent mMediaServerOk = false; 2829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project break; 2849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project case AudioSystem.AUDIO_STATUS_OK: 2859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (!mMediaServerOk) { 286afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent sendMsg(mAudioHandler, MSG_MEDIA_SERVER_STARTED, SENDMSG_NOOP, 0, 0, 2879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project null, 0); 28889e74ba1419732dd5c7f939e48d4aa7989fd3a51Eric Laurent mMediaServerOk = true; 2899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project break; 2919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project default: 2929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project break; 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 /** 2989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Current ringer mode from one of {@link AudioManager#RINGER_MODE_NORMAL}, 2999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * {@link AudioManager#RINGER_MODE_SILENT}, or 3009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * {@link AudioManager#RINGER_MODE_VIBRATE}. 3019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 302ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten // protected by mSettingsLock 3039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private int mRingerMode; 3049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3059bcf401d13d47416043a704430388abd59aef7cdEric Laurent /** @see System#MODE_RINGER_STREAMS_AFFECTED */ 3069bcf401d13d47416043a704430388abd59aef7cdEric Laurent private int mRingerModeAffectedStreams; 3079bcf401d13d47416043a704430388abd59aef7cdEric Laurent 3085b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent // Streams currently muted by ringer mode 3095b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent private int mRingerModeMutedStreams; 3105b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent 3119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** @see System#MUTE_STREAMS_AFFECTED */ 3129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private int mMuteAffectedStreams; 3139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 315bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent * NOTE: setVibrateSetting(), getVibrateSetting(), shouldVibrate() are deprecated. 316bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent * mVibrateSetting is just maintained during deprecation period but vibration policy is 317bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent * now only controlled by mHasVibrator and mRingerMode 3189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 3199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private int mVibrateSetting; 3209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 321bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent // Is there a vibrator 322bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent private final boolean mHasVibrator; 323bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent 324a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent // Broadcast receiver for device connections intent broadcasts 325a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent private final BroadcastReceiver mReceiver = new AudioServiceBroadcastReceiver(); 326a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent 327e73131a68408a0495ba96a4d5a60799ba293c176Jean-Michel Trivi // Used to alter media button redirection when the phone is ringing. 328e73131a68408a0495ba96a4d5a60799ba293c176Jean-Michel Trivi private boolean mIsRinging = false; 329e73131a68408a0495ba96a4d5a60799ba293c176Jean-Michel Trivi 330c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent // Devices currently connected 33130c918ce7fbe171944b28fc91b3f22b3d631872dGlenn Kasten private final HashMap <Integer, String> mConnectedDevices = new HashMap <Integer, String>(); 332c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent 333c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent // Forced device usage for communications 334c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent private int mForcedUseForComm; 335c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent 3360dc37cce9d564ae43883c8dc8672b9266b881e63Mike Lockwood // True if we have master volume support 3370dc37cce9d564ae43883c8dc8672b9266b881e63Mike Lockwood private final boolean mUseMasterVolume; 3380dc37cce9d564ae43883c8dc8672b9266b881e63Mike Lockwood 3399760647dd0ee67e7c20f3e9d661d2006b1df0b54Mike Lockwood private final int[] mMasterVolumeRamp; 3409760647dd0ee67e7c20f3e9d661d2006b1df0b54Mike Lockwood 3419272b4b4a44fe1f33e3030810618194f817caaecEric Laurent // List of binder death handlers for setMode() client processes. 3429272b4b4a44fe1f33e3030810618194f817caaecEric Laurent // The last process to have called setMode() is at the top of the list. 34330c918ce7fbe171944b28fc91b3f22b3d631872dGlenn Kasten private final ArrayList <SetModeDeathHandler> mSetModeDeathHandlers = new ArrayList <SetModeDeathHandler>(); 344eb14a783be073b5fd6e8c8c9bc87d2d1919f2c9eEric Laurent 3453def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent // List of clients having issued a SCO start request 34630c918ce7fbe171944b28fc91b3f22b3d631872dGlenn Kasten private final ArrayList <ScoClient> mScoClients = new ArrayList <ScoClient>(); 3473def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent 3483def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent // BluetoothHeadset API to control SCO connection 3493def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent private BluetoothHeadset mBluetoothHeadset; 3503def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent 35182aa7f017daaaeb96c13e6e3491d5037ab471085Jaikumar Ganesh // Bluetooth headset device 35282aa7f017daaaeb96c13e6e3491d5037ab471085Jaikumar Ganesh private BluetoothDevice mBluetoothHeadsetDevice; 3533def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent 35462ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent // Indicate if SCO audio connection is currently active and if the initiator is 35562ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent // audio service (internal) or bluetooth headset (external) 35662ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent private int mScoAudioState; 35762ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent // SCO audio state is not active 35862ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent private static final int SCO_STATE_INACTIVE = 0; 359dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent // SCO audio activation request waiting for headset service to connect 360dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent private static final int SCO_STATE_ACTIVATE_REQ = 1; 36162ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent // SCO audio state is active or starting due to a local request to start a virtual call 362dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent private static final int SCO_STATE_ACTIVE_INTERNAL = 3; 363dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent // SCO audio deactivation request waiting for headset service to connect 364dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent private static final int SCO_STATE_DEACTIVATE_REQ = 5; 365dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent 36662ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent // SCO audio state is active due to an action in BT handsfree (either voice recognition or 36762ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent // in call audio) 36862ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent private static final int SCO_STATE_ACTIVE_EXTERNAL = 2; 369dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent // Deactivation request for all SCO connections (initiated by audio mode change) 370dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent // waiting for headset service to connect 371dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent private static final int SCO_STATE_DEACTIVATE_EXT_REQ = 4; 372dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent 373dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent // Current connection state indicated by bluetooth headset 374dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent private int mScoConnectionState; 37562ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent 376a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent // true if boot sequence has been completed 377a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent private boolean mBootCompleted; 378a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent // listener for SoundPool sample load completion indication 379a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent private SoundPoolCallback mSoundPoolCallBack; 380a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent // thread for SoundPool listener 381a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent private SoundPoolListenerThread mSoundPoolListenerThread; 382a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent // message looper for SoundPool listener 383a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent private Looper mSoundPoolLooper = null; 384c55b393efd462490cd5e27fc373bceafdd25662eJean-Michel Trivi // volume applied to sound played with playSoundEffect() 385f2b0c11f4e797e183131261724d8de310dac5431Jean-Michel Trivi private static int sSoundEffectVolumeDb; 38625101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent // getActiveStreamType() will return STREAM_NOTIFICATION during this period after a notification 38725101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent // stopped 38825101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent private static final int NOTIFICATION_VOLUME_DELAY_MS = 5000; 38925101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent // previous volume adjustment direction received by checkForRingerModeChange() 39025101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent private int mPrevVolDirection = AudioManager.ADJUST_SAME; 3916243edd818b84adfbe712d5d233d6414b33653acAmith Yamasani // Keyguard manager proxy 3926243edd818b84adfbe712d5d233d6414b33653acAmith Yamasani private KeyguardManager mKeyguardManager; 39345c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent // mVolumeControlStream is set by VolumePanel to temporarily force the stream type which volume 39445c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent // is controlled by Vol keys. 39545c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent private int mVolumeControlStream = -1; 39645c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent private final Object mForceControlStreamLock = new Object(); 39745c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent // VolumePanel is currently the only client of forceVolumeControlStream() and runs in system 39845c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent // server process so in theory it is not necessary to monitor the client death. 39945c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent // However it is good to be ready for future evolutions. 40045c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent private ForceControlStreamClient mForceControlStreamClient = null; 401098d580cc2bb6c0891c756a4e5230c6c6b0d2376Jeff Sharkey // Used to play ringtones outside system_server 402098d580cc2bb6c0891c756a4e5230c6c6b0d2376Jeff Sharkey private volatile IRingtonePlayer mRingtonePlayer; 4039bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent 404f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi private int mDeviceOrientation = Configuration.ORIENTATION_UNDEFINED; 405f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi 4067847211fb4699bf6018e29d214a918ed6657319bEric Laurent // Request to override default use of A2DP for media. 4077847211fb4699bf6018e29d214a918ed6657319bEric Laurent private boolean mBluetoothA2dpEnabled; 4087847211fb4699bf6018e29d214a918ed6657319bEric Laurent private final Object mBluetoothA2dpEnabledLock = new Object(); 4097847211fb4699bf6018e29d214a918ed6657319bEric Laurent 410632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn // Monitoring of audio routes. Protected by mCurAudioRoutes. 411632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn final AudioRoutesInfo mCurAudioRoutes = new AudioRoutesInfo(); 412632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn final RemoteCallbackList<IAudioRoutesObserver> mRoutesObservers 413632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn = new RemoteCallbackList<IAudioRoutesObserver>(); 414632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn 4153114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi /** 4163114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi * A fake stream type to match the notion of remote media playback 4173114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi */ 4183114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi public final static int STREAM_REMOTE_MUSIC = -200; 4193114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi 4209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /////////////////////////////////////////////////////////////////////////// 4219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Construction 4229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /////////////////////////////////////////////////////////////////////////// 4239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** @hide */ 4259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public AudioService(Context context) { 4269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mContext = context; 4279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mContentResolver = context.getContentResolver(); 428c7fcba4b7bd3d78e7cfe975a3f8e4dde2f6738b7Joe Onorato mVoiceCapable = mContext.getResources().getBoolean( 429c7fcba4b7bd3d78e7cfe975a3f8e4dde2f6738b7Joe Onorato com.android.internal.R.bool.config_voice_capable); 4305982013cfc8274ff0bafaba83c676b3a8890cba9Jared Suttles 431c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE); 4322d8dab5a549b25b6f36df4614d7c0166d4d099e2Jean-Michel Trivi mMediaEventWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "handleMediaEvent"); 433c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi 434bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent Vibrator vibrator = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE); 435bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent mHasVibrator = vibrator == null ? false : vibrator.hasVibrator(); 436bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent 4375982013cfc8274ff0bafaba83c676b3a8890cba9Jared Suttles // Intialized volume 4385982013cfc8274ff0bafaba83c676b3a8890cba9Jared Suttles MAX_STREAM_VOLUME[AudioSystem.STREAM_VOICE_CALL] = SystemProperties.getInt( 4395982013cfc8274ff0bafaba83c676b3a8890cba9Jared Suttles "ro.config.vc_call_vol_steps", 4405982013cfc8274ff0bafaba83c676b3a8890cba9Jared Suttles MAX_STREAM_VOLUME[AudioSystem.STREAM_VOICE_CALL]); 4415982013cfc8274ff0bafaba83c676b3a8890cba9Jared Suttles 442f2b0c11f4e797e183131261724d8de310dac5431Jean-Michel Trivi sSoundEffectVolumeDb = context.getResources().getInteger( 443c55b393efd462490cd5e27fc373bceafdd25662eJean-Michel Trivi com.android.internal.R.integer.config_soundEffectVolumeDb); 44425101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent 4459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mVolumePanel = new VolumePanel(context, this); 4466d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent mMode = AudioSystem.MODE_NORMAL; 447c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent mForcedUseForComm = AudioSystem.FORCE_NONE; 4489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project createAudioSystemThread(); 4499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project readPersistedSettings(); 450c1d4166289ce016965d1147f7e8d37862ee347ecEric Laurent mSettingsObserver = new SettingsObserver(); 4516d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent updateStreamVolumeAlias(false /*updateVolumes*/); 452a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent createStreamStates(); 4539f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent 4549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mMediaServerOk = true; 4553891c4cc918e8062abb97c542a8625d556dccc59Eric Laurent 4563891c4cc918e8062abb97c542a8625d556dccc59Eric Laurent // Call setRingerModeInt() to apply correct mute 4573891c4cc918e8062abb97c542a8625d556dccc59Eric Laurent // state on streams affected by ringer mode. 4583891c4cc918e8062abb97c542a8625d556dccc59Eric Laurent mRingerModeMutedStreams = 0; 4593891c4cc918e8062abb97c542a8625d556dccc59Eric Laurent setRingerModeInt(getRingerMode(), false); 4603891c4cc918e8062abb97c542a8625d556dccc59Eric Laurent 4619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project AudioSystem.setErrorCallback(mAudioSystemCallback); 462a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent 463a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent // Register for device connection intent broadcasts. 464a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent IntentFilter intentFilter = 465b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent new IntentFilter(BluetoothHeadset.ACTION_AUDIO_STATE_CHANGED); 46682aa7f017daaaeb96c13e6e3491d5037ab471085Jaikumar Ganesh intentFilter.addAction(BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED); 46782aa7f017daaaeb96c13e6e3491d5037ab471085Jaikumar Ganesh intentFilter.addAction(Intent.ACTION_DOCK_EVENT); 46859f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent intentFilter.addAction(Intent.ACTION_USB_AUDIO_ACCESSORY_PLUG); 46959f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent intentFilter.addAction(Intent.ACTION_USB_AUDIO_DEVICE_PLUG); 47062ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent intentFilter.addAction(Intent.ACTION_BOOT_COMPLETED); 471950e8cb40a6d826af4cc2eef9d3908c1b70486e6Eric Laurent intentFilter.addAction(Intent.ACTION_SCREEN_ON); 472950e8cb40a6d826af4cc2eef9d3908c1b70486e6Eric Laurent intentFilter.addAction(Intent.ACTION_SCREEN_OFF); 473f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi 474f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi // Register a configuration change listener only if requested by system properties 475f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi // to monitor orientation changes (off by default) 476f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi if (SystemProperties.getBoolean("ro.audio.monitorOrientation", false)) { 477f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi Log.v(TAG, "monitoring device orientation"); 478f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi intentFilter.addAction(Intent.ACTION_CONFIGURATION_CHANGED); 479f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi // initialize orientation in AudioSystem 480f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi setOrientationForAudioSystem(); 481f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi } 482f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi 483a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent context.registerReceiver(mReceiver, intentFilter); 4845982013cfc8274ff0bafaba83c676b3a8890cba9Jared Suttles 485d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi // Register for package removal intent broadcasts for media button receiver persistence 486d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi IntentFilter pkgFilter = new IntentFilter(); 487d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi pkgFilter.addAction(Intent.ACTION_PACKAGE_REMOVED); 488d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi pkgFilter.addDataScheme("package"); 489d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi context.registerReceiver(mReceiver, pkgFilter); 490d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi 491b4bccb6d8df16a2c5235cead187156bc721cf074Jean-Michel Trivi // Register for phone state monitoring 492b4bccb6d8df16a2c5235cead187156bc721cf074Jean-Michel Trivi TelephonyManager tmgr = (TelephonyManager) 493b4bccb6d8df16a2c5235cead187156bc721cf074Jean-Michel Trivi context.getSystemService(Context.TELEPHONY_SERVICE); 494b4bccb6d8df16a2c5235cead187156bc721cf074Jean-Michel Trivi tmgr.listen(mPhoneStateListener, PhoneStateListener.LISTEN_CALL_STATE); 4958517e46f3d3c2ce11de09aa849a8533ffc1a2026Mike Lockwood 4960dc37cce9d564ae43883c8dc8672b9266b881e63Mike Lockwood mUseMasterVolume = context.getResources().getBoolean( 4970dc37cce9d564ae43883c8dc8672b9266b881e63Mike Lockwood com.android.internal.R.bool.config_useMasterVolume); 4989063154a793b0ab38b3c5992cbaed046427b4a82Mike Lockwood restoreMasterVolume(); 4999760647dd0ee67e7c20f3e9d661d2006b1df0b54Mike Lockwood 5009760647dd0ee67e7c20f3e9d661d2006b1df0b54Mike Lockwood mMasterVolumeRamp = context.getResources().getIntArray( 5019760647dd0ee67e7c20f3e9d661d2006b1df0b54Mike Lockwood com.android.internal.R.array.config_masterVolumeRamp); 5027847211fb4699bf6018e29d214a918ed6657319bEric Laurent 5033114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi mMainRemote = new RemotePlaybackState(-1, MAX_STREAM_VOLUME[AudioManager.STREAM_MUSIC], 5043114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi MAX_STREAM_VOLUME[AudioManager.STREAM_MUSIC]); 5053114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi mHasRemotePlayback = false; 5063114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi mMainRemoteIsActive = false; 5073114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi postReevaluateRemote(); 5089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private void createAudioSystemThread() { 5119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mAudioSystemThread = new AudioSystemThread(); 5129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mAudioSystemThread.start(); 5139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project waitForAudioHandlerCreation(); 5149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** Waits for the volume handler to be created by the other thread. */ 5179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private void waitForAudioHandlerCreation() { 5189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project synchronized(this) { 5199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project while (mAudioHandler == null) { 5209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project try { 5219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Wait for mAudioHandler to be set by the other thread 5229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project wait(); 5239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } catch (InterruptedException e) { 5249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Log.e(TAG, "Interrupted while waiting on volume handler."); 5259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 530244820185269991186d07068b92985624cede4a5Eric Laurent private void checkAllAliasStreamVolumes() { 531244820185269991186d07068b92985624cede4a5Eric Laurent int numStreamTypes = AudioSystem.getNumStreamTypes(); 532244820185269991186d07068b92985624cede4a5Eric Laurent for (int streamType = 0; streamType < numStreamTypes; streamType++) { 533244820185269991186d07068b92985624cede4a5Eric Laurent if (streamType != mStreamVolumeAlias[streamType]) { 534244820185269991186d07068b92985624cede4a5Eric Laurent mStreamStates[streamType]. 535244820185269991186d07068b92985624cede4a5Eric Laurent setAllIndexes(mStreamStates[mStreamVolumeAlias[streamType]], 536244820185269991186d07068b92985624cede4a5Eric Laurent false /*lastAudible*/); 537244820185269991186d07068b92985624cede4a5Eric Laurent mStreamStates[streamType]. 538244820185269991186d07068b92985624cede4a5Eric Laurent setAllIndexes(mStreamStates[mStreamVolumeAlias[streamType]], 539244820185269991186d07068b92985624cede4a5Eric Laurent true /*lastAudible*/); 540244820185269991186d07068b92985624cede4a5Eric Laurent } 541244820185269991186d07068b92985624cede4a5Eric Laurent // apply stream volume 542244820185269991186d07068b92985624cede4a5Eric Laurent if (mStreamStates[streamType].muteCount() == 0) { 543244820185269991186d07068b92985624cede4a5Eric Laurent mStreamStates[streamType].applyAllVolumes(); 544244820185269991186d07068b92985624cede4a5Eric Laurent } 545244820185269991186d07068b92985624cede4a5Eric Laurent } 546244820185269991186d07068b92985624cede4a5Eric Laurent } 547244820185269991186d07068b92985624cede4a5Eric Laurent 5489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private void createStreamStates() { 5499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int numStreamTypes = AudioSystem.getNumStreamTypes(); 5509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project VolumeStreamState[] streams = mStreamStates = new VolumeStreamState[numStreamTypes]; 5519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (int i = 0; i < numStreamTypes; i++) { 5536d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent streams[i] = new VolumeStreamState(System.VOLUME_SETTINGS[mStreamVolumeAlias[i]], i); 5549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 556244820185269991186d07068b92985624cede4a5Eric Laurent checkAllAliasStreamVolumes(); 5579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 559bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent private void dumpStreamStates(PrintWriter pw) { 560bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent pw.println("\nStream volumes (device: index)"); 561bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent int numStreamTypes = AudioSystem.getNumStreamTypes(); 562bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent for (int i = 0; i < numStreamTypes; i++) { 563bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent pw.println("- "+STREAM_NAMES[i]+":"); 564bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent mStreamStates[i].dump(pw); 565bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent pw.println(""); 566bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent } 567bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent } 568bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent 5696d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent 5706d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent private void updateStreamVolumeAlias(boolean updateVolumes) { 5716d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent int dtmfStreamAlias; 5726d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent if (mVoiceCapable) { 5736d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent mStreamVolumeAlias = STREAM_VOLUME_ALIAS; 5746d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent dtmfStreamAlias = AudioSystem.STREAM_RING; 5756d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent } else { 5766d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent mStreamVolumeAlias = STREAM_VOLUME_ALIAS_NON_VOICE; 5776d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent dtmfStreamAlias = AudioSystem.STREAM_MUSIC; 5786d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent } 5796d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent if (isInCommunication()) { 5806d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent dtmfStreamAlias = AudioSystem.STREAM_VOICE_CALL; 5816d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent } 5826d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent mStreamVolumeAlias[AudioSystem.STREAM_DTMF] = dtmfStreamAlias; 5836d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent if (updateVolumes) { 5846d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent mStreamStates[AudioSystem.STREAM_DTMF].setAllIndexes(mStreamStates[dtmfStreamAlias], 5856d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent false /*lastAudible*/); 5866d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent mStreamStates[AudioSystem.STREAM_DTMF].setAllIndexes(mStreamStates[dtmfStreamAlias], 5876d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent true /*lastAudible*/); 5886d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent sendMsg(mAudioHandler, 5896d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent MSG_SET_ALL_VOLUMES, 5906d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent SENDMSG_QUEUE, 5916d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent 0, 5926d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent 0, 5936d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent mStreamStates[AudioSystem.STREAM_DTMF], 0); 5946d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent } 5956d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent } 5966d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent 5979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private void readPersistedSettings() { 5989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final ContentResolver cr = mContentResolver; 5999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 600bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent int ringerModeFromSettings = 601bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent System.getInt(cr, System.MODE_RINGER, AudioManager.RINGER_MODE_NORMAL); 602bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent int ringerMode = ringerModeFromSettings; 60372668b2c040b581b298b069f3b5af5ed7f212d89Eric Laurent // sanity check in case the settings are restored from a device with incompatible 60472668b2c040b581b298b069f3b5af5ed7f212d89Eric Laurent // ringer modes 605ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten if (!AudioManager.isValidRingerMode(ringerMode)) { 606ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten ringerMode = AudioManager.RINGER_MODE_NORMAL; 607bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent } 608bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent if ((ringerMode == AudioManager.RINGER_MODE_VIBRATE) && !mHasVibrator) { 609bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent ringerMode = AudioManager.RINGER_MODE_SILENT; 610bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent } 611bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent if (ringerMode != ringerModeFromSettings) { 612ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten System.putInt(cr, System.MODE_RINGER, ringerMode); 613ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten } 614ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten synchronized(mSettingsLock) { 615ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten mRingerMode = ringerMode; 61672668b2c040b581b298b069f3b5af5ed7f212d89Eric Laurent } 6179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 618bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent // System.VIBRATE_ON is not used any more but defaults for mVibrateSetting 619bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent // are still needed while setVibrateSetting() and getVibrateSetting() are being deprecated. 620bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent mVibrateSetting = getValueForVibrateSetting(0, 621bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent AudioManager.VIBRATE_TYPE_NOTIFICATION, 622bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent mHasVibrator ? AudioManager.VIBRATE_SETTING_ONLY_SILENT 623bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent : AudioManager.VIBRATE_SETTING_OFF); 624bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent mVibrateSetting = getValueForVibrateSetting(mVibrateSetting, 625bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent AudioManager.VIBRATE_TYPE_RINGER, 626bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent mHasVibrator ? AudioManager.VIBRATE_SETTING_ONLY_SILENT 627bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent : AudioManager.VIBRATE_SETTING_OFF); 6289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 629c1d4166289ce016965d1147f7e8d37862ee347ecEric Laurent // make sure settings for ringer mode are consistent with device type: non voice capable 630c1d4166289ce016965d1147f7e8d37862ee347ecEric Laurent // devices (tablets) include media stream in silent mode whereas phones don't. 6319bcf401d13d47416043a704430388abd59aef7cdEric Laurent mRingerModeAffectedStreams = Settings.System.getInt(cr, 6329bcf401d13d47416043a704430388abd59aef7cdEric Laurent Settings.System.MODE_RINGER_STREAMS_AFFECTED, 633a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent ((1 << AudioSystem.STREAM_RING)|(1 << AudioSystem.STREAM_NOTIFICATION)| 634c1d4166289ce016965d1147f7e8d37862ee347ecEric Laurent (1 << AudioSystem.STREAM_SYSTEM)|(1 << AudioSystem.STREAM_SYSTEM_ENFORCED))); 635c1d4166289ce016965d1147f7e8d37862ee347ecEric Laurent if (mVoiceCapable) { 636c1d4166289ce016965d1147f7e8d37862ee347ecEric Laurent mRingerModeAffectedStreams &= ~(1 << AudioSystem.STREAM_MUSIC); 637c1d4166289ce016965d1147f7e8d37862ee347ecEric Laurent } else { 638402f7f29634a9f68e7929be828a927a3e2f5efe9Eric Laurent mRingerModeAffectedStreams |= (1 << AudioSystem.STREAM_MUSIC); 639402f7f29634a9f68e7929be828a927a3e2f5efe9Eric Laurent } 640c1d4166289ce016965d1147f7e8d37862ee347ecEric Laurent Settings.System.putInt(cr, 641c1d4166289ce016965d1147f7e8d37862ee347ecEric Laurent Settings.System.MODE_RINGER_STREAMS_AFFECTED, mRingerModeAffectedStreams); 642c1d4166289ce016965d1147f7e8d37862ee347ecEric Laurent 6439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mMuteAffectedStreams = System.getInt(cr, 6449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project System.MUTE_STREAMS_AFFECTED, 6459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ((1 << AudioSystem.STREAM_MUSIC)|(1 << AudioSystem.STREAM_RING)|(1 << AudioSystem.STREAM_SYSTEM))); 6469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 64757978ed86286a33d5b1a0fd000ca3406ba9d87b3Justin Koh boolean masterMute = System.getInt(cr, System.VOLUME_MASTER_MUTE, 0) == 1; 64857978ed86286a33d5b1a0fd000ca3406ba9d87b3Justin Koh AudioSystem.setMasterMute(masterMute); 64957978ed86286a33d5b1a0fd000ca3406ba9d87b3Justin Koh broadcastMasterMuteStatus(masterMute); 65057978ed86286a33d5b1a0fd000ca3406ba9d87b3Justin Koh 6519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Each stream will read its own persisted settings 6529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Broadcast the sticky intent 654ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten broadcastRingerMode(ringerMode); 6559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Broadcast vibrate settings 6579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project broadcastVibrateSetting(AudioManager.VIBRATE_TYPE_RINGER); 6589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project broadcastVibrateSetting(AudioManager.VIBRATE_TYPE_NOTIFICATION); 659d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi 660d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi // Restore the default media button receiver from the system settings 661d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi restoreMediaButtonReceiver(); 6629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 664a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent private int rescaleIndex(int index, int srcStream, int dstStream) { 665a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent return (index * mStreamStates[dstStream].getMaxIndex() + mStreamStates[srcStream].getMaxIndex() / 2) / mStreamStates[srcStream].getMaxIndex(); 666a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent } 6679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /////////////////////////////////////////////////////////////////////////// 6699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // IPC methods 6709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /////////////////////////////////////////////////////////////////////////// 6719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** @see AudioManager#adjustVolume(int, int) */ 6739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void adjustVolume(int direction, int flags) { 6749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project adjustSuggestedStreamVolume(direction, AudioManager.USE_DEFAULT_STREAM_TYPE, flags); 6759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6773114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi /** @see AudioManager#adjustLocalOrRemoteStreamVolume(int, int) with current assumption 6783114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi * on streamType: fixed to STREAM_MUSIC */ 6793114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi public void adjustLocalOrRemoteStreamVolume(int streamType, int direction) { 6803114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi if (DEBUG_VOL) Log.d(TAG, "adjustLocalOrRemoteStreamVolume(dir="+direction+")"); 6813114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi if (checkUpdateRemoteStateIfActive(AudioSystem.STREAM_MUSIC)) { 6823114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi adjustRemoteVolume(AudioSystem.STREAM_MUSIC, direction, 0); 6833114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi } else if (AudioSystem.isStreamActive(AudioSystem.STREAM_MUSIC, 0)) { 6843114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi adjustStreamVolume(AudioSystem.STREAM_MUSIC, direction, 0); 6853114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi } 6863114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi } 6873114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi 6889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** @see AudioManager#adjustVolume(int, int, int) */ 6899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void adjustSuggestedStreamVolume(int direction, int suggestedStreamType, int flags) { 6903114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi if (DEBUG_VOL) Log.d(TAG, "adjustSuggestedStreamVolume() stream="+suggestedStreamType); 691402f7f29634a9f68e7929be828a927a3e2f5efe9Eric Laurent int streamType; 69245c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent if (mVolumeControlStream != -1) { 69345c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent streamType = mVolumeControlStream; 694402f7f29634a9f68e7929be828a927a3e2f5efe9Eric Laurent } else { 695402f7f29634a9f68e7929be828a927a3e2f5efe9Eric Laurent streamType = getActiveStreamType(suggestedStreamType); 696402f7f29634a9f68e7929be828a927a3e2f5efe9Eric Laurent } 6979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6986243edd818b84adfbe712d5d233d6414b33653acAmith Yamasani // Play sounds on STREAM_RING only and if lock screen is not on. 6993114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi if ((streamType != STREAM_REMOTE_MUSIC) && 7003114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi (flags & AudioManager.FLAG_PLAY_SOUND) != 0 && 7016d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent ((mStreamVolumeAlias[streamType] != AudioSystem.STREAM_RING) 7026243edd818b84adfbe712d5d233d6414b33653acAmith Yamasani || (mKeyguardManager != null && mKeyguardManager.isKeyguardLocked()))) { 7039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project flags &= ~AudioManager.FLAG_PLAY_SOUND; 7049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 7063114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi if (streamType == STREAM_REMOTE_MUSIC) { 7073114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi // don't play sounds for remote 7083114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi flags &= ~AudioManager.FLAG_PLAY_SOUND; 7093114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi //if (DEBUG_VOL) Log.i(TAG, "Need to adjust remote volume: calling adjustRemoteVolume()"); 7103114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi adjustRemoteVolume(AudioSystem.STREAM_MUSIC, direction, flags); 7113114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi } else { 7123114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi adjustStreamVolume(streamType, direction, flags); 7133114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi } 7149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 7169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** @see AudioManager#adjustStreamVolume(int, int, int) */ 7179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void adjustStreamVolume(int streamType, int direction, int flags) { 7183114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi if (DEBUG_VOL) Log.d(TAG, "adjustStreamVolume() stream="+streamType+", dir="+direction); 7193114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi 7209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ensureValidDirection(direction); 7219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ensureValidStreamType(streamType); 7229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 72396a33d1caad2fab0bc28891cfbf553f4b050bf0bEric Laurent // use stream type alias here so that streams with same alias have the same behavior, 72496a33d1caad2fab0bc28891cfbf553f4b050bf0bEric Laurent // including with regard to silent mode control (e.g the use of STREAM_RING below and in 72596a33d1caad2fab0bc28891cfbf553f4b050bf0bEric Laurent // checkForRingerModeChange() in place of STREAM_RING or STREAM_NOTIFICATION) 7266d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent int streamTypeAlias = mStreamVolumeAlias[streamType]; 727b024c30a80684ac08daef3137b7ba0d347fe3ce5Eric Laurent VolumeStreamState streamState = mStreamStates[streamTypeAlias]; 7289bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent 7299bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent final int device = getDeviceForStream(streamTypeAlias); 7309bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent // get last audible index if stream is muted, current index otherwise 731244820185269991186d07068b92985624cede4a5Eric Laurent final int aliasIndex = streamState.getIndex(device, 7329bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent (streamState.muteCount() != 0) /* lastAudible */); 7339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project boolean adjustVolume = true; 7349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 735244820185269991186d07068b92985624cede4a5Eric Laurent // convert one UI step (+/-1) into a number of internal units on the stream alias 736244820185269991186d07068b92985624cede4a5Eric Laurent int step = rescaleIndex(10, streamType, streamTypeAlias); 737244820185269991186d07068b92985624cede4a5Eric Laurent 7389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // If either the client forces allowing ringer modes for this adjustment, 7399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // or the stream type is one that is affected by ringer modes 74025101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent if (((flags & AudioManager.FLAG_ALLOW_RINGER_MODES) != 0) || 741bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent (streamTypeAlias == getMasterStreamType())) { 742ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten int ringerMode = getRingerMode(); 743c696a53d1fe4d61373c5dc64dd057d322da90c8fAmith Yamasani // do not vibrate if already in vibrate mode 744ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten if (ringerMode == AudioManager.RINGER_MODE_VIBRATE) { 745cc11b1b8bb47aa6be23ff5c4caf683ff90074121Eric Laurent flags &= ~AudioManager.FLAG_VIBRATE; 746cc11b1b8bb47aa6be23ff5c4caf683ff90074121Eric Laurent } 7479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Check if the ringer mode changes with this volume adjustment. If 7489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // it does, it will handle adjusting the volume, so we won't below 749244820185269991186d07068b92985624cede4a5Eric Laurent adjustVolume = checkForRingerModeChange(aliasIndex, direction, step); 7508c78752f2bf786ca3e6f45b9dc6955d3b4bba59cEric Laurent if ((streamTypeAlias == getMasterStreamType()) && 7518c78752f2bf786ca3e6f45b9dc6955d3b4bba59cEric Laurent (mRingerMode == AudioManager.RINGER_MODE_SILENT)) { 7528c78752f2bf786ca3e6f45b9dc6955d3b4bba59cEric Laurent streamState.setLastAudibleIndex(0, device); 7538c78752f2bf786ca3e6f45b9dc6955d3b4bba59cEric Laurent } 7549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 7565b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent // If stream is muted, adjust last audible index only 7575b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent int index; 758244820185269991186d07068b92985624cede4a5Eric Laurent final int oldIndex = mStreamStates[streamType].getIndex(device, 759244820185269991186d07068b92985624cede4a5Eric Laurent (mStreamStates[streamType].muteCount() != 0) /* lastAudible */); 760244820185269991186d07068b92985624cede4a5Eric Laurent 7615b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent if (streamState.muteCount() != 0) { 7625b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent if (adjustVolume) { 763244820185269991186d07068b92985624cede4a5Eric Laurent // Post a persist volume msg 764244820185269991186d07068b92985624cede4a5Eric Laurent // no need to persist volume on all streams sharing the same alias 765244820185269991186d07068b92985624cede4a5Eric Laurent streamState.adjustLastAudibleIndex(direction * step, device); 766244820185269991186d07068b92985624cede4a5Eric Laurent sendMsg(mAudioHandler, 767244820185269991186d07068b92985624cede4a5Eric Laurent MSG_PERSIST_VOLUME, 768244820185269991186d07068b92985624cede4a5Eric Laurent SENDMSG_QUEUE, 769244820185269991186d07068b92985624cede4a5Eric Laurent PERSIST_LAST_AUDIBLE, 770244820185269991186d07068b92985624cede4a5Eric Laurent device, 771244820185269991186d07068b92985624cede4a5Eric Laurent streamState, 772244820185269991186d07068b92985624cede4a5Eric Laurent PERSIST_DELAY); 7735b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent } 774244820185269991186d07068b92985624cede4a5Eric Laurent index = mStreamStates[streamType].getIndex(device, true /* lastAudible */); 7755b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent } else { 776244820185269991186d07068b92985624cede4a5Eric Laurent if (adjustVolume && streamState.adjustIndex(direction * step, device)) { 7775b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent // Post message to set system volume (it in turn will post a message 7785b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent // to persist). Do not change volume if stream is muted. 779afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent sendMsg(mAudioHandler, 7809bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent MSG_SET_DEVICE_VOLUME, 78198ad9b9d6fd34aad487933170f50b5519313df61Eric Laurent SENDMSG_QUEUE, 7829bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent device, 783afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent 0, 784afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent streamState, 785afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent 0); 7869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 787244820185269991186d07068b92985624cede4a5Eric Laurent index = mStreamStates[streamType].getIndex(device, false /* lastAudible */); 7889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 78925101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent 79025101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent sendVolumeUpdate(streamType, oldIndex, index, flags); 7919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 793cbdb49dc5e1b993a0bc5c68dbfb9486bfa0cd762Mike Lockwood /** @see AudioManager#adjustMasterVolume(int) */ 7946c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang public void adjustMasterVolume(int steps, int flags) { 7956c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang ensureValidSteps(steps); 7969760647dd0ee67e7c20f3e9d661d2006b1df0b54Mike Lockwood int volume = Math.round(AudioSystem.getMasterVolume() * MAX_MASTER_VOLUME); 7979760647dd0ee67e7c20f3e9d661d2006b1df0b54Mike Lockwood int delta = 0; 7986c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang int numSteps = Math.abs(steps); 7996c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang int direction = steps > 0 ? AudioManager.ADJUST_RAISE : AudioManager.ADJUST_LOWER; 8006c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang for (int i = 0; i < numSteps; ++i) { 8016c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang delta = findVolumeDelta(direction, volume); 8026c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang volume += delta; 803cbdb49dc5e1b993a0bc5c68dbfb9486bfa0cd762Mike Lockwood } 80424b082f87e96c00d5c17d60c735423900be40e70RoboErik 8056c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang //Log.d(TAG, "adjustMasterVolume volume: " + volume + " steps: " + steps); 8066c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang setMasterVolume(volume, flags); 807cbdb49dc5e1b993a0bc5c68dbfb9486bfa0cd762Mike Lockwood } 808cbdb49dc5e1b993a0bc5c68dbfb9486bfa0cd762Mike Lockwood 8099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** @see AudioManager#setStreamVolume(int, int, int) */ 8109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void setStreamVolume(int streamType, int index, int flags) { 8119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ensureValidStreamType(streamType); 8126d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent VolumeStreamState streamState = mStreamStates[mStreamVolumeAlias[streamType]]; 8139ce379aef155e0c21b5d82d8dc713c62792e4f30Eric Laurent 8149bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent final int device = getDeviceForStream(streamType); 8159bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent // get last audible index if stream is muted, current index otherwise 8169bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent final int oldIndex = streamState.getIndex(device, 8179bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent (streamState.muteCount() != 0) /* lastAudible */); 8189ce379aef155e0c21b5d82d8dc713c62792e4f30Eric Laurent 819244820185269991186d07068b92985624cede4a5Eric Laurent index = rescaleIndex(index * 10, streamType, mStreamVolumeAlias[streamType]); 820244820185269991186d07068b92985624cede4a5Eric Laurent 821f740664cd808bebfc35ded46da6002bdc97a1a16Eric Laurent // setting volume on master stream type also controls silent mode 822f740664cd808bebfc35ded46da6002bdc97a1a16Eric Laurent if (((flags & AudioManager.FLAG_ALLOW_RINGER_MODES) != 0) || 823f740664cd808bebfc35ded46da6002bdc97a1a16Eric Laurent (mStreamVolumeAlias[streamType] == getMasterStreamType())) { 824ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten int newRingerMode; 825b024c30a80684ac08daef3137b7ba0d347fe3ce5Eric Laurent if (index == 0) { 826bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent newRingerMode = mHasVibrator ? AudioManager.RINGER_MODE_VIBRATE 827bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent : AudioManager.RINGER_MODE_SILENT; 8286d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent setStreamVolumeInt(mStreamVolumeAlias[streamType], 8299bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent index, 8309bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent device, 8319bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent false, 8329bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent true); 833b024c30a80684ac08daef3137b7ba0d347fe3ce5Eric Laurent } else { 834b024c30a80684ac08daef3137b7ba0d347fe3ce5Eric Laurent newRingerMode = AudioManager.RINGER_MODE_NORMAL; 835b024c30a80684ac08daef3137b7ba0d347fe3ce5Eric Laurent } 836ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten setRingerMode(newRingerMode); 837b024c30a80684ac08daef3137b7ba0d347fe3ce5Eric Laurent } 838b024c30a80684ac08daef3137b7ba0d347fe3ce5Eric Laurent 8396d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent setStreamVolumeInt(mStreamVolumeAlias[streamType], index, device, false, true); 8409bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent // get last audible index if stream is muted, current index otherwise 841244820185269991186d07068b92985624cede4a5Eric Laurent index = mStreamStates[streamType].getIndex(device, 842244820185269991186d07068b92985624cede4a5Eric Laurent (mStreamStates[streamType].muteCount() != 0) /* lastAudible */); 8435b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent 84425101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent sendVolumeUpdate(streamType, oldIndex, index, flags); 8459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 84745c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent /** @see AudioManager#forceVolumeControlStream(int) */ 84845c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent public void forceVolumeControlStream(int streamType, IBinder cb) { 84945c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent synchronized(mForceControlStreamLock) { 85045c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent mVolumeControlStream = streamType; 85145c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent if (mVolumeControlStream == -1) { 85245c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent if (mForceControlStreamClient != null) { 85345c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent mForceControlStreamClient.release(); 85445c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent mForceControlStreamClient = null; 85545c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent } 85645c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent } else { 85745c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent mForceControlStreamClient = new ForceControlStreamClient(cb); 85845c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent } 85945c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent } 86045c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent } 86145c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent 86245c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent private class ForceControlStreamClient implements IBinder.DeathRecipient { 86345c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent private IBinder mCb; // To be notified of client's death 86445c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent 86545c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent ForceControlStreamClient(IBinder cb) { 86645c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent if (cb != null) { 86745c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent try { 86845c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent cb.linkToDeath(this, 0); 86945c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent } catch (RemoteException e) { 87045c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent // Client has died! 87145c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent Log.w(TAG, "ForceControlStreamClient() could not link to "+cb+" binder death"); 87245c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent cb = null; 87345c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent } 87445c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent } 87545c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent mCb = cb; 87645c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent } 87745c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent 87845c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent public void binderDied() { 87945c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent synchronized(mForceControlStreamLock) { 88045c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent Log.w(TAG, "SCO client died"); 88145c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent if (mForceControlStreamClient != this) { 88245c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent Log.w(TAG, "unregistered control stream client died"); 88345c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent } else { 88445c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent mForceControlStreamClient = null; 88545c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent mVolumeControlStream = -1; 88645c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent } 88745c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent } 88845c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent } 88945c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent 89045c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent public void release() { 89145c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent if (mCb != null) { 89245c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent mCb.unlinkToDeath(this, 0); 89345c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent mCb = null; 89445c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent } 89545c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent } 89645c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent } 89745c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent 8986c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang private int findVolumeDelta(int direction, int volume) { 8996c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang int delta = 0; 9006c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang if (direction == AudioManager.ADJUST_RAISE) { 9016c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang if (volume == MAX_MASTER_VOLUME) { 9026c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang return 0; 9036c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang } 9046c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang // This is the default value if we make it to the end 9056c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang delta = mMasterVolumeRamp[1]; 9066c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang // If we're raising the volume move down the ramp array until we 9076c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang // find the volume we're above and use that groups delta. 9086c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang for (int i = mMasterVolumeRamp.length - 1; i > 1; i -= 2) { 9096c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang if (volume >= mMasterVolumeRamp[i - 1]) { 9106c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang delta = mMasterVolumeRamp[i]; 9116c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang break; 9126c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang } 9136c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang } 9146c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang } else if (direction == AudioManager.ADJUST_LOWER){ 9156c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang if (volume == 0) { 9166c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang return 0; 9176c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang } 9186c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang int length = mMasterVolumeRamp.length; 9196c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang // This is the default value if we make it to the end 9206c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang delta = -mMasterVolumeRamp[length - 1]; 9216c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang // If we're lowering the volume move up the ramp array until we 9226c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang // find the volume we're below and use the group below it's delta 9236c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang for (int i = 2; i < length; i += 2) { 9246c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang if (volume <= mMasterVolumeRamp[i]) { 9256c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang delta = -mMasterVolumeRamp[i - 1]; 9266c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang break; 9276c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang } 9286c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang } 9296c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang } 9306c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang return delta; 9316c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang } 9326c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang 93325101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent // UI update and Broadcast Intent 93425101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent private void sendVolumeUpdate(int streamType, int oldIndex, int index, int flags) { 93525101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent if (!mVoiceCapable && (streamType == AudioSystem.STREAM_RING)) { 93625101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent streamType = AudioSystem.STREAM_NOTIFICATION; 93725101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent } 93825101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent 93925101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent mVolumePanel.postVolumeChanged(streamType, flags); 94025101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent 9419ce379aef155e0c21b5d82d8dc713c62792e4f30Eric Laurent oldIndex = (oldIndex + 5) / 10; 9429ce379aef155e0c21b5d82d8dc713c62792e4f30Eric Laurent index = (index + 5) / 10; 9439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Intent intent = new Intent(AudioManager.VOLUME_CHANGED_ACTION); 9449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project intent.putExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, streamType); 9459ce379aef155e0c21b5d82d8dc713c62792e4f30Eric Laurent intent.putExtra(AudioManager.EXTRA_VOLUME_STREAM_VALUE, index); 9469ce379aef155e0c21b5d82d8dc713c62792e4f30Eric Laurent intent.putExtra(AudioManager.EXTRA_PREV_VOLUME_STREAM_VALUE, oldIndex); 9479ce379aef155e0c21b5d82d8dc713c62792e4f30Eric Laurent mContext.sendBroadcast(intent); 9489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 9500dc37cce9d564ae43883c8dc8672b9266b881e63Mike Lockwood // UI update and Broadcast Intent 9510dc37cce9d564ae43883c8dc8672b9266b881e63Mike Lockwood private void sendMasterVolumeUpdate(int flags, int oldVolume, int newVolume) { 9520dc37cce9d564ae43883c8dc8672b9266b881e63Mike Lockwood mVolumePanel.postMasterVolumeChanged(flags); 9530dc37cce9d564ae43883c8dc8672b9266b881e63Mike Lockwood 9540dc37cce9d564ae43883c8dc8672b9266b881e63Mike Lockwood Intent intent = new Intent(AudioManager.MASTER_VOLUME_CHANGED_ACTION); 9550dc37cce9d564ae43883c8dc8672b9266b881e63Mike Lockwood intent.putExtra(AudioManager.EXTRA_PREV_MASTER_VOLUME_VALUE, oldVolume); 9560dc37cce9d564ae43883c8dc8672b9266b881e63Mike Lockwood intent.putExtra(AudioManager.EXTRA_MASTER_VOLUME_VALUE, newVolume); 9570dc37cce9d564ae43883c8dc8672b9266b881e63Mike Lockwood mContext.sendBroadcast(intent); 9580dc37cce9d564ae43883c8dc8672b9266b881e63Mike Lockwood } 9590dc37cce9d564ae43883c8dc8672b9266b881e63Mike Lockwood 9600dc37cce9d564ae43883c8dc8672b9266b881e63Mike Lockwood // UI update and Broadcast Intent 9610dc37cce9d564ae43883c8dc8672b9266b881e63Mike Lockwood private void sendMasterMuteUpdate(boolean muted, int flags) { 9620dc37cce9d564ae43883c8dc8672b9266b881e63Mike Lockwood mVolumePanel.postMasterMuteChanged(flags); 96357978ed86286a33d5b1a0fd000ca3406ba9d87b3Justin Koh broadcastMasterMuteStatus(muted); 96457978ed86286a33d5b1a0fd000ca3406ba9d87b3Justin Koh } 9650dc37cce9d564ae43883c8dc8672b9266b881e63Mike Lockwood 96657978ed86286a33d5b1a0fd000ca3406ba9d87b3Justin Koh private void broadcastMasterMuteStatus(boolean muted) { 9670dc37cce9d564ae43883c8dc8672b9266b881e63Mike Lockwood Intent intent = new Intent(AudioManager.MASTER_MUTE_CHANGED_ACTION); 9680dc37cce9d564ae43883c8dc8672b9266b881e63Mike Lockwood intent.putExtra(AudioManager.EXTRA_MASTER_VOLUME_MUTED, muted); 96957978ed86286a33d5b1a0fd000ca3406ba9d87b3Justin Koh intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT 97057978ed86286a33d5b1a0fd000ca3406ba9d87b3Justin Koh | Intent.FLAG_RECEIVER_REPLACE_PENDING); 9710dc37cce9d564ae43883c8dc8672b9266b881e63Mike Lockwood long origCallerIdentityToken = Binder.clearCallingIdentity(); 9720dc37cce9d564ae43883c8dc8672b9266b881e63Mike Lockwood mContext.sendStickyBroadcast(intent); 9730dc37cce9d564ae43883c8dc8672b9266b881e63Mike Lockwood Binder.restoreCallingIdentity(origCallerIdentityToken); 9740dc37cce9d564ae43883c8dc8672b9266b881e63Mike Lockwood } 9750dc37cce9d564ae43883c8dc8672b9266b881e63Mike Lockwood 9769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 9779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Sets the stream state's index, and posts a message to set system volume. 9789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * This will not call out to the UI. Assumes a valid stream type. 9799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 9809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param streamType Type of the stream 9819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param index Desired volume index of the stream 9829bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent * @param device the device whose volume must be changed 9839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param force If true, set the volume even if the desired volume is same 9849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * as the current volume. 9859bcf401d13d47416043a704430388abd59aef7cdEric Laurent * @param lastAudible If true, stores new index as last audible one 9869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 9879bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent private void setStreamVolumeInt(int streamType, 9889bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent int index, 9899bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent int device, 9909bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent boolean force, 9919bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent boolean lastAudible) { 9929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project VolumeStreamState streamState = mStreamStates[streamType]; 9935b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent 9945b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent // If stream is muted, set last audible index only 9955b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent if (streamState.muteCount() != 0) { 996758dd527f64f1e827adfe09f0141ab213733ca22Eric Laurent // Do not allow last audible index to be 0 997758dd527f64f1e827adfe09f0141ab213733ca22Eric Laurent if (index != 0) { 9989bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent streamState.setLastAudibleIndex(index, device); 999758dd527f64f1e827adfe09f0141ab213733ca22Eric Laurent // Post a persist volume msg 1000afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent sendMsg(mAudioHandler, 1001afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent MSG_PERSIST_VOLUME, 100298ad9b9d6fd34aad487933170f50b5519313df61Eric Laurent SENDMSG_QUEUE, 1003afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent PERSIST_LAST_AUDIBLE, 10049bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent device, 1005afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent streamState, 1006afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent PERSIST_DELAY); 1007758dd527f64f1e827adfe09f0141ab213733ca22Eric Laurent } 10085b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent } else { 10099bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent if (streamState.setIndex(index, device, lastAudible) || force) { 10105b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent // Post message to set system volume (it in turn will post a message 10115b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent // to persist). 1012afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent sendMsg(mAudioHandler, 10139bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent MSG_SET_DEVICE_VOLUME, 101498ad9b9d6fd34aad487933170f50b5519313df61Eric Laurent SENDMSG_QUEUE, 10159bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent device, 1016afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent 0, 1017afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent streamState, 1018afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent 0); 10199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 10239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** @see AudioManager#setStreamSolo(int, boolean) */ 10249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void setStreamSolo(int streamType, boolean state, IBinder cb) { 10259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (int stream = 0; stream < mStreamStates.length; stream++) { 10269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (!isStreamAffectedByMute(stream) || stream == streamType) continue; 10279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Bring back last audible volume 10289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mStreamStates[stream].mute(cb, state); 10299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 10329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** @see AudioManager#setStreamMute(int, boolean) */ 10339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void setStreamMute(int streamType, boolean state, IBinder cb) { 10349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (isStreamAffectedByMute(streamType)) { 10359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mStreamStates[streamType].mute(cb, state); 10369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 103925101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent /** get stream mute state. */ 104025101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent public boolean isStreamMute(int streamType) { 104125101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent return (mStreamStates[streamType].muteCount() != 0); 104225101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent } 104325101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent 1044ce952c8e13c535bedde77bcdb94dfcc7508475aaMike Lockwood /** @see AudioManager#setMasterMute(boolean, IBinder) */ 10450273af55cf68d54d26d154b44d105d40fed79701Justin Koh public void setMasterMute(boolean state, int flags, IBinder cb) { 10461ce5b26d707e0086e09af3cd0428f1b441145261Jason Simmons if (state != AudioSystem.getMasterMute()) { 10471ce5b26d707e0086e09af3cd0428f1b441145261Jason Simmons AudioSystem.setMasterMute(state); 104857978ed86286a33d5b1a0fd000ca3406ba9d87b3Justin Koh // Post a persist master volume msg 104975cf9e19a575c28c200c02c0ab6f83bb79f5c50dJustin Koh sendMsg(mAudioHandler, MSG_PERSIST_MASTER_VOLUME_MUTE, SENDMSG_REPLACE, state ? 1 105057978ed86286a33d5b1a0fd000ca3406ba9d87b3Justin Koh : 0, 0, null, PERSIST_DELAY); 10510273af55cf68d54d26d154b44d105d40fed79701Justin Koh sendMasterMuteUpdate(state, flags); 10521ce5b26d707e0086e09af3cd0428f1b441145261Jason Simmons } 1053ce952c8e13c535bedde77bcdb94dfcc7508475aaMike Lockwood } 1054ce952c8e13c535bedde77bcdb94dfcc7508475aaMike Lockwood 1055ce952c8e13c535bedde77bcdb94dfcc7508475aaMike Lockwood /** get master mute state. */ 1056ce952c8e13c535bedde77bcdb94dfcc7508475aaMike Lockwood public boolean isMasterMute() { 10573194ea94348bce8e7ee9f803698d877f46f8279aMike Lockwood return AudioSystem.getMasterMute(); 1058ce952c8e13c535bedde77bcdb94dfcc7508475aaMike Lockwood } 1059ce952c8e13c535bedde77bcdb94dfcc7508475aaMike Lockwood 10609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** @see AudioManager#getStreamVolume(int) */ 10619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public int getStreamVolume(int streamType) { 10629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ensureValidStreamType(streamType); 10639bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent int device = getDeviceForStream(streamType); 10649bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent return (mStreamStates[streamType].getIndex(device, false /* lastAudible */) + 5) / 10; 10659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 10674767690f09ea3447b8c5c32fb28d27650aa18e00Mike Lockwood public int getMasterVolume() { 1068ce952c8e13c535bedde77bcdb94dfcc7508475aaMike Lockwood if (isMasterMute()) return 0; 1069ce952c8e13c535bedde77bcdb94dfcc7508475aaMike Lockwood return getLastAudibleMasterVolume(); 10708dc1dabd254249b7ddb8743e88fdb96580ffc585Mike Lockwood } 10718dc1dabd254249b7ddb8743e88fdb96580ffc585Mike Lockwood 10724767690f09ea3447b8c5c32fb28d27650aa18e00Mike Lockwood public void setMasterVolume(int volume, int flags) { 10739760647dd0ee67e7c20f3e9d661d2006b1df0b54Mike Lockwood if (volume < 0) { 10749760647dd0ee67e7c20f3e9d661d2006b1df0b54Mike Lockwood volume = 0; 10759760647dd0ee67e7c20f3e9d661d2006b1df0b54Mike Lockwood } else if (volume > MAX_MASTER_VOLUME) { 10769760647dd0ee67e7c20f3e9d661d2006b1df0b54Mike Lockwood volume = MAX_MASTER_VOLUME; 10779760647dd0ee67e7c20f3e9d661d2006b1df0b54Mike Lockwood } 10785c55a051ad7d86a464fb91426f1ea3c0250e38b3Mike Lockwood doSetMasterVolume((float)volume / MAX_MASTER_VOLUME, flags); 10795c55a051ad7d86a464fb91426f1ea3c0250e38b3Mike Lockwood } 10805c55a051ad7d86a464fb91426f1ea3c0250e38b3Mike Lockwood 10815c55a051ad7d86a464fb91426f1ea3c0250e38b3Mike Lockwood private void doSetMasterVolume(float volume, int flags) { 10825c55a051ad7d86a464fb91426f1ea3c0250e38b3Mike Lockwood // don't allow changing master volume when muted 10835c55a051ad7d86a464fb91426f1ea3c0250e38b3Mike Lockwood if (!AudioSystem.getMasterMute()) { 10845c55a051ad7d86a464fb91426f1ea3c0250e38b3Mike Lockwood int oldVolume = getMasterVolume(); 10855c55a051ad7d86a464fb91426f1ea3c0250e38b3Mike Lockwood AudioSystem.setMasterVolume(volume); 10865c55a051ad7d86a464fb91426f1ea3c0250e38b3Mike Lockwood 10875c55a051ad7d86a464fb91426f1ea3c0250e38b3Mike Lockwood int newVolume = getMasterVolume(); 10885c55a051ad7d86a464fb91426f1ea3c0250e38b3Mike Lockwood if (newVolume != oldVolume) { 10895c55a051ad7d86a464fb91426f1ea3c0250e38b3Mike Lockwood // Post a persist master volume msg 10905c55a051ad7d86a464fb91426f1ea3c0250e38b3Mike Lockwood sendMsg(mAudioHandler, MSG_PERSIST_MASTER_VOLUME, SENDMSG_REPLACE, 10915c55a051ad7d86a464fb91426f1ea3c0250e38b3Mike Lockwood Math.round(volume * (float)1000.0), 0, null, PERSIST_DELAY); 10925c55a051ad7d86a464fb91426f1ea3c0250e38b3Mike Lockwood } 10933caba517253d1703fc29b50740c4567b932279fbJustin Koh // Send the volume update regardless whether there was a change. 10943caba517253d1703fc29b50740c4567b932279fbJustin Koh sendMasterVolumeUpdate(flags, oldVolume, newVolume); 10955c55a051ad7d86a464fb91426f1ea3c0250e38b3Mike Lockwood } 10968dc1dabd254249b7ddb8743e88fdb96580ffc585Mike Lockwood } 10978dc1dabd254249b7ddb8743e88fdb96580ffc585Mike Lockwood 10989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** @see AudioManager#getStreamMaxVolume(int) */ 10999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public int getStreamMaxVolume(int streamType) { 11009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ensureValidStreamType(streamType); 1101a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent return (mStreamStates[streamType].getMaxIndex() + 5) / 10; 11029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 11039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 11044767690f09ea3447b8c5c32fb28d27650aa18e00Mike Lockwood public int getMasterMaxVolume() { 11054767690f09ea3447b8c5c32fb28d27650aa18e00Mike Lockwood return MAX_MASTER_VOLUME; 11064767690f09ea3447b8c5c32fb28d27650aa18e00Mike Lockwood } 110725101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent 110825101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent /** Get last audible volume before stream was muted. */ 110925101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent public int getLastAudibleStreamVolume(int streamType) { 111025101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent ensureValidStreamType(streamType); 11119bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent int device = getDeviceForStream(streamType); 11129bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent return (mStreamStates[streamType].getIndex(device, true /* lastAudible */) + 5) / 10; 111325101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent } 111425101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent 1115ce952c8e13c535bedde77bcdb94dfcc7508475aaMike Lockwood /** Get last audible master volume before it was muted. */ 1116ce952c8e13c535bedde77bcdb94dfcc7508475aaMike Lockwood public int getLastAudibleMasterVolume() { 1117ce952c8e13c535bedde77bcdb94dfcc7508475aaMike Lockwood return Math.round(AudioSystem.getMasterVolume() * MAX_MASTER_VOLUME); 1118ce952c8e13c535bedde77bcdb94dfcc7508475aaMike Lockwood } 1119ce952c8e13c535bedde77bcdb94dfcc7508475aaMike Lockwood 11206d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent /** @see AudioManager#getMasterStreamType(int) */ 11216d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent public int getMasterStreamType() { 11226d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent if (mVoiceCapable) { 11236d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent return AudioSystem.STREAM_RING; 11246d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent } else { 11256d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent return AudioSystem.STREAM_MUSIC; 11266d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent } 11276d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent } 11286d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent 11299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** @see AudioManager#getRingerMode() */ 11309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public int getRingerMode() { 1131ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten synchronized(mSettingsLock) { 1132ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten return mRingerMode; 1133ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten } 1134ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten } 1135ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten 1136ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten private void ensureValidRingerMode(int ringerMode) { 1137ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten if (!AudioManager.isValidRingerMode(ringerMode)) { 1138ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten throw new IllegalArgumentException("Bad ringer mode " + ringerMode); 1139ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten } 11409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 11419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 11429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** @see AudioManager#setRingerMode(int) */ 11439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void setRingerMode(int ringerMode) { 1144244820185269991186d07068b92985624cede4a5Eric Laurent if ((ringerMode == AudioManager.RINGER_MODE_VIBRATE) && !mHasVibrator) { 1145244820185269991186d07068b92985624cede4a5Eric Laurent ringerMode = AudioManager.RINGER_MODE_SILENT; 1146244820185269991186d07068b92985624cede4a5Eric Laurent } 1147ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten if (ringerMode != getRingerMode()) { 1148ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten setRingerModeInt(ringerMode, true); 1149ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten // Send sticky broadcast 1150ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten broadcastRingerMode(ringerMode); 1151b109615ebebd6f3b9ae789412279f576c3ace46bJason Parekh } 1152b109615ebebd6f3b9ae789412279f576c3ace46bJason Parekh } 11539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 11544050c93601b3c3609b21cc1e18a29b64747e7fa9Eric Laurent private void setRingerModeInt(int ringerMode, boolean persist) { 1155ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten synchronized(mSettingsLock) { 1156ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten mRingerMode = ringerMode; 1157ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten } 1158b109615ebebd6f3b9ae789412279f576c3ace46bJason Parekh 11595b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent // Mute stream if not previously muted by ringer mode and ringer mode 11605b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent // is not RINGER_MODE_NORMAL and stream is affected by ringer mode. 11615b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent // Unmute stream if previously muted by ringer mode and ringer mode 11625b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent // is RINGER_MODE_NORMAL or stream is not affected by ringer mode. 1163b109615ebebd6f3b9ae789412279f576c3ace46bJason Parekh int numStreamTypes = AudioSystem.getNumStreamTypes(); 11645b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) { 11655b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent if (isStreamMutedByRingerMode(streamType)) { 11665b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent if (!isStreamAffectedByRingerMode(streamType) || 1167ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten ringerMode == AudioManager.RINGER_MODE_NORMAL) { 1168b024c30a80684ac08daef3137b7ba0d347fe3ce5Eric Laurent // ring and notifications volume should never be 0 when not silenced 1169b024c30a80684ac08daef3137b7ba0d347fe3ce5Eric Laurent // on voice capable devices 1170b024c30a80684ac08daef3137b7ba0d347fe3ce5Eric Laurent if (mVoiceCapable && 11716d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent mStreamVolumeAlias[streamType] == AudioSystem.STREAM_RING) { 11723172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent synchronized (mStreamStates[streamType]) { 11733172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent Set set = mStreamStates[streamType].mLastAudibleIndex.entrySet(); 11743172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent Iterator i = set.iterator(); 11753172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent while (i.hasNext()) { 11763172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent Map.Entry entry = (Map.Entry)i.next(); 11773172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent if ((Integer)entry.getValue() == 0) { 11783172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent entry.setValue(10); 11793172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent } 11809bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent } 11819bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent } 1182b024c30a80684ac08daef3137b7ba0d347fe3ce5Eric Laurent } 11835b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent mStreamStates[streamType].mute(null, false); 11845b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent mRingerModeMutedStreams &= ~(1 << streamType); 11859bcf401d13d47416043a704430388abd59aef7cdEric Laurent } 11865b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent } else { 11875b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent if (isStreamAffectedByRingerMode(streamType) && 1188ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten ringerMode != AudioManager.RINGER_MODE_NORMAL) { 11895b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent mStreamStates[streamType].mute(null, true); 11905b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent mRingerModeMutedStreams |= (1 << streamType); 11915b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent } 1192b109615ebebd6f3b9ae789412279f576c3ace46bJason Parekh } 11939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1194a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent 1195b109615ebebd6f3b9ae789412279f576c3ace46bJason Parekh // Post a persist ringer mode msg 11964050c93601b3c3609b21cc1e18a29b64747e7fa9Eric Laurent if (persist) { 1197afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent sendMsg(mAudioHandler, MSG_PERSIST_RINGER_MODE, 11984050c93601b3c3609b21cc1e18a29b64747e7fa9Eric Laurent SENDMSG_REPLACE, 0, 0, null, PERSIST_DELAY); 11994050c93601b3c3609b21cc1e18a29b64747e7fa9Eric Laurent } 12009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 12019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 12029063154a793b0ab38b3c5992cbaed046427b4a82Mike Lockwood private void restoreMasterVolume() { 12039063154a793b0ab38b3c5992cbaed046427b4a82Mike Lockwood if (mUseMasterVolume) { 12049063154a793b0ab38b3c5992cbaed046427b4a82Mike Lockwood float volume = Settings.System.getFloat(mContentResolver, 12059063154a793b0ab38b3c5992cbaed046427b4a82Mike Lockwood Settings.System.VOLUME_MASTER, -1.0f); 12069063154a793b0ab38b3c5992cbaed046427b4a82Mike Lockwood if (volume >= 0.0f) { 12079063154a793b0ab38b3c5992cbaed046427b4a82Mike Lockwood AudioSystem.setMasterVolume(volume); 12089063154a793b0ab38b3c5992cbaed046427b4a82Mike Lockwood } 12099063154a793b0ab38b3c5992cbaed046427b4a82Mike Lockwood } 12109063154a793b0ab38b3c5992cbaed046427b4a82Mike Lockwood } 12119063154a793b0ab38b3c5992cbaed046427b4a82Mike Lockwood 12129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** @see AudioManager#shouldVibrate(int) */ 12139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public boolean shouldVibrate(int vibrateType) { 1214bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent if (!mHasVibrator) return false; 12159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 12169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project switch (getVibrateSetting(vibrateType)) { 12179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 12189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project case AudioManager.VIBRATE_SETTING_ON: 1219ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten return getRingerMode() != AudioManager.RINGER_MODE_SILENT; 12209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 12219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project case AudioManager.VIBRATE_SETTING_ONLY_SILENT: 1222ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten return getRingerMode() == AudioManager.RINGER_MODE_VIBRATE; 12239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 12249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project case AudioManager.VIBRATE_SETTING_OFF: 1225bcac496076ef6f439147e7a2be71e8a2b76ddedeDaniel Sandler // return false, even for incoming calls 1226bcac496076ef6f439147e7a2be71e8a2b76ddedeDaniel Sandler return false; 12279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 12289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project default: 12299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return false; 12309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 12319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 12329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 12339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** @see AudioManager#getVibrateSetting(int) */ 12349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public int getVibrateSetting(int vibrateType) { 1235bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent if (!mHasVibrator) return AudioManager.VIBRATE_SETTING_OFF; 12369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return (mVibrateSetting >> (vibrateType * 2)) & 3; 12379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 12389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 12399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** @see AudioManager#setVibrateSetting(int, int) */ 12409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void setVibrateSetting(int vibrateType, int vibrateSetting) { 12419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1242bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent if (!mHasVibrator) return; 1243bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent 12449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mVibrateSetting = getValueForVibrateSetting(mVibrateSetting, vibrateType, vibrateSetting); 12459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 12469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Broadcast change 12479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project broadcastVibrateSetting(vibrateType); 12489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 12499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 12509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 12519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 12529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @see #setVibrateSetting(int, int) 12539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 12549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public static int getValueForVibrateSetting(int existingValue, int vibrateType, 12559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int vibrateSetting) { 12569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 12579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // First clear the existing setting. Each vibrate type has two bits in 12589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // the value. Note '3' is '11' in binary. 12599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project existingValue &= ~(3 << (vibrateType * 2)); 12609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 12619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Set into the old value 12629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project existingValue |= (vibrateSetting & 3) << (vibrateType * 2); 12639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 12649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return existingValue; 12659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 12669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 12679272b4b4a44fe1f33e3030810618194f817caaecEric Laurent private class SetModeDeathHandler implements IBinder.DeathRecipient { 12689272b4b4a44fe1f33e3030810618194f817caaecEric Laurent private IBinder mCb; // To be notified of client's death 1269f1ddd51f9cd2f92b922bc636c307210a8d587c25Marco Nelissen private int mPid; 12709272b4b4a44fe1f33e3030810618194f817caaecEric Laurent private int mMode = AudioSystem.MODE_NORMAL; // Current mode set by this client 12719272b4b4a44fe1f33e3030810618194f817caaecEric Laurent 12729f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent SetModeDeathHandler(IBinder cb, int pid) { 12739272b4b4a44fe1f33e3030810618194f817caaecEric Laurent mCb = cb; 12749f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent mPid = pid; 12759272b4b4a44fe1f33e3030810618194f817caaecEric Laurent } 12769272b4b4a44fe1f33e3030810618194f817caaecEric Laurent 12779272b4b4a44fe1f33e3030810618194f817caaecEric Laurent public void binderDied() { 1278d7454be47f4111c0478a502353e11dea401378bdEric Laurent int newModeOwnerPid = 0; 12799272b4b4a44fe1f33e3030810618194f817caaecEric Laurent synchronized(mSetModeDeathHandlers) { 12809272b4b4a44fe1f33e3030810618194f817caaecEric Laurent Log.w(TAG, "setMode() client died"); 12819272b4b4a44fe1f33e3030810618194f817caaecEric Laurent int index = mSetModeDeathHandlers.indexOf(this); 12829272b4b4a44fe1f33e3030810618194f817caaecEric Laurent if (index < 0) { 12839272b4b4a44fe1f33e3030810618194f817caaecEric Laurent Log.w(TAG, "unregistered setMode() client died"); 12849272b4b4a44fe1f33e3030810618194f817caaecEric Laurent } else { 1285d7454be47f4111c0478a502353e11dea401378bdEric Laurent newModeOwnerPid = setModeInt(AudioSystem.MODE_NORMAL, mCb, mPid); 12869272b4b4a44fe1f33e3030810618194f817caaecEric Laurent } 12879272b4b4a44fe1f33e3030810618194f817caaecEric Laurent } 12889f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent // when entering RINGTONE, IN_CALL or IN_COMMUNICATION mode, clear all 12899f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent // SCO connections not started by the application changing the mode 1290d7454be47f4111c0478a502353e11dea401378bdEric Laurent if (newModeOwnerPid != 0) { 1291d7454be47f4111c0478a502353e11dea401378bdEric Laurent disconnectBluetoothSco(newModeOwnerPid); 12929f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent } 12939272b4b4a44fe1f33e3030810618194f817caaecEric Laurent } 12949272b4b4a44fe1f33e3030810618194f817caaecEric Laurent 1295f1ddd51f9cd2f92b922bc636c307210a8d587c25Marco Nelissen public int getPid() { 1296f1ddd51f9cd2f92b922bc636c307210a8d587c25Marco Nelissen return mPid; 1297f1ddd51f9cd2f92b922bc636c307210a8d587c25Marco Nelissen } 1298f1ddd51f9cd2f92b922bc636c307210a8d587c25Marco Nelissen 12999272b4b4a44fe1f33e3030810618194f817caaecEric Laurent public void setMode(int mode) { 13009272b4b4a44fe1f33e3030810618194f817caaecEric Laurent mMode = mode; 13019272b4b4a44fe1f33e3030810618194f817caaecEric Laurent } 13029272b4b4a44fe1f33e3030810618194f817caaecEric Laurent 13039272b4b4a44fe1f33e3030810618194f817caaecEric Laurent public int getMode() { 13049272b4b4a44fe1f33e3030810618194f817caaecEric Laurent return mMode; 13059272b4b4a44fe1f33e3030810618194f817caaecEric Laurent } 13069272b4b4a44fe1f33e3030810618194f817caaecEric Laurent 13079272b4b4a44fe1f33e3030810618194f817caaecEric Laurent public IBinder getBinder() { 13089272b4b4a44fe1f33e3030810618194f817caaecEric Laurent return mCb; 13099272b4b4a44fe1f33e3030810618194f817caaecEric Laurent } 13109272b4b4a44fe1f33e3030810618194f817caaecEric Laurent } 13119272b4b4a44fe1f33e3030810618194f817caaecEric Laurent 13129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** @see AudioManager#setMode(int) */ 13139272b4b4a44fe1f33e3030810618194f817caaecEric Laurent public void setMode(int mode, IBinder cb) { 13149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (!checkAudioSettingsPermission("setMode()")) { 13159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return; 13169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1317a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent 13188f677d66d9c3ba34c97e69b2bb9e161f129af0eeJean-Michel Trivi if (mode < AudioSystem.MODE_CURRENT || mode >= AudioSystem.NUM_MODES) { 1319a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent return; 1320a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent } 1321a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent 1322d7454be47f4111c0478a502353e11dea401378bdEric Laurent int newModeOwnerPid = 0; 13239f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent synchronized(mSetModeDeathHandlers) { 1324a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent if (mode == AudioSystem.MODE_CURRENT) { 1325a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent mode = mMode; 1326a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent } 1327d7454be47f4111c0478a502353e11dea401378bdEric Laurent newModeOwnerPid = setModeInt(mode, cb, Binder.getCallingPid()); 13289f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent } 13299f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent // when entering RINGTONE, IN_CALL or IN_COMMUNICATION mode, clear all 13309f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent // SCO connections not started by the application changing the mode 1331d7454be47f4111c0478a502353e11dea401378bdEric Laurent if (newModeOwnerPid != 0) { 1332d7454be47f4111c0478a502353e11dea401378bdEric Laurent disconnectBluetoothSco(newModeOwnerPid); 13339f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent } 13349f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent } 13352ade576148fe33c5ff6098d30ccfbcf28df70e8eJean-Michel Trivi 13369f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent // must be called synchronized on mSetModeDeathHandlers 1337d7454be47f4111c0478a502353e11dea401378bdEric Laurent // setModeInt() returns a valid PID if the audio mode was successfully set to 13389f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent // any mode other than NORMAL. 1339d7454be47f4111c0478a502353e11dea401378bdEric Laurent int setModeInt(int mode, IBinder cb, int pid) { 1340d7454be47f4111c0478a502353e11dea401378bdEric Laurent int newModeOwnerPid = 0; 13419f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent if (cb == null) { 13429f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent Log.e(TAG, "setModeInt() called with null binder"); 1343d7454be47f4111c0478a502353e11dea401378bdEric Laurent return newModeOwnerPid; 13449f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent } 13452ade576148fe33c5ff6098d30ccfbcf28df70e8eJean-Michel Trivi 13469f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent SetModeDeathHandler hdlr = null; 13479f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent Iterator iter = mSetModeDeathHandlers.iterator(); 13489f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent while (iter.hasNext()) { 13499f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent SetModeDeathHandler h = (SetModeDeathHandler)iter.next(); 13509f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent if (h.getPid() == pid) { 13519f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent hdlr = h; 13529f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent // Remove from client list so that it is re-inserted at top of list 13539f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent iter.remove(); 13549f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent hdlr.getBinder().unlinkToDeath(hdlr, 0); 13559f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent break; 13569f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent } 13579f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent } 13589f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent int status = AudioSystem.AUDIO_STATUS_OK; 13599f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent do { 13609f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent if (mode == AudioSystem.MODE_NORMAL) { 13619f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent // get new mode from client at top the list if any 13629f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent if (!mSetModeDeathHandlers.isEmpty()) { 13639f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent hdlr = mSetModeDeathHandlers.get(0); 13649f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent cb = hdlr.getBinder(); 13659f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent mode = hdlr.getMode(); 13669f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent } 13679f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent } else { 13689f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent if (hdlr == null) { 13699f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent hdlr = new SetModeDeathHandler(cb, pid); 13709f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent } 13719f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent // Register for client death notification 13729f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent try { 13739f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent cb.linkToDeath(hdlr, 0); 13749f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent } catch (RemoteException e) { 13759f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent // Client has died! 13769f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent Log.w(TAG, "setMode() could not link to "+cb+" binder death"); 13779f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent } 13789272b4b4a44fe1f33e3030810618194f817caaecEric Laurent 13799f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent // Last client to call setMode() is always at top of client list 13809f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent // as required by SetModeDeathHandler.binderDied() 13819f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent mSetModeDeathHandlers.add(0, hdlr); 13829f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent hdlr.setMode(mode); 13839f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent } 13843def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent 13859f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent if (mode != mMode) { 13869f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent status = AudioSystem.setPhoneState(mode); 13879f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent if (status == AudioSystem.AUDIO_STATUS_OK) { 13889f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent mMode = mode; 13899f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent } else { 13909f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent if (hdlr != null) { 13919f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent mSetModeDeathHandlers.remove(hdlr); 13929f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent cb.unlinkToDeath(hdlr, 0); 13933def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent } 13949f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent // force reading new top of mSetModeDeathHandlers stack 13959f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent mode = AudioSystem.MODE_NORMAL; 1396b9c9d260f21b321527c4622a123af9767630d94dEric Laurent } 13979f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent } else { 13989f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent status = AudioSystem.AUDIO_STATUS_OK; 13999f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent } 14009f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent } while (status != AudioSystem.AUDIO_STATUS_OK && !mSetModeDeathHandlers.isEmpty()); 14019f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent 14029f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent if (status == AudioSystem.AUDIO_STATUS_OK) { 14039f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent if (mode != AudioSystem.MODE_NORMAL) { 1404d7454be47f4111c0478a502353e11dea401378bdEric Laurent if (mSetModeDeathHandlers.isEmpty()) { 1405d7454be47f4111c0478a502353e11dea401378bdEric Laurent Log.e(TAG, "setMode() different from MODE_NORMAL with empty mode client stack"); 1406d7454be47f4111c0478a502353e11dea401378bdEric Laurent } else { 1407d7454be47f4111c0478a502353e11dea401378bdEric Laurent newModeOwnerPid = mSetModeDeathHandlers.get(0).getPid(); 1408d7454be47f4111c0478a502353e11dea401378bdEric Laurent } 14099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 14109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int streamType = getActiveStreamType(AudioManager.USE_DEFAULT_STREAM_TYPE); 14113114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi if (streamType == STREAM_REMOTE_MUSIC) { 14123114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi // here handle remote media playback the same way as local playback 14133114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi streamType = AudioManager.STREAM_MUSIC; 14143114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi } 14159bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent int device = getDeviceForStream(streamType); 14166d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent int index = mStreamStates[mStreamVolumeAlias[streamType]].getIndex(device, false); 14176d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent setStreamVolumeInt(mStreamVolumeAlias[streamType], index, device, true, false); 14186d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent 14196d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent updateStreamVolumeAlias(true /*updateVolumes*/); 14209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1421d7454be47f4111c0478a502353e11dea401378bdEric Laurent return newModeOwnerPid; 14229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 14239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 14249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** @see AudioManager#getMode() */ 14259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public int getMode() { 14269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return mMode; 14279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 14289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 14299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** @see AudioManager#playSoundEffect(int) */ 14309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void playSoundEffect(int effectType) { 1431afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent sendMsg(mAudioHandler, MSG_PLAY_SOUND_EFFECT, SENDMSG_NOOP, 1432a2ef57dba9ac77d8eccacd646b2b8a8d99fe9d8bEric Laurent effectType, -1, null, 0); 14339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 14349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 14359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** @see AudioManager#playSoundEffect(int, float) */ 14369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void playSoundEffectVolume(int effectType, float volume) { 1437a2ef57dba9ac77d8eccacd646b2b8a8d99fe9d8bEric Laurent loadSoundEffects(); 1438afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent sendMsg(mAudioHandler, MSG_PLAY_SOUND_EFFECT, SENDMSG_NOOP, 14399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project effectType, (int) (volume * 1000), null, 0); 14409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 14419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 14429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 14439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Loads samples into the soundpool. 14445c17a820f9e46e0756c11795b3e6f89105f2f539Glenn Kasten * This method must be called at first when sound effects are enabled 14459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 14469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public boolean loadSoundEffects() { 1447a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent int status; 1448a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent 14499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project synchronized (mSoundEffectsLock) { 1450a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent if (!mBootCompleted) { 1451a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent Log.w(TAG, "loadSoundEffects() called before boot complete"); 1452a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent return false; 1453a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent } 1454a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent 1455a2ef57dba9ac77d8eccacd646b2b8a8d99fe9d8bEric Laurent if (mSoundPool != null) { 1456a2ef57dba9ac77d8eccacd646b2b8a8d99fe9d8bEric Laurent return true; 1457a2ef57dba9ac77d8eccacd646b2b8a8d99fe9d8bEric Laurent } 14589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mSoundPool = new SoundPool(NUM_SOUNDPOOL_CHANNELS, AudioSystem.STREAM_SYSTEM, 0); 1459a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent 1460a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent try { 1461a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent mSoundPoolCallBack = null; 1462a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent mSoundPoolListenerThread = new SoundPoolListenerThread(); 1463a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent mSoundPoolListenerThread.start(); 1464a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent // Wait for mSoundPoolCallBack to be set by the other thread 1465a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent mSoundEffectsLock.wait(); 1466a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent } catch (InterruptedException e) { 1467a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent Log.w(TAG, "Interrupted while waiting sound pool listener thread."); 1468a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent } 1469a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent 1470a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent if (mSoundPoolCallBack == null) { 1471a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent Log.w(TAG, "loadSoundEffects() could not create SoundPool listener or thread"); 1472a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent if (mSoundPoolLooper != null) { 1473a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent mSoundPoolLooper.quit(); 1474a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent mSoundPoolLooper = null; 1475a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent } 1476a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent mSoundPoolListenerThread = null; 1477a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent mSoundPool.release(); 1478a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent mSoundPool = null; 14799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return false; 14809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 14819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /* 14829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * poolId table: The value -1 in this table indicates that corresponding 14839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * file (same index in SOUND_EFFECT_FILES[] has not been loaded. 14849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Once loaded, the value in poolId is the sample ID and the same 14859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * sample can be reused for another effect using the same file. 14869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 14879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int[] poolId = new int[SOUND_EFFECT_FILES.length]; 14889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (int fileIdx = 0; fileIdx < SOUND_EFFECT_FILES.length; fileIdx++) { 14899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project poolId[fileIdx] = -1; 14909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 14919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /* 14929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Effects whose value in SOUND_EFFECT_FILES_MAP[effect][1] is -1 must be loaded. 14939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * If load succeeds, value in SOUND_EFFECT_FILES_MAP[effect][1] is > 0: 14949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * this indicates we have a valid sample loaded for this effect. 14959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 1496a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent 1497117b7bb5b5a4457711f59bde3dcc83d8f111c524Eric Laurent int lastSample = 0; 14989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (int effect = 0; effect < AudioManager.NUM_SOUND_EFFECTS; effect++) { 14999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Do not load sample if this effect uses the MediaPlayer 15009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (SOUND_EFFECT_FILES_MAP[effect][1] == 0) { 15019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project continue; 15029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 15039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (poolId[SOUND_EFFECT_FILES_MAP[effect][0]] == -1) { 1504a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent String filePath = Environment.getRootDirectory() 1505a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent + SOUND_EFFECTS_PATH 1506a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent + SOUND_EFFECT_FILES[SOUND_EFFECT_FILES_MAP[effect][0]]; 15079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int sampleId = mSoundPool.load(filePath, 0); 15089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (sampleId <= 0) { 15099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Log.w(TAG, "Soundpool could not load file: "+filePath); 1510117b7bb5b5a4457711f59bde3dcc83d8f111c524Eric Laurent } else { 1511117b7bb5b5a4457711f59bde3dcc83d8f111c524Eric Laurent SOUND_EFFECT_FILES_MAP[effect][1] = sampleId; 1512117b7bb5b5a4457711f59bde3dcc83d8f111c524Eric Laurent poolId[SOUND_EFFECT_FILES_MAP[effect][0]] = sampleId; 1513117b7bb5b5a4457711f59bde3dcc83d8f111c524Eric Laurent lastSample = sampleId; 15149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 15159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 15169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project SOUND_EFFECT_FILES_MAP[effect][1] = poolId[SOUND_EFFECT_FILES_MAP[effect][0]]; 15179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 15189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1519a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent // wait for all samples to be loaded 1520117b7bb5b5a4457711f59bde3dcc83d8f111c524Eric Laurent if (lastSample != 0) { 1521117b7bb5b5a4457711f59bde3dcc83d8f111c524Eric Laurent mSoundPoolCallBack.setLastSample(lastSample); 1522117b7bb5b5a4457711f59bde3dcc83d8f111c524Eric Laurent 1523117b7bb5b5a4457711f59bde3dcc83d8f111c524Eric Laurent try { 1524117b7bb5b5a4457711f59bde3dcc83d8f111c524Eric Laurent mSoundEffectsLock.wait(); 1525117b7bb5b5a4457711f59bde3dcc83d8f111c524Eric Laurent status = mSoundPoolCallBack.status(); 1526117b7bb5b5a4457711f59bde3dcc83d8f111c524Eric Laurent } catch (java.lang.InterruptedException e) { 1527117b7bb5b5a4457711f59bde3dcc83d8f111c524Eric Laurent Log.w(TAG, "Interrupted while waiting sound pool callback."); 1528117b7bb5b5a4457711f59bde3dcc83d8f111c524Eric Laurent status = -1; 1529117b7bb5b5a4457711f59bde3dcc83d8f111c524Eric Laurent } 1530117b7bb5b5a4457711f59bde3dcc83d8f111c524Eric Laurent } else { 1531a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent status = -1; 1532a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent } 1533117b7bb5b5a4457711f59bde3dcc83d8f111c524Eric Laurent 1534a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent if (mSoundPoolLooper != null) { 1535a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent mSoundPoolLooper.quit(); 1536a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent mSoundPoolLooper = null; 1537a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent } 1538a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent mSoundPoolListenerThread = null; 1539a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent if (status != 0) { 1540a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent Log.w(TAG, 1541a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent "loadSoundEffects(), Error " 1542117b7bb5b5a4457711f59bde3dcc83d8f111c524Eric Laurent + ((lastSample != 0) ? mSoundPoolCallBack.status() : -1) 1543a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent + " while loading samples"); 1544117b7bb5b5a4457711f59bde3dcc83d8f111c524Eric Laurent for (int effect = 0; effect < AudioManager.NUM_SOUND_EFFECTS; effect++) { 1545117b7bb5b5a4457711f59bde3dcc83d8f111c524Eric Laurent if (SOUND_EFFECT_FILES_MAP[effect][1] > 0) { 1546117b7bb5b5a4457711f59bde3dcc83d8f111c524Eric Laurent SOUND_EFFECT_FILES_MAP[effect][1] = -1; 1547117b7bb5b5a4457711f59bde3dcc83d8f111c524Eric Laurent } 1548117b7bb5b5a4457711f59bde3dcc83d8f111c524Eric Laurent } 1549117b7bb5b5a4457711f59bde3dcc83d8f111c524Eric Laurent 1550a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent mSoundPool.release(); 1551a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent mSoundPool = null; 1552a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent } 15539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1554a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent return (status == 0); 15559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 15569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 15579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 15589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Unloads samples from the sound pool. 15599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * This method can be called to free some memory when 15609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * sound effects are disabled. 15619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 15629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void unloadSoundEffects() { 15639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project synchronized (mSoundEffectsLock) { 15649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mSoundPool == null) { 15659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return; 15669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1567a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent 1568117b7bb5b5a4457711f59bde3dcc83d8f111c524Eric Laurent mAudioHandler.removeMessages(MSG_LOAD_SOUND_EFFECTS); 1569a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent mAudioHandler.removeMessages(MSG_PLAY_SOUND_EFFECT); 1570a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent 15719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int[] poolId = new int[SOUND_EFFECT_FILES.length]; 15729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (int fileIdx = 0; fileIdx < SOUND_EFFECT_FILES.length; fileIdx++) { 15739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project poolId[fileIdx] = 0; 15749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 15759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 15769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (int effect = 0; effect < AudioManager.NUM_SOUND_EFFECTS; effect++) { 15779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (SOUND_EFFECT_FILES_MAP[effect][1] <= 0) { 15789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project continue; 15799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 15809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (poolId[SOUND_EFFECT_FILES_MAP[effect][0]] == 0) { 15819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mSoundPool.unload(SOUND_EFFECT_FILES_MAP[effect][1]); 15829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project SOUND_EFFECT_FILES_MAP[effect][1] = -1; 15839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project poolId[SOUND_EFFECT_FILES_MAP[effect][0]] = -1; 15849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 15859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1586a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent mSoundPool.release(); 15879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mSoundPool = null; 15889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 15899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 15909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1591a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent class SoundPoolListenerThread extends Thread { 1592a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent public SoundPoolListenerThread() { 1593a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent super("SoundPoolListenerThread"); 1594a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent } 1595a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent 1596a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent @Override 1597a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent public void run() { 1598a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent 1599a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent Looper.prepare(); 1600a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent mSoundPoolLooper = Looper.myLooper(); 1601a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent 1602a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent synchronized (mSoundEffectsLock) { 1603a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent if (mSoundPool != null) { 1604a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent mSoundPoolCallBack = new SoundPoolCallback(); 1605a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent mSoundPool.setOnLoadCompleteListener(mSoundPoolCallBack); 1606a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent } 1607a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent mSoundEffectsLock.notify(); 1608a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent } 1609a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent Looper.loop(); 1610a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent } 1611a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent } 1612a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent 1613a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent private final class SoundPoolCallback implements 1614a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent android.media.SoundPool.OnLoadCompleteListener { 1615a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent 1616a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent int mStatus; 1617a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent int mLastSample; 1618a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent 1619a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent public int status() { 1620a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent return mStatus; 1621a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent } 1622a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent 1623a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent public void setLastSample(int sample) { 1624a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent mLastSample = sample; 1625a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent } 1626a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent 1627a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent public void onLoadComplete(SoundPool soundPool, int sampleId, int status) { 1628a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent synchronized (mSoundEffectsLock) { 1629a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent if (status != 0) { 1630a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent mStatus = status; 1631a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent } 1632a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent if (sampleId == mLastSample) { 1633a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent mSoundEffectsLock.notify(); 1634a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent } 1635a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent } 1636a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent } 1637a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent } 1638a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent 16394050c93601b3c3609b21cc1e18a29b64747e7fa9Eric Laurent /** @see AudioManager#reloadAudioSettings() */ 16404050c93601b3c3609b21cc1e18a29b64747e7fa9Eric Laurent public void reloadAudioSettings() { 16414050c93601b3c3609b21cc1e18a29b64747e7fa9Eric Laurent // restore ringer mode, ringer mode affected streams, mute affected streams and vibrate settings 16424050c93601b3c3609b21cc1e18a29b64747e7fa9Eric Laurent readPersistedSettings(); 16434050c93601b3c3609b21cc1e18a29b64747e7fa9Eric Laurent 16444050c93601b3c3609b21cc1e18a29b64747e7fa9Eric Laurent // restore volume settings 16454050c93601b3c3609b21cc1e18a29b64747e7fa9Eric Laurent int numStreamTypes = AudioSystem.getNumStreamTypes(); 16464050c93601b3c3609b21cc1e18a29b64747e7fa9Eric Laurent for (int streamType = 0; streamType < numStreamTypes; streamType++) { 16474050c93601b3c3609b21cc1e18a29b64747e7fa9Eric Laurent VolumeStreamState streamState = mStreamStates[streamType]; 16484050c93601b3c3609b21cc1e18a29b64747e7fa9Eric Laurent 16493172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent synchronized (streamState) { 16503172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent streamState.readSettings(); 1651a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent 16523172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent // unmute stream that was muted but is not affect by mute anymore 16533172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent if (streamState.muteCount() != 0 && !isStreamAffectedByMute(streamType)) { 16543172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent int size = streamState.mDeathHandlers.size(); 16553172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent for (int i = 0; i < size; i++) { 16563172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent streamState.mDeathHandlers.get(i).mMuteCount = 1; 16573172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent streamState.mDeathHandlers.get(i).mute(false); 16583172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent } 16593172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent } 16604050c93601b3c3609b21cc1e18a29b64747e7fa9Eric Laurent } 16614050c93601b3c3609b21cc1e18a29b64747e7fa9Eric Laurent } 16624050c93601b3c3609b21cc1e18a29b64747e7fa9Eric Laurent 1663244820185269991186d07068b92985624cede4a5Eric Laurent checkAllAliasStreamVolumes(); 1664244820185269991186d07068b92985624cede4a5Eric Laurent 16654050c93601b3c3609b21cc1e18a29b64747e7fa9Eric Laurent // apply new ringer mode 16664050c93601b3c3609b21cc1e18a29b64747e7fa9Eric Laurent setRingerModeInt(getRingerMode(), false); 16674050c93601b3c3609b21cc1e18a29b64747e7fa9Eric Laurent } 16684050c93601b3c3609b21cc1e18a29b64747e7fa9Eric Laurent 1669c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent /** @see AudioManager#setSpeakerphoneOn() */ 1670c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent public void setSpeakerphoneOn(boolean on){ 1671dc1d17a1dbfc2ae01c20012133a836b62f5b6930Eric Laurent if (!checkAudioSettingsPermission("setSpeakerphoneOn()")) { 1672dc1d17a1dbfc2ae01c20012133a836b62f5b6930Eric Laurent return; 1673dc1d17a1dbfc2ae01c20012133a836b62f5b6930Eric Laurent } 1674fa640154f1f42121d81242b2f1a10f03e52f0014Eric Laurent mForcedUseForComm = on ? AudioSystem.FORCE_SPEAKER : AudioSystem.FORCE_NONE; 1675fa640154f1f42121d81242b2f1a10f03e52f0014Eric Laurent 1676afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent sendMsg(mAudioHandler, MSG_SET_FORCE_USE, SENDMSG_QUEUE, 1677fa640154f1f42121d81242b2f1a10f03e52f0014Eric Laurent AudioSystem.FOR_COMMUNICATION, mForcedUseForComm, null, 0); 1678c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent } 1679c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent 1680c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent /** @see AudioManager#isSpeakerphoneOn() */ 1681c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent public boolean isSpeakerphoneOn() { 1682fa640154f1f42121d81242b2f1a10f03e52f0014Eric Laurent return (mForcedUseForComm == AudioSystem.FORCE_SPEAKER); 1683c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent } 1684c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent 1685c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent /** @see AudioManager#setBluetoothScoOn() */ 1686c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent public void setBluetoothScoOn(boolean on){ 1687dc1d17a1dbfc2ae01c20012133a836b62f5b6930Eric Laurent if (!checkAudioSettingsPermission("setBluetoothScoOn()")) { 1688dc1d17a1dbfc2ae01c20012133a836b62f5b6930Eric Laurent return; 1689dc1d17a1dbfc2ae01c20012133a836b62f5b6930Eric Laurent } 1690fa640154f1f42121d81242b2f1a10f03e52f0014Eric Laurent mForcedUseForComm = on ? AudioSystem.FORCE_BT_SCO : AudioSystem.FORCE_NONE; 1691fa640154f1f42121d81242b2f1a10f03e52f0014Eric Laurent 1692afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent sendMsg(mAudioHandler, MSG_SET_FORCE_USE, SENDMSG_QUEUE, 1693fa640154f1f42121d81242b2f1a10f03e52f0014Eric Laurent AudioSystem.FOR_COMMUNICATION, mForcedUseForComm, null, 0); 1694afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent sendMsg(mAudioHandler, MSG_SET_FORCE_USE, SENDMSG_QUEUE, 1695fa640154f1f42121d81242b2f1a10f03e52f0014Eric Laurent AudioSystem.FOR_RECORD, mForcedUseForComm, null, 0); 1696c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent } 1697c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent 1698c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent /** @see AudioManager#isBluetoothScoOn() */ 1699c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent public boolean isBluetoothScoOn() { 1700fa640154f1f42121d81242b2f1a10f03e52f0014Eric Laurent return (mForcedUseForComm == AudioSystem.FORCE_BT_SCO); 1701c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent } 1702c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent 17037847211fb4699bf6018e29d214a918ed6657319bEric Laurent /** @see AudioManager#setBluetoothA2dpOn() */ 17047847211fb4699bf6018e29d214a918ed6657319bEric Laurent public void setBluetoothA2dpOn(boolean on) { 1705c390bed06b4a572e273ead1254da9a932e04dce3Eric Laurent synchronized (mBluetoothA2dpEnabledLock) { 1706c390bed06b4a572e273ead1254da9a932e04dce3Eric Laurent mBluetoothA2dpEnabled = on; 1707c390bed06b4a572e273ead1254da9a932e04dce3Eric Laurent sendMsg(mAudioHandler, MSG_SET_FORCE_BT_A2DP_USE, SENDMSG_QUEUE, 1708c390bed06b4a572e273ead1254da9a932e04dce3Eric Laurent AudioSystem.FOR_MEDIA, 1709c390bed06b4a572e273ead1254da9a932e04dce3Eric Laurent mBluetoothA2dpEnabled ? AudioSystem.FORCE_NONE : AudioSystem.FORCE_NO_BT_A2DP, 1710c390bed06b4a572e273ead1254da9a932e04dce3Eric Laurent null, 0); 1711c390bed06b4a572e273ead1254da9a932e04dce3Eric Laurent } 17127847211fb4699bf6018e29d214a918ed6657319bEric Laurent } 17137847211fb4699bf6018e29d214a918ed6657319bEric Laurent 17147847211fb4699bf6018e29d214a918ed6657319bEric Laurent /** @see AudioManager#isBluetoothA2dpOn() */ 17157847211fb4699bf6018e29d214a918ed6657319bEric Laurent public boolean isBluetoothA2dpOn() { 17167847211fb4699bf6018e29d214a918ed6657319bEric Laurent synchronized (mBluetoothA2dpEnabledLock) { 17177847211fb4699bf6018e29d214a918ed6657319bEric Laurent return mBluetoothA2dpEnabled; 17187847211fb4699bf6018e29d214a918ed6657319bEric Laurent } 17197847211fb4699bf6018e29d214a918ed6657319bEric Laurent } 17207847211fb4699bf6018e29d214a918ed6657319bEric Laurent 17213def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent /** @see AudioManager#startBluetoothSco() */ 17223def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent public void startBluetoothSco(IBinder cb){ 1723dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent if (!checkAudioSettingsPermission("startBluetoothSco()") || 1724dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent !mBootCompleted) { 17253def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent return; 17263def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent } 1727854938a72d968c1bc0de4e2b0ea87777cfebc045Eric Laurent ScoClient client = getScoClient(cb, true); 17283def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent client.incCount(); 17293def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent } 17303def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent 17313def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent /** @see AudioManager#stopBluetoothSco() */ 17323def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent public void stopBluetoothSco(IBinder cb){ 1733dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent if (!checkAudioSettingsPermission("stopBluetoothSco()") || 1734dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent !mBootCompleted) { 17353def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent return; 17363def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent } 1737854938a72d968c1bc0de4e2b0ea87777cfebc045Eric Laurent ScoClient client = getScoClient(cb, false); 1738854938a72d968c1bc0de4e2b0ea87777cfebc045Eric Laurent if (client != null) { 1739854938a72d968c1bc0de4e2b0ea87777cfebc045Eric Laurent client.decCount(); 1740854938a72d968c1bc0de4e2b0ea87777cfebc045Eric Laurent } 17413def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent } 17423def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent 17437847211fb4699bf6018e29d214a918ed6657319bEric Laurent 17443def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent private class ScoClient implements IBinder.DeathRecipient { 17453def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent private IBinder mCb; // To be notified of client's death 1746f1ddd51f9cd2f92b922bc636c307210a8d587c25Marco Nelissen private int mCreatorPid; 17473def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent private int mStartcount; // number of SCO connections started by this client 17483def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent 17493def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent ScoClient(IBinder cb) { 17503def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent mCb = cb; 1751f1ddd51f9cd2f92b922bc636c307210a8d587c25Marco Nelissen mCreatorPid = Binder.getCallingPid(); 17523def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent mStartcount = 0; 17533def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent } 17543def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent 17553def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent public void binderDied() { 17563def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent synchronized(mScoClients) { 17573def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent Log.w(TAG, "SCO client died"); 17583def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent int index = mScoClients.indexOf(this); 17593def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent if (index < 0) { 17603def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent Log.w(TAG, "unregistered SCO client died"); 17613def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent } else { 17623def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent clearCount(true); 17633def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent mScoClients.remove(this); 17643def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent } 17653def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent } 17663def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent } 17673def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent 17683def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent public void incCount() { 17693def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent synchronized(mScoClients) { 177082aa7f017daaaeb96c13e6e3491d5037ab471085Jaikumar Ganesh requestScoState(BluetoothHeadset.STATE_AUDIO_CONNECTED); 17713def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent if (mStartcount == 0) { 17723def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent try { 17733def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent mCb.linkToDeath(this, 0); 17743def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent } catch (RemoteException e) { 17753def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent // client has already died! 17763def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent Log.w(TAG, "ScoClient incCount() could not link to "+mCb+" binder death"); 17773def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent } 17783def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent } 17793def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent mStartcount++; 17803def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent } 17813def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent } 17823def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent 17833def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent public void decCount() { 17843def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent synchronized(mScoClients) { 17853def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent if (mStartcount == 0) { 17863def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent Log.w(TAG, "ScoClient.decCount() already 0"); 17873def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent } else { 17883def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent mStartcount--; 17893def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent if (mStartcount == 0) { 1790e2dd8c4592762414c2c27e4589be7edc91a5ecaeEric Laurent try { 1791e2dd8c4592762414c2c27e4589be7edc91a5ecaeEric Laurent mCb.unlinkToDeath(this, 0); 1792e2dd8c4592762414c2c27e4589be7edc91a5ecaeEric Laurent } catch (NoSuchElementException e) { 1793e2dd8c4592762414c2c27e4589be7edc91a5ecaeEric Laurent Log.w(TAG, "decCount() going to 0 but not registered to binder"); 1794e2dd8c4592762414c2c27e4589be7edc91a5ecaeEric Laurent } 17953def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent } 179682aa7f017daaaeb96c13e6e3491d5037ab471085Jaikumar Ganesh requestScoState(BluetoothHeadset.STATE_AUDIO_DISCONNECTED); 17973def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent } 17983def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent } 17993def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent } 18003def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent 18013def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent public void clearCount(boolean stopSco) { 18023def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent synchronized(mScoClients) { 1803e2dd8c4592762414c2c27e4589be7edc91a5ecaeEric Laurent if (mStartcount != 0) { 1804e2dd8c4592762414c2c27e4589be7edc91a5ecaeEric Laurent try { 1805e2dd8c4592762414c2c27e4589be7edc91a5ecaeEric Laurent mCb.unlinkToDeath(this, 0); 1806e2dd8c4592762414c2c27e4589be7edc91a5ecaeEric Laurent } catch (NoSuchElementException e) { 1807e2dd8c4592762414c2c27e4589be7edc91a5ecaeEric Laurent Log.w(TAG, "clearCount() mStartcount: "+mStartcount+" != 0 but not registered to binder"); 1808e2dd8c4592762414c2c27e4589be7edc91a5ecaeEric Laurent } 1809e2dd8c4592762414c2c27e4589be7edc91a5ecaeEric Laurent } 18103def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent mStartcount = 0; 18113def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent if (stopSco) { 181282aa7f017daaaeb96c13e6e3491d5037ab471085Jaikumar Ganesh requestScoState(BluetoothHeadset.STATE_AUDIO_DISCONNECTED); 18133def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent } 18143def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent } 18153def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent } 18163def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent 18173def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent public int getCount() { 18183def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent return mStartcount; 18193def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent } 18203def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent 18213def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent public IBinder getBinder() { 18223def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent return mCb; 18233def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent } 18243def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent 1825d7454be47f4111c0478a502353e11dea401378bdEric Laurent public int getPid() { 1826d7454be47f4111c0478a502353e11dea401378bdEric Laurent return mCreatorPid; 1827d7454be47f4111c0478a502353e11dea401378bdEric Laurent } 1828d7454be47f4111c0478a502353e11dea401378bdEric Laurent 18293def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent public int totalCount() { 18303def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent synchronized(mScoClients) { 18313def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent int count = 0; 18323def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent int size = mScoClients.size(); 18333def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent for (int i = 0; i < size; i++) { 18343def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent count += mScoClients.get(i).getCount(); 18353def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent } 18363def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent return count; 18373def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent } 18383def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent } 18393def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent 18403def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent private void requestScoState(int state) { 184162ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent checkScoAudioState(); 1842dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent if (totalCount() == 0) { 1843dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent if (state == BluetoothHeadset.STATE_AUDIO_CONNECTED) { 1844dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent // Make sure that the state transitions to CONNECTING even if we cannot initiate 1845dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent // the connection. 1846dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_CONNECTING); 1847dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent // Accept SCO audio activation only in NORMAL audio mode or if the mode is 1848f1ddd51f9cd2f92b922bc636c307210a8d587c25Marco Nelissen // currently controlled by the same client process. 18499f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent synchronized(mSetModeDeathHandlers) { 18509f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent if ((mSetModeDeathHandlers.isEmpty() || 18519f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent mSetModeDeathHandlers.get(0).getPid() == mCreatorPid) && 18529f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent (mScoAudioState == SCO_STATE_INACTIVE || 18539f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent mScoAudioState == SCO_STATE_DEACTIVATE_REQ)) { 18549f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent if (mScoAudioState == SCO_STATE_INACTIVE) { 18559f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent if (mBluetoothHeadset != null && mBluetoothHeadsetDevice != null) { 18569f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent if (mBluetoothHeadset.startScoUsingVirtualVoiceCall( 18579f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent mBluetoothHeadsetDevice)) { 18589f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent mScoAudioState = SCO_STATE_ACTIVE_INTERNAL; 18599f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent } else { 18609f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent broadcastScoConnectionState( 18619f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent AudioManager.SCO_AUDIO_STATE_DISCONNECTED); 18629f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent } 18639f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent } else if (getBluetoothHeadset()) { 18649f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent mScoAudioState = SCO_STATE_ACTIVATE_REQ; 1865dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent } 18669f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent } else { 18679f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent mScoAudioState = SCO_STATE_ACTIVE_INTERNAL; 18689f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_CONNECTED); 1869dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent } 1870dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent } else { 18719f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_DISCONNECTED); 1872dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent } 1873dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent } 187462ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent } else if (state == BluetoothHeadset.STATE_AUDIO_DISCONNECTED && 1875dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent (mScoAudioState == SCO_STATE_ACTIVE_INTERNAL || 1876dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent mScoAudioState == SCO_STATE_ACTIVATE_REQ)) { 1877dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent if (mScoAudioState == SCO_STATE_ACTIVE_INTERNAL) { 1878671db6f3ba1fdb3c907e0735fe6d0d284f5c34deMarco Nelissen if (mBluetoothHeadset != null && mBluetoothHeadsetDevice != null) { 1879dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent if (!mBluetoothHeadset.stopScoUsingVirtualVoiceCall( 1880dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent mBluetoothHeadsetDevice)) { 1881dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent mScoAudioState = SCO_STATE_INACTIVE; 1882dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent broadcastScoConnectionState( 1883dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent AudioManager.SCO_AUDIO_STATE_DISCONNECTED); 1884dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent } 1885dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent } else if (getBluetoothHeadset()) { 1886dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent mScoAudioState = SCO_STATE_DEACTIVATE_REQ; 1887dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent } 1888dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent } else { 1889dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent mScoAudioState = SCO_STATE_INACTIVE; 1890dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_DISCONNECTED); 1891dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent } 18923def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent } 18933def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent } 18943def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent } 18953def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent } 18963def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent 189762ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent private void checkScoAudioState() { 189862ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent if (mBluetoothHeadset != null && mBluetoothHeadsetDevice != null && 1899dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent mScoAudioState == SCO_STATE_INACTIVE && 190062ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent mBluetoothHeadset.getAudioState(mBluetoothHeadsetDevice) 190162ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent != BluetoothHeadset.STATE_AUDIO_DISCONNECTED) { 190262ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent mScoAudioState = SCO_STATE_ACTIVE_EXTERNAL; 190362ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent } 190462ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent } 190562ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent 1906854938a72d968c1bc0de4e2b0ea87777cfebc045Eric Laurent private ScoClient getScoClient(IBinder cb, boolean create) { 19073def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent synchronized(mScoClients) { 1908854938a72d968c1bc0de4e2b0ea87777cfebc045Eric Laurent ScoClient client = null; 19093def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent int size = mScoClients.size(); 19103def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent for (int i = 0; i < size; i++) { 19113def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent client = mScoClients.get(i); 19123def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent if (client.getBinder() == cb) 19133def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent return client; 19143def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent } 1915854938a72d968c1bc0de4e2b0ea87777cfebc045Eric Laurent if (create) { 1916854938a72d968c1bc0de4e2b0ea87777cfebc045Eric Laurent client = new ScoClient(cb); 1917854938a72d968c1bc0de4e2b0ea87777cfebc045Eric Laurent mScoClients.add(client); 1918854938a72d968c1bc0de4e2b0ea87777cfebc045Eric Laurent } 19193def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent return client; 19203def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent } 19213def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent } 19223def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent 1923d7454be47f4111c0478a502353e11dea401378bdEric Laurent public void clearAllScoClients(int exceptPid, boolean stopSco) { 19243def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent synchronized(mScoClients) { 1925854938a72d968c1bc0de4e2b0ea87777cfebc045Eric Laurent ScoClient savedClient = null; 19263def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent int size = mScoClients.size(); 19273def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent for (int i = 0; i < size; i++) { 1928854938a72d968c1bc0de4e2b0ea87777cfebc045Eric Laurent ScoClient cl = mScoClients.get(i); 1929d7454be47f4111c0478a502353e11dea401378bdEric Laurent if (cl.getPid() != exceptPid) { 1930854938a72d968c1bc0de4e2b0ea87777cfebc045Eric Laurent cl.clearCount(stopSco); 1931854938a72d968c1bc0de4e2b0ea87777cfebc045Eric Laurent } else { 1932854938a72d968c1bc0de4e2b0ea87777cfebc045Eric Laurent savedClient = cl; 1933854938a72d968c1bc0de4e2b0ea87777cfebc045Eric Laurent } 1934854938a72d968c1bc0de4e2b0ea87777cfebc045Eric Laurent } 1935854938a72d968c1bc0de4e2b0ea87777cfebc045Eric Laurent mScoClients.clear(); 1936854938a72d968c1bc0de4e2b0ea87777cfebc045Eric Laurent if (savedClient != null) { 1937854938a72d968c1bc0de4e2b0ea87777cfebc045Eric Laurent mScoClients.add(savedClient); 19383def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent } 19393def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent } 19403def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent } 19413def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent 1942dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent private boolean getBluetoothHeadset() { 1943dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent boolean result = false; 1944dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter(); 1945dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent if (adapter != null) { 1946dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent result = adapter.getProfileProxy(mContext, mBluetoothProfileServiceListener, 1947dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent BluetoothProfile.HEADSET); 1948dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent } 1949dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent // If we could not get a bluetooth headset proxy, send a failure message 1950dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent // without delay to reset the SCO audio state and clear SCO clients. 1951dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent // If we could get a proxy, send a delayed failure message that will reset our state 1952dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent // in case we don't receive onServiceConnected(). 1953afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent sendMsg(mAudioHandler, MSG_BT_HEADSET_CNCT_FAILED, 1954dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent SENDMSG_REPLACE, 0, 0, null, result ? BT_HEADSET_CNCT_TIMEOUT_MS : 0); 1955dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent return result; 1956dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent } 1957dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent 1958d7454be47f4111c0478a502353e11dea401378bdEric Laurent private void disconnectBluetoothSco(int exceptPid) { 1959dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent synchronized(mScoClients) { 1960dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent checkScoAudioState(); 1961dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent if (mScoAudioState == SCO_STATE_ACTIVE_EXTERNAL || 1962dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent mScoAudioState == SCO_STATE_DEACTIVATE_EXT_REQ) { 1963dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent if (mBluetoothHeadsetDevice != null) { 1964dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent if (mBluetoothHeadset != null) { 1965dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent if (!mBluetoothHeadset.stopVoiceRecognition( 1966b06ac839dd2d0437fc8314f6deb7233af5af521eEric Laurent mBluetoothHeadsetDevice)) { 1967afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent sendMsg(mAudioHandler, MSG_BT_HEADSET_CNCT_FAILED, 1968dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent SENDMSG_REPLACE, 0, 0, null, 0); 1969dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent } 1970dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent } else if (mScoAudioState == SCO_STATE_ACTIVE_EXTERNAL && 1971dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent getBluetoothHeadset()) { 1972dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent mScoAudioState = SCO_STATE_DEACTIVATE_EXT_REQ; 1973dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent } 1974dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent } 1975dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent } else { 1976d7454be47f4111c0478a502353e11dea401378bdEric Laurent clearAllScoClients(exceptPid, true); 1977dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent } 1978dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent } 1979dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent } 1980dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent 1981dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent private void resetBluetoothSco() { 1982dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent synchronized(mScoClients) { 1983d7454be47f4111c0478a502353e11dea401378bdEric Laurent clearAllScoClients(0, false); 1984dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent mScoAudioState = SCO_STATE_INACTIVE; 1985dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_DISCONNECTED); 1986dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent } 1987dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent } 1988dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent 1989dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent private void broadcastScoConnectionState(int state) { 1990dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent if (state != mScoConnectionState) { 1991dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent Intent newIntent = new Intent(AudioManager.ACTION_SCO_AUDIO_STATE_UPDATED); 1992dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent newIntent.putExtra(AudioManager.EXTRA_SCO_AUDIO_STATE, state); 1993dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent newIntent.putExtra(AudioManager.EXTRA_SCO_AUDIO_PREVIOUS_STATE, 1994dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent mScoConnectionState); 1995dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent mContext.sendStickyBroadcast(newIntent); 1996dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent mScoConnectionState = state; 1997dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent } 1998dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent } 1999dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent 200082aa7f017daaaeb96c13e6e3491d5037ab471085Jaikumar Ganesh private BluetoothProfile.ServiceListener mBluetoothProfileServiceListener = 200182aa7f017daaaeb96c13e6e3491d5037ab471085Jaikumar Ganesh new BluetoothProfile.ServiceListener() { 200282aa7f017daaaeb96c13e6e3491d5037ab471085Jaikumar Ganesh public void onServiceConnected(int profile, BluetoothProfile proxy) { 20036bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent BluetoothDevice btDevice; 20046bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent List<BluetoothDevice> deviceList; 20056bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent switch(profile) { 20066bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent case BluetoothProfile.A2DP: 20076bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent BluetoothA2dp a2dp = (BluetoothA2dp) proxy; 20086bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent deviceList = a2dp.getConnectedDevices(); 200962ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent if (deviceList.size() > 0) { 20106bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent btDevice = deviceList.get(0); 2011b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent synchronized (mConnectedDevices) { 2012b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent int state = a2dp.getConnectionState(btDevice); 2013b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent int delay = checkSendBecomingNoisyIntent( 2014b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, 2015b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent (state == BluetoothA2dp.STATE_CONNECTED) ? 1 : 0); 2016e12c39bb9cedb8b363658979872694eb55b1386eJean-Michel Trivi queueMsgUnderWakeLock(mAudioHandler, 2017b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent MSG_SET_A2DP_CONNECTION_STATE, 2018b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent state, 2019b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent 0, 2020b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent btDevice, 2021b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent delay); 2022b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent } 20236bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent } 20246bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent break; 20256bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent 20266bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent case BluetoothProfile.HEADSET: 20276bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent synchronized (mScoClients) { 20286bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent // Discard timeout message 20296bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent mAudioHandler.removeMessages(MSG_BT_HEADSET_CNCT_FAILED); 20306bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent mBluetoothHeadset = (BluetoothHeadset) proxy; 20316bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent deviceList = mBluetoothHeadset.getConnectedDevices(); 20326bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent if (deviceList.size() > 0) { 20336bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent mBluetoothHeadsetDevice = deviceList.get(0); 20346bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent } else { 20356bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent mBluetoothHeadsetDevice = null; 2036dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent } 20376bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent // Refresh SCO audio state 20386bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent checkScoAudioState(); 20396bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent // Continue pending action if any 20406bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent if (mScoAudioState == SCO_STATE_ACTIVATE_REQ || 20416bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent mScoAudioState == SCO_STATE_DEACTIVATE_REQ || 20426bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent mScoAudioState == SCO_STATE_DEACTIVATE_EXT_REQ) { 20436bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent boolean status = false; 20446bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent if (mBluetoothHeadsetDevice != null) { 20456bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent switch (mScoAudioState) { 20466bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent case SCO_STATE_ACTIVATE_REQ: 20476bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent mScoAudioState = SCO_STATE_ACTIVE_INTERNAL; 20486bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent status = mBluetoothHeadset.startScoUsingVirtualVoiceCall( 20496bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent mBluetoothHeadsetDevice); 20506bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent break; 20516bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent case SCO_STATE_DEACTIVATE_REQ: 20526bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent status = mBluetoothHeadset.stopScoUsingVirtualVoiceCall( 20536bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent mBluetoothHeadsetDevice); 20546bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent break; 20556bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent case SCO_STATE_DEACTIVATE_EXT_REQ: 20566bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent status = mBluetoothHeadset.stopVoiceRecognition( 20576bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent mBluetoothHeadsetDevice); 20586bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent } 20596bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent } 20606bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent if (!status) { 2061afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent sendMsg(mAudioHandler, MSG_BT_HEADSET_CNCT_FAILED, 20626bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent SENDMSG_REPLACE, 0, 0, null, 0); 20636bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent } 2064dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent } 2065dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent } 20666bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent break; 20676bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent 20686bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent default: 20696bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent break; 20703def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent } 20713def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent } 207282aa7f017daaaeb96c13e6e3491d5037ab471085Jaikumar Ganesh public void onServiceDisconnected(int profile) { 20736bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent switch(profile) { 20746bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent case BluetoothProfile.A2DP: 20756bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent synchronized (mConnectedDevices) { 20766bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent if (mConnectedDevices.containsKey(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP)) { 20776bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent makeA2dpDeviceUnavailableNow( 20786bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent mConnectedDevices.get(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP)); 20796bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent } 20806bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent } 20816bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent break; 20826bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent 20836bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent case BluetoothProfile.HEADSET: 20846bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent synchronized (mScoClients) { 20856bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent mBluetoothHeadset = null; 20866bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent } 20876bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent break; 20886bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent 20896bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent default: 20906bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent break; 20913def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent } 20923def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent } 20933def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent }; 2094d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi 20959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /////////////////////////////////////////////////////////////////////////// 20969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Internal methods 20979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /////////////////////////////////////////////////////////////////////////// 20989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 20999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 21009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Checks if the adjustment should change ringer mode instead of just 21019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * adjusting volume. If so, this will set the proper ringer mode and volume 21029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * indices on the stream states. 21039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 2104244820185269991186d07068b92985624cede4a5Eric Laurent private boolean checkForRingerModeChange(int oldIndex, int direction, int step) { 21059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project boolean adjustVolumeIndex = true; 2106ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten int ringerMode = getRingerMode(); 2107bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent 2108bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent switch (ringerMode) { 2109bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent case RINGER_MODE_NORMAL: 2110bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent if (direction == AudioManager.ADJUST_LOWER) { 2111bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent if (mHasVibrator) { 2112244820185269991186d07068b92985624cede4a5Eric Laurent // "step" is the delta in internal index units corresponding to a 2113244820185269991186d07068b92985624cede4a5Eric Laurent // change of 1 in UI index units. 2114244820185269991186d07068b92985624cede4a5Eric Laurent // Because of rounding when rescaling from one stream index range to its alias 2115244820185269991186d07068b92985624cede4a5Eric Laurent // index range, we cannot simply test oldIndex == step: 2116244820185269991186d07068b92985624cede4a5Eric Laurent // (step <= oldIndex < 2 * step) is equivalent to: (old UI index == 1) 2117244820185269991186d07068b92985624cede4a5Eric Laurent if (step <= oldIndex && oldIndex < 2 * step) { 2118bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent ringerMode = RINGER_MODE_VIBRATE; 2119bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent } 2120bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent } else { 2121244820185269991186d07068b92985624cede4a5Eric Laurent // (oldIndex < step) is equivalent to (old UI index == 0) 2122244820185269991186d07068b92985624cede4a5Eric Laurent if ((oldIndex < step) && mPrevVolDirection != AudioManager.ADJUST_LOWER) { 2123bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent ringerMode = RINGER_MODE_SILENT; 2124bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent } 21253d4c06f90726a85e89dab13c41ddc15b9c912a3fEric Laurent } 21266329bf7b1e2217c6c9477bd57349a1edade18417Daniel Sandler } 2127bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent break; 2128bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent case RINGER_MODE_VIBRATE: 2129bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent if (!mHasVibrator) { 2130bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent Log.e(TAG, "checkForRingerModeChange() current ringer mode is vibrate" + 2131bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent "but no vibrator is present"); 2132bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent break; 2133bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent } 2134c696a53d1fe4d61373c5dc64dd057d322da90c8fAmith Yamasani if ((direction == AudioManager.ADJUST_LOWER)) { 2135c696a53d1fe4d61373c5dc64dd057d322da90c8fAmith Yamasani if (mPrevVolDirection != AudioManager.ADJUST_LOWER) { 2136bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent ringerMode = RINGER_MODE_SILENT; 2137c696a53d1fe4d61373c5dc64dd057d322da90c8fAmith Yamasani } 2138c696a53d1fe4d61373c5dc64dd057d322da90c8fAmith Yamasani } else if (direction == AudioManager.ADJUST_RAISE) { 2139bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent ringerMode = RINGER_MODE_NORMAL; 2140c696a53d1fe4d61373c5dc64dd057d322da90c8fAmith Yamasani } 2141c696a53d1fe4d61373c5dc64dd057d322da90c8fAmith Yamasani adjustVolumeIndex = false; 2142bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent break; 2143bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent case RINGER_MODE_SILENT: 21449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (direction == AudioManager.ADJUST_RAISE) { 2145bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent if (mHasVibrator) { 2146bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent ringerMode = RINGER_MODE_VIBRATE; 2147bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent } else { 2148bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent ringerMode = RINGER_MODE_NORMAL; 2149bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent } 21509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2151b024c30a80684ac08daef3137b7ba0d347fe3ce5Eric Laurent adjustVolumeIndex = false; 2152bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent break; 2153bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent default: 2154bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent Log.e(TAG, "checkForRingerModeChange() wrong ringer mode: "+ringerMode); 2155bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent break; 21569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 21579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2158bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent setRingerMode(ringerMode); 21599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 216025101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent mPrevVolDirection = direction; 216125101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent 21629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return adjustVolumeIndex; 21639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 21649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 21659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public boolean isStreamAffectedByRingerMode(int streamType) { 21669bcf401d13d47416043a704430388abd59aef7cdEric Laurent return (mRingerModeAffectedStreams & (1 << streamType)) != 0; 21679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 21689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 21695b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent private boolean isStreamMutedByRingerMode(int streamType) { 21705b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent return (mRingerModeMutedStreams & (1 << streamType)) != 0; 21715b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent } 21725b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent 21739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public boolean isStreamAffectedByMute(int streamType) { 21749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return (mMuteAffectedStreams & (1 << streamType)) != 0; 21759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 21769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 21779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private void ensureValidDirection(int direction) { 21789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (direction < AudioManager.ADJUST_LOWER || direction > AudioManager.ADJUST_RAISE) { 21799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project throw new IllegalArgumentException("Bad direction " + direction); 21809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 21819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 21829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 21836c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang private void ensureValidSteps(int steps) { 21846c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang if (Math.abs(steps) > MAX_BATCH_VOLUME_ADJUST_STEPS) { 21856c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang throw new IllegalArgumentException("Bad volume adjust steps " + steps); 21866c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang } 21876c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang } 21886c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang 21899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private void ensureValidStreamType(int streamType) { 21909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (streamType < 0 || streamType >= mStreamStates.length) { 21919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project throw new IllegalArgumentException("Bad stream type " + streamType); 21929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 21939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 21949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 21956d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent private boolean isInCommunication() { 21966d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent boolean isOffhook = false; 219725101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent 219825101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent if (mVoiceCapable) { 219925101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent try { 220025101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent ITelephony phone = ITelephony.Stub.asInterface(ServiceManager.checkService("phone")); 220125101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent if (phone != null) isOffhook = phone.isOffhook(); 220225101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent } catch (RemoteException e) { 220325101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent Log.w(TAG, "Couldn't connect to phone service", e); 220425101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent } 22056d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent } 22066d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent return (isOffhook || getMode() == AudioManager.MODE_IN_COMMUNICATION); 22076d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent } 220825101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent 22096d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent private int getActiveStreamType(int suggestedStreamType) { 22106d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent if (mVoiceCapable) { 22116d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent if (isInCommunication()) { 221225101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent if (AudioSystem.getForceUse(AudioSystem.FOR_COMMUNICATION) 221325101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent == AudioSystem.FORCE_BT_SCO) { 221425101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent // Log.v(TAG, "getActiveStreamType: Forcing STREAM_BLUETOOTH_SCO..."); 221525101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent return AudioSystem.STREAM_BLUETOOTH_SCO; 221625101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent } else { 221725101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent // Log.v(TAG, "getActiveStreamType: Forcing STREAM_VOICE_CALL..."); 221825101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent return AudioSystem.STREAM_VOICE_CALL; 221925101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent } 22203114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi } else if (suggestedStreamType == AudioManager.USE_DEFAULT_STREAM_TYPE) { 22213114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi // Having the suggested stream be USE_DEFAULT_STREAM_TYPE is how remote control 22223114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi // volume can have priority over STREAM_MUSIC 22233114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi if (checkUpdateRemoteStateIfActive(AudioSystem.STREAM_MUSIC)) { 22243114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi if (DEBUG_VOL) 22253114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi Log.v(TAG, "getActiveStreamType: Forcing STREAM_REMOTE_MUSIC"); 22263114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi return STREAM_REMOTE_MUSIC; 22273114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi } else if (AudioSystem.isStreamActive(AudioSystem.STREAM_MUSIC, 0)) { 22283114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi if (DEBUG_VOL) 22293114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi Log.v(TAG, "getActiveStreamType: Forcing STREAM_MUSIC stream active"); 22303114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi return AudioSystem.STREAM_MUSIC; 22313114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi } else { 22323114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi if (DEBUG_VOL) 22333114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi Log.v(TAG, "getActiveStreamType: Forcing STREAM_RING b/c default"); 22343114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi return AudioSystem.STREAM_RING; 22353114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi } 223625101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent } else if (AudioSystem.isStreamActive(AudioSystem.STREAM_MUSIC, 0)) { 22373114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi if (DEBUG_VOL) 22383114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi Log.v(TAG, "getActiveStreamType: Forcing STREAM_MUSIC stream active"); 223925101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent return AudioSystem.STREAM_MUSIC; 2240c7fcba4b7bd3d78e7cfe975a3f8e4dde2f6738b7Joe Onorato } else { 22413114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: Returning suggested type " 22423114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi + suggestedStreamType); 224325101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent return suggestedStreamType; 224425101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent } 224525101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent } else { 22466d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent if (isInCommunication()) { 224725101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent if (AudioSystem.getForceUse(AudioSystem.FOR_COMMUNICATION) 224825101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent == AudioSystem.FORCE_BT_SCO) { 22493114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: Forcing STREAM_BLUETOOTH_SCO"); 225025101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent return AudioSystem.STREAM_BLUETOOTH_SCO; 225125101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent } else { 22523114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: Forcing STREAM_VOICE_CALL"); 225325101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent return AudioSystem.STREAM_VOICE_CALL; 225425101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent } 225525101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent } else if (AudioSystem.isStreamActive(AudioSystem.STREAM_NOTIFICATION, 22563114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi NOTIFICATION_VOLUME_DELAY_MS) || 22573114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi AudioSystem.isStreamActive(AudioSystem.STREAM_RING, 225825101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent NOTIFICATION_VOLUME_DELAY_MS)) { 22593114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: Forcing STREAM_NOTIFICATION"); 226025101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent return AudioSystem.STREAM_NOTIFICATION; 22613114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi } else if (suggestedStreamType == AudioManager.USE_DEFAULT_STREAM_TYPE) { 22623114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi if (checkUpdateRemoteStateIfActive(AudioSystem.STREAM_MUSIC)) { 22633114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi // Having the suggested stream be USE_DEFAULT_STREAM_TYPE is how remote control 22643114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi // volume can have priority over STREAM_MUSIC 22653114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: Forcing STREAM_REMOTE_MUSIC"); 22663114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi return STREAM_REMOTE_MUSIC; 22673114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi } else { 22683114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi if (DEBUG_VOL) 22693114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi Log.v(TAG, "getActiveStreamType: using STREAM_MUSIC as default"); 22703114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi return AudioSystem.STREAM_MUSIC; 22713114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi } 227225101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent } else { 22733114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: Returning suggested type " 22743114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi + suggestedStreamType); 227525101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent return suggestedStreamType; 2276c7fcba4b7bd3d78e7cfe975a3f8e4dde2f6738b7Joe Onorato } 22779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 22789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 22799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2280ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten private void broadcastRingerMode(int ringerMode) { 22819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Send sticky broadcast 22821c633fc89bae9bf0af6fe643ac7ad2e744f27bedDianne Hackborn Intent broadcast = new Intent(AudioManager.RINGER_MODE_CHANGED_ACTION); 2283ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten broadcast.putExtra(AudioManager.EXTRA_RINGER_MODE, ringerMode); 22841c633fc89bae9bf0af6fe643ac7ad2e744f27bedDianne Hackborn broadcast.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT 22851c633fc89bae9bf0af6fe643ac7ad2e744f27bedDianne Hackborn | Intent.FLAG_RECEIVER_REPLACE_PENDING); 22861c633fc89bae9bf0af6fe643ac7ad2e744f27bedDianne Hackborn long origCallerIdentityToken = Binder.clearCallingIdentity(); 22871c633fc89bae9bf0af6fe643ac7ad2e744f27bedDianne Hackborn mContext.sendStickyBroadcast(broadcast); 22881c633fc89bae9bf0af6fe643ac7ad2e744f27bedDianne Hackborn Binder.restoreCallingIdentity(origCallerIdentityToken); 22899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 22909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 22919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private void broadcastVibrateSetting(int vibrateType) { 22929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Send broadcast 22939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (ActivityManagerNative.isSystemReady()) { 22949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Intent broadcast = new Intent(AudioManager.VIBRATE_SETTING_CHANGED_ACTION); 22959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project broadcast.putExtra(AudioManager.EXTRA_VIBRATE_TYPE, vibrateType); 22969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project broadcast.putExtra(AudioManager.EXTRA_VIBRATE_SETTING, getVibrateSetting(vibrateType)); 22979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mContext.sendBroadcast(broadcast); 22989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 22999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 23009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 23019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Message helper methods 23022d8dab5a549b25b6f36df4614d7c0166d4d099e2Jean-Michel Trivi /** 23032d8dab5a549b25b6f36df4614d7c0166d4d099e2Jean-Michel Trivi * Queue a message on the given handler's message queue, after acquiring the service wake lock. 23042d8dab5a549b25b6f36df4614d7c0166d4d099e2Jean-Michel Trivi * Note that the wake lock needs to be released after the message has been handled. 23052d8dab5a549b25b6f36df4614d7c0166d4d099e2Jean-Michel Trivi */ 23062d8dab5a549b25b6f36df4614d7c0166d4d099e2Jean-Michel Trivi private void queueMsgUnderWakeLock(Handler handler, int msg, 23072d8dab5a549b25b6f36df4614d7c0166d4d099e2Jean-Michel Trivi int arg1, int arg2, Object obj, int delay) { 23082d8dab5a549b25b6f36df4614d7c0166d4d099e2Jean-Michel Trivi mMediaEventWakeLock.acquire(); 23092d8dab5a549b25b6f36df4614d7c0166d4d099e2Jean-Michel Trivi sendMsg(handler, msg, SENDMSG_QUEUE, arg1, arg2, obj, delay); 23102d8dab5a549b25b6f36df4614d7c0166d4d099e2Jean-Michel Trivi } 23119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2312afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent private static void sendMsg(Handler handler, int msg, 23139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int existingMsgPolicy, int arg1, int arg2, Object obj, int delay) { 23149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 23159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (existingMsgPolicy == SENDMSG_REPLACE) { 23169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project handler.removeMessages(msg); 23179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else if (existingMsgPolicy == SENDMSG_NOOP && handler.hasMessages(msg)) { 23189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return; 23199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 23209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2321afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent handler.sendMessageDelayed(handler.obtainMessage(msg, arg1, arg2, obj), delay); 23229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 23239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 23249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project boolean checkAudioSettingsPermission(String method) { 23259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mContext.checkCallingOrSelfPermission("android.permission.MODIFY_AUDIO_SETTINGS") 23269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project == PackageManager.PERMISSION_GRANTED) { 23279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return true; 23289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 23299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project String msg = "Audio Settings Permission Denial: " + method + " from pid=" 23309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project + Binder.getCallingPid() 23319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project + ", uid=" + Binder.getCallingUid(); 23329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Log.w(TAG, msg); 23339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return false; 23349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 23359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 23369bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent private int getDeviceForStream(int stream) { 23379bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent int device = AudioSystem.getDevicesForStream(stream); 23389bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent if ((device & (device - 1)) != 0) { 23399bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent // Multiple device selection is either: 23409bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent // - speaker + one other device: give priority to speaker in this case. 23419bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent // - one A2DP device + another device: happens with duplicated output. In this case 23429bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent // retain the device on the A2DP output as the other must not correspond to an active 23439bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent // selection if not the speaker. 23449bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent if ((device & AudioSystem.DEVICE_OUT_SPEAKER) != 0) { 23459bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent device = AudioSystem.DEVICE_OUT_SPEAKER; 23469bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent } else { 23479bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent device &= AudioSystem.DEVICE_OUT_ALL_A2DP; 23489bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent } 23499bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent } 23509bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent return device; 23519bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent } 23529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2353b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent public void setWiredDeviceConnectionState(int device, int state, String name) { 2354b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent synchronized (mConnectedDevices) { 2355b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent int delay = checkSendBecomingNoisyIntent(device, state); 23562d8dab5a549b25b6f36df4614d7c0166d4d099e2Jean-Michel Trivi queueMsgUnderWakeLock(mAudioHandler, 2357b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent MSG_SET_WIRED_DEVICE_CONNECTION_STATE, 2358b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent device, 2359b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent state, 2360b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent name, 2361b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent delay); 2362b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent } 2363b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent } 2364b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent 2365b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent public int setBluetoothA2dpDeviceConnectionState(BluetoothDevice device, int state) 2366b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent { 2367b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent int delay; 2368b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent synchronized (mConnectedDevices) { 2369b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent delay = checkSendBecomingNoisyIntent(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, 2370b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent (state == BluetoothA2dp.STATE_CONNECTED) ? 1 : 0); 23712d8dab5a549b25b6f36df4614d7c0166d4d099e2Jean-Michel Trivi queueMsgUnderWakeLock(mAudioHandler, 2372b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent MSG_SET_A2DP_CONNECTION_STATE, 2373b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent state, 2374b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent 0, 2375b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent device, 2376b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent delay); 2377b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent } 2378b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent return delay; 2379b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent } 2380b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent 23819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /////////////////////////////////////////////////////////////////////////// 23829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Inner classes 23839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /////////////////////////////////////////////////////////////////////////// 23849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 23859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public class VolumeStreamState { 23869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private final int mStreamType; 23879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 238811a74a75653197a3d31fe91590cd8312f5270c44Jean-Michel Trivi private String mVolumeIndexSettingName; 238911a74a75653197a3d31fe91590cd8312f5270c44Jean-Michel Trivi private String mLastAudibleVolumeIndexSettingName; 2390a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent private int mIndexMax; 23913172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent private final ConcurrentHashMap<Integer, Integer> mIndex = 23923172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent new ConcurrentHashMap<Integer, Integer>(8, 0.75f, 4); 23933172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent private final ConcurrentHashMap<Integer, Integer> mLastAudibleIndex = 23943172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent new ConcurrentHashMap<Integer, Integer>(8, 0.75f, 4); 23959bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent private ArrayList<VolumeDeathHandler> mDeathHandlers; //handles mute/solo clients death 23969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2397a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent private VolumeStreamState(String settingName, int streamType) { 23989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 23999bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent mVolumeIndexSettingName = settingName; 24009bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent mLastAudibleVolumeIndexSettingName = settingName + System.APPEND_FOR_LAST_AUDIBLE; 24019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 24029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mStreamType = streamType; 24035982013cfc8274ff0bafaba83c676b3a8890cba9Jared Suttles mIndexMax = MAX_STREAM_VOLUME[streamType]; 2404a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent AudioSystem.initStreamVolume(streamType, 0, mIndexMax); 2405a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent mIndexMax *= 10; 24069bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent 24079bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent readSettings(); 24089bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent 24099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mDeathHandlers = new ArrayList<VolumeDeathHandler>(); 24109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 24119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 24129bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent public String getSettingNameForDevice(boolean lastAudible, int device) { 24139bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent String name = lastAudible ? 24149bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent mLastAudibleVolumeIndexSettingName : 24159bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent mVolumeIndexSettingName; 24169bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent String suffix = AudioSystem.getDeviceName(device); 24179bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent if (suffix.isEmpty()) { 24189bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent return name; 24199bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent } 24209bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent return name + "_" + suffix; 24219bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent } 24229bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent 24233172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent public synchronized void readSettings() { 24249bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent int remainingDevices = AudioSystem.DEVICE_OUT_ALL; 24259ac8d0c445a3ccde40c05f0f3ad0ec4e8265d4c6Eric Laurent 24269bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent for (int i = 0; remainingDevices != 0; i++) { 24279bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent int device = (1 << i); 24289bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent if ((device & remainingDevices) == 0) { 24299bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent continue; 24309bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent } 24319bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent remainingDevices &= ~device; 24329bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent 24339bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent // retrieve current volume for device 24349ac8d0c445a3ccde40c05f0f3ad0ec4e8265d4c6Eric Laurent String name = getSettingNameForDevice(false /* lastAudible */, device); 24359ac8d0c445a3ccde40c05f0f3ad0ec4e8265d4c6Eric Laurent // if no volume stored for current stream and device, use default volume if default 24369ac8d0c445a3ccde40c05f0f3ad0ec4e8265d4c6Eric Laurent // device, continue otherwise 24379ac8d0c445a3ccde40c05f0f3ad0ec4e8265d4c6Eric Laurent int defaultIndex = (device == AudioSystem.DEVICE_OUT_DEFAULT) ? 24389ac8d0c445a3ccde40c05f0f3ad0ec4e8265d4c6Eric Laurent AudioManager.DEFAULT_STREAM_VOLUME[mStreamType] : -1; 24399ac8d0c445a3ccde40c05f0f3ad0ec4e8265d4c6Eric Laurent int index = Settings.System.getInt(mContentResolver, name, defaultIndex); 24409bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent if (index == -1) { 24419bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent continue; 24429bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent } 24439bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent 24449bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent // retrieve last audible volume for device 24459ac8d0c445a3ccde40c05f0f3ad0ec4e8265d4c6Eric Laurent name = getSettingNameForDevice(true /* lastAudible */, device); 24469ac8d0c445a3ccde40c05f0f3ad0ec4e8265d4c6Eric Laurent // use stored last audible index if present, otherwise use current index if not 0 24479ac8d0c445a3ccde40c05f0f3ad0ec4e8265d4c6Eric Laurent // or default index 24489ac8d0c445a3ccde40c05f0f3ad0ec4e8265d4c6Eric Laurent defaultIndex = (index > 0) ? 24499ac8d0c445a3ccde40c05f0f3ad0ec4e8265d4c6Eric Laurent index : AudioManager.DEFAULT_STREAM_VOLUME[mStreamType]; 24509ac8d0c445a3ccde40c05f0f3ad0ec4e8265d4c6Eric Laurent int lastAudibleIndex = Settings.System.getInt(mContentResolver, name, defaultIndex); 24519ac8d0c445a3ccde40c05f0f3ad0ec4e8265d4c6Eric Laurent 2452bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent // a last audible index of 0 should never be stored for ring and notification 2453bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent // streams on phones (voice capable devices). 2454bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent // same for system stream on phones and tablets 24559ac8d0c445a3ccde40c05f0f3ad0ec4e8265d4c6Eric Laurent if ((lastAudibleIndex == 0) && 2456bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent ((mVoiceCapable && 2457bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent (mStreamVolumeAlias[mStreamType] == AudioSystem.STREAM_RING)) || 2458bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent (mStreamVolumeAlias[mStreamType] == AudioSystem.STREAM_SYSTEM))) { 24599ac8d0c445a3ccde40c05f0f3ad0ec4e8265d4c6Eric Laurent lastAudibleIndex = AudioManager.DEFAULT_STREAM_VOLUME[mStreamType]; 24609ac8d0c445a3ccde40c05f0f3ad0ec4e8265d4c6Eric Laurent // Correct the data base 24619ac8d0c445a3ccde40c05f0f3ad0ec4e8265d4c6Eric Laurent sendMsg(mAudioHandler, 24629ac8d0c445a3ccde40c05f0f3ad0ec4e8265d4c6Eric Laurent MSG_PERSIST_VOLUME, 24639ac8d0c445a3ccde40c05f0f3ad0ec4e8265d4c6Eric Laurent SENDMSG_QUEUE, 24649ac8d0c445a3ccde40c05f0f3ad0ec4e8265d4c6Eric Laurent PERSIST_LAST_AUDIBLE, 24659ac8d0c445a3ccde40c05f0f3ad0ec4e8265d4c6Eric Laurent device, 24669ac8d0c445a3ccde40c05f0f3ad0ec4e8265d4c6Eric Laurent this, 24679ac8d0c445a3ccde40c05f0f3ad0ec4e8265d4c6Eric Laurent PERSIST_DELAY); 24689ac8d0c445a3ccde40c05f0f3ad0ec4e8265d4c6Eric Laurent } 24699ac8d0c445a3ccde40c05f0f3ad0ec4e8265d4c6Eric Laurent mLastAudibleIndex.put(device, getValidIndex(10 * lastAudibleIndex)); 2470bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent // the initial index should never be 0 for ring and notification streams on phones 2471bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent // (voice capable devices) if not in silent or vibrate mode. 2472bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent // same for system stream on phones and tablets 2473bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent if ((index == 0) && (mRingerMode == AudioManager.RINGER_MODE_NORMAL) && 2474bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent ((mVoiceCapable && 2475bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent (mStreamVolumeAlias[mStreamType] == AudioSystem.STREAM_RING)) || 2476bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent (mStreamVolumeAlias[mStreamType] == AudioSystem.STREAM_SYSTEM))) { 24779ac8d0c445a3ccde40c05f0f3ad0ec4e8265d4c6Eric Laurent index = lastAudibleIndex; 24789ac8d0c445a3ccde40c05f0f3ad0ec4e8265d4c6Eric Laurent // Correct the data base 24799ac8d0c445a3ccde40c05f0f3ad0ec4e8265d4c6Eric Laurent sendMsg(mAudioHandler, 24809ac8d0c445a3ccde40c05f0f3ad0ec4e8265d4c6Eric Laurent MSG_PERSIST_VOLUME, 24819ac8d0c445a3ccde40c05f0f3ad0ec4e8265d4c6Eric Laurent SENDMSG_QUEUE, 24829ac8d0c445a3ccde40c05f0f3ad0ec4e8265d4c6Eric Laurent PERSIST_CURRENT, 24839ac8d0c445a3ccde40c05f0f3ad0ec4e8265d4c6Eric Laurent device, 24849ac8d0c445a3ccde40c05f0f3ad0ec4e8265d4c6Eric Laurent this, 24859ac8d0c445a3ccde40c05f0f3ad0ec4e8265d4c6Eric Laurent PERSIST_DELAY); 24869ac8d0c445a3ccde40c05f0f3ad0ec4e8265d4c6Eric Laurent } 24879ac8d0c445a3ccde40c05f0f3ad0ec4e8265d4c6Eric Laurent mIndex.put(device, getValidIndex(10 * index)); 24889bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent } 24899bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent } 24909bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent 24919bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent public void applyDeviceVolume(int device) { 24929bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent AudioSystem.setStreamVolumeIndex(mStreamType, 24939bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent (getIndex(device, false /* lastAudible */) + 5)/10, 24949bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent device); 24959bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent } 24969bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent 24973172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent public synchronized void applyAllVolumes() { 24989bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent // apply default volume first: by convention this will reset all 24999bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent // devices volumes in audio policy manager to the supplied value 25009bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent AudioSystem.setStreamVolumeIndex(mStreamType, 25019bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent (getIndex(AudioSystem.DEVICE_OUT_DEFAULT, false /* lastAudible */) + 5)/10, 25029bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent AudioSystem.DEVICE_OUT_DEFAULT); 25039bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent // then apply device specific volumes 25049bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent Set set = mIndex.entrySet(); 25059bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent Iterator i = set.iterator(); 25069bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent while (i.hasNext()) { 25079bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent Map.Entry entry = (Map.Entry)i.next(); 25089bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent int device = ((Integer)entry.getKey()).intValue(); 25099bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent if (device != AudioSystem.DEVICE_OUT_DEFAULT) { 25109bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent AudioSystem.setStreamVolumeIndex(mStreamType, 25119bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent ((Integer)entry.getValue() + 5)/10, 25129bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent device); 25139bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent } 25149bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent } 251511a74a75653197a3d31fe91590cd8312f5270c44Jean-Michel Trivi } 251611a74a75653197a3d31fe91590cd8312f5270c44Jean-Michel Trivi 25179bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent public boolean adjustIndex(int deltaIndex, int device) { 25189bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent return setIndex(getIndex(device, 2519244820185269991186d07068b92985624cede4a5Eric Laurent false /* lastAudible */) + deltaIndex, 25209bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent device, 25219bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent true /* lastAudible */); 25229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 25239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 25243172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent public synchronized boolean setIndex(int index, int device, boolean lastAudible) { 25259bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent int oldIndex = getIndex(device, false /* lastAudible */); 25269bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent index = getValidIndex(index); 25279bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent mIndex.put(device, getValidIndex(index)); 25289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 25299bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent if (oldIndex != index) { 25309bcf401d13d47416043a704430388abd59aef7cdEric Laurent if (lastAudible) { 25319bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent mLastAudibleIndex.put(device, index); 25329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2533a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent // Apply change to all streams using this one as alias 2534bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent // if changing volume of current device, also change volume of current 2535bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent // device on aliased stream 2536bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent boolean currentDevice = (device == getDeviceForStream(mStreamType)); 2537a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent int numStreamTypes = AudioSystem.getNumStreamTypes(); 2538a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) { 2539bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent if (streamType != mStreamType && 2540bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent mStreamVolumeAlias[streamType] == mStreamType) { 2541bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent int scaledIndex = rescaleIndex(index, mStreamType, streamType); 2542bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent mStreamStates[streamType].setIndex(scaledIndex, 2543bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent device, 25449bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent lastAudible); 2545bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent if (currentDevice) { 2546bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent mStreamStates[streamType].setIndex(scaledIndex, 2547bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent getDeviceForStream(streamType), 2548bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent lastAudible); 2549bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent } 2550a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent } 2551a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent } 25529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return true; 25539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 25549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return false; 25559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 25569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 25579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 25583172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent public synchronized int getIndex(int device, boolean lastAudible) { 25593172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent ConcurrentHashMap <Integer, Integer> indexes; 25609bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent if (lastAudible) { 25619bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent indexes = mLastAudibleIndex; 25629bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent } else { 25639bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent indexes = mIndex; 25649bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent } 25659bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent Integer index = indexes.get(device); 25669bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent if (index == null) { 25679bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent // there is always an entry for AudioSystem.DEVICE_OUT_DEFAULT 25689bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent index = indexes.get(AudioSystem.DEVICE_OUT_DEFAULT); 25699bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent } 25709bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent return index.intValue(); 25719bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent } 25729bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent 25733172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent public synchronized void setLastAudibleIndex(int index, int device) { 2574244820185269991186d07068b92985624cede4a5Eric Laurent // Apply change to all streams using this one as alias 2575244820185269991186d07068b92985624cede4a5Eric Laurent // if changing volume of current device, also change volume of current 2576244820185269991186d07068b92985624cede4a5Eric Laurent // device on aliased stream 2577244820185269991186d07068b92985624cede4a5Eric Laurent boolean currentDevice = (device == getDeviceForStream(mStreamType)); 2578244820185269991186d07068b92985624cede4a5Eric Laurent int numStreamTypes = AudioSystem.getNumStreamTypes(); 2579244820185269991186d07068b92985624cede4a5Eric Laurent for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) { 2580244820185269991186d07068b92985624cede4a5Eric Laurent if (streamType != mStreamType && 2581244820185269991186d07068b92985624cede4a5Eric Laurent mStreamVolumeAlias[streamType] == mStreamType) { 2582244820185269991186d07068b92985624cede4a5Eric Laurent int scaledIndex = rescaleIndex(index, mStreamType, streamType); 2583244820185269991186d07068b92985624cede4a5Eric Laurent mStreamStates[streamType].setLastAudibleIndex(scaledIndex, device); 2584244820185269991186d07068b92985624cede4a5Eric Laurent if (currentDevice) { 2585244820185269991186d07068b92985624cede4a5Eric Laurent mStreamStates[streamType].setLastAudibleIndex(scaledIndex, 2586244820185269991186d07068b92985624cede4a5Eric Laurent getDeviceForStream(streamType)); 2587244820185269991186d07068b92985624cede4a5Eric Laurent } 2588244820185269991186d07068b92985624cede4a5Eric Laurent } 2589244820185269991186d07068b92985624cede4a5Eric Laurent } 25909bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent mLastAudibleIndex.put(device, getValidIndex(index)); 25915b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent } 25925b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent 25933172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent public synchronized void adjustLastAudibleIndex(int deltaIndex, int device) { 25949bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent setLastAudibleIndex(getIndex(device, 2595244820185269991186d07068b92985624cede4a5Eric Laurent true /* lastAudible */) + deltaIndex, 25969bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent device); 25975b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent } 25985b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent 25999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public int getMaxIndex() { 2600a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent return mIndexMax; 26019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 26029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 26033172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent // only called by setAllIndexes() which is already synchronized 26043172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent public ConcurrentHashMap <Integer, Integer> getAllIndexes(boolean lastAudible) { 26056d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent if (lastAudible) { 26066d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent return mLastAudibleIndex; 26076d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent } else { 26086d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent return mIndex; 26096d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent } 26106d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent } 26116d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent 26123172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent public synchronized void setAllIndexes(VolumeStreamState srcStream, boolean lastAudible) { 26133172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent ConcurrentHashMap <Integer, Integer> indexes = srcStream.getAllIndexes(lastAudible); 26146d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent Set set = indexes.entrySet(); 26156d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent Iterator i = set.iterator(); 26166d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent while (i.hasNext()) { 26176d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent Map.Entry entry = (Map.Entry)i.next(); 26186d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent int device = ((Integer)entry.getKey()).intValue(); 26196d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent int index = ((Integer)entry.getValue()).intValue(); 26206d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent index = rescaleIndex(index, srcStream.getStreamType(), mStreamType); 26216d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent setIndex(index, device, lastAudible); 26226d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent } 26236d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent } 26246d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent 26253172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent public synchronized void mute(IBinder cb, boolean state) { 26269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project VolumeDeathHandler handler = getDeathHandler(cb, state); 26279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (handler == null) { 26289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Log.e(TAG, "Could not get client death handler for stream: "+mStreamType); 26299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return; 26309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 26319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project handler.mute(state); 26329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 26339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 26346d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent public int getStreamType() { 26356d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent return mStreamType; 26366d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent } 26376d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent 26389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private int getValidIndex(int index) { 26399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (index < 0) { 26409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return 0; 2641a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent } else if (index > mIndexMax) { 2642a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent return mIndexMax; 26439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 26449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 26459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return index; 26469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 26479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 26489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private class VolumeDeathHandler implements IBinder.DeathRecipient { 26499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private IBinder mICallback; // To be notified of client's death 26509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private int mMuteCount; // Number of active mutes for this client 26519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 26529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project VolumeDeathHandler(IBinder cb) { 26539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mICallback = cb; 26549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 26559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 26563172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent // must be called while synchronized on parent VolumeStreamState 26579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void mute(boolean state) { 26583172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent if (state) { 26593172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent if (mMuteCount == 0) { 26603172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent // Register for client death notification 26613172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent try { 26623172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent // mICallback can be 0 if muted by AudioService 26633172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent if (mICallback != null) { 26643172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent mICallback.linkToDeath(this, 0); 26653172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent } 26663172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent mDeathHandlers.add(this); 26673172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent // If the stream is not yet muted by any client, set level to 0 26683172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent if (muteCount() == 0) { 26693172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent Set set = mIndex.entrySet(); 26703172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent Iterator i = set.iterator(); 26713172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent while (i.hasNext()) { 26723172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent Map.Entry entry = (Map.Entry)i.next(); 26733172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent int device = ((Integer)entry.getKey()).intValue(); 26743172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent setIndex(0, device, false /* lastAudible */); 26755b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent } 26763172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent sendMsg(mAudioHandler, 26773172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent MSG_SET_ALL_VOLUMES, 26783172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent SENDMSG_QUEUE, 26793172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent 0, 26803172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent 0, 26813172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent VolumeStreamState.this, 0); 26823172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent } 26833172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent } catch (RemoteException e) { 26843172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent // Client has died! 26853172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent binderDied(); 26863172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent return; 26873172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent } 26883172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent } else { 26893172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent Log.w(TAG, "stream: "+mStreamType+" was already muted by this client"); 26903172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent } 26913172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent mMuteCount++; 26923172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent } else { 26933172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent if (mMuteCount == 0) { 26943172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent Log.e(TAG, "unexpected unmute for stream: "+mStreamType); 26953172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent } else { 26963172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent mMuteCount--; 26973172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent if (mMuteCount == 0) { 26983172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent // Unregister from client death notification 26993172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent mDeathHandlers.remove(this); 27003172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent // mICallback can be 0 if muted by AudioService 27013172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent if (mICallback != null) { 27023172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent mICallback.unlinkToDeath(this, 0); 27033172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent } 27043172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent if (muteCount() == 0) { 27053172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent // If the stream is not muted any more, restore its volume if 27063172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent // ringer mode allows it 27073172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent if (!isStreamAffectedByRingerMode(mStreamType) || 27083172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent mRingerMode == AudioManager.RINGER_MODE_NORMAL) { 27099bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent Set set = mIndex.entrySet(); 27109bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent Iterator i = set.iterator(); 27119bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent while (i.hasNext()) { 27129bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent Map.Entry entry = (Map.Entry)i.next(); 27139bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent int device = ((Integer)entry.getKey()).intValue(); 27143172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent setIndex(getIndex(device, 27153172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent true /* lastAudible */), 27163172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent device, 27173172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent false /* lastAudible */); 27189bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent } 27199bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent sendMsg(mAudioHandler, 27209bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent MSG_SET_ALL_VOLUMES, 272198ad9b9d6fd34aad487933170f50b5519313df61Eric Laurent SENDMSG_QUEUE, 27229bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent 0, 27239bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent 0, 27249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project VolumeStreamState.this, 0); 27259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 27269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 27279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 27289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 27299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 27309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 27319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 27329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void binderDied() { 27339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Log.w(TAG, "Volume service client died for stream: "+mStreamType); 27349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mMuteCount != 0) { 27359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Reset all active mute requests from this client. 27369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mMuteCount = 1; 27379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mute(false); 27389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 27399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 27409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 27419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 27423172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent private synchronized int muteCount() { 27439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int count = 0; 27449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int size = mDeathHandlers.size(); 27459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (int i = 0; i < size; i++) { 27469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project count += mDeathHandlers.get(i).mMuteCount; 27479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 27489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return count; 27499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 27509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 27513172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent // only called by mute() which is already synchronized 27529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private VolumeDeathHandler getDeathHandler(IBinder cb, boolean state) { 27533172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent VolumeDeathHandler handler; 27543172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent int size = mDeathHandlers.size(); 27553172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent for (int i = 0; i < size; i++) { 27563172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent handler = mDeathHandlers.get(i); 27573172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent if (cb == handler.mICallback) { 27583172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent return handler; 2759ce952c8e13c535bedde77bcdb94dfcc7508475aaMike Lockwood } 2760ce952c8e13c535bedde77bcdb94dfcc7508475aaMike Lockwood } 27613172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent // If this is the first mute request for this client, create a new 27623172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent // client death handler. Otherwise, it is an out of sequence unmute request. 27633172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent if (state) { 27643172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent handler = new VolumeDeathHandler(cb); 27653172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent } else { 27663172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent Log.w(TAG, "stream was not muted by this client"); 27673172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent handler = null; 27683172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent } 27693172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent return handler; 2770ce952c8e13c535bedde77bcdb94dfcc7508475aaMike Lockwood } 2771bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent 2772bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent private void dump(PrintWriter pw) { 2773bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent pw.print(" Current: "); 2774bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent Set set = mIndex.entrySet(); 2775bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent Iterator i = set.iterator(); 2776bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent while (i.hasNext()) { 2777bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent Map.Entry entry = (Map.Entry)i.next(); 2778bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent pw.print(Integer.toHexString(((Integer)entry.getKey()).intValue()) 2779bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent + ": " + ((((Integer)entry.getValue()).intValue() + 5) / 10)+", "); 2780bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent } 2781bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent pw.print("\n Last audible: "); 2782bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent set = mLastAudibleIndex.entrySet(); 2783bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent i = set.iterator(); 2784bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent while (i.hasNext()) { 2785bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent Map.Entry entry = (Map.Entry)i.next(); 2786bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent pw.print(Integer.toHexString(((Integer)entry.getKey()).intValue()) 2787bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent + ": " + ((((Integer)entry.getValue()).intValue() + 5) / 10)+", "); 2788bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent } 2789bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent } 2790ce952c8e13c535bedde77bcdb94dfcc7508475aaMike Lockwood } 2791ce952c8e13c535bedde77bcdb94dfcc7508475aaMike Lockwood 27929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** Thread that handles native AudioSystem control. */ 27939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private class AudioSystemThread extends Thread { 27949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project AudioSystemThread() { 27959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project super("AudioService"); 27969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 27979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 27989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @Override 27999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void run() { 28009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Set this thread up so the handler will work on it 28019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Looper.prepare(); 28029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 28039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project synchronized(AudioService.this) { 28049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mAudioHandler = new AudioHandler(); 28059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 28069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Notify that the handler has been created 28079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project AudioService.this.notify(); 28089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 28099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 28109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Listen for volume change requests that are set by VolumePanel 28119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Looper.loop(); 28129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 28139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 28149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 28159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** Handles internal volume messages in separate volume thread. */ 28169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private class AudioHandler extends Handler { 28179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 28189bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent private void setDeviceVolume(VolumeStreamState streamState, int device) { 28199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 28209bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent // Apply volume 28219bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent streamState.applyDeviceVolume(device); 2822a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent 2823a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent // Apply change to all streams using this one as alias 2824a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent int numStreamTypes = AudioSystem.getNumStreamTypes(); 2825a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) { 2826a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent if (streamType != streamState.mStreamType && 28276d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent mStreamVolumeAlias[streamType] == streamState.mStreamType) { 28286d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent mStreamStates[streamType].applyDeviceVolume(getDeviceForStream(streamType)); 2829a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent } 2830a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent } 28319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 28329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Post a persist volume msg 2833afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent sendMsg(mAudioHandler, 2834afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent MSG_PERSIST_VOLUME, 283598ad9b9d6fd34aad487933170f50b5519313df61Eric Laurent SENDMSG_QUEUE, 2836afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent PERSIST_CURRENT|PERSIST_LAST_AUDIBLE, 28379bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent device, 2838afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent streamState, 2839afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent PERSIST_DELAY); 2840afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent 28419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 28429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 28439bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent private void setAllVolumes(VolumeStreamState streamState) { 28449bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent 28459bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent // Apply volume 28469bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent streamState.applyAllVolumes(); 28479bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent 28489bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent // Apply change to all streams using this one as alias 28499bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent int numStreamTypes = AudioSystem.getNumStreamTypes(); 28509bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) { 28519bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent if (streamType != streamState.mStreamType && 28526d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent mStreamVolumeAlias[streamType] == streamState.mStreamType) { 28539bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent mStreamStates[streamType].applyAllVolumes(); 28549bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent } 28559bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent } 28569bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent } 28579bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent 2858afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent private void persistVolume(VolumeStreamState streamState, 28599bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent int persistType, 28609bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent int device) { 2861afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent if ((persistType & PERSIST_CURRENT) != 0) { 28629bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent System.putInt(mContentResolver, 28639bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent streamState.getSettingNameForDevice(false /* lastAudible */, device), 28649bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent (streamState.getIndex(device, false /* lastAudible */) + 5)/ 10); 286531951ca52aa007891b0be975318199e207c70e02Eric Laurent } 2866afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent if ((persistType & PERSIST_LAST_AUDIBLE) != 0) { 28679bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent System.putInt(mContentResolver, 28689bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent streamState.getSettingNameForDevice(true /* lastAudible */, device), 28699bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent (streamState.getIndex(device, true /* lastAudible */) + 5) / 10); 287031951ca52aa007891b0be975318199e207c70e02Eric Laurent } 28719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 28729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2873ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten private void persistRingerMode(int ringerMode) { 2874ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten System.putInt(mContentResolver, System.MODE_RINGER, ringerMode); 28759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 28769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 28779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private void playSoundEffect(int effectType, int volume) { 28789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project synchronized (mSoundEffectsLock) { 28799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mSoundPool == null) { 28809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return; 28819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2882a2ef57dba9ac77d8eccacd646b2b8a8d99fe9d8bEric Laurent float volFloat; 288325101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent // use default if volume is not specified by caller 2884a2ef57dba9ac77d8eccacd646b2b8a8d99fe9d8bEric Laurent if (volume < 0) { 2885f2b0c11f4e797e183131261724d8de310dac5431Jean-Michel Trivi volFloat = (float)Math.pow(10, (float)sSoundEffectVolumeDb/20); 2886a2ef57dba9ac77d8eccacd646b2b8a8d99fe9d8bEric Laurent } else { 2887a2ef57dba9ac77d8eccacd646b2b8a8d99fe9d8bEric Laurent volFloat = (float) volume / 1000.0f; 2888a2ef57dba9ac77d8eccacd646b2b8a8d99fe9d8bEric Laurent } 28899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 28909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (SOUND_EFFECT_FILES_MAP[effectType][1] > 0) { 2891a2ef57dba9ac77d8eccacd646b2b8a8d99fe9d8bEric Laurent mSoundPool.play(SOUND_EFFECT_FILES_MAP[effectType][1], volFloat, volFloat, 0, 0, 1.0f); 28929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 28939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project MediaPlayer mediaPlayer = new MediaPlayer(); 289462b9aec7a0a4e1cf8cfec7e39ea3103ab510d72eGlenn Kasten try { 289562b9aec7a0a4e1cf8cfec7e39ea3103ab510d72eGlenn Kasten String filePath = Environment.getRootDirectory() + SOUND_EFFECTS_PATH + SOUND_EFFECT_FILES[SOUND_EFFECT_FILES_MAP[effectType][0]]; 289662b9aec7a0a4e1cf8cfec7e39ea3103ab510d72eGlenn Kasten mediaPlayer.setDataSource(filePath); 289762b9aec7a0a4e1cf8cfec7e39ea3103ab510d72eGlenn Kasten mediaPlayer.setAudioStreamType(AudioSystem.STREAM_SYSTEM); 289862b9aec7a0a4e1cf8cfec7e39ea3103ab510d72eGlenn Kasten mediaPlayer.prepare(); 289962b9aec7a0a4e1cf8cfec7e39ea3103ab510d72eGlenn Kasten mediaPlayer.setVolume(volFloat, volFloat); 290062b9aec7a0a4e1cf8cfec7e39ea3103ab510d72eGlenn Kasten mediaPlayer.setOnCompletionListener(new OnCompletionListener() { 290162b9aec7a0a4e1cf8cfec7e39ea3103ab510d72eGlenn Kasten public void onCompletion(MediaPlayer mp) { 290262b9aec7a0a4e1cf8cfec7e39ea3103ab510d72eGlenn Kasten cleanupPlayer(mp); 290362b9aec7a0a4e1cf8cfec7e39ea3103ab510d72eGlenn Kasten } 290462b9aec7a0a4e1cf8cfec7e39ea3103ab510d72eGlenn Kasten }); 290562b9aec7a0a4e1cf8cfec7e39ea3103ab510d72eGlenn Kasten mediaPlayer.setOnErrorListener(new OnErrorListener() { 290662b9aec7a0a4e1cf8cfec7e39ea3103ab510d72eGlenn Kasten public boolean onError(MediaPlayer mp, int what, int extra) { 290762b9aec7a0a4e1cf8cfec7e39ea3103ab510d72eGlenn Kasten cleanupPlayer(mp); 290862b9aec7a0a4e1cf8cfec7e39ea3103ab510d72eGlenn Kasten return true; 290962b9aec7a0a4e1cf8cfec7e39ea3103ab510d72eGlenn Kasten } 291062b9aec7a0a4e1cf8cfec7e39ea3103ab510d72eGlenn Kasten }); 291162b9aec7a0a4e1cf8cfec7e39ea3103ab510d72eGlenn Kasten mediaPlayer.start(); 291262b9aec7a0a4e1cf8cfec7e39ea3103ab510d72eGlenn Kasten } catch (IOException ex) { 291362b9aec7a0a4e1cf8cfec7e39ea3103ab510d72eGlenn Kasten Log.w(TAG, "MediaPlayer IOException: "+ex); 291462b9aec7a0a4e1cf8cfec7e39ea3103ab510d72eGlenn Kasten } catch (IllegalArgumentException ex) { 291562b9aec7a0a4e1cf8cfec7e39ea3103ab510d72eGlenn Kasten Log.w(TAG, "MediaPlayer IllegalArgumentException: "+ex); 291662b9aec7a0a4e1cf8cfec7e39ea3103ab510d72eGlenn Kasten } catch (IllegalStateException ex) { 291762b9aec7a0a4e1cf8cfec7e39ea3103ab510d72eGlenn Kasten Log.w(TAG, "MediaPlayer IllegalStateException: "+ex); 29189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 29199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 29209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 29219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 29229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2923f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi private void onHandlePersistMediaButtonReceiver(ComponentName receiver) { 2924d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi Settings.System.putString(mContentResolver, Settings.System.MEDIA_BUTTON_RECEIVER, 2925d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi receiver == null ? "" : receiver.flattenToString()); 2926d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi } 2927d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi 29289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private void cleanupPlayer(MediaPlayer mp) { 29299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mp != null) { 29309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project try { 29319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mp.stop(); 29329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mp.release(); 29339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } catch (IllegalStateException ex) { 29349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Log.w(TAG, "MediaPlayer IllegalStateException: "+ex); 29359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 29369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 29379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 29389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2939fa640154f1f42121d81242b2f1a10f03e52f0014Eric Laurent private void setForceUse(int usage, int config) { 2940fa640154f1f42121d81242b2f1a10f03e52f0014Eric Laurent AudioSystem.setForceUse(usage, config); 2941fa640154f1f42121d81242b2f1a10f03e52f0014Eric Laurent } 2942fa640154f1f42121d81242b2f1a10f03e52f0014Eric Laurent 29439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @Override 29449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void handleMessage(Message msg) { 29459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2946afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent switch (msg.what) { 29479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 29489bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent case MSG_SET_DEVICE_VOLUME: 29499bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent setDeviceVolume((VolumeStreamState) msg.obj, msg.arg1); 29509bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent break; 29519bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent 29529bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent case MSG_SET_ALL_VOLUMES: 29539bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent setAllVolumes((VolumeStreamState) msg.obj); 29549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project break; 29559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 29569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project case MSG_PERSIST_VOLUME: 29579bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent persistVolume((VolumeStreamState) msg.obj, msg.arg1, msg.arg2); 29589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project break; 29599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 29605c55a051ad7d86a464fb91426f1ea3c0250e38b3Mike Lockwood case MSG_PERSIST_MASTER_VOLUME: 29615c55a051ad7d86a464fb91426f1ea3c0250e38b3Mike Lockwood Settings.System.putFloat(mContentResolver, Settings.System.VOLUME_MASTER, 29625c55a051ad7d86a464fb91426f1ea3c0250e38b3Mike Lockwood (float)msg.arg1 / (float)1000.0); 29635c55a051ad7d86a464fb91426f1ea3c0250e38b3Mike Lockwood break; 29645c55a051ad7d86a464fb91426f1ea3c0250e38b3Mike Lockwood 296557978ed86286a33d5b1a0fd000ca3406ba9d87b3Justin Koh case MSG_PERSIST_MASTER_VOLUME_MUTE: 296657978ed86286a33d5b1a0fd000ca3406ba9d87b3Justin Koh Settings.System.putInt(mContentResolver, Settings.System.VOLUME_MASTER_MUTE, 296757978ed86286a33d5b1a0fd000ca3406ba9d87b3Justin Koh msg.arg1); 296857978ed86286a33d5b1a0fd000ca3406ba9d87b3Justin Koh break; 296957978ed86286a33d5b1a0fd000ca3406ba9d87b3Justin Koh 29709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project case MSG_PERSIST_RINGER_MODE: 2971ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten // note that the value persisted is the current ringer mode, not the 2972ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten // value of ringer mode as of the time the request was made to persist 2973ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten persistRingerMode(getRingerMode()); 29749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project break; 29759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 29769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project case MSG_MEDIA_SERVER_DIED: 297789e74ba1419732dd5c7f939e48d4aa7989fd3a51Eric Laurent if (!mMediaServerOk) { 297889e74ba1419732dd5c7f939e48d4aa7989fd3a51Eric Laurent Log.e(TAG, "Media server died."); 2979a25c5d88d17f251262307ce31e799c9cf361d145Eric Laurent // Force creation of new IAudioFlinger interface so that we are notified 2980a25c5d88d17f251262307ce31e799c9cf361d145Eric Laurent // when new media_server process is back to life. 2981a25c5d88d17f251262307ce31e799c9cf361d145Eric Laurent AudioSystem.setErrorCallback(mAudioSystemCallback); 2982afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent sendMsg(mAudioHandler, MSG_MEDIA_SERVER_DIED, SENDMSG_NOOP, 0, 0, 298389e74ba1419732dd5c7f939e48d4aa7989fd3a51Eric Laurent null, 500); 298489e74ba1419732dd5c7f939e48d4aa7989fd3a51Eric Laurent } 29859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project break; 29869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 29879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project case MSG_MEDIA_SERVER_STARTED: 29889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Log.e(TAG, "Media server started."); 29893c652ca5a546e7227a5f4bdbf0f81552b2c91383Eric Laurent // indicate to audio HAL that we start the reconfiguration phase after a media 29903c652ca5a546e7227a5f4bdbf0f81552b2c91383Eric Laurent // server crash 29913c652ca5a546e7227a5f4bdbf0f81552b2c91383Eric Laurent // Note that MSG_MEDIA_SERVER_STARTED message is only received when the media server 29923c652ca5a546e7227a5f4bdbf0f81552b2c91383Eric Laurent // process restarts after a crash, not the first time it is started. 29933c652ca5a546e7227a5f4bdbf0f81552b2c91383Eric Laurent AudioSystem.setParameters("restarting=true"); 29943c652ca5a546e7227a5f4bdbf0f81552b2c91383Eric Laurent 2995c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent // Restore device connection states 29966bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent synchronized (mConnectedDevices) { 29976bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent Set set = mConnectedDevices.entrySet(); 29986bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent Iterator i = set.iterator(); 29999bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent while (i.hasNext()) { 30006bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent Map.Entry device = (Map.Entry)i.next(); 30016bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent AudioSystem.setDeviceConnectionState( 30026bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent ((Integer)device.getKey()).intValue(), 30036bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent AudioSystem.DEVICE_STATE_AVAILABLE, 30046bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent (String)device.getValue()); 30056bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent } 3006c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent } 3007c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent // Restore call state 3008c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent AudioSystem.setPhoneState(mMode); 3009c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent 3010d5603c126acdd94d9f7400bb1d04188020a425b4Eric Laurent // Restore forced usage for communcations and record 3011c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent AudioSystem.setForceUse(AudioSystem.FOR_COMMUNICATION, mForcedUseForComm); 3012d5603c126acdd94d9f7400bb1d04188020a425b4Eric Laurent AudioSystem.setForceUse(AudioSystem.FOR_RECORD, mForcedUseForComm); 3013c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent 3014a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent // Restore stream volumes 30159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int numStreamTypes = AudioSystem.getNumStreamTypes(); 30169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) { 30179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project VolumeStreamState streamState = mStreamStates[streamType]; 3018c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent AudioSystem.initStreamVolume(streamType, 0, (streamState.mIndexMax + 5) / 10); 30199bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent 30209bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent streamState.applyAllVolumes(); 30219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3022c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent 3023c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent // Restore ringer mode 3024c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent setRingerModeInt(getRingerMode(), false); 30253c652ca5a546e7227a5f4bdbf0f81552b2c91383Eric Laurent 30269063154a793b0ab38b3c5992cbaed046427b4a82Mike Lockwood // Restore master volume 30279063154a793b0ab38b3c5992cbaed046427b4a82Mike Lockwood restoreMasterVolume(); 30289063154a793b0ab38b3c5992cbaed046427b4a82Mike Lockwood 3029f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi // Reset device orientation (if monitored for this device) 3030f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi if (SystemProperties.getBoolean("ro.audio.monitorOrientation", false)) { 3031f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi setOrientationForAudioSystem(); 3032f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi } 3033f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi 30347847211fb4699bf6018e29d214a918ed6657319bEric Laurent synchronized (mBluetoothA2dpEnabledLock) { 30357847211fb4699bf6018e29d214a918ed6657319bEric Laurent AudioSystem.setForceUse(AudioSystem.FOR_MEDIA, 30367847211fb4699bf6018e29d214a918ed6657319bEric Laurent mBluetoothA2dpEnabled ? 30377847211fb4699bf6018e29d214a918ed6657319bEric Laurent AudioSystem.FORCE_NONE : AudioSystem.FORCE_NO_BT_A2DP); 30387847211fb4699bf6018e29d214a918ed6657319bEric Laurent } 30393c652ca5a546e7227a5f4bdbf0f81552b2c91383Eric Laurent // indicate the end of reconfiguration phase to audio HAL 30403c652ca5a546e7227a5f4bdbf0f81552b2c91383Eric Laurent AudioSystem.setParameters("restarting=false"); 30419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project break; 30429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3043117b7bb5b5a4457711f59bde3dcc83d8f111c524Eric Laurent case MSG_LOAD_SOUND_EFFECTS: 3044117b7bb5b5a4457711f59bde3dcc83d8f111c524Eric Laurent loadSoundEffects(); 3045117b7bb5b5a4457711f59bde3dcc83d8f111c524Eric Laurent break; 3046117b7bb5b5a4457711f59bde3dcc83d8f111c524Eric Laurent 30479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project case MSG_PLAY_SOUND_EFFECT: 30489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project playSoundEffect(msg.arg1, msg.arg2); 30499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project break; 30504c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi 30514c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi case MSG_BTA2DP_DOCK_TIMEOUT: 30524c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi // msg.obj == address of BTA2DP device 30536bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent synchronized (mConnectedDevices) { 30546bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent makeA2dpDeviceUnavailableNow( (String) msg.obj ); 30556bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent } 30564c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi break; 3057fa640154f1f42121d81242b2f1a10f03e52f0014Eric Laurent 3058fa640154f1f42121d81242b2f1a10f03e52f0014Eric Laurent case MSG_SET_FORCE_USE: 3059c390bed06b4a572e273ead1254da9a932e04dce3Eric Laurent case MSG_SET_FORCE_BT_A2DP_USE: 3060fa640154f1f42121d81242b2f1a10f03e52f0014Eric Laurent setForceUse(msg.arg1, msg.arg2); 3061fa640154f1f42121d81242b2f1a10f03e52f0014Eric Laurent break; 3062d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi 3063d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi case MSG_PERSIST_MEDIABUTTONRECEIVER: 3064f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi onHandlePersistMediaButtonReceiver( (ComponentName) msg.obj ); 3065d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi break; 3066dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent 30678f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi case MSG_RCDISPLAY_CLEAR: 30684426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi onRcDisplayClear(); 30698f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi break; 30708f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi 30718f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi case MSG_RCDISPLAY_UPDATE: 30724426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi // msg.obj is guaranteed to be non null 30734426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi onRcDisplayUpdate( (RemoteControlStackEntry) msg.obj, msg.arg1); 30748f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi break; 30758f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi 3076dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent case MSG_BT_HEADSET_CNCT_FAILED: 3077dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent resetBluetoothSco(); 3078dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent break; 3079b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent 3080b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent case MSG_SET_WIRED_DEVICE_CONNECTION_STATE: 3081b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent onSetWiredDeviceConnectionState(msg.arg1, msg.arg2, (String)msg.obj); 30822d8dab5a549b25b6f36df4614d7c0166d4d099e2Jean-Michel Trivi mMediaEventWakeLock.release(); 3083b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent break; 3084b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent 3085b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent case MSG_SET_A2DP_CONNECTION_STATE: 3086b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent onSetA2dpConnectionState((BluetoothDevice)msg.obj, msg.arg1); 30872d8dab5a549b25b6f36df4614d7c0166d4d099e2Jean-Michel Trivi mMediaEventWakeLock.release(); 3088b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent break; 3089632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn 3090632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn case MSG_REPORT_NEW_ROUTES: { 3091632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn int N = mRoutesObservers.beginBroadcast(); 3092632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn if (N > 0) { 3093632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn AudioRoutesInfo routes; 3094632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn synchronized (mCurAudioRoutes) { 3095632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn routes = new AudioRoutesInfo(mCurAudioRoutes); 3096632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn } 3097632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn while (N > 0) { 3098632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn N--; 3099632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn IAudioRoutesObserver obs = mRoutesObservers.getBroadcastItem(N); 3100632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn try { 3101632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn obs.dispatchAudioRoutesChanged(routes); 3102632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn } catch (RemoteException e) { 3103632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn } 3104632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn } 3105632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn } 3106632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn mRoutesObservers.finishBroadcast(); 3107632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn break; 3108632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn } 31093114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi 31103114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi case MSG_REEVALUATE_REMOTE: 31113114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi onReevaluateRemote(); 31123114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi break; 3113f98de1e8dd6dcbd191921b4aa07a1d41b0b9db91Jean-Michel Trivi 3114f98de1e8dd6dcbd191921b4aa07a1d41b0b9db91Jean-Michel Trivi case MSG_RCC_NEW_PLAYBACK_INFO: 3115f98de1e8dd6dcbd191921b4aa07a1d41b0b9db91Jean-Michel Trivi onNewPlaybackInfoForRcc(msg.arg1 /* rccId */, msg.arg2 /* key */, 3116f98de1e8dd6dcbd191921b4aa07a1d41b0b9db91Jean-Michel Trivi ((Integer)msg.obj).intValue() /* value */); 3117f98de1e8dd6dcbd191921b4aa07a1d41b0b9db91Jean-Michel Trivi break; 3118f98de1e8dd6dcbd191921b4aa07a1d41b0b9db91Jean-Michel Trivi case MSG_RCC_NEW_VOLUME_OBS: 3119f98de1e8dd6dcbd191921b4aa07a1d41b0b9db91Jean-Michel Trivi onRegisterVolumeObserverForRcc(msg.arg1 /* rccId */, 3120f98de1e8dd6dcbd191921b4aa07a1d41b0b9db91Jean-Michel Trivi (IRemoteVolumeObserver)msg.obj /* rvo */); 3121f98de1e8dd6dcbd191921b4aa07a1d41b0b9db91Jean-Michel Trivi break; 31229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 31239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 31249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 31259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3126b109615ebebd6f3b9ae789412279f576c3ace46bJason Parekh private class SettingsObserver extends ContentObserver { 3127a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent 3128b109615ebebd6f3b9ae789412279f576c3ace46bJason Parekh SettingsObserver() { 3129b109615ebebd6f3b9ae789412279f576c3ace46bJason Parekh super(new Handler()); 3130b109615ebebd6f3b9ae789412279f576c3ace46bJason Parekh mContentResolver.registerContentObserver(Settings.System.getUriFor( 3131b109615ebebd6f3b9ae789412279f576c3ace46bJason Parekh Settings.System.MODE_RINGER_STREAMS_AFFECTED), false, this); 3132b109615ebebd6f3b9ae789412279f576c3ace46bJason Parekh } 3133b109615ebebd6f3b9ae789412279f576c3ace46bJason Parekh 3134b109615ebebd6f3b9ae789412279f576c3ace46bJason Parekh @Override 3135b109615ebebd6f3b9ae789412279f576c3ace46bJason Parekh public void onChange(boolean selfChange) { 3136b109615ebebd6f3b9ae789412279f576c3ace46bJason Parekh super.onChange(selfChange); 3137ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten // FIXME This synchronized is not necessary if mSettingsLock only protects mRingerMode. 3138ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten // However there appear to be some missing locks around mRingerModeMutedStreams 3139ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten // and mRingerModeAffectedStreams, so will leave this synchronized for now. 3140ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten // mRingerModeMutedStreams and mMuteAffectedStreams are safe (only accessed once). 3141a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent synchronized (mSettingsLock) { 3142a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent int ringerModeAffectedStreams = Settings.System.getInt(mContentResolver, 3143c1d4166289ce016965d1147f7e8d37862ee347ecEric Laurent Settings.System.MODE_RINGER_STREAMS_AFFECTED, 3144c1d4166289ce016965d1147f7e8d37862ee347ecEric Laurent ((1 << AudioSystem.STREAM_RING)|(1 << AudioSystem.STREAM_NOTIFICATION)| 3145c1d4166289ce016965d1147f7e8d37862ee347ecEric Laurent (1 << AudioSystem.STREAM_SYSTEM)|(1 << AudioSystem.STREAM_SYSTEM_ENFORCED))); 3146c1d4166289ce016965d1147f7e8d37862ee347ecEric Laurent if (mVoiceCapable) { 3147c1d4166289ce016965d1147f7e8d37862ee347ecEric Laurent ringerModeAffectedStreams &= ~(1 << AudioSystem.STREAM_MUSIC); 3148c1d4166289ce016965d1147f7e8d37862ee347ecEric Laurent } else { 3149402f7f29634a9f68e7929be828a927a3e2f5efe9Eric Laurent ringerModeAffectedStreams |= (1 << AudioSystem.STREAM_MUSIC); 3150402f7f29634a9f68e7929be828a927a3e2f5efe9Eric Laurent } 3151a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent if (ringerModeAffectedStreams != mRingerModeAffectedStreams) { 3152a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent /* 3153a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent * Ensure all stream types that should be affected by ringer mode 3154a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent * are in the proper state. 3155a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent */ 3156a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent mRingerModeAffectedStreams = ringerModeAffectedStreams; 3157a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent setRingerModeInt(getRingerMode(), false); 3158a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent } 3159a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent } 3160b109615ebebd6f3b9ae789412279f576c3ace46bJason Parekh } 3161b109615ebebd6f3b9ae789412279f576c3ace46bJason Parekh } 3162a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent 31636bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent // must be called synchronized on mConnectedDevices 31644c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi private void makeA2dpDeviceAvailable(String address) { 31657847211fb4699bf6018e29d214a918ed6657319bEric Laurent // enable A2DP before notifying A2DP connection to avoid unecessary processing in 31667847211fb4699bf6018e29d214a918ed6657319bEric Laurent // audio policy manager 31677847211fb4699bf6018e29d214a918ed6657319bEric Laurent setBluetoothA2dpOnInt(true); 31684c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, 31694c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi AudioSystem.DEVICE_STATE_AVAILABLE, 31704c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi address); 31714c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi // Reset A2DP suspend state each time a new sink is connected 31724c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi AudioSystem.setParameters("A2dpSuspended=false"); 31734c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi mConnectedDevices.put( new Integer(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP), 31744c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi address); 31754c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi } 31764c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi 31779841818b9a0280abf59343c9e00a2976dbc084faMike Lockwood private void sendBecomingNoisyIntent() { 31789841818b9a0280abf59343c9e00a2976dbc084faMike Lockwood mContext.sendBroadcast(new Intent(AudioManager.ACTION_AUDIO_BECOMING_NOISY)); 31799841818b9a0280abf59343c9e00a2976dbc084faMike Lockwood } 31809841818b9a0280abf59343c9e00a2976dbc084faMike Lockwood 31816bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent // must be called synchronized on mConnectedDevices 31824c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi private void makeA2dpDeviceUnavailableNow(String address) { 31834c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, 31844c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi AudioSystem.DEVICE_STATE_UNAVAILABLE, 31854c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi address); 31864c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi mConnectedDevices.remove(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP); 31874c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi } 31884c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi 31896bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent // must be called synchronized on mConnectedDevices 31904c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi private void makeA2dpDeviceUnavailableLater(String address) { 31913b5912602bec6ccbe8eef8a576730b1565f0067cEric Laurent // prevent any activity on the A2DP audio output to avoid unwanted 31923b5912602bec6ccbe8eef8a576730b1565f0067cEric Laurent // reconnection of the sink. 31933b5912602bec6ccbe8eef8a576730b1565f0067cEric Laurent AudioSystem.setParameters("A2dpSuspended=true"); 31944c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi // the device will be made unavailable later, so consider it disconnected right away 31954c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi mConnectedDevices.remove(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP); 31964c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi // send the delayed message to make the device unavailable later 31974c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi Message msg = mAudioHandler.obtainMessage(MSG_BTA2DP_DOCK_TIMEOUT, address); 31984c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi mAudioHandler.sendMessageDelayed(msg, BTA2DP_DOCK_TIMEOUT_MILLIS); 31994c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi 32004c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi } 32014c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi 32026bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent // must be called synchronized on mConnectedDevices 3203a847ba4080675d395de725cfac5dfd9d5a993d4eJean-Michel Trivi private void cancelA2dpDeviceTimeout() { 32044c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi mAudioHandler.removeMessages(MSG_BTA2DP_DOCK_TIMEOUT); 32054c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi } 32064c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi 32076bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent // must be called synchronized on mConnectedDevices 3208a847ba4080675d395de725cfac5dfd9d5a993d4eJean-Michel Trivi private boolean hasScheduledA2dpDockTimeout() { 3209a847ba4080675d395de725cfac5dfd9d5a993d4eJean-Michel Trivi return mAudioHandler.hasMessages(MSG_BTA2DP_DOCK_TIMEOUT); 3210a847ba4080675d395de725cfac5dfd9d5a993d4eJean-Michel Trivi } 3211a847ba4080675d395de725cfac5dfd9d5a993d4eJean-Michel Trivi 3212b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent private void onSetA2dpConnectionState(BluetoothDevice btDevice, int state) 32136bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent { 32146bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent if (btDevice == null) { 32156bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent return; 32166bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent } 32176bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent String address = btDevice.getAddress(); 32186bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent if (!BluetoothAdapter.checkBluetoothAddress(address)) { 32196bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent address = ""; 32206bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent } 32216bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent synchronized (mConnectedDevices) { 32226bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent boolean isConnected = 32236bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent (mConnectedDevices.containsKey(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP) && 32246bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent mConnectedDevices.get(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP).equals(address)); 32256bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent 32266bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent if (isConnected && state != BluetoothProfile.STATE_CONNECTED) { 32276bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent if (btDevice.isBluetoothDock()) { 32286bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent if (state == BluetoothProfile.STATE_DISCONNECTED) { 32296bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent // introduction of a delay for transient disconnections of docks when 32306bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent // power is rapidly turned off/on, this message will be canceled if 32316bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent // we reconnect the dock under a preset delay 32326bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent makeA2dpDeviceUnavailableLater(address); 32336bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent // the next time isConnected is evaluated, it will be false for the dock 32346bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent } 32356bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent } else { 32366bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent makeA2dpDeviceUnavailableNow(address); 32376bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent } 3238632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn synchronized (mCurAudioRoutes) { 3239632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn if (mCurAudioRoutes.mBluetoothName != null) { 3240632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn mCurAudioRoutes.mBluetoothName = null; 3241632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn sendMsg(mAudioHandler, MSG_REPORT_NEW_ROUTES, 3242632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn SENDMSG_NOOP, 0, 0, null, 0); 3243632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn } 3244632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn } 32456bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent } else if (!isConnected && state == BluetoothProfile.STATE_CONNECTED) { 32466bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent if (btDevice.isBluetoothDock()) { 32476bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent // this could be a reconnection after a transient disconnection 32486bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent cancelA2dpDeviceTimeout(); 32496bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent mDockAddress = address; 32506bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent } else { 32516bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent // this could be a connection of another A2DP device before the timeout of 32526bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent // a dock: cancel the dock timeout, and make the dock unavailable now 32536bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent if(hasScheduledA2dpDockTimeout()) { 32546bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent cancelA2dpDeviceTimeout(); 32556bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent makeA2dpDeviceUnavailableNow(mDockAddress); 32566bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent } 32576bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent } 32586bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent makeA2dpDeviceAvailable(address); 3259632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn synchronized (mCurAudioRoutes) { 3260632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn String name = btDevice.getAliasName(); 3261632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn if (!TextUtils.equals(mCurAudioRoutes.mBluetoothName, name)) { 3262632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn mCurAudioRoutes.mBluetoothName = name; 3263632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn sendMsg(mAudioHandler, MSG_REPORT_NEW_ROUTES, 3264632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn SENDMSG_NOOP, 0, 0, null, 0); 3265632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn } 3266632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn } 32676bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent } 32686bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent } 32696bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent } 32706bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent 327159f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent private boolean handleDeviceConnection(boolean connected, int device, String params) { 327259f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent synchronized (mConnectedDevices) { 327359f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent boolean isConnected = (mConnectedDevices.containsKey(device) && 32749841818b9a0280abf59343c9e00a2976dbc084faMike Lockwood (params.isEmpty() || mConnectedDevices.get(device).equals(params))); 327559f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent 327659f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent if (isConnected && !connected) { 327759f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent AudioSystem.setDeviceConnectionState(device, 327859f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent AudioSystem.DEVICE_STATE_UNAVAILABLE, 32799841818b9a0280abf59343c9e00a2976dbc084faMike Lockwood mConnectedDevices.get(device)); 328059f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent mConnectedDevices.remove(device); 328159f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent return true; 328259f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent } else if (!isConnected && connected) { 328359f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent AudioSystem.setDeviceConnectionState(device, 328459f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent AudioSystem.DEVICE_STATE_AVAILABLE, 328559f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent params); 328659f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent mConnectedDevices.put(new Integer(device), params); 328759f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent return true; 328859f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent } 328959f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent } 329059f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent return false; 329159f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent } 329259f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent 3293b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent // Devices which removal triggers intent ACTION_AUDIO_BECOMING_NOISY. The intent is only 3294b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent // sent if none of these devices is connected. 3295b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent int mBecomingNoisyIntentDevices = 3296b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent AudioSystem.DEVICE_OUT_WIRED_HEADSET | AudioSystem.DEVICE_OUT_WIRED_HEADPHONE | 3297b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent AudioSystem.DEVICE_OUT_ALL_A2DP; 3298b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent 3299b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent // must be called before removing the device from mConnectedDevices 3300b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent private int checkSendBecomingNoisyIntent(int device, int state) { 3301b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent int delay = 0; 3302b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent if ((state == 0) && ((device & mBecomingNoisyIntentDevices) != 0)) { 3303b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent int devices = 0; 3304b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent for (int dev : mConnectedDevices.keySet()) { 3305b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent if ((dev & mBecomingNoisyIntentDevices) != 0) { 3306b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent devices |= dev; 3307b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent } 3308b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent } 3309b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent if (devices == device) { 3310b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent delay = 1000; 3311b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent sendBecomingNoisyIntent(); 3312b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent } 3313b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent } 3314b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent 3315b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent if (mAudioHandler.hasMessages(MSG_SET_A2DP_CONNECTION_STATE) || 3316b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent mAudioHandler.hasMessages(MSG_SET_WIRED_DEVICE_CONNECTION_STATE)) { 3317b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent delay = 1000; 3318b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent } 3319b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent return delay; 3320b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent } 3321b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent 3322b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent private void sendDeviceConnectionIntent(int device, int state, String name) 3323b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent { 3324b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent Intent intent = new Intent(); 3325b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent 3326b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent intent.putExtra("state", state); 3327b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent intent.putExtra("name", name); 3328b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY); 3329b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent 3330632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn int connType = 0; 3331632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn 3332b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent if (device == AudioSystem.DEVICE_OUT_WIRED_HEADSET) { 3333632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn connType = AudioRoutesInfo.MAIN_HEADSET; 3334b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent intent.setAction(Intent.ACTION_HEADSET_PLUG); 3335b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent intent.putExtra("microphone", 1); 3336b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent } else if (device == AudioSystem.DEVICE_OUT_WIRED_HEADPHONE) { 3337632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn connType = AudioRoutesInfo.MAIN_HEADPHONES; 3338b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent intent.setAction(Intent.ACTION_HEADSET_PLUG); 3339b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent intent.putExtra("microphone", 0); 3340b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent } else if (device == AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET) { 3341632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn connType = AudioRoutesInfo.MAIN_DOCK_SPEAKERS; 3342b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent intent.setAction(Intent.ACTION_ANALOG_AUDIO_DOCK_PLUG); 3343b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent } else if (device == AudioSystem.DEVICE_OUT_DGTL_DOCK_HEADSET) { 3344632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn connType = AudioRoutesInfo.MAIN_DOCK_SPEAKERS; 3345b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent intent.setAction(Intent.ACTION_DIGITAL_AUDIO_DOCK_PLUG); 3346b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent } else if (device == AudioSystem.DEVICE_OUT_AUX_DIGITAL) { 3347632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn connType = AudioRoutesInfo.MAIN_HDMI; 3348b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent intent.setAction(Intent.ACTION_HDMI_AUDIO_PLUG); 3349b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent } 3350b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent 3351632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn synchronized (mCurAudioRoutes) { 3352632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn if (connType != 0) { 3353632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn int newConn = mCurAudioRoutes.mMainType; 3354632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn if (state != 0) { 3355632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn newConn |= connType; 3356632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn } else { 3357632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn newConn &= ~connType; 3358632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn } 3359632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn if (newConn != mCurAudioRoutes.mMainType) { 3360632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn mCurAudioRoutes.mMainType = newConn; 3361632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn sendMsg(mAudioHandler, MSG_REPORT_NEW_ROUTES, 3362632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn SENDMSG_NOOP, 0, 0, null, 0); 3363632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn } 3364632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn } 3365632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn } 3366632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn 3367b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent ActivityManagerNative.broadcastStickyIntent(intent, null); 3368b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent } 3369b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent 3370b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent private void onSetWiredDeviceConnectionState(int device, int state, String name) 3371b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent { 3372b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent synchronized (mConnectedDevices) { 3373b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent if ((state == 0) && ((device == AudioSystem.DEVICE_OUT_WIRED_HEADSET) || 3374b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent (device == AudioSystem.DEVICE_OUT_WIRED_HEADPHONE))) { 3375b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent setBluetoothA2dpOnInt(true); 3376b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent } 3377b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent handleDeviceConnection((state == 1), device, ""); 3378b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent if ((state != 0) && ((device == AudioSystem.DEVICE_OUT_WIRED_HEADSET) || 3379b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent (device == AudioSystem.DEVICE_OUT_WIRED_HEADPHONE))) { 3380b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent setBluetoothA2dpOnInt(false); 3381b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent } 3382b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent sendDeviceConnectionIntent(device, state, name); 3383b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent } 3384b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent } 3385b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent 3386a847ba4080675d395de725cfac5dfd9d5a993d4eJean-Michel Trivi /* cache of the address of the last dock the device was connected to */ 3387a847ba4080675d395de725cfac5dfd9d5a993d4eJean-Michel Trivi private String mDockAddress; 3388a847ba4080675d395de725cfac5dfd9d5a993d4eJean-Michel Trivi 3389a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent /** 3390a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent * Receiver for misc intent broadcasts the Phone app cares about. 3391a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent */ 3392a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent private class AudioServiceBroadcastReceiver extends BroadcastReceiver { 3393a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent @Override 3394a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent public void onReceive(Context context, Intent intent) { 3395a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent String action = intent.getAction(); 339659f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent int device; 339759f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent int state; 3398a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent 3399758559e6b7e310cf46cc269437f44decd58d68d6Jean-Michel Trivi if (action.equals(Intent.ACTION_DOCK_EVENT)) { 3400758559e6b7e310cf46cc269437f44decd58d68d6Jean-Michel Trivi int dockState = intent.getIntExtra(Intent.EXTRA_DOCK_STATE, 3401758559e6b7e310cf46cc269437f44decd58d68d6Jean-Michel Trivi Intent.EXTRA_DOCK_STATE_UNDOCKED); 3402758559e6b7e310cf46cc269437f44decd58d68d6Jean-Michel Trivi int config; 3403758559e6b7e310cf46cc269437f44decd58d68d6Jean-Michel Trivi switch (dockState) { 3404758559e6b7e310cf46cc269437f44decd58d68d6Jean-Michel Trivi case Intent.EXTRA_DOCK_STATE_DESK: 3405758559e6b7e310cf46cc269437f44decd58d68d6Jean-Michel Trivi config = AudioSystem.FORCE_BT_DESK_DOCK; 3406758559e6b7e310cf46cc269437f44decd58d68d6Jean-Michel Trivi break; 3407758559e6b7e310cf46cc269437f44decd58d68d6Jean-Michel Trivi case Intent.EXTRA_DOCK_STATE_CAR: 3408758559e6b7e310cf46cc269437f44decd58d68d6Jean-Michel Trivi config = AudioSystem.FORCE_BT_CAR_DOCK; 3409758559e6b7e310cf46cc269437f44decd58d68d6Jean-Michel Trivi break; 341021e941bf43362ddc6639a9f2d0828053360f53d7Praveen Bharathi case Intent.EXTRA_DOCK_STATE_LE_DESK: 341121e941bf43362ddc6639a9f2d0828053360f53d7Praveen Bharathi config = AudioSystem.FORCE_ANALOG_DOCK; 341221e941bf43362ddc6639a9f2d0828053360f53d7Praveen Bharathi break; 341321e941bf43362ddc6639a9f2d0828053360f53d7Praveen Bharathi case Intent.EXTRA_DOCK_STATE_HE_DESK: 341421e941bf43362ddc6639a9f2d0828053360f53d7Praveen Bharathi config = AudioSystem.FORCE_DIGITAL_DOCK; 341521e941bf43362ddc6639a9f2d0828053360f53d7Praveen Bharathi break; 3416758559e6b7e310cf46cc269437f44decd58d68d6Jean-Michel Trivi case Intent.EXTRA_DOCK_STATE_UNDOCKED: 3417758559e6b7e310cf46cc269437f44decd58d68d6Jean-Michel Trivi default: 3418758559e6b7e310cf46cc269437f44decd58d68d6Jean-Michel Trivi config = AudioSystem.FORCE_NONE; 3419758559e6b7e310cf46cc269437f44decd58d68d6Jean-Michel Trivi } 3420758559e6b7e310cf46cc269437f44decd58d68d6Jean-Michel Trivi AudioSystem.setForceUse(AudioSystem.FOR_DOCK, config); 342182aa7f017daaaeb96c13e6e3491d5037ab471085Jaikumar Ganesh } else if (action.equals(BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED)) { 342259f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent state = intent.getIntExtra(BluetoothProfile.EXTRA_STATE, 342382aa7f017daaaeb96c13e6e3491d5037ab471085Jaikumar Ganesh BluetoothProfile.STATE_DISCONNECTED); 342459f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent device = AudioSystem.DEVICE_OUT_BLUETOOTH_SCO; 3425a56d1c72190462aa9e377906583eceb58e0efcddNick Pelly String address = null; 3426dca56b9432e2cc851d1a58920071fed2e1e3d142Eric Laurent 3427dca56b9432e2cc851d1a58920071fed2e1e3d142Eric Laurent BluetoothDevice btDevice = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); 3428dca56b9432e2cc851d1a58920071fed2e1e3d142Eric Laurent if (btDevice == null) { 3429dca56b9432e2cc851d1a58920071fed2e1e3d142Eric Laurent return; 3430dca56b9432e2cc851d1a58920071fed2e1e3d142Eric Laurent } 3431dca56b9432e2cc851d1a58920071fed2e1e3d142Eric Laurent 3432dca56b9432e2cc851d1a58920071fed2e1e3d142Eric Laurent address = btDevice.getAddress(); 3433dca56b9432e2cc851d1a58920071fed2e1e3d142Eric Laurent BluetoothClass btClass = btDevice.getBluetoothClass(); 3434dca56b9432e2cc851d1a58920071fed2e1e3d142Eric Laurent if (btClass != null) { 3435dca56b9432e2cc851d1a58920071fed2e1e3d142Eric Laurent switch (btClass.getDeviceClass()) { 3436dca56b9432e2cc851d1a58920071fed2e1e3d142Eric Laurent case BluetoothClass.Device.AUDIO_VIDEO_WEARABLE_HEADSET: 3437dca56b9432e2cc851d1a58920071fed2e1e3d142Eric Laurent case BluetoothClass.Device.AUDIO_VIDEO_HANDSFREE: 3438dca56b9432e2cc851d1a58920071fed2e1e3d142Eric Laurent device = AudioSystem.DEVICE_OUT_BLUETOOTH_SCO_HEADSET; 3439dca56b9432e2cc851d1a58920071fed2e1e3d142Eric Laurent break; 3440dca56b9432e2cc851d1a58920071fed2e1e3d142Eric Laurent case BluetoothClass.Device.AUDIO_VIDEO_CAR_AUDIO: 3441dca56b9432e2cc851d1a58920071fed2e1e3d142Eric Laurent device = AudioSystem.DEVICE_OUT_BLUETOOTH_SCO_CARKIT; 3442dca56b9432e2cc851d1a58920071fed2e1e3d142Eric Laurent break; 3443d5603c126acdd94d9f7400bb1d04188020a425b4Eric Laurent } 3444d5603c126acdd94d9f7400bb1d04188020a425b4Eric Laurent } 3445d5603c126acdd94d9f7400bb1d04188020a425b4Eric Laurent 3446dca56b9432e2cc851d1a58920071fed2e1e3d142Eric Laurent if (!BluetoothAdapter.checkBluetoothAddress(address)) { 3447dca56b9432e2cc851d1a58920071fed2e1e3d142Eric Laurent address = ""; 3448dca56b9432e2cc851d1a58920071fed2e1e3d142Eric Laurent } 3449d5603c126acdd94d9f7400bb1d04188020a425b4Eric Laurent 345059f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent boolean connected = (state == BluetoothProfile.STATE_CONNECTED); 345159f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent if (handleDeviceConnection(connected, device, address)) { 34526bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent synchronized (mScoClients) { 345359f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent if (connected) { 345459f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent mBluetoothHeadsetDevice = btDevice; 345559f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent } else { 34566bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent mBluetoothHeadsetDevice = null; 34576bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent resetBluetoothSco(); 34586bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent } 345962ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent } 3460a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent } 346159f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent } else if (action.equals(Intent.ACTION_USB_AUDIO_ACCESSORY_PLUG) || 346259f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent action.equals(Intent.ACTION_USB_AUDIO_DEVICE_PLUG)) { 346359f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent state = intent.getIntExtra("state", 0); 346459f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent int alsaCard = intent.getIntExtra("card", -1); 346559f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent int alsaDevice = intent.getIntExtra("device", -1); 34669841818b9a0280abf59343c9e00a2976dbc084faMike Lockwood String params = (alsaCard == -1 && alsaDevice == -1 ? "" 34679841818b9a0280abf59343c9e00a2976dbc084faMike Lockwood : "card=" + alsaCard + ";device=" + alsaDevice); 346859f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent device = action.equals(Intent.ACTION_USB_AUDIO_ACCESSORY_PLUG) ? 346959f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent AudioSystem.DEVICE_OUT_USB_ACCESSORY : AudioSystem.DEVICE_OUT_USB_DEVICE; 347059f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent Log.v(TAG, "Broadcast Receiver: Got " 347159f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent + (action.equals(Intent.ACTION_USB_AUDIO_ACCESSORY_PLUG) ? 347259f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent "ACTION_USB_AUDIO_ACCESSORY_PLUG" : "ACTION_USB_AUDIO_DEVICE_PLUG") 347359f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent + ", state = " + state + ", card: " + alsaCard + ", device: " + alsaDevice); 347459f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent handleDeviceConnection((state == 1), device, params); 34753def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent } else if (action.equals(BluetoothHeadset.ACTION_AUDIO_STATE_CHANGED)) { 347662ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent boolean broadcast = false; 347759f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent int scoAudioState = AudioManager.SCO_AUDIO_STATE_ERROR; 34783def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent synchronized (mScoClients) { 347962ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent int btState = intent.getIntExtra(BluetoothProfile.EXTRA_STATE, -1); 3480dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent // broadcast intent if the connection was initated by AudioService 3481dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent if (!mScoClients.isEmpty() && 3482dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent (mScoAudioState == SCO_STATE_ACTIVE_INTERNAL || 3483dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent mScoAudioState == SCO_STATE_ACTIVATE_REQ || 3484dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent mScoAudioState == SCO_STATE_DEACTIVATE_REQ)) { 348562ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent broadcast = true; 348662ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent } 348762ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent switch (btState) { 348862ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent case BluetoothHeadset.STATE_AUDIO_CONNECTED: 348959f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent scoAudioState = AudioManager.SCO_AUDIO_STATE_CONNECTED; 3490dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent if (mScoAudioState != SCO_STATE_ACTIVE_INTERNAL && 3491dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent mScoAudioState != SCO_STATE_DEACTIVATE_REQ && 3492dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent mScoAudioState != SCO_STATE_DEACTIVATE_EXT_REQ) { 349362ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent mScoAudioState = SCO_STATE_ACTIVE_EXTERNAL; 34943def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent } 349562ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent break; 349662ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent case BluetoothHeadset.STATE_AUDIO_DISCONNECTED: 349759f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent scoAudioState = AudioManager.SCO_AUDIO_STATE_DISCONNECTED; 349862ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent mScoAudioState = SCO_STATE_INACTIVE; 3499d7454be47f4111c0478a502353e11dea401378bdEric Laurent clearAllScoClients(0, false); 350062ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent break; 350162ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent case BluetoothHeadset.STATE_AUDIO_CONNECTING: 3502dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent if (mScoAudioState != SCO_STATE_ACTIVE_INTERNAL && 3503dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent mScoAudioState != SCO_STATE_DEACTIVATE_REQ && 3504dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent mScoAudioState != SCO_STATE_DEACTIVATE_EXT_REQ) { 350562ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent mScoAudioState = SCO_STATE_ACTIVE_EXTERNAL; 35063def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent } 350762ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent default: 350862ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent // do not broadcast CONNECTING or invalid state 350962ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent broadcast = false; 351062ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent break; 35113def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent } 35123def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent } 351362ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent if (broadcast) { 351459f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent broadcastScoConnectionState(scoAudioState); 3515dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent //FIXME: this is to maintain compatibility with deprecated intent 3516dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent // AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED. Remove when appropriate. 351762ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent Intent newIntent = new Intent(AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED); 351859f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent newIntent.putExtra(AudioManager.EXTRA_SCO_AUDIO_STATE, scoAudioState); 351962ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent mContext.sendStickyBroadcast(newIntent); 352062ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent } 352162ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent } else if (action.equals(Intent.ACTION_BOOT_COMPLETED)) { 3522a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent mBootCompleted = true; 3523afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent sendMsg(mAudioHandler, MSG_LOAD_SOUND_EFFECTS, SENDMSG_NOOP, 3524117b7bb5b5a4457711f59bde3dcc83d8f111c524Eric Laurent 0, 0, null, 0); 3525dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent 35266243edd818b84adfbe712d5d233d6414b33653acAmith Yamasani mKeyguardManager = 35276243edd818b84adfbe712d5d233d6414b33653acAmith Yamasani (KeyguardManager) mContext.getSystemService(Context.KEYGUARD_SERVICE); 3528dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent mScoConnectionState = AudioManager.SCO_AUDIO_STATE_ERROR; 3529dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent resetBluetoothSco(); 3530dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent getBluetoothHeadset(); 3531dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent //FIXME: this is to maintain compatibility with deprecated intent 3532dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent // AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED. Remove when appropriate. 353362ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent Intent newIntent = new Intent(AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED); 353462ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent newIntent.putExtra(AudioManager.EXTRA_SCO_AUDIO_STATE, 353562ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent AudioManager.SCO_AUDIO_STATE_DISCONNECTED); 353662ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent mContext.sendStickyBroadcast(newIntent); 35376bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent 35386bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter(); 35396bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent if (adapter != null) { 35406bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent adapter.getProfileProxy(mContext, mBluetoothProfileServiceListener, 35416bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent BluetoothProfile.A2DP); 35426bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent } 3543d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi } else if (action.equals(Intent.ACTION_PACKAGE_REMOVED)) { 3544d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi if (!intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) { 3545d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi // a package is being removed, not replaced 3546d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi String packageName = intent.getData().getSchemeSpecificPart(); 3547d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi if (packageName != null) { 3548d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi removeMediaButtonReceiverForPackage(packageName); 3549d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi } 3550d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi } 3551950e8cb40a6d826af4cc2eef9d3908c1b70486e6Eric Laurent } else if (action.equals(Intent.ACTION_SCREEN_ON)) { 3552950e8cb40a6d826af4cc2eef9d3908c1b70486e6Eric Laurent AudioSystem.setParameters("screen_state=on"); 3553950e8cb40a6d826af4cc2eef9d3908c1b70486e6Eric Laurent } else if (action.equals(Intent.ACTION_SCREEN_OFF)) { 3554950e8cb40a6d826af4cc2eef9d3908c1b70486e6Eric Laurent AudioSystem.setParameters("screen_state=off"); 3555f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi } else if (action.equalsIgnoreCase(Intent.ACTION_CONFIGURATION_CHANGED)) { 3556f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi handleConfigurationChanged(context); 3557a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent } 3558a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent } 3559a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent } 3560d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi 3561d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi //========================================================================================== 3562d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi // AudioFocus 3563d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi //========================================================================================== 3564b4bccb6d8df16a2c5235cead187156bc721cf074Jean-Michel Trivi 3565b4bccb6d8df16a2c5235cead187156bc721cf074Jean-Michel Trivi /* constant to identify focus stack entry that is used to hold the focus while the phone 35664dd3674e517051f130fef36d2eb201c68ff61094Jean-Michel Trivi * is ringing or during a call. Used by com.android.internal.telephony.CallManager when 35674dd3674e517051f130fef36d2eb201c68ff61094Jean-Michel Trivi * entering and exiting calls. 3568e5e1e870fdb35f5291790e6d178bde7126f6fe35Jean-Michel Trivi */ 35694dd3674e517051f130fef36d2eb201c68ff61094Jean-Michel Trivi public final static String IN_VOICE_COMM_FOCUS_ID = "AudioFocus_For_Phone_Ring_And_Calls"; 3570e5e1e870fdb35f5291790e6d178bde7126f6fe35Jean-Michel Trivi 3571392a2bbb52688ebd25768a7784d9edca7f498110Jean-Michel Trivi private final static Object mAudioFocusLock = new Object(); 3572392a2bbb52688ebd25768a7784d9edca7f498110Jean-Michel Trivi 3573e73131a68408a0495ba96a4d5a60799ba293c176Jean-Michel Trivi private final static Object mRingingLock = new Object(); 3574e73131a68408a0495ba96a4d5a60799ba293c176Jean-Michel Trivi 3575b4bccb6d8df16a2c5235cead187156bc721cf074Jean-Michel Trivi private PhoneStateListener mPhoneStateListener = new PhoneStateListener() { 3576b4bccb6d8df16a2c5235cead187156bc721cf074Jean-Michel Trivi @Override 3577b4bccb6d8df16a2c5235cead187156bc721cf074Jean-Michel Trivi public void onCallStateChanged(int state, String incomingNumber) { 3578b4bccb6d8df16a2c5235cead187156bc721cf074Jean-Michel Trivi if (state == TelephonyManager.CALL_STATE_RINGING) { 3579b4bccb6d8df16a2c5235cead187156bc721cf074Jean-Michel Trivi //Log.v(TAG, " CALL_STATE_RINGING"); 3580e73131a68408a0495ba96a4d5a60799ba293c176Jean-Michel Trivi synchronized(mRingingLock) { 3581e73131a68408a0495ba96a4d5a60799ba293c176Jean-Michel Trivi mIsRinging = true; 3582e73131a68408a0495ba96a4d5a60799ba293c176Jean-Michel Trivi } 35832ade576148fe33c5ff6098d30ccfbcf28df70e8eJean-Michel Trivi } else if ((state == TelephonyManager.CALL_STATE_OFFHOOK) 35842ade576148fe33c5ff6098d30ccfbcf28df70e8eJean-Michel Trivi || (state == TelephonyManager.CALL_STATE_IDLE)) { 3585e73131a68408a0495ba96a4d5a60799ba293c176Jean-Michel Trivi synchronized(mRingingLock) { 3586e73131a68408a0495ba96a4d5a60799ba293c176Jean-Michel Trivi mIsRinging = false; 3587e73131a68408a0495ba96a4d5a60799ba293c176Jean-Michel Trivi } 3588e5e1e870fdb35f5291790e6d178bde7126f6fe35Jean-Michel Trivi } 3589e5e1e870fdb35f5291790e6d178bde7126f6fe35Jean-Michel Trivi } 3590b4bccb6d8df16a2c5235cead187156bc721cf074Jean-Michel Trivi }; 3591e5e1e870fdb35f5291790e6d178bde7126f6fe35Jean-Michel Trivi 3592e5e1e870fdb35f5291790e6d178bde7126f6fe35Jean-Michel Trivi private void notifyTopOfAudioFocusStack() { 3593e5e1e870fdb35f5291790e6d178bde7126f6fe35Jean-Michel Trivi // notify the top of the stack it gained focus 3594e5e1e870fdb35f5291790e6d178bde7126f6fe35Jean-Michel Trivi if (!mFocusStack.empty() && (mFocusStack.peek().mFocusDispatcher != null)) { 3595e5e1e870fdb35f5291790e6d178bde7126f6fe35Jean-Michel Trivi if (canReassignAudioFocus()) { 3596e5e1e870fdb35f5291790e6d178bde7126f6fe35Jean-Michel Trivi try { 3597e5e1e870fdb35f5291790e6d178bde7126f6fe35Jean-Michel Trivi mFocusStack.peek().mFocusDispatcher.dispatchAudioFocusChange( 3598e5e1e870fdb35f5291790e6d178bde7126f6fe35Jean-Michel Trivi AudioManager.AUDIOFOCUS_GAIN, mFocusStack.peek().mClientId); 3599e5e1e870fdb35f5291790e6d178bde7126f6fe35Jean-Michel Trivi } catch (RemoteException e) { 3600e5e1e870fdb35f5291790e6d178bde7126f6fe35Jean-Michel Trivi Log.e(TAG, "Failure to signal gain of audio control focus due to "+ e); 3601e5e1e870fdb35f5291790e6d178bde7126f6fe35Jean-Michel Trivi e.printStackTrace(); 3602e5e1e870fdb35f5291790e6d178bde7126f6fe35Jean-Michel Trivi } 3603e5e1e870fdb35f5291790e6d178bde7126f6fe35Jean-Michel Trivi } 3604e5e1e870fdb35f5291790e6d178bde7126f6fe35Jean-Michel Trivi } 3605e5e1e870fdb35f5291790e6d178bde7126f6fe35Jean-Michel Trivi } 3606e5e1e870fdb35f5291790e6d178bde7126f6fe35Jean-Michel Trivi 3607d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi private static class FocusStackEntry { 3608d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi public int mStreamType = -1;// no stream type 3609d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi public IAudioFocusDispatcher mFocusDispatcher = null; 3610d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi public IBinder mSourceRef = null; 3611d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi public String mClientId; 3612078fd47e91d495175927d1a4a8b9aad039a7ba4eJean-Michel Trivi public int mFocusChangeType; 3613061214bb71a4a4211e670001226c68f5e8036b84Jean-Michel Trivi public AudioFocusDeathHandler mHandler; 36148f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi public String mPackageName; 36158f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi public int mCallingUid; 3616d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi 3617d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi public FocusStackEntry() { 3618d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi } 3619d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi 36208f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi public FocusStackEntry(int streamType, int duration, 3621061214bb71a4a4211e670001226c68f5e8036b84Jean-Michel Trivi IAudioFocusDispatcher afl, IBinder source, String id, AudioFocusDeathHandler hdlr, 3622061214bb71a4a4211e670001226c68f5e8036b84Jean-Michel Trivi String pn, int uid) { 3623d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi mStreamType = streamType; 3624d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi mFocusDispatcher = afl; 3625d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi mSourceRef = source; 3626d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi mClientId = id; 3627078fd47e91d495175927d1a4a8b9aad039a7ba4eJean-Michel Trivi mFocusChangeType = duration; 3628061214bb71a4a4211e670001226c68f5e8036b84Jean-Michel Trivi mHandler = hdlr; 36298f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi mPackageName = pn; 36308f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi mCallingUid = uid; 3631d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi } 3632061214bb71a4a4211e670001226c68f5e8036b84Jean-Michel Trivi 3633e7edc868538e83152e7bc35c830fee0d629baefcJean-Michel Trivi public void unlinkToDeath() { 3634e7edc868538e83152e7bc35c830fee0d629baefcJean-Michel Trivi try { 3635e7edc868538e83152e7bc35c830fee0d629baefcJean-Michel Trivi if (mSourceRef != null && mHandler != null) { 3636e7edc868538e83152e7bc35c830fee0d629baefcJean-Michel Trivi mSourceRef.unlinkToDeath(mHandler, 0); 3637e7edc868538e83152e7bc35c830fee0d629baefcJean-Michel Trivi mHandler = null; 3638e7edc868538e83152e7bc35c830fee0d629baefcJean-Michel Trivi } 3639e7edc868538e83152e7bc35c830fee0d629baefcJean-Michel Trivi } catch (java.util.NoSuchElementException e) { 3640e7edc868538e83152e7bc35c830fee0d629baefcJean-Michel Trivi Log.e(TAG, "Encountered " + e + " in FocusStackEntry.unlinkToDeath()"); 3641061214bb71a4a4211e670001226c68f5e8036b84Jean-Michel Trivi } 3642061214bb71a4a4211e670001226c68f5e8036b84Jean-Michel Trivi } 3643de1f065be109e1c313d8330c8e34210fedaac74eJean-Michel Trivi 3644de1f065be109e1c313d8330c8e34210fedaac74eJean-Michel Trivi @Override 3645de1f065be109e1c313d8330c8e34210fedaac74eJean-Michel Trivi protected void finalize() throws Throwable { 3646e7edc868538e83152e7bc35c830fee0d629baefcJean-Michel Trivi unlinkToDeath(); // unlink exception handled inside method 3647e7edc868538e83152e7bc35c830fee0d629baefcJean-Michel Trivi super.finalize(); 3648de1f065be109e1c313d8330c8e34210fedaac74eJean-Michel Trivi } 3649d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi } 3650d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi 365130c918ce7fbe171944b28fc91b3f22b3d631872dGlenn Kasten private final Stack<FocusStackEntry> mFocusStack = new Stack<FocusStackEntry>(); 3652d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi 3653d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi /** 3654d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi * Helper function: 3655d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi * Display in the log the current entries in the audio focus stack 3656d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi */ 3657d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi private void dumpFocusStack(PrintWriter pw) { 3658b4bccb6d8df16a2c5235cead187156bc721cf074Jean-Michel Trivi pw.println("\nAudio Focus stack entries:"); 3659392a2bbb52688ebd25768a7784d9edca7f498110Jean-Michel Trivi synchronized(mAudioFocusLock) { 3660d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi Iterator<FocusStackEntry> stackIterator = mFocusStack.iterator(); 3661d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi while(stackIterator.hasNext()) { 3662d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi FocusStackEntry fse = stackIterator.next(); 3663d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi pw.println(" source:" + fse.mSourceRef + " -- client: " + fse.mClientId 36648f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi + " -- duration: " + fse.mFocusChangeType 36658f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi + " -- uid: " + fse.mCallingUid); 3666d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi } 3667d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi } 3668d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi } 3669d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi 3670d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi /** 3671d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi * Helper function: 36728f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi * Called synchronized on mAudioFocusLock 3673d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi * Remove a focus listener from the focus stack. 3674d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi * @param focusListenerToRemove the focus listener 3675d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi * @param signal if true and the listener was at the top of the focus stack, i.e. it was holding 3676d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi * focus, notify the next item in the stack it gained focus. 3677d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi */ 3678d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi private void removeFocusStackEntry(String clientToRemove, boolean signal) { 3679e7edc868538e83152e7bc35c830fee0d629baefcJean-Michel Trivi // is the current top of the focus stack abandoning focus? (because of request, not death) 3680d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi if (!mFocusStack.empty() && mFocusStack.peek().mClientId.equals(clientToRemove)) 3681d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi { 3682d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi //Log.i(TAG, " removeFocusStackEntry() removing top of stack"); 3683e7edc868538e83152e7bc35c830fee0d629baefcJean-Michel Trivi FocusStackEntry fse = mFocusStack.pop(); 3684e7edc868538e83152e7bc35c830fee0d629baefcJean-Michel Trivi fse.unlinkToDeath(); 3685d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi if (signal) { 3686d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi // notify the new top of the stack it gained focus 3687e5e1e870fdb35f5291790e6d178bde7126f6fe35Jean-Michel Trivi notifyTopOfAudioFocusStack(); 36888f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi // there's a new top of the stack, let the remote control know 36898f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi synchronized(mRCStack) { 3690b716f0b7b2d8e4b045843fc6a7004910eb344c19Jean-Michel Trivi checkUpdateRemoteControlDisplay_syncAfRcs(RC_INFO_ALL); 36918f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi } 3692d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi } 3693d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi } else { 3694d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi // focus is abandoned by a client that's not at the top of the stack, 3695d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi // no need to update focus. 3696d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi Iterator<FocusStackEntry> stackIterator = mFocusStack.iterator(); 3697d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi while(stackIterator.hasNext()) { 3698d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi FocusStackEntry fse = (FocusStackEntry)stackIterator.next(); 3699d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi if(fse.mClientId.equals(clientToRemove)) { 3700d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi Log.i(TAG, " AudioFocus abandonAudioFocus(): removing entry for " 3701d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi + fse.mClientId); 370272843377d50a8f95cceaf33d316ab68d9b47f2ebJean-Michel Trivi stackIterator.remove(); 3703e7edc868538e83152e7bc35c830fee0d629baefcJean-Michel Trivi fse.unlinkToDeath(); 3704d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi } 3705d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi } 3706d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi } 3707d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi } 3708d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi 3709d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi /** 3710d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi * Helper function: 37118f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi * Called synchronized on mAudioFocusLock 3712e7edc868538e83152e7bc35c830fee0d629baefcJean-Michel Trivi * Remove focus listeners from the focus stack for a particular client when it has died. 3713d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi */ 3714d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi private void removeFocusStackEntryForClient(IBinder cb) { 3715e5e1e870fdb35f5291790e6d178bde7126f6fe35Jean-Michel Trivi // is the owner of the audio focus part of the client to remove? 3716e5e1e870fdb35f5291790e6d178bde7126f6fe35Jean-Michel Trivi boolean isTopOfStackForClientToRemove = !mFocusStack.isEmpty() && 3717e5e1e870fdb35f5291790e6d178bde7126f6fe35Jean-Michel Trivi mFocusStack.peek().mSourceRef.equals(cb); 3718d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi Iterator<FocusStackEntry> stackIterator = mFocusStack.iterator(); 3719d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi while(stackIterator.hasNext()) { 3720d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi FocusStackEntry fse = (FocusStackEntry)stackIterator.next(); 3721d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi if(fse.mSourceRef.equals(cb)) { 3722d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi Log.i(TAG, " AudioFocus abandonAudioFocus(): removing entry for " 3723d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi + fse.mClientId); 372472843377d50a8f95cceaf33d316ab68d9b47f2ebJean-Michel Trivi stackIterator.remove(); 3725e7edc868538e83152e7bc35c830fee0d629baefcJean-Michel Trivi // the client just died, no need to unlink to its death 3726d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi } 3727d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi } 3728e5e1e870fdb35f5291790e6d178bde7126f6fe35Jean-Michel Trivi if (isTopOfStackForClientToRemove) { 3729e5e1e870fdb35f5291790e6d178bde7126f6fe35Jean-Michel Trivi // we removed an entry at the top of the stack: 3730e5e1e870fdb35f5291790e6d178bde7126f6fe35Jean-Michel Trivi // notify the new top of the stack it gained focus. 3731e5e1e870fdb35f5291790e6d178bde7126f6fe35Jean-Michel Trivi notifyTopOfAudioFocusStack(); 37328f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi // there's a new top of the stack, let the remote control know 37338f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi synchronized(mRCStack) { 3734b716f0b7b2d8e4b045843fc6a7004910eb344c19Jean-Michel Trivi checkUpdateRemoteControlDisplay_syncAfRcs(RC_INFO_ALL); 37358f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi } 3736e5e1e870fdb35f5291790e6d178bde7126f6fe35Jean-Michel Trivi } 3737d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi } 3738d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi 3739d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi /** 3740d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi * Helper function: 3741d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi * Returns true if the system is in a state where the focus can be reevaluated, false otherwise. 3742d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi */ 3743d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi private boolean canReassignAudioFocus() { 3744b4bccb6d8df16a2c5235cead187156bc721cf074Jean-Michel Trivi // focus requests are rejected during a phone call or when the phone is ringing 3745b4bccb6d8df16a2c5235cead187156bc721cf074Jean-Michel Trivi // this is equivalent to IN_VOICE_COMM_FOCUS_ID having the focus 3746b4bccb6d8df16a2c5235cead187156bc721cf074Jean-Michel Trivi if (!mFocusStack.isEmpty() && IN_VOICE_COMM_FOCUS_ID.equals(mFocusStack.peek().mClientId)) { 3747d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi return false; 3748d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi } 3749d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi return true; 3750d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi } 3751d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi 3752d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi /** 3753d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi * Inner class to monitor audio focus client deaths, and remove them from the audio focus 3754d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi * stack if necessary. 3755d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi */ 3756d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi private class AudioFocusDeathHandler implements IBinder.DeathRecipient { 3757d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi private IBinder mCb; // To be notified of client's death 3758d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi 3759d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi AudioFocusDeathHandler(IBinder cb) { 3760d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi mCb = cb; 3761d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi } 3762d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi 3763d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi public void binderDied() { 3764392a2bbb52688ebd25768a7784d9edca7f498110Jean-Michel Trivi synchronized(mAudioFocusLock) { 3765d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi Log.w(TAG, " AudioFocus audio focus client died"); 3766d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi removeFocusStackEntryForClient(mCb); 3767d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi } 3768d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi } 3769d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi 3770d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi public IBinder getBinder() { 3771d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi return mCb; 3772d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi } 3773d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi } 3774d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi 3775d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi 3776d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi /** @see AudioManager#requestAudioFocus(IAudioFocusDispatcher, int, int) */ 3777078fd47e91d495175927d1a4a8b9aad039a7ba4eJean-Michel Trivi public int requestAudioFocus(int mainStreamType, int focusChangeHint, IBinder cb, 37788f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi IAudioFocusDispatcher fd, String clientId, String callingPackageName) { 3779d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi Log.i(TAG, " AudioFocus requestAudioFocus() from " + clientId); 3780d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi // the main stream type for the audio focus request is currently not used. It may 3781d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi // potentially be used to handle multiple stream type-dependent audio focuses. 3782d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi 3783382f4e6ea4dcf39105b36364582ed01642daa93cJean-Michel Trivi // we need a valid binder callback for clients 3784382f4e6ea4dcf39105b36364582ed01642daa93cJean-Michel Trivi if (!cb.pingBinder()) { 3785382f4e6ea4dcf39105b36364582ed01642daa93cJean-Michel Trivi Log.e(TAG, " AudioFocus DOA client for requestAudioFocus(), aborting."); 3786d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi return AudioManager.AUDIOFOCUS_REQUEST_FAILED; 3787d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi } 3788d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi 3789392a2bbb52688ebd25768a7784d9edca7f498110Jean-Michel Trivi synchronized(mAudioFocusLock) { 3790392a2bbb52688ebd25768a7784d9edca7f498110Jean-Michel Trivi if (!canReassignAudioFocus()) { 3791392a2bbb52688ebd25768a7784d9edca7f498110Jean-Michel Trivi return AudioManager.AUDIOFOCUS_REQUEST_FAILED; 3792392a2bbb52688ebd25768a7784d9edca7f498110Jean-Michel Trivi } 3793d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi 3794baf674eedd5ecff9da0cf8cabe9868f7699b1695Jean-Michel Trivi // handle the potential premature death of the new holder of the focus 3795baf674eedd5ecff9da0cf8cabe9868f7699b1695Jean-Michel Trivi // (premature death == death before abandoning focus) 3796baf674eedd5ecff9da0cf8cabe9868f7699b1695Jean-Michel Trivi // Register for client death notification 3797baf674eedd5ecff9da0cf8cabe9868f7699b1695Jean-Michel Trivi AudioFocusDeathHandler afdh = new AudioFocusDeathHandler(cb); 3798baf674eedd5ecff9da0cf8cabe9868f7699b1695Jean-Michel Trivi try { 3799baf674eedd5ecff9da0cf8cabe9868f7699b1695Jean-Michel Trivi cb.linkToDeath(afdh, 0); 3800baf674eedd5ecff9da0cf8cabe9868f7699b1695Jean-Michel Trivi } catch (RemoteException e) { 3801baf674eedd5ecff9da0cf8cabe9868f7699b1695Jean-Michel Trivi // client has already died! 3802baf674eedd5ecff9da0cf8cabe9868f7699b1695Jean-Michel Trivi Log.w(TAG, "AudioFocus requestAudioFocus() could not link to "+cb+" binder death"); 3803baf674eedd5ecff9da0cf8cabe9868f7699b1695Jean-Michel Trivi return AudioManager.AUDIOFOCUS_REQUEST_FAILED; 3804baf674eedd5ecff9da0cf8cabe9868f7699b1695Jean-Michel Trivi } 3805baf674eedd5ecff9da0cf8cabe9868f7699b1695Jean-Michel Trivi 3806d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi if (!mFocusStack.empty() && mFocusStack.peek().mClientId.equals(clientId)) { 3807e5e1e870fdb35f5291790e6d178bde7126f6fe35Jean-Michel Trivi // if focus is already owned by this client and the reason for acquiring the focus 3808e5e1e870fdb35f5291790e6d178bde7126f6fe35Jean-Michel Trivi // hasn't changed, don't do anything 3809e5e1e870fdb35f5291790e6d178bde7126f6fe35Jean-Michel Trivi if (mFocusStack.peek().mFocusChangeType == focusChangeHint) { 3810de1f065be109e1c313d8330c8e34210fedaac74eJean-Michel Trivi // unlink death handler so it can be gc'ed. 3811de1f065be109e1c313d8330c8e34210fedaac74eJean-Michel Trivi // linkToDeath() creates a JNI global reference preventing collection. 3812de1f065be109e1c313d8330c8e34210fedaac74eJean-Michel Trivi cb.unlinkToDeath(afdh, 0); 3813e5e1e870fdb35f5291790e6d178bde7126f6fe35Jean-Michel Trivi return AudioManager.AUDIOFOCUS_REQUEST_GRANTED; 3814e5e1e870fdb35f5291790e6d178bde7126f6fe35Jean-Michel Trivi } 3815e5e1e870fdb35f5291790e6d178bde7126f6fe35Jean-Michel Trivi // the reason for the audio focus request has changed: remove the current top of 3816e5e1e870fdb35f5291790e6d178bde7126f6fe35Jean-Michel Trivi // stack and respond as if we had a new focus owner 3817e7edc868538e83152e7bc35c830fee0d629baefcJean-Michel Trivi FocusStackEntry fse = mFocusStack.pop(); 3818e7edc868538e83152e7bc35c830fee0d629baefcJean-Michel Trivi fse.unlinkToDeath(); 3819d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi } 3820d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi 3821d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi // notify current top of stack it is losing focus 3822d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi if (!mFocusStack.empty() && (mFocusStack.peek().mFocusDispatcher != null)) { 3823d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi try { 3824d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi mFocusStack.peek().mFocusDispatcher.dispatchAudioFocusChange( 3825078fd47e91d495175927d1a4a8b9aad039a7ba4eJean-Michel Trivi -1 * focusChangeHint, // loss and gain codes are inverse of each other 3826d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi mFocusStack.peek().mClientId); 3827d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi } catch (RemoteException e) { 3828d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi Log.e(TAG, " Failure to signal loss of focus due to "+ e); 3829d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi e.printStackTrace(); 3830d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi } 3831d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi } 3832d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi 383355d1bb3483e17a11d122e68044e552d96ab55ff4Jean-Michel Trivi // focus requester might already be somewhere below in the stack, remove it 3834baf674eedd5ecff9da0cf8cabe9868f7699b1695Jean-Michel Trivi removeFocusStackEntry(clientId, false /* signal */); 3835061214bb71a4a4211e670001226c68f5e8036b84Jean-Michel Trivi 3836d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi // push focus requester at the top of the audio focus stack 38378f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi mFocusStack.push(new FocusStackEntry(mainStreamType, focusChangeHint, fd, cb, 3838061214bb71a4a4211e670001226c68f5e8036b84Jean-Michel Trivi clientId, afdh, callingPackageName, Binder.getCallingUid())); 38398f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi 38408f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi // there's a new top of the stack, let the remote control know 38418f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi synchronized(mRCStack) { 3842b716f0b7b2d8e4b045843fc6a7004910eb344c19Jean-Michel Trivi checkUpdateRemoteControlDisplay_syncAfRcs(RC_INFO_ALL); 38438f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi } 3844392a2bbb52688ebd25768a7784d9edca7f498110Jean-Michel Trivi }//synchronized(mAudioFocusLock) 3845d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi 3846d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi return AudioManager.AUDIOFOCUS_REQUEST_GRANTED; 3847d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi } 3848d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi 3849d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi /** @see AudioManager#abandonAudioFocus(IAudioFocusDispatcher) */ 3850d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi public int abandonAudioFocus(IAudioFocusDispatcher fl, String clientId) { 3851d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi Log.i(TAG, " AudioFocus abandonAudioFocus() from " + clientId); 3852392a2bbb52688ebd25768a7784d9edca7f498110Jean-Michel Trivi try { 3853392a2bbb52688ebd25768a7784d9edca7f498110Jean-Michel Trivi // this will take care of notifying the new focus owner if needed 3854392a2bbb52688ebd25768a7784d9edca7f498110Jean-Michel Trivi synchronized(mAudioFocusLock) { 3855392a2bbb52688ebd25768a7784d9edca7f498110Jean-Michel Trivi removeFocusStackEntry(clientId, true); 3856392a2bbb52688ebd25768a7784d9edca7f498110Jean-Michel Trivi } 3857392a2bbb52688ebd25768a7784d9edca7f498110Jean-Michel Trivi } catch (java.util.ConcurrentModificationException cme) { 3858392a2bbb52688ebd25768a7784d9edca7f498110Jean-Michel Trivi // Catching this exception here is temporary. It is here just to prevent 3859392a2bbb52688ebd25768a7784d9edca7f498110Jean-Michel Trivi // a crash seen when the "Silent" notification is played. This is believed to be fixed 3860392a2bbb52688ebd25768a7784d9edca7f498110Jean-Michel Trivi // but this try catch block is left just to be safe. 3861392a2bbb52688ebd25768a7784d9edca7f498110Jean-Michel Trivi Log.e(TAG, "FATAL EXCEPTION AudioFocus abandonAudioFocus() caused " + cme); 3862392a2bbb52688ebd25768a7784d9edca7f498110Jean-Michel Trivi cme.printStackTrace(); 38632930bb2d47be279dd228ba8c749c1e39e5da8be1Jean-Michel Trivi } 3864d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi 3865d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi return AudioManager.AUDIOFOCUS_REQUEST_GRANTED; 3866d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi } 3867d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi 3868d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi 3869d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi public void unregisterAudioFocusClient(String clientId) { 3870392a2bbb52688ebd25768a7784d9edca7f498110Jean-Michel Trivi synchronized(mAudioFocusLock) { 38712930bb2d47be279dd228ba8c749c1e39e5da8be1Jean-Michel Trivi removeFocusStackEntry(clientId, false); 38722930bb2d47be279dd228ba8c749c1e39e5da8be1Jean-Michel Trivi } 3873d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi } 3874d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi 3875d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi 3876d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi //========================================================================================== 3877d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi // RemoteControl 3878d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi //========================================================================================== 3879c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi public void dispatchMediaKeyEvent(KeyEvent keyEvent) { 38804294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi filterMediaKeyEvent(keyEvent, false /*needWakeLock*/); 3881c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi } 3882c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi 3883c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi public void dispatchMediaKeyEventUnderWakelock(KeyEvent keyEvent) { 38844294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi filterMediaKeyEvent(keyEvent, true /*needWakeLock*/); 3885c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi } 3886c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi 38874294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi private void filterMediaKeyEvent(KeyEvent keyEvent, boolean needWakeLock) { 3888c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi // sanity check on the incoming key event 3889c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi if (!isValidMediaKeyEvent(keyEvent)) { 3890c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi Log.e(TAG, "not dispatching invalid media key event " + keyEvent); 3891c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi return; 3892c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi } 3893722b808662eb20fa91151f1e3aa05fd911d1d226Jean-Michel Trivi // event filtering for telephony 3894c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi synchronized(mRingingLock) { 3895722b808662eb20fa91151f1e3aa05fd911d1d226Jean-Michel Trivi synchronized(mRCStack) { 3896722b808662eb20fa91151f1e3aa05fd911d1d226Jean-Michel Trivi if ((mMediaReceiverForCalls != null) && 3897722b808662eb20fa91151f1e3aa05fd911d1d226Jean-Michel Trivi (mIsRinging || (getMode() == AudioSystem.MODE_IN_CALL))) { 3898722b808662eb20fa91151f1e3aa05fd911d1d226Jean-Michel Trivi dispatchMediaKeyEventForCalls(keyEvent, needWakeLock); 3899722b808662eb20fa91151f1e3aa05fd911d1d226Jean-Michel Trivi return; 3900722b808662eb20fa91151f1e3aa05fd911d1d226Jean-Michel Trivi } 3901d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi } 3902c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi } 39034294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi // event filtering based on voice-based interactions 39044294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi if (isValidVoiceInputKeyCode(keyEvent.getKeyCode())) { 39054294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi filterVoiceInputKeyEvent(keyEvent, needWakeLock); 39064294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi } else { 39074294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi dispatchMediaKeyEvent(keyEvent, needWakeLock); 39084294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi } 39094294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi } 39104294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi 39114294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi /** 3912722b808662eb20fa91151f1e3aa05fd911d1d226Jean-Michel Trivi * Handles the dispatching of the media button events to the telephony package. 3913722b808662eb20fa91151f1e3aa05fd911d1d226Jean-Michel Trivi * Precondition: mMediaReceiverForCalls != null 3914722b808662eb20fa91151f1e3aa05fd911d1d226Jean-Michel Trivi * @param keyEvent a non-null KeyEvent whose key code is one of the supported media buttons 3915722b808662eb20fa91151f1e3aa05fd911d1d226Jean-Michel Trivi * @param needWakeLock true if a PARTIAL_WAKE_LOCK needs to be held while this key event 3916722b808662eb20fa91151f1e3aa05fd911d1d226Jean-Michel Trivi * is dispatched. 3917722b808662eb20fa91151f1e3aa05fd911d1d226Jean-Michel Trivi */ 3918722b808662eb20fa91151f1e3aa05fd911d1d226Jean-Michel Trivi private void dispatchMediaKeyEventForCalls(KeyEvent keyEvent, boolean needWakeLock) { 3919722b808662eb20fa91151f1e3aa05fd911d1d226Jean-Michel Trivi Intent keyIntent = new Intent(Intent.ACTION_MEDIA_BUTTON, null); 3920722b808662eb20fa91151f1e3aa05fd911d1d226Jean-Michel Trivi keyIntent.putExtra(Intent.EXTRA_KEY_EVENT, keyEvent); 3921722b808662eb20fa91151f1e3aa05fd911d1d226Jean-Michel Trivi keyIntent.setPackage(mMediaReceiverForCalls.getPackageName()); 3922722b808662eb20fa91151f1e3aa05fd911d1d226Jean-Michel Trivi if (needWakeLock) { 3923722b808662eb20fa91151f1e3aa05fd911d1d226Jean-Michel Trivi mMediaEventWakeLock.acquire(); 3924722b808662eb20fa91151f1e3aa05fd911d1d226Jean-Michel Trivi keyIntent.putExtra(EXTRA_WAKELOCK_ACQUIRED, WAKELOCK_RELEASE_ON_FINISHED); 3925722b808662eb20fa91151f1e3aa05fd911d1d226Jean-Michel Trivi } 3926722b808662eb20fa91151f1e3aa05fd911d1d226Jean-Michel Trivi mContext.sendOrderedBroadcast(keyIntent, null, mKeyEventDone, 3927722b808662eb20fa91151f1e3aa05fd911d1d226Jean-Michel Trivi mAudioHandler, Activity.RESULT_OK, null, null); 3928722b808662eb20fa91151f1e3aa05fd911d1d226Jean-Michel Trivi } 3929722b808662eb20fa91151f1e3aa05fd911d1d226Jean-Michel Trivi 3930722b808662eb20fa91151f1e3aa05fd911d1d226Jean-Michel Trivi /** 39314294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi * Handles the dispatching of the media button events to one of the registered listeners, 39324294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi * or if there was none, broadcast an ACTION_MEDIA_BUTTON intent to the rest of the system. 39334294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi * @param keyEvent a non-null KeyEvent whose key code is one of the supported media buttons 39344294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi * @param needWakeLock true if a PARTIAL_WAKE_LOCK needs to be held while this key event 39354294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi * is dispatched. 39364294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi */ 39374294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi private void dispatchMediaKeyEvent(KeyEvent keyEvent, boolean needWakeLock) { 3938c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi if (needWakeLock) { 3939c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi mMediaEventWakeLock.acquire(); 3940c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi } 3941c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi Intent keyIntent = new Intent(Intent.ACTION_MEDIA_BUTTON, null); 3942c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi keyIntent.putExtra(Intent.EXTRA_KEY_EVENT, keyEvent); 3943c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi synchronized(mRCStack) { 3944c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi if (!mRCStack.empty()) { 3945c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi // send the intent that was registered by the client 3946c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi try { 3947c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi mRCStack.peek().mMediaIntent.send(mContext, 3948c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi needWakeLock ? WAKELOCK_RELEASE_ON_FINISHED : 0 /*code*/, 3949c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi keyIntent, AudioService.this, mAudioHandler); 3950c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi } catch (CanceledException e) { 3951c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi Log.e(TAG, "Error sending pending intent " + mRCStack.peek()); 3952c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi e.printStackTrace(); 3953d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi } 3954c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi } else { 3955c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi // legacy behavior when nobody registered their media button event receiver 3956c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi // through AudioManager 3957c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi if (needWakeLock) { 3958c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi keyIntent.putExtra(EXTRA_WAKELOCK_ACQUIRED, WAKELOCK_RELEASE_ON_FINISHED); 3959d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi } 3960c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi mContext.sendOrderedBroadcast(keyIntent, null, mKeyEventDone, 3961c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi mAudioHandler, Activity.RESULT_OK, null, null); 3962d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi } 3963d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi } 3964d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi } 3965d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi 39664294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi /** 3967ab624c2fd4f0fad6ba7f422a960942e5a7035ceaJeff Brown * The different actions performed in response to a voice button key event. 39684294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi */ 39694294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi private final static int VOICEBUTTON_ACTION_DISCARD_CURRENT_KEY_PRESS = 1; 39704294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi private final static int VOICEBUTTON_ACTION_START_VOICE_INPUT = 2; 39714294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi private final static int VOICEBUTTON_ACTION_SIMULATE_KEY_PRESS = 3; 39724294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi 39734294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi private final Object mVoiceEventLock = new Object(); 3974ab624c2fd4f0fad6ba7f422a960942e5a7035ceaJeff Brown private boolean mVoiceButtonDown; 3975ab624c2fd4f0fad6ba7f422a960942e5a7035ceaJeff Brown private boolean mVoiceButtonHandled; 39764294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi 39774294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi /** 39784294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi * Filter key events that may be used for voice-based interactions 39794294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi * @param keyEvent a non-null KeyEvent whose key code is that of one of the supported 39804294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi * media buttons that can be used to trigger voice-based interactions. 39814294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi * @param needWakeLock true if a PARTIAL_WAKE_LOCK needs to be held while this key event 39824294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi * is dispatched. 39834294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi */ 39844294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi private void filterVoiceInputKeyEvent(KeyEvent keyEvent, boolean needWakeLock) { 3985ab624c2fd4f0fad6ba7f422a960942e5a7035ceaJeff Brown if (DEBUG_RC) { 3986ab624c2fd4f0fad6ba7f422a960942e5a7035ceaJeff Brown Log.v(TAG, "voice input key event: " + keyEvent + ", needWakeLock=" + needWakeLock); 3987ab624c2fd4f0fad6ba7f422a960942e5a7035ceaJeff Brown } 3988ab624c2fd4f0fad6ba7f422a960942e5a7035ceaJeff Brown 39894294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi int voiceButtonAction = VOICEBUTTON_ACTION_DISCARD_CURRENT_KEY_PRESS; 39904294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi int keyAction = keyEvent.getAction(); 39914294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi synchronized (mVoiceEventLock) { 3992ab624c2fd4f0fad6ba7f422a960942e5a7035ceaJeff Brown if (keyAction == KeyEvent.ACTION_DOWN) { 3993ab624c2fd4f0fad6ba7f422a960942e5a7035ceaJeff Brown if (keyEvent.getRepeatCount() == 0) { 3994ab624c2fd4f0fad6ba7f422a960942e5a7035ceaJeff Brown // initial down 3995ab624c2fd4f0fad6ba7f422a960942e5a7035ceaJeff Brown mVoiceButtonDown = true; 3996ab624c2fd4f0fad6ba7f422a960942e5a7035ceaJeff Brown mVoiceButtonHandled = false; 3997ab624c2fd4f0fad6ba7f422a960942e5a7035ceaJeff Brown } else if (mVoiceButtonDown && !mVoiceButtonHandled 3998ab624c2fd4f0fad6ba7f422a960942e5a7035ceaJeff Brown && (keyEvent.getFlags() & KeyEvent.FLAG_LONG_PRESS) != 0) { 3999ab624c2fd4f0fad6ba7f422a960942e5a7035ceaJeff Brown // long-press, start voice-based interactions 4000ab624c2fd4f0fad6ba7f422a960942e5a7035ceaJeff Brown mVoiceButtonHandled = true; 4001ab624c2fd4f0fad6ba7f422a960942e5a7035ceaJeff Brown voiceButtonAction = VOICEBUTTON_ACTION_START_VOICE_INPUT; 4002ab624c2fd4f0fad6ba7f422a960942e5a7035ceaJeff Brown } 4003ab624c2fd4f0fad6ba7f422a960942e5a7035ceaJeff Brown } else if (keyAction == KeyEvent.ACTION_UP) { 4004ab624c2fd4f0fad6ba7f422a960942e5a7035ceaJeff Brown if (mVoiceButtonDown) { 4005ab624c2fd4f0fad6ba7f422a960942e5a7035ceaJeff Brown // voice button up 4006ab624c2fd4f0fad6ba7f422a960942e5a7035ceaJeff Brown mVoiceButtonDown = false; 4007ab624c2fd4f0fad6ba7f422a960942e5a7035ceaJeff Brown if (!mVoiceButtonHandled && !keyEvent.isCanceled()) { 4008ab624c2fd4f0fad6ba7f422a960942e5a7035ceaJeff Brown voiceButtonAction = VOICEBUTTON_ACTION_SIMULATE_KEY_PRESS; 40094294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi } 4010ab624c2fd4f0fad6ba7f422a960942e5a7035ceaJeff Brown } 40114294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi } 40124294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi }//synchronized (mVoiceEventLock) 40134294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi 40144294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi // take action after media button event filtering for voice-based interactions 40154294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi switch (voiceButtonAction) { 40164294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi case VOICEBUTTON_ACTION_DISCARD_CURRENT_KEY_PRESS: 40174294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi if (DEBUG_RC) Log.v(TAG, " ignore key event"); 40184294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi break; 40194294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi case VOICEBUTTON_ACTION_START_VOICE_INPUT: 40204294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi if (DEBUG_RC) Log.v(TAG, " start voice-based interactions"); 40214294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi // then start the voice-based interactions 40224294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi startVoiceBasedInteractions(needWakeLock); 40234294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi break; 40244294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi case VOICEBUTTON_ACTION_SIMULATE_KEY_PRESS: 40254294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi if (DEBUG_RC) Log.v(TAG, " send simulated key event"); 40264294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi sendSimulatedMediaButtonEvent(keyEvent, needWakeLock); 40274294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi break; 40284294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi } 40294294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi } 40304294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi 40314294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi private void sendSimulatedMediaButtonEvent(KeyEvent originalKeyEvent, boolean needWakeLock) { 40324294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi // send DOWN event 40334294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi KeyEvent keyEvent = KeyEvent.changeAction(originalKeyEvent, KeyEvent.ACTION_DOWN); 40344294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi dispatchMediaKeyEvent(keyEvent, needWakeLock); 40354294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi // send UP event 40364294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi keyEvent = KeyEvent.changeAction(originalKeyEvent, KeyEvent.ACTION_UP); 40374294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi dispatchMediaKeyEvent(keyEvent, needWakeLock); 40384294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi 40394294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi } 40404294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi 40414294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi 4042c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi private static boolean isValidMediaKeyEvent(KeyEvent keyEvent) { 4043c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi if (keyEvent == null) { 4044c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi return false; 4045c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi } 4046c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi final int keyCode = keyEvent.getKeyCode(); 4047c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi switch (keyCode) { 4048c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi case KeyEvent.KEYCODE_MUTE: 4049c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi case KeyEvent.KEYCODE_HEADSETHOOK: 4050c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi case KeyEvent.KEYCODE_MEDIA_PLAY: 4051c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi case KeyEvent.KEYCODE_MEDIA_PAUSE: 4052c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE: 4053c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi case KeyEvent.KEYCODE_MEDIA_STOP: 4054c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi case KeyEvent.KEYCODE_MEDIA_NEXT: 4055c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi case KeyEvent.KEYCODE_MEDIA_PREVIOUS: 4056c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi case KeyEvent.KEYCODE_MEDIA_REWIND: 4057c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi case KeyEvent.KEYCODE_MEDIA_RECORD: 4058c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi case KeyEvent.KEYCODE_MEDIA_FAST_FORWARD: 4059c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi case KeyEvent.KEYCODE_MEDIA_CLOSE: 4060c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi case KeyEvent.KEYCODE_MEDIA_EJECT: 4061c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi break; 4062c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi default: 4063c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi return false; 4064c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi } 4065c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi return true; 4066c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi } 4067c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi 40684294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi /** 40694294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi * Checks whether the given key code is one that can trigger the launch of voice-based 40704294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi * interactions. 40714294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi * @param keyCode the key code associated with the key event 40724294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi * @return true if the key is one of the supported voice-based interaction triggers 40734294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi */ 40744294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi private static boolean isValidVoiceInputKeyCode(int keyCode) { 40754294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi if (keyCode == KeyEvent.KEYCODE_HEADSETHOOK) { 40764294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi return true; 40774294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi } else { 40784294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi return false; 40794294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi } 40804294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi } 40814294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi 40824294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi /** 40834294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi * Tell the system to start voice-based interactions / voice commands 40844294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi */ 40854294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi private void startVoiceBasedInteractions(boolean needWakeLock) { 40863c2711fc2853394324b044632b79ca67388df8f4Jean-Michel Trivi Intent voiceIntent = null; 40873c2711fc2853394324b044632b79ca67388df8f4Jean-Michel Trivi // select which type of search to launch: 40883c2711fc2853394324b044632b79ca67388df8f4Jean-Michel Trivi // - screen on and device unlocked: action is ACTION_WEB_SEARCH 40893c2711fc2853394324b044632b79ca67388df8f4Jean-Michel Trivi // - device locked or screen off: action is ACTION_VOICE_SEARCH_HANDS_FREE 40903c2711fc2853394324b044632b79ca67388df8f4Jean-Michel Trivi // with EXTRA_SECURE set to true if the device is securely locked 40913c2711fc2853394324b044632b79ca67388df8f4Jean-Michel Trivi PowerManager pm = (PowerManager)mContext.getSystemService(Context.POWER_SERVICE); 40923c2711fc2853394324b044632b79ca67388df8f4Jean-Michel Trivi boolean isLocked = mKeyguardManager != null && mKeyguardManager.isKeyguardLocked(); 40933c2711fc2853394324b044632b79ca67388df8f4Jean-Michel Trivi if (!isLocked && pm.isScreenOn()) { 40943c2711fc2853394324b044632b79ca67388df8f4Jean-Michel Trivi voiceIntent = new Intent(android.speech.RecognizerIntent.ACTION_WEB_SEARCH); 40953c2711fc2853394324b044632b79ca67388df8f4Jean-Michel Trivi } else { 40963c2711fc2853394324b044632b79ca67388df8f4Jean-Michel Trivi voiceIntent = new Intent(RecognizerIntent.ACTION_VOICE_SEARCH_HANDS_FREE); 40973c2711fc2853394324b044632b79ca67388df8f4Jean-Michel Trivi voiceIntent.putExtra(RecognizerIntent.EXTRA_SECURE, 40983c2711fc2853394324b044632b79ca67388df8f4Jean-Michel Trivi isLocked && mKeyguardManager.isKeyguardSecure()); 40993c2711fc2853394324b044632b79ca67388df8f4Jean-Michel Trivi } 41003c2711fc2853394324b044632b79ca67388df8f4Jean-Michel Trivi // start the search activity 41014294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi if (needWakeLock) { 41024294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi mMediaEventWakeLock.acquire(); 41034294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi } 41044294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi try { 41053c2711fc2853394324b044632b79ca67388df8f4Jean-Michel Trivi if (voiceIntent != null) { 41063c2711fc2853394324b044632b79ca67388df8f4Jean-Michel Trivi voiceIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK 41073c2711fc2853394324b044632b79ca67388df8f4Jean-Michel Trivi | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS); 41083c2711fc2853394324b044632b79ca67388df8f4Jean-Michel Trivi mContext.startActivity(voiceIntent); 41094294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi } 41104294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi } catch (ActivityNotFoundException e) { 41113c2711fc2853394324b044632b79ca67388df8f4Jean-Michel Trivi Log.w(TAG, "No activity for search: " + e); 41124294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi } finally { 41134294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi if (needWakeLock) { 41144294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi mMediaEventWakeLock.release(); 41154294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi } 41164294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi } 41174294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi } 41184294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi 4119c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi private PowerManager.WakeLock mMediaEventWakeLock; 4120c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi 4121c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi private static final int WAKELOCK_RELEASE_ON_FINISHED = 1980; //magic number 4122c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi 4123c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi // only set when wakelock was acquired, no need to check value when received 4124c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi private static final String EXTRA_WAKELOCK_ACQUIRED = 4125c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi "android.media.AudioService.WAKELOCK_ACQUIRED"; 4126c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi 4127c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi public void onSendFinished(PendingIntent pendingIntent, Intent intent, 4128c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi int resultCode, String resultData, Bundle resultExtras) { 4129c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi if (resultCode == WAKELOCK_RELEASE_ON_FINISHED) { 4130c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi mMediaEventWakeLock.release(); 4131c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi } 4132c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi } 4133c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi 4134c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi BroadcastReceiver mKeyEventDone = new BroadcastReceiver() { 4135c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi public void onReceive(Context context, Intent intent) { 41364294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi if (intent == null) { 41374294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi return; 41384294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi } 41394294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi Bundle extras = intent.getExtras(); 41404294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi if (extras == null) { 41414294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi return; 41424294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi } 41434294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi if (extras.containsKey(EXTRA_WAKELOCK_ACQUIRED)) { 4144c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi mMediaEventWakeLock.release(); 4145c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi } 4146c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi } 4147c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi }; 4148c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi 4149ced110ec5970c632f523dfc0350b6071461ea9bcNeel Parekh private final Object mCurrentRcLock = new Object(); 41508f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi /** 41514426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi * The one remote control client which will receive a request for display information. 415217da769e987de40e113c5b2a3b867b25ba7ac0a2Jean-Michel Trivi * This object may be null. 41538f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi * Access protected by mCurrentRcLock. 41548f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi */ 41554426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi private IRemoteControlClient mCurrentRcClient = null; 41568f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi 41577b6198cacc3e7dd31ef91537d809857d826fb7faJean-Michel Trivi private final static int RC_INFO_NONE = 0; 41587b6198cacc3e7dd31ef91537d809857d826fb7faJean-Michel Trivi private final static int RC_INFO_ALL = 41594426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi RemoteControlClient.FLAG_INFORMATION_REQUEST_ALBUM_ART | 41604426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi RemoteControlClient.FLAG_INFORMATION_REQUEST_KEY_MEDIA | 41614426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi RemoteControlClient.FLAG_INFORMATION_REQUEST_METADATA | 41624426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi RemoteControlClient.FLAG_INFORMATION_REQUEST_PLAYSTATE; 41637b6198cacc3e7dd31ef91537d809857d826fb7faJean-Michel Trivi 41647b6198cacc3e7dd31ef91537d809857d826fb7faJean-Michel Trivi /** 416517da769e987de40e113c5b2a3b867b25ba7ac0a2Jean-Michel Trivi * A monotonically increasing generation counter for mCurrentRcClient. 41668f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi * Only accessed with a lock on mCurrentRcLock. 416717da769e987de40e113c5b2a3b867b25ba7ac0a2Jean-Michel Trivi * No value wrap-around issues as we only act on equal values. 41688f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi */ 4169ced110ec5970c632f523dfc0350b6071461ea9bcNeel Parekh private int mCurrentRcClientGen = 0; 41708f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi 41718f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi /** 41728f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi * Inner class to monitor remote control client deaths, and remove the client for the 41738f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi * remote control stack if necessary. 41748f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi */ 41758f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi private class RcClientDeathHandler implements IBinder.DeathRecipient { 41768f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi private IBinder mCb; // To be notified of client's death 4177f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi private PendingIntent mMediaIntent; 41788f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi 4179f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi RcClientDeathHandler(IBinder cb, PendingIntent pi) { 41808f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi mCb = cb; 4181f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi mMediaIntent = pi; 41828f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi } 41838f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi 41848f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi public void binderDied() { 41858f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi Log.w(TAG, " RemoteControlClient died"); 41868f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi // remote control client died, make sure the displays don't use it anymore 41878f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi // by setting its remote control client to null 418826b3d1ff38998c7cb80a2950da0589ebd8510897Jean-Michel Trivi registerRemoteControlClient(mMediaIntent, null/*rcClient*/, null/*ignored*/); 41893114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi // the dead client was maybe handling remote playback, reevaluate 41903114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi postReevaluateRemote(); 41918f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi } 41928f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi 41938f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi public IBinder getBinder() { 41948f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi return mCb; 41958f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi } 41968f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi } 41978f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi 41983114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi /** 41993114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi * A global counter for RemoteControlClient identifiers 42003114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi */ 42013114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi private static int sLastRccId = 0; 42023114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi 42033114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi private class RemotePlaybackState { 42043114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi int mRccId; 42053114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi int mVolume; 42063114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi int mVolumeMax; 42073114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi int mVolumeHandling; 42083114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi 42093114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi private RemotePlaybackState(int id, int vol, int volMax) { 42103114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi mRccId = id; 42113114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi mVolume = vol; 42123114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi mVolumeMax = volMax; 42133114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi mVolumeHandling = RemoteControlClient.DEFAULT_PLAYBACK_VOLUME_HANDLING; 42143114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi } 42153114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi } 42163114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi 42173114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi /** 42183114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi * Internal cache for the playback information of the RemoteControlClient whose volume gets to 42193114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi * be controlled by the volume keys ("main"), so we don't have to iterate over the RC stack 42203114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi * every time we need this info. 42213114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi */ 42223114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi private RemotePlaybackState mMainRemote; 42233114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi /** 42243114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi * Indicates whether the "main" RemoteControlClient is considered active. 42253114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi * Use synchronized on mMainRemote. 42263114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi */ 42273114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi private boolean mMainRemoteIsActive; 42283114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi /** 42293114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi * Indicates whether there is remote playback going on. True even if there is no "active" 42303114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi * remote playback (mMainRemoteIsActive is false), but a RemoteControlClient has declared it 42313114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi * handles remote playback. 42323114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi * Use synchronized on mMainRemote. 42333114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi */ 42343114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi private boolean mHasRemotePlayback; 42353114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi 4236d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi private static class RemoteControlStackEntry { 42373114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi public int mRccId = RemoteControlClient.RCSE_ID_UNREGISTERED; 4238f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi /** 4239f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi * The target for the ACTION_MEDIA_BUTTON events. 4240f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi * Always non null. 4241f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi */ 4242f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi public PendingIntent mMediaIntent; 4243f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi /** 4244f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi * The registered media button event receiver. 4245f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi * Always non null. 4246f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi */ 4247f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi public ComponentName mReceiverComponent; 42488f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi public String mCallingPackageName; 42498f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi public int mCallingUid; 4250f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi /** 4251f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi * Provides access to the information to display on the remote control. 4252f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi * May be null (when a media button event receiver is registered, 4253f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi * but no remote control client has been registered) */ 42544426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi public IRemoteControlClient mRcClient; 42558f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi public RcClientDeathHandler mRcClientDeathHandler; 42563114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi /** 42573114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi * Information only used for non-local playback 42583114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi */ 42593114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi public int mPlaybackType; 42603114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi public int mPlaybackVolume; 42613114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi public int mPlaybackVolumeMax; 42623114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi public int mPlaybackVolumeHandling; 42633114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi public int mPlaybackStream; 42643114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi public int mPlaybackState; 42651357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi public IRemoteVolumeObserver mRemoteVolumeObs; 42663114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi 42673114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi public void resetPlaybackInfo() { 42683114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi mPlaybackType = RemoteControlClient.PLAYBACK_TYPE_LOCAL; 42693114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi mPlaybackVolume = RemoteControlClient.DEFAULT_PLAYBACK_VOLUME; 42703114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi mPlaybackVolumeMax = RemoteControlClient.DEFAULT_PLAYBACK_VOLUME; 42713114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi mPlaybackVolumeHandling = RemoteControlClient.DEFAULT_PLAYBACK_VOLUME_HANDLING; 42723114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi mPlaybackStream = AudioManager.STREAM_MUSIC; 42733114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi mPlaybackState = RemoteControlClient.PLAYSTATE_STOPPED; 42741357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi mRemoteVolumeObs = null; 42753114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi } 4276d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi 4277f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi /** precondition: mediaIntent != null, eventReceiver != null */ 4278f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi public RemoteControlStackEntry(PendingIntent mediaIntent, ComponentName eventReceiver) { 4279f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi mMediaIntent = mediaIntent; 4280f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi mReceiverComponent = eventReceiver; 42818f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi mCallingUid = -1; 428217da769e987de40e113c5b2a3b867b25ba7ac0a2Jean-Michel Trivi mRcClient = null; 42833114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi mRccId = ++sLastRccId; 42843114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi 42853114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi resetPlaybackInfo(); 42868f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi } 42878f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi 42888f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi public void unlinkToRcClientDeath() { 42898f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi if ((mRcClientDeathHandler != null) && (mRcClientDeathHandler.mCb != null)) { 42908f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi try { 42918f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi mRcClientDeathHandler.mCb.unlinkToDeath(mRcClientDeathHandler, 0); 4292a9509736c85c19fe4ad4ba97a0545f0422a3dfc1Jean-Michel Trivi mRcClientDeathHandler = null; 42938f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi } catch (java.util.NoSuchElementException e) { 42948f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi // not much we can do here 42958f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi Log.e(TAG, "Encountered " + e + " in unlinkToRcClientDeath()"); 42968f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi e.printStackTrace(); 42978f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi } 42988f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi } 4299d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi } 4300a9509736c85c19fe4ad4ba97a0545f0422a3dfc1Jean-Michel Trivi 4301a9509736c85c19fe4ad4ba97a0545f0422a3dfc1Jean-Michel Trivi @Override 4302a9509736c85c19fe4ad4ba97a0545f0422a3dfc1Jean-Michel Trivi protected void finalize() throws Throwable { 4303a9509736c85c19fe4ad4ba97a0545f0422a3dfc1Jean-Michel Trivi unlinkToRcClientDeath();// unlink exception handled inside method 4304a9509736c85c19fe4ad4ba97a0545f0422a3dfc1Jean-Michel Trivi super.finalize(); 4305a9509736c85c19fe4ad4ba97a0545f0422a3dfc1Jean-Michel Trivi } 4306d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi } 4307d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi 43088f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi /** 43098f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi * The stack of remote control event receivers. 43108f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi * Code sections and methods that modify the remote control event receiver stack are 43118f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi * synchronized on mRCStack, but also BEFORE on mFocusLock as any change in either 43128f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi * stack, audio focus or RC, can lead to a change in the remote control display 43138f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi */ 431430c918ce7fbe171944b28fc91b3f22b3d631872dGlenn Kasten private final Stack<RemoteControlStackEntry> mRCStack = new Stack<RemoteControlStackEntry>(); 4315d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi 4316d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi /** 4317722b808662eb20fa91151f1e3aa05fd911d1d226Jean-Michel Trivi * The component the telephony package can register so telephony calls have priority to 4318722b808662eb20fa91151f1e3aa05fd911d1d226Jean-Michel Trivi * handle media button events 4319722b808662eb20fa91151f1e3aa05fd911d1d226Jean-Michel Trivi */ 4320722b808662eb20fa91151f1e3aa05fd911d1d226Jean-Michel Trivi private ComponentName mMediaReceiverForCalls = null; 4321722b808662eb20fa91151f1e3aa05fd911d1d226Jean-Michel Trivi 4322722b808662eb20fa91151f1e3aa05fd911d1d226Jean-Michel Trivi /** 4323d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi * Helper function: 4324d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi * Display in the log the current entries in the remote control focus stack 4325d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi */ 4326d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi private void dumpRCStack(PrintWriter pw) { 4327b4bccb6d8df16a2c5235cead187156bc721cf074Jean-Michel Trivi pw.println("\nRemote Control stack entries:"); 4328d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi synchronized(mRCStack) { 4329d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator(); 4330d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi while(stackIterator.hasNext()) { 43318f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi RemoteControlStackEntry rcse = stackIterator.next(); 4332f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi pw.println(" pi: " + rcse.mMediaIntent + 4333f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi " -- ercvr: " + rcse.mReceiverComponent + 433417da769e987de40e113c5b2a3b867b25ba7ac0a2Jean-Michel Trivi " -- client: " + rcse.mRcClient + 43353114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi " -- uid: " + rcse.mCallingUid + 43363114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi " -- type: " + rcse.mPlaybackType + 43373114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi " state: " + rcse.mPlaybackState); 43383114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi } 43393114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi } 43403114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi } 43413114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi 43423114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi /** 43433114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi * Helper function: 43443114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi * Display in the log the current entries in the remote control stack, focusing 43453114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi * on RemoteControlClient data 43463114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi */ 43473114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi private void dumpRCCStack(PrintWriter pw) { 43483114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi pw.println("\nRemote Control Client stack entries:"); 43493114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi synchronized(mRCStack) { 43503114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator(); 43513114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi while(stackIterator.hasNext()) { 43523114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi RemoteControlStackEntry rcse = stackIterator.next(); 43533114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi pw.println(" uid: " + rcse.mCallingUid + 43543114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi " -- id: " + rcse.mRccId + 43553114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi " -- type: " + rcse.mPlaybackType + 43563114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi " -- state: " + rcse.mPlaybackState + 43573114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi " -- vol handling: " + rcse.mPlaybackVolumeHandling + 43583114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi " -- vol: " + rcse.mPlaybackVolume + 43591357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi " -- volMax: " + rcse.mPlaybackVolumeMax + 43601357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi " -- volObs: " + rcse.mRemoteVolumeObs); 43611357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi 4362d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi } 4363d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi } 43643114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi synchronized (mMainRemote) { 43653114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi pw.println("\nRemote Volume State:"); 43663114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi pw.println(" has remote: " + mHasRemotePlayback); 43673114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi pw.println(" is remote active: " + mMainRemoteIsActive); 43683114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi pw.println(" rccId: " + mMainRemote.mRccId); 43693114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi pw.println(" volume handling: " 43703114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi + ((mMainRemote.mVolumeHandling == RemoteControlClient.PLAYBACK_VOLUME_FIXED) ? 43713114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi "PLAYBACK_VOLUME_FIXED(0)" : "PLAYBACK_VOLUME_VARIABLE(1)")); 43723114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi pw.println(" volume: " + mMainRemote.mVolume); 43733114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi pw.println(" volume steps: " + mMainRemote.mVolumeMax); 43743114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi } 4375d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi } 4376d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi 4377d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi /** 4378d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi * Helper function: 4379d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi * Remove any entry in the remote control stack that has the same package name as packageName 4380d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi * Pre-condition: packageName != null 4381d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi */ 4382d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi private void removeMediaButtonReceiverForPackage(String packageName) { 4383d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi synchronized(mRCStack) { 4384d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi if (mRCStack.empty()) { 4385d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi return; 4386d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi } else { 4387d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi RemoteControlStackEntry oldTop = mRCStack.peek(); 4388d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator(); 4389d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi // iterate over the stack entries 4390d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi while(stackIterator.hasNext()) { 4391d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi RemoteControlStackEntry rcse = (RemoteControlStackEntry)stackIterator.next(); 4392d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi if (packageName.equalsIgnoreCase(rcse.mReceiverComponent.getPackageName())) { 4393d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi // a stack entry is from the package being removed, remove it from the stack 4394d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi stackIterator.remove(); 4395a9509736c85c19fe4ad4ba97a0545f0422a3dfc1Jean-Michel Trivi rcse.unlinkToRcClientDeath(); 4396d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi } 4397d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi } 4398d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi if (mRCStack.empty()) { 4399d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi // no saved media button receiver 4400d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi mAudioHandler.sendMessage( 4401d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi mAudioHandler.obtainMessage(MSG_PERSIST_MEDIABUTTONRECEIVER, 0, 0, 4402d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi null)); 4403d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi } else if (oldTop != mRCStack.peek()) { 4404d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi // the top of the stack has changed, save it in the system settings 4405d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi // by posting a message to persist it 4406d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi mAudioHandler.sendMessage( 4407d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi mAudioHandler.obtainMessage(MSG_PERSIST_MEDIABUTTONRECEIVER, 0, 0, 4408d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi mRCStack.peek().mReceiverComponent)); 4409d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi } 4410d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi } 4411d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi } 4412d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi } 4413d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi 4414d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi /** 4415d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi * Helper function: 4416f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi * Restore remote control receiver from the system settings. 4417d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi */ 4418d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi private void restoreMediaButtonReceiver() { 4419d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi String receiverName = Settings.System.getString(mContentResolver, 4420d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi Settings.System.MEDIA_BUTTON_RECEIVER); 4421d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi if ((null != receiverName) && !receiverName.isEmpty()) { 4422f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi ComponentName eventReceiver = ComponentName.unflattenFromString(receiverName); 4423f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi // construct a PendingIntent targeted to the restored component name 4424f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi // for the media button and register it 4425f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi Intent mediaButtonIntent = new Intent(Intent.ACTION_MEDIA_BUTTON); 4426f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi // the associated intent will be handled by the component being registered 4427f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi mediaButtonIntent.setComponent(eventReceiver); 4428f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi PendingIntent pi = PendingIntent.getBroadcast(mContext, 4429f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi 0/*requestCode, ignored*/, mediaButtonIntent, 0/*flags*/); 4430f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi registerMediaButtonIntent(pi, eventReceiver); 4431d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi } 4432d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi } 4433d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi 4434d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi /** 4435d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi * Helper function: 4436f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi * Set the new remote control receiver at the top of the RC focus stack. 4437f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi * precondition: mediaIntent != null, target != null 4438d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi */ 4439f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi private void pushMediaButtonReceiver(PendingIntent mediaIntent, ComponentName target) { 4440d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi // already at top of stack? 4441f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi if (!mRCStack.empty() && mRCStack.peek().mMediaIntent.equals(mediaIntent)) { 4442d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi return; 4443d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi } 4444d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator(); 44458f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi RemoteControlStackEntry rcse = null; 44468f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi boolean wasInsideStack = false; 4447d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi while(stackIterator.hasNext()) { 44488f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi rcse = (RemoteControlStackEntry)stackIterator.next(); 4449f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi if(rcse.mMediaIntent.equals(mediaIntent)) { 44508f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi wasInsideStack = true; 445172843377d50a8f95cceaf33d316ab68d9b47f2ebJean-Michel Trivi stackIterator.remove(); 4452d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi break; 4453d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi } 4454d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi } 44558f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi if (!wasInsideStack) { 4456f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi rcse = new RemoteControlStackEntry(mediaIntent, target); 44578f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi } 44588f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi mRCStack.push(rcse); 4459d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi 4460d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi // post message to persist the default media button receiver 4461d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi mAudioHandler.sendMessage( mAudioHandler.obtainMessage( 4462f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi MSG_PERSIST_MEDIABUTTONRECEIVER, 0, 0, target/*obj*/) ); 4463d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi } 4464d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi 4465d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi /** 4466d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi * Helper function: 4467f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi * Remove the remote control receiver from the RC focus stack. 4468f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi * precondition: pi != null 4469d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi */ 4470f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi private void removeMediaButtonReceiver(PendingIntent pi) { 4471d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator(); 4472d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi while(stackIterator.hasNext()) { 4473d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi RemoteControlStackEntry rcse = (RemoteControlStackEntry)stackIterator.next(); 4474f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi if(rcse.mMediaIntent.equals(pi)) { 447572843377d50a8f95cceaf33d316ab68d9b47f2ebJean-Michel Trivi stackIterator.remove(); 4476a9509736c85c19fe4ad4ba97a0545f0422a3dfc1Jean-Michel Trivi rcse.unlinkToRcClientDeath(); 4477d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi break; 4478d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi } 4479d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi } 4480d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi } 4481d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi 44828f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi /** 44838f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi * Helper function: 44848f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi * Called synchronized on mRCStack 44858f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi */ 4486f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi private boolean isCurrentRcController(PendingIntent pi) { 4487f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi if (!mRCStack.empty() && mRCStack.peek().mMediaIntent.equals(pi)) { 44888f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi return true; 44898f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi } 44908f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi return false; 44918f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi } 44928f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi 44934426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi //========================================================================================== 44944426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi // Remote control display / client 44954426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi //========================================================================================== 44964426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi /** 44974426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi * Update the remote control displays with the new "focused" client generation 44984426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi */ 449918e7bce52318f00b5023f33933a571c477f2b61cJean-Michel Trivi private void setNewRcClientOnDisplays_syncRcsCurrc(int newClientGeneration, 4500f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi PendingIntent newMediaIntent, boolean clearing) { 45014426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi // NOTE: Only one IRemoteControlDisplay supported in this implementation 45024426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi if (mRcDisplay != null) { 45034426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi try { 45044b6df6a3dcbd9990e36438c529fa8c16b2580df9Jean-Michel Trivi mRcDisplay.setCurrentClientId( 4505f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi newClientGeneration, newMediaIntent, clearing); 45064426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi } catch (RemoteException e) { 4507db8a361629f06f62b9e1c40d4413b3b5099bd124Jean-Michel Trivi Log.e(TAG, "Dead display in setNewRcClientOnDisplays_syncRcsCurrc() "+e); 45084426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi // if we had a display before, stop monitoring its death 45094426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi rcDisplay_stopDeathMonitor_syncRcStack(); 45104426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi mRcDisplay = null; 45114426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi } 45124426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi } 45134426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi } 45144426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi 45154426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi /** 45164426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi * Update the remote control clients with the new "focused" client generation 45174426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi */ 451818e7bce52318f00b5023f33933a571c477f2b61cJean-Michel Trivi private void setNewRcClientGenerationOnClients_syncRcsCurrc(int newClientGeneration) { 45194426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator(); 45204426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi while(stackIterator.hasNext()) { 45214426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi RemoteControlStackEntry se = stackIterator.next(); 45224426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi if ((se != null) && (se.mRcClient != null)) { 45234426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi try { 45244426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi se.mRcClient.setCurrentClientGenerationId(newClientGeneration); 45254426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi } catch (RemoteException e) { 4526db8a361629f06f62b9e1c40d4413b3b5099bd124Jean-Michel Trivi Log.w(TAG, "Dead client in setNewRcClientGenerationOnClients_syncRcsCurrc()"+e); 45274426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi stackIterator.remove(); 45284426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi se.unlinkToRcClientDeath(); 45294426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi } 45304426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi } 45314426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi } 45324426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi } 45334426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi 45344426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi /** 45354b6df6a3dcbd9990e36438c529fa8c16b2580df9Jean-Michel Trivi * Update the displays and clients with the new "focused" client generation and name 45364b6df6a3dcbd9990e36438c529fa8c16b2580df9Jean-Michel Trivi * @param newClientGeneration the new generation value matching a client update 45374b6df6a3dcbd9990e36438c529fa8c16b2580df9Jean-Michel Trivi * @param newClientEventReceiver the media button event receiver associated with the client. 45384b6df6a3dcbd9990e36438c529fa8c16b2580df9Jean-Michel Trivi * May be null, which implies there is no registered media button event receiver. 45394b6df6a3dcbd9990e36438c529fa8c16b2580df9Jean-Michel Trivi * @param clearing true if the new client generation value maps to a remote control update 45404b6df6a3dcbd9990e36438c529fa8c16b2580df9Jean-Michel Trivi * where the display should be cleared. 45414426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi */ 454218e7bce52318f00b5023f33933a571c477f2b61cJean-Michel Trivi private void setNewRcClient_syncRcsCurrc(int newClientGeneration, 4543f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi PendingIntent newMediaIntent, boolean clearing) { 45443094d955b8321f01e50cb0c448ae1c4c461f41c9Jean-Michel Trivi // send the new valid client generation ID to all displays 4545f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi setNewRcClientOnDisplays_syncRcsCurrc(newClientGeneration, newMediaIntent, clearing); 45463094d955b8321f01e50cb0c448ae1c4c461f41c9Jean-Michel Trivi // send the new valid client generation ID to all clients 454718e7bce52318f00b5023f33933a571c477f2b61cJean-Michel Trivi setNewRcClientGenerationOnClients_syncRcsCurrc(newClientGeneration); 45484426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi } 45494426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi 45504426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi /** 45514426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi * Called when processing MSG_RCDISPLAY_CLEAR event 45524426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi */ 45534426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi private void onRcDisplayClear() { 455418e7bce52318f00b5023f33933a571c477f2b61cJean-Michel Trivi if (DEBUG_RC) Log.i(TAG, "Clear remote control display"); 45554426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi 45563094d955b8321f01e50cb0c448ae1c4c461f41c9Jean-Michel Trivi synchronized(mRCStack) { 45573094d955b8321f01e50cb0c448ae1c4c461f41c9Jean-Michel Trivi synchronized(mCurrentRcLock) { 45583094d955b8321f01e50cb0c448ae1c4c461f41c9Jean-Michel Trivi mCurrentRcClientGen++; 45593094d955b8321f01e50cb0c448ae1c4c461f41c9Jean-Michel Trivi // synchronously update the displays and clients with the new client generation 456018e7bce52318f00b5023f33933a571c477f2b61cJean-Michel Trivi setNewRcClient_syncRcsCurrc(mCurrentRcClientGen, 4561f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi null /*newMediaIntent*/, true /*clearing*/); 45623094d955b8321f01e50cb0c448ae1c4c461f41c9Jean-Michel Trivi } 45634426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi } 45644426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi } 45654426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi 45664426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi /** 45674426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi * Called when processing MSG_RCDISPLAY_UPDATE event 45684426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi */ 45694426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi private void onRcDisplayUpdate(RemoteControlStackEntry rcse, int flags /* USED ?*/) { 45703094d955b8321f01e50cb0c448ae1c4c461f41c9Jean-Michel Trivi synchronized(mRCStack) { 45713094d955b8321f01e50cb0c448ae1c4c461f41c9Jean-Michel Trivi synchronized(mCurrentRcLock) { 45723094d955b8321f01e50cb0c448ae1c4c461f41c9Jean-Michel Trivi if ((mCurrentRcClient != null) && (mCurrentRcClient.equals(rcse.mRcClient))) { 457318e7bce52318f00b5023f33933a571c477f2b61cJean-Michel Trivi if (DEBUG_RC) Log.i(TAG, "Display/update remote control "); 45743094d955b8321f01e50cb0c448ae1c4c461f41c9Jean-Michel Trivi 45753094d955b8321f01e50cb0c448ae1c4c461f41c9Jean-Michel Trivi mCurrentRcClientGen++; 45763094d955b8321f01e50cb0c448ae1c4c461f41c9Jean-Michel Trivi // synchronously update the displays and clients with 45773094d955b8321f01e50cb0c448ae1c4c461f41c9Jean-Michel Trivi // the new client generation 457818e7bce52318f00b5023f33933a571c477f2b61cJean-Michel Trivi setNewRcClient_syncRcsCurrc(mCurrentRcClientGen, 4579f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi rcse.mMediaIntent /*newMediaIntent*/, 45803094d955b8321f01e50cb0c448ae1c4c461f41c9Jean-Michel Trivi false /*clearing*/); 45813094d955b8321f01e50cb0c448ae1c4c461f41c9Jean-Michel Trivi 4582db8a361629f06f62b9e1c40d4413b3b5099bd124Jean-Michel Trivi // tell the current client that it needs to send info 45833094d955b8321f01e50cb0c448ae1c4c461f41c9Jean-Michel Trivi try { 45843094d955b8321f01e50cb0c448ae1c4c461f41c9Jean-Michel Trivi mCurrentRcClient.onInformationRequested(mCurrentRcClientGen, 45853094d955b8321f01e50cb0c448ae1c4c461f41c9Jean-Michel Trivi flags, mArtworkExpectedWidth, mArtworkExpectedHeight); 45863094d955b8321f01e50cb0c448ae1c4c461f41c9Jean-Michel Trivi } catch (RemoteException e) { 45873094d955b8321f01e50cb0c448ae1c4c461f41c9Jean-Michel Trivi Log.e(TAG, "Current valid remote client is dead: "+e); 45883094d955b8321f01e50cb0c448ae1c4c461f41c9Jean-Michel Trivi mCurrentRcClient = null; 45893094d955b8321f01e50cb0c448ae1c4c461f41c9Jean-Michel Trivi } 45903094d955b8321f01e50cb0c448ae1c4c461f41c9Jean-Michel Trivi } else { 45913094d955b8321f01e50cb0c448ae1c4c461f41c9Jean-Michel Trivi // the remote control display owner has changed between the 45923094d955b8321f01e50cb0c448ae1c4c461f41c9Jean-Michel Trivi // the message to update the display was sent, and the time it 45933094d955b8321f01e50cb0c448ae1c4c461f41c9Jean-Michel Trivi // gets to be processed (now) 45944426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi } 45954426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi } 45964426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi } 45974426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi } 45984426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi 45994426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi 46008f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi /** 46018f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi * Helper function: 46028f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi * Called synchronized on mRCStack 46038f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi */ 4604b716f0b7b2d8e4b045843fc6a7004910eb344c19Jean-Michel Trivi private void clearRemoteControlDisplay_syncAfRcs() { 46058f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi synchronized(mCurrentRcLock) { 460617da769e987de40e113c5b2a3b867b25ba7ac0a2Jean-Michel Trivi mCurrentRcClient = null; 46078f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi } 46084426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi // will cause onRcDisplayClear() to be called in AudioService's handler thread 46098f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi mAudioHandler.sendMessage( mAudioHandler.obtainMessage(MSG_RCDISPLAY_CLEAR) ); 46108f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi } 46118f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi 46128f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi /** 4613b716f0b7b2d8e4b045843fc6a7004910eb344c19Jean-Michel Trivi * Helper function for code readability: only to be called from 4614b716f0b7b2d8e4b045843fc6a7004910eb344c19Jean-Michel Trivi * checkUpdateRemoteControlDisplay_syncAfRcs() which checks the preconditions for 4615b716f0b7b2d8e4b045843fc6a7004910eb344c19Jean-Michel Trivi * this method. 4616b716f0b7b2d8e4b045843fc6a7004910eb344c19Jean-Michel Trivi * Preconditions: 4617b716f0b7b2d8e4b045843fc6a7004910eb344c19Jean-Michel Trivi * - called synchronized mAudioFocusLock then on mRCStack 4618b716f0b7b2d8e4b045843fc6a7004910eb344c19Jean-Michel Trivi * - mRCStack.isEmpty() is false 46198f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi */ 4620b716f0b7b2d8e4b045843fc6a7004910eb344c19Jean-Michel Trivi private void updateRemoteControlDisplay_syncAfRcs(int infoChangedFlags) { 46218f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi RemoteControlStackEntry rcse = mRCStack.peek(); 4622b5f04d6dbf5106140df367ae07f0e7708e1b650eJean-Michel Trivi int infoFlagsAboutToBeUsed = infoChangedFlags; 46238f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi // this is where we enforce opt-in for information display on the remote controls 46248f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi // with the new AudioManager.registerRemoteControlClient() API 462517da769e987de40e113c5b2a3b867b25ba7ac0a2Jean-Michel Trivi if (rcse.mRcClient == null) { 462617da769e987de40e113c5b2a3b867b25ba7ac0a2Jean-Michel Trivi //Log.w(TAG, "Can't update remote control display with null remote control client"); 4627b716f0b7b2d8e4b045843fc6a7004910eb344c19Jean-Michel Trivi clearRemoteControlDisplay_syncAfRcs(); 46288f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi return; 46298f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi } 46308f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi synchronized(mCurrentRcLock) { 463117da769e987de40e113c5b2a3b867b25ba7ac0a2Jean-Michel Trivi if (!rcse.mRcClient.equals(mCurrentRcClient)) { 46327b6198cacc3e7dd31ef91537d809857d826fb7faJean-Michel Trivi // new RC client, assume every type of information shall be queried 4633b5f04d6dbf5106140df367ae07f0e7708e1b650eJean-Michel Trivi infoFlagsAboutToBeUsed = RC_INFO_ALL; 46347b6198cacc3e7dd31ef91537d809857d826fb7faJean-Michel Trivi } 463517da769e987de40e113c5b2a3b867b25ba7ac0a2Jean-Michel Trivi mCurrentRcClient = rcse.mRcClient; 46368f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi } 46374426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi // will cause onRcDisplayUpdate() to be called in AudioService's handler thread 4638b5f04d6dbf5106140df367ae07f0e7708e1b650eJean-Michel Trivi mAudioHandler.sendMessage( mAudioHandler.obtainMessage(MSG_RCDISPLAY_UPDATE, 46390a9faa8cf934ef38319cd945b600825c6bb88b9cJean-Michel Trivi infoFlagsAboutToBeUsed /* arg1 */, 0, rcse /* obj, != null */) ); 46408f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi } 46418f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi 46428f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi /** 46438f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi * Helper function: 4644b716f0b7b2d8e4b045843fc6a7004910eb344c19Jean-Michel Trivi * Called synchronized on mAudioFocusLock, then mRCStack 46458f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi * Check whether the remote control display should be updated, triggers the update if required 4646b5f04d6dbf5106140df367ae07f0e7708e1b650eJean-Michel Trivi * @param infoChangedFlags the flags corresponding to the remote control client information 4647b5f04d6dbf5106140df367ae07f0e7708e1b650eJean-Michel Trivi * that has changed, if applicable (checking for the update conditions might trigger a 4648b5f04d6dbf5106140df367ae07f0e7708e1b650eJean-Michel Trivi * clear, rather than an update event). 46498f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi */ 4650b716f0b7b2d8e4b045843fc6a7004910eb344c19Jean-Michel Trivi private void checkUpdateRemoteControlDisplay_syncAfRcs(int infoChangedFlags) { 46518f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi // determine whether the remote control display should be refreshed 46528f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi // if either stack is empty, there is a mismatch, so clear the RC display 46538f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi if (mRCStack.isEmpty() || mFocusStack.isEmpty()) { 4654b716f0b7b2d8e4b045843fc6a7004910eb344c19Jean-Michel Trivi clearRemoteControlDisplay_syncAfRcs(); 46558f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi return; 46568f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi } 46578f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi // if the top of the two stacks belong to different packages, there is a mismatch, clear 46588f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi if ((mRCStack.peek().mCallingPackageName != null) 46598f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi && (mFocusStack.peek().mPackageName != null) 46608f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi && !(mRCStack.peek().mCallingPackageName.compareTo( 46618f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi mFocusStack.peek().mPackageName) == 0)) { 4662b716f0b7b2d8e4b045843fc6a7004910eb344c19Jean-Michel Trivi clearRemoteControlDisplay_syncAfRcs(); 46638f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi return; 46648f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi } 46658f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi // if the audio focus didn't originate from the same Uid as the one in which the remote 46668f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi // control information will be retrieved, clear 46678f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi if (mRCStack.peek().mCallingUid != mFocusStack.peek().mCallingUid) { 4668b716f0b7b2d8e4b045843fc6a7004910eb344c19Jean-Michel Trivi clearRemoteControlDisplay_syncAfRcs(); 46698f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi return; 46708f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi } 46718f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi // refresh conditions were verified: update the remote controls 4672b716f0b7b2d8e4b045843fc6a7004910eb344c19Jean-Michel Trivi // ok to call: synchronized mAudioFocusLock then on mRCStack, mRCStack is not empty 4673b716f0b7b2d8e4b045843fc6a7004910eb344c19Jean-Michel Trivi updateRemoteControlDisplay_syncAfRcs(infoChangedFlags); 46748f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi } 4675d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi 46766bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent /** 4677f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi * see AudioManager.registerMediaButtonIntent(PendingIntent pi, ComponentName c) 4678f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi * precondition: mediaIntent != null, target != null 4679f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi */ 4680f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi public void registerMediaButtonIntent(PendingIntent mediaIntent, ComponentName eventReceiver) { 4681f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi Log.i(TAG, " Remote Control registerMediaButtonIntent() for " + mediaIntent); 4682d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi 46838f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi synchronized(mAudioFocusLock) { 46848f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi synchronized(mRCStack) { 4685f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi pushMediaButtonReceiver(mediaIntent, eventReceiver); 4686b5f04d6dbf5106140df367ae07f0e7708e1b650eJean-Michel Trivi // new RC client, assume every type of information shall be queried 4687b716f0b7b2d8e4b045843fc6a7004910eb344c19Jean-Michel Trivi checkUpdateRemoteControlDisplay_syncAfRcs(RC_INFO_ALL); 46888f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi } 4689d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi } 4690d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi } 4691d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi 46926bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent /** 4693f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi * see AudioManager.unregisterMediaButtonIntent(PendingIntent mediaIntent) 4694f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi * precondition: mediaIntent != null, eventReceiver != null 4695f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi */ 4696f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi public void unregisterMediaButtonIntent(PendingIntent mediaIntent, ComponentName eventReceiver) 4697f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi { 4698f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi Log.i(TAG, " Remote Control unregisterMediaButtonIntent() for " + mediaIntent); 4699d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi 47008f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi synchronized(mAudioFocusLock) { 47018f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi synchronized(mRCStack) { 4702f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi boolean topOfStackWillChange = isCurrentRcController(mediaIntent); 4703f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi removeMediaButtonReceiver(mediaIntent); 47048f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi if (topOfStackWillChange) { 4705b5f04d6dbf5106140df367ae07f0e7708e1b650eJean-Michel Trivi // current RC client will change, assume every type of info needs to be queried 4706b716f0b7b2d8e4b045843fc6a7004910eb344c19Jean-Michel Trivi checkUpdateRemoteControlDisplay_syncAfRcs(RC_INFO_ALL); 47078f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi } 47088f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi } 4709d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi } 4710d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi } 4711d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi 471226b3d1ff38998c7cb80a2950da0589ebd8510897Jean-Michel Trivi /** 4713722b808662eb20fa91151f1e3aa05fd911d1d226Jean-Michel Trivi * see AudioManager.registerMediaButtonEventReceiverForCalls(ComponentName c) 4714722b808662eb20fa91151f1e3aa05fd911d1d226Jean-Michel Trivi * precondition: c != null 4715722b808662eb20fa91151f1e3aa05fd911d1d226Jean-Michel Trivi */ 4716722b808662eb20fa91151f1e3aa05fd911d1d226Jean-Michel Trivi public void registerMediaButtonEventReceiverForCalls(ComponentName c) { 4717722b808662eb20fa91151f1e3aa05fd911d1d226Jean-Michel Trivi if (mContext.checkCallingPermission("android.permission.MODIFY_PHONE_STATE") 4718722b808662eb20fa91151f1e3aa05fd911d1d226Jean-Michel Trivi != PackageManager.PERMISSION_GRANTED) { 4719722b808662eb20fa91151f1e3aa05fd911d1d226Jean-Michel Trivi Log.e(TAG, "Invalid permissions to register media button receiver for calls"); 4720722b808662eb20fa91151f1e3aa05fd911d1d226Jean-Michel Trivi return; 4721722b808662eb20fa91151f1e3aa05fd911d1d226Jean-Michel Trivi } 4722722b808662eb20fa91151f1e3aa05fd911d1d226Jean-Michel Trivi synchronized(mRCStack) { 4723722b808662eb20fa91151f1e3aa05fd911d1d226Jean-Michel Trivi mMediaReceiverForCalls = c; 4724722b808662eb20fa91151f1e3aa05fd911d1d226Jean-Michel Trivi } 4725722b808662eb20fa91151f1e3aa05fd911d1d226Jean-Michel Trivi } 4726722b808662eb20fa91151f1e3aa05fd911d1d226Jean-Michel Trivi 4727722b808662eb20fa91151f1e3aa05fd911d1d226Jean-Michel Trivi /** 4728722b808662eb20fa91151f1e3aa05fd911d1d226Jean-Michel Trivi * see AudioManager.unregisterMediaButtonEventReceiverForCalls() 4729722b808662eb20fa91151f1e3aa05fd911d1d226Jean-Michel Trivi */ 4730722b808662eb20fa91151f1e3aa05fd911d1d226Jean-Michel Trivi public void unregisterMediaButtonEventReceiverForCalls() { 4731722b808662eb20fa91151f1e3aa05fd911d1d226Jean-Michel Trivi if (mContext.checkCallingPermission("android.permission.MODIFY_PHONE_STATE") 4732722b808662eb20fa91151f1e3aa05fd911d1d226Jean-Michel Trivi != PackageManager.PERMISSION_GRANTED) { 4733722b808662eb20fa91151f1e3aa05fd911d1d226Jean-Michel Trivi Log.e(TAG, "Invalid permissions to unregister media button receiver for calls"); 4734722b808662eb20fa91151f1e3aa05fd911d1d226Jean-Michel Trivi return; 4735722b808662eb20fa91151f1e3aa05fd911d1d226Jean-Michel Trivi } 4736722b808662eb20fa91151f1e3aa05fd911d1d226Jean-Michel Trivi synchronized(mRCStack) { 4737722b808662eb20fa91151f1e3aa05fd911d1d226Jean-Michel Trivi mMediaReceiverForCalls = null; 4738722b808662eb20fa91151f1e3aa05fd911d1d226Jean-Michel Trivi } 4739722b808662eb20fa91151f1e3aa05fd911d1d226Jean-Michel Trivi } 4740722b808662eb20fa91151f1e3aa05fd911d1d226Jean-Michel Trivi 4741722b808662eb20fa91151f1e3aa05fd911d1d226Jean-Michel Trivi /** 474226b3d1ff38998c7cb80a2950da0589ebd8510897Jean-Michel Trivi * see AudioManager.registerRemoteControlClient(ComponentName eventReceiver, ...) 47433114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi * @return the unique ID of the RemoteControlStackEntry associated with the RemoteControlClient 474426b3d1ff38998c7cb80a2950da0589ebd8510897Jean-Michel Trivi * Note: using this method with rcClient == null is a way to "disable" the IRemoteControlClient 474526b3d1ff38998c7cb80a2950da0589ebd8510897Jean-Michel Trivi * without modifying the RC stack, but while still causing the display to refresh (will 474626b3d1ff38998c7cb80a2950da0589ebd8510897Jean-Michel Trivi * become blank as a result of this) 474726b3d1ff38998c7cb80a2950da0589ebd8510897Jean-Michel Trivi */ 47483114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi public int registerRemoteControlClient(PendingIntent mediaIntent, 4749f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi IRemoteControlClient rcClient, String callingPackageName) { 4750b716f0b7b2d8e4b045843fc6a7004910eb344c19Jean-Michel Trivi if (DEBUG_RC) Log.i(TAG, "Register remote control client rcClient="+rcClient); 47513114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi int rccId = RemoteControlClient.RCSE_ID_UNREGISTERED; 47528f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi synchronized(mAudioFocusLock) { 47538f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi synchronized(mRCStack) { 47548f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi // store the new display information 47558f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator(); 47568f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi while(stackIterator.hasNext()) { 47578f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi RemoteControlStackEntry rcse = stackIterator.next(); 4758f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi if(rcse.mMediaIntent.equals(mediaIntent)) { 47598f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi // already had a remote control client? 47608f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi if (rcse.mRcClientDeathHandler != null) { 47618f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi // stop monitoring the old client's death 47628f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi rcse.unlinkToRcClientDeath(); 47638f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi } 47648f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi // save the new remote control client 476517da769e987de40e113c5b2a3b867b25ba7ac0a2Jean-Michel Trivi rcse.mRcClient = rcClient; 476626b3d1ff38998c7cb80a2950da0589ebd8510897Jean-Michel Trivi rcse.mCallingPackageName = callingPackageName; 476726b3d1ff38998c7cb80a2950da0589ebd8510897Jean-Michel Trivi rcse.mCallingUid = Binder.getCallingUid(); 476826b3d1ff38998c7cb80a2950da0589ebd8510897Jean-Michel Trivi if (rcClient == null) { 4769a9509736c85c19fe4ad4ba97a0545f0422a3dfc1Jean-Michel Trivi // here rcse.mRcClientDeathHandler is null; 47703114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi rcse.resetPlaybackInfo(); 477126b3d1ff38998c7cb80a2950da0589ebd8510897Jean-Michel Trivi break; 477226b3d1ff38998c7cb80a2950da0589ebd8510897Jean-Michel Trivi } 47733114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi rccId = rcse.mRccId; 477426b3d1ff38998c7cb80a2950da0589ebd8510897Jean-Michel Trivi 477526b3d1ff38998c7cb80a2950da0589ebd8510897Jean-Michel Trivi // there is a new (non-null) client: 477626b3d1ff38998c7cb80a2950da0589ebd8510897Jean-Michel Trivi // 1/ give the new client the current display (if any) 47774426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi if (mRcDisplay != null) { 47784426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi try { 47794426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi rcse.mRcClient.plugRemoteControlDisplay(mRcDisplay); 47804426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi } catch (RemoteException e) { 47814426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi Log.e(TAG, "Error connecting remote control display to client: "+e); 47824426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi e.printStackTrace(); 47834426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi } 47844426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi } 478526b3d1ff38998c7cb80a2950da0589ebd8510897Jean-Michel Trivi // 2/ monitor the new client's death 478626b3d1ff38998c7cb80a2950da0589ebd8510897Jean-Michel Trivi IBinder b = rcse.mRcClient.asBinder(); 47878f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi RcClientDeathHandler rcdh = 4788f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi new RcClientDeathHandler(b, rcse.mMediaIntent); 47898f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi try { 47908f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi b.linkToDeath(rcdh, 0); 47918f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi } catch (RemoteException e) { 47928f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi // remote control client is DOA, disqualify it 47938f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi Log.w(TAG, "registerRemoteControlClient() has a dead client " + b); 479417da769e987de40e113c5b2a3b867b25ba7ac0a2Jean-Michel Trivi rcse.mRcClient = null; 47958f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi } 47968f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi rcse.mRcClientDeathHandler = rcdh; 47978f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi break; 47988f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi } 47998f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi } 48008f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi // if the eventReceiver is at the top of the stack 48018f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi // then check for potential refresh of the remote controls 4802f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi if (isCurrentRcController(mediaIntent)) { 4803b716f0b7b2d8e4b045843fc6a7004910eb344c19Jean-Michel Trivi checkUpdateRemoteControlDisplay_syncAfRcs(RC_INFO_ALL); 48048f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi } 48058f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi } 48068f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi } 48073114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi return rccId; 48088f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi } 48098f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi 48104b6df6a3dcbd9990e36438c529fa8c16b2580df9Jean-Michel Trivi /** 4811f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi * see AudioManager.unregisterRemoteControlClient(PendingIntent pi, ...) 48124b6df6a3dcbd9990e36438c529fa8c16b2580df9Jean-Michel Trivi * rcClient is guaranteed non-null 48134b6df6a3dcbd9990e36438c529fa8c16b2580df9Jean-Michel Trivi */ 4814f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi public void unregisterRemoteControlClient(PendingIntent mediaIntent, 48154426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi IRemoteControlClient rcClient) { 48164b6df6a3dcbd9990e36438c529fa8c16b2580df9Jean-Michel Trivi synchronized(mAudioFocusLock) { 48174b6df6a3dcbd9990e36438c529fa8c16b2580df9Jean-Michel Trivi synchronized(mRCStack) { 48184b6df6a3dcbd9990e36438c529fa8c16b2580df9Jean-Michel Trivi Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator(); 48194b6df6a3dcbd9990e36438c529fa8c16b2580df9Jean-Michel Trivi while(stackIterator.hasNext()) { 48204b6df6a3dcbd9990e36438c529fa8c16b2580df9Jean-Michel Trivi RemoteControlStackEntry rcse = stackIterator.next(); 4821f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi if ((rcse.mMediaIntent.equals(mediaIntent)) 48224b6df6a3dcbd9990e36438c529fa8c16b2580df9Jean-Michel Trivi && rcClient.equals(rcse.mRcClient)) { 48234b6df6a3dcbd9990e36438c529fa8c16b2580df9Jean-Michel Trivi // we found the IRemoteControlClient to unregister 48244b6df6a3dcbd9990e36438c529fa8c16b2580df9Jean-Michel Trivi // stop monitoring its death 48254b6df6a3dcbd9990e36438c529fa8c16b2580df9Jean-Michel Trivi rcse.unlinkToRcClientDeath(); 48264b6df6a3dcbd9990e36438c529fa8c16b2580df9Jean-Michel Trivi // reset the client-related fields 48274b6df6a3dcbd9990e36438c529fa8c16b2580df9Jean-Michel Trivi rcse.mRcClient = null; 48284b6df6a3dcbd9990e36438c529fa8c16b2580df9Jean-Michel Trivi rcse.mCallingPackageName = null; 48294b6df6a3dcbd9990e36438c529fa8c16b2580df9Jean-Michel Trivi } 48304b6df6a3dcbd9990e36438c529fa8c16b2580df9Jean-Michel Trivi } 48314b6df6a3dcbd9990e36438c529fa8c16b2580df9Jean-Michel Trivi } 48324b6df6a3dcbd9990e36438c529fa8c16b2580df9Jean-Michel Trivi } 48334426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi } 48344426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi 48354426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi /** 48364426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi * The remote control displays. 48374426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi * Access synchronized on mRCStack 48384426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi * NOTE: Only one IRemoteControlDisplay supported in this implementation 48394426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi */ 48404426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi private IRemoteControlDisplay mRcDisplay; 48414426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi private RcDisplayDeathHandler mRcDisplayDeathHandler; 48424426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi private int mArtworkExpectedWidth = -1; 48434426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi private int mArtworkExpectedHeight = -1; 48444426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi /** 48454426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi * Inner class to monitor remote control display deaths, and unregister them from the list 48464426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi * of displays if necessary. 48474426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi */ 48484426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi private class RcDisplayDeathHandler implements IBinder.DeathRecipient { 484918e7bce52318f00b5023f33933a571c477f2b61cJean-Michel Trivi private IBinder mCb; // To be notified of client's death 485018e7bce52318f00b5023f33933a571c477f2b61cJean-Michel Trivi 485118e7bce52318f00b5023f33933a571c477f2b61cJean-Michel Trivi public RcDisplayDeathHandler(IBinder b) { 485218e7bce52318f00b5023f33933a571c477f2b61cJean-Michel Trivi if (DEBUG_RC) Log.i(TAG, "new RcDisplayDeathHandler for "+b); 485318e7bce52318f00b5023f33933a571c477f2b61cJean-Michel Trivi mCb = b; 485418e7bce52318f00b5023f33933a571c477f2b61cJean-Michel Trivi } 485518e7bce52318f00b5023f33933a571c477f2b61cJean-Michel Trivi 48564426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi public void binderDied() { 48578f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi synchronized(mRCStack) { 485818e7bce52318f00b5023f33933a571c477f2b61cJean-Michel Trivi Log.w(TAG, "RemoteControl: display died"); 48594426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi mRcDisplay = null; 48604426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi } 48614426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi } 48624426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi 486318e7bce52318f00b5023f33933a571c477f2b61cJean-Michel Trivi public void unlinkToRcDisplayDeath() { 486418e7bce52318f00b5023f33933a571c477f2b61cJean-Michel Trivi if (DEBUG_RC) Log.i(TAG, "unlinkToRcDisplayDeath for "+mCb); 48654426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi try { 486618e7bce52318f00b5023f33933a571c477f2b61cJean-Michel Trivi mCb.unlinkToDeath(this, 0); 48674426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi } catch (java.util.NoSuchElementException e) { 486818e7bce52318f00b5023f33933a571c477f2b61cJean-Michel Trivi // not much we can do here, the display was being unregistered anyway 486918e7bce52318f00b5023f33933a571c477f2b61cJean-Michel Trivi Log.e(TAG, "Encountered " + e + " in unlinkToRcDisplayDeath()"); 48704426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi e.printStackTrace(); 48714426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi } 48724426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi } 487318e7bce52318f00b5023f33933a571c477f2b61cJean-Michel Trivi 487418e7bce52318f00b5023f33933a571c477f2b61cJean-Michel Trivi } 487518e7bce52318f00b5023f33933a571c477f2b61cJean-Michel Trivi 487618e7bce52318f00b5023f33933a571c477f2b61cJean-Michel Trivi private void rcDisplay_stopDeathMonitor_syncRcStack() { 487718e7bce52318f00b5023f33933a571c477f2b61cJean-Michel Trivi if (mRcDisplay != null) { // implies (mRcDisplayDeathHandler != null) 487818e7bce52318f00b5023f33933a571c477f2b61cJean-Michel Trivi // we had a display before, stop monitoring its death 487918e7bce52318f00b5023f33933a571c477f2b61cJean-Michel Trivi mRcDisplayDeathHandler.unlinkToRcDisplayDeath(); 488018e7bce52318f00b5023f33933a571c477f2b61cJean-Michel Trivi } 48814426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi } 48824426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi 48834426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi private void rcDisplay_startDeathMonitor_syncRcStack() { 48844426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi if (mRcDisplay != null) { 48854426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi // new non-null display, monitor its death 48864426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi IBinder b = mRcDisplay.asBinder(); 488718e7bce52318f00b5023f33933a571c477f2b61cJean-Michel Trivi mRcDisplayDeathHandler = new RcDisplayDeathHandler(b); 48884426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi try { 48894426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi b.linkToDeath(mRcDisplayDeathHandler, 0); 48904426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi } catch (RemoteException e) { 48914426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi // remote control display is DOA, disqualify it 48924426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi Log.w(TAG, "registerRemoteControlDisplay() has a dead client " + b); 48934426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi mRcDisplay = null; 48944426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi } 48954426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi } 48964426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi } 48974426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi 489818e7bce52318f00b5023f33933a571c477f2b61cJean-Michel Trivi /** 4899958bba6862c9540c528263686b0de044b4a7a5f6Jean-Michel Trivi * Register an IRemoteControlDisplay. 4900958bba6862c9540c528263686b0de044b4a7a5f6Jean-Michel Trivi * Notify all IRemoteControlClient of the new display and cause the RemoteControlClient 4901958bba6862c9540c528263686b0de044b4a7a5f6Jean-Michel Trivi * at the top of the stack to update the new display with its information. 490218e7bce52318f00b5023f33933a571c477f2b61cJean-Michel Trivi * Since only one IRemoteControlDisplay is supported, this will unregister the previous display. 490318e7bce52318f00b5023f33933a571c477f2b61cJean-Michel Trivi * @param rcd the IRemoteControlDisplay to register. No effect if null. 490418e7bce52318f00b5023f33933a571c477f2b61cJean-Michel Trivi */ 49054426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi public void registerRemoteControlDisplay(IRemoteControlDisplay rcd) { 490618e7bce52318f00b5023f33933a571c477f2b61cJean-Michel Trivi if (DEBUG_RC) Log.d(TAG, ">>> registerRemoteControlDisplay("+rcd+")"); 4907b716f0b7b2d8e4b045843fc6a7004910eb344c19Jean-Michel Trivi synchronized(mAudioFocusLock) { 4908b716f0b7b2d8e4b045843fc6a7004910eb344c19Jean-Michel Trivi synchronized(mRCStack) { 4909b716f0b7b2d8e4b045843fc6a7004910eb344c19Jean-Michel Trivi if ((mRcDisplay == rcd) || (rcd == null)) { 4910b716f0b7b2d8e4b045843fc6a7004910eb344c19Jean-Michel Trivi return; 4911b716f0b7b2d8e4b045843fc6a7004910eb344c19Jean-Michel Trivi } 4912b716f0b7b2d8e4b045843fc6a7004910eb344c19Jean-Michel Trivi // if we had a display before, stop monitoring its death 4913b716f0b7b2d8e4b045843fc6a7004910eb344c19Jean-Michel Trivi rcDisplay_stopDeathMonitor_syncRcStack(); 4914b716f0b7b2d8e4b045843fc6a7004910eb344c19Jean-Michel Trivi mRcDisplay = rcd; 4915b716f0b7b2d8e4b045843fc6a7004910eb344c19Jean-Michel Trivi // new display, start monitoring its death 4916b716f0b7b2d8e4b045843fc6a7004910eb344c19Jean-Michel Trivi rcDisplay_startDeathMonitor_syncRcStack(); 49174426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi 4918b716f0b7b2d8e4b045843fc6a7004910eb344c19Jean-Michel Trivi // let all the remote control clients there is a new display 4919b716f0b7b2d8e4b045843fc6a7004910eb344c19Jean-Michel Trivi // no need to unplug the previous because we only support one display 4920b716f0b7b2d8e4b045843fc6a7004910eb344c19Jean-Michel Trivi // and the clients don't track the death of the display 4921b716f0b7b2d8e4b045843fc6a7004910eb344c19Jean-Michel Trivi Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator(); 4922b716f0b7b2d8e4b045843fc6a7004910eb344c19Jean-Michel Trivi while(stackIterator.hasNext()) { 4923b716f0b7b2d8e4b045843fc6a7004910eb344c19Jean-Michel Trivi RemoteControlStackEntry rcse = stackIterator.next(); 4924b716f0b7b2d8e4b045843fc6a7004910eb344c19Jean-Michel Trivi if(rcse.mRcClient != null) { 4925b716f0b7b2d8e4b045843fc6a7004910eb344c19Jean-Michel Trivi try { 4926b716f0b7b2d8e4b045843fc6a7004910eb344c19Jean-Michel Trivi rcse.mRcClient.plugRemoteControlDisplay(mRcDisplay); 4927b716f0b7b2d8e4b045843fc6a7004910eb344c19Jean-Michel Trivi } catch (RemoteException e) { 4928b716f0b7b2d8e4b045843fc6a7004910eb344c19Jean-Michel Trivi Log.e(TAG, "Error connecting remote control display to client: " + e); 4929b716f0b7b2d8e4b045843fc6a7004910eb344c19Jean-Michel Trivi e.printStackTrace(); 4930b716f0b7b2d8e4b045843fc6a7004910eb344c19Jean-Michel Trivi } 49314426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi } 49328f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi } 4933db8a361629f06f62b9e1c40d4413b3b5099bd124Jean-Michel Trivi 4934338794576667745b060ac269b2c2b36e0c6964f2Jean-Michel Trivi // we have a new display, of which all the clients are now aware: have it be updated 4935b716f0b7b2d8e4b045843fc6a7004910eb344c19Jean-Michel Trivi checkUpdateRemoteControlDisplay_syncAfRcs(RC_INFO_ALL); 4936338794576667745b060ac269b2c2b36e0c6964f2Jean-Michel Trivi } 49378f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi } 49388f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi } 4939d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi 494018e7bce52318f00b5023f33933a571c477f2b61cJean-Michel Trivi /** 494118e7bce52318f00b5023f33933a571c477f2b61cJean-Michel Trivi * Unregister an IRemoteControlDisplay. 494218e7bce52318f00b5023f33933a571c477f2b61cJean-Michel Trivi * Since only one IRemoteControlDisplay is supported, this has no effect if the one to 494318e7bce52318f00b5023f33933a571c477f2b61cJean-Michel Trivi * unregister is not the current one. 494418e7bce52318f00b5023f33933a571c477f2b61cJean-Michel Trivi * @param rcd the IRemoteControlDisplay to unregister. No effect if null. 494518e7bce52318f00b5023f33933a571c477f2b61cJean-Michel Trivi */ 49464426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi public void unregisterRemoteControlDisplay(IRemoteControlDisplay rcd) { 494718e7bce52318f00b5023f33933a571c477f2b61cJean-Michel Trivi if (DEBUG_RC) Log.d(TAG, "<<< unregisterRemoteControlDisplay("+rcd+")"); 49484426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi synchronized(mRCStack) { 494918e7bce52318f00b5023f33933a571c477f2b61cJean-Michel Trivi // only one display here, so you can only unregister the current display 495018e7bce52318f00b5023f33933a571c477f2b61cJean-Michel Trivi if ((rcd == null) || (rcd != mRcDisplay)) { 495118e7bce52318f00b5023f33933a571c477f2b61cJean-Michel Trivi if (DEBUG_RC) Log.w(TAG, " trying to unregister unregistered RCD"); 495218e7bce52318f00b5023f33933a571c477f2b61cJean-Michel Trivi return; 495318e7bce52318f00b5023f33933a571c477f2b61cJean-Michel Trivi } 49544426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi // if we had a display before, stop monitoring its death 49554426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi rcDisplay_stopDeathMonitor_syncRcStack(); 49564426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi mRcDisplay = null; 49574426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi 49584426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi // disconnect this remote control display from all the clients 49594426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator(); 49604426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi while(stackIterator.hasNext()) { 49614426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi RemoteControlStackEntry rcse = stackIterator.next(); 49624426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi if(rcse.mRcClient != null) { 49634426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi try { 49644426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi rcse.mRcClient.unplugRemoteControlDisplay(rcd); 49654426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi } catch (RemoteException e) { 49664426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi Log.e(TAG, "Error disconnecting remote control display to client: " + e); 49674426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi e.printStackTrace(); 49684426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi } 49694426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi } 49704426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi } 49714426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi } 49724426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi } 49734426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi 49744426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi public void remoteControlDisplayUsesBitmapSize(IRemoteControlDisplay rcd, int w, int h) { 49754426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi synchronized(mRCStack) { 49764426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi // NOTE: Only one IRemoteControlDisplay supported in this implementation 49774426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi mArtworkExpectedWidth = w; 49784426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi mArtworkExpectedHeight = h; 49794426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi } 49804426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi } 49814426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi 49823114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi public void setPlaybackInfoForRcc(int rccId, int what, int value) { 4983f98de1e8dd6dcbd191921b4aa07a1d41b0b9db91Jean-Michel Trivi sendMsg(mAudioHandler, MSG_RCC_NEW_PLAYBACK_INFO, SENDMSG_QUEUE, 4984f98de1e8dd6dcbd191921b4aa07a1d41b0b9db91Jean-Michel Trivi rccId /* arg1 */, what /* arg2 */, Integer.valueOf(value) /* obj */, 0 /* delay */); 4985f98de1e8dd6dcbd191921b4aa07a1d41b0b9db91Jean-Michel Trivi } 4986f98de1e8dd6dcbd191921b4aa07a1d41b0b9db91Jean-Michel Trivi 4987f98de1e8dd6dcbd191921b4aa07a1d41b0b9db91Jean-Michel Trivi // handler for MSG_RCC_NEW_PLAYBACK_INFO 4988f98de1e8dd6dcbd191921b4aa07a1d41b0b9db91Jean-Michel Trivi private void onNewPlaybackInfoForRcc(int rccId, int key, int value) { 4989f98de1e8dd6dcbd191921b4aa07a1d41b0b9db91Jean-Michel Trivi if(DEBUG_RC) Log.d(TAG, "onNewPlaybackInfoForRcc(id=" + rccId + 4990f98de1e8dd6dcbd191921b4aa07a1d41b0b9db91Jean-Michel Trivi ", what=" + key + ",val=" + value + ")"); 49913114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi synchronized(mRCStack) { 49923114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator(); 49933114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi while(stackIterator.hasNext()) { 49943114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi RemoteControlStackEntry rcse = stackIterator.next(); 49953114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi if (rcse.mRccId == rccId) { 4996f98de1e8dd6dcbd191921b4aa07a1d41b0b9db91Jean-Michel Trivi switch (key) { 49973114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi case RemoteControlClient.PLAYBACKINFO_PLAYBACK_TYPE: 49983114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi rcse.mPlaybackType = value; 49993114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi postReevaluateRemote(); 50003114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi break; 50013114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi case RemoteControlClient.PLAYBACKINFO_VOLUME: 50023114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi rcse.mPlaybackVolume = value; 50033114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi synchronized (mMainRemote) { 50043114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi if (rccId == mMainRemote.mRccId) { 50053114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi mMainRemote.mVolume = value; 50063114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi mVolumePanel.postHasNewRemotePlaybackInfo(); 50073114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi } 50083114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi } 50093114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi break; 50103114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi case RemoteControlClient.PLAYBACKINFO_VOLUME_MAX: 50113114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi rcse.mPlaybackVolumeMax = value; 50123114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi synchronized (mMainRemote) { 50133114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi if (rccId == mMainRemote.mRccId) { 50143114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi mMainRemote.mVolumeMax = value; 50153114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi mVolumePanel.postHasNewRemotePlaybackInfo(); 50163114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi } 50173114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi } 50183114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi break; 50193114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi case RemoteControlClient.PLAYBACKINFO_VOLUME_HANDLING: 50203114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi rcse.mPlaybackVolumeHandling = value; 50213114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi synchronized (mMainRemote) { 50223114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi if (rccId == mMainRemote.mRccId) { 50233114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi mMainRemote.mVolumeHandling = value; 50243114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi mVolumePanel.postHasNewRemotePlaybackInfo(); 50253114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi } 50263114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi } 50273114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi break; 50283114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi case RemoteControlClient.PLAYBACKINFO_USES_STREAM: 50293114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi rcse.mPlaybackStream = value; 50303114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi break; 50313114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi case RemoteControlClient.PLAYBACKINFO_PLAYSTATE: 50323114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi rcse.mPlaybackState = value; 50333114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi synchronized (mMainRemote) { 50343114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi if (rccId == mMainRemote.mRccId) { 50353114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi mMainRemoteIsActive = isPlaystateActive(value); 50363114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi postReevaluateRemote(); 50373114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi } 50383114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi } 50393114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi break; 50403114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi default: 5041f98de1e8dd6dcbd191921b4aa07a1d41b0b9db91Jean-Michel Trivi Log.e(TAG, "unhandled key " + key + " for RCC " + rccId); 50423114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi break; 50433114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi } 50443114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi return; 50453114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi } 50463114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi } 50473114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi } 50483114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi } 50493114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi 50501357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi public void registerRemoteVolumeObserverForRcc(int rccId, IRemoteVolumeObserver rvo) { 5051f98de1e8dd6dcbd191921b4aa07a1d41b0b9db91Jean-Michel Trivi sendMsg(mAudioHandler, MSG_RCC_NEW_VOLUME_OBS, SENDMSG_QUEUE, 5052f98de1e8dd6dcbd191921b4aa07a1d41b0b9db91Jean-Michel Trivi rccId /* arg1 */, 0, rvo /* obj */, 0 /* delay */); 5053f98de1e8dd6dcbd191921b4aa07a1d41b0b9db91Jean-Michel Trivi } 5054f98de1e8dd6dcbd191921b4aa07a1d41b0b9db91Jean-Michel Trivi 5055f98de1e8dd6dcbd191921b4aa07a1d41b0b9db91Jean-Michel Trivi // handler for MSG_RCC_NEW_VOLUME_OBS 5056f98de1e8dd6dcbd191921b4aa07a1d41b0b9db91Jean-Michel Trivi private void onRegisterVolumeObserverForRcc(int rccId, IRemoteVolumeObserver rvo) { 50571357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi synchronized(mRCStack) { 50581357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator(); 50591357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi while(stackIterator.hasNext()) { 50601357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi RemoteControlStackEntry rcse = stackIterator.next(); 50611357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi if (rcse.mRccId == rccId) { 50621357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi rcse.mRemoteVolumeObs = rvo; 50631357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi break; 50641357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 50651357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 50661357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 50671357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 50681357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi 50693114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi /** 50703114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi * Checks if a remote client is active on the supplied stream type. Update the remote stream 50713114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi * volume state if found and playing 50723114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi * @param streamType 50733114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi * @return false if no remote playing is currently playing 50743114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi */ 50753114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi private boolean checkUpdateRemoteStateIfActive(int streamType) { 50763114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi synchronized(mRCStack) { 50773114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator(); 50783114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi while(stackIterator.hasNext()) { 50793114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi RemoteControlStackEntry rcse = stackIterator.next(); 50803114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi if ((rcse.mPlaybackType == RemoteControlClient.PLAYBACK_TYPE_REMOTE) 50813114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi && isPlaystateActive(rcse.mPlaybackState) 50823114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi && (rcse.mPlaybackStream == streamType)) { 50833114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi if (DEBUG_RC) Log.d(TAG, "remote playback active on stream " + streamType 50843114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi + ", vol =" + rcse.mPlaybackVolume); 50853114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi synchronized (mMainRemote) { 50863114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi mMainRemote.mRccId = rcse.mRccId; 50873114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi mMainRemote.mVolume = rcse.mPlaybackVolume; 50883114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi mMainRemote.mVolumeMax = rcse.mPlaybackVolumeMax; 50893114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi mMainRemote.mVolumeHandling = rcse.mPlaybackVolumeHandling; 50903114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi mMainRemoteIsActive = true; 50913114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi } 50923114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi return true; 50933114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi } 50943114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi } 50953114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi } 50963114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi synchronized (mMainRemote) { 50973114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi mMainRemoteIsActive = false; 50983114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi } 50993114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi return false; 51003114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi } 51013114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi 51023114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi /** 51033114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi * Returns true if the given playback state is considered "active", i.e. it describes a state 51043114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi * where playback is happening, or about to 51053114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi * @param playState the playback state to evaluate 51063114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi * @return true if active, false otherwise (inactive or unknown) 51073114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi */ 51083114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi private static boolean isPlaystateActive(int playState) { 51093114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi switch (playState) { 51103114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi case RemoteControlClient.PLAYSTATE_PLAYING: 51113114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi case RemoteControlClient.PLAYSTATE_BUFFERING: 51123114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi case RemoteControlClient.PLAYSTATE_FAST_FORWARDING: 51133114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi case RemoteControlClient.PLAYSTATE_REWINDING: 51143114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi case RemoteControlClient.PLAYSTATE_SKIPPING_BACKWARDS: 51153114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi case RemoteControlClient.PLAYSTATE_SKIPPING_FORWARDS: 51163114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi return true; 51173114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi default: 51183114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi return false; 51193114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi } 51203114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi } 51213114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi 51223114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi private void adjustRemoteVolume(int streamType, int direction, int flags) { 51233114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi int rccId = RemoteControlClient.RCSE_ID_UNREGISTERED; 51243114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi boolean volFixed = false; 51253114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi synchronized (mMainRemote) { 51263114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi if (!mMainRemoteIsActive) { 51273114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi if (DEBUG_VOL) Log.w(TAG, "adjustRemoteVolume didn't find an active client"); 51283114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi return; 51293114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi } 51303114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi rccId = mMainRemote.mRccId; 51313114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi volFixed = (mMainRemote.mVolumeHandling == 51323114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi RemoteControlClient.PLAYBACK_VOLUME_FIXED); 51333114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi } 51343114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi // unlike "local" stream volumes, we can't compute the new volume based on the direction, 51353114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi // we can only notify the remote that volume needs to be updated, and we'll get an async' 51363114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi // update through setPlaybackInfoForRcc() 51373114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi if (!volFixed) { 51383114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi sendVolumeUpdateToRemote(rccId, direction); 51393114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi } 51403114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi 51413114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi // fire up the UI 51423114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi mVolumePanel.postRemoteVolumeChanged(streamType, flags); 51433114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi } 51443114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi 51453114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi private void sendVolumeUpdateToRemote(int rccId, int direction) { 51463114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi if (DEBUG_VOL) { Log.d(TAG, "sendVolumeUpdateToRemote(rccId="+rccId+" , dir="+direction); } 51473114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi if (direction == 0) { 51483114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi // only handling discrete events 51493114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi return; 51503114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi } 51511357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi IRemoteVolumeObserver rvo = null; 51523114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi synchronized (mRCStack) { 51533114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator(); 51543114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi while(stackIterator.hasNext()) { 51553114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi RemoteControlStackEntry rcse = stackIterator.next(); 51563114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi //FIXME OPTIMIZE store this info in mMainRemote so we don't have to iterate? 51573114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi if (rcse.mRccId == rccId) { 51581357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi rvo = rcse.mRemoteVolumeObs; 51593114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi break; 51603114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi } 51613114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi } 51623114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi } 51631357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi if (rvo != null) { 51641357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi try { 51651357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi rvo.dispatchRemoteVolumeUpdate(direction, -1); 51661357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } catch (RemoteException e) { 51671357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi Log.e(TAG, "Error dispatching relative volume update", e); 51681357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 51693114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi } 51703114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi } 51713114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi 51723114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi public int getRemoteStreamMaxVolume() { 51733114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi synchronized (mMainRemote) { 51743114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi if (mMainRemote.mRccId == RemoteControlClient.RCSE_ID_UNREGISTERED) { 51753114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi return 0; 51763114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi } 51773114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi return mMainRemote.mVolumeMax; 51783114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi } 51793114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi } 51803114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi 51813114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi public int getRemoteStreamVolume() { 51823114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi synchronized (mMainRemote) { 51833114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi if (mMainRemote.mRccId == RemoteControlClient.RCSE_ID_UNREGISTERED) { 51843114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi return 0; 51853114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi } 51863114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi return mMainRemote.mVolume; 51873114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi } 51883114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi } 51893114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi 51903114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi public void setRemoteStreamVolume(int vol) { 51913114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi if (DEBUG_VOL) { Log.d(TAG, "setRemoteStreamVolume(vol="+vol+")"); } 51923114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi int rccId = RemoteControlClient.RCSE_ID_UNREGISTERED; 51933114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi synchronized (mMainRemote) { 51943114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi if (mMainRemote.mRccId == RemoteControlClient.RCSE_ID_UNREGISTERED) { 51953114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi return; 51963114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi } 51973114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi rccId = mMainRemote.mRccId; 51983114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi } 51991357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi IRemoteVolumeObserver rvo = null; 52003114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi synchronized (mRCStack) { 52013114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator(); 52023114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi while(stackIterator.hasNext()) { 52033114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi RemoteControlStackEntry rcse = stackIterator.next(); 52043114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi if (rcse.mRccId == rccId) { 52053114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi //FIXME OPTIMIZE store this info in mMainRemote so we don't have to iterate? 52061357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi rvo = rcse.mRemoteVolumeObs; 52073114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi break; 52083114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi } 52093114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi } 52103114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi } 52111357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi if (rvo != null) { 52121357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi try { 52131357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi rvo.dispatchRemoteVolumeUpdate(0, vol); 52141357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } catch (RemoteException e) { 52151357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi Log.e(TAG, "Error dispatching absolute volume update", e); 52161357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi } 52173114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi } 52183114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi } 52193114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi 52203114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi /** 52213114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi * Call to make AudioService reevaluate whether it's in a mode where remote players should 52223114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi * have their volume controlled. In this implementation this is only to reset whether 52233114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi * VolumePanel should display remote volumes 52243114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi */ 52253114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi private void postReevaluateRemote() { 52263114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi sendMsg(mAudioHandler, MSG_REEVALUATE_REMOTE, SENDMSG_QUEUE, 0, 0, null, 0); 52273114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi } 52283114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi 52293114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi private void onReevaluateRemote() { 52303114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi if (DEBUG_VOL) { Log.w(TAG, "onReevaluateRemote()"); } 52313114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi // is there a registered RemoteControlClient that is handling remote playback 52323114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi boolean hasRemotePlayback = false; 52333114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi synchronized (mRCStack) { 52343114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator(); 52353114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi while(stackIterator.hasNext()) { 52363114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi RemoteControlStackEntry rcse = stackIterator.next(); 52373114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi if (rcse.mPlaybackType == RemoteControlClient.PLAYBACK_TYPE_REMOTE) { 52383114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi hasRemotePlayback = true; 52393114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi break; 52403114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi } 52413114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi } 52423114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi } 52433114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi synchronized (mMainRemote) { 52443114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi if (mHasRemotePlayback != hasRemotePlayback) { 52453114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi mHasRemotePlayback = hasRemotePlayback; 52463114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi mVolumePanel.postRemoteSliderVisibility(hasRemotePlayback); 52473114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi } 52483114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi } 52493114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi } 52503114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi 5251f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi //========================================================================================== 5252f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi // Device orientation 5253f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi //========================================================================================== 5254f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi /** 5255f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi * Handles device configuration changes that may map to a change in the orientation. 5256f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi * This feature is optional, and is defined by the definition and value of the 5257f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi * "ro.audio.monitorOrientation" system property. 5258f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi */ 5259f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi private void handleConfigurationChanged(Context context) { 5260f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi try { 5261f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi // reading new orientation "safely" (i.e. under try catch) in case anything 5262f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi // goes wrong when obtaining resources and configuration 5263f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi int newOrientation = context.getResources().getConfiguration().orientation; 5264f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi if (newOrientation != mDeviceOrientation) { 5265f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi mDeviceOrientation = newOrientation; 5266f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi setOrientationForAudioSystem(); 5267f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi } 5268f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi } catch (Exception e) { 5269f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi Log.e(TAG, "Error retrieving device orientation: " + e); 5270f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi } 5271f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi } 5272f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi 5273f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi private void setOrientationForAudioSystem() { 5274f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi switch (mDeviceOrientation) { 5275f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi case Configuration.ORIENTATION_LANDSCAPE: 5276f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi //Log.i(TAG, "orientation is landscape"); 5277f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi AudioSystem.setParameters("orientation=landscape"); 5278f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi break; 5279f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi case Configuration.ORIENTATION_PORTRAIT: 5280f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi //Log.i(TAG, "orientation is portrait"); 5281f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi AudioSystem.setParameters("orientation=portrait"); 5282f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi break; 5283f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi case Configuration.ORIENTATION_SQUARE: 5284f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi //Log.i(TAG, "orientation is square"); 5285f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi AudioSystem.setParameters("orientation=square"); 5286f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi break; 5287f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi case Configuration.ORIENTATION_UNDEFINED: 5288f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi //Log.i(TAG, "orientation is undefined"); 5289f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi AudioSystem.setParameters("orientation=undefined"); 5290f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi break; 5291f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi default: 5292f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi Log.e(TAG, "Unknown orientation"); 5293f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi } 5294f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi } 5295f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi 5296f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi 52977847211fb4699bf6018e29d214a918ed6657319bEric Laurent // Handles request to override default use of A2DP for media. 52987847211fb4699bf6018e29d214a918ed6657319bEric Laurent public void setBluetoothA2dpOnInt(boolean on) { 52997847211fb4699bf6018e29d214a918ed6657319bEric Laurent synchronized (mBluetoothA2dpEnabledLock) { 53007847211fb4699bf6018e29d214a918ed6657319bEric Laurent mBluetoothA2dpEnabled = on; 5301c390bed06b4a572e273ead1254da9a932e04dce3Eric Laurent mAudioHandler.removeMessages(MSG_SET_FORCE_BT_A2DP_USE); 5302c390bed06b4a572e273ead1254da9a932e04dce3Eric Laurent AudioSystem.setForceUse(AudioSystem.FOR_MEDIA, 5303c390bed06b4a572e273ead1254da9a932e04dce3Eric Laurent mBluetoothA2dpEnabled ? AudioSystem.FORCE_NONE : AudioSystem.FORCE_NO_BT_A2DP); 53047847211fb4699bf6018e29d214a918ed6657319bEric Laurent } 53057847211fb4699bf6018e29d214a918ed6657319bEric Laurent } 53067847211fb4699bf6018e29d214a918ed6657319bEric Laurent 5307d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi @Override 5308098d580cc2bb6c0891c756a4e5230c6c6b0d2376Jeff Sharkey public void setRingtonePlayer(IRingtonePlayer player) { 5309098d580cc2bb6c0891c756a4e5230c6c6b0d2376Jeff Sharkey mContext.enforceCallingOrSelfPermission(REMOTE_AUDIO_PLAYBACK, null); 5310098d580cc2bb6c0891c756a4e5230c6c6b0d2376Jeff Sharkey mRingtonePlayer = player; 5311098d580cc2bb6c0891c756a4e5230c6c6b0d2376Jeff Sharkey } 5312098d580cc2bb6c0891c756a4e5230c6c6b0d2376Jeff Sharkey 5313098d580cc2bb6c0891c756a4e5230c6c6b0d2376Jeff Sharkey @Override 5314098d580cc2bb6c0891c756a4e5230c6c6b0d2376Jeff Sharkey public IRingtonePlayer getRingtonePlayer() { 5315098d580cc2bb6c0891c756a4e5230c6c6b0d2376Jeff Sharkey return mRingtonePlayer; 5316098d580cc2bb6c0891c756a4e5230c6c6b0d2376Jeff Sharkey } 5317098d580cc2bb6c0891c756a4e5230c6c6b0d2376Jeff Sharkey 5318098d580cc2bb6c0891c756a4e5230c6c6b0d2376Jeff Sharkey @Override 5319632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn public AudioRoutesInfo startWatchingRoutes(IAudioRoutesObserver observer) { 5320632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn synchronized (mCurAudioRoutes) { 5321632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn AudioRoutesInfo routes = new AudioRoutesInfo(mCurAudioRoutes); 5322632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn mRoutesObservers.register(observer); 5323632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn return routes; 5324632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn } 5325632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn } 5326632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn 5327632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn @Override 5328d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 5329eb4cc492c93ab9635dde78b958a834120412e72aJeff Sharkey mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DUMP, TAG); 5330eb4cc492c93ab9635dde78b958a834120412e72aJeff Sharkey 5331d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi dumpFocusStack(pw); 5332d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi dumpRCStack(pw); 53333114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi dumpRCCStack(pw); 5334bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent dumpStreamStates(pw); 5335632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn pw.println("\nAudio routes:"); 5336632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn pw.print(" mMainType=0x"); pw.println(Integer.toHexString(mCurAudioRoutes.mMainType)); 5337632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn pw.print(" mBluetoothName="); pw.println(mCurAudioRoutes.mBluetoothName); 5338d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi } 53399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project} 5340