blob: 5d386bd5ba4877f81c7b89b35c09d323587f6f37 [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/*
2 * Copyright (C) 2006 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
John Spurlock61560172015-02-06 19:46:04 -050017package com.android.server.audio;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080018
Jeff Sharkey098d5802012-04-26 17:30:34 -070019import static android.Manifest.permission.REMOTE_AUDIO_PLAYBACK;
Amith Yamasanic696a532011-10-28 17:02:37 -070020import static android.media.AudioManager.RINGER_MODE_NORMAL;
21import static android.media.AudioManager.RINGER_MODE_SILENT;
22import static android.media.AudioManager.RINGER_MODE_VIBRATE;
23
Glenn Kastenfd116ad2013-07-12 17:10:39 -070024import android.app.ActivityManager;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080025import android.app.ActivityManagerNative;
Dianne Hackbornba50b97c2013-04-30 15:04:46 -070026import android.app.AppOpsManager;
Amith Yamasani6243edd2011-12-05 19:58:48 -080027import android.app.KeyguardManager;
Jaikumar Ganesh82aa7f02010-09-27 17:05:10 -070028import android.bluetooth.BluetoothA2dp;
29import android.bluetooth.BluetoothAdapter;
30import android.bluetooth.BluetoothClass;
31import android.bluetooth.BluetoothDevice;
32import android.bluetooth.BluetoothHeadset;
33import android.bluetooth.BluetoothProfile;
Nick Pellybd022f42009-08-14 18:33:38 -070034import android.content.BroadcastReceiver;
Jean-Michel Trivid327f212010-03-16 21:44:33 -070035import android.content.ComponentName;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080036import android.content.ContentResolver;
37import android.content.Context;
38import android.content.Intent;
Eric Laurenta553c252009-07-17 12:17:14 -070039import android.content.IntentFilter;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080040import android.content.pm.PackageManager;
Jean-Michel Trivif26f0172012-04-25 16:23:20 -070041import android.content.res.Configuration;
Eric Laurente78fced2013-03-15 16:03:47 -070042import android.content.res.Resources;
43import android.content.res.XmlResourceParser;
Jason Parekhb1096152009-03-24 17:48:25 -070044import android.database.ContentObserver;
Jungshik Jang41d97462014-06-30 22:26:29 +090045import android.hardware.hdmi.HdmiControlManager;
Eric Laurent212532b2014-07-21 15:43:18 -070046import android.hardware.hdmi.HdmiPlaybackClient;
Jungshik Jang41d97462014-06-30 22:26:29 +090047import android.hardware.hdmi.HdmiTvClient;
Paul McLeanc837a452014-04-09 09:04:43 -070048import android.hardware.usb.UsbManager;
John Spurlock61560172015-02-06 19:46:04 -050049import android.media.AudioAttributes;
50import android.media.AudioDevicePort;
51import android.media.AudioSystem;
52import android.media.AudioFormat;
53import android.media.AudioManager;
54import android.media.AudioManagerInternal;
55import android.media.AudioPort;
56import android.media.AudioRoutesInfo;
John Spurlock61560172015-02-06 19:46:04 -050057import android.media.IAudioFocusDispatcher;
58import android.media.IAudioRoutesObserver;
59import android.media.IAudioService;
60import android.media.IRemoteControlDisplay;
61import android.media.IRingtonePlayer;
62import android.media.IVolumeController;
63import android.media.MediaPlayer;
64import android.media.SoundPool;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080065import android.media.MediaPlayer.OnCompletionListener;
66import android.media.MediaPlayer.OnErrorListener;
Jean-Michel Trivi958876f2014-11-16 15:40:22 -080067import android.media.audiopolicy.AudioPolicy;
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -070068import android.media.audiopolicy.AudioPolicyConfig;
Jean-Michel Trivi0212be52014-11-24 14:43:10 -080069import android.media.audiopolicy.IAudioPolicyCallback;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080070import android.os.Binder;
Eric Laurentc18c9132013-04-12 17:24:56 -070071import android.os.Build;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080072import android.os.Environment;
73import android.os.Handler;
74import android.os.IBinder;
75import android.os.Looper;
76import android.os.Message;
Jean-Michel Trivic6802222012-04-30 11:15:03 -070077import android.os.PowerManager;
Dianne Hackborn632ca412012-06-14 19:34:10 -070078import android.os.RemoteCallbackList;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080079import android.os.RemoteException;
John Spurlock33f4e042014-07-11 13:10:58 -040080import android.os.SystemClock;
Jaikumar Ganesh82aa7f02010-09-27 17:05:10 -070081import android.os.SystemProperties;
Dianne Hackborn5ac72a22012-08-29 18:32:08 -070082import android.os.UserHandle;
Eric Laurentbffc3d12012-05-07 17:43:49 -070083import android.os.Vibrator;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080084import android.provider.Settings;
85import android.provider.Settings.System;
Tyler Gunnef9f6f92014-09-12 22:16:17 -070086import android.telecom.TelecomManager;
Dianne Hackborn632ca412012-06-14 19:34:10 -070087import android.text.TextUtils;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080088import android.util.Log;
John Spurlockaa5ee4d2014-07-25 13:05:12 -040089import android.util.MathUtils;
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -070090import android.util.Slog;
John Spurlock2bb02ec2015-03-02 13:13:06 -050091import android.util.SparseIntArray;
Jean-Michel Trivid327f212010-03-16 21:44:33 -070092import android.view.KeyEvent;
RoboErik519c7742014-11-18 10:59:09 -080093import android.view.OrientationEventListener;
Jean-Michel Trivibb6f8712013-05-23 15:02:41 -070094import android.view.Surface;
Jean-Michel Trivibb6f8712013-05-23 15:02:41 -070095import android.view.WindowManager;
Jean-Michel Trivi873cc452014-09-11 17:25:09 -070096import android.view.accessibility.AccessibilityManager;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080097
Eric Laurente78fced2013-03-15 16:03:47 -070098import com.android.internal.util.XmlUtils;
RoboErik0dac35a2014-08-12 15:48:49 -070099import com.android.server.LocalServices;
Eric Laurente78fced2013-03-15 16:03:47 -0700100
101import org.xmlpull.v1.XmlPullParserException;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800102
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -0800103import java.io.FileDescriptor;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800104import java.io.IOException;
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -0800105import java.io.PrintWriter;
Eric Laurente78fced2013-03-15 16:03:47 -0700106import java.lang.reflect.Field;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800107import java.util.ArrayList;
Eric Laurentc42ac9d2009-07-29 08:53:03 -0700108import java.util.HashMap;
109import java.util.Iterator;
Jaikumar Ganesh5a1e4cf2010-10-18 17:05:09 -0700110import java.util.List;
Eric Laurentc42ac9d2009-07-29 08:53:03 -0700111import java.util.Map;
Jaikumar Ganesh82aa7f02010-09-27 17:05:10 -0700112import java.util.NoSuchElementException;
RoboErikd09bd0c2014-06-24 17:45:19 -0700113import java.util.Objects;
Eric Laurentc42ac9d2009-07-29 08:53:03 -0700114import java.util.Set;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800115
116/**
117 * The implementation of the volume manager service.
118 * <p>
119 * This implementation focuses on delivering a responsive UI. Most methods are
120 * asynchronous to external calls. For example, the task of setting a volume
121 * will update our internal state, but in a separate thread will set the system
122 * volume and later persist to the database. Similarly, setting the ringer mode
123 * will update the state and broadcast a change and in a separate thread later
124 * persist the ringer mode.
125 *
126 * @hide
127 */
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700128public class AudioService extends IAudioService.Stub {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800129
130 private static final String TAG = "AudioService";
131
Jean-Michel Trivi339567d2014-07-29 09:53:34 -0700132 /** Debug audio mode */
133 protected static final boolean DEBUG_MODE = Log.isLoggable(TAG + ".MOD", Log.DEBUG);
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -0700134
135 /** Debug audio policy feature */
136 protected static final boolean DEBUG_AP = Log.isLoggable(TAG + ".AP", Log.DEBUG);
137
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -0700138 /** Debug volumes */
John Spurlockae641c92014-06-30 18:11:40 -0400139 protected static final boolean DEBUG_VOL = Log.isLoggable(TAG + ".VOL", Log.DEBUG);
Jean-Michel Trivi18e7bce2011-08-26 12:11:36 -0700140
RoboErik430fc482014-06-12 15:49:20 -0700141 /** debug calls to media session apis */
John Spurlockae641c92014-06-30 18:11:40 -0400142 private static final boolean DEBUG_SESSIONS = Log.isLoggable(TAG + ".SESSIONS", Log.DEBUG);
RoboErik8a2cfc32014-05-16 11:19:38 -0700143
John Spurlock86005342014-05-23 11:58:00 -0400144 /** Allow volume changes to set ringer mode to silent? */
145 private static final boolean VOLUME_SETS_RINGER_MODE_SILENT = false;
146
John Spurlocka11b4af2014-06-01 11:52:23 -0400147 /** In silent mode, are volume adjustments (raises) prevented? */
148 private static final boolean PREVENT_VOLUME_ADJUSTMENT_IF_SILENT = true;
149
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800150 /** How long to delay before persisting a change in volume/ringer mode. */
RoboErik45edba12012-03-27 17:54:36 -0700151 private static final int PERSIST_DELAY = 500;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800152
RoboErik5452e252015-02-06 15:33:53 -0800153 /** How long to delay after a volume down event before unmuting a stream */
154 private static final int UNMUTE_STREAM_DELAY = 350;
155
John Spurlock3346a802014-05-20 16:25:37 -0400156 /**
John Spurlocka11b4af2014-06-01 11:52:23 -0400157 * Only used in the result from {@link #checkForRingerModeChange(int, int, int)}
158 */
159 private static final int FLAG_ADJUST_VOLUME = 1;
160
Dianne Hackbornba50b97c2013-04-30 15:04:46 -0700161 private final Context mContext;
162 private final ContentResolver mContentResolver;
163 private final AppOpsManager mAppOps;
Eric Laurent212532b2014-07-21 15:43:18 -0700164
Eric Laurent212532b2014-07-21 15:43:18 -0700165 // the platform type affects volume and silent mode behavior
166 private final int mPlatformType;
167
168 private boolean isPlatformVoice() {
John Spurlock61560172015-02-06 19:46:04 -0500169 return mPlatformType == AudioSystem.PLATFORM_VOICE;
Eric Laurent212532b2014-07-21 15:43:18 -0700170 }
171
172 private boolean isPlatformTelevision() {
John Spurlock61560172015-02-06 19:46:04 -0500173 return mPlatformType == AudioSystem.PLATFORM_TELEVISION;
Eric Laurent212532b2014-07-21 15:43:18 -0700174 }
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -0800175
John Spurlock3346a802014-05-20 16:25:37 -0400176 /** The controller for the volume UI. */
177 private final VolumeController mVolumeController = new VolumeController();
John Spurlockcdb57ae2015-02-11 19:04:11 -0500178 private final ControllerService mControllerService = new ControllerService();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800179
180 // sendMsg() flags
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800181 /** If the msg is already queued, replace it with this one. */
182 private static final int SENDMSG_REPLACE = 0;
183 /** If the msg is already queued, ignore this one and leave the old. */
184 private static final int SENDMSG_NOOP = 1;
185 /** If the msg is already queued, queue this one and leave the old. */
186 private static final int SENDMSG_QUEUE = 2;
187
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -0700188 // AudioHandler messages
Eric Laurent9bc8358d2011-11-18 16:43:31 -0800189 private static final int MSG_SET_DEVICE_VOLUME = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800190 private static final int MSG_PERSIST_VOLUME = 1;
191 private static final int MSG_PERSIST_RINGER_MODE = 3;
Eric Laurentbffc3d12012-05-07 17:43:49 -0700192 private static final int MSG_MEDIA_SERVER_DIED = 4;
Eric Laurentdfb881f2013-07-18 14:41:39 -0700193 private static final int MSG_PLAY_SOUND_EFFECT = 5;
194 private static final int MSG_BTA2DP_DOCK_TIMEOUT = 6;
195 private static final int MSG_LOAD_SOUND_EFFECTS = 7;
196 private static final int MSG_SET_FORCE_USE = 8;
197 private static final int MSG_BT_HEADSET_CNCT_FAILED = 9;
198 private static final int MSG_SET_ALL_VOLUMES = 10;
199 private static final int MSG_PERSIST_MASTER_VOLUME_MUTE = 11;
200 private static final int MSG_REPORT_NEW_ROUTES = 12;
201 private static final int MSG_SET_FORCE_BT_A2DP_USE = 13;
202 private static final int MSG_CHECK_MUSIC_ACTIVE = 14;
203 private static final int MSG_BROADCAST_AUDIO_BECOMING_NOISY = 15;
204 private static final int MSG_CONFIGURE_SAFE_MEDIA_VOLUME = 16;
205 private static final int MSG_CONFIGURE_SAFE_MEDIA_VOLUME_FORCED = 17;
206 private static final int MSG_PERSIST_SAFE_VOLUME_STATE = 18;
207 private static final int MSG_BROADCAST_BT_CONNECTION_STATE = 19;
208 private static final int MSG_UNLOAD_SOUND_EFFECTS = 20;
Eric Laurent4a5eeb92014-05-06 10:49:04 -0700209 private static final int MSG_SYSTEM_READY = 21;
John Spurlockaa5ee4d2014-07-25 13:05:12 -0400210 private static final int MSG_PERSIST_MUSIC_ACTIVE_MS = 22;
Julia Reynoldsb53453f2014-08-22 11:42:43 -0400211 private static final int MSG_PERSIST_MICROPHONE_MUTE = 23;
RoboErik5452e252015-02-06 15:33:53 -0800212 private static final int MSG_UNMUTE_STREAM = 24;
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -0700213 // start of messages handled under wakelock
214 // these messages can only be queued, i.e. sent with queueMsgUnderWakeLock(),
Jean-Michel Trivie12c39b2012-06-06 10:51:58 -0700215 // and not with sendMsg(..., ..., SENDMSG_QUEUE, ...)
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700216 private static final int MSG_SET_WIRED_DEVICE_CONNECTION_STATE = 100;
Mike Lockwood0a40ec22014-05-21 10:08:50 -0700217 private static final int MSG_SET_A2DP_SRC_CONNECTION_STATE = 101;
218 private static final int MSG_SET_A2DP_SINK_CONNECTION_STATE = 102;
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -0700219 // end of messages handled under wakelock
Eric Laurentafbb0472011-12-15 09:04:23 -0800220
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -0700221 private static final int BTA2DP_DOCK_TIMEOUT_MILLIS = 8000;
Eric Laurentdc03c612011-04-01 10:59:41 -0700222 // Timeout for connection to bluetooth headset service
223 private static final int BT_HEADSET_CNCT_TIMEOUT_MS = 3000;
224
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800225 /** @see AudioSystemThread */
226 private AudioSystemThread mAudioSystemThread;
227 /** @see AudioHandler */
228 private AudioHandler mAudioHandler;
229 /** @see VolumeStreamState */
230 private VolumeStreamState[] mStreamStates;
Jason Parekhb1096152009-03-24 17:48:25 -0700231 private SettingsObserver mSettingsObserver;
Eric Laurenta553c252009-07-17 12:17:14 -0700232
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700233 private int mMode = AudioSystem.MODE_NORMAL;
Glenn Kastenba195eb2011-12-13 09:30:40 -0800234 // protects mRingerMode
235 private final Object mSettingsLock = new Object();
Eric Laurent45c90ce2012-04-24 18:44:22 -0700236
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800237 private SoundPool mSoundPool;
Glenn Kasten30c918c2011-11-10 17:56:41 -0800238 private final Object mSoundEffectsLock = new Object();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800239 private static final int NUM_SOUNDPOOL_CHANNELS = 4;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800240
Lei Zhang6c798972012-03-02 11:40:12 -0800241 // Maximum volume adjust steps allowed in a single batch call.
242 private static final int MAX_BATCH_VOLUME_ADJUST_STEPS = 4;
243
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800244 /* Sound effect file names */
245 private static final String SOUND_EFFECTS_PATH = "/media/audio/ui/";
Eric Laurente78fced2013-03-15 16:03:47 -0700246 private static final List<String> SOUND_EFFECT_FILES = new ArrayList<String>();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800247
248 /* Sound effect file name mapping sound effect id (AudioManager.FX_xxx) to
249 * file index in SOUND_EFFECT_FILES[] (first column) and indicating if effect
250 * uses soundpool (second column) */
Eric Laurente78fced2013-03-15 16:03:47 -0700251 private final int[][] SOUND_EFFECT_FILES_MAP = new int[AudioManager.NUM_SOUND_EFFECTS][2];
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800252
Jared Suttles59820132009-08-13 21:50:52 -0500253 /** @hide Maximum volume index values for audio streams */
Eric Laurent91377de2014-10-10 15:24:04 -0700254 private static int[] MAX_STREAM_VOLUME = new int[] {
Eric Laurent6ee99522009-08-25 06:30:59 -0700255 5, // STREAM_VOICE_CALL
256 7, // STREAM_SYSTEM
257 7, // STREAM_RING
258 15, // STREAM_MUSIC
259 7, // STREAM_ALARM
260 7, // STREAM_NOTIFICATION
261 15, // STREAM_BLUETOOTH_SCO
262 7, // STREAM_SYSTEM_ENFORCED
263 15, // STREAM_DTMF
264 15 // STREAM_TTS
Jared Suttles59820132009-08-13 21:50:52 -0500265 };
Eric Laurent91377de2014-10-10 15:24:04 -0700266
Eric Laurent6d517662012-04-23 18:42:39 -0700267 /* mStreamVolumeAlias[] indicates for each stream if it uses the volume settings
Eric Laurenta553c252009-07-17 12:17:14 -0700268 * of another stream: This avoids multiplying the volume settings for hidden
269 * stream types that follow other stream behavior for volume settings
Eric Laurent6d517662012-04-23 18:42:39 -0700270 * NOTE: do not create loops in aliases!
271 * Some streams alias to different streams according to device category (phone or tablet) or
Eric Laurent24e0d9b2013-10-03 18:15:07 -0700272 * use case (in call vs off call...). See updateStreamVolumeAlias() for more details.
Eric Laurent212532b2014-07-21 15:43:18 -0700273 * mStreamVolumeAlias contains STREAM_VOLUME_ALIAS_VOICE aliases for a voice capable device
274 * (phone), STREAM_VOLUME_ALIAS_TELEVISION for a television or set-top box and
275 * STREAM_VOLUME_ALIAS_DEFAULT for other devices (e.g. tablets).*/
276 private final int[] STREAM_VOLUME_ALIAS_VOICE = new int[] {
Eric Laurent6d517662012-04-23 18:42:39 -0700277 AudioSystem.STREAM_VOICE_CALL, // STREAM_VOICE_CALL
278 AudioSystem.STREAM_RING, // STREAM_SYSTEM
279 AudioSystem.STREAM_RING, // STREAM_RING
280 AudioSystem.STREAM_MUSIC, // STREAM_MUSIC
281 AudioSystem.STREAM_ALARM, // STREAM_ALARM
282 AudioSystem.STREAM_RING, // STREAM_NOTIFICATION
283 AudioSystem.STREAM_BLUETOOTH_SCO, // STREAM_BLUETOOTH_SCO
284 AudioSystem.STREAM_RING, // STREAM_SYSTEM_ENFORCED
285 AudioSystem.STREAM_RING, // STREAM_DTMF
286 AudioSystem.STREAM_MUSIC // STREAM_TTS
Eric Laurenta553c252009-07-17 12:17:14 -0700287 };
Eric Laurent212532b2014-07-21 15:43:18 -0700288 private final int[] STREAM_VOLUME_ALIAS_TELEVISION = new int[] {
289 AudioSystem.STREAM_MUSIC, // STREAM_VOICE_CALL
290 AudioSystem.STREAM_MUSIC, // STREAM_SYSTEM
291 AudioSystem.STREAM_MUSIC, // STREAM_RING
292 AudioSystem.STREAM_MUSIC, // STREAM_MUSIC
293 AudioSystem.STREAM_MUSIC, // STREAM_ALARM
294 AudioSystem.STREAM_MUSIC, // STREAM_NOTIFICATION
295 AudioSystem.STREAM_MUSIC, // STREAM_BLUETOOTH_SCO
296 AudioSystem.STREAM_MUSIC, // STREAM_SYSTEM_ENFORCED
297 AudioSystem.STREAM_MUSIC, // STREAM_DTMF
298 AudioSystem.STREAM_MUSIC // STREAM_TTS
299 };
300 private final int[] STREAM_VOLUME_ALIAS_DEFAULT = new int[] {
Eric Laurent6d517662012-04-23 18:42:39 -0700301 AudioSystem.STREAM_VOICE_CALL, // STREAM_VOICE_CALL
John Spurlock4f0f1202014-08-05 13:28:33 -0400302 AudioSystem.STREAM_RING, // STREAM_SYSTEM
Eric Laurent6d517662012-04-23 18:42:39 -0700303 AudioSystem.STREAM_RING, // STREAM_RING
304 AudioSystem.STREAM_MUSIC, // STREAM_MUSIC
305 AudioSystem.STREAM_ALARM, // STREAM_ALARM
306 AudioSystem.STREAM_RING, // STREAM_NOTIFICATION
307 AudioSystem.STREAM_BLUETOOTH_SCO, // STREAM_BLUETOOTH_SCO
John Spurlock4f0f1202014-08-05 13:28:33 -0400308 AudioSystem.STREAM_RING, // STREAM_SYSTEM_ENFORCED
309 AudioSystem.STREAM_RING, // STREAM_DTMF
Eric Laurent6d517662012-04-23 18:42:39 -0700310 AudioSystem.STREAM_MUSIC // STREAM_TTS
311 };
312 private int[] mStreamVolumeAlias;
Eric Laurenta553c252009-07-17 12:17:14 -0700313
Dianne Hackbornba50b97c2013-04-30 15:04:46 -0700314 /**
315 * Map AudioSystem.STREAM_* constants to app ops. This should be used
316 * after mapping through mStreamVolumeAlias.
317 */
John Spurlock59dc9c12015-03-02 11:20:15 -0500318 private static final int[] STREAM_VOLUME_OPS = new int[] {
Dianne Hackbornba50b97c2013-04-30 15:04:46 -0700319 AppOpsManager.OP_AUDIO_VOICE_VOLUME, // STREAM_VOICE_CALL
320 AppOpsManager.OP_AUDIO_MEDIA_VOLUME, // STREAM_SYSTEM
321 AppOpsManager.OP_AUDIO_RING_VOLUME, // STREAM_RING
322 AppOpsManager.OP_AUDIO_MEDIA_VOLUME, // STREAM_MUSIC
323 AppOpsManager.OP_AUDIO_ALARM_VOLUME, // STREAM_ALARM
324 AppOpsManager.OP_AUDIO_NOTIFICATION_VOLUME, // STREAM_NOTIFICATION
325 AppOpsManager.OP_AUDIO_BLUETOOTH_VOLUME, // STREAM_BLUETOOTH_SCO
326 AppOpsManager.OP_AUDIO_MEDIA_VOLUME, // STREAM_SYSTEM_ENFORCED
327 AppOpsManager.OP_AUDIO_MEDIA_VOLUME, // STREAM_DTMF
328 AppOpsManager.OP_AUDIO_MEDIA_VOLUME, // STREAM_TTS
329 };
330
Eric Laurent83a017b2013-03-19 18:15:31 -0700331 private final boolean mUseFixedVolume;
332
Glenn Kasten30c918c2011-11-10 17:56:41 -0800333 private final AudioSystem.ErrorCallback mAudioSystemCallback = new AudioSystem.ErrorCallback() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800334 public void onError(int error) {
335 switch (error) {
336 case AudioSystem.AUDIO_STATUS_SERVER_DIED:
Eric Laurentdfb881f2013-07-18 14:41:39 -0700337 sendMsg(mAudioHandler, MSG_MEDIA_SERVER_DIED,
338 SENDMSG_NOOP, 0, 0, null, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800339 break;
340 default:
341 break;
342 }
Eric Laurentdfb881f2013-07-18 14:41:39 -0700343 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800344 };
345
346 /**
347 * Current ringer mode from one of {@link AudioManager#RINGER_MODE_NORMAL},
348 * {@link AudioManager#RINGER_MODE_SILENT}, or
349 * {@link AudioManager#RINGER_MODE_VIBRATE}.
350 */
Glenn Kastenba195eb2011-12-13 09:30:40 -0800351 // protected by mSettingsLock
John Spurlock661f2cf2014-11-17 10:29:10 -0500352 private int mRingerMode; // internal ringer mode, affects muting of underlying streams
353 private int mRingerModeExternal = -1; // reported ringer mode to outside clients (AudioManager)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800354
Eric Laurent9bcf4012009-06-12 06:09:28 -0700355 /** @see System#MODE_RINGER_STREAMS_AFFECTED */
Eric Laurent24e0d9b2013-10-03 18:15:07 -0700356 private int mRingerModeAffectedStreams = 0;
Eric Laurent9bcf4012009-06-12 06:09:28 -0700357
Eric Laurent5b4e6542010-03-19 20:02:21 -0700358 // Streams currently muted by ringer mode
359 private int mRingerModeMutedStreams;
360
John Spurlock3ce37252015-02-17 13:20:45 -0500361 /** Streams that can be muted. Do not resolve to aliases when checking.
362 * @see System#MUTE_STREAMS_AFFECTED */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800363 private int mMuteAffectedStreams;
364
365 /**
Eric Laurentbffc3d12012-05-07 17:43:49 -0700366 * NOTE: setVibrateSetting(), getVibrateSetting(), shouldVibrate() are deprecated.
367 * mVibrateSetting is just maintained during deprecation period but vibration policy is
368 * now only controlled by mHasVibrator and mRingerMode
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800369 */
370 private int mVibrateSetting;
371
Eric Laurentbffc3d12012-05-07 17:43:49 -0700372 // Is there a vibrator
373 private final boolean mHasVibrator;
374
Eric Laurenta553c252009-07-17 12:17:14 -0700375 // Broadcast receiver for device connections intent broadcasts
376 private final BroadcastReceiver mReceiver = new AudioServiceBroadcastReceiver();
377
Eric Laurentc42ac9d2009-07-29 08:53:03 -0700378 // Devices currently connected
Glenn Kasten30c918c2011-11-10 17:56:41 -0800379 private final HashMap <Integer, String> mConnectedDevices = new HashMap <Integer, String>();
Eric Laurentc42ac9d2009-07-29 08:53:03 -0700380
381 // Forced device usage for communications
382 private int mForcedUseForComm;
383
Eric Laurent9272b4b2010-01-23 17:12:59 -0800384 // List of binder death handlers for setMode() client processes.
385 // The last process to have called setMode() is at the top of the list.
Glenn Kasten30c918c2011-11-10 17:56:41 -0800386 private final ArrayList <SetModeDeathHandler> mSetModeDeathHandlers = new ArrayList <SetModeDeathHandler>();
Eric Laurenteb14a782009-12-17 03:12:59 -0800387
Eric Laurent3def1ee2010-03-17 23:26:26 -0700388 // List of clients having issued a SCO start request
Glenn Kasten30c918c2011-11-10 17:56:41 -0800389 private final ArrayList <ScoClient> mScoClients = new ArrayList <ScoClient>();
Eric Laurent3def1ee2010-03-17 23:26:26 -0700390
391 // BluetoothHeadset API to control SCO connection
392 private BluetoothHeadset mBluetoothHeadset;
393
Jaikumar Ganesh82aa7f02010-09-27 17:05:10 -0700394 // Bluetooth headset device
395 private BluetoothDevice mBluetoothHeadsetDevice;
Eric Laurent3def1ee2010-03-17 23:26:26 -0700396
Eric Laurent62ef7672010-11-24 10:58:32 -0800397 // Indicate if SCO audio connection is currently active and if the initiator is
398 // audio service (internal) or bluetooth headset (external)
399 private int mScoAudioState;
400 // SCO audio state is not active
401 private static final int SCO_STATE_INACTIVE = 0;
Eric Laurentdc03c612011-04-01 10:59:41 -0700402 // SCO audio activation request waiting for headset service to connect
403 private static final int SCO_STATE_ACTIVATE_REQ = 1;
Eric Laurent25fc29b2013-04-05 12:13:54 -0700404 // SCO audio state is active or starting due to a request from AudioManager API
Eric Laurentdc03c612011-04-01 10:59:41 -0700405 private static final int SCO_STATE_ACTIVE_INTERNAL = 3;
406 // SCO audio deactivation request waiting for headset service to connect
407 private static final int SCO_STATE_DEACTIVATE_REQ = 5;
408
Eric Laurent62ef7672010-11-24 10:58:32 -0800409 // SCO audio state is active due to an action in BT handsfree (either voice recognition or
410 // in call audio)
411 private static final int SCO_STATE_ACTIVE_EXTERNAL = 2;
Eric Laurentdc03c612011-04-01 10:59:41 -0700412 // Deactivation request for all SCO connections (initiated by audio mode change)
413 // waiting for headset service to connect
414 private static final int SCO_STATE_DEACTIVATE_EXT_REQ = 4;
415
Eric Laurentc18c9132013-04-12 17:24:56 -0700416 // Indicates the mode used for SCO audio connection. The mode is virtual call if the request
417 // originated from an app targeting an API version before JB MR2 and raw audio after that.
418 private int mScoAudioMode;
Liejun Taof4e51d82014-07-16 11:18:29 -0700419 // SCO audio mode is undefined
420 private static final int SCO_MODE_UNDEFINED = -1;
Eric Laurentc18c9132013-04-12 17:24:56 -0700421 // SCO audio mode is virtual voice call (BluetoothHeadset.startScoUsingVirtualVoiceCall())
422 private static final int SCO_MODE_VIRTUAL_CALL = 0;
423 // SCO audio mode is raw audio (BluetoothHeadset.connectAudio())
424 private static final int SCO_MODE_RAW = 1;
Liejun Taof4e51d82014-07-16 11:18:29 -0700425 // SCO audio mode is Voice Recognition (BluetoothHeadset.startVoiceRecognition())
426 private static final int SCO_MODE_VR = 2;
427
428 private static final int SCO_MODE_MAX = 2;
Eric Laurentc18c9132013-04-12 17:24:56 -0700429
Eric Laurentdc03c612011-04-01 10:59:41 -0700430 // Current connection state indicated by bluetooth headset
431 private int mScoConnectionState;
Eric Laurent62ef7672010-11-24 10:58:32 -0800432
Eric Laurenta60e2122010-12-28 16:49:07 -0800433 // true if boot sequence has been completed
Eric Laurent4a5eeb92014-05-06 10:49:04 -0700434 private boolean mSystemReady;
Eric Laurenta60e2122010-12-28 16:49:07 -0800435 // listener for SoundPool sample load completion indication
436 private SoundPoolCallback mSoundPoolCallBack;
437 // thread for SoundPool listener
438 private SoundPoolListenerThread mSoundPoolListenerThread;
439 // message looper for SoundPool listener
440 private Looper mSoundPoolLooper = null;
Jean-Michel Trivic55b3932012-06-05 11:57:59 -0700441 // volume applied to sound played with playSoundEffect()
Jean-Michel Trivif2b0c112012-07-09 11:59:11 -0700442 private static int sSoundEffectVolumeDb;
Eric Laurent25101b02011-02-02 09:33:30 -0800443 // previous volume adjustment direction received by checkForRingerModeChange()
444 private int mPrevVolDirection = AudioManager.ADJUST_SAME;
Amith Yamasani6243edd2011-12-05 19:58:48 -0800445 // Keyguard manager proxy
446 private KeyguardManager mKeyguardManager;
Eric Laurent45c90ce2012-04-24 18:44:22 -0700447 // mVolumeControlStream is set by VolumePanel to temporarily force the stream type which volume
448 // is controlled by Vol keys.
449 private int mVolumeControlStream = -1;
450 private final Object mForceControlStreamLock = new Object();
451 // VolumePanel is currently the only client of forceVolumeControlStream() and runs in system
452 // server process so in theory it is not necessary to monitor the client death.
453 // However it is good to be ready for future evolutions.
454 private ForceControlStreamClient mForceControlStreamClient = null;
Jeff Sharkey098d5802012-04-26 17:30:34 -0700455 // Used to play ringtones outside system_server
456 private volatile IRingtonePlayer mRingtonePlayer;
Eric Laurent9bc8358d2011-11-18 16:43:31 -0800457
Jean-Michel Trivif26f0172012-04-25 16:23:20 -0700458 private int mDeviceOrientation = Configuration.ORIENTATION_UNDEFINED;
Jean-Michel Trivibb6f8712013-05-23 15:02:41 -0700459 private int mDeviceRotation = Surface.ROTATION_0;
Jean-Michel Trivif26f0172012-04-25 16:23:20 -0700460
Eric Laurent78472112012-05-21 08:57:21 -0700461 // Request to override default use of A2DP for media.
462 private boolean mBluetoothA2dpEnabled;
463 private final Object mBluetoothA2dpEnabledLock = new Object();
464
Dianne Hackborn632ca412012-06-14 19:34:10 -0700465 // Monitoring of audio routes. Protected by mCurAudioRoutes.
466 final AudioRoutesInfo mCurAudioRoutes = new AudioRoutesInfo();
467 final RemoteCallbackList<IAudioRoutesObserver> mRoutesObservers
468 = new RemoteCallbackList<IAudioRoutesObserver>();
469
Eric Laurent4bbcc652012-09-24 14:26:30 -0700470 // Devices for which the volume is fixed and VolumePanel slider should be disabled
Eric Laurent212532b2014-07-21 15:43:18 -0700471 int mFixedVolumeDevices = AudioSystem.DEVICE_OUT_HDMI |
Eric Laurent4bbcc652012-09-24 14:26:30 -0700472 AudioSystem.DEVICE_OUT_DGTL_DOCK_HEADSET |
Eric Laurent212532b2014-07-21 15:43:18 -0700473 AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET |
474 AudioSystem.DEVICE_OUT_HDMI_ARC |
475 AudioSystem.DEVICE_OUT_SPDIF |
476 AudioSystem.DEVICE_OUT_AUX_LINE;
Jean-Michel Triviba5270b2014-10-01 17:49:29 -0700477 int mFullVolumeDevices = 0;
Eric Laurent4bbcc652012-09-24 14:26:30 -0700478
Jean-Michel Trivibb6f8712013-05-23 15:02:41 -0700479 // TODO merge orientation and rotation
Eric Laurentd640bd32012-09-28 18:01:48 -0700480 private final boolean mMonitorOrientation;
Jean-Michel Trivibb6f8712013-05-23 15:02:41 -0700481 private final boolean mMonitorRotation;
Eric Laurentd640bd32012-09-28 18:01:48 -0700482
Eric Laurent7ee1e4f2012-10-26 18:11:21 -0700483 private boolean mDockAudioMediaEnabled = true;
484
Eric Laurent08ed1b92012-11-05 14:54:12 -0800485 private int mDockState = Intent.EXTRA_DOCK_STATE_UNDOCKED;
486
Eric Laurentfde16d52012-12-03 14:42:39 -0800487 // Used when safe volume warning message display is requested by setStreamVolume(). In this
488 // case, the new requested volume, stream type and device are stored in mPendingVolumeCommand
489 // and used later when/if disableSafeMediaVolume() is called.
490 private StreamVolumeCommand mPendingVolumeCommand;
491
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700492 private PowerManager.WakeLock mAudioEventWakeLock;
493
494 private final MediaFocusControl mMediaFocusControl;
495
John Du5a0cf7a2013-07-19 11:30:34 -0700496 // Reference to BluetoothA2dp to query for AbsoluteVolume.
497 private BluetoothA2dp mA2dp;
seunghwan.hong4fe77952014-10-29 17:43:20 +0900498 // lock always taken synchronized on mConnectedDevices
John Du5a0cf7a2013-07-19 11:30:34 -0700499 private final Object mA2dpAvrcpLock = new Object();
500 // If absolute volume is supported in AVRCP device
501 private boolean mAvrcpAbsVolSupported = false;
502
Jon Eklund318f0fe2014-01-23 17:53:48 -0600503 private AudioOrientationEventListener mOrientationListener;
504
Eric Laurentadbe8bf2014-11-03 18:26:32 -0800505 private static Long mLastDeviceConnectMsgTime = new Long(0);
506
John Spurlock661f2cf2014-11-17 10:29:10 -0500507 private AudioManagerInternal.RingerModeDelegate mRingerModeDelegate;
508
Paul McLean10804eb2015-01-28 11:16:35 -0800509 // Intent "extra" data keys.
510 public static final String CONNECT_INTENT_KEY_PORT_NAME = "portName";
511 public static final String CONNECT_INTENT_KEY_STATE = "state";
512 public static final String CONNECT_INTENT_KEY_ADDRESS = "address";
513 public static final String CONNECT_INTENT_KEY_HAS_PLAYBACK = "hasPlayback";
514 public static final String CONNECT_INTENT_KEY_HAS_CAPTURE = "hasCapture";
515 public static final String CONNECT_INTENT_KEY_HAS_MIDI = "hasMIDI";
516 public static final String CONNECT_INTENT_KEY_DEVICE_CLASS = "class";
517
518 // Defines the format for the connection "address" for ALSA devices
519 public static String makeAlsaAddressString(int card, int device) {
520 return "card=" + card + ";device=" + device + ";";
521 }
522
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800523 ///////////////////////////////////////////////////////////////////////////
524 // Construction
525 ///////////////////////////////////////////////////////////////////////////
526
527 /** @hide */
528 public AudioService(Context context) {
529 mContext = context;
530 mContentResolver = context.getContentResolver();
Dianne Hackbornba50b97c2013-04-30 15:04:46 -0700531 mAppOps = (AppOpsManager)context.getSystemService(Context.APP_OPS_SERVICE);
Eric Laurent212532b2014-07-21 15:43:18 -0700532
John Spurlock61560172015-02-06 19:46:04 -0500533 mPlatformType = AudioSystem.getPlatformType(context);
Jared Suttles59820132009-08-13 21:50:52 -0500534
Jean-Michel Trivic6802222012-04-30 11:15:03 -0700535 PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700536 mAudioEventWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "handleAudioEvent");
Jean-Michel Trivic6802222012-04-30 11:15:03 -0700537
Eric Laurentbffc3d12012-05-07 17:43:49 -0700538 Vibrator vibrator = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE);
539 mHasVibrator = vibrator == null ? false : vibrator.hasVibrator();
540
Jared Suttles59820132009-08-13 21:50:52 -0500541 // Intialized volume
Eric Laurent91377de2014-10-10 15:24:04 -0700542 int maxVolume = SystemProperties.getInt("ro.config.vc_call_vol_steps",
543 MAX_STREAM_VOLUME[AudioSystem.STREAM_VOICE_CALL]);
544 if (maxVolume != MAX_STREAM_VOLUME[AudioSystem.STREAM_VOICE_CALL]) {
545 MAX_STREAM_VOLUME[AudioSystem.STREAM_VOICE_CALL] = maxVolume;
John Spurlock61560172015-02-06 19:46:04 -0500546 AudioSystem.DEFAULT_STREAM_VOLUME[AudioSystem.STREAM_VOICE_CALL] = (maxVolume * 3) / 4;
Eric Laurent91377de2014-10-10 15:24:04 -0700547 }
548 maxVolume = SystemProperties.getInt("ro.config.media_vol_steps",
549 MAX_STREAM_VOLUME[AudioSystem.STREAM_MUSIC]);
550 if (maxVolume != MAX_STREAM_VOLUME[AudioSystem.STREAM_MUSIC]) {
551 MAX_STREAM_VOLUME[AudioSystem.STREAM_MUSIC] = maxVolume;
John Spurlock61560172015-02-06 19:46:04 -0500552 AudioSystem.DEFAULT_STREAM_VOLUME[AudioSystem.STREAM_MUSIC] = (maxVolume * 3) / 4;
Eric Laurent91377de2014-10-10 15:24:04 -0700553 }
Jared Suttles59820132009-08-13 21:50:52 -0500554
Jean-Michel Trivif2b0c112012-07-09 11:59:11 -0700555 sSoundEffectVolumeDb = context.getResources().getInteger(
Jean-Michel Trivic55b3932012-06-05 11:57:59 -0700556 com.android.internal.R.integer.config_soundEffectVolumeDb);
Eric Laurent25101b02011-02-02 09:33:30 -0800557
Eric Laurentc42ac9d2009-07-29 08:53:03 -0700558 mForcedUseForComm = AudioSystem.FORCE_NONE;
Eric Laurentdd45d012012-10-08 09:04:34 -0700559
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800560 createAudioSystemThread();
Eric Laurentdd45d012012-10-08 09:04:34 -0700561
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700562 mMediaFocusControl = new MediaFocusControl(mAudioHandler.getLooper(),
John Spurlock3346a802014-05-20 16:25:37 -0400563 mContext, mVolumeController, this);
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -0700564
Eric Laurentdfb881f2013-07-18 14:41:39 -0700565 AudioSystem.setErrorCallback(mAudioSystemCallback);
566
John Spurlock5e783732015-02-19 10:28:59 -0500567 boolean cameraSoundForced = readCameraSoundForced();
Eric Laurentdd45d012012-10-08 09:04:34 -0700568 mCameraSoundForced = new Boolean(cameraSoundForced);
569 sendMsg(mAudioHandler,
570 MSG_SET_FORCE_USE,
571 SENDMSG_QUEUE,
572 AudioSystem.FOR_SYSTEM,
573 cameraSoundForced ?
574 AudioSystem.FORCE_SYSTEM_ENFORCED : AudioSystem.FORCE_NONE,
575 null,
576 0);
577
Eric Laurent05274f32012-11-29 12:48:18 -0800578 mSafeMediaVolumeState = new Integer(Settings.Global.getInt(mContentResolver,
579 Settings.Global.AUDIO_SAFE_VOLUME_STATE,
580 SAFE_MEDIA_VOLUME_NOT_CONFIGURED));
581 // The default safe volume index read here will be replaced by the actual value when
582 // the mcc is read by onConfigureSafeVolume()
583 mSafeMediaVolumeIndex = mContext.getResources().getInteger(
584 com.android.internal.R.integer.config_safe_media_volume_index) * 10;
585
Eric Laurent83a017b2013-03-19 18:15:31 -0700586 mUseFixedVolume = mContext.getResources().getBoolean(
587 com.android.internal.R.bool.config_useFixedVolume);
588
Eric Laurent24e0d9b2013-10-03 18:15:07 -0700589 // must be called before readPersistedSettings() which needs a valid mStreamVolumeAlias[]
590 // array initialized by updateStreamVolumeAlias()
591 updateStreamVolumeAlias(false /*updateVolumes*/);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800592 readPersistedSettings();
Eric Laurentc1d41662011-07-19 11:21:13 -0700593 mSettingsObserver = new SettingsObserver();
Eric Laurenta553c252009-07-17 12:17:14 -0700594 createStreamStates();
Eric Laurent9f103de2011-09-08 15:04:23 -0700595
Glenn Kastenfd116ad2013-07-12 17:10:39 -0700596 readAndSetLowRamDevice();
Eric Laurent3891c4c2010-04-20 09:40:57 -0700597
598 // Call setRingerModeInt() to apply correct mute
599 // state on streams affected by ringer mode.
600 mRingerModeMutedStreams = 0;
John Spurlock661f2cf2014-11-17 10:29:10 -0500601 setRingerModeInt(getRingerModeInternal(), false);
Eric Laurent3891c4c2010-04-20 09:40:57 -0700602
Eric Laurenta553c252009-07-17 12:17:14 -0700603 // Register for device connection intent broadcasts.
604 IntentFilter intentFilter =
Eric Laurentb1fbaac2012-05-29 09:24:28 -0700605 new IntentFilter(BluetoothHeadset.ACTION_AUDIO_STATE_CHANGED);
Jaikumar Ganesh82aa7f02010-09-27 17:05:10 -0700606 intentFilter.addAction(BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED);
607 intentFilter.addAction(Intent.ACTION_DOCK_EVENT);
Eric Laurent950e8cb2011-10-13 08:57:54 -0700608 intentFilter.addAction(Intent.ACTION_SCREEN_ON);
609 intentFilter.addAction(Intent.ACTION_SCREEN_OFF);
Eric Laurentbc0fab1f2012-09-19 11:24:41 -0700610 intentFilter.addAction(Intent.ACTION_USER_SWITCHED);
Paul McLeanc837a452014-04-09 09:04:43 -0700611 intentFilter.addAction(UsbManager.ACTION_USB_DEVICE_ATTACHED);
Jean-Michel Trivif26f0172012-04-25 16:23:20 -0700612
Eric Laurentd640bd32012-09-28 18:01:48 -0700613 intentFilter.addAction(Intent.ACTION_CONFIGURATION_CHANGED);
Jean-Michel Trivibb6f8712013-05-23 15:02:41 -0700614 // TODO merge orientation and rotation
Eric Laurentd640bd32012-09-28 18:01:48 -0700615 mMonitorOrientation = SystemProperties.getBoolean("ro.audio.monitorOrientation", false);
616 if (mMonitorOrientation) {
Jean-Michel Trivif26f0172012-04-25 16:23:20 -0700617 Log.v(TAG, "monitoring device orientation");
Jean-Michel Trivif26f0172012-04-25 16:23:20 -0700618 // initialize orientation in AudioSystem
619 setOrientationForAudioSystem();
620 }
Jean-Michel Trivibb6f8712013-05-23 15:02:41 -0700621 mMonitorRotation = SystemProperties.getBoolean("ro.audio.monitorRotation", false);
622 if (mMonitorRotation) {
623 mDeviceRotation = ((WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE))
624 .getDefaultDisplay().getRotation();
625 Log.v(TAG, "monitoring device rotation, initial=" + mDeviceRotation);
Jon Eklund318f0fe2014-01-23 17:53:48 -0600626
627 mOrientationListener = new AudioOrientationEventListener(mContext);
628 mOrientationListener.enable();
629
Jean-Michel Trivibb6f8712013-05-23 15:02:41 -0700630 // initialize rotation in AudioSystem
631 setRotationForAudioSystem();
632 }
Jean-Michel Trivif26f0172012-04-25 16:23:20 -0700633
Eric Laurenta553c252009-07-17 12:17:14 -0700634 context.registerReceiver(mReceiver, intentFilter);
Jared Suttles59820132009-08-13 21:50:52 -0500635
RoboErik0dac35a2014-08-12 15:48:49 -0700636 LocalServices.addService(AudioManagerInternal.class, new AudioServiceInternal());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800637 }
638
Eric Laurent4a5eeb92014-05-06 10:49:04 -0700639 public void systemReady() {
640 sendMsg(mAudioHandler, MSG_SYSTEM_READY, SENDMSG_QUEUE,
641 0, 0, null, 0);
642 }
643
644 public void onSystemReady() {
645 mSystemReady = true;
646 sendMsg(mAudioHandler, MSG_LOAD_SOUND_EFFECTS, SENDMSG_QUEUE,
647 0, 0, null, 0);
648
649 mKeyguardManager =
650 (KeyguardManager) mContext.getSystemService(Context.KEYGUARD_SERVICE);
651 mScoConnectionState = AudioManager.SCO_AUDIO_STATE_ERROR;
652 resetBluetoothSco();
653 getBluetoothHeadset();
654 //FIXME: this is to maintain compatibility with deprecated intent
655 // AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED. Remove when appropriate.
656 Intent newIntent = new Intent(AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED);
657 newIntent.putExtra(AudioManager.EXTRA_SCO_AUDIO_STATE,
658 AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
659 sendStickyBroadcastToAll(newIntent);
660
661 BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
662 if (adapter != null) {
663 adapter.getProfileProxy(mContext, mBluetoothProfileServiceListener,
664 BluetoothProfile.A2DP);
665 }
666
Eric Laurent212532b2014-07-21 15:43:18 -0700667 mHdmiManager =
Wonsik Kim7f4342e2014-07-20 23:04:59 +0900668 (HdmiControlManager) mContext.getSystemService(Context.HDMI_CONTROL_SERVICE);
Eric Laurent212532b2014-07-21 15:43:18 -0700669 if (mHdmiManager != null) {
670 synchronized (mHdmiManager) {
671 mHdmiTvClient = mHdmiManager.getTvClient();
Jungshik Jangc9ff9682014-09-15 17:41:06 +0900672 if (mHdmiTvClient != null) {
673 mFixedVolumeDevices &= ~AudioSystem.DEVICE_ALL_HDMI_SYSTEM_AUDIO_AND_SPEAKER;
674 }
Eric Laurent212532b2014-07-21 15:43:18 -0700675 mHdmiPlaybackClient = mHdmiManager.getPlaybackClient();
676 mHdmiCecSink = false;
677 }
678 }
Wonsik Kim7f4342e2014-07-20 23:04:59 +0900679
Eric Laurent4a5eeb92014-05-06 10:49:04 -0700680 sendMsg(mAudioHandler,
681 MSG_CONFIGURE_SAFE_MEDIA_VOLUME_FORCED,
682 SENDMSG_REPLACE,
683 0,
684 0,
685 null,
686 SAFE_VOLUME_CONFIGURE_TIMEOUT_MS);
Jean-Michel Trivi873cc452014-09-11 17:25:09 -0700687
688 StreamOverride.init(mContext);
John Spurlockcdb57ae2015-02-11 19:04:11 -0500689 mControllerService.init();
Eric Laurent4a5eeb92014-05-06 10:49:04 -0700690 }
691
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800692 private void createAudioSystemThread() {
693 mAudioSystemThread = new AudioSystemThread();
694 mAudioSystemThread.start();
695 waitForAudioHandlerCreation();
696 }
697
698 /** Waits for the volume handler to be created by the other thread. */
699 private void waitForAudioHandlerCreation() {
700 synchronized(this) {
701 while (mAudioHandler == null) {
702 try {
703 // Wait for mAudioHandler to be set by the other thread
704 wait();
705 } catch (InterruptedException e) {
706 Log.e(TAG, "Interrupted while waiting on volume handler.");
707 }
708 }
709 }
710 }
711
Eric Laurent24482012012-05-10 09:41:17 -0700712 private void checkAllAliasStreamVolumes() {
Eric Laurent8fa4d6f2014-10-30 14:13:03 -0700713 synchronized (VolumeStreamState.class) {
714 int numStreamTypes = AudioSystem.getNumStreamTypes();
715 for (int streamType = 0; streamType < numStreamTypes; streamType++) {
716 if (streamType != mStreamVolumeAlias[streamType]) {
717 mStreamStates[streamType].
Eric Laurent42b041e2013-03-29 11:36:03 -0700718 setAllIndexes(mStreamStates[mStreamVolumeAlias[streamType]]);
Eric Laurent8fa4d6f2014-10-30 14:13:03 -0700719 }
720 // apply stream volume
RoboErik4197cb62015-01-21 15:45:32 -0800721 if (!mStreamStates[streamType].mIsMuted) {
Eric Laurent8fa4d6f2014-10-30 14:13:03 -0700722 mStreamStates[streamType].applyAllVolumes();
723 }
Eric Laurent24482012012-05-10 09:41:17 -0700724 }
725 }
726 }
727
Eric Laurent212532b2014-07-21 15:43:18 -0700728 private void checkAllFixedVolumeDevices()
729 {
730 int numStreamTypes = AudioSystem.getNumStreamTypes();
731 for (int streamType = 0; streamType < numStreamTypes; streamType++) {
732 mStreamStates[streamType].checkFixedVolumeDevices();
733 }
734 }
735
Jean-Michel Triviba5270b2014-10-01 17:49:29 -0700736 private void checkAllFixedVolumeDevices(int streamType) {
737 mStreamStates[streamType].checkFixedVolumeDevices();
738 }
739
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800740 private void createStreamStates() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800741 int numStreamTypes = AudioSystem.getNumStreamTypes();
742 VolumeStreamState[] streams = mStreamStates = new VolumeStreamState[numStreamTypes];
743
744 for (int i = 0; i < numStreamTypes; i++) {
Eric Laurent6d517662012-04-23 18:42:39 -0700745 streams[i] = new VolumeStreamState(System.VOLUME_SETTINGS[mStreamVolumeAlias[i]], i);
Eric Laurenta553c252009-07-17 12:17:14 -0700746 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800747
Eric Laurent212532b2014-07-21 15:43:18 -0700748 checkAllFixedVolumeDevices();
Eric Laurent24482012012-05-10 09:41:17 -0700749 checkAllAliasStreamVolumes();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800750 }
751
Eric Laurentbffc3d12012-05-07 17:43:49 -0700752 private void dumpStreamStates(PrintWriter pw) {
753 pw.println("\nStream volumes (device: index)");
754 int numStreamTypes = AudioSystem.getNumStreamTypes();
755 for (int i = 0; i < numStreamTypes; i++) {
John Spurlock61560172015-02-06 19:46:04 -0500756 pw.println("- " + AudioSystem.STREAM_NAMES[i] + ":");
Eric Laurentbffc3d12012-05-07 17:43:49 -0700757 mStreamStates[i].dump(pw);
758 pw.println("");
759 }
Eric Laurentdd45d012012-10-08 09:04:34 -0700760 pw.print("\n- mute affected streams = 0x");
761 pw.println(Integer.toHexString(mMuteAffectedStreams));
Eric Laurentbffc3d12012-05-07 17:43:49 -0700762 }
763
Eric Laurent6d517662012-04-23 18:42:39 -0700764 private void updateStreamVolumeAlias(boolean updateVolumes) {
765 int dtmfStreamAlias;
Eric Laurent212532b2014-07-21 15:43:18 -0700766
767 switch (mPlatformType) {
John Spurlock61560172015-02-06 19:46:04 -0500768 case AudioSystem.PLATFORM_VOICE:
Eric Laurent212532b2014-07-21 15:43:18 -0700769 mStreamVolumeAlias = STREAM_VOLUME_ALIAS_VOICE;
Eric Laurent6d517662012-04-23 18:42:39 -0700770 dtmfStreamAlias = AudioSystem.STREAM_RING;
Eric Laurent212532b2014-07-21 15:43:18 -0700771 break;
John Spurlock61560172015-02-06 19:46:04 -0500772 case AudioSystem.PLATFORM_TELEVISION:
Eric Laurent212532b2014-07-21 15:43:18 -0700773 mStreamVolumeAlias = STREAM_VOLUME_ALIAS_TELEVISION;
774 dtmfStreamAlias = AudioSystem.STREAM_MUSIC;
775 break;
776 default:
777 mStreamVolumeAlias = STREAM_VOLUME_ALIAS_DEFAULT;
Eric Laurent6d517662012-04-23 18:42:39 -0700778 dtmfStreamAlias = AudioSystem.STREAM_MUSIC;
779 }
Eric Laurent212532b2014-07-21 15:43:18 -0700780
781 if (isPlatformTelevision()) {
782 mRingerModeAffectedStreams = 0;
Eric Laurent24e0d9b2013-10-03 18:15:07 -0700783 } else {
Eric Laurent212532b2014-07-21 15:43:18 -0700784 if (isInCommunication()) {
785 dtmfStreamAlias = AudioSystem.STREAM_VOICE_CALL;
786 mRingerModeAffectedStreams &= ~(1 << AudioSystem.STREAM_DTMF);
787 } else {
788 mRingerModeAffectedStreams |= (1 << AudioSystem.STREAM_DTMF);
789 }
Eric Laurent6d517662012-04-23 18:42:39 -0700790 }
Eric Laurent212532b2014-07-21 15:43:18 -0700791
Eric Laurent6d517662012-04-23 18:42:39 -0700792 mStreamVolumeAlias[AudioSystem.STREAM_DTMF] = dtmfStreamAlias;
793 if (updateVolumes) {
Eric Laurent42b041e2013-03-29 11:36:03 -0700794 mStreamStates[AudioSystem.STREAM_DTMF].setAllIndexes(mStreamStates[dtmfStreamAlias]);
Eric Laurent24e0d9b2013-10-03 18:15:07 -0700795 // apply stream mute states according to new value of mRingerModeAffectedStreams
John Spurlock661f2cf2014-11-17 10:29:10 -0500796 setRingerModeInt(getRingerModeInternal(), false);
Eric Laurent6d517662012-04-23 18:42:39 -0700797 sendMsg(mAudioHandler,
798 MSG_SET_ALL_VOLUMES,
799 SENDMSG_QUEUE,
800 0,
801 0,
802 mStreamStates[AudioSystem.STREAM_DTMF], 0);
803 }
804 }
805
Eric Laurent7ee1e4f2012-10-26 18:11:21 -0700806 private void readDockAudioSettings(ContentResolver cr)
807 {
808 mDockAudioMediaEnabled = Settings.Global.getInt(
Eric Laurent5ba0ffa02012-10-29 12:31:09 -0700809 cr, Settings.Global.DOCK_AUDIO_MEDIA_ENABLED, 0) == 1;
Eric Laurent7ee1e4f2012-10-26 18:11:21 -0700810
Eric Laurent7ee1e4f2012-10-26 18:11:21 -0700811 sendMsg(mAudioHandler,
812 MSG_SET_FORCE_USE,
813 SENDMSG_QUEUE,
814 AudioSystem.FOR_DOCK,
815 mDockAudioMediaEnabled ?
816 AudioSystem.FORCE_ANALOG_DOCK : AudioSystem.FORCE_NONE,
817 null,
818 0);
819 }
820
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800821 private void readPersistedSettings() {
822 final ContentResolver cr = mContentResolver;
823
Eric Laurentbffc3d12012-05-07 17:43:49 -0700824 int ringerModeFromSettings =
Jeff Sharkey8d9a1f62012-10-18 15:38:14 -0700825 Settings.Global.getInt(
826 cr, Settings.Global.MODE_RINGER, AudioManager.RINGER_MODE_NORMAL);
Eric Laurentbffc3d12012-05-07 17:43:49 -0700827 int ringerMode = ringerModeFromSettings;
Eric Laurent72668b22011-07-19 16:04:27 -0700828 // sanity check in case the settings are restored from a device with incompatible
829 // ringer modes
John Spurlock97559372014-10-24 16:27:36 -0400830 if (!isValidRingerMode(ringerMode)) {
Glenn Kastenba195eb2011-12-13 09:30:40 -0800831 ringerMode = AudioManager.RINGER_MODE_NORMAL;
Eric Laurentbffc3d12012-05-07 17:43:49 -0700832 }
833 if ((ringerMode == AudioManager.RINGER_MODE_VIBRATE) && !mHasVibrator) {
834 ringerMode = AudioManager.RINGER_MODE_SILENT;
835 }
836 if (ringerMode != ringerModeFromSettings) {
Jeff Sharkey8d9a1f62012-10-18 15:38:14 -0700837 Settings.Global.putInt(cr, Settings.Global.MODE_RINGER, ringerMode);
Glenn Kastenba195eb2011-12-13 09:30:40 -0800838 }
Eric Laurent212532b2014-07-21 15:43:18 -0700839 if (mUseFixedVolume || isPlatformTelevision()) {
Eric Laurent83a017b2013-03-19 18:15:31 -0700840 ringerMode = AudioManager.RINGER_MODE_NORMAL;
841 }
Glenn Kastenba195eb2011-12-13 09:30:40 -0800842 synchronized(mSettingsLock) {
843 mRingerMode = ringerMode;
John Spurlock661f2cf2014-11-17 10:29:10 -0500844 if (mRingerModeExternal == -1) {
845 mRingerModeExternal = mRingerMode;
846 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800847
Eric Laurentdd45d012012-10-08 09:04:34 -0700848 // System.VIBRATE_ON is not used any more but defaults for mVibrateSetting
849 // are still needed while setVibrateSetting() and getVibrateSetting() are being
850 // deprecated.
John Spurlock61560172015-02-06 19:46:04 -0500851 mVibrateSetting = AudioSystem.getValueForVibrateSetting(0,
Eric Laurentdd45d012012-10-08 09:04:34 -0700852 AudioManager.VIBRATE_TYPE_NOTIFICATION,
853 mHasVibrator ? AudioManager.VIBRATE_SETTING_ONLY_SILENT
854 : AudioManager.VIBRATE_SETTING_OFF);
John Spurlock61560172015-02-06 19:46:04 -0500855 mVibrateSetting = AudioSystem.getValueForVibrateSetting(mVibrateSetting,
Eric Laurentdd45d012012-10-08 09:04:34 -0700856 AudioManager.VIBRATE_TYPE_RINGER,
857 mHasVibrator ? AudioManager.VIBRATE_SETTING_ONLY_SILENT
858 : AudioManager.VIBRATE_SETTING_OFF);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800859
Eric Laurent24e0d9b2013-10-03 18:15:07 -0700860 updateRingerModeAffectedStreams();
Eric Laurent7ee1e4f2012-10-26 18:11:21 -0700861 readDockAudioSettings(cr);
Eric Laurent402f7f22011-02-04 12:30:32 -0800862 }
Eric Laurentc1d41662011-07-19 11:21:13 -0700863
Eric Laurentbc0fab1f2012-09-19 11:24:41 -0700864 mMuteAffectedStreams = System.getIntForUser(cr,
John Spurlock61560172015-02-06 19:46:04 -0500865 System.MUTE_STREAMS_AFFECTED, AudioSystem.DEFAULT_MUTE_STREAMS_AFFECTED,
John Spurlock24c05182015-02-05 12:30:36 -0500866 UserHandle.USER_CURRENT);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800867
Eric Laurentbc0fab1f2012-09-19 11:24:41 -0700868 boolean masterMute = System.getIntForUser(cr, System.VOLUME_MASTER_MUTE,
John Spurlockee5ad722015-03-03 16:17:21 -0500869 0, UserHandle.USER_CURRENT) == 1;
Eric Laurent83a017b2013-03-19 18:15:31 -0700870 if (mUseFixedVolume) {
871 masterMute = false;
872 AudioSystem.setMasterVolume(1.0f);
873 }
Justin Koh57978ed2012-04-03 17:37:58 -0700874 AudioSystem.setMasterMute(masterMute);
875 broadcastMasterMuteStatus(masterMute);
876
Julia Reynoldsb53453f2014-08-22 11:42:43 -0400877 boolean microphoneMute =
878 System.getIntForUser(cr, System.MICROPHONE_MUTE, 0, UserHandle.USER_CURRENT) == 1;
879 AudioSystem.muteMicrophone(microphoneMute);
880
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800881 // Each stream will read its own persisted settings
882
John Spurlockbcc10872014-11-28 15:29:21 -0500883 // Broadcast the sticky intents
884 broadcastRingerMode(AudioManager.RINGER_MODE_CHANGED_ACTION, mRingerModeExternal);
885 broadcastRingerMode(AudioManager.INTERNAL_RINGER_MODE_CHANGED_ACTION, mRingerMode);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800886
887 // Broadcast vibrate settings
888 broadcastVibrateSetting(AudioManager.VIBRATE_TYPE_RINGER);
889 broadcastVibrateSetting(AudioManager.VIBRATE_TYPE_NOTIFICATION);
Jean-Michel Trivid589fea2011-04-15 11:28:10 -0700890
John Spurlock33f4e042014-07-11 13:10:58 -0400891 // Load settings for the volume controller
892 mVolumeController.loadSettings(cr);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800893 }
894
Eric Laurenta553c252009-07-17 12:17:14 -0700895 private int rescaleIndex(int index, int srcStream, int dstStream) {
896 return (index * mStreamStates[dstStream].getMaxIndex() + mStreamStates[srcStream].getMaxIndex() / 2) / mStreamStates[srcStream].getMaxIndex();
897 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800898
Jon Eklund318f0fe2014-01-23 17:53:48 -0600899 private class AudioOrientationEventListener
900 extends OrientationEventListener {
901 public AudioOrientationEventListener(Context context) {
902 super(context);
903 }
904
905 @Override
906 public void onOrientationChanged(int orientation) {
907 //Even though we're responding to phone orientation events,
908 //use display rotation so audio stays in sync with video/dialogs
909 int newRotation = ((WindowManager) mContext.getSystemService(
910 Context.WINDOW_SERVICE)).getDefaultDisplay().getRotation();
911 if (newRotation != mDeviceRotation) {
912 mDeviceRotation = newRotation;
913 setRotationForAudioSystem();
914 }
915 }
916 }
917
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800918 ///////////////////////////////////////////////////////////////////////////
919 // IPC methods
920 ///////////////////////////////////////////////////////////////////////////
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800921 /** @see AudioManager#adjustVolume(int, int) */
Dianne Hackbornba50b97c2013-04-30 15:04:46 -0700922 public void adjustSuggestedStreamVolume(int direction, int suggestedStreamType, int flags,
923 String callingPackage) {
RoboErik272e1612014-09-05 11:39:29 -0700924 adjustSuggestedStreamVolume(direction, suggestedStreamType, flags, callingPackage,
925 Binder.getCallingUid());
926 }
927
928 private void adjustSuggestedStreamVolume(int direction, int suggestedStreamType, int flags,
929 String callingPackage, int uid) {
John Spurlockae641c92014-06-30 18:11:40 -0400930 if (DEBUG_VOL) Log.d(TAG, "adjustSuggestedStreamVolume() stream="+suggestedStreamType
931 + ", flags=" + flags);
Eric Laurent402f7f22011-02-04 12:30:32 -0800932 int streamType;
RoboErik4197cb62015-01-21 15:45:32 -0800933 boolean isMute = isMuteAdjust(direction);
Eric Laurent45c90ce2012-04-24 18:44:22 -0700934 if (mVolumeControlStream != -1) {
935 streamType = mVolumeControlStream;
Eric Laurent402f7f22011-02-04 12:30:32 -0800936 } else {
937 streamType = getActiveStreamType(suggestedStreamType);
938 }
John Spurlock33f4e042014-07-11 13:10:58 -0400939 final int resolvedStream = mStreamVolumeAlias[streamType];
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800940
RoboErik2811dd32014-08-12 09:48:13 -0700941 // Play sounds on STREAM_RING only.
942 if ((flags & AudioManager.FLAG_PLAY_SOUND) != 0 &&
John Spurlock33f4e042014-07-11 13:10:58 -0400943 resolvedStream != AudioSystem.STREAM_RING) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800944 flags &= ~AudioManager.FLAG_PLAY_SOUND;
945 }
946
John Spurlock33f4e042014-07-11 13:10:58 -0400947 // For notifications/ring, show the ui before making any adjustments
RoboErik4197cb62015-01-21 15:45:32 -0800948 // Don't suppress mute/unmute requests
949 if (mVolumeController.suppressAdjustment(resolvedStream, flags, isMute)) {
John Spurlock33f4e042014-07-11 13:10:58 -0400950 direction = 0;
951 flags &= ~AudioManager.FLAG_PLAY_SOUND;
952 flags &= ~AudioManager.FLAG_VIBRATE;
953 if (DEBUG_VOL) Log.d(TAG, "Volume controller suppressed adjustment");
954 }
955
RoboErik272e1612014-09-05 11:39:29 -0700956 adjustStreamVolume(streamType, direction, flags, callingPackage, uid);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800957 }
958
959 /** @see AudioManager#adjustStreamVolume(int, int, int) */
Dianne Hackbornba50b97c2013-04-30 15:04:46 -0700960 public void adjustStreamVolume(int streamType, int direction, int flags,
961 String callingPackage) {
RoboErik0dac35a2014-08-12 15:48:49 -0700962 adjustStreamVolume(streamType, direction, flags, callingPackage, Binder.getCallingUid());
963 }
964
965 private void adjustStreamVolume(int streamType, int direction, int flags,
966 String callingPackage, int uid) {
Eric Laurent83a017b2013-03-19 18:15:31 -0700967 if (mUseFixedVolume) {
968 return;
969 }
John Spurlockae641c92014-06-30 18:11:40 -0400970 if (DEBUG_VOL) Log.d(TAG, "adjustStreamVolume() stream="+streamType+", dir="+direction
971 + ", flags="+flags);
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -0700972
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800973 ensureValidDirection(direction);
974 ensureValidStreamType(streamType);
975
RoboErik4197cb62015-01-21 15:45:32 -0800976 boolean isMuteAdjust = isMuteAdjust(direction);
977
John Spurlock3ce37252015-02-17 13:20:45 -0500978 if (isMuteAdjust && !isStreamAffectedByMute(streamType)) {
979 return;
980 }
981
Eric Laurent96a33d12011-11-08 10:31:57 -0800982 // use stream type alias here so that streams with same alias have the same behavior,
983 // including with regard to silent mode control (e.g the use of STREAM_RING below and in
984 // checkForRingerModeChange() in place of STREAM_RING or STREAM_NOTIFICATION)
Eric Laurent6d517662012-04-23 18:42:39 -0700985 int streamTypeAlias = mStreamVolumeAlias[streamType];
RoboErik4197cb62015-01-21 15:45:32 -0800986
Eric Laurentb024c302011-10-14 17:19:27 -0700987 VolumeStreamState streamState = mStreamStates[streamTypeAlias];
Eric Laurent9bc8358d2011-11-18 16:43:31 -0800988
989 final int device = getDeviceForStream(streamTypeAlias);
Eric Laurent3ef75492012-11-28 12:12:23 -0800990
Eric Laurent42b041e2013-03-29 11:36:03 -0700991 int aliasIndex = streamState.getIndex(device);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800992 boolean adjustVolume = true;
Eric Laurent3ef75492012-11-28 12:12:23 -0800993 int step;
Eric Laurent24482012012-05-10 09:41:17 -0700994
Matthew Xiec9d1d5f2013-09-12 00:32:22 -0700995 // skip a2dp absolute volume control request when the device
996 // is not an a2dp device
997 if ((device & AudioSystem.DEVICE_OUT_ALL_A2DP) == 0 &&
998 (flags & AudioManager.FLAG_BLUETOOTH_ABS_VOLUME) != 0) {
999 return;
1000 }
1001
John Spurlock59dc9c12015-03-02 11:20:15 -05001002 if (mAppOps.noteOp(STREAM_VOLUME_OPS[streamTypeAlias], uid, callingPackage)
RoboErik0dac35a2014-08-12 15:48:49 -07001003 != AppOpsManager.MODE_ALLOWED) {
Dianne Hackbornba50b97c2013-04-30 15:04:46 -07001004 return;
1005 }
1006
Eric Laurentfde16d52012-12-03 14:42:39 -08001007 // reset any pending volume command
1008 synchronized (mSafeMediaVolumeState) {
1009 mPendingVolumeCommand = null;
1010 }
1011
Eric Laurent3ef75492012-11-28 12:12:23 -08001012 flags &= ~AudioManager.FLAG_FIXED_VOLUME;
1013 if ((streamTypeAlias == AudioSystem.STREAM_MUSIC) &&
1014 ((device & mFixedVolumeDevices) != 0)) {
1015 flags |= AudioManager.FLAG_FIXED_VOLUME;
1016
1017 // Always toggle between max safe volume and 0 for fixed volume devices where safe
1018 // volume is enforced, and max and 0 for the others.
1019 // This is simulated by stepping by the full allowed volume range
1020 if (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_ACTIVE &&
1021 (device & mSafeMediaVolumeDevices) != 0) {
1022 step = mSafeMediaVolumeIndex;
1023 } else {
1024 step = streamState.getMaxIndex();
1025 }
1026 if (aliasIndex != 0) {
1027 aliasIndex = step;
1028 }
1029 } else {
1030 // convert one UI step (+/-1) into a number of internal units on the stream alias
1031 step = rescaleIndex(10, streamType, streamTypeAlias);
1032 }
1033
Eric Laurent42b041e2013-03-29 11:36:03 -07001034 // If either the client forces allowing ringer modes for this adjustment,
1035 // or the stream type is one that is affected by ringer modes
1036 if (((flags & AudioManager.FLAG_ALLOW_RINGER_MODES) != 0) ||
John Spurlockee5ad722015-03-03 16:17:21 -05001037 (streamTypeAlias == getUiSoundsStreamType())) {
John Spurlock661f2cf2014-11-17 10:29:10 -05001038 int ringerMode = getRingerModeInternal();
Eric Laurent42b041e2013-03-29 11:36:03 -07001039 // do not vibrate if already in vibrate mode
1040 if (ringerMode == AudioManager.RINGER_MODE_VIBRATE) {
1041 flags &= ~AudioManager.FLAG_VIBRATE;
Eric Laurent3ef75492012-11-28 12:12:23 -08001042 }
RoboErik5452e252015-02-06 15:33:53 -08001043 // Check if the ringer mode handles this adjustment. If it does we don't
1044 // need to adjust the volume further.
1045 final int result = checkForRingerModeChange(aliasIndex, direction, step, streamState.mIsMuted);
John Spurlocka11b4af2014-06-01 11:52:23 -04001046 adjustVolume = (result & FLAG_ADJUST_VOLUME) != 0;
1047 // If suppressing a volume adjustment in silent mode, display the UI hint
1048 if ((result & AudioManager.FLAG_SHOW_SILENT_HINT) != 0) {
1049 flags |= AudioManager.FLAG_SHOW_SILENT_HINT;
1050 }
John Spurlock661f2cf2014-11-17 10:29:10 -05001051 // If suppressing a volume down adjustment in vibrate mode, display the UI hint
1052 if ((result & AudioManager.FLAG_SHOW_VIBRATE_HINT) != 0) {
1053 flags |= AudioManager.FLAG_SHOW_VIBRATE_HINT;
1054 }
Eric Laurent42b041e2013-03-29 11:36:03 -07001055 }
Eric Laurent3ef75492012-11-28 12:12:23 -08001056
Eric Laurent42b041e2013-03-29 11:36:03 -07001057 int oldIndex = mStreamStates[streamType].getIndex(device);
Eric Laurent3ef75492012-11-28 12:12:23 -08001058
Eric Laurent42b041e2013-03-29 11:36:03 -07001059 if (adjustVolume && (direction != AudioManager.ADJUST_SAME)) {
RoboErik5452e252015-02-06 15:33:53 -08001060 mAudioHandler.removeMessages(MSG_UNMUTE_STREAM);
Matthew Xiec9d1d5f2013-09-12 00:32:22 -07001061
John Du5a0cf7a2013-07-19 11:30:34 -07001062 // Check if volume update should be send to AVRCP
Matthew Xiec9d1d5f2013-09-12 00:32:22 -07001063 if (streamTypeAlias == AudioSystem.STREAM_MUSIC &&
1064 (device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0 &&
1065 (flags & AudioManager.FLAG_BLUETOOTH_ABS_VOLUME) == 0) {
1066 synchronized (mA2dpAvrcpLock) {
1067 if (mA2dp != null && mAvrcpAbsVolSupported) {
1068 mA2dp.adjustAvrcpAbsoluteVolume(direction);
1069 }
John Du5a0cf7a2013-07-19 11:30:34 -07001070 }
1071 }
Matthew Xiec9d1d5f2013-09-12 00:32:22 -07001072
RoboErik4197cb62015-01-21 15:45:32 -08001073 if (isMuteAdjust) {
1074 boolean state;
1075 if (direction == AudioManager.ADJUST_TOGGLE_MUTE) {
1076 state = !streamState.mIsMuted;
1077 } else {
1078 state = direction == AudioManager.ADJUST_MUTE;
1079 }
1080 if (streamTypeAlias == AudioSystem.STREAM_MUSIC) {
1081 setSystemAudioMute(state);
1082 }
1083 for (int stream = 0; stream < mStreamStates.length; stream++) {
1084 if (streamTypeAlias == mStreamVolumeAlias[stream]) {
1085 mStreamStates[stream].mute(state);
RoboErik4197cb62015-01-21 15:45:32 -08001086 }
1087 }
1088 } else if ((direction == AudioManager.ADJUST_RAISE) &&
Eric Laurent42b041e2013-03-29 11:36:03 -07001089 !checkSafeMediaVolume(streamTypeAlias, aliasIndex + step, device)) {
RoboErik4197cb62015-01-21 15:45:32 -08001090 Log.e(TAG, "adjustStreamVolume() safe volume index = " + oldIndex);
John Spurlock3346a802014-05-20 16:25:37 -04001091 mVolumeController.postDisplaySafeVolumeWarning(flags);
RoboErik4197cb62015-01-21 15:45:32 -08001092 } else if (streamState.adjustIndex(direction * step, device) || streamState.mIsMuted) {
1093 // Post message to set system volume (it in turn will post a
1094 // message to persist).
1095 if (streamState.mIsMuted) {
1096 // Unmute the stream if it was previously muted
RoboErik5452e252015-02-06 15:33:53 -08001097 if (direction == AudioManager.ADJUST_RAISE) {
1098 // unmute immediately for volume up
1099 streamState.mute(false);
1100 } else if (direction == AudioManager.ADJUST_LOWER) {
1101 sendMsg(mAudioHandler, MSG_UNMUTE_STREAM, SENDMSG_QUEUE,
1102 streamTypeAlias, flags, null, UNMUTE_STREAM_DELAY);
1103 }
RoboErik4197cb62015-01-21 15:45:32 -08001104 }
Eric Laurent42b041e2013-03-29 11:36:03 -07001105 sendMsg(mAudioHandler,
1106 MSG_SET_DEVICE_VOLUME,
1107 SENDMSG_QUEUE,
1108 device,
1109 0,
1110 streamState,
1111 0);
Eric Laurent4bbcc652012-09-24 14:26:30 -07001112 }
Jungshik Jang41d97462014-06-30 22:26:29 +09001113
RoboErik4197cb62015-01-21 15:45:32 -08001114 // Check if volume update should be sent to Hdmi system audio.
Jungshik Jang41d97462014-06-30 22:26:29 +09001115 int newIndex = mStreamStates[streamType].getIndex(device);
Jinsuk Kim336cdb42014-11-29 06:27:00 +09001116 if (streamTypeAlias == AudioSystem.STREAM_MUSIC) {
1117 setSystemAudioVolume(oldIndex, newIndex, getStreamMaxVolume(streamType), flags);
1118 }
Eric Laurent212532b2014-07-21 15:43:18 -07001119 if (mHdmiManager != null) {
1120 synchronized (mHdmiManager) {
Eric Laurent212532b2014-07-21 15:43:18 -07001121 // mHdmiCecSink true => mHdmiPlaybackClient != null
1122 if (mHdmiCecSink &&
1123 streamTypeAlias == AudioSystem.STREAM_MUSIC &&
1124 oldIndex != newIndex) {
1125 synchronized (mHdmiPlaybackClient) {
1126 int keyCode = (direction == -1) ? KeyEvent.KEYCODE_VOLUME_DOWN :
RoboErik4197cb62015-01-21 15:45:32 -08001127 KeyEvent.KEYCODE_VOLUME_UP;
Eric Laurent212532b2014-07-21 15:43:18 -07001128 mHdmiPlaybackClient.sendKeyEvent(keyCode, true);
1129 mHdmiPlaybackClient.sendKeyEvent(keyCode, false);
1130 }
Jungshik Jang41d97462014-06-30 22:26:29 +09001131 }
1132 }
1133 }
Eric Laurent4bbcc652012-09-24 14:26:30 -07001134 }
Eric Laurent42b041e2013-03-29 11:36:03 -07001135 int index = mStreamStates[streamType].getIndex(device);
Eric Laurent25101b02011-02-02 09:33:30 -08001136 sendVolumeUpdate(streamType, oldIndex, index, flags);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001137 }
1138
RoboErik5452e252015-02-06 15:33:53 -08001139 // Called after a delay when volume down is pressed while muted
1140 private void onUnmuteStream(int stream, int flags) {
1141 VolumeStreamState streamState = mStreamStates[stream];
1142 streamState.mute(false);
1143
1144 final int device = getDeviceForStream(stream);
1145 final int index = mStreamStates[stream].getIndex(device);
1146 sendVolumeUpdate(stream, index, index, flags);
1147 }
1148
Jinsuk Kim336cdb42014-11-29 06:27:00 +09001149 private void setSystemAudioVolume(int oldVolume, int newVolume, int maxVolume, int flags) {
1150 if (mHdmiManager == null
1151 || mHdmiTvClient == null
1152 || oldVolume == newVolume
1153 || (flags & AudioManager.FLAG_HDMI_SYSTEM_AUDIO_VOLUME) != 0) return;
1154
1155 // Sets the audio volume of AVR when we are in system audio mode. The new volume info
1156 // is tranformed to HDMI-CEC commands and passed through CEC bus.
1157 synchronized (mHdmiManager) {
1158 if (!mHdmiSystemAudioSupported) return;
1159 synchronized (mHdmiTvClient) {
Jinsuk Kim48cbf292014-12-13 02:16:28 +09001160 final long token = Binder.clearCallingIdentity();
1161 try {
Jinsuk Kim7a9ba422015-02-16 16:47:38 +09001162 mHdmiTvClient.setSystemAudioVolume(oldVolume, newVolume, maxVolume);
Jinsuk Kim48cbf292014-12-13 02:16:28 +09001163 } finally {
1164 Binder.restoreCallingIdentity(token);
1165 }
Jinsuk Kim336cdb42014-11-29 06:27:00 +09001166 }
1167 }
1168 }
1169
Eric Laurentfde16d52012-12-03 14:42:39 -08001170 // StreamVolumeCommand contains the information needed to defer the process of
1171 // setStreamVolume() in case the user has to acknowledge the safe volume warning message.
1172 class StreamVolumeCommand {
1173 public final int mStreamType;
1174 public final int mIndex;
1175 public final int mFlags;
1176 public final int mDevice;
Eric Laurent9ce379a2010-02-16 06:00:26 -08001177
Eric Laurentfde16d52012-12-03 14:42:39 -08001178 StreamVolumeCommand(int streamType, int index, int flags, int device) {
1179 mStreamType = streamType;
1180 mIndex = index;
1181 mFlags = flags;
1182 mDevice = device;
Eric Laurentb024c302011-10-14 17:19:27 -07001183 }
John Spurlock35134602014-07-24 18:10:48 -04001184
1185 @Override
1186 public String toString() {
1187 return new StringBuilder().append("{streamType=").append(mStreamType).append(",index=")
1188 .append(mIndex).append(",flags=").append(mFlags).append(",device=")
1189 .append(mDevice).append('}').toString();
1190 }
Eric Laurentfde16d52012-12-03 14:42:39 -08001191 };
Eric Laurent3ef75492012-11-28 12:12:23 -08001192
Eric Laurentfde16d52012-12-03 14:42:39 -08001193 private void onSetStreamVolume(int streamType, int index, int flags, int device) {
Eric Laurent42b041e2013-03-29 11:36:03 -07001194 setStreamVolumeInt(mStreamVolumeAlias[streamType], index, device, false);
John Spurlockee5ad722015-03-03 16:17:21 -05001195 // setting volume on ui sounds stream type also controls silent mode
Eric Laurent3ef75492012-11-28 12:12:23 -08001196 if (((flags & AudioManager.FLAG_ALLOW_RINGER_MODES) != 0) ||
John Spurlockee5ad722015-03-03 16:17:21 -05001197 (mStreamVolumeAlias[streamType] == getUiSoundsStreamType())) {
Eric Laurent3ef75492012-11-28 12:12:23 -08001198 int newRingerMode;
1199 if (index == 0) {
1200 newRingerMode = mHasVibrator ? AudioManager.RINGER_MODE_VIBRATE
John Spurlock86005342014-05-23 11:58:00 -04001201 : VOLUME_SETS_RINGER_MODE_SILENT ? AudioManager.RINGER_MODE_SILENT
1202 : AudioManager.RINGER_MODE_NORMAL;
Eric Laurent3ef75492012-11-28 12:12:23 -08001203 } else {
1204 newRingerMode = AudioManager.RINGER_MODE_NORMAL;
1205 }
John Spurlock661f2cf2014-11-17 10:29:10 -05001206 setRingerMode(newRingerMode, TAG + ".onSetStreamVolume", false /*external*/);
Eric Laurent3ef75492012-11-28 12:12:23 -08001207 }
Eric Laurentfde16d52012-12-03 14:42:39 -08001208 }
1209
1210 /** @see AudioManager#setStreamVolume(int, int, int) */
Dianne Hackbornba50b97c2013-04-30 15:04:46 -07001211 public void setStreamVolume(int streamType, int index, int flags, String callingPackage) {
RoboErik0dac35a2014-08-12 15:48:49 -07001212 setStreamVolume(streamType, index, flags, callingPackage, Binder.getCallingUid());
1213 }
1214
1215 private void setStreamVolume(int streamType, int index, int flags, String callingPackage,
1216 int uid) {
Eric Laurent83a017b2013-03-19 18:15:31 -07001217 if (mUseFixedVolume) {
1218 return;
1219 }
1220
Eric Laurentfde16d52012-12-03 14:42:39 -08001221 ensureValidStreamType(streamType);
Dianne Hackbornba50b97c2013-04-30 15:04:46 -07001222 int streamTypeAlias = mStreamVolumeAlias[streamType];
1223 VolumeStreamState streamState = mStreamStates[streamTypeAlias];
Eric Laurentfde16d52012-12-03 14:42:39 -08001224
1225 final int device = getDeviceForStream(streamType);
1226 int oldIndex;
1227
Matthew Xiec9d1d5f2013-09-12 00:32:22 -07001228 // skip a2dp absolute volume control request when the device
1229 // is not an a2dp device
1230 if ((device & AudioSystem.DEVICE_OUT_ALL_A2DP) == 0 &&
1231 (flags & AudioManager.FLAG_BLUETOOTH_ABS_VOLUME) != 0) {
1232 return;
1233 }
1234
John Spurlock59dc9c12015-03-02 11:20:15 -05001235 if (mAppOps.noteOp(STREAM_VOLUME_OPS[streamTypeAlias], uid, callingPackage)
RoboErik0dac35a2014-08-12 15:48:49 -07001236 != AppOpsManager.MODE_ALLOWED) {
Dianne Hackbornba50b97c2013-04-30 15:04:46 -07001237 return;
1238 }
1239
Eric Laurentfde16d52012-12-03 14:42:39 -08001240 synchronized (mSafeMediaVolumeState) {
1241 // reset any pending volume command
1242 mPendingVolumeCommand = null;
1243
Eric Laurent42b041e2013-03-29 11:36:03 -07001244 oldIndex = streamState.getIndex(device);
Eric Laurentfde16d52012-12-03 14:42:39 -08001245
Dianne Hackbornba50b97c2013-04-30 15:04:46 -07001246 index = rescaleIndex(index * 10, streamType, streamTypeAlias);
Eric Laurentfde16d52012-12-03 14:42:39 -08001247
Matthew Xiec9d1d5f2013-09-12 00:32:22 -07001248 if (streamTypeAlias == AudioSystem.STREAM_MUSIC &&
1249 (device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0 &&
1250 (flags & AudioManager.FLAG_BLUETOOTH_ABS_VOLUME) == 0) {
1251 synchronized (mA2dpAvrcpLock) {
1252 if (mA2dp != null && mAvrcpAbsVolSupported) {
Zhihai Xu2f4a2b12014-01-10 16:44:39 -08001253 mA2dp.setAvrcpAbsoluteVolume(index / 10);
Matthew Xiec9d1d5f2013-09-12 00:32:22 -07001254 }
John Du5a0cf7a2013-07-19 11:30:34 -07001255 }
1256 }
1257
Jinsuk Kim336cdb42014-11-29 06:27:00 +09001258 if (streamTypeAlias == AudioSystem.STREAM_MUSIC) {
1259 setSystemAudioVolume(oldIndex, index, getStreamMaxVolume(streamType), flags);
Jungshik Jang41d97462014-06-30 22:26:29 +09001260 }
1261
Eric Laurentfde16d52012-12-03 14:42:39 -08001262 flags &= ~AudioManager.FLAG_FIXED_VOLUME;
Dianne Hackbornba50b97c2013-04-30 15:04:46 -07001263 if ((streamTypeAlias == AudioSystem.STREAM_MUSIC) &&
Eric Laurentfde16d52012-12-03 14:42:39 -08001264 ((device & mFixedVolumeDevices) != 0)) {
1265 flags |= AudioManager.FLAG_FIXED_VOLUME;
1266
1267 // volume is either 0 or max allowed for fixed volume devices
1268 if (index != 0) {
1269 if (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_ACTIVE &&
1270 (device & mSafeMediaVolumeDevices) != 0) {
1271 index = mSafeMediaVolumeIndex;
1272 } else {
1273 index = streamState.getMaxIndex();
1274 }
1275 }
1276 }
1277
Dianne Hackbornba50b97c2013-04-30 15:04:46 -07001278 if (!checkSafeMediaVolume(streamTypeAlias, index, device)) {
John Spurlock3346a802014-05-20 16:25:37 -04001279 mVolumeController.postDisplaySafeVolumeWarning(flags);
Eric Laurentfde16d52012-12-03 14:42:39 -08001280 mPendingVolumeCommand = new StreamVolumeCommand(
1281 streamType, index, flags, device);
1282 } else {
1283 onSetStreamVolume(streamType, index, flags, device);
Eric Laurent42b041e2013-03-29 11:36:03 -07001284 index = mStreamStates[streamType].getIndex(device);
Eric Laurentfde16d52012-12-03 14:42:39 -08001285 }
1286 }
Eric Laurent25101b02011-02-02 09:33:30 -08001287 sendVolumeUpdate(streamType, oldIndex, index, flags);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001288 }
1289
Eric Laurent45c90ce2012-04-24 18:44:22 -07001290 /** @see AudioManager#forceVolumeControlStream(int) */
1291 public void forceVolumeControlStream(int streamType, IBinder cb) {
1292 synchronized(mForceControlStreamLock) {
1293 mVolumeControlStream = streamType;
1294 if (mVolumeControlStream == -1) {
1295 if (mForceControlStreamClient != null) {
1296 mForceControlStreamClient.release();
1297 mForceControlStreamClient = null;
1298 }
1299 } else {
1300 mForceControlStreamClient = new ForceControlStreamClient(cb);
1301 }
1302 }
1303 }
1304
1305 private class ForceControlStreamClient implements IBinder.DeathRecipient {
1306 private IBinder mCb; // To be notified of client's death
1307
1308 ForceControlStreamClient(IBinder cb) {
1309 if (cb != null) {
1310 try {
1311 cb.linkToDeath(this, 0);
1312 } catch (RemoteException e) {
1313 // Client has died!
1314 Log.w(TAG, "ForceControlStreamClient() could not link to "+cb+" binder death");
1315 cb = null;
1316 }
1317 }
1318 mCb = cb;
1319 }
1320
1321 public void binderDied() {
1322 synchronized(mForceControlStreamLock) {
1323 Log.w(TAG, "SCO client died");
1324 if (mForceControlStreamClient != this) {
1325 Log.w(TAG, "unregistered control stream client died");
1326 } else {
1327 mForceControlStreamClient = null;
1328 mVolumeControlStream = -1;
1329 }
1330 }
1331 }
1332
1333 public void release() {
1334 if (mCb != null) {
1335 mCb.unlinkToDeath(this, 0);
1336 mCb = null;
1337 }
1338 }
1339 }
1340
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07001341 private void sendBroadcastToAll(Intent intent) {
Christopher Tate267603f2015-01-20 14:21:21 -08001342 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
John Spurlock86490862015-02-25 11:22:52 -05001343 intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07001344 final long ident = Binder.clearCallingIdentity();
1345 try {
1346 mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
1347 } finally {
1348 Binder.restoreCallingIdentity(ident);
1349 }
1350 }
1351
1352 private void sendStickyBroadcastToAll(Intent intent) {
John Spurlock86490862015-02-25 11:22:52 -05001353 intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07001354 final long ident = Binder.clearCallingIdentity();
1355 try {
1356 mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
1357 } finally {
1358 Binder.restoreCallingIdentity(ident);
1359 }
1360 }
1361
Eric Laurent25101b02011-02-02 09:33:30 -08001362 // UI update and Broadcast Intent
1363 private void sendVolumeUpdate(int streamType, int oldIndex, int index, int flags) {
Eric Laurent212532b2014-07-21 15:43:18 -07001364 if (!isPlatformVoice() && (streamType == AudioSystem.STREAM_RING)) {
Eric Laurent25101b02011-02-02 09:33:30 -08001365 streamType = AudioSystem.STREAM_NOTIFICATION;
1366 }
1367
Jinsuk Kim336cdb42014-11-29 06:27:00 +09001368 if (streamType == AudioSystem.STREAM_MUSIC) {
1369 flags = updateFlagsForSystemAudio(flags);
Jungshik Jang1a6be6e2014-09-16 11:04:54 +09001370 }
John Spurlock3346a802014-05-20 16:25:37 -04001371 mVolumeController.postVolumeChanged(streamType, flags);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001372 }
1373
Jinsuk Kim336cdb42014-11-29 06:27:00 +09001374 // If Hdmi-CEC system audio mode is on, we show volume bar only when TV
1375 // receives volume notification from Audio Receiver.
1376 private int updateFlagsForSystemAudio(int flags) {
1377 if (mHdmiTvClient != null) {
1378 synchronized (mHdmiTvClient) {
1379 if (mHdmiSystemAudioSupported &&
1380 ((flags & AudioManager.FLAG_HDMI_SYSTEM_AUDIO_VOLUME) == 0)) {
1381 flags &= ~AudioManager.FLAG_SHOW_UI;
1382 }
1383 }
1384 }
1385 return flags;
1386 }
1387
Mike Lockwood0dc37cc2011-12-01 16:14:19 -05001388 // UI update and Broadcast Intent
Mike Lockwood0dc37cc2011-12-01 16:14:19 -05001389 private void sendMasterMuteUpdate(boolean muted, int flags) {
Jinsuk Kim336cdb42014-11-29 06:27:00 +09001390 mVolumeController.postMasterMuteChanged(updateFlagsForSystemAudio(flags));
Justin Koh57978ed2012-04-03 17:37:58 -07001391 broadcastMasterMuteStatus(muted);
1392 }
Mike Lockwood0dc37cc2011-12-01 16:14:19 -05001393
Justin Koh57978ed2012-04-03 17:37:58 -07001394 private void broadcastMasterMuteStatus(boolean muted) {
Mike Lockwood0dc37cc2011-12-01 16:14:19 -05001395 Intent intent = new Intent(AudioManager.MASTER_MUTE_CHANGED_ACTION);
1396 intent.putExtra(AudioManager.EXTRA_MASTER_VOLUME_MUTED, muted);
Justin Koh57978ed2012-04-03 17:37:58 -07001397 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT
1398 | Intent.FLAG_RECEIVER_REPLACE_PENDING);
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07001399 sendStickyBroadcastToAll(intent);
Mike Lockwood0dc37cc2011-12-01 16:14:19 -05001400 }
1401
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001402 /**
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001403 * Sets the stream state's index, and posts a message to set system volume.
1404 * This will not call out to the UI. Assumes a valid stream type.
1405 *
1406 * @param streamType Type of the stream
1407 * @param index Desired volume index of the stream
Eric Laurent9bc8358d2011-11-18 16:43:31 -08001408 * @param device the device whose volume must be changed
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001409 * @param force If true, set the volume even if the desired volume is same
1410 * as the current volume.
1411 */
Eric Laurent9bc8358d2011-11-18 16:43:31 -08001412 private void setStreamVolumeInt(int streamType,
1413 int index,
1414 int device,
Eric Laurent42b041e2013-03-29 11:36:03 -07001415 boolean force) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001416 VolumeStreamState streamState = mStreamStates[streamType];
Eric Laurent5b4e6542010-03-19 20:02:21 -07001417
Eric Laurent42b041e2013-03-29 11:36:03 -07001418 if (streamState.setIndex(index, device) || force) {
1419 // Post message to set system volume (it in turn will post a message
1420 // to persist).
1421 sendMsg(mAudioHandler,
1422 MSG_SET_DEVICE_VOLUME,
1423 SENDMSG_QUEUE,
1424 device,
1425 0,
1426 streamState,
1427 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001428 }
1429 }
1430
Jinsuk Kim336cdb42014-11-29 06:27:00 +09001431 private void setSystemAudioMute(boolean state) {
1432 if (mHdmiManager == null || mHdmiTvClient == null) return;
1433 synchronized (mHdmiManager) {
Jinsuk Kim48cbf292014-12-13 02:16:28 +09001434 if (!mHdmiSystemAudioSupported) return;
1435 synchronized (mHdmiTvClient) {
1436 final long token = Binder.clearCallingIdentity();
1437 try {
1438 mHdmiTvClient.setSystemAudioMute(state);
1439 } finally {
1440 Binder.restoreCallingIdentity(token);
Jinsuk Kim336cdb42014-11-29 06:27:00 +09001441 }
Jinsuk Kim336cdb42014-11-29 06:27:00 +09001442 }
1443 }
1444 }
1445
Eric Laurent25101b02011-02-02 09:33:30 -08001446 /** get stream mute state. */
1447 public boolean isStreamMute(int streamType) {
RoboErik7c82ced2014-12-04 17:39:08 -08001448 if (streamType == AudioManager.USE_DEFAULT_STREAM_TYPE) {
1449 streamType = getActiveStreamType(streamType);
1450 }
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07001451 synchronized (VolumeStreamState.class) {
RoboErik4197cb62015-01-21 15:45:32 -08001452 return mStreamStates[streamType].mIsMuted;
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07001453 }
Eric Laurent25101b02011-02-02 09:33:30 -08001454 }
1455
Jean-Michel Triviba5270b2014-10-01 17:49:29 -07001456 private class RmtSbmxFullVolDeathHandler implements IBinder.DeathRecipient {
1457 private IBinder mICallback; // To be notified of client's death
1458
1459 RmtSbmxFullVolDeathHandler(IBinder cb) {
1460 mICallback = cb;
1461 try {
1462 cb.linkToDeath(this, 0/*flags*/);
1463 } catch (RemoteException e) {
1464 Log.e(TAG, "can't link to death", e);
1465 }
1466 }
1467
1468 boolean isHandlerFor(IBinder cb) {
1469 return mICallback.equals(cb);
1470 }
1471
1472 void forget() {
1473 try {
1474 mICallback.unlinkToDeath(this, 0/*flags*/);
1475 } catch (NoSuchElementException e) {
1476 Log.e(TAG, "error unlinking to death", e);
1477 }
1478 }
1479
1480 public void binderDied() {
1481 Log.w(TAG, "Recorder with remote submix at full volume died " + mICallback);
1482 forceRemoteSubmixFullVolume(false, mICallback);
1483 }
1484 }
1485
1486 /**
1487 * call must be synchronized on mRmtSbmxFullVolDeathHandlers
1488 * @return true if there is a registered death handler, false otherwise */
1489 private boolean discardRmtSbmxFullVolDeathHandlerFor(IBinder cb) {
1490 Iterator<RmtSbmxFullVolDeathHandler> it = mRmtSbmxFullVolDeathHandlers.iterator();
1491 while (it.hasNext()) {
1492 final RmtSbmxFullVolDeathHandler handler = it.next();
1493 if (handler.isHandlerFor(cb)) {
1494 handler.forget();
1495 mRmtSbmxFullVolDeathHandlers.remove(handler);
1496 return true;
1497 }
1498 }
1499 return false;
1500 }
1501
1502 /** call synchronized on mRmtSbmxFullVolDeathHandlers */
1503 private boolean hasRmtSbmxFullVolDeathHandlerFor(IBinder cb) {
1504 Iterator<RmtSbmxFullVolDeathHandler> it = mRmtSbmxFullVolDeathHandlers.iterator();
1505 while (it.hasNext()) {
1506 if (it.next().isHandlerFor(cb)) {
1507 return true;
1508 }
1509 }
1510 return false;
1511 }
1512
1513 private int mRmtSbmxFullVolRefCount = 0;
1514 private ArrayList<RmtSbmxFullVolDeathHandler> mRmtSbmxFullVolDeathHandlers =
1515 new ArrayList<RmtSbmxFullVolDeathHandler>();
1516
1517 public void forceRemoteSubmixFullVolume(boolean startForcing, IBinder cb) {
1518 if (cb == null) {
1519 return;
1520 }
1521 if ((PackageManager.PERMISSION_GRANTED != mContext.checkCallingOrSelfPermission(
1522 android.Manifest.permission.CAPTURE_AUDIO_OUTPUT))) {
1523 Log.w(TAG, "Trying to call forceRemoteSubmixFullVolume() without CAPTURE_AUDIO_OUTPUT");
1524 return;
1525 }
1526 synchronized(mRmtSbmxFullVolDeathHandlers) {
1527 boolean applyRequired = false;
1528 if (startForcing) {
1529 if (!hasRmtSbmxFullVolDeathHandlerFor(cb)) {
1530 mRmtSbmxFullVolDeathHandlers.add(new RmtSbmxFullVolDeathHandler(cb));
1531 if (mRmtSbmxFullVolRefCount == 0) {
1532 mFullVolumeDevices |= AudioSystem.DEVICE_OUT_REMOTE_SUBMIX;
1533 mFixedVolumeDevices |= AudioSystem.DEVICE_OUT_REMOTE_SUBMIX;
1534 applyRequired = true;
1535 }
1536 mRmtSbmxFullVolRefCount++;
1537 }
1538 } else {
1539 if (discardRmtSbmxFullVolDeathHandlerFor(cb) && (mRmtSbmxFullVolRefCount > 0)) {
1540 mRmtSbmxFullVolRefCount--;
1541 if (mRmtSbmxFullVolRefCount == 0) {
1542 mFullVolumeDevices &= ~AudioSystem.DEVICE_OUT_REMOTE_SUBMIX;
1543 mFixedVolumeDevices &= ~AudioSystem.DEVICE_OUT_REMOTE_SUBMIX;
1544 applyRequired = true;
1545 }
1546 }
1547 }
1548 if (applyRequired) {
1549 // Assumes only STREAM_MUSIC going through DEVICE_OUT_REMOTE_SUBMIX
1550 checkAllFixedVolumeDevices(AudioSystem.STREAM_MUSIC);
1551 mStreamStates[AudioSystem.STREAM_MUSIC].applyAllVolumes();
1552 }
1553 }
1554 }
1555
John Spurlockee5ad722015-03-03 16:17:21 -05001556 private void setMasterMuteInternal(boolean mute, int flags, String callingPackage, int uid) {
RoboErik7c82ced2014-12-04 17:39:08 -08001557 if (mAppOps.noteOp(AppOpsManager.OP_AUDIO_MASTER_VOLUME, uid, callingPackage)
1558 != AppOpsManager.MODE_ALLOWED) {
Julia Reynolds4a21b252014-06-04 11:11:43 -04001559 return;
1560 }
John Spurlockee5ad722015-03-03 16:17:21 -05001561 if (mute != AudioSystem.getMasterMute()) {
1562 setSystemAudioMute(mute);
1563 AudioSystem.setMasterMute(mute);
Justin Koh57978ed2012-04-03 17:37:58 -07001564 // Post a persist master volume msg
John Spurlockee5ad722015-03-03 16:17:21 -05001565 sendMsg(mAudioHandler, MSG_PERSIST_MASTER_VOLUME_MUTE, SENDMSG_REPLACE, mute ? 1
Julia Reynoldsb53453f2014-08-22 11:42:43 -04001566 : 0, UserHandle.getCallingUserId(), null, PERSIST_DELAY);
John Spurlockee5ad722015-03-03 16:17:21 -05001567 sendMasterMuteUpdate(mute, flags);
RoboErik7c82ced2014-12-04 17:39:08 -08001568
1569 Intent intent = new Intent(AudioManager.MASTER_MUTE_CHANGED_ACTION);
John Spurlockee5ad722015-03-03 16:17:21 -05001570 intent.putExtra(AudioManager.EXTRA_MASTER_VOLUME_MUTED, mute);
RoboErik7c82ced2014-12-04 17:39:08 -08001571 sendBroadcastToAll(intent);
Jason Simmons1ce5b262012-02-02 13:00:17 -08001572 }
Mike Lockwoodce952c82011-11-14 10:47:42 -08001573 }
1574
1575 /** get master mute state. */
1576 public boolean isMasterMute() {
Mike Lockwood3194ea92011-12-07 11:47:31 -08001577 return AudioSystem.getMasterMute();
Mike Lockwoodce952c82011-11-14 10:47:42 -08001578 }
1579
John Spurlockee5ad722015-03-03 16:17:21 -05001580 public void setMasterMute(boolean mute, int flags, String callingPackage) {
1581 setMasterMuteInternal(mute, flags, callingPackage, Binder.getCallingUid());
1582 }
1583
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -07001584 protected static int getMaxStreamVolume(int streamType) {
1585 return MAX_STREAM_VOLUME[streamType];
1586 }
1587
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001588 /** @see AudioManager#getStreamVolume(int) */
1589 public int getStreamVolume(int streamType) {
1590 ensureValidStreamType(streamType);
Eric Laurent9bc8358d2011-11-18 16:43:31 -08001591 int device = getDeviceForStream(streamType);
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07001592 synchronized (VolumeStreamState.class) {
1593 int index = mStreamStates[streamType].getIndex(device);
Eric Laurent4bbcc652012-09-24 14:26:30 -07001594
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07001595 // by convention getStreamVolume() returns 0 when a stream is muted.
RoboErik4197cb62015-01-21 15:45:32 -08001596 if (mStreamStates[streamType].mIsMuted) {
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07001597 index = 0;
1598 }
1599 if (index != 0 && (mStreamVolumeAlias[streamType] == AudioSystem.STREAM_MUSIC) &&
1600 (device & mFixedVolumeDevices) != 0) {
1601 index = mStreamStates[streamType].getMaxIndex();
1602 }
1603 return (index + 5) / 10;
Eric Laurent42b041e2013-03-29 11:36:03 -07001604 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001605 }
1606
1607 /** @see AudioManager#getStreamMaxVolume(int) */
1608 public int getStreamMaxVolume(int streamType) {
1609 ensureValidStreamType(streamType);
Eric Laurenta553c252009-07-17 12:17:14 -07001610 return (mStreamStates[streamType].getMaxIndex() + 5) / 10;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001611 }
1612
Eric Laurent25101b02011-02-02 09:33:30 -08001613 /** Get last audible volume before stream was muted. */
1614 public int getLastAudibleStreamVolume(int streamType) {
1615 ensureValidStreamType(streamType);
Eric Laurent9bc8358d2011-11-18 16:43:31 -08001616 int device = getDeviceForStream(streamType);
Eric Laurent42b041e2013-03-29 11:36:03 -07001617 return (mStreamStates[streamType].getIndex(device) + 5) / 10;
Eric Laurent25101b02011-02-02 09:33:30 -08001618 }
1619
John Spurlockee5ad722015-03-03 16:17:21 -05001620 /** @see AudioManager#getUiSoundsStreamType() */
1621 public int getUiSoundsStreamType() {
John Spurlock4f0f1202014-08-05 13:28:33 -04001622 return mStreamVolumeAlias[AudioSystem.STREAM_SYSTEM];
Eric Laurent6d517662012-04-23 18:42:39 -07001623 }
1624
Emily Bernier22c921a2014-05-28 11:01:32 -04001625 /** @see AudioManager#setMicrophoneMute(boolean) */
1626 public void setMicrophoneMute(boolean on, String callingPackage) {
1627 if (mAppOps.noteOp(AppOpsManager.OP_MUTE_MICROPHONE, Binder.getCallingUid(),
1628 callingPackage) != AppOpsManager.MODE_ALLOWED) {
1629 return;
1630 }
Jean-Michel Trivi4a4fea02014-08-29 18:14:09 -07001631 if (!checkAudioSettingsPermission("setMicrophoneMute()")) {
1632 return;
1633 }
Emily Bernier22c921a2014-05-28 11:01:32 -04001634
1635 AudioSystem.muteMicrophone(on);
Julia Reynoldsb53453f2014-08-22 11:42:43 -04001636 // Post a persist microphone msg.
1637 sendMsg(mAudioHandler, MSG_PERSIST_MICROPHONE_MUTE, SENDMSG_REPLACE, on ? 1
1638 : 0, UserHandle.getCallingUserId(), null, PERSIST_DELAY);
Emily Bernier22c921a2014-05-28 11:01:32 -04001639 }
1640
John Spurlock661f2cf2014-11-17 10:29:10 -05001641 @Override
1642 public int getRingerModeExternal() {
1643 synchronized(mSettingsLock) {
1644 return mRingerModeExternal;
1645 }
1646 }
1647
1648 @Override
1649 public int getRingerModeInternal() {
Glenn Kastenba195eb2011-12-13 09:30:40 -08001650 synchronized(mSettingsLock) {
1651 return mRingerMode;
1652 }
1653 }
1654
1655 private void ensureValidRingerMode(int ringerMode) {
John Spurlock97559372014-10-24 16:27:36 -04001656 if (!isValidRingerMode(ringerMode)) {
Glenn Kastenba195eb2011-12-13 09:30:40 -08001657 throw new IllegalArgumentException("Bad ringer mode " + ringerMode);
1658 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001659 }
1660
John Spurlock97559372014-10-24 16:27:36 -04001661 /** @see AudioManager#isValidRingerMode(int) */
1662 public boolean isValidRingerMode(int ringerMode) {
1663 return ringerMode >= 0 && ringerMode <= AudioManager.RINGER_MODE_MAX;
1664 }
1665
John Spurlock661f2cf2014-11-17 10:29:10 -05001666 public void setRingerModeExternal(int ringerMode, String caller) {
John Spurlockaf88a192014-12-23 16:14:44 -05001667 setRingerMode(ringerMode, caller, true /*external*/);
John Spurlock661f2cf2014-11-17 10:29:10 -05001668 }
1669
1670 public void setRingerModeInternal(int ringerMode, String caller) {
John Spurlockcdb57ae2015-02-11 19:04:11 -05001671 enforceVolumeController("setRingerModeInternal");
John Spurlockaf88a192014-12-23 16:14:44 -05001672 setRingerMode(ringerMode, caller, false /*external*/);
John Spurlock661f2cf2014-11-17 10:29:10 -05001673 }
1674
1675 private void setRingerMode(int ringerMode, String caller, boolean external) {
Eric Laurent212532b2014-07-21 15:43:18 -07001676 if (mUseFixedVolume || isPlatformTelevision()) {
Eric Laurent83a017b2013-03-19 18:15:31 -07001677 return;
1678 }
John Spurlock661f2cf2014-11-17 10:29:10 -05001679 if (caller == null || caller.length() == 0) {
1680 throw new IllegalArgumentException("Bad caller: " + caller);
1681 }
John Spurlock97559372014-10-24 16:27:36 -04001682 ensureValidRingerMode(ringerMode);
Eric Laurent24482012012-05-10 09:41:17 -07001683 if ((ringerMode == AudioManager.RINGER_MODE_VIBRATE) && !mHasVibrator) {
1684 ringerMode = AudioManager.RINGER_MODE_SILENT;
1685 }
John Spurlockaf88a192014-12-23 16:14:44 -05001686 final long identity = Binder.clearCallingIdentity();
1687 try {
1688 synchronized (mSettingsLock) {
1689 final int ringerModeInternal = getRingerModeInternal();
1690 final int ringerModeExternal = getRingerModeExternal();
1691 if (external) {
1692 setRingerModeExt(ringerMode);
1693 if (mRingerModeDelegate != null) {
1694 ringerMode = mRingerModeDelegate.onSetRingerModeExternal(ringerModeExternal,
1695 ringerMode, caller, ringerModeInternal);
1696 }
1697 if (ringerMode != ringerModeInternal) {
1698 setRingerModeInt(ringerMode, true /*persist*/);
1699 }
1700 } else /*internal*/ {
1701 if (ringerMode != ringerModeInternal) {
1702 setRingerModeInt(ringerMode, true /*persist*/);
1703 }
1704 if (mRingerModeDelegate != null) {
1705 ringerMode = mRingerModeDelegate.onSetRingerModeInternal(ringerModeInternal,
1706 ringerMode, caller, ringerModeExternal);
1707 }
1708 setRingerModeExt(ringerMode);
John Spurlock57627792014-12-11 11:29:54 -05001709 }
John Spurlock661f2cf2014-11-17 10:29:10 -05001710 }
John Spurlockaf88a192014-12-23 16:14:44 -05001711 } finally {
1712 Binder.restoreCallingIdentity(identity);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001713 }
1714 }
1715
John Spurlock661f2cf2014-11-17 10:29:10 -05001716 private void setRingerModeExt(int ringerMode) {
1717 synchronized(mSettingsLock) {
1718 if (ringerMode == mRingerModeExternal) return;
1719 mRingerModeExternal = ringerMode;
John Spurlocke5b42d92014-10-15 12:03:48 -04001720 }
John Spurlock661f2cf2014-11-17 10:29:10 -05001721 // Send sticky broadcast
John Spurlockbcc10872014-11-28 15:29:21 -05001722 broadcastRingerMode(AudioManager.RINGER_MODE_CHANGED_ACTION, ringerMode);
John Spurlocke5b42d92014-10-15 12:03:48 -04001723 }
1724
Eric Laurent4050c932009-07-08 02:52:14 -07001725 private void setRingerModeInt(int ringerMode, boolean persist) {
John Spurlockbcc10872014-11-28 15:29:21 -05001726 final boolean change;
Glenn Kastenba195eb2011-12-13 09:30:40 -08001727 synchronized(mSettingsLock) {
John Spurlockbcc10872014-11-28 15:29:21 -05001728 change = mRingerMode != ringerMode;
Glenn Kastenba195eb2011-12-13 09:30:40 -08001729 mRingerMode = ringerMode;
1730 }
Jason Parekhb1096152009-03-24 17:48:25 -07001731
Eric Laurent5b4e6542010-03-19 20:02:21 -07001732 // Mute stream if not previously muted by ringer mode and ringer mode
1733 // is not RINGER_MODE_NORMAL and stream is affected by ringer mode.
1734 // Unmute stream if previously muted by ringer mode and ringer mode
1735 // is RINGER_MODE_NORMAL or stream is not affected by ringer mode.
Jason Parekhb1096152009-03-24 17:48:25 -07001736 int numStreamTypes = AudioSystem.getNumStreamTypes();
John Spurlock661f2cf2014-11-17 10:29:10 -05001737 final boolean ringerModeMute = ringerMode == AudioManager.RINGER_MODE_VIBRATE
1738 || ringerMode == AudioManager.RINGER_MODE_SILENT;
Eric Laurent5b4e6542010-03-19 20:02:21 -07001739 for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
John Spurlock661f2cf2014-11-17 10:29:10 -05001740 final boolean isMuted = isStreamMutedByRingerMode(streamType);
1741 final boolean shouldMute = ringerModeMute && isStreamAffectedByRingerMode(streamType);
1742 if (isMuted == shouldMute) continue;
1743 if (!shouldMute) {
1744 // unmute
1745 // ring and notifications volume should never be 0 when not silenced
1746 // on voice capable devices or devices that support vibration
1747 if ((isPlatformVoice() || mHasVibrator) &&
1748 mStreamVolumeAlias[streamType] == AudioSystem.STREAM_RING) {
1749 synchronized (VolumeStreamState.class) {
John Spurlock2bb02ec2015-03-02 13:13:06 -05001750 SparseIntArray indexMap = mStreamStates[streamType].mIndexMap;
1751 for (int i = 0; i < indexMap.size(); i++) {
1752 int device = indexMap.keyAt(i);
1753 int value = indexMap.valueAt(i);
1754 if (value == 0) {
1755 indexMap.put(device, 10);
Eric Laurent9bc8358d2011-11-18 16:43:31 -08001756 }
1757 }
Eric Laurent9e0d25f2015-02-12 17:28:53 -08001758 // Persist volume for stream ring when it is changed here
1759 final int device = getDeviceForStream(streamType);
1760 sendMsg(mAudioHandler,
1761 MSG_PERSIST_VOLUME,
1762 SENDMSG_QUEUE,
1763 device,
1764 0,
1765 mStreamStates[streamType],
1766 PERSIST_DELAY);
Eric Laurentb024c302011-10-14 17:19:27 -07001767 }
Eric Laurent9bcf4012009-06-12 06:09:28 -07001768 }
RoboErik4197cb62015-01-21 15:45:32 -08001769 mStreamStates[streamType].mute(false);
John Spurlock661f2cf2014-11-17 10:29:10 -05001770 mRingerModeMutedStreams &= ~(1 << streamType);
Eric Laurent5b4e6542010-03-19 20:02:21 -07001771 } else {
John Spurlock661f2cf2014-11-17 10:29:10 -05001772 // mute
RoboErik4197cb62015-01-21 15:45:32 -08001773 mStreamStates[streamType].mute(true);
John Spurlock661f2cf2014-11-17 10:29:10 -05001774 mRingerModeMutedStreams |= (1 << streamType);
Jason Parekhb1096152009-03-24 17:48:25 -07001775 }
1776 }
Eric Laurenta553c252009-07-17 12:17:14 -07001777
Jason Parekhb1096152009-03-24 17:48:25 -07001778 // Post a persist ringer mode msg
Eric Laurent4050c932009-07-08 02:52:14 -07001779 if (persist) {
Eric Laurentafbb0472011-12-15 09:04:23 -08001780 sendMsg(mAudioHandler, MSG_PERSIST_RINGER_MODE,
Eric Laurent4050c932009-07-08 02:52:14 -07001781 SENDMSG_REPLACE, 0, 0, null, PERSIST_DELAY);
1782 }
John Spurlockbcc10872014-11-28 15:29:21 -05001783 if (change) {
1784 // Send sticky broadcast
1785 broadcastRingerMode(AudioManager.INTERNAL_RINGER_MODE_CHANGED_ACTION, ringerMode);
1786 }
Jason Parekhb1096152009-03-24 17:48:25 -07001787 }
1788
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001789 /** @see AudioManager#shouldVibrate(int) */
1790 public boolean shouldVibrate(int vibrateType) {
Eric Laurentbffc3d12012-05-07 17:43:49 -07001791 if (!mHasVibrator) return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001792
1793 switch (getVibrateSetting(vibrateType)) {
1794
1795 case AudioManager.VIBRATE_SETTING_ON:
John Spurlock57627792014-12-11 11:29:54 -05001796 return getRingerModeExternal() != AudioManager.RINGER_MODE_SILENT;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001797
1798 case AudioManager.VIBRATE_SETTING_ONLY_SILENT:
John Spurlock57627792014-12-11 11:29:54 -05001799 return getRingerModeExternal() == AudioManager.RINGER_MODE_VIBRATE;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001800
1801 case AudioManager.VIBRATE_SETTING_OFF:
Daniel Sandlerbcac4962010-04-12 13:23:57 -04001802 // return false, even for incoming calls
1803 return false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001804
1805 default:
1806 return false;
1807 }
1808 }
1809
1810 /** @see AudioManager#getVibrateSetting(int) */
1811 public int getVibrateSetting(int vibrateType) {
Eric Laurentbffc3d12012-05-07 17:43:49 -07001812 if (!mHasVibrator) return AudioManager.VIBRATE_SETTING_OFF;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001813 return (mVibrateSetting >> (vibrateType * 2)) & 3;
1814 }
1815
1816 /** @see AudioManager#setVibrateSetting(int, int) */
1817 public void setVibrateSetting(int vibrateType, int vibrateSetting) {
1818
Eric Laurentbffc3d12012-05-07 17:43:49 -07001819 if (!mHasVibrator) return;
1820
John Spurlock61560172015-02-06 19:46:04 -05001821 mVibrateSetting = AudioSystem.getValueForVibrateSetting(mVibrateSetting, vibrateType,
1822 vibrateSetting);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001823
1824 // Broadcast change
1825 broadcastVibrateSetting(vibrateType);
1826
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001827 }
1828
Eric Laurent9272b4b2010-01-23 17:12:59 -08001829 private class SetModeDeathHandler implements IBinder.DeathRecipient {
1830 private IBinder mCb; // To be notified of client's death
Marco Nelissenf1ddd512011-08-10 14:15:44 -07001831 private int mPid;
Eric Laurent9272b4b2010-01-23 17:12:59 -08001832 private int mMode = AudioSystem.MODE_NORMAL; // Current mode set by this client
1833
Eric Laurent9f103de2011-09-08 15:04:23 -07001834 SetModeDeathHandler(IBinder cb, int pid) {
Eric Laurent9272b4b2010-01-23 17:12:59 -08001835 mCb = cb;
Eric Laurent9f103de2011-09-08 15:04:23 -07001836 mPid = pid;
Eric Laurent9272b4b2010-01-23 17:12:59 -08001837 }
1838
1839 public void binderDied() {
Eric Laurentd7454be2011-09-14 08:45:58 -07001840 int newModeOwnerPid = 0;
Eric Laurent9272b4b2010-01-23 17:12:59 -08001841 synchronized(mSetModeDeathHandlers) {
1842 Log.w(TAG, "setMode() client died");
1843 int index = mSetModeDeathHandlers.indexOf(this);
1844 if (index < 0) {
1845 Log.w(TAG, "unregistered setMode() client died");
1846 } else {
Eric Laurentd7454be2011-09-14 08:45:58 -07001847 newModeOwnerPid = setModeInt(AudioSystem.MODE_NORMAL, mCb, mPid);
Eric Laurent9272b4b2010-01-23 17:12:59 -08001848 }
1849 }
Eric Laurent9f103de2011-09-08 15:04:23 -07001850 // when entering RINGTONE, IN_CALL or IN_COMMUNICATION mode, clear all
1851 // SCO connections not started by the application changing the mode
Eric Laurentd7454be2011-09-14 08:45:58 -07001852 if (newModeOwnerPid != 0) {
Eric Laurent6b5e22d2013-03-28 16:10:45 -07001853 final long ident = Binder.clearCallingIdentity();
1854 disconnectBluetoothSco(newModeOwnerPid);
1855 Binder.restoreCallingIdentity(ident);
Eric Laurent9f103de2011-09-08 15:04:23 -07001856 }
Eric Laurent9272b4b2010-01-23 17:12:59 -08001857 }
1858
Marco Nelissenf1ddd512011-08-10 14:15:44 -07001859 public int getPid() {
1860 return mPid;
1861 }
1862
Eric Laurent9272b4b2010-01-23 17:12:59 -08001863 public void setMode(int mode) {
1864 mMode = mode;
1865 }
1866
1867 public int getMode() {
1868 return mMode;
1869 }
1870
1871 public IBinder getBinder() {
1872 return mCb;
1873 }
1874 }
1875
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001876 /** @see AudioManager#setMode(int) */
Eric Laurent9272b4b2010-01-23 17:12:59 -08001877 public void setMode(int mode, IBinder cb) {
Jean-Michel Trivi339567d2014-07-29 09:53:34 -07001878 if (DEBUG_MODE) { Log.v(TAG, "setMode(mode=" + mode + ")"); }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001879 if (!checkAudioSettingsPermission("setMode()")) {
1880 return;
1881 }
Eric Laurenta553c252009-07-17 12:17:14 -07001882
Jean-Michel Triviccd654e2014-09-03 17:48:47 -07001883 if ( (mode == AudioSystem.MODE_IN_CALL) &&
1884 (mContext.checkCallingOrSelfPermission(
1885 android.Manifest.permission.MODIFY_PHONE_STATE)
1886 != PackageManager.PERMISSION_GRANTED)) {
1887 Log.w(TAG, "MODIFY_PHONE_STATE Permission Denial: setMode(MODE_IN_CALL) from pid="
1888 + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid());
1889 return;
1890 }
1891
Jean-Michel Trivi8f677d62010-11-15 12:11:32 -08001892 if (mode < AudioSystem.MODE_CURRENT || mode >= AudioSystem.NUM_MODES) {
Eric Laurenta553c252009-07-17 12:17:14 -07001893 return;
1894 }
1895
Eric Laurentd7454be2011-09-14 08:45:58 -07001896 int newModeOwnerPid = 0;
Eric Laurent9f103de2011-09-08 15:04:23 -07001897 synchronized(mSetModeDeathHandlers) {
Eric Laurenta553c252009-07-17 12:17:14 -07001898 if (mode == AudioSystem.MODE_CURRENT) {
1899 mode = mMode;
1900 }
Eric Laurentd7454be2011-09-14 08:45:58 -07001901 newModeOwnerPid = setModeInt(mode, cb, Binder.getCallingPid());
Eric Laurent9f103de2011-09-08 15:04:23 -07001902 }
1903 // when entering RINGTONE, IN_CALL or IN_COMMUNICATION mode, clear all
1904 // SCO connections not started by the application changing the mode
Eric Laurentd7454be2011-09-14 08:45:58 -07001905 if (newModeOwnerPid != 0) {
1906 disconnectBluetoothSco(newModeOwnerPid);
Eric Laurent9f103de2011-09-08 15:04:23 -07001907 }
1908 }
Jean-Michel Trivi2ade5762010-12-11 13:18:30 -08001909
Eric Laurent9f103de2011-09-08 15:04:23 -07001910 // must be called synchronized on mSetModeDeathHandlers
Eric Laurentd7454be2011-09-14 08:45:58 -07001911 // setModeInt() returns a valid PID if the audio mode was successfully set to
Eric Laurent9f103de2011-09-08 15:04:23 -07001912 // any mode other than NORMAL.
Jean-Michel Triviccd654e2014-09-03 17:48:47 -07001913 private int setModeInt(int mode, IBinder cb, int pid) {
Jean-Michel Trivi339567d2014-07-29 09:53:34 -07001914 if (DEBUG_MODE) { Log.v(TAG, "setModeInt(mode=" + mode + ", pid=" + pid + ")"); }
Eric Laurentd7454be2011-09-14 08:45:58 -07001915 int newModeOwnerPid = 0;
Eric Laurent9f103de2011-09-08 15:04:23 -07001916 if (cb == null) {
1917 Log.e(TAG, "setModeInt() called with null binder");
Eric Laurentd7454be2011-09-14 08:45:58 -07001918 return newModeOwnerPid;
Eric Laurent9f103de2011-09-08 15:04:23 -07001919 }
Jean-Michel Trivi2ade5762010-12-11 13:18:30 -08001920
Eric Laurent9f103de2011-09-08 15:04:23 -07001921 SetModeDeathHandler hdlr = null;
1922 Iterator iter = mSetModeDeathHandlers.iterator();
1923 while (iter.hasNext()) {
1924 SetModeDeathHandler h = (SetModeDeathHandler)iter.next();
1925 if (h.getPid() == pid) {
1926 hdlr = h;
1927 // Remove from client list so that it is re-inserted at top of list
1928 iter.remove();
1929 hdlr.getBinder().unlinkToDeath(hdlr, 0);
1930 break;
1931 }
1932 }
1933 int status = AudioSystem.AUDIO_STATUS_OK;
1934 do {
1935 if (mode == AudioSystem.MODE_NORMAL) {
1936 // get new mode from client at top the list if any
1937 if (!mSetModeDeathHandlers.isEmpty()) {
1938 hdlr = mSetModeDeathHandlers.get(0);
1939 cb = hdlr.getBinder();
1940 mode = hdlr.getMode();
Jean-Michel Trivi339567d2014-07-29 09:53:34 -07001941 if (DEBUG_MODE) {
1942 Log.w(TAG, " using mode=" + mode + " instead due to death hdlr at pid="
1943 + hdlr.mPid);
1944 }
Eric Laurentb9c9d262009-05-06 08:13:20 -07001945 }
Eric Laurent9f103de2011-09-08 15:04:23 -07001946 } else {
1947 if (hdlr == null) {
1948 hdlr = new SetModeDeathHandler(cb, pid);
1949 }
1950 // Register for client death notification
1951 try {
1952 cb.linkToDeath(hdlr, 0);
1953 } catch (RemoteException e) {
1954 // Client has died!
1955 Log.w(TAG, "setMode() could not link to "+cb+" binder death");
1956 }
1957
1958 // Last client to call setMode() is always at top of client list
1959 // as required by SetModeDeathHandler.binderDied()
1960 mSetModeDeathHandlers.add(0, hdlr);
1961 hdlr.setMode(mode);
1962 }
1963
1964 if (mode != mMode) {
1965 status = AudioSystem.setPhoneState(mode);
1966 if (status == AudioSystem.AUDIO_STATUS_OK) {
Jean-Michel Trivi339567d2014-07-29 09:53:34 -07001967 if (DEBUG_MODE) { Log.v(TAG, " mode successfully set to " + mode); }
Eric Laurent9f103de2011-09-08 15:04:23 -07001968 mMode = mode;
1969 } else {
1970 if (hdlr != null) {
1971 mSetModeDeathHandlers.remove(hdlr);
1972 cb.unlinkToDeath(hdlr, 0);
1973 }
1974 // force reading new top of mSetModeDeathHandlers stack
Jean-Michel Trivi339567d2014-07-29 09:53:34 -07001975 if (DEBUG_MODE) { Log.w(TAG, " mode set to MODE_NORMAL after phoneState pb"); }
Eric Laurent9f103de2011-09-08 15:04:23 -07001976 mode = AudioSystem.MODE_NORMAL;
1977 }
1978 } else {
1979 status = AudioSystem.AUDIO_STATUS_OK;
1980 }
1981 } while (status != AudioSystem.AUDIO_STATUS_OK && !mSetModeDeathHandlers.isEmpty());
1982
1983 if (status == AudioSystem.AUDIO_STATUS_OK) {
1984 if (mode != AudioSystem.MODE_NORMAL) {
Eric Laurentd7454be2011-09-14 08:45:58 -07001985 if (mSetModeDeathHandlers.isEmpty()) {
1986 Log.e(TAG, "setMode() different from MODE_NORMAL with empty mode client stack");
1987 } else {
1988 newModeOwnerPid = mSetModeDeathHandlers.get(0).getPid();
1989 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001990 }
1991 int streamType = getActiveStreamType(AudioManager.USE_DEFAULT_STREAM_TYPE);
Eric Laurent9bc8358d2011-11-18 16:43:31 -08001992 int device = getDeviceForStream(streamType);
Eric Laurent42b041e2013-03-29 11:36:03 -07001993 int index = mStreamStates[mStreamVolumeAlias[streamType]].getIndex(device);
1994 setStreamVolumeInt(mStreamVolumeAlias[streamType], index, device, true);
Eric Laurent6d517662012-04-23 18:42:39 -07001995
1996 updateStreamVolumeAlias(true /*updateVolumes*/);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001997 }
Eric Laurentd7454be2011-09-14 08:45:58 -07001998 return newModeOwnerPid;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001999 }
2000
2001 /** @see AudioManager#getMode() */
2002 public int getMode() {
2003 return mMode;
2004 }
2005
Eric Laurente78fced2013-03-15 16:03:47 -07002006 //==========================================================================================
2007 // Sound Effects
2008 //==========================================================================================
2009
2010 private static final String TAG_AUDIO_ASSETS = "audio_assets";
2011 private static final String ATTR_VERSION = "version";
2012 private static final String TAG_GROUP = "group";
2013 private static final String ATTR_GROUP_NAME = "name";
2014 private static final String TAG_ASSET = "asset";
2015 private static final String ATTR_ASSET_ID = "id";
2016 private static final String ATTR_ASSET_FILE = "file";
2017
2018 private static final String ASSET_FILE_VERSION = "1.0";
2019 private static final String GROUP_TOUCH_SOUNDS = "touch_sounds";
2020
Glenn Kasten167d1a22013-07-23 16:24:41 -07002021 private static final int SOUND_EFFECTS_LOAD_TIMEOUT_MS = 5000;
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07002022
2023 class LoadSoundEffectReply {
2024 public int mStatus = 1;
2025 };
2026
Eric Laurente78fced2013-03-15 16:03:47 -07002027 private void loadTouchSoundAssetDefaults() {
2028 SOUND_EFFECT_FILES.add("Effect_Tick.ogg");
2029 for (int i = 0; i < AudioManager.NUM_SOUND_EFFECTS; i++) {
2030 SOUND_EFFECT_FILES_MAP[i][0] = 0;
2031 SOUND_EFFECT_FILES_MAP[i][1] = -1;
2032 }
2033 }
2034
2035 private void loadTouchSoundAssets() {
2036 XmlResourceParser parser = null;
2037
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07002038 // only load assets once.
2039 if (!SOUND_EFFECT_FILES.isEmpty()) {
2040 return;
2041 }
2042
Eric Laurente78fced2013-03-15 16:03:47 -07002043 loadTouchSoundAssetDefaults();
2044
2045 try {
2046 parser = mContext.getResources().getXml(com.android.internal.R.xml.audio_assets);
2047
2048 XmlUtils.beginDocument(parser, TAG_AUDIO_ASSETS);
2049 String version = parser.getAttributeValue(null, ATTR_VERSION);
2050 boolean inTouchSoundsGroup = false;
2051
2052 if (ASSET_FILE_VERSION.equals(version)) {
2053 while (true) {
2054 XmlUtils.nextElement(parser);
2055 String element = parser.getName();
2056 if (element == null) {
2057 break;
2058 }
2059 if (element.equals(TAG_GROUP)) {
2060 String name = parser.getAttributeValue(null, ATTR_GROUP_NAME);
2061 if (GROUP_TOUCH_SOUNDS.equals(name)) {
2062 inTouchSoundsGroup = true;
2063 break;
2064 }
2065 }
2066 }
2067 while (inTouchSoundsGroup) {
2068 XmlUtils.nextElement(parser);
2069 String element = parser.getName();
2070 if (element == null) {
2071 break;
2072 }
2073 if (element.equals(TAG_ASSET)) {
2074 String id = parser.getAttributeValue(null, ATTR_ASSET_ID);
2075 String file = parser.getAttributeValue(null, ATTR_ASSET_FILE);
2076 int fx;
2077
2078 try {
2079 Field field = AudioManager.class.getField(id);
2080 fx = field.getInt(null);
2081 } catch (Exception e) {
2082 Log.w(TAG, "Invalid touch sound ID: "+id);
2083 continue;
2084 }
2085
2086 int i = SOUND_EFFECT_FILES.indexOf(file);
2087 if (i == -1) {
2088 i = SOUND_EFFECT_FILES.size();
2089 SOUND_EFFECT_FILES.add(file);
2090 }
2091 SOUND_EFFECT_FILES_MAP[fx][0] = i;
2092 } else {
2093 break;
2094 }
2095 }
2096 }
2097 } catch (Resources.NotFoundException e) {
2098 Log.w(TAG, "audio assets file not found", e);
2099 } catch (XmlPullParserException e) {
2100 Log.w(TAG, "XML parser exception reading touch sound assets", e);
2101 } catch (IOException e) {
2102 Log.w(TAG, "I/O exception reading touch sound assets", e);
2103 } finally {
2104 if (parser != null) {
2105 parser.close();
2106 }
2107 }
2108 }
2109
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002110 /** @see AudioManager#playSoundEffect(int) */
2111 public void playSoundEffect(int effectType) {
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07002112 playSoundEffectVolume(effectType, -1.0f);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002113 }
2114
2115 /** @see AudioManager#playSoundEffect(int, float) */
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002116 public void playSoundEffectVolume(int effectType, float volume) {
Natalie Silvanovich559c76d2014-05-01 10:16:24 -07002117 if (effectType >= AudioManager.NUM_SOUND_EFFECTS || effectType < 0) {
2118 Log.w(TAG, "AudioService effectType value " + effectType + " out of range");
2119 return;
2120 }
2121
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07002122 sendMsg(mAudioHandler, MSG_PLAY_SOUND_EFFECT, SENDMSG_QUEUE,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002123 effectType, (int) (volume * 1000), null, 0);
2124 }
2125
2126 /**
2127 * Loads samples into the soundpool.
Glenn Kasten5c17a822011-11-30 09:41:01 -08002128 * This method must be called at first when sound effects are enabled
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002129 */
2130 public boolean loadSoundEffects() {
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07002131 int attempts = 3;
2132 LoadSoundEffectReply reply = new LoadSoundEffectReply();
Eric Laurenta60e2122010-12-28 16:49:07 -08002133
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07002134 synchronized (reply) {
2135 sendMsg(mAudioHandler, MSG_LOAD_SOUND_EFFECTS, SENDMSG_QUEUE, 0, 0, reply, 0);
2136 while ((reply.mStatus == 1) && (attempts-- > 0)) {
Eric Laurent117b7bb2011-01-16 17:07:27 -08002137 try {
Glenn Kasten167d1a22013-07-23 16:24:41 -07002138 reply.wait(SOUND_EFFECTS_LOAD_TIMEOUT_MS);
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07002139 } catch (InterruptedException e) {
2140 Log.w(TAG, "loadSoundEffects Interrupted while waiting sound pool loaded.");
Eric Laurent117b7bb2011-01-16 17:07:27 -08002141 }
Eric Laurenta60e2122010-12-28 16:49:07 -08002142 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002143 }
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07002144 return (reply.mStatus == 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002145 }
2146
2147 /**
2148 * Unloads samples from the sound pool.
2149 * This method can be called to free some memory when
2150 * sound effects are disabled.
2151 */
2152 public void unloadSoundEffects() {
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07002153 sendMsg(mAudioHandler, MSG_UNLOAD_SOUND_EFFECTS, SENDMSG_QUEUE, 0, 0, null, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002154 }
2155
Eric Laurenta60e2122010-12-28 16:49:07 -08002156 class SoundPoolListenerThread extends Thread {
2157 public SoundPoolListenerThread() {
2158 super("SoundPoolListenerThread");
2159 }
2160
2161 @Override
2162 public void run() {
2163
2164 Looper.prepare();
2165 mSoundPoolLooper = Looper.myLooper();
2166
2167 synchronized (mSoundEffectsLock) {
2168 if (mSoundPool != null) {
2169 mSoundPoolCallBack = new SoundPoolCallback();
2170 mSoundPool.setOnLoadCompleteListener(mSoundPoolCallBack);
2171 }
2172 mSoundEffectsLock.notify();
2173 }
2174 Looper.loop();
2175 }
2176 }
2177
2178 private final class SoundPoolCallback implements
2179 android.media.SoundPool.OnLoadCompleteListener {
2180
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07002181 int mStatus = 1; // 1 means neither error nor last sample loaded yet
2182 List<Integer> mSamples = new ArrayList<Integer>();
Eric Laurenta60e2122010-12-28 16:49:07 -08002183
2184 public int status() {
2185 return mStatus;
2186 }
2187
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07002188 public void setSamples(int[] samples) {
2189 for (int i = 0; i < samples.length; i++) {
2190 // do not wait ack for samples rejected upfront by SoundPool
2191 if (samples[i] > 0) {
2192 mSamples.add(samples[i]);
2193 }
2194 }
Eric Laurenta60e2122010-12-28 16:49:07 -08002195 }
2196
2197 public void onLoadComplete(SoundPool soundPool, int sampleId, int status) {
2198 synchronized (mSoundEffectsLock) {
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07002199 int i = mSamples.indexOf(sampleId);
2200 if (i >= 0) {
2201 mSamples.remove(i);
Eric Laurenta60e2122010-12-28 16:49:07 -08002202 }
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07002203 if ((status != 0) || mSamples. isEmpty()) {
2204 mStatus = status;
Eric Laurenta60e2122010-12-28 16:49:07 -08002205 mSoundEffectsLock.notify();
2206 }
2207 }
2208 }
2209 }
2210
Eric Laurent4050c932009-07-08 02:52:14 -07002211 /** @see AudioManager#reloadAudioSettings() */
2212 public void reloadAudioSettings() {
Eric Laurentbc0fab1f2012-09-19 11:24:41 -07002213 readAudioSettings(false /*userSwitch*/);
2214 }
2215
2216 private void readAudioSettings(boolean userSwitch) {
Eric Laurent4050c932009-07-08 02:52:14 -07002217 // restore ringer mode, ringer mode affected streams, mute affected streams and vibrate settings
2218 readPersistedSettings();
2219
2220 // restore volume settings
2221 int numStreamTypes = AudioSystem.getNumStreamTypes();
2222 for (int streamType = 0; streamType < numStreamTypes; streamType++) {
2223 VolumeStreamState streamState = mStreamStates[streamType];
2224
Eric Laurentbc0fab1f2012-09-19 11:24:41 -07002225 if (userSwitch && mStreamVolumeAlias[streamType] == AudioSystem.STREAM_MUSIC) {
2226 continue;
2227 }
2228
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07002229 streamState.readSettings();
2230 synchronized (VolumeStreamState.class) {
Eric Laurent3172d5e2012-05-09 11:38:16 -07002231 // unmute stream that was muted but is not affect by mute anymore
RoboErik4197cb62015-01-21 15:45:32 -08002232 if (streamState.mIsMuted && ((!isStreamAffectedByMute(streamType) &&
Eric Laurent83a017b2013-03-19 18:15:31 -07002233 !isStreamMutedByRingerMode(streamType)) || mUseFixedVolume)) {
RoboErik4197cb62015-01-21 15:45:32 -08002234 streamState.mIsMuted = false;
Eric Laurent4050c932009-07-08 02:52:14 -07002235 }
Eric Laurent4050c932009-07-08 02:52:14 -07002236 }
2237 }
2238
Eric Laurent33902db2012-10-07 16:15:07 -07002239 // apply new ringer mode before checking volume for alias streams so that streams
2240 // muted by ringer mode have the correct volume
John Spurlock661f2cf2014-11-17 10:29:10 -05002241 setRingerModeInt(getRingerModeInternal(), false);
Eric Laurent33902db2012-10-07 16:15:07 -07002242
Eric Laurent212532b2014-07-21 15:43:18 -07002243 checkAllFixedVolumeDevices();
Eric Laurent24482012012-05-10 09:41:17 -07002244 checkAllAliasStreamVolumes();
2245
Eric Laurentd640bd32012-09-28 18:01:48 -07002246 synchronized (mSafeMediaVolumeState) {
John Spurlockaa5ee4d2014-07-25 13:05:12 -04002247 mMusicActiveMs = MathUtils.constrain(Settings.Secure.getIntForUser(mContentResolver,
2248 Settings.Secure.UNSAFE_VOLUME_MUSIC_ACTIVE_MS, 0, UserHandle.USER_CURRENT),
2249 0, UNSAFE_VOLUME_MUSIC_ACTIVE_MS_MAX);
Eric Laurentd640bd32012-09-28 18:01:48 -07002250 if (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_ACTIVE) {
Eric Laurentf1a457d2012-09-20 16:27:23 -07002251 enforceSafeMediaVolume();
2252 }
Eric Laurentc34dcc12012-09-10 13:51:52 -07002253 }
Eric Laurent4050c932009-07-08 02:52:14 -07002254 }
2255
Dianne Hackborn961cae92013-03-20 14:59:43 -07002256 /** @see AudioManager#setSpeakerphoneOn(boolean) */
Eric Laurentc42ac9d2009-07-29 08:53:03 -07002257 public void setSpeakerphoneOn(boolean on){
Eric Laurentdc1d17a2009-09-10 00:48:21 -07002258 if (!checkAudioSettingsPermission("setSpeakerphoneOn()")) {
2259 return;
2260 }
Johan Gustavsson7337bee2013-03-01 15:53:30 +01002261
2262 if (on) {
2263 if (mForcedUseForComm == AudioSystem.FORCE_BT_SCO) {
2264 sendMsg(mAudioHandler, MSG_SET_FORCE_USE, SENDMSG_QUEUE,
2265 AudioSystem.FOR_RECORD, AudioSystem.FORCE_NONE, null, 0);
2266 }
2267 mForcedUseForComm = AudioSystem.FORCE_SPEAKER;
2268 } else if (mForcedUseForComm == AudioSystem.FORCE_SPEAKER){
2269 mForcedUseForComm = AudioSystem.FORCE_NONE;
2270 }
Eric Laurentfa640152011-03-12 15:59:51 -08002271
Eric Laurentafbb0472011-12-15 09:04:23 -08002272 sendMsg(mAudioHandler, MSG_SET_FORCE_USE, SENDMSG_QUEUE,
Eric Laurentfa640152011-03-12 15:59:51 -08002273 AudioSystem.FOR_COMMUNICATION, mForcedUseForComm, null, 0);
Eric Laurentc42ac9d2009-07-29 08:53:03 -07002274 }
2275
2276 /** @see AudioManager#isSpeakerphoneOn() */
2277 public boolean isSpeakerphoneOn() {
Eric Laurentfa640152011-03-12 15:59:51 -08002278 return (mForcedUseForComm == AudioSystem.FORCE_SPEAKER);
Eric Laurentc42ac9d2009-07-29 08:53:03 -07002279 }
2280
Dianne Hackborn961cae92013-03-20 14:59:43 -07002281 /** @see AudioManager#setBluetoothScoOn(boolean) */
Eric Laurentc42ac9d2009-07-29 08:53:03 -07002282 public void setBluetoothScoOn(boolean on){
Eric Laurentdc1d17a2009-09-10 00:48:21 -07002283 if (!checkAudioSettingsPermission("setBluetoothScoOn()")) {
2284 return;
2285 }
Johan Gustavsson7337bee2013-03-01 15:53:30 +01002286
2287 if (on) {
2288 mForcedUseForComm = AudioSystem.FORCE_BT_SCO;
2289 } else if (mForcedUseForComm == AudioSystem.FORCE_BT_SCO) {
2290 mForcedUseForComm = AudioSystem.FORCE_NONE;
2291 }
Eric Laurentfa640152011-03-12 15:59:51 -08002292
Eric Laurentafbb0472011-12-15 09:04:23 -08002293 sendMsg(mAudioHandler, MSG_SET_FORCE_USE, SENDMSG_QUEUE,
Eric Laurentfa640152011-03-12 15:59:51 -08002294 AudioSystem.FOR_COMMUNICATION, mForcedUseForComm, null, 0);
Eric Laurentafbb0472011-12-15 09:04:23 -08002295 sendMsg(mAudioHandler, MSG_SET_FORCE_USE, SENDMSG_QUEUE,
Eric Laurentfa640152011-03-12 15:59:51 -08002296 AudioSystem.FOR_RECORD, mForcedUseForComm, null, 0);
Eric Laurentc42ac9d2009-07-29 08:53:03 -07002297 }
2298
2299 /** @see AudioManager#isBluetoothScoOn() */
2300 public boolean isBluetoothScoOn() {
Eric Laurentfa640152011-03-12 15:59:51 -08002301 return (mForcedUseForComm == AudioSystem.FORCE_BT_SCO);
Eric Laurentc42ac9d2009-07-29 08:53:03 -07002302 }
2303
Dianne Hackborn961cae92013-03-20 14:59:43 -07002304 /** @see AudioManager#setBluetoothA2dpOn(boolean) */
Eric Laurent78472112012-05-21 08:57:21 -07002305 public void setBluetoothA2dpOn(boolean on) {
Eric Laurentc390bed2012-07-03 12:24:05 -07002306 synchronized (mBluetoothA2dpEnabledLock) {
2307 mBluetoothA2dpEnabled = on;
2308 sendMsg(mAudioHandler, MSG_SET_FORCE_BT_A2DP_USE, SENDMSG_QUEUE,
2309 AudioSystem.FOR_MEDIA,
2310 mBluetoothA2dpEnabled ? AudioSystem.FORCE_NONE : AudioSystem.FORCE_NO_BT_A2DP,
2311 null, 0);
2312 }
Eric Laurent78472112012-05-21 08:57:21 -07002313 }
2314
2315 /** @see AudioManager#isBluetoothA2dpOn() */
2316 public boolean isBluetoothA2dpOn() {
2317 synchronized (mBluetoothA2dpEnabledLock) {
2318 return mBluetoothA2dpEnabled;
2319 }
2320 }
2321
Eric Laurent3def1ee2010-03-17 23:26:26 -07002322 /** @see AudioManager#startBluetoothSco() */
Eric Laurent83900752014-05-15 15:14:22 -07002323 public void startBluetoothSco(IBinder cb, int targetSdkVersion) {
2324 int scoAudioMode =
2325 (targetSdkVersion < Build.VERSION_CODES.JELLY_BEAN_MR2) ?
Liejun Taof4e51d82014-07-16 11:18:29 -07002326 SCO_MODE_VIRTUAL_CALL : SCO_MODE_UNDEFINED;
Eric Laurent83900752014-05-15 15:14:22 -07002327 startBluetoothScoInt(cb, scoAudioMode);
2328 }
2329
2330 /** @see AudioManager#startBluetoothScoVirtualCall() */
2331 public void startBluetoothScoVirtualCall(IBinder cb) {
2332 startBluetoothScoInt(cb, SCO_MODE_VIRTUAL_CALL);
2333 }
2334
2335 void startBluetoothScoInt(IBinder cb, int scoAudioMode){
Eric Laurentdc03c612011-04-01 10:59:41 -07002336 if (!checkAudioSettingsPermission("startBluetoothSco()") ||
Eric Laurent4a5eeb92014-05-06 10:49:04 -07002337 !mSystemReady) {
Eric Laurent3def1ee2010-03-17 23:26:26 -07002338 return;
2339 }
Eric Laurent854938a2011-02-22 12:05:20 -08002340 ScoClient client = getScoClient(cb, true);
Eric Laurentf5a1fc32013-03-11 18:52:57 -07002341 // The calling identity must be cleared before calling ScoClient.incCount().
2342 // inCount() calls requestScoState() which in turn can call BluetoothHeadset APIs
2343 // and this must be done on behalf of system server to make sure permissions are granted.
2344 // The caller identity must be cleared after getScoClient() because it is needed if a new
2345 // client is created.
2346 final long ident = Binder.clearCallingIdentity();
Eric Laurent83900752014-05-15 15:14:22 -07002347 client.incCount(scoAudioMode);
Eric Laurent2a57ca92013-03-07 17:29:27 -08002348 Binder.restoreCallingIdentity(ident);
Eric Laurent3def1ee2010-03-17 23:26:26 -07002349 }
2350
2351 /** @see AudioManager#stopBluetoothSco() */
2352 public void stopBluetoothSco(IBinder cb){
Eric Laurentdc03c612011-04-01 10:59:41 -07002353 if (!checkAudioSettingsPermission("stopBluetoothSco()") ||
Eric Laurent4a5eeb92014-05-06 10:49:04 -07002354 !mSystemReady) {
Eric Laurent3def1ee2010-03-17 23:26:26 -07002355 return;
2356 }
Eric Laurent854938a2011-02-22 12:05:20 -08002357 ScoClient client = getScoClient(cb, false);
Eric Laurentf5a1fc32013-03-11 18:52:57 -07002358 // The calling identity must be cleared before calling ScoClient.decCount().
2359 // decCount() calls requestScoState() which in turn can call BluetoothHeadset APIs
2360 // and this must be done on behalf of system server to make sure permissions are granted.
2361 final long ident = Binder.clearCallingIdentity();
Eric Laurent854938a2011-02-22 12:05:20 -08002362 if (client != null) {
2363 client.decCount();
2364 }
Eric Laurent2a57ca92013-03-07 17:29:27 -08002365 Binder.restoreCallingIdentity(ident);
Eric Laurent3def1ee2010-03-17 23:26:26 -07002366 }
2367
Eric Laurent78472112012-05-21 08:57:21 -07002368
Eric Laurent3def1ee2010-03-17 23:26:26 -07002369 private class ScoClient implements IBinder.DeathRecipient {
2370 private IBinder mCb; // To be notified of client's death
Marco Nelissenf1ddd512011-08-10 14:15:44 -07002371 private int mCreatorPid;
Eric Laurent3def1ee2010-03-17 23:26:26 -07002372 private int mStartcount; // number of SCO connections started by this client
2373
2374 ScoClient(IBinder cb) {
2375 mCb = cb;
Marco Nelissenf1ddd512011-08-10 14:15:44 -07002376 mCreatorPid = Binder.getCallingPid();
Eric Laurent3def1ee2010-03-17 23:26:26 -07002377 mStartcount = 0;
2378 }
2379
2380 public void binderDied() {
2381 synchronized(mScoClients) {
2382 Log.w(TAG, "SCO client died");
2383 int index = mScoClients.indexOf(this);
2384 if (index < 0) {
2385 Log.w(TAG, "unregistered SCO client died");
2386 } else {
2387 clearCount(true);
2388 mScoClients.remove(this);
2389 }
2390 }
2391 }
2392
Eric Laurent83900752014-05-15 15:14:22 -07002393 public void incCount(int scoAudioMode) {
Eric Laurent3def1ee2010-03-17 23:26:26 -07002394 synchronized(mScoClients) {
Eric Laurent83900752014-05-15 15:14:22 -07002395 requestScoState(BluetoothHeadset.STATE_AUDIO_CONNECTED, scoAudioMode);
Eric Laurent3def1ee2010-03-17 23:26:26 -07002396 if (mStartcount == 0) {
2397 try {
2398 mCb.linkToDeath(this, 0);
2399 } catch (RemoteException e) {
2400 // client has already died!
2401 Log.w(TAG, "ScoClient incCount() could not link to "+mCb+" binder death");
2402 }
2403 }
2404 mStartcount++;
2405 }
2406 }
2407
2408 public void decCount() {
2409 synchronized(mScoClients) {
2410 if (mStartcount == 0) {
2411 Log.w(TAG, "ScoClient.decCount() already 0");
2412 } else {
2413 mStartcount--;
2414 if (mStartcount == 0) {
Eric Laurente2dd8c42010-06-30 19:41:56 -07002415 try {
2416 mCb.unlinkToDeath(this, 0);
2417 } catch (NoSuchElementException e) {
2418 Log.w(TAG, "decCount() going to 0 but not registered to binder");
2419 }
Eric Laurent3def1ee2010-03-17 23:26:26 -07002420 }
Eric Laurentc18c9132013-04-12 17:24:56 -07002421 requestScoState(BluetoothHeadset.STATE_AUDIO_DISCONNECTED, 0);
Eric Laurent3def1ee2010-03-17 23:26:26 -07002422 }
2423 }
2424 }
2425
2426 public void clearCount(boolean stopSco) {
2427 synchronized(mScoClients) {
Eric Laurente2dd8c42010-06-30 19:41:56 -07002428 if (mStartcount != 0) {
2429 try {
2430 mCb.unlinkToDeath(this, 0);
2431 } catch (NoSuchElementException e) {
2432 Log.w(TAG, "clearCount() mStartcount: "+mStartcount+" != 0 but not registered to binder");
2433 }
2434 }
Eric Laurent3def1ee2010-03-17 23:26:26 -07002435 mStartcount = 0;
Eric Laurent3def1ee2010-03-17 23:26:26 -07002436 if (stopSco) {
Eric Laurentc18c9132013-04-12 17:24:56 -07002437 requestScoState(BluetoothHeadset.STATE_AUDIO_DISCONNECTED, 0);
Eric Laurent3def1ee2010-03-17 23:26:26 -07002438 }
2439 }
2440 }
2441
2442 public int getCount() {
2443 return mStartcount;
2444 }
2445
2446 public IBinder getBinder() {
2447 return mCb;
2448 }
2449
Eric Laurentd7454be2011-09-14 08:45:58 -07002450 public int getPid() {
2451 return mCreatorPid;
2452 }
2453
Eric Laurent3def1ee2010-03-17 23:26:26 -07002454 public int totalCount() {
2455 synchronized(mScoClients) {
2456 int count = 0;
2457 int size = mScoClients.size();
2458 for (int i = 0; i < size; i++) {
2459 count += mScoClients.get(i).getCount();
2460 }
2461 return count;
2462 }
2463 }
2464
Eric Laurent83900752014-05-15 15:14:22 -07002465 private void requestScoState(int state, int scoAudioMode) {
Eric Laurent62ef7672010-11-24 10:58:32 -08002466 checkScoAudioState();
Eric Laurentdc03c612011-04-01 10:59:41 -07002467 if (totalCount() == 0) {
2468 if (state == BluetoothHeadset.STATE_AUDIO_CONNECTED) {
2469 // Make sure that the state transitions to CONNECTING even if we cannot initiate
2470 // the connection.
2471 broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_CONNECTING);
2472 // Accept SCO audio activation only in NORMAL audio mode or if the mode is
Marco Nelissenf1ddd512011-08-10 14:15:44 -07002473 // currently controlled by the same client process.
Eric Laurent9f103de2011-09-08 15:04:23 -07002474 synchronized(mSetModeDeathHandlers) {
2475 if ((mSetModeDeathHandlers.isEmpty() ||
2476 mSetModeDeathHandlers.get(0).getPid() == mCreatorPid) &&
2477 (mScoAudioState == SCO_STATE_INACTIVE ||
2478 mScoAudioState == SCO_STATE_DEACTIVATE_REQ)) {
2479 if (mScoAudioState == SCO_STATE_INACTIVE) {
Eric Laurent83900752014-05-15 15:14:22 -07002480 mScoAudioMode = scoAudioMode;
Liejun Taof4e51d82014-07-16 11:18:29 -07002481 if (scoAudioMode == SCO_MODE_UNDEFINED) {
Andre Eisenbach570cc532014-10-28 17:03:18 -07002482 if (mBluetoothHeadsetDevice != null) {
2483 mScoAudioMode = new Integer(Settings.Global.getInt(
2484 mContentResolver,
2485 "bluetooth_sco_channel_"+
2486 mBluetoothHeadsetDevice.getAddress(),
2487 SCO_MODE_VIRTUAL_CALL));
2488 if (mScoAudioMode > SCO_MODE_MAX || mScoAudioMode < 0) {
2489 mScoAudioMode = SCO_MODE_VIRTUAL_CALL;
2490 }
2491 } else {
2492 mScoAudioMode = SCO_MODE_RAW;
Liejun Taof4e51d82014-07-16 11:18:29 -07002493 }
2494 }
Eric Laurent9f103de2011-09-08 15:04:23 -07002495 if (mBluetoothHeadset != null && mBluetoothHeadsetDevice != null) {
Liejun Taof4e51d82014-07-16 11:18:29 -07002496 boolean status = false;
Eric Laurentc18c9132013-04-12 17:24:56 -07002497 if (mScoAudioMode == SCO_MODE_RAW) {
2498 status = mBluetoothHeadset.connectAudio();
Liejun Taof4e51d82014-07-16 11:18:29 -07002499 } else if (mScoAudioMode == SCO_MODE_VIRTUAL_CALL) {
Eric Laurentc18c9132013-04-12 17:24:56 -07002500 status = mBluetoothHeadset.startScoUsingVirtualVoiceCall(
2501 mBluetoothHeadsetDevice);
Liejun Taof4e51d82014-07-16 11:18:29 -07002502 } else if (mScoAudioMode == SCO_MODE_VR) {
2503 status = mBluetoothHeadset.startVoiceRecognition(
2504 mBluetoothHeadsetDevice);
Eric Laurentc18c9132013-04-12 17:24:56 -07002505 }
Liejun Taof4e51d82014-07-16 11:18:29 -07002506
Eric Laurentc18c9132013-04-12 17:24:56 -07002507 if (status) {
Eric Laurent9f103de2011-09-08 15:04:23 -07002508 mScoAudioState = SCO_STATE_ACTIVE_INTERNAL;
2509 } else {
2510 broadcastScoConnectionState(
2511 AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
2512 }
2513 } else if (getBluetoothHeadset()) {
2514 mScoAudioState = SCO_STATE_ACTIVATE_REQ;
Eric Laurentdc03c612011-04-01 10:59:41 -07002515 }
Eric Laurent9f103de2011-09-08 15:04:23 -07002516 } else {
2517 mScoAudioState = SCO_STATE_ACTIVE_INTERNAL;
2518 broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_CONNECTED);
Eric Laurentdc03c612011-04-01 10:59:41 -07002519 }
2520 } else {
Eric Laurent9f103de2011-09-08 15:04:23 -07002521 broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
Eric Laurentdc03c612011-04-01 10:59:41 -07002522 }
Eric Laurentdc03c612011-04-01 10:59:41 -07002523 }
Eric Laurent62ef7672010-11-24 10:58:32 -08002524 } else if (state == BluetoothHeadset.STATE_AUDIO_DISCONNECTED &&
Eric Laurentdc03c612011-04-01 10:59:41 -07002525 (mScoAudioState == SCO_STATE_ACTIVE_INTERNAL ||
2526 mScoAudioState == SCO_STATE_ACTIVATE_REQ)) {
2527 if (mScoAudioState == SCO_STATE_ACTIVE_INTERNAL) {
Marco Nelissen671db6f2011-09-06 16:29:12 -07002528 if (mBluetoothHeadset != null && mBluetoothHeadsetDevice != null) {
Liejun Taof4e51d82014-07-16 11:18:29 -07002529 boolean status = false;
Eric Laurentc18c9132013-04-12 17:24:56 -07002530 if (mScoAudioMode == SCO_MODE_RAW) {
2531 status = mBluetoothHeadset.disconnectAudio();
Liejun Taof4e51d82014-07-16 11:18:29 -07002532 } else if (mScoAudioMode == SCO_MODE_VIRTUAL_CALL) {
Eric Laurentc18c9132013-04-12 17:24:56 -07002533 status = mBluetoothHeadset.stopScoUsingVirtualVoiceCall(
2534 mBluetoothHeadsetDevice);
Liejun Taof4e51d82014-07-16 11:18:29 -07002535 } else if (mScoAudioMode == SCO_MODE_VR) {
2536 status = mBluetoothHeadset.stopVoiceRecognition(
2537 mBluetoothHeadsetDevice);
Eric Laurentc18c9132013-04-12 17:24:56 -07002538 }
Liejun Taof4e51d82014-07-16 11:18:29 -07002539
Eric Laurentc18c9132013-04-12 17:24:56 -07002540 if (!status) {
Eric Laurentdc03c612011-04-01 10:59:41 -07002541 mScoAudioState = SCO_STATE_INACTIVE;
2542 broadcastScoConnectionState(
2543 AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
2544 }
2545 } else if (getBluetoothHeadset()) {
2546 mScoAudioState = SCO_STATE_DEACTIVATE_REQ;
2547 }
2548 } else {
2549 mScoAudioState = SCO_STATE_INACTIVE;
2550 broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
2551 }
Eric Laurent3def1ee2010-03-17 23:26:26 -07002552 }
2553 }
2554 }
2555 }
2556
Eric Laurent62ef7672010-11-24 10:58:32 -08002557 private void checkScoAudioState() {
2558 if (mBluetoothHeadset != null && mBluetoothHeadsetDevice != null &&
Eric Laurentdc03c612011-04-01 10:59:41 -07002559 mScoAudioState == SCO_STATE_INACTIVE &&
Eric Laurent62ef7672010-11-24 10:58:32 -08002560 mBluetoothHeadset.getAudioState(mBluetoothHeadsetDevice)
2561 != BluetoothHeadset.STATE_AUDIO_DISCONNECTED) {
2562 mScoAudioState = SCO_STATE_ACTIVE_EXTERNAL;
2563 }
2564 }
2565
Eric Laurent854938a2011-02-22 12:05:20 -08002566 private ScoClient getScoClient(IBinder cb, boolean create) {
Eric Laurent3def1ee2010-03-17 23:26:26 -07002567 synchronized(mScoClients) {
Eric Laurent854938a2011-02-22 12:05:20 -08002568 ScoClient client = null;
Eric Laurent3def1ee2010-03-17 23:26:26 -07002569 int size = mScoClients.size();
2570 for (int i = 0; i < size; i++) {
2571 client = mScoClients.get(i);
2572 if (client.getBinder() == cb)
2573 return client;
2574 }
Eric Laurent854938a2011-02-22 12:05:20 -08002575 if (create) {
2576 client = new ScoClient(cb);
2577 mScoClients.add(client);
2578 }
Eric Laurent3def1ee2010-03-17 23:26:26 -07002579 return client;
2580 }
2581 }
2582
Eric Laurentd7454be2011-09-14 08:45:58 -07002583 public void clearAllScoClients(int exceptPid, boolean stopSco) {
Eric Laurent3def1ee2010-03-17 23:26:26 -07002584 synchronized(mScoClients) {
Eric Laurent854938a2011-02-22 12:05:20 -08002585 ScoClient savedClient = null;
Eric Laurent3def1ee2010-03-17 23:26:26 -07002586 int size = mScoClients.size();
2587 for (int i = 0; i < size; i++) {
Eric Laurent854938a2011-02-22 12:05:20 -08002588 ScoClient cl = mScoClients.get(i);
Eric Laurentd7454be2011-09-14 08:45:58 -07002589 if (cl.getPid() != exceptPid) {
Eric Laurent854938a2011-02-22 12:05:20 -08002590 cl.clearCount(stopSco);
2591 } else {
2592 savedClient = cl;
2593 }
2594 }
2595 mScoClients.clear();
2596 if (savedClient != null) {
2597 mScoClients.add(savedClient);
Eric Laurent3def1ee2010-03-17 23:26:26 -07002598 }
2599 }
2600 }
2601
Eric Laurentdc03c612011-04-01 10:59:41 -07002602 private boolean getBluetoothHeadset() {
2603 boolean result = false;
2604 BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
2605 if (adapter != null) {
2606 result = adapter.getProfileProxy(mContext, mBluetoothProfileServiceListener,
2607 BluetoothProfile.HEADSET);
2608 }
2609 // If we could not get a bluetooth headset proxy, send a failure message
2610 // without delay to reset the SCO audio state and clear SCO clients.
2611 // If we could get a proxy, send a delayed failure message that will reset our state
2612 // in case we don't receive onServiceConnected().
Eric Laurentafbb0472011-12-15 09:04:23 -08002613 sendMsg(mAudioHandler, MSG_BT_HEADSET_CNCT_FAILED,
Eric Laurentdc03c612011-04-01 10:59:41 -07002614 SENDMSG_REPLACE, 0, 0, null, result ? BT_HEADSET_CNCT_TIMEOUT_MS : 0);
2615 return result;
2616 }
2617
Eric Laurentd7454be2011-09-14 08:45:58 -07002618 private void disconnectBluetoothSco(int exceptPid) {
Eric Laurentdc03c612011-04-01 10:59:41 -07002619 synchronized(mScoClients) {
2620 checkScoAudioState();
2621 if (mScoAudioState == SCO_STATE_ACTIVE_EXTERNAL ||
2622 mScoAudioState == SCO_STATE_DEACTIVATE_EXT_REQ) {
2623 if (mBluetoothHeadsetDevice != null) {
2624 if (mBluetoothHeadset != null) {
2625 if (!mBluetoothHeadset.stopVoiceRecognition(
Eric Laurentb06ac832011-05-25 15:55:18 -07002626 mBluetoothHeadsetDevice)) {
Eric Laurentafbb0472011-12-15 09:04:23 -08002627 sendMsg(mAudioHandler, MSG_BT_HEADSET_CNCT_FAILED,
Eric Laurentdc03c612011-04-01 10:59:41 -07002628 SENDMSG_REPLACE, 0, 0, null, 0);
2629 }
2630 } else if (mScoAudioState == SCO_STATE_ACTIVE_EXTERNAL &&
2631 getBluetoothHeadset()) {
2632 mScoAudioState = SCO_STATE_DEACTIVATE_EXT_REQ;
2633 }
2634 }
2635 } else {
Eric Laurentd7454be2011-09-14 08:45:58 -07002636 clearAllScoClients(exceptPid, true);
Eric Laurentdc03c612011-04-01 10:59:41 -07002637 }
2638 }
2639 }
2640
2641 private void resetBluetoothSco() {
2642 synchronized(mScoClients) {
Eric Laurentd7454be2011-09-14 08:45:58 -07002643 clearAllScoClients(0, false);
Eric Laurentdc03c612011-04-01 10:59:41 -07002644 mScoAudioState = SCO_STATE_INACTIVE;
2645 broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
2646 }
2647 }
2648
2649 private void broadcastScoConnectionState(int state) {
Eric Laurent2a57ca92013-03-07 17:29:27 -08002650 sendMsg(mAudioHandler, MSG_BROADCAST_BT_CONNECTION_STATE,
2651 SENDMSG_QUEUE, state, 0, null, 0);
2652 }
2653
2654 private void onBroadcastScoConnectionState(int state) {
Eric Laurentdc03c612011-04-01 10:59:41 -07002655 if (state != mScoConnectionState) {
2656 Intent newIntent = new Intent(AudioManager.ACTION_SCO_AUDIO_STATE_UPDATED);
2657 newIntent.putExtra(AudioManager.EXTRA_SCO_AUDIO_STATE, state);
2658 newIntent.putExtra(AudioManager.EXTRA_SCO_AUDIO_PREVIOUS_STATE,
2659 mScoConnectionState);
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07002660 sendStickyBroadcastToAll(newIntent);
Eric Laurentdc03c612011-04-01 10:59:41 -07002661 mScoConnectionState = state;
2662 }
2663 }
2664
Jaikumar Ganesh82aa7f02010-09-27 17:05:10 -07002665 private BluetoothProfile.ServiceListener mBluetoothProfileServiceListener =
2666 new BluetoothProfile.ServiceListener() {
2667 public void onServiceConnected(int profile, BluetoothProfile proxy) {
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08002668 BluetoothDevice btDevice;
2669 List<BluetoothDevice> deviceList;
2670 switch(profile) {
2671 case BluetoothProfile.A2DP:
seunghwan.hong4fe77952014-10-29 17:43:20 +09002672 synchronized (mConnectedDevices) {
2673 synchronized (mA2dpAvrcpLock) {
2674 mA2dp = (BluetoothA2dp) proxy;
2675 deviceList = mA2dp.getConnectedDevices();
2676 if (deviceList.size() > 0) {
2677 btDevice = deviceList.get(0);
John Du5a0cf7a2013-07-19 11:30:34 -07002678 int state = mA2dp.getConnectionState(btDevice);
2679 int delay = checkSendBecomingNoisyIntent(
Mike Lockwood0a40ec22014-05-21 10:08:50 -07002680 AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
2681 (state == BluetoothA2dp.STATE_CONNECTED) ? 1 : 0);
John Du5a0cf7a2013-07-19 11:30:34 -07002682 queueMsgUnderWakeLock(mAudioHandler,
Mike Lockwood0a40ec22014-05-21 10:08:50 -07002683 MSG_SET_A2DP_SINK_CONNECTION_STATE,
John Du5a0cf7a2013-07-19 11:30:34 -07002684 state,
2685 0,
2686 btDevice,
2687 delay);
2688 }
Eric Laurentb1fbaac2012-05-29 09:24:28 -07002689 }
Eric Laurent62ef7672010-11-24 10:58:32 -08002690 }
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08002691 break;
2692
Mike Lockwood0a40ec22014-05-21 10:08:50 -07002693 case BluetoothProfile.A2DP_SINK:
2694 deviceList = proxy.getConnectedDevices();
2695 if (deviceList.size() > 0) {
2696 btDevice = deviceList.get(0);
2697 synchronized (mConnectedDevices) {
2698 int state = proxy.getConnectionState(btDevice);
2699 queueMsgUnderWakeLock(mAudioHandler,
2700 MSG_SET_A2DP_SRC_CONNECTION_STATE,
2701 state,
2702 0,
2703 btDevice,
2704 0 /* delay */);
2705 }
2706 }
2707 break;
2708
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08002709 case BluetoothProfile.HEADSET:
2710 synchronized (mScoClients) {
2711 // Discard timeout message
2712 mAudioHandler.removeMessages(MSG_BT_HEADSET_CNCT_FAILED);
2713 mBluetoothHeadset = (BluetoothHeadset) proxy;
2714 deviceList = mBluetoothHeadset.getConnectedDevices();
2715 if (deviceList.size() > 0) {
2716 mBluetoothHeadsetDevice = deviceList.get(0);
2717 } else {
2718 mBluetoothHeadsetDevice = null;
2719 }
2720 // Refresh SCO audio state
2721 checkScoAudioState();
2722 // Continue pending action if any
2723 if (mScoAudioState == SCO_STATE_ACTIVATE_REQ ||
2724 mScoAudioState == SCO_STATE_DEACTIVATE_REQ ||
2725 mScoAudioState == SCO_STATE_DEACTIVATE_EXT_REQ) {
2726 boolean status = false;
2727 if (mBluetoothHeadsetDevice != null) {
2728 switch (mScoAudioState) {
2729 case SCO_STATE_ACTIVATE_REQ:
2730 mScoAudioState = SCO_STATE_ACTIVE_INTERNAL;
Eric Laurentc18c9132013-04-12 17:24:56 -07002731 if (mScoAudioMode == SCO_MODE_RAW) {
2732 status = mBluetoothHeadset.connectAudio();
Liejun Taof4e51d82014-07-16 11:18:29 -07002733 } else if (mScoAudioMode == SCO_MODE_VIRTUAL_CALL) {
Eric Laurentc18c9132013-04-12 17:24:56 -07002734 status = mBluetoothHeadset.startScoUsingVirtualVoiceCall(
2735 mBluetoothHeadsetDevice);
Liejun Taof4e51d82014-07-16 11:18:29 -07002736 } else if (mScoAudioMode == SCO_MODE_VR) {
2737 status = mBluetoothHeadset.startVoiceRecognition(
2738 mBluetoothHeadsetDevice);
Eric Laurentc18c9132013-04-12 17:24:56 -07002739 }
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08002740 break;
2741 case SCO_STATE_DEACTIVATE_REQ:
Eric Laurentc18c9132013-04-12 17:24:56 -07002742 if (mScoAudioMode == SCO_MODE_RAW) {
2743 status = mBluetoothHeadset.disconnectAudio();
Liejun Taof4e51d82014-07-16 11:18:29 -07002744 } else if (mScoAudioMode == SCO_MODE_VIRTUAL_CALL) {
Eric Laurentc18c9132013-04-12 17:24:56 -07002745 status = mBluetoothHeadset.stopScoUsingVirtualVoiceCall(
2746 mBluetoothHeadsetDevice);
Liejun Taof4e51d82014-07-16 11:18:29 -07002747 } else if (mScoAudioMode == SCO_MODE_VR) {
2748 status = mBluetoothHeadset.stopVoiceRecognition(
2749 mBluetoothHeadsetDevice);
Eric Laurentc18c9132013-04-12 17:24:56 -07002750 }
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08002751 break;
2752 case SCO_STATE_DEACTIVATE_EXT_REQ:
2753 status = mBluetoothHeadset.stopVoiceRecognition(
2754 mBluetoothHeadsetDevice);
2755 }
2756 }
2757 if (!status) {
Eric Laurentafbb0472011-12-15 09:04:23 -08002758 sendMsg(mAudioHandler, MSG_BT_HEADSET_CNCT_FAILED,
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08002759 SENDMSG_REPLACE, 0, 0, null, 0);
Eric Laurentdc03c612011-04-01 10:59:41 -07002760 }
2761 }
Eric Laurentdc03c612011-04-01 10:59:41 -07002762 }
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08002763 break;
2764
2765 default:
2766 break;
Eric Laurent3def1ee2010-03-17 23:26:26 -07002767 }
2768 }
Jaikumar Ganesh82aa7f02010-09-27 17:05:10 -07002769 public void onServiceDisconnected(int profile) {
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08002770 switch(profile) {
2771 case BluetoothProfile.A2DP:
seunghwan.hong4fe77952014-10-29 17:43:20 +09002772 synchronized (mConnectedDevices) {
2773 synchronized (mA2dpAvrcpLock) {
2774 mA2dp = null;
John Du5a0cf7a2013-07-19 11:30:34 -07002775 if (mConnectedDevices.containsKey(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP)) {
2776 makeA2dpDeviceUnavailableNow(
2777 mConnectedDevices.get(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP));
2778 }
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08002779 }
2780 }
2781 break;
2782
Mike Lockwood0a40ec22014-05-21 10:08:50 -07002783 case BluetoothProfile.A2DP_SINK:
2784 synchronized (mConnectedDevices) {
2785 if (mConnectedDevices.containsKey(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP)) {
2786 makeA2dpSrcUnavailable(
2787 mConnectedDevices.get(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP));
2788 }
2789 }
2790 break;
2791
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08002792 case BluetoothProfile.HEADSET:
2793 synchronized (mScoClients) {
2794 mBluetoothHeadset = null;
2795 }
2796 break;
2797
2798 default:
2799 break;
Eric Laurent3def1ee2010-03-17 23:26:26 -07002800 }
2801 }
2802 };
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08002803
Eric Laurentc34dcc12012-09-10 13:51:52 -07002804 private void onCheckMusicActive() {
Eric Laurentd640bd32012-09-28 18:01:48 -07002805 synchronized (mSafeMediaVolumeState) {
2806 if (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_INACTIVE) {
Eric Laurentc34dcc12012-09-10 13:51:52 -07002807 int device = getDeviceForStream(AudioSystem.STREAM_MUSIC);
2808
2809 if ((device & mSafeMediaVolumeDevices) != 0) {
2810 sendMsg(mAudioHandler,
2811 MSG_CHECK_MUSIC_ACTIVE,
2812 SENDMSG_REPLACE,
Eric Laurentf1a457d2012-09-20 16:27:23 -07002813 0,
Eric Laurentc34dcc12012-09-10 13:51:52 -07002814 0,
2815 null,
2816 MUSIC_ACTIVE_POLL_PERIOD_MS);
Eric Laurent42b041e2013-03-29 11:36:03 -07002817 int index = mStreamStates[AudioSystem.STREAM_MUSIC].getIndex(device);
Eric Laurentf1a457d2012-09-20 16:27:23 -07002818 if (AudioSystem.isStreamActive(AudioSystem.STREAM_MUSIC, 0) &&
2819 (index > mSafeMediaVolumeIndex)) {
Eric Laurentc34dcc12012-09-10 13:51:52 -07002820 // Approximate cumulative active music time
2821 mMusicActiveMs += MUSIC_ACTIVE_POLL_PERIOD_MS;
2822 if (mMusicActiveMs > UNSAFE_VOLUME_MUSIC_ACTIVE_MS_MAX) {
2823 setSafeMediaVolumeEnabled(true);
2824 mMusicActiveMs = 0;
Eric Laurentc34dcc12012-09-10 13:51:52 -07002825 }
John Spurlockaa5ee4d2014-07-25 13:05:12 -04002826 saveMusicActiveMs();
Eric Laurentc34dcc12012-09-10 13:51:52 -07002827 }
2828 }
2829 }
2830 }
2831 }
2832
John Spurlockaa5ee4d2014-07-25 13:05:12 -04002833 private void saveMusicActiveMs() {
2834 mAudioHandler.obtainMessage(MSG_PERSIST_MUSIC_ACTIVE_MS, mMusicActiveMs, 0).sendToTarget();
2835 }
2836
Eric Laurentd640bd32012-09-28 18:01:48 -07002837 private void onConfigureSafeVolume(boolean force) {
2838 synchronized (mSafeMediaVolumeState) {
2839 int mcc = mContext.getResources().getConfiguration().mcc;
2840 if ((mMcc != mcc) || ((mMcc == 0) && force)) {
2841 mSafeMediaVolumeIndex = mContext.getResources().getInteger(
2842 com.android.internal.R.integer.config_safe_media_volume_index) * 10;
John Spurlock35134602014-07-24 18:10:48 -04002843 boolean safeMediaVolumeEnabled =
2844 SystemProperties.getBoolean("audio.safemedia.force", false)
2845 || mContext.getResources().getBoolean(
2846 com.android.internal.R.bool.config_safe_media_volume_enabled);
Eric Laurent05274f32012-11-29 12:48:18 -08002847
2848 // The persisted state is either "disabled" or "active": this is the state applied
2849 // next time we boot and cannot be "inactive"
2850 int persistedState;
Eric Laurentd640bd32012-09-28 18:01:48 -07002851 if (safeMediaVolumeEnabled) {
Eric Laurent05274f32012-11-29 12:48:18 -08002852 persistedState = SAFE_MEDIA_VOLUME_ACTIVE;
2853 // The state can already be "inactive" here if the user has forced it before
2854 // the 30 seconds timeout for forced configuration. In this case we don't reset
2855 // it to "active".
2856 if (mSafeMediaVolumeState != SAFE_MEDIA_VOLUME_INACTIVE) {
John Spurlockaa5ee4d2014-07-25 13:05:12 -04002857 if (mMusicActiveMs == 0) {
2858 mSafeMediaVolumeState = SAFE_MEDIA_VOLUME_ACTIVE;
2859 enforceSafeMediaVolume();
2860 } else {
2861 // We have existing playback time recorded, already confirmed.
2862 mSafeMediaVolumeState = SAFE_MEDIA_VOLUME_INACTIVE;
2863 }
Eric Laurent05274f32012-11-29 12:48:18 -08002864 }
Eric Laurentd640bd32012-09-28 18:01:48 -07002865 } else {
Eric Laurent05274f32012-11-29 12:48:18 -08002866 persistedState = SAFE_MEDIA_VOLUME_DISABLED;
Eric Laurentd640bd32012-09-28 18:01:48 -07002867 mSafeMediaVolumeState = SAFE_MEDIA_VOLUME_DISABLED;
2868 }
2869 mMcc = mcc;
Eric Laurent05274f32012-11-29 12:48:18 -08002870 sendMsg(mAudioHandler,
2871 MSG_PERSIST_SAFE_VOLUME_STATE,
2872 SENDMSG_QUEUE,
2873 persistedState,
2874 0,
2875 null,
2876 0);
Eric Laurentd640bd32012-09-28 18:01:48 -07002877 }
2878 }
2879 }
2880
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002881 ///////////////////////////////////////////////////////////////////////////
2882 // Internal methods
2883 ///////////////////////////////////////////////////////////////////////////
2884
2885 /**
2886 * Checks if the adjustment should change ringer mode instead of just
2887 * adjusting volume. If so, this will set the proper ringer mode and volume
2888 * indices on the stream states.
2889 */
RoboErik5452e252015-02-06 15:33:53 -08002890 private int checkForRingerModeChange(int oldIndex, int direction, int step, boolean isMuted) {
John Spurlocka11b4af2014-06-01 11:52:23 -04002891 int result = FLAG_ADJUST_VOLUME;
John Spurlock661f2cf2014-11-17 10:29:10 -05002892 int ringerMode = getRingerModeInternal();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002893
Eric Laurentbffc3d12012-05-07 17:43:49 -07002894 switch (ringerMode) {
2895 case RINGER_MODE_NORMAL:
2896 if (direction == AudioManager.ADJUST_LOWER) {
2897 if (mHasVibrator) {
Eric Laurent24482012012-05-10 09:41:17 -07002898 // "step" is the delta in internal index units corresponding to a
2899 // change of 1 in UI index units.
2900 // Because of rounding when rescaling from one stream index range to its alias
2901 // index range, we cannot simply test oldIndex == step:
2902 // (step <= oldIndex < 2 * step) is equivalent to: (old UI index == 1)
2903 if (step <= oldIndex && oldIndex < 2 * step) {
Eric Laurentbffc3d12012-05-07 17:43:49 -07002904 ringerMode = RINGER_MODE_VIBRATE;
2905 }
2906 } else {
Eric Laurent24482012012-05-10 09:41:17 -07002907 // (oldIndex < step) is equivalent to (old UI index == 0)
John Spurlock86005342014-05-23 11:58:00 -04002908 if ((oldIndex < step)
2909 && VOLUME_SETS_RINGER_MODE_SILENT
2910 && mPrevVolDirection != AudioManager.ADJUST_LOWER) {
Eric Laurentbffc3d12012-05-07 17:43:49 -07002911 ringerMode = RINGER_MODE_SILENT;
2912 }
Eric Laurent3d4c06f2011-08-15 19:58:28 -07002913 }
RoboErik5452e252015-02-06 15:33:53 -08002914 } else if (direction == AudioManager.ADJUST_TOGGLE_MUTE
2915 || direction == AudioManager.ADJUST_MUTE) {
2916 if (mHasVibrator) {
2917 ringerMode = RINGER_MODE_VIBRATE;
2918 } else {
2919 ringerMode = RINGER_MODE_SILENT;
2920 }
2921 // Setting the ringer mode will toggle mute
2922 result &= ~FLAG_ADJUST_VOLUME;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002923 }
Eric Laurentbffc3d12012-05-07 17:43:49 -07002924 break;
2925 case RINGER_MODE_VIBRATE:
2926 if (!mHasVibrator) {
2927 Log.e(TAG, "checkForRingerModeChange() current ringer mode is vibrate" +
2928 "but no vibrator is present");
2929 break;
2930 }
Amith Yamasanic696a532011-10-28 17:02:37 -07002931 if ((direction == AudioManager.ADJUST_LOWER)) {
RoboErik5452e252015-02-06 15:33:53 -08002932 // This is the case we were muted with the volume turned up
2933 if (oldIndex >= 2 * step && isMuted) {
2934 ringerMode = RINGER_MODE_NORMAL;
2935 } else if (mPrevVolDirection != AudioManager.ADJUST_LOWER) {
John Spurlock795a5142014-12-08 14:09:35 -05002936 if (VOLUME_SETS_RINGER_MODE_SILENT) {
2937 ringerMode = RINGER_MODE_SILENT;
2938 } else {
2939 result |= AudioManager.FLAG_SHOW_VIBRATE_HINT;
2940 }
Amith Yamasanic696a532011-10-28 17:02:37 -07002941 }
RoboErik5452e252015-02-06 15:33:53 -08002942 } else if (direction == AudioManager.ADJUST_RAISE
2943 || direction == AudioManager.ADJUST_TOGGLE_MUTE
2944 || direction == AudioManager.ADJUST_UNMUTE) {
Eric Laurentbffc3d12012-05-07 17:43:49 -07002945 ringerMode = RINGER_MODE_NORMAL;
Amith Yamasanic696a532011-10-28 17:02:37 -07002946 }
John Spurlocka11b4af2014-06-01 11:52:23 -04002947 result &= ~FLAG_ADJUST_VOLUME;
Eric Laurentbffc3d12012-05-07 17:43:49 -07002948 break;
2949 case RINGER_MODE_SILENT:
RoboErik5452e252015-02-06 15:33:53 -08002950 if (direction == AudioManager.ADJUST_LOWER && oldIndex >= 2 * step && isMuted) {
2951 // This is the case we were muted with the volume turned up
2952 ringerMode = RINGER_MODE_NORMAL;
2953 } else if (direction == AudioManager.ADJUST_RAISE
2954 || direction == AudioManager.ADJUST_TOGGLE_MUTE
2955 || direction == AudioManager.ADJUST_UNMUTE) {
John Spurlocka11b4af2014-06-01 11:52:23 -04002956 if (PREVENT_VOLUME_ADJUSTMENT_IF_SILENT) {
2957 result |= AudioManager.FLAG_SHOW_SILENT_HINT;
Eric Laurentbffc3d12012-05-07 17:43:49 -07002958 } else {
RoboErik5452e252015-02-06 15:33:53 -08002959 if (mHasVibrator && direction == AudioManager.ADJUST_RAISE) {
John Spurlocka11b4af2014-06-01 11:52:23 -04002960 ringerMode = RINGER_MODE_VIBRATE;
2961 } else {
RoboErik5452e252015-02-06 15:33:53 -08002962 // If we don't have a vibrator or they were toggling mute
2963 // go straight back to normal.
John Spurlocka11b4af2014-06-01 11:52:23 -04002964 ringerMode = RINGER_MODE_NORMAL;
2965 }
Eric Laurentbffc3d12012-05-07 17:43:49 -07002966 }
Daniel Sandler6329bf72010-02-26 15:17:44 -05002967 }
John Spurlocka11b4af2014-06-01 11:52:23 -04002968 result &= ~FLAG_ADJUST_VOLUME;
Eric Laurentbffc3d12012-05-07 17:43:49 -07002969 break;
2970 default:
2971 Log.e(TAG, "checkForRingerModeChange() wrong ringer mode: "+ringerMode);
2972 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002973 }
2974
John Spurlock661f2cf2014-11-17 10:29:10 -05002975 setRingerMode(ringerMode, TAG + ".checkForRingerModeChange", false /*external*/);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002976
Eric Laurent25101b02011-02-02 09:33:30 -08002977 mPrevVolDirection = direction;
2978
John Spurlocka11b4af2014-06-01 11:52:23 -04002979 return result;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002980 }
2981
John Spurlock3346a802014-05-20 16:25:37 -04002982 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002983 public boolean isStreamAffectedByRingerMode(int streamType) {
Eric Laurent9bcf4012009-06-12 06:09:28 -07002984 return (mRingerModeAffectedStreams & (1 << streamType)) != 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08002985 }
2986
Eric Laurent5b4e6542010-03-19 20:02:21 -07002987 private boolean isStreamMutedByRingerMode(int streamType) {
2988 return (mRingerModeMutedStreams & (1 << streamType)) != 0;
2989 }
2990
Eric Laurent24e0d9b2013-10-03 18:15:07 -07002991 boolean updateRingerModeAffectedStreams() {
2992 int ringerModeAffectedStreams;
2993 // make sure settings for ringer mode are consistent with device type: non voice capable
2994 // devices (tablets) include media stream in silent mode whereas phones don't.
2995 ringerModeAffectedStreams = Settings.System.getIntForUser(mContentResolver,
2996 Settings.System.MODE_RINGER_STREAMS_AFFECTED,
2997 ((1 << AudioSystem.STREAM_RING)|(1 << AudioSystem.STREAM_NOTIFICATION)|
2998 (1 << AudioSystem.STREAM_SYSTEM)|(1 << AudioSystem.STREAM_SYSTEM_ENFORCED)),
2999 UserHandle.USER_CURRENT);
3000
3001 // ringtone, notification and system streams are always affected by ringer mode
3002 ringerModeAffectedStreams |= (1 << AudioSystem.STREAM_RING)|
3003 (1 << AudioSystem.STREAM_NOTIFICATION)|
3004 (1 << AudioSystem.STREAM_SYSTEM);
3005
Eric Laurent212532b2014-07-21 15:43:18 -07003006 switch (mPlatformType) {
John Spurlock61560172015-02-06 19:46:04 -05003007 case AudioSystem.PLATFORM_TELEVISION:
Eric Laurent212532b2014-07-21 15:43:18 -07003008 ringerModeAffectedStreams = 0;
3009 break;
3010 default:
John Spurlock77e54d92014-08-11 12:16:24 -04003011 ringerModeAffectedStreams &= ~(1 << AudioSystem.STREAM_MUSIC);
Eric Laurent212532b2014-07-21 15:43:18 -07003012 break;
Eric Laurent24e0d9b2013-10-03 18:15:07 -07003013 }
Eric Laurent212532b2014-07-21 15:43:18 -07003014
Eric Laurent24e0d9b2013-10-03 18:15:07 -07003015 synchronized (mCameraSoundForced) {
3016 if (mCameraSoundForced) {
3017 ringerModeAffectedStreams &= ~(1 << AudioSystem.STREAM_SYSTEM_ENFORCED);
3018 } else {
3019 ringerModeAffectedStreams |= (1 << AudioSystem.STREAM_SYSTEM_ENFORCED);
3020 }
3021 }
3022 if (mStreamVolumeAlias[AudioSystem.STREAM_DTMF] == AudioSystem.STREAM_RING) {
3023 ringerModeAffectedStreams |= (1 << AudioSystem.STREAM_DTMF);
3024 } else {
3025 ringerModeAffectedStreams &= ~(1 << AudioSystem.STREAM_DTMF);
3026 }
3027
3028 if (ringerModeAffectedStreams != mRingerModeAffectedStreams) {
3029 Settings.System.putIntForUser(mContentResolver,
3030 Settings.System.MODE_RINGER_STREAMS_AFFECTED,
3031 ringerModeAffectedStreams,
3032 UserHandle.USER_CURRENT);
3033 mRingerModeAffectedStreams = ringerModeAffectedStreams;
3034 return true;
3035 }
3036 return false;
3037 }
3038
John Spurlocka9dfbe8b2015-02-17 11:01:51 -05003039 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003040 public boolean isStreamAffectedByMute(int streamType) {
3041 return (mMuteAffectedStreams & (1 << streamType)) != 0;
3042 }
3043
3044 private void ensureValidDirection(int direction) {
RoboErik4197cb62015-01-21 15:45:32 -08003045 switch (direction) {
3046 case AudioManager.ADJUST_LOWER:
3047 case AudioManager.ADJUST_RAISE:
3048 case AudioManager.ADJUST_SAME:
3049 case AudioManager.ADJUST_MUTE:
3050 case AudioManager.ADJUST_UNMUTE:
3051 case AudioManager.ADJUST_TOGGLE_MUTE:
3052 break;
3053 default:
3054 throw new IllegalArgumentException("Bad direction " + direction);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003055 }
3056 }
3057
Lei Zhang6c798972012-03-02 11:40:12 -08003058 private void ensureValidSteps(int steps) {
3059 if (Math.abs(steps) > MAX_BATCH_VOLUME_ADJUST_STEPS) {
3060 throw new IllegalArgumentException("Bad volume adjust steps " + steps);
3061 }
3062 }
3063
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003064 private void ensureValidStreamType(int streamType) {
3065 if (streamType < 0 || streamType >= mStreamStates.length) {
3066 throw new IllegalArgumentException("Bad stream type " + streamType);
3067 }
3068 }
3069
RoboErik4197cb62015-01-21 15:45:32 -08003070 private boolean isMuteAdjust(int adjust) {
3071 return adjust == AudioManager.ADJUST_MUTE || adjust == AudioManager.ADJUST_UNMUTE
3072 || adjust == AudioManager.ADJUST_TOGGLE_MUTE;
3073 }
3074
Eric Laurent6d517662012-04-23 18:42:39 -07003075 private boolean isInCommunication() {
Nancy Chen0eb1e402014-08-21 22:52:29 -07003076 boolean IsInCall = false;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003077
Tyler Gunnef9f6f92014-09-12 22:16:17 -07003078 TelecomManager telecomManager =
3079 (TelecomManager) mContext.getSystemService(Context.TELECOM_SERVICE);
Eric Laurent38edfda2014-12-18 17:38:04 -08003080
3081 final long ident = Binder.clearCallingIdentity();
Tyler Gunnef9f6f92014-09-12 22:16:17 -07003082 IsInCall = telecomManager.isInCall();
Eric Laurent38edfda2014-12-18 17:38:04 -08003083 Binder.restoreCallingIdentity(ident);
Santos Cordon9eb45932014-06-27 12:28:43 -07003084
Nancy Chen0eb1e402014-08-21 22:52:29 -07003085 return (IsInCall || getMode() == AudioManager.MODE_IN_COMMUNICATION);
Eric Laurent6d517662012-04-23 18:42:39 -07003086 }
Eric Laurent25101b02011-02-02 09:33:30 -08003087
Jean-Michel Trivifca1e602013-10-10 18:12:59 -07003088 /**
3089 * For code clarity for getActiveStreamType(int)
3090 * @param delay_ms max time since last STREAM_MUSIC activity to consider
3091 * @return true if STREAM_MUSIC is active in streams handled by AudioFlinger now or
3092 * in the last "delay_ms" ms.
3093 */
3094 private boolean isAfMusicActiveRecently(int delay_ms) {
3095 return AudioSystem.isStreamActive(AudioSystem.STREAM_MUSIC, delay_ms)
3096 || AudioSystem.isStreamActiveRemotely(AudioSystem.STREAM_MUSIC, delay_ms);
3097 }
3098
Eric Laurent6d517662012-04-23 18:42:39 -07003099 private int getActiveStreamType(int suggestedStreamType) {
Eric Laurent212532b2014-07-21 15:43:18 -07003100 switch (mPlatformType) {
John Spurlock61560172015-02-06 19:46:04 -05003101 case AudioSystem.PLATFORM_VOICE:
Eric Laurent6d517662012-04-23 18:42:39 -07003102 if (isInCommunication()) {
Eric Laurent25101b02011-02-02 09:33:30 -08003103 if (AudioSystem.getForceUse(AudioSystem.FOR_COMMUNICATION)
3104 == AudioSystem.FORCE_BT_SCO) {
3105 // Log.v(TAG, "getActiveStreamType: Forcing STREAM_BLUETOOTH_SCO...");
3106 return AudioSystem.STREAM_BLUETOOTH_SCO;
3107 } else {
3108 // Log.v(TAG, "getActiveStreamType: Forcing STREAM_VOICE_CALL...");
3109 return AudioSystem.STREAM_VOICE_CALL;
3110 }
Eric Laurent25101b02011-02-02 09:33:30 -08003111 } else if (suggestedStreamType == AudioManager.USE_DEFAULT_STREAM_TYPE) {
Jean-Michel Trivi873cc452014-09-11 17:25:09 -07003112 if (isAfMusicActiveRecently(StreamOverride.sDelayMs)) {
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07003113 if (DEBUG_VOL)
3114 Log.v(TAG, "getActiveStreamType: Forcing STREAM_MUSIC stream active");
3115 return AudioSystem.STREAM_MUSIC;
Jean-Michel Trivifca1e602013-10-10 18:12:59 -07003116 } else {
3117 if (DEBUG_VOL)
3118 Log.v(TAG, "getActiveStreamType: Forcing STREAM_RING b/c default");
3119 return AudioSystem.STREAM_RING;
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07003120 }
Jean-Michel Trivifca1e602013-10-10 18:12:59 -07003121 } else if (isAfMusicActiveRecently(0)) {
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07003122 if (DEBUG_VOL)
3123 Log.v(TAG, "getActiveStreamType: Forcing STREAM_MUSIC stream active");
3124 return AudioSystem.STREAM_MUSIC;
Eric Laurent25101b02011-02-02 09:33:30 -08003125 }
Eric Laurent212532b2014-07-21 15:43:18 -07003126 break;
John Spurlock61560172015-02-06 19:46:04 -05003127 case AudioSystem.PLATFORM_TELEVISION:
Eric Laurent212532b2014-07-21 15:43:18 -07003128 if (suggestedStreamType == AudioManager.USE_DEFAULT_STREAM_TYPE) {
RoboErik2811dd32014-08-12 09:48:13 -07003129 // TV always defaults to STREAM_MUSIC
Eric Laurent212532b2014-07-21 15:43:18 -07003130 return AudioSystem.STREAM_MUSIC;
Eric Laurent212532b2014-07-21 15:43:18 -07003131 }
3132 break;
3133 default:
Eric Laurent6d517662012-04-23 18:42:39 -07003134 if (isInCommunication()) {
Eric Laurent25101b02011-02-02 09:33:30 -08003135 if (AudioSystem.getForceUse(AudioSystem.FOR_COMMUNICATION)
3136 == AudioSystem.FORCE_BT_SCO) {
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07003137 if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: Forcing STREAM_BLUETOOTH_SCO");
Eric Laurent25101b02011-02-02 09:33:30 -08003138 return AudioSystem.STREAM_BLUETOOTH_SCO;
3139 } else {
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07003140 if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: Forcing STREAM_VOICE_CALL");
Eric Laurent25101b02011-02-02 09:33:30 -08003141 return AudioSystem.STREAM_VOICE_CALL;
3142 }
3143 } else if (AudioSystem.isStreamActive(AudioSystem.STREAM_NOTIFICATION,
Jean-Michel Trivi873cc452014-09-11 17:25:09 -07003144 StreamOverride.sDelayMs) ||
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07003145 AudioSystem.isStreamActive(AudioSystem.STREAM_RING,
Jean-Michel Trivi873cc452014-09-11 17:25:09 -07003146 StreamOverride.sDelayMs)) {
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07003147 if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: Forcing STREAM_NOTIFICATION");
Eric Laurent25101b02011-02-02 09:33:30 -08003148 return AudioSystem.STREAM_NOTIFICATION;
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07003149 } else if (suggestedStreamType == AudioManager.USE_DEFAULT_STREAM_TYPE) {
Jean-Michel Trivi873cc452014-09-11 17:25:09 -07003150 if (isAfMusicActiveRecently(StreamOverride.sDelayMs)) {
Jean-Michel Trivifca1e602013-10-10 18:12:59 -07003151 if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: forcing STREAM_MUSIC");
3152 return AudioSystem.STREAM_MUSIC;
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07003153 } else {
John Spurlockeb1d88d2014-07-19 14:49:19 -04003154 if (DEBUG_VOL) Log.v(TAG,
3155 "getActiveStreamType: using STREAM_NOTIFICATION as default");
3156 return AudioSystem.STREAM_NOTIFICATION;
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07003157 }
Joe Onoratoc7fcba42011-01-05 16:53:11 -08003158 }
Eric Laurent212532b2014-07-21 15:43:18 -07003159 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003160 }
Eric Laurent212532b2014-07-21 15:43:18 -07003161 if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: Returning suggested type "
3162 + suggestedStreamType);
3163 return suggestedStreamType;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003164 }
3165
John Spurlockbcc10872014-11-28 15:29:21 -05003166 private void broadcastRingerMode(String action, int ringerMode) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003167 // Send sticky broadcast
John Spurlockbcc10872014-11-28 15:29:21 -05003168 Intent broadcast = new Intent(action);
Glenn Kastenba195eb2011-12-13 09:30:40 -08003169 broadcast.putExtra(AudioManager.EXTRA_RINGER_MODE, ringerMode);
Dianne Hackborn1c633fc2009-12-08 19:45:14 -08003170 broadcast.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT
3171 | Intent.FLAG_RECEIVER_REPLACE_PENDING);
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07003172 sendStickyBroadcastToAll(broadcast);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003173 }
3174
3175 private void broadcastVibrateSetting(int vibrateType) {
3176 // Send broadcast
3177 if (ActivityManagerNative.isSystemReady()) {
3178 Intent broadcast = new Intent(AudioManager.VIBRATE_SETTING_CHANGED_ACTION);
3179 broadcast.putExtra(AudioManager.EXTRA_VIBRATE_TYPE, vibrateType);
3180 broadcast.putExtra(AudioManager.EXTRA_VIBRATE_SETTING, getVibrateSetting(vibrateType));
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07003181 sendBroadcastToAll(broadcast);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003182 }
3183 }
3184
3185 // Message helper methods
Jean-Michel Trivi2d8dab52012-05-30 18:13:59 -07003186 /**
3187 * Queue a message on the given handler's message queue, after acquiring the service wake lock.
3188 * Note that the wake lock needs to be released after the message has been handled.
3189 */
3190 private void queueMsgUnderWakeLock(Handler handler, int msg,
3191 int arg1, int arg2, Object obj, int delay) {
Eric Laurenta4dfbdc52013-10-01 11:53:51 -07003192 final long ident = Binder.clearCallingIdentity();
3193 // Always acquire the wake lock as AudioService because it is released by the
3194 // message handler.
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -07003195 mAudioEventWakeLock.acquire();
Eric Laurenta4dfbdc52013-10-01 11:53:51 -07003196 Binder.restoreCallingIdentity(ident);
Jean-Michel Trivi2d8dab52012-05-30 18:13:59 -07003197 sendMsg(handler, msg, SENDMSG_QUEUE, arg1, arg2, obj, delay);
3198 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003199
Eric Laurentafbb0472011-12-15 09:04:23 -08003200 private static void sendMsg(Handler handler, int msg,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003201 int existingMsgPolicy, int arg1, int arg2, Object obj, int delay) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003202
3203 if (existingMsgPolicy == SENDMSG_REPLACE) {
3204 handler.removeMessages(msg);
3205 } else if (existingMsgPolicy == SENDMSG_NOOP && handler.hasMessages(msg)) {
3206 return;
3207 }
Eric Laurentadbe8bf2014-11-03 18:26:32 -08003208 synchronized (mLastDeviceConnectMsgTime) {
3209 long time = SystemClock.uptimeMillis() + delay;
3210 handler.sendMessageAtTime(handler.obtainMessage(msg, arg1, arg2, obj), time);
3211 if (msg == MSG_SET_WIRED_DEVICE_CONNECTION_STATE ||
3212 msg == MSG_SET_A2DP_SRC_CONNECTION_STATE ||
3213 msg == MSG_SET_A2DP_SINK_CONNECTION_STATE) {
3214 mLastDeviceConnectMsgTime = time;
3215 }
3216 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003217 }
3218
3219 boolean checkAudioSettingsPermission(String method) {
Jean-Michel Triviccd654e2014-09-03 17:48:47 -07003220 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.MODIFY_AUDIO_SETTINGS)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003221 == PackageManager.PERMISSION_GRANTED) {
3222 return true;
3223 }
3224 String msg = "Audio Settings Permission Denial: " + method + " from pid="
3225 + Binder.getCallingPid()
3226 + ", uid=" + Binder.getCallingUid();
3227 Log.w(TAG, msg);
3228 return false;
3229 }
3230
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003231 private int getDeviceForStream(int stream) {
3232 int device = AudioSystem.getDevicesForStream(stream);
3233 if ((device & (device - 1)) != 0) {
3234 // Multiple device selection is either:
3235 // - speaker + one other device: give priority to speaker in this case.
3236 // - one A2DP device + another device: happens with duplicated output. In this case
3237 // retain the device on the A2DP output as the other must not correspond to an active
3238 // selection if not the speaker.
Jungshik Jangc9ff9682014-09-15 17:41:06 +09003239 // - HDMI-CEC system audio mode only output: give priority to available item in order.
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003240 if ((device & AudioSystem.DEVICE_OUT_SPEAKER) != 0) {
3241 device = AudioSystem.DEVICE_OUT_SPEAKER;
Jungshik Jangc9ff9682014-09-15 17:41:06 +09003242 } else if ((device & AudioSystem.DEVICE_OUT_HDMI_ARC) != 0) {
3243 device = AudioSystem.DEVICE_OUT_HDMI_ARC;
3244 } else if ((device & AudioSystem.DEVICE_OUT_SPDIF) != 0) {
3245 device = AudioSystem.DEVICE_OUT_SPDIF;
3246 } else if ((device & AudioSystem.DEVICE_OUT_AUX_LINE) != 0) {
3247 device = AudioSystem.DEVICE_OUT_AUX_LINE;
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003248 } else {
3249 device &= AudioSystem.DEVICE_OUT_ALL_A2DP;
3250 }
3251 }
3252 return device;
3253 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003254
Paul McLean10804eb2015-01-28 11:16:35 -08003255 /*
3256 * A class just for packaging up a set of connection parameters.
3257 */
3258 private class WiredDeviceConnectionState {
3259 public int mType;
3260 public int mState;
3261 public String mAddress;
3262 public String mName;
3263
3264 public WiredDeviceConnectionState(int type, int state, String address, String name) {
3265 mType = type;
3266 mState = state;
3267 mAddress = address;
3268 mName = name;
3269 }
3270 }
3271
3272 public void setWiredDeviceConnectionState(int type, int state, String address,
3273 String name) {
Eric Laurentb1fbaac2012-05-29 09:24:28 -07003274 synchronized (mConnectedDevices) {
Paul McLean10804eb2015-01-28 11:16:35 -08003275 int delay = checkSendBecomingNoisyIntent(type, state);
Jean-Michel Trivi2d8dab52012-05-30 18:13:59 -07003276 queueMsgUnderWakeLock(mAudioHandler,
Eric Laurentb1fbaac2012-05-29 09:24:28 -07003277 MSG_SET_WIRED_DEVICE_CONNECTION_STATE,
Paul McLean10804eb2015-01-28 11:16:35 -08003278 0,
3279 0,
3280 new WiredDeviceConnectionState(type, state, address, name),
Eric Laurentb1fbaac2012-05-29 09:24:28 -07003281 delay);
3282 }
3283 }
3284
Mike Lockwood0a40ec22014-05-21 10:08:50 -07003285 public int setBluetoothA2dpDeviceConnectionState(BluetoothDevice device, int state, int profile)
Eric Laurentb1fbaac2012-05-29 09:24:28 -07003286 {
3287 int delay;
Mike Lockwood0a40ec22014-05-21 10:08:50 -07003288 if (profile != BluetoothProfile.A2DP && profile != BluetoothProfile.A2DP_SINK) {
3289 throw new IllegalArgumentException("invalid profile " + profile);
3290 }
Eric Laurentb1fbaac2012-05-29 09:24:28 -07003291 synchronized (mConnectedDevices) {
Mike Lockwood0a40ec22014-05-21 10:08:50 -07003292 if (profile == BluetoothProfile.A2DP) {
3293 delay = checkSendBecomingNoisyIntent(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
3294 (state == BluetoothA2dp.STATE_CONNECTED) ? 1 : 0);
3295 } else {
3296 delay = 0;
3297 }
Jean-Michel Trivi2d8dab52012-05-30 18:13:59 -07003298 queueMsgUnderWakeLock(mAudioHandler,
Mike Lockwood0a40ec22014-05-21 10:08:50 -07003299 (profile == BluetoothProfile.A2DP ?
3300 MSG_SET_A2DP_SINK_CONNECTION_STATE : MSG_SET_A2DP_SRC_CONNECTION_STATE),
Eric Laurentb1fbaac2012-05-29 09:24:28 -07003301 state,
3302 0,
3303 device,
3304 delay);
3305 }
3306 return delay;
3307 }
3308
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003309 ///////////////////////////////////////////////////////////////////////////
3310 // Inner classes
3311 ///////////////////////////////////////////////////////////////////////////
3312
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07003313 // NOTE: Locking order for synchronized objects related to volume or ringer mode management:
3314 // 1 mScoclient OR mSafeMediaVolumeState
3315 // 2 mSetModeDeathHandlers
3316 // 3 mSettingsLock
3317 // 4 VolumeStreamState.class
3318 // 5 mCameraSoundForced
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003319 public class VolumeStreamState {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003320 private final int mStreamType;
3321
RoboErik4197cb62015-01-21 15:45:32 -08003322 private boolean mIsMuted;
Jean-Michel Trivi11a74a72009-10-27 17:39:30 -07003323 private String mVolumeIndexSettingName;
Eric Laurenta553c252009-07-17 12:17:14 -07003324 private int mIndexMax;
John Spurlock2bb02ec2015-03-02 13:13:06 -05003325 private final SparseIntArray mIndexMap = new SparseIntArray(8);
John Spurlockf63860c2015-02-19 09:46:27 -05003326 private final Intent mVolumeChanged;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003327
Eric Laurenta553c252009-07-17 12:17:14 -07003328 private VolumeStreamState(String settingName, int streamType) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003329
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003330 mVolumeIndexSettingName = settingName;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003331
3332 mStreamType = streamType;
Jared Suttles59820132009-08-13 21:50:52 -05003333 mIndexMax = MAX_STREAM_VOLUME[streamType];
Eric Laurenta553c252009-07-17 12:17:14 -07003334 AudioSystem.initStreamVolume(streamType, 0, mIndexMax);
3335 mIndexMax *= 10;
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003336
Eric Laurent33902db2012-10-07 16:15:07 -07003337 readSettings();
John Spurlockf63860c2015-02-19 09:46:27 -05003338 mVolumeChanged = new Intent(AudioManager.VOLUME_CHANGED_ACTION);
3339 mVolumeChanged.putExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, mStreamType);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003340 }
3341
Eric Laurent42b041e2013-03-29 11:36:03 -07003342 public String getSettingNameForDevice(int device) {
3343 String name = mVolumeIndexSettingName;
Eric Laurent948d3272014-05-16 15:18:45 -07003344 String suffix = AudioSystem.getOutputDeviceName(device);
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003345 if (suffix.isEmpty()) {
3346 return name;
3347 }
3348 return name + "_" + suffix;
Jean-Michel Trivi11a74a72009-10-27 17:39:30 -07003349 }
3350
Eric Laurentfdbee862014-05-12 15:26:12 -07003351 public void readSettings() {
3352 synchronized (VolumeStreamState.class) {
John Spurlockee5ad722015-03-03 16:17:21 -05003353 // force maximum volume on all streams if fixed volume property is set
3354 if (mUseFixedVolume) {
John Spurlock2bb02ec2015-03-02 13:13:06 -05003355 mIndexMap.put(AudioSystem.DEVICE_OUT_DEFAULT, mIndexMax);
Eric Laurentfdbee862014-05-12 15:26:12 -07003356 return;
3357 }
3358 // do not read system stream volume from settings: this stream is always aliased
3359 // to another stream type and its volume is never persisted. Values in settings can
3360 // only be stale values
3361 if ((mStreamType == AudioSystem.STREAM_SYSTEM) ||
3362 (mStreamType == AudioSystem.STREAM_SYSTEM_ENFORCED)) {
John Spurlock61560172015-02-06 19:46:04 -05003363 int index = 10 * AudioSystem.DEFAULT_STREAM_VOLUME[mStreamType];
Eric Laurentfdbee862014-05-12 15:26:12 -07003364 synchronized (mCameraSoundForced) {
3365 if (mCameraSoundForced) {
3366 index = mIndexMax;
3367 }
Eric Laurentdd45d012012-10-08 09:04:34 -07003368 }
John Spurlock2bb02ec2015-03-02 13:13:06 -05003369 mIndexMap.put(AudioSystem.DEVICE_OUT_DEFAULT, index);
Eric Laurentfdbee862014-05-12 15:26:12 -07003370 return;
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003371 }
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003372
Eric Laurentfdbee862014-05-12 15:26:12 -07003373 int remainingDevices = AudioSystem.DEVICE_OUT_ALL;
3374
3375 for (int i = 0; remainingDevices != 0; i++) {
3376 int device = (1 << i);
3377 if ((device & remainingDevices) == 0) {
3378 continue;
3379 }
3380 remainingDevices &= ~device;
3381
3382 // retrieve current volume for device
3383 String name = getSettingNameForDevice(device);
3384 // if no volume stored for current stream and device, use default volume if default
3385 // device, continue otherwise
3386 int defaultIndex = (device == AudioSystem.DEVICE_OUT_DEFAULT) ?
John Spurlock61560172015-02-06 19:46:04 -05003387 AudioSystem.DEFAULT_STREAM_VOLUME[mStreamType] : -1;
Eric Laurentfdbee862014-05-12 15:26:12 -07003388 int index = Settings.System.getIntForUser(
3389 mContentResolver, name, defaultIndex, UserHandle.USER_CURRENT);
3390 if (index == -1) {
3391 continue;
3392 }
3393
John Spurlock2bb02ec2015-03-02 13:13:06 -05003394 mIndexMap.put(device, getValidIndex(10 * index));
Eric Laurentdd45d012012-10-08 09:04:34 -07003395 }
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003396 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003397 }
3398
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07003399 // must be called while synchronized VolumeStreamState.class
3400 public void applyDeviceVolume_syncVSS(int device) {
Eric Laurent42b041e2013-03-29 11:36:03 -07003401 int index;
RoboErik4197cb62015-01-21 15:45:32 -08003402 if (mIsMuted) {
Eric Laurent42b041e2013-03-29 11:36:03 -07003403 index = 0;
Jean-Michel Triviba5270b2014-10-01 17:49:29 -07003404 } else if (((device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0 && mAvrcpAbsVolSupported)
3405 || ((device & mFullVolumeDevices) != 0)) {
Matthew Xiec9d1d5f2013-09-12 00:32:22 -07003406 index = (mIndexMax + 5)/10;
Eric Laurentcd772d02013-10-30 18:31:07 -07003407 } else {
Eric Laurent42b041e2013-03-29 11:36:03 -07003408 index = (getIndex(device) + 5)/10;
3409 }
3410 AudioSystem.setStreamVolumeIndex(mStreamType, index, device);
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003411 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003412
Eric Laurentfdbee862014-05-12 15:26:12 -07003413 public void applyAllVolumes() {
3414 synchronized (VolumeStreamState.class) {
3415 // apply default volume first: by convention this will reset all
3416 // devices volumes in audio policy manager to the supplied value
3417 int index;
RoboErik4197cb62015-01-21 15:45:32 -08003418 if (mIsMuted) {
Eric Laurentfdbee862014-05-12 15:26:12 -07003419 index = 0;
3420 } else {
3421 index = (getIndex(AudioSystem.DEVICE_OUT_DEFAULT) + 5)/10;
3422 }
3423 AudioSystem.setStreamVolumeIndex(mStreamType, index, AudioSystem.DEVICE_OUT_DEFAULT);
3424 // then apply device specific volumes
John Spurlock2bb02ec2015-03-02 13:13:06 -05003425 for (int i = 0; i < mIndexMap.size(); i++) {
3426 int device = mIndexMap.keyAt(i);
Eric Laurentfdbee862014-05-12 15:26:12 -07003427 if (device != AudioSystem.DEVICE_OUT_DEFAULT) {
RoboErik4197cb62015-01-21 15:45:32 -08003428 if (mIsMuted) {
Eric Laurentfdbee862014-05-12 15:26:12 -07003429 index = 0;
Jean-Michel Triviba5270b2014-10-01 17:49:29 -07003430 } else if (((device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0 &&
3431 mAvrcpAbsVolSupported)
3432 || ((device & mFullVolumeDevices) != 0))
3433 {
Eric Laurentfdbee862014-05-12 15:26:12 -07003434 index = (mIndexMax + 5)/10;
3435 } else {
John Spurlock2bb02ec2015-03-02 13:13:06 -05003436 index = (mIndexMap.valueAt(i) + 5)/10;
Eric Laurentfdbee862014-05-12 15:26:12 -07003437 }
3438 AudioSystem.setStreamVolumeIndex(mStreamType, index, device);
Eric Laurent42b041e2013-03-29 11:36:03 -07003439 }
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003440 }
3441 }
3442 }
3443
3444 public boolean adjustIndex(int deltaIndex, int device) {
Eric Laurent42b041e2013-03-29 11:36:03 -07003445 return setIndex(getIndex(device) + deltaIndex,
3446 device);
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003447 }
3448
Eric Laurentfdbee862014-05-12 15:26:12 -07003449 public boolean setIndex(int index, int device) {
John Spurlockf63860c2015-02-19 09:46:27 -05003450 boolean changed = false;
3451 int oldIndex;
Eric Laurentfdbee862014-05-12 15:26:12 -07003452 synchronized (VolumeStreamState.class) {
John Spurlockf63860c2015-02-19 09:46:27 -05003453 oldIndex = getIndex(device);
Eric Laurentfdbee862014-05-12 15:26:12 -07003454 index = getValidIndex(index);
3455 synchronized (mCameraSoundForced) {
3456 if ((mStreamType == AudioSystem.STREAM_SYSTEM_ENFORCED) && mCameraSoundForced) {
3457 index = mIndexMax;
Eric Laurenta553c252009-07-17 12:17:14 -07003458 }
3459 }
John Spurlock2bb02ec2015-03-02 13:13:06 -05003460 mIndexMap.put(device, index);
Eric Laurentfdbee862014-05-12 15:26:12 -07003461
John Spurlockf63860c2015-02-19 09:46:27 -05003462 changed = oldIndex != index;
3463 if (changed) {
Eric Laurentfdbee862014-05-12 15:26:12 -07003464 // Apply change to all streams using this one as alias
3465 // if changing volume of current device, also change volume of current
3466 // device on aliased stream
3467 boolean currentDevice = (device == getDeviceForStream(mStreamType));
3468 int numStreamTypes = AudioSystem.getNumStreamTypes();
3469 for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
3470 if (streamType != mStreamType &&
3471 mStreamVolumeAlias[streamType] == mStreamType) {
3472 int scaledIndex = rescaleIndex(index, mStreamType, streamType);
3473 mStreamStates[streamType].setIndex(scaledIndex,
3474 device);
3475 if (currentDevice) {
3476 mStreamStates[streamType].setIndex(scaledIndex,
3477 getDeviceForStream(streamType));
3478 }
3479 }
3480 }
Eric Laurentfdbee862014-05-12 15:26:12 -07003481 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003482 }
John Spurlockf63860c2015-02-19 09:46:27 -05003483 if (changed) {
3484 oldIndex = (oldIndex + 5) / 10;
3485 index = (index + 5) / 10;
3486 mVolumeChanged.putExtra(AudioManager.EXTRA_VOLUME_STREAM_VALUE, index);
3487 mVolumeChanged.putExtra(AudioManager.EXTRA_PREV_VOLUME_STREAM_VALUE, oldIndex);
3488 sendBroadcastToAll(mVolumeChanged);
3489 }
3490 return changed;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003491 }
3492
Eric Laurentfdbee862014-05-12 15:26:12 -07003493 public int getIndex(int device) {
3494 synchronized (VolumeStreamState.class) {
John Spurlock2bb02ec2015-03-02 13:13:06 -05003495 int index = mIndexMap.get(device, -1);
3496 if (index == -1) {
Eric Laurentfdbee862014-05-12 15:26:12 -07003497 // there is always an entry for AudioSystem.DEVICE_OUT_DEFAULT
John Spurlock2bb02ec2015-03-02 13:13:06 -05003498 index = mIndexMap.get(AudioSystem.DEVICE_OUT_DEFAULT);
Eric Laurentfdbee862014-05-12 15:26:12 -07003499 }
John Spurlock2bb02ec2015-03-02 13:13:06 -05003500 return index;
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003501 }
Eric Laurent5b4e6542010-03-19 20:02:21 -07003502 }
3503
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003504 public int getMaxIndex() {
Eric Laurenta553c252009-07-17 12:17:14 -07003505 return mIndexMax;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003506 }
3507
Eric Laurentfdbee862014-05-12 15:26:12 -07003508 public void setAllIndexes(VolumeStreamState srcStream) {
3509 synchronized (VolumeStreamState.class) {
3510 int srcStreamType = srcStream.getStreamType();
3511 // apply default device volume from source stream to all devices first in case
3512 // some devices are present in this stream state but not in source stream state
3513 int index = srcStream.getIndex(AudioSystem.DEVICE_OUT_DEFAULT);
Eric Laurent24e0d9b2013-10-03 18:15:07 -07003514 index = rescaleIndex(index, srcStreamType, mStreamType);
John Spurlock2bb02ec2015-03-02 13:13:06 -05003515 for (int i = 0; i < mIndexMap.size(); i++) {
3516 mIndexMap.put(mIndexMap.keyAt(i), index);
Eric Laurentfdbee862014-05-12 15:26:12 -07003517 }
3518 // Now apply actual volume for devices in source stream state
John Spurlock2bb02ec2015-03-02 13:13:06 -05003519 SparseIntArray srcMap = srcStream.mIndexMap;
3520 for (int i = 0; i < srcMap.size(); i++) {
3521 int device = srcMap.keyAt(i);
3522 index = srcMap.valueAt(i);
Eric Laurentfdbee862014-05-12 15:26:12 -07003523 index = rescaleIndex(index, srcStreamType, mStreamType);
Eric Laurent33902db2012-10-07 16:15:07 -07003524
Eric Laurentfdbee862014-05-12 15:26:12 -07003525 setIndex(index, device);
3526 }
Eric Laurent6d517662012-04-23 18:42:39 -07003527 }
3528 }
3529
Eric Laurentfdbee862014-05-12 15:26:12 -07003530 public void setAllIndexesToMax() {
3531 synchronized (VolumeStreamState.class) {
John Spurlock2bb02ec2015-03-02 13:13:06 -05003532 for (int i = 0; i < mIndexMap.size(); i++) {
3533 mIndexMap.put(mIndexMap.keyAt(i), mIndexMax);
Eric Laurentfdbee862014-05-12 15:26:12 -07003534 }
Eric Laurentdd45d012012-10-08 09:04:34 -07003535 }
Eric Laurentdd45d012012-10-08 09:04:34 -07003536 }
3537
RoboErik4197cb62015-01-21 15:45:32 -08003538 public void mute(boolean state) {
John Spurlock22b9ee12015-02-18 22:51:44 -05003539 boolean changed = false;
Eric Laurentfdbee862014-05-12 15:26:12 -07003540 synchronized (VolumeStreamState.class) {
RoboErik4197cb62015-01-21 15:45:32 -08003541 if (state != mIsMuted) {
John Spurlock22b9ee12015-02-18 22:51:44 -05003542 changed = true;
RoboErik4197cb62015-01-21 15:45:32 -08003543 mIsMuted = state;
John Spurlock22b9ee12015-02-18 22:51:44 -05003544
RoboErik4197cb62015-01-21 15:45:32 -08003545 // Set the new mute volume. This propagates the values to
3546 // the audio system, otherwise the volume won't be changed
3547 // at the lower level.
3548 sendMsg(mAudioHandler,
3549 MSG_SET_ALL_VOLUMES,
3550 SENDMSG_QUEUE,
3551 0,
3552 0,
3553 this, 0);
Eric Laurentfdbee862014-05-12 15:26:12 -07003554 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003555 }
John Spurlock22b9ee12015-02-18 22:51:44 -05003556 if (changed) {
3557 // Stream mute changed, fire the intent.
3558 Intent intent = new Intent(AudioManager.STREAM_MUTE_CHANGED_ACTION);
3559 intent.putExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, mStreamType);
3560 intent.putExtra(AudioManager.EXTRA_STREAM_VOLUME_MUTED, state);
3561 sendBroadcastToAll(intent);
3562 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003563 }
3564
Eric Laurent6d517662012-04-23 18:42:39 -07003565 public int getStreamType() {
3566 return mStreamType;
3567 }
3568
Eric Laurent212532b2014-07-21 15:43:18 -07003569 public void checkFixedVolumeDevices() {
3570 synchronized (VolumeStreamState.class) {
3571 // ignore settings for fixed volume devices: volume should always be at max or 0
3572 if (mStreamVolumeAlias[mStreamType] == AudioSystem.STREAM_MUSIC) {
John Spurlock2bb02ec2015-03-02 13:13:06 -05003573 for (int i = 0; i < mIndexMap.size(); i++) {
3574 int device = mIndexMap.keyAt(i);
3575 int index = mIndexMap.valueAt(i);
Jean-Michel Triviba5270b2014-10-01 17:49:29 -07003576 if (((device & mFullVolumeDevices) != 0)
3577 || (((device & mFixedVolumeDevices) != 0) && index != 0)) {
John Spurlock2bb02ec2015-03-02 13:13:06 -05003578 mIndexMap.put(device, mIndexMax);
Eric Laurent212532b2014-07-21 15:43:18 -07003579 }
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07003580 applyDeviceVolume_syncVSS(device);
Eric Laurent212532b2014-07-21 15:43:18 -07003581 }
3582 }
3583 }
3584 }
3585
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003586 private int getValidIndex(int index) {
3587 if (index < 0) {
3588 return 0;
John Spurlockee5ad722015-03-03 16:17:21 -05003589 } else if (mUseFixedVolume || index > mIndexMax) {
Eric Laurenta553c252009-07-17 12:17:14 -07003590 return mIndexMax;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003591 }
3592
3593 return index;
3594 }
3595
Eric Laurentbffc3d12012-05-07 17:43:49 -07003596 private void dump(PrintWriter pw) {
RoboErik4197cb62015-01-21 15:45:32 -08003597 pw.print(" Muted: ");
3598 pw.println(mIsMuted);
John Spurlock2b29bc42014-08-26 16:40:35 -04003599 pw.print(" Max: ");
3600 pw.println((mIndexMax + 5) / 10);
Eric Laurentbffc3d12012-05-07 17:43:49 -07003601 pw.print(" Current: ");
John Spurlock2bb02ec2015-03-02 13:13:06 -05003602 for (int i = 0; i < mIndexMap.size(); i++) {
3603 if (i > 0) {
3604 pw.print(", ");
3605 }
3606 final int device = mIndexMap.keyAt(i);
John Spurlock2b29bc42014-08-26 16:40:35 -04003607 pw.print(Integer.toHexString(device));
3608 final String deviceName = device == AudioSystem.DEVICE_OUT_DEFAULT ? "default"
3609 : AudioSystem.getOutputDeviceName(device);
3610 if (!deviceName.isEmpty()) {
3611 pw.print(" (");
3612 pw.print(deviceName);
3613 pw.print(")");
3614 }
3615 pw.print(": ");
John Spurlock2bb02ec2015-03-02 13:13:06 -05003616 final int index = (mIndexMap.valueAt(i) + 5) / 10;
John Spurlock2b29bc42014-08-26 16:40:35 -04003617 pw.print(index);
Eric Laurentbffc3d12012-05-07 17:43:49 -07003618 }
John Spurlockb32fc972015-03-05 13:58:00 -05003619 pw.println();
3620 pw.print(" Devices: ");
3621 final int devices = AudioSystem.getDevicesForStream(mStreamType);
3622 int device, i = 0, n = 0;
3623 while ((device = 1 << i) <= AudioSystem.DEVICE_OUT_DEFAULT) {
3624 if ((devices & device) != 0) {
3625 if (n++ > 0) {
3626 pw.print(", ");
3627 }
3628 pw.print(AudioSystem.getOutputDeviceName(device));
3629 }
3630 i++;
3631 }
Eric Laurentbffc3d12012-05-07 17:43:49 -07003632 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003633 }
3634
3635 /** Thread that handles native AudioSystem control. */
3636 private class AudioSystemThread extends Thread {
3637 AudioSystemThread() {
3638 super("AudioService");
3639 }
3640
3641 @Override
3642 public void run() {
3643 // Set this thread up so the handler will work on it
3644 Looper.prepare();
3645
3646 synchronized(AudioService.this) {
3647 mAudioHandler = new AudioHandler();
3648
3649 // Notify that the handler has been created
3650 AudioService.this.notify();
3651 }
3652
3653 // Listen for volume change requests that are set by VolumePanel
3654 Looper.loop();
3655 }
3656 }
3657
3658 /** Handles internal volume messages in separate volume thread. */
3659 private class AudioHandler extends Handler {
3660
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003661 private void setDeviceVolume(VolumeStreamState streamState, int device) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003662
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07003663 synchronized (VolumeStreamState.class) {
3664 // Apply volume
3665 streamState.applyDeviceVolume_syncVSS(device);
Eric Laurenta553c252009-07-17 12:17:14 -07003666
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07003667 // Apply change to all streams using this one as alias
3668 int numStreamTypes = AudioSystem.getNumStreamTypes();
3669 for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
3670 if (streamType != streamState.mStreamType &&
3671 mStreamVolumeAlias[streamType] == streamState.mStreamType) {
3672 // Make sure volume is also maxed out on A2DP device for aliased stream
3673 // that may have a different device selected
3674 int streamDevice = getDeviceForStream(streamType);
3675 if ((device != streamDevice) && mAvrcpAbsVolSupported &&
3676 ((device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0)) {
3677 mStreamStates[streamType].applyDeviceVolume_syncVSS(device);
3678 }
3679 mStreamStates[streamType].applyDeviceVolume_syncVSS(streamDevice);
Eric Laurentcd772d02013-10-30 18:31:07 -07003680 }
Eric Laurenta553c252009-07-17 12:17:14 -07003681 }
3682 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003683 // Post a persist volume msg
Eric Laurentafbb0472011-12-15 09:04:23 -08003684 sendMsg(mAudioHandler,
3685 MSG_PERSIST_VOLUME,
Eric Laurent98ad9b92012-02-15 17:21:37 -08003686 SENDMSG_QUEUE,
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003687 device,
Eric Laurent42b041e2013-03-29 11:36:03 -07003688 0,
Eric Laurentafbb0472011-12-15 09:04:23 -08003689 streamState,
3690 PERSIST_DELAY);
3691
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003692 }
3693
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003694 private void setAllVolumes(VolumeStreamState streamState) {
3695
3696 // Apply volume
3697 streamState.applyAllVolumes();
3698
3699 // Apply change to all streams using this one as alias
3700 int numStreamTypes = AudioSystem.getNumStreamTypes();
3701 for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
3702 if (streamType != streamState.mStreamType &&
Eric Laurent6d517662012-04-23 18:42:39 -07003703 mStreamVolumeAlias[streamType] == streamState.mStreamType) {
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003704 mStreamStates[streamType].applyAllVolumes();
3705 }
3706 }
3707 }
3708
Eric Laurent42b041e2013-03-29 11:36:03 -07003709 private void persistVolume(VolumeStreamState streamState, int device) {
Eric Laurent83a017b2013-03-19 18:15:31 -07003710 if (mUseFixedVolume) {
3711 return;
3712 }
Eric Laurent212532b2014-07-21 15:43:18 -07003713 if (isPlatformTelevision() && (streamState.mStreamType != AudioSystem.STREAM_MUSIC)) {
3714 return;
3715 }
Eric Laurent42b041e2013-03-29 11:36:03 -07003716 System.putIntForUser(mContentResolver,
3717 streamState.getSettingNameForDevice(device),
3718 (streamState.getIndex(device) + 5)/ 10,
3719 UserHandle.USER_CURRENT);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003720 }
3721
Glenn Kastenba195eb2011-12-13 09:30:40 -08003722 private void persistRingerMode(int ringerMode) {
Eric Laurent83a017b2013-03-19 18:15:31 -07003723 if (mUseFixedVolume) {
3724 return;
3725 }
Jeff Sharkey8d9a1f62012-10-18 15:38:14 -07003726 Settings.Global.putInt(mContentResolver, Settings.Global.MODE_RINGER, ringerMode);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003727 }
3728
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07003729 private boolean onLoadSoundEffects() {
3730 int status;
3731
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003732 synchronized (mSoundEffectsLock) {
Eric Laurent4a5eeb92014-05-06 10:49:04 -07003733 if (!mSystemReady) {
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07003734 Log.w(TAG, "onLoadSoundEffects() called before boot complete");
3735 return false;
3736 }
3737
3738 if (mSoundPool != null) {
3739 return true;
3740 }
3741
3742 loadTouchSoundAssets();
3743
Jean-Michel Trivi55a30c42014-07-20 17:56:11 -07003744 mSoundPool = new SoundPool.Builder()
3745 .setMaxStreams(NUM_SOUNDPOOL_CHANNELS)
3746 .setAudioAttributes(new AudioAttributes.Builder()
3747 .setUsage(AudioAttributes.USAGE_ASSISTANCE_SONIFICATION)
3748 .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
3749 .build())
3750 .build();
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07003751 mSoundPoolCallBack = null;
3752 mSoundPoolListenerThread = new SoundPoolListenerThread();
3753 mSoundPoolListenerThread.start();
3754 int attempts = 3;
3755 while ((mSoundPoolCallBack == null) && (attempts-- > 0)) {
3756 try {
3757 // Wait for mSoundPoolCallBack to be set by the other thread
Glenn Kasten167d1a22013-07-23 16:24:41 -07003758 mSoundEffectsLock.wait(SOUND_EFFECTS_LOAD_TIMEOUT_MS);
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07003759 } catch (InterruptedException e) {
3760 Log.w(TAG, "Interrupted while waiting sound pool listener thread.");
3761 }
3762 }
3763
3764 if (mSoundPoolCallBack == null) {
3765 Log.w(TAG, "onLoadSoundEffects() SoundPool listener or thread creation error");
3766 if (mSoundPoolLooper != null) {
3767 mSoundPoolLooper.quit();
3768 mSoundPoolLooper = null;
3769 }
3770 mSoundPoolListenerThread = null;
3771 mSoundPool.release();
3772 mSoundPool = null;
3773 return false;
3774 }
3775 /*
3776 * poolId table: The value -1 in this table indicates that corresponding
3777 * file (same index in SOUND_EFFECT_FILES[] has not been loaded.
3778 * Once loaded, the value in poolId is the sample ID and the same
3779 * sample can be reused for another effect using the same file.
3780 */
3781 int[] poolId = new int[SOUND_EFFECT_FILES.size()];
3782 for (int fileIdx = 0; fileIdx < SOUND_EFFECT_FILES.size(); fileIdx++) {
3783 poolId[fileIdx] = -1;
3784 }
3785 /*
3786 * Effects whose value in SOUND_EFFECT_FILES_MAP[effect][1] is -1 must be loaded.
3787 * If load succeeds, value in SOUND_EFFECT_FILES_MAP[effect][1] is > 0:
3788 * this indicates we have a valid sample loaded for this effect.
3789 */
3790
3791 int numSamples = 0;
3792 for (int effect = 0; effect < AudioManager.NUM_SOUND_EFFECTS; effect++) {
3793 // Do not load sample if this effect uses the MediaPlayer
3794 if (SOUND_EFFECT_FILES_MAP[effect][1] == 0) {
3795 continue;
3796 }
3797 if (poolId[SOUND_EFFECT_FILES_MAP[effect][0]] == -1) {
3798 String filePath = Environment.getRootDirectory()
3799 + SOUND_EFFECTS_PATH
3800 + SOUND_EFFECT_FILES.get(SOUND_EFFECT_FILES_MAP[effect][0]);
3801 int sampleId = mSoundPool.load(filePath, 0);
3802 if (sampleId <= 0) {
3803 Log.w(TAG, "Soundpool could not load file: "+filePath);
3804 } else {
3805 SOUND_EFFECT_FILES_MAP[effect][1] = sampleId;
3806 poolId[SOUND_EFFECT_FILES_MAP[effect][0]] = sampleId;
3807 numSamples++;
3808 }
3809 } else {
3810 SOUND_EFFECT_FILES_MAP[effect][1] =
3811 poolId[SOUND_EFFECT_FILES_MAP[effect][0]];
3812 }
3813 }
3814 // wait for all samples to be loaded
3815 if (numSamples > 0) {
3816 mSoundPoolCallBack.setSamples(poolId);
3817
3818 attempts = 3;
3819 status = 1;
3820 while ((status == 1) && (attempts-- > 0)) {
3821 try {
Glenn Kasten167d1a22013-07-23 16:24:41 -07003822 mSoundEffectsLock.wait(SOUND_EFFECTS_LOAD_TIMEOUT_MS);
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07003823 status = mSoundPoolCallBack.status();
3824 } catch (InterruptedException e) {
3825 Log.w(TAG, "Interrupted while waiting sound pool callback.");
3826 }
3827 }
3828 } else {
3829 status = -1;
3830 }
3831
3832 if (mSoundPoolLooper != null) {
3833 mSoundPoolLooper.quit();
3834 mSoundPoolLooper = null;
3835 }
3836 mSoundPoolListenerThread = null;
3837 if (status != 0) {
3838 Log.w(TAG,
3839 "onLoadSoundEffects(), Error "+status+ " while loading samples");
3840 for (int effect = 0; effect < AudioManager.NUM_SOUND_EFFECTS; effect++) {
3841 if (SOUND_EFFECT_FILES_MAP[effect][1] > 0) {
3842 SOUND_EFFECT_FILES_MAP[effect][1] = -1;
3843 }
3844 }
3845
3846 mSoundPool.release();
3847 mSoundPool = null;
3848 }
3849 }
3850 return (status == 0);
3851 }
3852
3853 /**
3854 * Unloads samples from the sound pool.
3855 * This method can be called to free some memory when
3856 * sound effects are disabled.
3857 */
3858 private void onUnloadSoundEffects() {
3859 synchronized (mSoundEffectsLock) {
3860 if (mSoundPool == null) {
3861 return;
3862 }
3863
3864 int[] poolId = new int[SOUND_EFFECT_FILES.size()];
3865 for (int fileIdx = 0; fileIdx < SOUND_EFFECT_FILES.size(); fileIdx++) {
3866 poolId[fileIdx] = 0;
3867 }
3868
3869 for (int effect = 0; effect < AudioManager.NUM_SOUND_EFFECTS; effect++) {
3870 if (SOUND_EFFECT_FILES_MAP[effect][1] <= 0) {
3871 continue;
3872 }
3873 if (poolId[SOUND_EFFECT_FILES_MAP[effect][0]] == 0) {
3874 mSoundPool.unload(SOUND_EFFECT_FILES_MAP[effect][1]);
3875 SOUND_EFFECT_FILES_MAP[effect][1] = -1;
3876 poolId[SOUND_EFFECT_FILES_MAP[effect][0]] = -1;
3877 }
3878 }
3879 mSoundPool.release();
3880 mSoundPool = null;
3881 }
3882 }
3883
3884 private void onPlaySoundEffect(int effectType, int volume) {
3885 synchronized (mSoundEffectsLock) {
3886
3887 onLoadSoundEffects();
3888
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003889 if (mSoundPool == null) {
3890 return;
3891 }
Eric Laurenta2ef57d2009-09-28 04:46:10 -07003892 float volFloat;
Eric Laurent25101b02011-02-02 09:33:30 -08003893 // use default if volume is not specified by caller
Eric Laurenta2ef57d2009-09-28 04:46:10 -07003894 if (volume < 0) {
Jean-Michel Trivif2b0c112012-07-09 11:59:11 -07003895 volFloat = (float)Math.pow(10, (float)sSoundEffectVolumeDb/20);
Eric Laurenta2ef57d2009-09-28 04:46:10 -07003896 } else {
RoboErik8a2cfc32014-05-16 11:19:38 -07003897 volFloat = volume / 1000.0f;
Eric Laurenta2ef57d2009-09-28 04:46:10 -07003898 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003899
3900 if (SOUND_EFFECT_FILES_MAP[effectType][1] > 0) {
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07003901 mSoundPool.play(SOUND_EFFECT_FILES_MAP[effectType][1],
3902 volFloat, volFloat, 0, 0, 1.0f);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003903 } else {
3904 MediaPlayer mediaPlayer = new MediaPlayer();
Glenn Kasten62b9aec2011-11-07 11:10:16 -08003905 try {
Eric Laurente78fced2013-03-15 16:03:47 -07003906 String filePath = Environment.getRootDirectory() + SOUND_EFFECTS_PATH +
3907 SOUND_EFFECT_FILES.get(SOUND_EFFECT_FILES_MAP[effectType][0]);
Glenn Kasten62b9aec2011-11-07 11:10:16 -08003908 mediaPlayer.setDataSource(filePath);
3909 mediaPlayer.setAudioStreamType(AudioSystem.STREAM_SYSTEM);
3910 mediaPlayer.prepare();
Glenn Kasten068225d2012-02-27 16:21:04 -08003911 mediaPlayer.setVolume(volFloat);
Glenn Kasten62b9aec2011-11-07 11:10:16 -08003912 mediaPlayer.setOnCompletionListener(new OnCompletionListener() {
3913 public void onCompletion(MediaPlayer mp) {
3914 cleanupPlayer(mp);
3915 }
3916 });
3917 mediaPlayer.setOnErrorListener(new OnErrorListener() {
3918 public boolean onError(MediaPlayer mp, int what, int extra) {
3919 cleanupPlayer(mp);
3920 return true;
3921 }
3922 });
3923 mediaPlayer.start();
3924 } catch (IOException ex) {
3925 Log.w(TAG, "MediaPlayer IOException: "+ex);
3926 } catch (IllegalArgumentException ex) {
3927 Log.w(TAG, "MediaPlayer IllegalArgumentException: "+ex);
3928 } catch (IllegalStateException ex) {
3929 Log.w(TAG, "MediaPlayer IllegalStateException: "+ex);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003930 }
3931 }
3932 }
3933 }
3934
3935 private void cleanupPlayer(MediaPlayer mp) {
3936 if (mp != null) {
3937 try {
3938 mp.stop();
3939 mp.release();
3940 } catch (IllegalStateException ex) {
3941 Log.w(TAG, "MediaPlayer IllegalStateException: "+ex);
3942 }
3943 }
3944 }
3945
Eric Laurentfa640152011-03-12 15:59:51 -08003946 private void setForceUse(int usage, int config) {
Jean-Michel Trivi7e2f3712015-01-12 11:01:55 -08003947 synchronized (mConnectedDevices) {
3948 setForceUseInt_SyncDevices(usage, config);
3949 }
Eric Laurentfa640152011-03-12 15:59:51 -08003950 }
3951
Eric Laurent05274f32012-11-29 12:48:18 -08003952 private void onPersistSafeVolumeState(int state) {
3953 Settings.Global.putInt(mContentResolver,
3954 Settings.Global.AUDIO_SAFE_VOLUME_STATE,
3955 state);
3956 }
3957
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003958 @Override
3959 public void handleMessage(Message msg) {
Eric Laurentafbb0472011-12-15 09:04:23 -08003960 switch (msg.what) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003961
Eric Laurent9bc8358d2011-11-18 16:43:31 -08003962 case MSG_SET_DEVICE_VOLUME:
3963 setDeviceVolume((VolumeStreamState) msg.obj, msg.arg1);
3964 break;
3965
3966 case MSG_SET_ALL_VOLUMES:
3967 setAllVolumes((VolumeStreamState) msg.obj);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003968 break;
3969
3970 case MSG_PERSIST_VOLUME:
Eric Laurent42b041e2013-03-29 11:36:03 -07003971 persistVolume((VolumeStreamState) msg.obj, msg.arg1);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003972 break;
3973
Justin Koh57978ed2012-04-03 17:37:58 -07003974 case MSG_PERSIST_MASTER_VOLUME_MUTE:
Eric Laurent83a017b2013-03-19 18:15:31 -07003975 if (mUseFixedVolume) {
3976 return;
3977 }
Eric Laurentbc0fab1f2012-09-19 11:24:41 -07003978 Settings.System.putIntForUser(mContentResolver,
3979 Settings.System.VOLUME_MASTER_MUTE,
3980 msg.arg1,
Julia Reynoldsb53453f2014-08-22 11:42:43 -04003981 msg.arg2);
Justin Koh57978ed2012-04-03 17:37:58 -07003982 break;
3983
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003984 case MSG_PERSIST_RINGER_MODE:
Glenn Kastenba195eb2011-12-13 09:30:40 -08003985 // note that the value persisted is the current ringer mode, not the
3986 // value of ringer mode as of the time the request was made to persist
John Spurlock661f2cf2014-11-17 10:29:10 -05003987 persistRingerMode(getRingerModeInternal());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003988 break;
3989
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003990 case MSG_MEDIA_SERVER_DIED:
Eric Laurenteb4b8a22014-07-21 13:10:07 -07003991 if (!mSystemReady ||
3992 (AudioSystem.checkAudioFlinger() != AudioSystem.AUDIO_STATUS_OK)) {
Eric Laurent89e74ba2009-09-30 18:26:36 -07003993 Log.e(TAG, "Media server died.");
Eric Laurentafbb0472011-12-15 09:04:23 -08003994 sendMsg(mAudioHandler, MSG_MEDIA_SERVER_DIED, SENDMSG_NOOP, 0, 0,
Eric Laurent89e74ba2009-09-30 18:26:36 -07003995 null, 500);
Eric Laurentdfb881f2013-07-18 14:41:39 -07003996 break;
Eric Laurent89e74ba2009-09-30 18:26:36 -07003997 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08003998 Log.e(TAG, "Media server started.");
Eric Laurentdfb881f2013-07-18 14:41:39 -07003999
Eric Laurent3c652ca2010-06-21 20:46:26 -07004000 // indicate to audio HAL that we start the reconfiguration phase after a media
4001 // server crash
Eric Laurentdfb881f2013-07-18 14:41:39 -07004002 // Note that we only execute this when the media server
Eric Laurent3c652ca2010-06-21 20:46:26 -07004003 // process restarts after a crash, not the first time it is started.
4004 AudioSystem.setParameters("restarting=true");
4005
Glenn Kastenfd116ad2013-07-12 17:10:39 -07004006 readAndSetLowRamDevice();
4007
Eric Laurentc42ac9d2009-07-29 08:53:03 -07004008 // Restore device connection states
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004009 synchronized (mConnectedDevices) {
4010 Set set = mConnectedDevices.entrySet();
4011 Iterator i = set.iterator();
Eric Laurent9bc8358d2011-11-18 16:43:31 -08004012 while (i.hasNext()) {
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004013 Map.Entry device = (Map.Entry)i.next();
4014 AudioSystem.setDeviceConnectionState(
4015 ((Integer)device.getKey()).intValue(),
4016 AudioSystem.DEVICE_STATE_AVAILABLE,
Paul McLean10804eb2015-01-28 11:16:35 -08004017 (String)device.getValue(),
4018 "unknown-device");
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004019 }
Eric Laurentc42ac9d2009-07-29 08:53:03 -07004020 }
Eric Laurentc42ac9d2009-07-29 08:53:03 -07004021 // Restore call state
4022 AudioSystem.setPhoneState(mMode);
4023
Eric Laurentd5603c12009-08-06 08:49:39 -07004024 // Restore forced usage for communcations and record
Eric Laurentc42ac9d2009-07-29 08:53:03 -07004025 AudioSystem.setForceUse(AudioSystem.FOR_COMMUNICATION, mForcedUseForComm);
Eric Laurentd5603c12009-08-06 08:49:39 -07004026 AudioSystem.setForceUse(AudioSystem.FOR_RECORD, mForcedUseForComm);
Eric Laurentdd45d012012-10-08 09:04:34 -07004027 AudioSystem.setForceUse(AudioSystem.FOR_SYSTEM, mCameraSoundForced ?
4028 AudioSystem.FORCE_SYSTEM_ENFORCED : AudioSystem.FORCE_NONE);
Eric Laurentc42ac9d2009-07-29 08:53:03 -07004029
Eric Laurenta553c252009-07-17 12:17:14 -07004030 // Restore stream volumes
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004031 int numStreamTypes = AudioSystem.getNumStreamTypes();
4032 for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004033 VolumeStreamState streamState = mStreamStates[streamType];
Eric Laurentc42ac9d2009-07-29 08:53:03 -07004034 AudioSystem.initStreamVolume(streamType, 0, (streamState.mIndexMax + 5) / 10);
Eric Laurent9bc8358d2011-11-18 16:43:31 -08004035
4036 streamState.applyAllVolumes();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004037 }
Eric Laurentc42ac9d2009-07-29 08:53:03 -07004038
4039 // Restore ringer mode
John Spurlock661f2cf2014-11-17 10:29:10 -05004040 setRingerModeInt(getRingerModeInternal(), false);
Eric Laurent3c652ca2010-06-21 20:46:26 -07004041
Jean-Michel Trivif26f0172012-04-25 16:23:20 -07004042 // Reset device orientation (if monitored for this device)
Eric Laurentd640bd32012-09-28 18:01:48 -07004043 if (mMonitorOrientation) {
Jean-Michel Trivif26f0172012-04-25 16:23:20 -07004044 setOrientationForAudioSystem();
4045 }
Jean-Michel Trivibb6f8712013-05-23 15:02:41 -07004046 if (mMonitorRotation) {
4047 setRotationForAudioSystem();
4048 }
Jean-Michel Trivif26f0172012-04-25 16:23:20 -07004049
Eric Laurent78472112012-05-21 08:57:21 -07004050 synchronized (mBluetoothA2dpEnabledLock) {
4051 AudioSystem.setForceUse(AudioSystem.FOR_MEDIA,
4052 mBluetoothA2dpEnabled ?
4053 AudioSystem.FORCE_NONE : AudioSystem.FORCE_NO_BT_A2DP);
4054 }
Eric Laurentbff5ca52012-11-02 16:48:26 -07004055
4056 synchronized (mSettingsLock) {
4057 AudioSystem.setForceUse(AudioSystem.FOR_DOCK,
4058 mDockAudioMediaEnabled ?
4059 AudioSystem.FORCE_ANALOG_DOCK : AudioSystem.FORCE_NONE);
4060 }
Eric Laurent212532b2014-07-21 15:43:18 -07004061 if (mHdmiManager != null) {
4062 synchronized (mHdmiManager) {
4063 if (mHdmiTvClient != null) {
4064 setHdmiSystemAudioSupported(mHdmiSystemAudioSupported);
4065 }
4066 }
Jungshik Jang6f34f5a2014-07-08 21:17:29 +09004067 }
Eric Laurent7f5eb9f2014-12-01 19:36:30 -08004068
4069 synchronized (mAudioPolicies) {
4070 for(AudioPolicyProxy policy : mAudioPolicies.values()) {
4071 policy.connectMixes();
4072 }
4073 }
4074
Eric Laurent3c652ca2010-06-21 20:46:26 -07004075 // indicate the end of reconfiguration phase to audio HAL
4076 AudioSystem.setParameters("restarting=false");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004077 break;
4078
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07004079 case MSG_UNLOAD_SOUND_EFFECTS:
4080 onUnloadSoundEffects();
4081 break;
4082
Eric Laurent117b7bb2011-01-16 17:07:27 -08004083 case MSG_LOAD_SOUND_EFFECTS:
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07004084 //FIXME: onLoadSoundEffects() should be executed in a separate thread as it
4085 // can take several dozens of milliseconds to complete
4086 boolean loaded = onLoadSoundEffects();
4087 if (msg.obj != null) {
4088 LoadSoundEffectReply reply = (LoadSoundEffectReply)msg.obj;
4089 synchronized (reply) {
4090 reply.mStatus = loaded ? 0 : -1;
4091 reply.notify();
4092 }
4093 }
Eric Laurent117b7bb2011-01-16 17:07:27 -08004094 break;
4095
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004096 case MSG_PLAY_SOUND_EFFECT:
Eric Laurent5d3eb44a2013-03-21 15:35:10 -07004097 onPlaySoundEffect(msg.arg1, msg.arg2);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004098 break;
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07004099
4100 case MSG_BTA2DP_DOCK_TIMEOUT:
4101 // msg.obj == address of BTA2DP device
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004102 synchronized (mConnectedDevices) {
4103 makeA2dpDeviceUnavailableNow( (String) msg.obj );
4104 }
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07004105 break;
Eric Laurentfa640152011-03-12 15:59:51 -08004106
4107 case MSG_SET_FORCE_USE:
Eric Laurentc390bed2012-07-03 12:24:05 -07004108 case MSG_SET_FORCE_BT_A2DP_USE:
Eric Laurentfa640152011-03-12 15:59:51 -08004109 setForceUse(msg.arg1, msg.arg2);
4110 break;
Jean-Michel Trivid589fea2011-04-15 11:28:10 -07004111
Eric Laurentdc03c612011-04-01 10:59:41 -07004112 case MSG_BT_HEADSET_CNCT_FAILED:
4113 resetBluetoothSco();
4114 break;
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004115
4116 case MSG_SET_WIRED_DEVICE_CONNECTION_STATE:
Paul McLean10804eb2015-01-28 11:16:35 -08004117 { WiredDeviceConnectionState connectState =
4118 (WiredDeviceConnectionState)msg.obj;
4119 onSetWiredDeviceConnectionState(connectState.mType, connectState.mState,
4120 connectState.mAddress, connectState.mName);
4121 mAudioEventWakeLock.release();
4122 }
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004123 break;
4124
Mike Lockwood0a40ec22014-05-21 10:08:50 -07004125 case MSG_SET_A2DP_SRC_CONNECTION_STATE:
4126 onSetA2dpSourceConnectionState((BluetoothDevice)msg.obj, msg.arg1);
4127 mAudioEventWakeLock.release();
4128 break;
4129
4130 case MSG_SET_A2DP_SINK_CONNECTION_STATE:
4131 onSetA2dpSinkConnectionState((BluetoothDevice)msg.obj, msg.arg1);
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -07004132 mAudioEventWakeLock.release();
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004133 break;
Dianne Hackborn632ca412012-06-14 19:34:10 -07004134
4135 case MSG_REPORT_NEW_ROUTES: {
4136 int N = mRoutesObservers.beginBroadcast();
4137 if (N > 0) {
4138 AudioRoutesInfo routes;
4139 synchronized (mCurAudioRoutes) {
4140 routes = new AudioRoutesInfo(mCurAudioRoutes);
4141 }
4142 while (N > 0) {
4143 N--;
4144 IAudioRoutesObserver obs = mRoutesObservers.getBroadcastItem(N);
4145 try {
4146 obs.dispatchAudioRoutesChanged(routes);
4147 } catch (RemoteException e) {
4148 }
4149 }
4150 }
4151 mRoutesObservers.finishBroadcast();
4152 break;
4153 }
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07004154
Eric Laurentc34dcc12012-09-10 13:51:52 -07004155 case MSG_CHECK_MUSIC_ACTIVE:
4156 onCheckMusicActive();
4157 break;
Eric Laurent5bfaeae2012-09-21 18:44:48 -07004158
4159 case MSG_BROADCAST_AUDIO_BECOMING_NOISY:
4160 onSendBecomingNoisyIntent();
4161 break;
Eric Laurentd640bd32012-09-28 18:01:48 -07004162
4163 case MSG_CONFIGURE_SAFE_MEDIA_VOLUME_FORCED:
4164 case MSG_CONFIGURE_SAFE_MEDIA_VOLUME:
4165 onConfigureSafeVolume((msg.what == MSG_CONFIGURE_SAFE_MEDIA_VOLUME_FORCED));
4166 break;
Eric Laurent05274f32012-11-29 12:48:18 -08004167 case MSG_PERSIST_SAFE_VOLUME_STATE:
4168 onPersistSafeVolumeState(msg.arg1);
4169 break;
Jean-Michel Trivia578c482012-12-28 11:19:49 -08004170
Eric Laurent2a57ca92013-03-07 17:29:27 -08004171 case MSG_BROADCAST_BT_CONNECTION_STATE:
4172 onBroadcastScoConnectionState(msg.arg1);
4173 break;
Eric Laurent4a5eeb92014-05-06 10:49:04 -07004174
4175 case MSG_SYSTEM_READY:
4176 onSystemReady();
4177 break;
John Spurlockaa5ee4d2014-07-25 13:05:12 -04004178
4179 case MSG_PERSIST_MUSIC_ACTIVE_MS:
4180 final int musicActiveMs = msg.arg1;
4181 Settings.Secure.putIntForUser(mContentResolver,
4182 Settings.Secure.UNSAFE_VOLUME_MUSIC_ACTIVE_MS, musicActiveMs,
4183 UserHandle.USER_CURRENT);
4184 break;
Julia Reynoldsb53453f2014-08-22 11:42:43 -04004185 case MSG_PERSIST_MICROPHONE_MUTE:
4186 Settings.System.putIntForUser(mContentResolver,
4187 Settings.System.MICROPHONE_MUTE,
4188 msg.arg1,
4189 msg.arg2);
4190 break;
RoboErik5452e252015-02-06 15:33:53 -08004191 case MSG_UNMUTE_STREAM:
4192 onUnmuteStream(msg.arg1, msg.arg2);
4193 break;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08004194 }
4195 }
4196 }
4197
Jason Parekhb1096152009-03-24 17:48:25 -07004198 private class SettingsObserver extends ContentObserver {
Eric Laurenta553c252009-07-17 12:17:14 -07004199
Jason Parekhb1096152009-03-24 17:48:25 -07004200 SettingsObserver() {
4201 super(new Handler());
4202 mContentResolver.registerContentObserver(Settings.System.getUriFor(
4203 Settings.System.MODE_RINGER_STREAMS_AFFECTED), false, this);
Eric Laurent7ee1e4f2012-10-26 18:11:21 -07004204 mContentResolver.registerContentObserver(Settings.Global.getUriFor(
4205 Settings.Global.DOCK_AUDIO_MEDIA_ENABLED), false, this);
Jason Parekhb1096152009-03-24 17:48:25 -07004206 }
4207
4208 @Override
4209 public void onChange(boolean selfChange) {
4210 super.onChange(selfChange);
Glenn Kastenba195eb2011-12-13 09:30:40 -08004211 // FIXME This synchronized is not necessary if mSettingsLock only protects mRingerMode.
4212 // However there appear to be some missing locks around mRingerModeMutedStreams
4213 // and mRingerModeAffectedStreams, so will leave this synchronized for now.
4214 // mRingerModeMutedStreams and mMuteAffectedStreams are safe (only accessed once).
Eric Laurenta553c252009-07-17 12:17:14 -07004215 synchronized (mSettingsLock) {
Eric Laurent24e0d9b2013-10-03 18:15:07 -07004216 if (updateRingerModeAffectedStreams()) {
Eric Laurenta553c252009-07-17 12:17:14 -07004217 /*
4218 * Ensure all stream types that should be affected by ringer mode
4219 * are in the proper state.
4220 */
John Spurlock661f2cf2014-11-17 10:29:10 -05004221 setRingerModeInt(getRingerModeInternal(), false);
Eric Laurenta553c252009-07-17 12:17:14 -07004222 }
Eric Laurent7ee1e4f2012-10-26 18:11:21 -07004223 readDockAudioSettings(mContentResolver);
Eric Laurenta553c252009-07-17 12:17:14 -07004224 }
Jason Parekhb1096152009-03-24 17:48:25 -07004225 }
Jason Parekhb1096152009-03-24 17:48:25 -07004226 }
Eric Laurenta553c252009-07-17 12:17:14 -07004227
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004228 // must be called synchronized on mConnectedDevices
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07004229 private void makeA2dpDeviceAvailable(String address) {
Eric Laurent78472112012-05-21 08:57:21 -07004230 // enable A2DP before notifying A2DP connection to avoid unecessary processing in
4231 // audio policy manager
Matthew Xiec9d1d5f2013-09-12 00:32:22 -07004232 VolumeStreamState streamState = mStreamStates[AudioSystem.STREAM_MUSIC];
4233 sendMsg(mAudioHandler, MSG_SET_DEVICE_VOLUME, SENDMSG_QUEUE,
4234 AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, 0, streamState, 0);
Eric Laurent78472112012-05-21 08:57:21 -07004235 setBluetoothA2dpOnInt(true);
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07004236 AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
4237 AudioSystem.DEVICE_STATE_AVAILABLE,
Paul McLean10804eb2015-01-28 11:16:35 -08004238 address,
4239 "a2dp-device");
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07004240 // Reset A2DP suspend state each time a new sink is connected
4241 AudioSystem.setParameters("A2dpSuspended=false");
4242 mConnectedDevices.put( new Integer(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP),
4243 address);
4244 }
4245
Eric Laurent5bfaeae2012-09-21 18:44:48 -07004246 private void onSendBecomingNoisyIntent() {
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07004247 sendBroadcastToAll(new Intent(AudioManager.ACTION_AUDIO_BECOMING_NOISY));
Mike Lockwood98418182012-05-10 17:13:20 -07004248 }
4249
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004250 // must be called synchronized on mConnectedDevices
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07004251 private void makeA2dpDeviceUnavailableNow(String address) {
Matthew Xiec9d1d5f2013-09-12 00:32:22 -07004252 synchronized (mA2dpAvrcpLock) {
4253 mAvrcpAbsVolSupported = false;
4254 }
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07004255 AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
4256 AudioSystem.DEVICE_STATE_UNAVAILABLE,
Paul McLean10804eb2015-01-28 11:16:35 -08004257 address,
4258 "a2dp-device");
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07004259 mConnectedDevices.remove(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP);
RoboErik5535ea82014-09-25 14:53:16 -07004260 synchronized (mCurAudioRoutes) {
4261 // Remove A2DP routes as well
John Spurlock61560172015-02-06 19:46:04 -05004262 if (mCurAudioRoutes.bluetoothName != null) {
4263 mCurAudioRoutes.bluetoothName = null;
RoboErik5535ea82014-09-25 14:53:16 -07004264 sendMsg(mAudioHandler, MSG_REPORT_NEW_ROUTES,
4265 SENDMSG_NOOP, 0, 0, null, 0);
4266 }
4267 }
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07004268 }
4269
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004270 // must be called synchronized on mConnectedDevices
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07004271 private void makeA2dpDeviceUnavailableLater(String address) {
Eric Laurent3b591262010-04-20 07:01:00 -07004272 // prevent any activity on the A2DP audio output to avoid unwanted
4273 // reconnection of the sink.
4274 AudioSystem.setParameters("A2dpSuspended=true");
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07004275 // the device will be made unavailable later, so consider it disconnected right away
4276 mConnectedDevices.remove(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP);
4277 // send the delayed message to make the device unavailable later
4278 Message msg = mAudioHandler.obtainMessage(MSG_BTA2DP_DOCK_TIMEOUT, address);
4279 mAudioHandler.sendMessageDelayed(msg, BTA2DP_DOCK_TIMEOUT_MILLIS);
4280
4281 }
4282
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004283 // must be called synchronized on mConnectedDevices
Mike Lockwood0a40ec22014-05-21 10:08:50 -07004284 private void makeA2dpSrcAvailable(String address) {
4285 AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP,
4286 AudioSystem.DEVICE_STATE_AVAILABLE,
Paul McLean10804eb2015-01-28 11:16:35 -08004287 address,
4288 "a2dp-device");
Mike Lockwood0a40ec22014-05-21 10:08:50 -07004289 mConnectedDevices.put( new Integer(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP),
4290 address);
4291 }
4292
4293 // must be called synchronized on mConnectedDevices
4294 private void makeA2dpSrcUnavailable(String address) {
4295 AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP,
4296 AudioSystem.DEVICE_STATE_UNAVAILABLE,
Paul McLean10804eb2015-01-28 11:16:35 -08004297 address,
4298 "a2dp-device");
Mike Lockwood0a40ec22014-05-21 10:08:50 -07004299 mConnectedDevices.remove(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP);
4300 }
4301
4302 // must be called synchronized on mConnectedDevices
Jean-Michel Trivia847ba42010-04-23 11:49:29 -07004303 private void cancelA2dpDeviceTimeout() {
Jean-Michel Trivi4c637b92010-04-12 18:44:10 -07004304 mAudioHandler.removeMessages(MSG_BTA2DP_DOCK_TIMEOUT);
4305 }
4306
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004307 // must be called synchronized on mConnectedDevices
Jean-Michel Trivia847ba42010-04-23 11:49:29 -07004308 private boolean hasScheduledA2dpDockTimeout() {
4309 return mAudioHandler.hasMessages(MSG_BTA2DP_DOCK_TIMEOUT);
4310 }
4311
Mike Lockwood0a40ec22014-05-21 10:08:50 -07004312 private void onSetA2dpSinkConnectionState(BluetoothDevice btDevice, int state)
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004313 {
Mike Lockwood0a40ec22014-05-21 10:08:50 -07004314 if (DEBUG_VOL) {
4315 Log.d(TAG, "onSetA2dpSinkConnectionState btDevice="+btDevice+"state="+state);
4316 }
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004317 if (btDevice == null) {
4318 return;
4319 }
4320 String address = btDevice.getAddress();
4321 if (!BluetoothAdapter.checkBluetoothAddress(address)) {
4322 address = "";
4323 }
John Du5a0cf7a2013-07-19 11:30:34 -07004324
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004325 synchronized (mConnectedDevices) {
4326 boolean isConnected =
4327 (mConnectedDevices.containsKey(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP) &&
4328 mConnectedDevices.get(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP).equals(address));
4329
4330 if (isConnected && state != BluetoothProfile.STATE_CONNECTED) {
4331 if (btDevice.isBluetoothDock()) {
4332 if (state == BluetoothProfile.STATE_DISCONNECTED) {
4333 // introduction of a delay for transient disconnections of docks when
4334 // power is rapidly turned off/on, this message will be canceled if
4335 // we reconnect the dock under a preset delay
4336 makeA2dpDeviceUnavailableLater(address);
4337 // the next time isConnected is evaluated, it will be false for the dock
4338 }
4339 } else {
4340 makeA2dpDeviceUnavailableNow(address);
4341 }
Dianne Hackborn632ca412012-06-14 19:34:10 -07004342 synchronized (mCurAudioRoutes) {
John Spurlock61560172015-02-06 19:46:04 -05004343 if (mCurAudioRoutes.bluetoothName != null) {
4344 mCurAudioRoutes.bluetoothName = null;
Dianne Hackborn632ca412012-06-14 19:34:10 -07004345 sendMsg(mAudioHandler, MSG_REPORT_NEW_ROUTES,
4346 SENDMSG_NOOP, 0, 0, null, 0);
4347 }
4348 }
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004349 } else if (!isConnected && state == BluetoothProfile.STATE_CONNECTED) {
4350 if (btDevice.isBluetoothDock()) {
4351 // this could be a reconnection after a transient disconnection
4352 cancelA2dpDeviceTimeout();
4353 mDockAddress = address;
4354 } else {
4355 // this could be a connection of another A2DP device before the timeout of
4356 // a dock: cancel the dock timeout, and make the dock unavailable now
4357 if(hasScheduledA2dpDockTimeout()) {
4358 cancelA2dpDeviceTimeout();
4359 makeA2dpDeviceUnavailableNow(mDockAddress);
4360 }
4361 }
4362 makeA2dpDeviceAvailable(address);
Dianne Hackborn632ca412012-06-14 19:34:10 -07004363 synchronized (mCurAudioRoutes) {
4364 String name = btDevice.getAliasName();
John Spurlock61560172015-02-06 19:46:04 -05004365 if (!TextUtils.equals(mCurAudioRoutes.bluetoothName, name)) {
4366 mCurAudioRoutes.bluetoothName = name;
Dianne Hackborn632ca412012-06-14 19:34:10 -07004367 sendMsg(mAudioHandler, MSG_REPORT_NEW_ROUTES,
4368 SENDMSG_NOOP, 0, 0, null, 0);
4369 }
4370 }
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004371 }
4372 }
4373 }
4374
Mike Lockwood0a40ec22014-05-21 10:08:50 -07004375 private void onSetA2dpSourceConnectionState(BluetoothDevice btDevice, int state)
4376 {
4377 if (DEBUG_VOL) {
4378 Log.d(TAG, "onSetA2dpSourceConnectionState btDevice="+btDevice+" state="+state);
4379 }
4380 if (btDevice == null) {
4381 return;
4382 }
4383 String address = btDevice.getAddress();
4384 if (!BluetoothAdapter.checkBluetoothAddress(address)) {
4385 address = "";
4386 }
4387
4388 synchronized (mConnectedDevices) {
4389 boolean isConnected =
4390 (mConnectedDevices.containsKey(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP) &&
4391 mConnectedDevices.get(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP).equals(address));
4392
4393 if (isConnected && state != BluetoothProfile.STATE_CONNECTED) {
4394 makeA2dpSrcUnavailable(address);
4395 } else if (!isConnected && state == BluetoothProfile.STATE_CONNECTED) {
4396 makeA2dpSrcAvailable(address);
4397 }
4398 }
4399 }
4400
John Du5a0cf7a2013-07-19 11:30:34 -07004401 public void avrcpSupportsAbsoluteVolume(String address, boolean support) {
4402 // address is not used for now, but may be used when multiple a2dp devices are supported
4403 synchronized (mA2dpAvrcpLock) {
4404 mAvrcpAbsVolSupported = support;
Matthew Xiec9d1d5f2013-09-12 00:32:22 -07004405 sendMsg(mAudioHandler, MSG_SET_DEVICE_VOLUME, SENDMSG_QUEUE,
Eric Laurentcd772d02013-10-30 18:31:07 -07004406 AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, 0,
4407 mStreamStates[AudioSystem.STREAM_MUSIC], 0);
4408 sendMsg(mAudioHandler, MSG_SET_DEVICE_VOLUME, SENDMSG_QUEUE,
4409 AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, 0,
4410 mStreamStates[AudioSystem.STREAM_RING], 0);
John Du5a0cf7a2013-07-19 11:30:34 -07004411 }
4412 }
4413
Paul McLean10804eb2015-01-28 11:16:35 -08004414 private boolean handleDeviceConnection(boolean connect, int device, String address, String deviceName) {
4415 Slog.i(TAG, "handleDeviceConnection(" + connect +
4416 " dev:" + Integer.toHexString(device) +
RoboErik5452e252015-02-06 15:33:53 -08004417 " address:" + address +
Paul McLean10804eb2015-01-28 11:16:35 -08004418 " name:" + deviceName + ")");
Eric Laurent59f48272012-04-05 19:42:21 -07004419 synchronized (mConnectedDevices) {
4420 boolean isConnected = (mConnectedDevices.containsKey(device) &&
Paul McLean10804eb2015-01-28 11:16:35 -08004421 (address.isEmpty() || mConnectedDevices.get(device).equals(address)));
Eric Laurent59f48272012-04-05 19:42:21 -07004422
Paul McLean10804eb2015-01-28 11:16:35 -08004423 if (isConnected && !connect) {
Eric Laurent59f48272012-04-05 19:42:21 -07004424 AudioSystem.setDeviceConnectionState(device,
4425 AudioSystem.DEVICE_STATE_UNAVAILABLE,
Paul McLean10804eb2015-01-28 11:16:35 -08004426 address, deviceName);
Eric Laurent59f48272012-04-05 19:42:21 -07004427 mConnectedDevices.remove(device);
4428 return true;
Paul McLean10804eb2015-01-28 11:16:35 -08004429 } else if (!isConnected && connect) {
Eric Laurent59f48272012-04-05 19:42:21 -07004430 AudioSystem.setDeviceConnectionState(device,
4431 AudioSystem.DEVICE_STATE_AVAILABLE,
Paul McLean10804eb2015-01-28 11:16:35 -08004432 address, deviceName);
4433 mConnectedDevices.put(new Integer(device), address);
Eric Laurent59f48272012-04-05 19:42:21 -07004434 return true;
4435 }
4436 }
4437 return false;
4438 }
4439
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004440 // Devices which removal triggers intent ACTION_AUDIO_BECOMING_NOISY. The intent is only
4441 // sent if none of these devices is connected.
Jean-Michel Trivi7e2f3712015-01-12 11:01:55 -08004442 // Access synchronized on mConnectedDevices
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004443 int mBecomingNoisyIntentDevices =
4444 AudioSystem.DEVICE_OUT_WIRED_HEADSET | AudioSystem.DEVICE_OUT_WIRED_HEADPHONE |
Eric Laurent948d3272014-05-16 15:18:45 -07004445 AudioSystem.DEVICE_OUT_ALL_A2DP | AudioSystem.DEVICE_OUT_HDMI |
Eric Laurent794da7a2012-08-30 11:30:16 -07004446 AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET | AudioSystem.DEVICE_OUT_DGTL_DOCK_HEADSET |
Jon Eklund43cc8bb2014-07-28 16:07:24 -05004447 AudioSystem.DEVICE_OUT_ALL_USB | AudioSystem.DEVICE_OUT_LINE;
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004448
4449 // must be called before removing the device from mConnectedDevices
Jean-Michel Trivi7e2f3712015-01-12 11:01:55 -08004450 // Called synchronized on mConnectedDevices
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004451 private int checkSendBecomingNoisyIntent(int device, int state) {
4452 int delay = 0;
4453 if ((state == 0) && ((device & mBecomingNoisyIntentDevices) != 0)) {
4454 int devices = 0;
4455 for (int dev : mConnectedDevices.keySet()) {
Eric Laurent27c30e42014-08-27 12:36:33 -07004456 if (((dev & AudioSystem.DEVICE_BIT_IN) == 0) &&
4457 ((dev & mBecomingNoisyIntentDevices) != 0)) {
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004458 devices |= dev;
4459 }
4460 }
4461 if (devices == device) {
Eric Laurent5bfaeae2012-09-21 18:44:48 -07004462 sendMsg(mAudioHandler,
4463 MSG_BROADCAST_AUDIO_BECOMING_NOISY,
4464 SENDMSG_REPLACE,
4465 0,
4466 0,
4467 null,
4468 0);
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004469 delay = 1000;
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004470 }
4471 }
4472
Mike Lockwood0a40ec22014-05-21 10:08:50 -07004473 if (mAudioHandler.hasMessages(MSG_SET_A2DP_SRC_CONNECTION_STATE) ||
4474 mAudioHandler.hasMessages(MSG_SET_A2DP_SINK_CONNECTION_STATE) ||
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004475 mAudioHandler.hasMessages(MSG_SET_WIRED_DEVICE_CONNECTION_STATE)) {
Eric Laurentadbe8bf2014-11-03 18:26:32 -08004476 synchronized (mLastDeviceConnectMsgTime) {
4477 long time = SystemClock.uptimeMillis();
4478 if (mLastDeviceConnectMsgTime > time) {
Matthew Xiec525cf72015-01-22 20:13:17 -08004479 delay = (int)(mLastDeviceConnectMsgTime - time) + 30;
Eric Laurentadbe8bf2014-11-03 18:26:32 -08004480 }
4481 }
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004482 }
4483 return delay;
4484 }
4485
Paul McLean10804eb2015-01-28 11:16:35 -08004486 private void sendDeviceConnectionIntent(int device, int state, String address, String deviceName)
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004487 {
Paul McLean10804eb2015-01-28 11:16:35 -08004488 Slog.i(TAG, "sendDeviceConnectionIntent(dev:0x" + Integer.toHexString(device) +
4489 " state:0x" + Integer.toHexString(state) +
4490 " address:" + address +
4491 " name:" + deviceName + ");");
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004492 Intent intent = new Intent();
4493
Paul McLean10804eb2015-01-28 11:16:35 -08004494 intent.putExtra(CONNECT_INTENT_KEY_STATE, state);
4495 intent.putExtra(CONNECT_INTENT_KEY_ADDRESS, address);
4496 intent.putExtra(CONNECT_INTENT_KEY_PORT_NAME, deviceName);
4497
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004498 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
4499
Dianne Hackborn632ca412012-06-14 19:34:10 -07004500 int connType = 0;
4501
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004502 if (device == AudioSystem.DEVICE_OUT_WIRED_HEADSET) {
Dianne Hackborn632ca412012-06-14 19:34:10 -07004503 connType = AudioRoutesInfo.MAIN_HEADSET;
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004504 intent.setAction(Intent.ACTION_HEADSET_PLUG);
4505 intent.putExtra("microphone", 1);
Jon Eklund43cc8bb2014-07-28 16:07:24 -05004506 } else if (device == AudioSystem.DEVICE_OUT_WIRED_HEADPHONE ||
4507 device == AudioSystem.DEVICE_OUT_LINE) {
4508 /*do apps care about line-out vs headphones?*/
Dianne Hackborn632ca412012-06-14 19:34:10 -07004509 connType = AudioRoutesInfo.MAIN_HEADPHONES;
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004510 intent.setAction(Intent.ACTION_HEADSET_PLUG);
4511 intent.putExtra("microphone", 0);
Eric Laurent6fa42452015-01-09 15:09:40 -08004512 } else if (device == AudioSystem.DEVICE_OUT_HDMI ||
4513 device == AudioSystem.DEVICE_OUT_HDMI_ARC) {
Dianne Hackborn632ca412012-06-14 19:34:10 -07004514 connType = AudioRoutesInfo.MAIN_HDMI;
Jean-Michel Trivi37d78042014-08-10 14:59:15 -07004515 configureHdmiPlugIntent(intent, state);
Paul McLean10804eb2015-01-28 11:16:35 -08004516 } else if (device == AudioSystem.DEVICE_OUT_USB_DEVICE) {
4517 connType = AudioRoutesInfo.MAIN_USB;
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004518 }
4519
Dianne Hackborn632ca412012-06-14 19:34:10 -07004520 synchronized (mCurAudioRoutes) {
4521 if (connType != 0) {
John Spurlock61560172015-02-06 19:46:04 -05004522 int newConn = mCurAudioRoutes.mainType;
Dianne Hackborn632ca412012-06-14 19:34:10 -07004523 if (state != 0) {
4524 newConn |= connType;
4525 } else {
4526 newConn &= ~connType;
4527 }
John Spurlock61560172015-02-06 19:46:04 -05004528 if (newConn != mCurAudioRoutes.mainType) {
4529 mCurAudioRoutes.mainType = newConn;
Dianne Hackborn632ca412012-06-14 19:34:10 -07004530 sendMsg(mAudioHandler, MSG_REPORT_NEW_ROUTES,
4531 SENDMSG_NOOP, 0, 0, null, 0);
4532 }
4533 }
4534 }
4535
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07004536 final long ident = Binder.clearCallingIdentity();
4537 try {
4538 ActivityManagerNative.broadcastStickyIntent(intent, null, UserHandle.USER_ALL);
4539 } finally {
4540 Binder.restoreCallingIdentity(ident);
4541 }
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004542 }
4543
Paul McLean10804eb2015-01-28 11:16:35 -08004544 private void onSetWiredDeviceConnectionState(int device, int state, String address,
4545 String deviceName)
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004546 {
Paul McLean10804eb2015-01-28 11:16:35 -08004547 Slog.i(TAG, "onSetWiredDeviceConnectionState(dev:" + Integer.toHexString(device)
4548 + " state:" + Integer.toHexString(state)
4549 + " address:" + address
4550 + " deviceName:" + deviceName + ");");
4551
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004552 synchronized (mConnectedDevices) {
4553 if ((state == 0) && ((device == AudioSystem.DEVICE_OUT_WIRED_HEADSET) ||
Jon Eklund43cc8bb2014-07-28 16:07:24 -05004554 (device == AudioSystem.DEVICE_OUT_WIRED_HEADPHONE) ||
4555 (device == AudioSystem.DEVICE_OUT_LINE))) {
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004556 setBluetoothA2dpOnInt(true);
4557 }
Eric Laurentae4506e2014-05-29 16:04:32 -07004558 boolean isUsb = ((device & ~AudioSystem.DEVICE_OUT_ALL_USB) == 0) ||
4559 (((device & AudioSystem.DEVICE_BIT_IN) != 0) &&
4560 ((device & ~AudioSystem.DEVICE_IN_ALL_USB) == 0));
Paul McLean10804eb2015-01-28 11:16:35 -08004561 handleDeviceConnection(state == 1, device, address, deviceName);
Eric Laurentf1a457d2012-09-20 16:27:23 -07004562 if (state != 0) {
4563 if ((device == AudioSystem.DEVICE_OUT_WIRED_HEADSET) ||
Jon Eklund43cc8bb2014-07-28 16:07:24 -05004564 (device == AudioSystem.DEVICE_OUT_WIRED_HEADPHONE) ||
4565 (device == AudioSystem.DEVICE_OUT_LINE)) {
Eric Laurentf1a457d2012-09-20 16:27:23 -07004566 setBluetoothA2dpOnInt(false);
4567 }
4568 if ((device & mSafeMediaVolumeDevices) != 0) {
4569 sendMsg(mAudioHandler,
4570 MSG_CHECK_MUSIC_ACTIVE,
4571 SENDMSG_REPLACE,
4572 0,
4573 0,
4574 null,
4575 MUSIC_ACTIVE_POLL_PERIOD_MS);
4576 }
Eric Laurent212532b2014-07-21 15:43:18 -07004577 // Television devices without CEC service apply software volume on HDMI output
4578 if (isPlatformTelevision() && ((device & AudioSystem.DEVICE_OUT_HDMI) != 0)) {
4579 mFixedVolumeDevices |= AudioSystem.DEVICE_OUT_HDMI;
4580 checkAllFixedVolumeDevices();
4581 if (mHdmiManager != null) {
4582 synchronized (mHdmiManager) {
4583 if (mHdmiPlaybackClient != null) {
4584 mHdmiCecSink = false;
4585 mHdmiPlaybackClient.queryDisplayStatus(mHdmiDisplayStatusCallback);
4586 }
4587 }
4588 }
4589 }
4590 } else {
4591 if (isPlatformTelevision() && ((device & AudioSystem.DEVICE_OUT_HDMI) != 0)) {
4592 if (mHdmiManager != null) {
4593 synchronized (mHdmiManager) {
4594 mHdmiCecSink = false;
4595 }
4596 }
4597 }
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004598 }
Paul McLean10804eb2015-01-28 11:16:35 -08004599 if (!isUsb && device != AudioSystem.DEVICE_IN_WIRED_HEADSET) {
4600 sendDeviceConnectionIntent(device, state, address, deviceName);
Mike Lockwooddb454842012-09-18 11:16:57 -07004601 }
Eric Laurentb1fbaac2012-05-29 09:24:28 -07004602 }
4603 }
4604
Jean-Michel Trivi37d78042014-08-10 14:59:15 -07004605 private void configureHdmiPlugIntent(Intent intent, int state) {
Jean-Michel Trivic5258432014-08-27 15:46:54 -07004606 intent.setAction(AudioManager.ACTION_HDMI_AUDIO_PLUG);
4607 intent.putExtra(AudioManager.EXTRA_AUDIO_PLUG_STATE, state);
Jean-Michel Trivi37d78042014-08-10 14:59:15 -07004608 if (state == 1) {
4609 ArrayList<AudioPort> ports = new ArrayList<AudioPort>();
4610 int[] portGeneration = new int[1];
4611 int status = AudioSystem.listAudioPorts(ports, portGeneration);
4612 if (status == AudioManager.SUCCESS) {
4613 for (AudioPort port : ports) {
4614 if (port instanceof AudioDevicePort) {
4615 final AudioDevicePort devicePort = (AudioDevicePort) port;
Eric Laurent6fa42452015-01-09 15:09:40 -08004616 if (devicePort.type() == AudioManager.DEVICE_OUT_HDMI ||
4617 devicePort.type() == AudioManager.DEVICE_OUT_HDMI_ARC) {
Jean-Michel Trivi37d78042014-08-10 14:59:15 -07004618 // format the list of supported encodings
4619 int[] formats = devicePort.formats();
4620 if (formats.length > 0) {
4621 ArrayList<Integer> encodingList = new ArrayList(1);
4622 for (int format : formats) {
4623 // a format in the list can be 0, skip it
4624 if (format != AudioFormat.ENCODING_INVALID) {
4625 encodingList.add(format);
4626 }
4627 }
4628 int[] encodingArray = new int[encodingList.size()];
4629 for (int i = 0 ; i < encodingArray.length ; i++) {
4630 encodingArray[i] = encodingList.get(i);
4631 }
Jean-Michel Trivic5258432014-08-27 15:46:54 -07004632 intent.putExtra(AudioManager.EXTRA_ENCODINGS, encodingArray);
Jean-Michel Trivi37d78042014-08-10 14:59:15 -07004633 }
4634 // find the maximum supported number of channels
4635 int maxChannels = 0;
4636 for (int mask : devicePort.channelMasks()) {
4637 int channelCount = AudioFormat.channelCountFromOutChannelMask(mask);
4638 if (channelCount > maxChannels) {
4639 maxChannels = channelCount;
4640 }
4641 }
Jean-Michel Trivic5258432014-08-27 15:46:54 -07004642 intent.putExtra(AudioManager.EXTRA_MAX_CHANNEL_COUNT, maxChannels);
Jean-Michel Trivi37d78042014-08-10 14:59:15 -07004643 }
4644 }
4645 }
4646 }
4647 }
4648 }
4649
Jean-Michel Trivia847ba42010-04-23 11:49:29 -07004650 /* cache of the address of the last dock the device was connected to */
4651 private String mDockAddress;
4652
Eric Laurenta553c252009-07-17 12:17:14 -07004653 /**
4654 * Receiver for misc intent broadcasts the Phone app cares about.
4655 */
4656 private class AudioServiceBroadcastReceiver extends BroadcastReceiver {
4657 @Override
4658 public void onReceive(Context context, Intent intent) {
4659 String action = intent.getAction();
Eric Laurentae4506e2014-05-29 16:04:32 -07004660 int outDevice;
4661 int inDevice;
Eric Laurent59f48272012-04-05 19:42:21 -07004662 int state;
Eric Laurenta553c252009-07-17 12:17:14 -07004663
Jean-Michel Trivi758559e2010-03-09 09:26:08 -08004664 if (action.equals(Intent.ACTION_DOCK_EVENT)) {
4665 int dockState = intent.getIntExtra(Intent.EXTRA_DOCK_STATE,
4666 Intent.EXTRA_DOCK_STATE_UNDOCKED);
4667 int config;
4668 switch (dockState) {
4669 case Intent.EXTRA_DOCK_STATE_DESK:
4670 config = AudioSystem.FORCE_BT_DESK_DOCK;
4671 break;
4672 case Intent.EXTRA_DOCK_STATE_CAR:
4673 config = AudioSystem.FORCE_BT_CAR_DOCK;
4674 break;
Praveen Bharathi21e941b2010-10-06 15:23:14 -05004675 case Intent.EXTRA_DOCK_STATE_LE_DESK:
Eric Laurent08ed1b92012-11-05 14:54:12 -08004676 config = AudioSystem.FORCE_ANALOG_DOCK;
Praveen Bharathi21e941b2010-10-06 15:23:14 -05004677 break;
4678 case Intent.EXTRA_DOCK_STATE_HE_DESK:
4679 config = AudioSystem.FORCE_DIGITAL_DOCK;
4680 break;
Jean-Michel Trivi758559e2010-03-09 09:26:08 -08004681 case Intent.EXTRA_DOCK_STATE_UNDOCKED:
4682 default:
4683 config = AudioSystem.FORCE_NONE;
4684 }
Eric Laurent08ed1b92012-11-05 14:54:12 -08004685 // Low end docks have a menu to enable or disable audio
4686 // (see mDockAudioMediaEnabled)
4687 if (!((dockState == Intent.EXTRA_DOCK_STATE_LE_DESK) ||
4688 ((dockState == Intent.EXTRA_DOCK_STATE_UNDOCKED) &&
4689 (mDockState == Intent.EXTRA_DOCK_STATE_LE_DESK)))) {
4690 AudioSystem.setForceUse(AudioSystem.FOR_DOCK, config);
4691 }
4692 mDockState = dockState;
Jaikumar Ganesh82aa7f02010-09-27 17:05:10 -07004693 } else if (action.equals(BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED)) {
Eric Laurent59f48272012-04-05 19:42:21 -07004694 state = intent.getIntExtra(BluetoothProfile.EXTRA_STATE,
Jaikumar Ganesh82aa7f02010-09-27 17:05:10 -07004695 BluetoothProfile.STATE_DISCONNECTED);
Eric Laurentae4506e2014-05-29 16:04:32 -07004696 outDevice = AudioSystem.DEVICE_OUT_BLUETOOTH_SCO;
4697 inDevice = AudioSystem.DEVICE_IN_BLUETOOTH_SCO_HEADSET;
Nick Pellya56d1c72009-08-19 14:49:29 -07004698 String address = null;
Eric Laurentdca56b92011-09-02 14:20:56 -07004699
4700 BluetoothDevice btDevice = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
4701 if (btDevice == null) {
4702 return;
4703 }
4704
4705 address = btDevice.getAddress();
4706 BluetoothClass btClass = btDevice.getBluetoothClass();
4707 if (btClass != null) {
4708 switch (btClass.getDeviceClass()) {
4709 case BluetoothClass.Device.AUDIO_VIDEO_WEARABLE_HEADSET:
4710 case BluetoothClass.Device.AUDIO_VIDEO_HANDSFREE:
Eric Laurentae4506e2014-05-29 16:04:32 -07004711 outDevice = AudioSystem.DEVICE_OUT_BLUETOOTH_SCO_HEADSET;
Eric Laurentdca56b92011-09-02 14:20:56 -07004712 break;
4713 case BluetoothClass.Device.AUDIO_VIDEO_CAR_AUDIO:
Eric Laurentae4506e2014-05-29 16:04:32 -07004714 outDevice = AudioSystem.DEVICE_OUT_BLUETOOTH_SCO_CARKIT;
Eric Laurentdca56b92011-09-02 14:20:56 -07004715 break;
Eric Laurentd5603c12009-08-06 08:49:39 -07004716 }
4717 }
4718
Eric Laurentdca56b92011-09-02 14:20:56 -07004719 if (!BluetoothAdapter.checkBluetoothAddress(address)) {
4720 address = "";
4721 }
Eric Laurentd5603c12009-08-06 08:49:39 -07004722
Eric Laurent59f48272012-04-05 19:42:21 -07004723 boolean connected = (state == BluetoothProfile.STATE_CONNECTED);
Paul McLean10804eb2015-01-28 11:16:35 -08004724 boolean success =
4725 handleDeviceConnection(connected, outDevice, address, "Bluetooth Headset") &&
4726 handleDeviceConnection(connected, inDevice, address, "Bluetooth Headset");
Eric Laurentae4506e2014-05-29 16:04:32 -07004727 if (success) {
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004728 synchronized (mScoClients) {
Eric Laurent59f48272012-04-05 19:42:21 -07004729 if (connected) {
4730 mBluetoothHeadsetDevice = btDevice;
4731 } else {
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004732 mBluetoothHeadsetDevice = null;
4733 resetBluetoothSco();
Eric Laurent6bc7f2c2011-11-29 18:49:40 -08004734 }
Eric Laurent62ef7672010-11-24 10:58:32 -08004735 }
Eric Laurenta553c252009-07-17 12:17:14 -07004736 }
Paul McLeandf361462014-04-10 16:02:55 -07004737 } else if (action.equals(BluetoothHeadset.ACTION_AUDIO_STATE_CHANGED)) {
Eric Laurent62ef7672010-11-24 10:58:32 -08004738 boolean broadcast = false;
Eric Laurent59f48272012-04-05 19:42:21 -07004739 int scoAudioState = AudioManager.SCO_AUDIO_STATE_ERROR;
Eric Laurent3def1ee2010-03-17 23:26:26 -07004740 synchronized (mScoClients) {
Eric Laurent62ef7672010-11-24 10:58:32 -08004741 int btState = intent.getIntExtra(BluetoothProfile.EXTRA_STATE, -1);
Eric Laurentdc03c612011-04-01 10:59:41 -07004742 // broadcast intent if the connection was initated by AudioService
4743 if (!mScoClients.isEmpty() &&
4744 (mScoAudioState == SCO_STATE_ACTIVE_INTERNAL ||
4745 mScoAudioState == SCO_STATE_ACTIVATE_REQ ||
4746 mScoAudioState == SCO_STATE_DEACTIVATE_REQ)) {
Eric Laurent62ef7672010-11-24 10:58:32 -08004747 broadcast = true;
4748 }
4749 switch (btState) {
4750 case BluetoothHeadset.STATE_AUDIO_CONNECTED:
Eric Laurent59f48272012-04-05 19:42:21 -07004751 scoAudioState = AudioManager.SCO_AUDIO_STATE_CONNECTED;
Eric Laurentdc03c612011-04-01 10:59:41 -07004752 if (mScoAudioState != SCO_STATE_ACTIVE_INTERNAL &&
4753 mScoAudioState != SCO_STATE_DEACTIVATE_REQ &&
4754 mScoAudioState != SCO_STATE_DEACTIVATE_EXT_REQ) {
Eric Laurent62ef7672010-11-24 10:58:32 -08004755 mScoAudioState = SCO_STATE_ACTIVE_EXTERNAL;
Eric Laurent3def1ee2010-03-17 23:26:26 -07004756 }
Eric Laurent62ef7672010-11-24 10:58:32 -08004757 break;
4758 case BluetoothHeadset.STATE_AUDIO_DISCONNECTED:
Eric Laurent59f48272012-04-05 19:42:21 -07004759 scoAudioState = AudioManager.SCO_AUDIO_STATE_DISCONNECTED;
Eric Laurent62ef7672010-11-24 10:58:32 -08004760 mScoAudioState = SCO_STATE_INACTIVE;
Eric Laurentd7454be2011-09-14 08:45:58 -07004761 clearAllScoClients(0, false);
Eric Laurent62ef7672010-11-24 10:58:32 -08004762 break;
4763 case BluetoothHeadset.STATE_AUDIO_CONNECTING:
Eric Laurentdc03c612011-04-01 10:59:41 -07004764 if (mScoAudioState != SCO_STATE_ACTIVE_INTERNAL &&
4765 mScoAudioState != SCO_STATE_DEACTIVATE_REQ &&
4766 mScoAudioState != SCO_STATE_DEACTIVATE_EXT_REQ) {
Eric Laurent62ef7672010-11-24 10:58:32 -08004767 mScoAudioState = SCO_STATE_ACTIVE_EXTERNAL;
Eric Laurent3def1ee2010-03-17 23:26:26 -07004768 }
Eric Laurent62ef7672010-11-24 10:58:32 -08004769 default:
4770 // do not broadcast CONNECTING or invalid state
4771 broadcast = false;
4772 break;
Eric Laurent3def1ee2010-03-17 23:26:26 -07004773 }
4774 }
Eric Laurent62ef7672010-11-24 10:58:32 -08004775 if (broadcast) {
Eric Laurent59f48272012-04-05 19:42:21 -07004776 broadcastScoConnectionState(scoAudioState);
Eric Laurentdc03c612011-04-01 10:59:41 -07004777 //FIXME: this is to maintain compatibility with deprecated intent
4778 // AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED. Remove when appropriate.
Eric Laurent62ef7672010-11-24 10:58:32 -08004779 Intent newIntent = new Intent(AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED);
Eric Laurent59f48272012-04-05 19:42:21 -07004780 newIntent.putExtra(AudioManager.EXTRA_SCO_AUDIO_STATE, scoAudioState);
Dianne Hackborn5ac72a22012-08-29 18:32:08 -07004781 sendStickyBroadcastToAll(newIntent);
Eric Laurent62ef7672010-11-24 10:58:32 -08004782 }
Eric Laurent950e8cb2011-10-13 08:57:54 -07004783 } else if (action.equals(Intent.ACTION_SCREEN_ON)) {
Jon Eklund318f0fe2014-01-23 17:53:48 -06004784 if (mMonitorRotation) {
4785 mOrientationListener.onOrientationChanged(0); //argument is ignored anyway
4786 mOrientationListener.enable();
4787 }
Eric Laurent950e8cb2011-10-13 08:57:54 -07004788 AudioSystem.setParameters("screen_state=on");
4789 } else if (action.equals(Intent.ACTION_SCREEN_OFF)) {
Jon Eklund318f0fe2014-01-23 17:53:48 -06004790 if (mMonitorRotation) {
4791 //reduce wakeups (save current) by only listening when display is on
4792 mOrientationListener.disable();
4793 }
Eric Laurent950e8cb2011-10-13 08:57:54 -07004794 AudioSystem.setParameters("screen_state=off");
Dianne Hackborn961cae92013-03-20 14:59:43 -07004795 } else if (action.equals(Intent.ACTION_CONFIGURATION_CHANGED)) {
Jean-Michel Trivif26f0172012-04-25 16:23:20 -07004796 handleConfigurationChanged(context);
Eric Laurentbc0fab1f2012-09-19 11:24:41 -07004797 } else if (action.equals(Intent.ACTION_USER_SWITCHED)) {
Jean-Michel Trivif4a8eb22012-10-29 12:42:55 -07004798 // attempt to stop music playback for background user
Eric Laurent5bfaeae2012-09-21 18:44:48 -07004799 sendMsg(mAudioHandler,
4800 MSG_BROADCAST_AUDIO_BECOMING_NOISY,
4801 SENDMSG_REPLACE,
4802 0,
4803 0,
4804 null,
4805 0);
Jean-Michel Trivif4a8eb22012-10-29 12:42:55 -07004806 // the current audio focus owner is no longer valid
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -07004807 mMediaFocusControl.discardAudioFocusOwner();
Jean-Michel Trivif4a8eb22012-10-29 12:42:55 -07004808
Eric Laurent5bfaeae2012-09-21 18:44:48 -07004809 // load volume settings for new user
Eric Laurentbc0fab1f2012-09-19 11:24:41 -07004810 readAudioSettings(true /*userSwitch*/);
4811 // preserve STREAM_MUSIC volume from one user to the next.
4812 sendMsg(mAudioHandler,
4813 MSG_SET_ALL_VOLUMES,
4814 SENDMSG_QUEUE,
4815 0,
4816 0,
4817 mStreamStates[AudioSystem.STREAM_MUSIC], 0);
Eric Laurenta553c252009-07-17 12:17:14 -07004818 }
4819 }
Paul McLeanc837a452014-04-09 09:04:43 -07004820 } // end class AudioServiceBroadcastReceiver
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004821
4822 //==========================================================================================
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -07004823 // RemoteControlDisplay / RemoteControlClient / Remote info
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08004824 //==========================================================================================
Jean-Michel Trivif108cdd92013-09-27 18:37:36 -07004825 public boolean registerRemoteController(IRemoteControlDisplay rcd, int w, int h,
4826 ComponentName listenerComp) {
4827 return mMediaFocusControl.registerRemoteController(rcd, w, h, listenerComp);
4828 }
4829
Jean-Michel Trivi7ddd2262013-09-01 18:06:45 -07004830 public boolean registerRemoteControlDisplay(IRemoteControlDisplay rcd, int w, int h) {
Jean-Michel Trivif108cdd92013-09-27 18:37:36 -07004831 return mMediaFocusControl.registerRemoteControlDisplay(rcd, w, h);
Jean-Michel Trivi8f619182011-07-21 15:10:10 -07004832 }
Jean-Michel Trivid327f212010-03-16 21:44:33 -07004833
Jean-Michel Trivi4426e422011-08-18 19:16:47 -07004834 public void unregisterRemoteControlDisplay(IRemoteControlDisplay rcd) {
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -07004835 mMediaFocusControl.unregisterRemoteControlDisplay(rcd);
Jean-Michel Trivi4426e422011-08-18 19:16:47 -07004836 }
4837
4838 public void remoteControlDisplayUsesBitmapSize(IRemoteControlDisplay rcd, int w, int h) {
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -07004839 mMediaFocusControl.remoteControlDisplayUsesBitmapSize(rcd, w, h);
Jean-Michel Trivi4426e422011-08-18 19:16:47 -07004840 }
4841
Jean-Michel Trivic3c4bab2013-04-19 08:56:50 -07004842 public void remoteControlDisplayWantsPlaybackPositionSync(IRemoteControlDisplay rcd,
4843 boolean wantsSync) {
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -07004844 mMediaFocusControl.remoteControlDisplayWantsPlaybackPositionSync(rcd, wantsSync);
4845 }
4846
John Spurlock3346a802014-05-20 16:25:37 -04004847 @Override
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -07004848 public void setRemoteStreamVolume(int index) {
John Spurlockcdb57ae2015-02-11 19:04:11 -05004849 enforceVolumeController("set the remote stream volume");
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -07004850 mMediaFocusControl.setRemoteStreamVolume(index);
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07004851 }
4852
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -07004853 //==========================================================================================
4854 // Audio Focus
4855 //==========================================================================================
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -08004856 public int requestAudioFocus(AudioAttributes aa, int durationHint, IBinder cb,
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08004857 IAudioFocusDispatcher fd, String clientId, String callingPackageName, int flags,
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08004858 IAudioPolicyCallback pcb) {
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08004859 // permission checks
4860 if ((flags & AudioManager.AUDIOFOCUS_FLAG_LOCK) == AudioManager.AUDIOFOCUS_FLAG_LOCK) {
John Spurlock61560172015-02-06 19:46:04 -05004861 if (AudioSystem.IN_VOICE_COMM_FOCUS_ID.equals(clientId)) {
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08004862 if (PackageManager.PERMISSION_GRANTED != mContext.checkCallingOrSelfPermission(
4863 android.Manifest.permission.MODIFY_PHONE_STATE)) {
4864 Log.e(TAG, "Invalid permission to (un)lock audio focus", new Exception());
4865 return AudioManager.AUDIOFOCUS_REQUEST_FAILED;
4866 }
4867 } else {
4868 // only a registered audio policy can be used to lock focus
4869 synchronized (mAudioPolicies) {
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08004870 if (!mAudioPolicies.containsKey(pcb.asBinder())) {
4871 Log.e(TAG, "Invalid unregistered AudioPolicy to (un)lock audio focus");
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08004872 return AudioManager.AUDIOFOCUS_REQUEST_FAILED;
4873 }
4874 }
4875 }
4876 }
4877
Jean-Michel Trivifd6ad742014-11-10 14:38:30 -08004878 return mMediaFocusControl.requestAudioFocus(aa, durationHint, cb, fd,
4879 clientId, callingPackageName, flags);
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -07004880 }
4881
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08004882 public int abandonAudioFocus(IAudioFocusDispatcher fd, String clientId, AudioAttributes aa) {
4883 return mMediaFocusControl.abandonAudioFocus(fd, clientId, aa);
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -07004884 }
4885
4886 public void unregisterAudioFocusClient(String clientId) {
4887 mMediaFocusControl.unregisterAudioFocusClient(clientId);
Jean-Michel Trivi3114ce32012-06-11 15:03:52 -07004888 }
4889
Jean-Michel Trivi23805662013-07-31 14:19:18 -07004890 public int getCurrentAudioFocus() {
4891 return mMediaFocusControl.getCurrentAudioFocus();
4892 }
4893
John Spurlock5e783732015-02-19 10:28:59 -05004894 private boolean readCameraSoundForced() {
4895 return SystemProperties.getBoolean("audio.camerasound.force", false) ||
4896 mContext.getResources().getBoolean(
4897 com.android.internal.R.bool.config_camera_sound_forced);
4898 }
4899
Jean-Michel Trivif26f0172012-04-25 16:23:20 -07004900 //==========================================================================================
4901 // Device orientation
4902 //==========================================================================================
4903 /**
Jean-Michel Trivibb6f8712013-05-23 15:02:41 -07004904 * Handles device configuration changes that may map to a change in the orientation
4905 * or orientation.
4906 * Monitoring orientation and rotation is optional, and is defined by the definition and value
4907 * of the "ro.audio.monitorOrientation" and "ro.audio.monitorRotation" system properties.
Jean-Michel Trivif26f0172012-04-25 16:23:20 -07004908 */
4909 private void handleConfigurationChanged(Context context) {
4910 try {
4911 // reading new orientation "safely" (i.e. under try catch) in case anything
4912 // goes wrong when obtaining resources and configuration
Eric Laurentd640bd32012-09-28 18:01:48 -07004913 Configuration config = context.getResources().getConfiguration();
Jean-Michel Trivibb6f8712013-05-23 15:02:41 -07004914 // TODO merge rotation and orientation
Eric Laurentd640bd32012-09-28 18:01:48 -07004915 if (mMonitorOrientation) {
4916 int newOrientation = config.orientation;
4917 if (newOrientation != mDeviceOrientation) {
4918 mDeviceOrientation = newOrientation;
4919 setOrientationForAudioSystem();
4920 }
Jean-Michel Trivif26f0172012-04-25 16:23:20 -07004921 }
Eric Laurentd640bd32012-09-28 18:01:48 -07004922 sendMsg(mAudioHandler,
4923 MSG_CONFIGURE_SAFE_MEDIA_VOLUME,
4924 SENDMSG_REPLACE,
4925 0,
4926 0,
4927 null,
4928 0);
Eric Laurentdd45d012012-10-08 09:04:34 -07004929
John Spurlock5e783732015-02-19 10:28:59 -05004930 boolean cameraSoundForced = readCameraSoundForced();
Eric Laurentdd45d012012-10-08 09:04:34 -07004931 synchronized (mSettingsLock) {
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07004932 boolean cameraSoundForcedChanged = false;
Eric Laurentdd45d012012-10-08 09:04:34 -07004933 synchronized (mCameraSoundForced) {
4934 if (cameraSoundForced != mCameraSoundForced) {
4935 mCameraSoundForced = cameraSoundForced;
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07004936 cameraSoundForcedChanged = true;
Eric Laurentdd45d012012-10-08 09:04:34 -07004937 }
4938 }
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07004939 if (cameraSoundForcedChanged) {
4940 if (!isPlatformTelevision()) {
4941 VolumeStreamState s = mStreamStates[AudioSystem.STREAM_SYSTEM_ENFORCED];
4942 if (cameraSoundForced) {
4943 s.setAllIndexesToMax();
4944 mRingerModeAffectedStreams &=
4945 ~(1 << AudioSystem.STREAM_SYSTEM_ENFORCED);
4946 } else {
4947 s.setAllIndexes(mStreamStates[AudioSystem.STREAM_SYSTEM]);
4948 mRingerModeAffectedStreams |=
4949 (1 << AudioSystem.STREAM_SYSTEM_ENFORCED);
4950 }
4951 // take new state into account for streams muted by ringer mode
John Spurlock661f2cf2014-11-17 10:29:10 -05004952 setRingerModeInt(getRingerModeInternal(), false);
Eric Laurent8fa4d6f2014-10-30 14:13:03 -07004953 }
4954
4955 sendMsg(mAudioHandler,
4956 MSG_SET_FORCE_USE,
4957 SENDMSG_QUEUE,
4958 AudioSystem.FOR_SYSTEM,
4959 cameraSoundForced ?
4960 AudioSystem.FORCE_SYSTEM_ENFORCED : AudioSystem.FORCE_NONE,
4961 null,
4962 0);
4963
4964 sendMsg(mAudioHandler,
4965 MSG_SET_ALL_VOLUMES,
4966 SENDMSG_QUEUE,
4967 0,
4968 0,
4969 mStreamStates[AudioSystem.STREAM_SYSTEM_ENFORCED], 0);
4970 }
Eric Laurentdd45d012012-10-08 09:04:34 -07004971 }
John Spurlock3346a802014-05-20 16:25:37 -04004972 mVolumeController.setLayoutDirection(config.getLayoutDirection());
Jean-Michel Trivif26f0172012-04-25 16:23:20 -07004973 } catch (Exception e) {
Jean-Michel Trivibb6f8712013-05-23 15:02:41 -07004974 Log.e(TAG, "Error handling configuration change: ", e);
Jean-Michel Trivif26f0172012-04-25 16:23:20 -07004975 }
4976 }
4977
4978 private void setOrientationForAudioSystem() {
4979 switch (mDeviceOrientation) {
4980 case Configuration.ORIENTATION_LANDSCAPE:
4981 //Log.i(TAG, "orientation is landscape");
4982 AudioSystem.setParameters("orientation=landscape");
4983 break;
4984 case Configuration.ORIENTATION_PORTRAIT:
4985 //Log.i(TAG, "orientation is portrait");
4986 AudioSystem.setParameters("orientation=portrait");
4987 break;
4988 case Configuration.ORIENTATION_SQUARE:
4989 //Log.i(TAG, "orientation is square");
4990 AudioSystem.setParameters("orientation=square");
4991 break;
4992 case Configuration.ORIENTATION_UNDEFINED:
4993 //Log.i(TAG, "orientation is undefined");
4994 AudioSystem.setParameters("orientation=undefined");
4995 break;
4996 default:
4997 Log.e(TAG, "Unknown orientation");
4998 }
4999 }
5000
Jean-Michel Trivibb6f8712013-05-23 15:02:41 -07005001 private void setRotationForAudioSystem() {
5002 switch (mDeviceRotation) {
5003 case Surface.ROTATION_0:
5004 AudioSystem.setParameters("rotation=0");
5005 break;
5006 case Surface.ROTATION_90:
5007 AudioSystem.setParameters("rotation=90");
5008 break;
5009 case Surface.ROTATION_180:
5010 AudioSystem.setParameters("rotation=180");
5011 break;
5012 case Surface.ROTATION_270:
5013 AudioSystem.setParameters("rotation=270");
5014 break;
5015 default:
5016 Log.e(TAG, "Unknown device rotation");
5017 }
5018 }
5019
Jean-Michel Trivif26f0172012-04-25 16:23:20 -07005020
Eric Laurent78472112012-05-21 08:57:21 -07005021 // Handles request to override default use of A2DP for media.
Jean-Michel Trivi7e2f3712015-01-12 11:01:55 -08005022 // Must be called synchronized on mConnectedDevices
Eric Laurent78472112012-05-21 08:57:21 -07005023 public void setBluetoothA2dpOnInt(boolean on) {
5024 synchronized (mBluetoothA2dpEnabledLock) {
5025 mBluetoothA2dpEnabled = on;
Eric Laurentc390bed2012-07-03 12:24:05 -07005026 mAudioHandler.removeMessages(MSG_SET_FORCE_BT_A2DP_USE);
Jean-Michel Trivi7e2f3712015-01-12 11:01:55 -08005027 setForceUseInt_SyncDevices(AudioSystem.FOR_MEDIA,
Eric Laurentc390bed2012-07-03 12:24:05 -07005028 mBluetoothA2dpEnabled ? AudioSystem.FORCE_NONE : AudioSystem.FORCE_NO_BT_A2DP);
Eric Laurent78472112012-05-21 08:57:21 -07005029 }
5030 }
5031
Jean-Michel Trivi7e2f3712015-01-12 11:01:55 -08005032 // Must be called synchronized on mConnectedDevices
5033 private void setForceUseInt_SyncDevices(int usage, int config) {
5034 switch (usage) {
5035 case AudioSystem.FOR_MEDIA:
5036 if (config == AudioSystem.FORCE_NO_BT_A2DP) {
5037 mBecomingNoisyIntentDevices &= ~AudioSystem.DEVICE_OUT_ALL_A2DP;
5038 } else { // config == AudioSystem.FORCE_NONE
5039 mBecomingNoisyIntentDevices |= AudioSystem.DEVICE_OUT_ALL_A2DP;
5040 }
5041 break;
5042 case AudioSystem.FOR_DOCK:
5043 if (config == AudioSystem.FORCE_ANALOG_DOCK) {
5044 mBecomingNoisyIntentDevices |= AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET;
5045 } else { // config == AudioSystem.FORCE_NONE
5046 mBecomingNoisyIntentDevices &= ~AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET;
5047 }
5048 break;
5049 default:
5050 // usage doesn't affect the broadcast of ACTION_AUDIO_BECOMING_NOISY
5051 }
5052 AudioSystem.setForceUse(usage, config);
5053 }
5054
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08005055 @Override
Jeff Sharkey098d5802012-04-26 17:30:34 -07005056 public void setRingtonePlayer(IRingtonePlayer player) {
5057 mContext.enforceCallingOrSelfPermission(REMOTE_AUDIO_PLAYBACK, null);
5058 mRingtonePlayer = player;
5059 }
5060
5061 @Override
5062 public IRingtonePlayer getRingtonePlayer() {
5063 return mRingtonePlayer;
5064 }
5065
5066 @Override
Dianne Hackborn632ca412012-06-14 19:34:10 -07005067 public AudioRoutesInfo startWatchingRoutes(IAudioRoutesObserver observer) {
5068 synchronized (mCurAudioRoutes) {
5069 AudioRoutesInfo routes = new AudioRoutesInfo(mCurAudioRoutes);
5070 mRoutesObservers.register(observer);
5071 return routes;
5072 }
5073 }
5074
Eric Laurentc34dcc12012-09-10 13:51:52 -07005075
5076 //==========================================================================================
5077 // Safe media volume management.
5078 // MUSIC stream volume level is limited when headphones are connected according to safety
5079 // regulation. When the user attempts to raise the volume above the limit, a warning is
5080 // displayed and the user has to acknowlegde before the volume is actually changed.
5081 // The volume index corresponding to the limit is stored in config_safe_media_volume_index
5082 // property. Platforms with a different limit must set this property accordingly in their
5083 // overlay.
5084 //==========================================================================================
5085
Eric Laurentd640bd32012-09-28 18:01:48 -07005086 // mSafeMediaVolumeState indicates whether the media volume is limited over headphones.
5087 // It is SAFE_MEDIA_VOLUME_NOT_CONFIGURED at boot time until a network service is connected
5088 // or the configure time is elapsed. It is then set to SAFE_MEDIA_VOLUME_ACTIVE or
5089 // SAFE_MEDIA_VOLUME_DISABLED according to country option. If not SAFE_MEDIA_VOLUME_DISABLED, it
5090 // can be set to SAFE_MEDIA_VOLUME_INACTIVE by calling AudioService.disableSafeMediaVolume()
5091 // (when user opts out).
John Spurlock35134602014-07-24 18:10:48 -04005092 private static final int SAFE_MEDIA_VOLUME_NOT_CONFIGURED = 0;
5093 private static final int SAFE_MEDIA_VOLUME_DISABLED = 1;
5094 private static final int SAFE_MEDIA_VOLUME_INACTIVE = 2; // confirmed
5095 private static final int SAFE_MEDIA_VOLUME_ACTIVE = 3; // unconfirmed
Eric Laurentd640bd32012-09-28 18:01:48 -07005096 private Integer mSafeMediaVolumeState;
5097
5098 private int mMcc = 0;
Eric Laurentc34dcc12012-09-10 13:51:52 -07005099 // mSafeMediaVolumeIndex is the cached value of config_safe_media_volume_index property
Eric Laurentd640bd32012-09-28 18:01:48 -07005100 private int mSafeMediaVolumeIndex;
Eric Laurentc34dcc12012-09-10 13:51:52 -07005101 // mSafeMediaVolumeDevices lists the devices for which safe media volume is enforced,
5102 private final int mSafeMediaVolumeDevices = AudioSystem.DEVICE_OUT_WIRED_HEADSET |
5103 AudioSystem.DEVICE_OUT_WIRED_HEADPHONE;
5104 // mMusicActiveMs is the cumulative time of music activity since safe volume was disabled.
5105 // When this time reaches UNSAFE_VOLUME_MUSIC_ACTIVE_MS_MAX, the safe media volume is re-enabled
5106 // automatically. mMusicActiveMs is rounded to a multiple of MUSIC_ACTIVE_POLL_PERIOD_MS.
5107 private int mMusicActiveMs;
5108 private static final int UNSAFE_VOLUME_MUSIC_ACTIVE_MS_MAX = (20 * 3600 * 1000); // 20 hours
5109 private static final int MUSIC_ACTIVE_POLL_PERIOD_MS = 60000; // 1 minute polling interval
Eric Laurentd640bd32012-09-28 18:01:48 -07005110 private static final int SAFE_VOLUME_CONFIGURE_TIMEOUT_MS = 30000; // 30s after boot completed
Eric Laurentc34dcc12012-09-10 13:51:52 -07005111
5112 private void setSafeMediaVolumeEnabled(boolean on) {
Eric Laurentd640bd32012-09-28 18:01:48 -07005113 synchronized (mSafeMediaVolumeState) {
5114 if ((mSafeMediaVolumeState != SAFE_MEDIA_VOLUME_NOT_CONFIGURED) &&
5115 (mSafeMediaVolumeState != SAFE_MEDIA_VOLUME_DISABLED)) {
5116 if (on && (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_INACTIVE)) {
5117 mSafeMediaVolumeState = SAFE_MEDIA_VOLUME_ACTIVE;
5118 enforceSafeMediaVolume();
5119 } else if (!on && (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_ACTIVE)) {
5120 mSafeMediaVolumeState = SAFE_MEDIA_VOLUME_INACTIVE;
John Spurlockaa5ee4d2014-07-25 13:05:12 -04005121 mMusicActiveMs = 1; // nonzero = confirmed
5122 saveMusicActiveMs();
Eric Laurentd640bd32012-09-28 18:01:48 -07005123 sendMsg(mAudioHandler,
5124 MSG_CHECK_MUSIC_ACTIVE,
5125 SENDMSG_REPLACE,
5126 0,
5127 0,
5128 null,
5129 MUSIC_ACTIVE_POLL_PERIOD_MS);
5130 }
Eric Laurentc34dcc12012-09-10 13:51:52 -07005131 }
Eric Laurentc34dcc12012-09-10 13:51:52 -07005132 }
5133 }
5134
5135 private void enforceSafeMediaVolume() {
5136 VolumeStreamState streamState = mStreamStates[AudioSystem.STREAM_MUSIC];
Eric Laurentc34dcc12012-09-10 13:51:52 -07005137 int devices = mSafeMediaVolumeDevices;
5138 int i = 0;
5139
5140 while (devices != 0) {
5141 int device = 1 << i++;
5142 if ((device & devices) == 0) {
5143 continue;
5144 }
Eric Laurent42b041e2013-03-29 11:36:03 -07005145 int index = streamState.getIndex(device);
Eric Laurentc34dcc12012-09-10 13:51:52 -07005146 if (index > mSafeMediaVolumeIndex) {
Eric Laurent42b041e2013-03-29 11:36:03 -07005147 streamState.setIndex(mSafeMediaVolumeIndex, device);
5148 sendMsg(mAudioHandler,
5149 MSG_SET_DEVICE_VOLUME,
5150 SENDMSG_QUEUE,
5151 device,
5152 0,
5153 streamState,
5154 0);
Eric Laurentc34dcc12012-09-10 13:51:52 -07005155 }
5156 devices &= ~device;
5157 }
5158 }
5159
5160 private boolean checkSafeMediaVolume(int streamType, int index, int device) {
Eric Laurentd640bd32012-09-28 18:01:48 -07005161 synchronized (mSafeMediaVolumeState) {
5162 if ((mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_ACTIVE) &&
Eric Laurentc34dcc12012-09-10 13:51:52 -07005163 (mStreamVolumeAlias[streamType] == AudioSystem.STREAM_MUSIC) &&
5164 ((device & mSafeMediaVolumeDevices) != 0) &&
5165 (index > mSafeMediaVolumeIndex)) {
Eric Laurentc34dcc12012-09-10 13:51:52 -07005166 return false;
5167 }
5168 return true;
5169 }
5170 }
5171
John Spurlock3346a802014-05-20 16:25:37 -04005172 @Override
Eric Laurentc34dcc12012-09-10 13:51:52 -07005173 public void disableSafeMediaVolume() {
John Spurlockcdb57ae2015-02-11 19:04:11 -05005174 enforceVolumeController("disable the safe media volume");
Eric Laurentd640bd32012-09-28 18:01:48 -07005175 synchronized (mSafeMediaVolumeState) {
Eric Laurentc34dcc12012-09-10 13:51:52 -07005176 setSafeMediaVolumeEnabled(false);
Eric Laurentfde16d52012-12-03 14:42:39 -08005177 if (mPendingVolumeCommand != null) {
5178 onSetStreamVolume(mPendingVolumeCommand.mStreamType,
5179 mPendingVolumeCommand.mIndex,
5180 mPendingVolumeCommand.mFlags,
5181 mPendingVolumeCommand.mDevice);
5182 mPendingVolumeCommand = null;
5183 }
Eric Laurentc34dcc12012-09-10 13:51:52 -07005184 }
5185 }
5186
Jungshik Jang41d97462014-06-30 22:26:29 +09005187 //==========================================================================================
5188 // Hdmi Cec system audio mode.
John Spurlockbc82b122015-03-02 16:12:38 -05005189 // If Hdmi Cec's system audio mode is on, audio service should send the volume change
5190 // to HdmiControlService so that the audio receiver can handle it.
Jungshik Jang41d97462014-06-30 22:26:29 +09005191 //==========================================================================================
5192
Eric Laurent212532b2014-07-21 15:43:18 -07005193 private class MyDisplayStatusCallback implements HdmiPlaybackClient.DisplayStatusCallback {
5194 public void onComplete(int status) {
5195 if (mHdmiManager != null) {
5196 synchronized (mHdmiManager) {
5197 mHdmiCecSink = (status != HdmiControlManager.POWER_STATUS_UNKNOWN);
5198 // Television devices without CEC service apply software volume on HDMI output
5199 if (isPlatformTelevision() && !mHdmiCecSink) {
5200 mFixedVolumeDevices &= ~AudioSystem.DEVICE_OUT_HDMI;
5201 }
5202 checkAllFixedVolumeDevices();
5203 }
5204 }
5205 }
5206 };
5207
Jungshik Jang41d97462014-06-30 22:26:29 +09005208 // If HDMI-CEC system audio is supported
5209 private boolean mHdmiSystemAudioSupported = false;
5210 // Set only when device is tv.
5211 private HdmiTvClient mHdmiTvClient;
Eric Laurent0b03f992014-11-18 18:08:02 -08005212 // true if the device has system feature PackageManager.FEATURE_LEANBACK.
Eric Laurent212532b2014-07-21 15:43:18 -07005213 // cached HdmiControlManager interface
5214 private HdmiControlManager mHdmiManager;
5215 // Set only when device is a set-top box.
5216 private HdmiPlaybackClient mHdmiPlaybackClient;
5217 // true if we are a set-top box, an HDMI sink is connected and it supports CEC.
5218 private boolean mHdmiCecSink;
5219
5220 private MyDisplayStatusCallback mHdmiDisplayStatusCallback = new MyDisplayStatusCallback();
Jungshik Jang41d97462014-06-30 22:26:29 +09005221
5222 @Override
Jungshik Jang12307ca2014-07-15 19:27:56 +09005223 public int setHdmiSystemAudioSupported(boolean on) {
Eric Laurent212532b2014-07-21 15:43:18 -07005224 int device = AudioSystem.DEVICE_NONE;
5225 if (mHdmiManager != null) {
5226 synchronized (mHdmiManager) {
5227 if (mHdmiTvClient == null) {
5228 Log.w(TAG, "Only Hdmi-Cec enabled TV device supports system audio mode.");
5229 return device;
5230 }
Jungshik Jang41d97462014-06-30 22:26:29 +09005231
Eric Laurent212532b2014-07-21 15:43:18 -07005232 synchronized (mHdmiTvClient) {
5233 if (mHdmiSystemAudioSupported != on) {
5234 mHdmiSystemAudioSupported = on;
5235 AudioSystem.setForceUse(AudioSystem.FOR_HDMI_SYSTEM_AUDIO,
5236 on ? AudioSystem.FORCE_HDMI_SYSTEM_AUDIO_ENFORCED :
5237 AudioSystem.FORCE_NONE);
5238 }
5239 device = AudioSystem.getDevicesForStream(AudioSystem.STREAM_MUSIC);
5240 }
Jungshik Jang6f34f5a2014-07-08 21:17:29 +09005241 }
Jungshik Jang6f34f5a2014-07-08 21:17:29 +09005242 }
Eric Laurent212532b2014-07-21 15:43:18 -07005243 return device;
Jungshik Jang6f34f5a2014-07-08 21:17:29 +09005244 }
Jungshik Jang41d97462014-06-30 22:26:29 +09005245
Terry Heoe7d6d972014-09-04 21:05:28 +09005246 @Override
5247 public boolean isHdmiSystemAudioSupported() {
5248 return mHdmiSystemAudioSupported;
5249 }
5250
Eric Laurentdd45d012012-10-08 09:04:34 -07005251 //==========================================================================================
Jean-Michel Trivi873cc452014-09-11 17:25:09 -07005252 // Accessibility: taking touch exploration into account for selecting the default
5253 // stream override timeout when adjusting volume
5254 //==========================================================================================
5255 private static class StreamOverride
5256 implements AccessibilityManager.TouchExplorationStateChangeListener {
5257
5258 // AudioService.getActiveStreamType() will return:
5259 // - STREAM_NOTIFICATION on tablets during this period after a notification stopped
5260 // - STREAM_MUSIC on phones during this period after music or talkback/voice search prompt
5261 // stopped
5262 private static final int DEFAULT_STREAM_TYPE_OVERRIDE_DELAY_MS = 5000;
5263 private static final int TOUCH_EXPLORE_STREAM_TYPE_OVERRIDE_DELAY_MS = 1000;
5264
5265 static int sDelayMs;
5266
5267 static void init(Context ctxt) {
5268 AccessibilityManager accessibilityManager =
5269 (AccessibilityManager) ctxt.getSystemService(Context.ACCESSIBILITY_SERVICE);
5270 updateDefaultStreamOverrideDelay(
5271 accessibilityManager.isTouchExplorationEnabled());
5272 accessibilityManager.addTouchExplorationStateChangeListener(
5273 new StreamOverride());
5274 }
5275
5276 @Override
5277 public void onTouchExplorationStateChanged(boolean enabled) {
5278 updateDefaultStreamOverrideDelay(enabled);
5279 }
5280
5281 private static void updateDefaultStreamOverrideDelay(boolean touchExploreEnabled) {
5282 if (touchExploreEnabled) {
5283 sDelayMs = TOUCH_EXPLORE_STREAM_TYPE_OVERRIDE_DELAY_MS;
5284 } else {
5285 sDelayMs = DEFAULT_STREAM_TYPE_OVERRIDE_DELAY_MS;
5286 }
5287 if (DEBUG_VOL) Log.d(TAG, "Touch exploration enabled=" + touchExploreEnabled
5288 + " stream override delay is now " + sDelayMs + " ms");
5289 }
5290 }
5291
5292 //==========================================================================================
Eric Laurentdd45d012012-10-08 09:04:34 -07005293 // Camera shutter sound policy.
5294 // config_camera_sound_forced configuration option in config.xml defines if the camera shutter
5295 // sound is forced (sound even if the device is in silent mode) or not. This option is false by
5296 // default and can be overridden by country specific overlay in values-mccXXX/config.xml.
5297 //==========================================================================================
5298
5299 // cached value of com.android.internal.R.bool.config_camera_sound_forced
5300 private Boolean mCameraSoundForced;
5301
5302 // called by android.hardware.Camera to populate CameraInfo.canDisableShutterSound
5303 public boolean isCameraSoundForced() {
5304 synchronized (mCameraSoundForced) {
5305 return mCameraSoundForced;
5306 }
5307 }
5308
5309 private static final String[] RINGER_MODE_NAMES = new String[] {
5310 "SILENT",
5311 "VIBRATE",
5312 "NORMAL"
5313 };
5314
5315 private void dumpRingerMode(PrintWriter pw) {
5316 pw.println("\nRinger mode: ");
John Spurlock661f2cf2014-11-17 10:29:10 -05005317 pw.println("- mode (internal) = " + RINGER_MODE_NAMES[mRingerMode]);
5318 pw.println("- mode (external) = " + RINGER_MODE_NAMES[mRingerModeExternal]);
Eric Laurentdd45d012012-10-08 09:04:34 -07005319 pw.print("- ringer mode affected streams = 0x");
5320 pw.println(Integer.toHexString(mRingerModeAffectedStreams));
5321 pw.print("- ringer mode muted streams = 0x");
5322 pw.println(Integer.toHexString(mRingerModeMutedStreams));
John Spurlock661f2cf2014-11-17 10:29:10 -05005323 pw.print("- delegate = "); pw.println(mRingerModeDelegate);
Eric Laurentdd45d012012-10-08 09:04:34 -07005324 }
5325
Dianne Hackborn632ca412012-06-14 19:34:10 -07005326 @Override
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08005327 protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
Jeff Sharkeyeb4cc4922012-04-26 18:17:29 -07005328 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DUMP, TAG);
5329
Jean-Michel Trivifa9a6982013-06-27 16:22:58 -07005330 mMediaFocusControl.dump(pw);
Eric Laurentbffc3d12012-05-07 17:43:49 -07005331 dumpStreamStates(pw);
Eric Laurentdd45d012012-10-08 09:04:34 -07005332 dumpRingerMode(pw);
Dianne Hackborn632ca412012-06-14 19:34:10 -07005333 pw.println("\nAudio routes:");
John Spurlock61560172015-02-06 19:46:04 -05005334 pw.print(" mMainType=0x"); pw.println(Integer.toHexString(mCurAudioRoutes.mainType));
5335 pw.print(" mBluetoothName="); pw.println(mCurAudioRoutes.bluetoothName);
John Spurlock35134602014-07-24 18:10:48 -04005336
5337 pw.println("\nOther state:");
John Spurlock3346a802014-05-20 16:25:37 -04005338 pw.print(" mVolumeController="); pw.println(mVolumeController);
John Spurlock35134602014-07-24 18:10:48 -04005339 pw.print(" mSafeMediaVolumeState=");
5340 pw.println(safeMediaVolumeStateToString(mSafeMediaVolumeState));
5341 pw.print(" mSafeMediaVolumeIndex="); pw.println(mSafeMediaVolumeIndex);
5342 pw.print(" mPendingVolumeCommand="); pw.println(mPendingVolumeCommand);
5343 pw.print(" mMusicActiveMs="); pw.println(mMusicActiveMs);
John Spurlockaa5ee4d2014-07-25 13:05:12 -04005344 pw.print(" mMcc="); pw.println(mMcc);
John Spurlock5e783732015-02-19 10:28:59 -05005345 pw.print(" mCameraSoundForced="); pw.println(mCameraSoundForced);
John Spurlock661f2cf2014-11-17 10:29:10 -05005346 pw.print(" mHasVibrator="); pw.println(mHasVibrator);
John Spurlockcdb57ae2015-02-11 19:04:11 -05005347 pw.print(" mControllerService="); pw.println(mControllerService);
Jean-Michel Trivi1b3541d2014-11-25 12:53:41 -08005348
5349 dumpAudioPolicies(pw);
John Spurlock35134602014-07-24 18:10:48 -04005350 }
5351
5352 private static String safeMediaVolumeStateToString(Integer state) {
5353 switch(state) {
5354 case SAFE_MEDIA_VOLUME_NOT_CONFIGURED: return "SAFE_MEDIA_VOLUME_NOT_CONFIGURED";
5355 case SAFE_MEDIA_VOLUME_DISABLED: return "SAFE_MEDIA_VOLUME_DISABLED";
5356 case SAFE_MEDIA_VOLUME_INACTIVE: return "SAFE_MEDIA_VOLUME_INACTIVE";
5357 case SAFE_MEDIA_VOLUME_ACTIVE: return "SAFE_MEDIA_VOLUME_ACTIVE";
5358 }
5359 return null;
Jean-Michel Trivid5176cf2010-01-28 11:56:42 -08005360 }
Glenn Kastenfd116ad2013-07-12 17:10:39 -07005361
5362 // Inform AudioFlinger of our device's low RAM attribute
5363 private static void readAndSetLowRamDevice()
5364 {
5365 int status = AudioSystem.setLowRamDevice(ActivityManager.isLowRamDeviceStatic());
5366 if (status != 0) {
5367 Log.w(TAG, "AudioFlinger informed of device's low RAM attribute; status " + status);
5368 }
5369 }
John Spurlock3346a802014-05-20 16:25:37 -04005370
John Spurlockcdb57ae2015-02-11 19:04:11 -05005371 private void enforceVolumeController(String action) {
5372 if (mControllerService.mUid != 0 && Binder.getCallingUid() == mControllerService.mUid) {
5373 return;
5374 }
John Spurlock3346a802014-05-20 16:25:37 -04005375 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.STATUS_BAR_SERVICE,
5376 "Only SystemUI can " + action);
5377 }
5378
5379 @Override
5380 public void setVolumeController(final IVolumeController controller) {
John Spurlockcdb57ae2015-02-11 19:04:11 -05005381 enforceVolumeController("set the volume controller");
John Spurlock3346a802014-05-20 16:25:37 -04005382
5383 // return early if things are not actually changing
5384 if (mVolumeController.isSameBinder(controller)) {
5385 return;
5386 }
5387
5388 // dismiss the old volume controller
5389 mVolumeController.postDismiss();
5390 if (controller != null) {
5391 // we are about to register a new controller, listen for its death
5392 try {
5393 controller.asBinder().linkToDeath(new DeathRecipient() {
5394 @Override
5395 public void binderDied() {
5396 if (mVolumeController.isSameBinder(controller)) {
5397 Log.w(TAG, "Current remote volume controller died, unregistering");
5398 setVolumeController(null);
5399 }
5400 }
5401 }, 0);
5402 } catch (RemoteException e) {
5403 // noop
5404 }
5405 }
5406 mVolumeController.setController(controller);
John Spurlock33f4e042014-07-11 13:10:58 -04005407 if (DEBUG_VOL) Log.d(TAG, "Volume controller: " + mVolumeController);
5408 }
5409
5410 @Override
5411 public void notifyVolumeControllerVisible(final IVolumeController controller, boolean visible) {
John Spurlockcdb57ae2015-02-11 19:04:11 -05005412 enforceVolumeController("notify about volume controller visibility");
John Spurlock33f4e042014-07-11 13:10:58 -04005413
5414 // return early if the controller is not current
5415 if (!mVolumeController.isSameBinder(controller)) {
5416 return;
5417 }
5418
5419 mVolumeController.setVisible(visible);
5420 if (DEBUG_VOL) Log.d(TAG, "Volume controller visible: " + visible);
John Spurlock3346a802014-05-20 16:25:37 -04005421 }
RoboErikd09bd0c2014-06-24 17:45:19 -07005422
5423 public static class VolumeController {
5424 private static final String TAG = "VolumeController";
5425
5426 private IVolumeController mController;
John Spurlock33f4e042014-07-11 13:10:58 -04005427 private boolean mVisible;
5428 private long mNextLongPress;
5429 private int mLongPressTimeout;
RoboErikd09bd0c2014-06-24 17:45:19 -07005430
5431 public void setController(IVolumeController controller) {
5432 mController = controller;
John Spurlock33f4e042014-07-11 13:10:58 -04005433 mVisible = false;
5434 }
5435
5436 public void loadSettings(ContentResolver cr) {
5437 mLongPressTimeout = Settings.Secure.getIntForUser(cr,
5438 Settings.Secure.LONG_PRESS_TIMEOUT, 500, UserHandle.USER_CURRENT);
5439 }
5440
RoboErik4197cb62015-01-21 15:45:32 -08005441 public boolean suppressAdjustment(int resolvedStream, int flags, boolean isMute) {
5442 if (isMute) {
5443 return false;
5444 }
John Spurlock33f4e042014-07-11 13:10:58 -04005445 boolean suppress = false;
5446 if (resolvedStream == AudioSystem.STREAM_RING && mController != null) {
5447 final long now = SystemClock.uptimeMillis();
5448 if ((flags & AudioManager.FLAG_SHOW_UI) != 0 && !mVisible) {
5449 // ui will become visible
5450 if (mNextLongPress < now) {
5451 mNextLongPress = now + mLongPressTimeout;
5452 }
5453 suppress = true;
5454 } else if (mNextLongPress > 0) { // in a long-press
5455 if (now > mNextLongPress) {
5456 // long press triggered, no more suppression
5457 mNextLongPress = 0;
5458 } else {
5459 // keep suppressing until the long press triggers
5460 suppress = true;
5461 }
5462 }
5463 }
5464 return suppress;
5465 }
5466
5467 public void setVisible(boolean visible) {
5468 mVisible = visible;
RoboErikd09bd0c2014-06-24 17:45:19 -07005469 }
5470
5471 public boolean isSameBinder(IVolumeController controller) {
5472 return Objects.equals(asBinder(), binder(controller));
5473 }
5474
5475 public IBinder asBinder() {
5476 return binder(mController);
5477 }
5478
5479 private static IBinder binder(IVolumeController controller) {
5480 return controller == null ? null : controller.asBinder();
5481 }
5482
5483 @Override
5484 public String toString() {
John Spurlock33f4e042014-07-11 13:10:58 -04005485 return "VolumeController(" + asBinder() + ",mVisible=" + mVisible + ")";
RoboErikd09bd0c2014-06-24 17:45:19 -07005486 }
5487
5488 public void postDisplaySafeVolumeWarning(int flags) {
5489 if (mController == null)
5490 return;
5491 try {
5492 mController.displaySafeVolumeWarning(flags);
5493 } catch (RemoteException e) {
5494 Log.w(TAG, "Error calling displaySafeVolumeWarning", e);
5495 }
5496 }
5497
5498 public void postVolumeChanged(int streamType, int flags) {
5499 if (mController == null)
5500 return;
5501 try {
5502 mController.volumeChanged(streamType, flags);
5503 } catch (RemoteException e) {
5504 Log.w(TAG, "Error calling volumeChanged", e);
5505 }
5506 }
5507
RoboErikd09bd0c2014-06-24 17:45:19 -07005508 public void postMasterMuteChanged(int flags) {
5509 if (mController == null)
5510 return;
5511 try {
5512 mController.masterMuteChanged(flags);
5513 } catch (RemoteException e) {
5514 Log.w(TAG, "Error calling masterMuteChanged", e);
5515 }
5516 }
5517
5518 public void setLayoutDirection(int layoutDirection) {
5519 if (mController == null)
5520 return;
5521 try {
5522 mController.setLayoutDirection(layoutDirection);
5523 } catch (RemoteException e) {
5524 Log.w(TAG, "Error calling setLayoutDirection", e);
5525 }
5526 }
5527
5528 public void postDismiss() {
5529 if (mController == null)
5530 return;
5531 try {
5532 mController.dismiss();
5533 } catch (RemoteException e) {
5534 Log.w(TAG, "Error calling dismiss", e);
5535 }
5536 }
5537 }
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07005538
RoboErik0dac35a2014-08-12 15:48:49 -07005539 /**
5540 * Interface for system components to get some extra functionality through
5541 * LocalServices.
5542 */
5543 final class AudioServiceInternal extends AudioManagerInternal {
John Spurlock661f2cf2014-11-17 10:29:10 -05005544 @Override
5545 public void setRingerModeDelegate(RingerModeDelegate delegate) {
5546 mRingerModeDelegate = delegate;
5547 if (mRingerModeDelegate != null) {
5548 setRingerModeInternal(getRingerModeInternal(), TAG + ".setRingerModeDelegate");
5549 }
5550 }
RoboErik272e1612014-09-05 11:39:29 -07005551
5552 @Override
5553 public void adjustSuggestedStreamVolumeForUid(int streamType, int direction, int flags,
5554 String callingPackage, int uid) {
5555 // direction and stream type swap here because the public
5556 // adjustSuggested has a different order than the other methods.
5557 adjustSuggestedStreamVolume(direction, streamType, flags, callingPackage, uid);
5558 }
5559
RoboErik0dac35a2014-08-12 15:48:49 -07005560 @Override
5561 public void adjustStreamVolumeForUid(int streamType, int direction, int flags,
5562 String callingPackage, int uid) {
5563 adjustStreamVolume(streamType, direction, flags, callingPackage, uid);
5564 }
5565
5566 @Override
5567 public void setStreamVolumeForUid(int streamType, int direction, int flags,
5568 String callingPackage, int uid) {
5569 setStreamVolume(streamType, direction, flags, callingPackage, uid);
5570 }
RoboErik519c7742014-11-18 10:59:09 -08005571
5572 @Override
John Spurlock661f2cf2014-11-17 10:29:10 -05005573 public int getRingerModeInternal() {
5574 return AudioService.this.getRingerModeInternal();
5575 }
5576
5577 @Override
5578 public void setRingerModeInternal(int ringerMode, String caller) {
5579 AudioService.this.setRingerModeInternal(ringerMode, caller);
5580 }
John Spurlockcdb57ae2015-02-11 19:04:11 -05005581
5582 @Override
5583 public int getVolumeControllerUid() {
5584 return mControllerService.mUid;
5585 }
RoboErik0dac35a2014-08-12 15:48:49 -07005586 }
5587
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07005588 //==========================================================================================
5589 // Audio policy management
5590 //==========================================================================================
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08005591 public String registerAudioPolicy(AudioPolicyConfig policyConfig, IAudioPolicyCallback pcb,
5592 boolean hasFocusListener) {
5593 if (DEBUG_AP) Log.d(TAG, "registerAudioPolicy for " + pcb.asBinder()
5594 + " with config:" + policyConfig);
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07005595 String regId = null;
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08005596 // error handling
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07005597 boolean hasPermissionForPolicy =
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08005598 (PackageManager.PERMISSION_GRANTED == mContext.checkCallingPermission(
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07005599 android.Manifest.permission.MODIFY_AUDIO_ROUTING));
5600 if (!hasPermissionForPolicy) {
5601 Slog.w(TAG, "Can't register audio policy for pid " + Binder.getCallingPid() + " / uid "
5602 + Binder.getCallingUid() + ", need MODIFY_AUDIO_ROUTING");
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07005603 return null;
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07005604 }
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08005605
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07005606 synchronized (mAudioPolicies) {
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07005607 try {
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08005608 if (mAudioPolicies.containsKey(pcb.asBinder())) {
Jean-Michel Trivi1b3541d2014-11-25 12:53:41 -08005609 Slog.e(TAG, "Cannot re-register policy");
5610 return null;
5611 }
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08005612 AudioPolicyProxy app = new AudioPolicyProxy(policyConfig, pcb, hasFocusListener);
5613 pcb.asBinder().linkToDeath(app, 0/*flags*/);
5614 regId = app.getRegistrationId();
5615 mAudioPolicies.put(pcb.asBinder(), app);
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07005616 } catch (RemoteException e) {
5617 // audio policy owner has already died!
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08005618 Slog.w(TAG, "Audio policy registration failed, could not link to " + pcb +
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07005619 " binder death", e);
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07005620 return null;
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07005621 }
5622 }
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07005623 return regId;
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07005624 }
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07005625
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08005626 public void unregisterAudioPolicyAsync(IAudioPolicyCallback pcb) {
5627 if (DEBUG_AP) Log.d(TAG, "unregisterAudioPolicyAsync for " + pcb.asBinder());
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07005628 synchronized (mAudioPolicies) {
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08005629 AudioPolicyProxy app = mAudioPolicies.remove(pcb.asBinder());
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07005630 if (app == null) {
5631 Slog.w(TAG, "Trying to unregister unknown audio policy for pid "
5632 + Binder.getCallingPid() + " / uid " + Binder.getCallingUid());
Jean-Michel Trivi1b3541d2014-11-25 12:53:41 -08005633 return;
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07005634 } else {
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08005635 pcb.asBinder().unlinkToDeath(app, 0/*flags*/);
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07005636 }
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08005637 app.release();
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07005638 }
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07005639 // TODO implement clearing mix attribute matching info in native audio policy
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07005640 }
5641
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08005642 public int setFocusPropertiesForPolicy(int duckingBehavior, IAudioPolicyCallback pcb) {
5643 if (DEBUG_AP) Log.d(TAG, "setFocusPropertiesForPolicy() duck behavior=" + duckingBehavior
5644 + " policy " + pcb.asBinder());
5645 // error handling
5646 boolean hasPermissionForPolicy =
5647 (PackageManager.PERMISSION_GRANTED == mContext.checkCallingPermission(
5648 android.Manifest.permission.MODIFY_AUDIO_ROUTING));
5649 if (!hasPermissionForPolicy) {
5650 Slog.w(TAG, "Cannot change audio policy ducking handling for pid " +
5651 + Binder.getCallingPid() + " / uid "
5652 + Binder.getCallingUid() + ", need MODIFY_AUDIO_ROUTING");
5653 return AudioManager.ERROR;
5654 }
5655
5656 synchronized (mAudioPolicies) {
5657 if (!mAudioPolicies.containsKey(pcb.asBinder())) {
5658 Slog.e(TAG, "Cannot change audio policy focus properties, unregistered policy");
5659 return AudioManager.ERROR;
5660 }
5661 final AudioPolicyProxy app = mAudioPolicies.get(pcb.asBinder());
5662 if (duckingBehavior == AudioPolicy.FOCUS_POLICY_DUCKING_IN_POLICY) {
5663 // is there already one policy managing ducking?
5664 for(AudioPolicyProxy policy : mAudioPolicies.values()) {
5665 if (policy.mFocusDuckBehavior == AudioPolicy.FOCUS_POLICY_DUCKING_IN_POLICY) {
5666 Slog.e(TAG, "Cannot change audio policy ducking behavior, already handled");
5667 return AudioManager.ERROR;
5668 }
5669 }
5670 }
5671 app.mFocusDuckBehavior = duckingBehavior;
5672 mMediaFocusControl.setDuckingInExtPolicyAvailable(
5673 duckingBehavior == AudioPolicy.FOCUS_POLICY_DUCKING_IN_POLICY);
5674 }
5675 return AudioManager.SUCCESS;
5676 }
5677
Jean-Michel Trivi1b3541d2014-11-25 12:53:41 -08005678 private void dumpAudioPolicies(PrintWriter pw) {
5679 pw.println("\nAudio policies:");
5680 synchronized (mAudioPolicies) {
5681 for(AudioPolicyProxy policy : mAudioPolicies.values()) {
5682 pw.println(policy.toLogFriendlyString());
5683 }
5684 }
5685 }
5686
Jean-Michel Trivi958876f2014-11-16 15:40:22 -08005687 //======================
5688 // Audio policy proxy
5689 //======================
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07005690 /**
Jean-Michel Trivi1b3541d2014-11-25 12:53:41 -08005691 * This internal class inherits from AudioPolicyConfig, each instance contains all the
5692 * mixes of an AudioPolicy and their configurations.
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07005693 */
5694 public class AudioPolicyProxy extends AudioPolicyConfig implements IBinder.DeathRecipient {
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07005695 private static final String TAG = "AudioPolicyProxy";
5696 AudioPolicyConfig mConfig;
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08005697 IAudioPolicyCallback mPolicyToken;
5698 boolean mHasFocusListener;
5699 /**
5700 * Audio focus ducking behavior for an audio policy.
5701 * This variable reflects the value that was successfully set in
5702 * {@link AudioService#setFocusPropertiesForPolicy(int, IAudioPolicyCallback)}. This
5703 * implies that a value of FOCUS_POLICY_DUCKING_IN_POLICY means the corresponding policy
5704 * is handling ducking for audio focus.
5705 */
5706 int mFocusDuckBehavior = AudioPolicy.FOCUS_POLICY_DUCKING_DEFAULT;
5707
5708 AudioPolicyProxy(AudioPolicyConfig config, IAudioPolicyCallback token,
5709 boolean hasFocusListener) {
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07005710 super(config);
Jean-Michel Trivi1b3541d2014-11-25 12:53:41 -08005711 setRegistration(new String(config.hashCode() + ":ap:" + mAudioPolicyCounter++));
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08005712 mPolicyToken = token;
5713 mHasFocusListener = hasFocusListener;
5714 if (mHasFocusListener) {
5715 mMediaFocusControl.addFocusFollower(mPolicyToken);
5716 }
Eric Laurent7f5eb9f2014-12-01 19:36:30 -08005717 connectMixes();
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07005718 }
5719
5720 public void binderDied() {
5721 synchronized (mAudioPolicies) {
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08005722 Log.i(TAG, "audio policy " + mPolicyToken + " died");
5723 release();
5724 mAudioPolicies.remove(mPolicyToken.asBinder());
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07005725 }
5726 }
5727
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08005728 String getRegistrationId() {
Jean-Michel Trivi1b3541d2014-11-25 12:53:41 -08005729 return getRegistration();
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07005730 }
5731
Jean-Michel Trivi0212be52014-11-24 14:43:10 -08005732 void release() {
5733 if (mFocusDuckBehavior == AudioPolicy.FOCUS_POLICY_DUCKING_IN_POLICY) {
5734 mMediaFocusControl.setDuckingInExtPolicyAvailable(false);
5735 }
5736 if (mHasFocusListener) {
5737 mMediaFocusControl.removeFocusFollower(mPolicyToken);
5738 }
Eric Laurent7f5eb9f2014-12-01 19:36:30 -08005739 AudioSystem.registerPolicyMixes(mMixes, false);
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07005740 }
5741
Eric Laurent7f5eb9f2014-12-01 19:36:30 -08005742 void connectMixes() {
5743 AudioSystem.registerPolicyMixes(mMixes, true);
Jean-Michel Trivia8b6bd82014-07-01 09:48:46 -07005744 }
5745 };
5746
5747 private HashMap<IBinder, AudioPolicyProxy> mAudioPolicies =
5748 new HashMap<IBinder, AudioPolicyProxy>();
Jean-Michel Trivi8fdb0d42014-07-16 19:08:37 -07005749 private int mAudioPolicyCounter = 0; // always accessed synchronized on mAudioPolicies
John Spurlockcdb57ae2015-02-11 19:04:11 -05005750
5751 private class ControllerService extends ContentObserver {
5752 private int mUid;
5753 private ComponentName mComponent;
5754
5755 public ControllerService() {
5756 super(null);
5757 }
5758
5759 @Override
5760 public String toString() {
5761 return String.format("{mUid=%d,mComponent=%s}", mUid, mComponent);
5762 }
5763
5764 public void init() {
5765 onChange(true);
5766 mContentResolver.registerContentObserver(Settings.Secure.getUriFor(
5767 Settings.Secure.VOLUME_CONTROLLER_SERVICE_COMPONENT), false, this);
5768 }
5769
5770 @Override
5771 public void onChange(boolean selfChange) {
5772 mUid = 0;
5773 mComponent = null;
5774 final String setting = Settings.Secure.getString(mContentResolver,
5775 Settings.Secure.VOLUME_CONTROLLER_SERVICE_COMPONENT);
5776 if (setting == null) return;
5777 try {
5778 mComponent = ComponentName.unflattenFromString(setting);
5779 if (mComponent == null) return;
5780 mUid = mContext.getPackageManager()
5781 .getApplicationInfo(mComponent.getPackageName(), 0).uid;
5782 } catch (Exception e) {
5783 Log.w(TAG, "Error loading controller service", e);
5784 }
5785 if (DEBUG_VOL) Log.d(TAG, "Reloaded controller service: " + this);
5786 }
5787 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08005788}