Home | History | Annotate | Download | only in audio
      1 /*
      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 
     17 package com.android.server.audio;
     18 
     19 import static android.Manifest.permission.REMOTE_AUDIO_PLAYBACK;
     20 import static android.media.AudioManager.RINGER_MODE_NORMAL;
     21 import static android.media.AudioManager.RINGER_MODE_SILENT;
     22 import static android.media.AudioManager.RINGER_MODE_VIBRATE;
     23 import static android.os.Process.FIRST_APPLICATION_UID;
     24 
     25 import android.Manifest;
     26 import android.app.ActivityManager;
     27 import android.app.ActivityManagerInternal;
     28 import android.app.ActivityManagerNative;
     29 import android.app.AppGlobals;
     30 import android.app.AppOpsManager;
     31 import android.app.KeyguardManager;
     32 import android.bluetooth.BluetoothA2dp;
     33 import android.bluetooth.BluetoothAdapter;
     34 import android.bluetooth.BluetoothClass;
     35 import android.bluetooth.BluetoothDevice;
     36 import android.bluetooth.BluetoothHeadset;
     37 import android.bluetooth.BluetoothProfile;
     38 import android.content.BroadcastReceiver;
     39 import android.content.ComponentName;
     40 import android.content.ContentResolver;
     41 import android.content.Context;
     42 import android.content.Intent;
     43 import android.content.IntentFilter;
     44 import android.content.pm.PackageInfo;
     45 import android.content.pm.PackageManager;
     46 import android.content.pm.UserInfo;
     47 import android.content.res.Configuration;
     48 import android.content.res.Resources;
     49 import android.content.res.XmlResourceParser;
     50 import android.database.ContentObserver;
     51 import android.hardware.hdmi.HdmiControlManager;
     52 import android.hardware.hdmi.HdmiPlaybackClient;
     53 import android.hardware.hdmi.HdmiTvClient;
     54 import android.hardware.usb.UsbManager;
     55 import android.media.AudioAttributes;
     56 import android.media.AudioDevicePort;
     57 import android.media.AudioSystem;
     58 import android.media.AudioFormat;
     59 import android.media.AudioManager;
     60 import android.media.AudioManagerInternal;
     61 import android.media.AudioPort;
     62 import android.media.AudioRoutesInfo;
     63 import android.media.IAudioFocusDispatcher;
     64 import android.media.IAudioRoutesObserver;
     65 import android.media.IAudioService;
     66 import android.media.IRemoteControlDisplay;
     67 import android.media.IRingtonePlayer;
     68 import android.media.IVolumeController;
     69 import android.media.MediaPlayer;
     70 import android.media.SoundPool;
     71 import android.media.VolumePolicy;
     72 import android.media.MediaPlayer.OnCompletionListener;
     73 import android.media.MediaPlayer.OnErrorListener;
     74 import android.media.audiopolicy.AudioMix;
     75 import android.media.audiopolicy.AudioPolicy;
     76 import android.media.audiopolicy.AudioPolicyConfig;
     77 import android.media.audiopolicy.IAudioPolicyCallback;
     78 import android.os.Binder;
     79 import android.os.Build;
     80 import android.os.Environment;
     81 import android.os.Handler;
     82 import android.os.IBinder;
     83 import android.os.Looper;
     84 import android.os.Message;
     85 import android.os.PowerManager;
     86 import android.os.RemoteCallbackList;
     87 import android.os.RemoteException;
     88 import android.os.SystemClock;
     89 import android.os.SystemProperties;
     90 import android.os.UserHandle;
     91 import android.os.UserManager;
     92 import android.os.Vibrator;
     93 import android.provider.Settings;
     94 import android.provider.Settings.System;
     95 import android.telecom.TelecomManager;
     96 import android.text.TextUtils;
     97 import android.util.AndroidRuntimeException;
     98 import android.util.ArrayMap;
     99 import android.util.ArraySet;
    100 import android.util.Log;
    101 import android.util.MathUtils;
    102 import android.util.Slog;
    103 import android.util.SparseIntArray;
    104 import android.view.KeyEvent;
    105 import android.view.OrientationEventListener;
    106 import android.view.Surface;
    107 import android.view.WindowManager;
    108 import android.view.accessibility.AccessibilityManager;
    109 
    110 import com.android.internal.util.XmlUtils;
    111 import com.android.server.EventLogTags;
    112 import com.android.server.LocalServices;
    113 import com.android.server.pm.UserManagerService;
    114 
    115 import org.xmlpull.v1.XmlPullParserException;
    116 
    117 import java.io.FileDescriptor;
    118 import java.io.IOException;
    119 import java.io.PrintWriter;
    120 import java.lang.reflect.Field;
    121 import java.util.ArrayList;
    122 import java.util.HashMap;
    123 import java.util.Iterator;
    124 import java.util.List;
    125 import java.util.NoSuchElementException;
    126 import java.util.Objects;
    127 
    128 /**
    129  * The implementation of the volume manager service.
    130  * <p>
    131  * This implementation focuses on delivering a responsive UI. Most methods are
    132  * asynchronous to external calls. For example, the task of setting a volume
    133  * will update our internal state, but in a separate thread will set the system
    134  * volume and later persist to the database. Similarly, setting the ringer mode
    135  * will update the state and broadcast a change and in a separate thread later
    136  * persist the ringer mode.
    137  *
    138  * @hide
    139  */
    140 public class AudioService extends IAudioService.Stub {
    141 
    142     private static final String TAG = "AudioService";
    143 
    144     /** Debug audio mode */
    145     protected static final boolean DEBUG_MODE = Log.isLoggable(TAG + ".MOD", Log.DEBUG);
    146 
    147     /** Debug audio policy feature */
    148     protected static final boolean DEBUG_AP = Log.isLoggable(TAG + ".AP", Log.DEBUG);
    149 
    150     /** Debug volumes */
    151     protected static final boolean DEBUG_VOL = Log.isLoggable(TAG + ".VOL", Log.DEBUG);
    152 
    153     /** debug calls to devices APIs */
    154     protected static final boolean DEBUG_DEVICES = Log.isLoggable(TAG + ".DEVICES", Log.DEBUG);
    155 
    156     /** How long to delay before persisting a change in volume/ringer mode. */
    157     private static final int PERSIST_DELAY = 500;
    158 
    159     /** How long to delay after a volume down event before unmuting a stream */
    160     private static final int UNMUTE_STREAM_DELAY = 350;
    161 
    162     /**
    163      * Only used in the result from {@link #checkForRingerModeChange(int, int, int)}
    164      */
    165     private static final int FLAG_ADJUST_VOLUME = 1;
    166 
    167     private final Context mContext;
    168     private final ContentResolver mContentResolver;
    169     private final AppOpsManager mAppOps;
    170 
    171     // the platform type affects volume and silent mode behavior
    172     private final int mPlatformType;
    173 
    174     private boolean isPlatformVoice() {
    175         return mPlatformType == AudioSystem.PLATFORM_VOICE;
    176     }
    177 
    178     private boolean isPlatformTelevision() {
    179         return mPlatformType == AudioSystem.PLATFORM_TELEVISION;
    180     }
    181 
    182     /** The controller for the volume UI. */
    183     private final VolumeController mVolumeController = new VolumeController();
    184     private final ControllerService mControllerService = new ControllerService();
    185 
    186     // sendMsg() flags
    187     /** If the msg is already queued, replace it with this one. */
    188     private static final int SENDMSG_REPLACE = 0;
    189     /** If the msg is already queued, ignore this one and leave the old. */
    190     private static final int SENDMSG_NOOP = 1;
    191     /** If the msg is already queued, queue this one and leave the old. */
    192     private static final int SENDMSG_QUEUE = 2;
    193 
    194     // AudioHandler messages
    195     private static final int MSG_SET_DEVICE_VOLUME = 0;
    196     private static final int MSG_PERSIST_VOLUME = 1;
    197     private static final int MSG_PERSIST_RINGER_MODE = 3;
    198     private static final int MSG_MEDIA_SERVER_DIED = 4;
    199     private static final int MSG_PLAY_SOUND_EFFECT = 5;
    200     private static final int MSG_BTA2DP_DOCK_TIMEOUT = 6;
    201     private static final int MSG_LOAD_SOUND_EFFECTS = 7;
    202     private static final int MSG_SET_FORCE_USE = 8;
    203     private static final int MSG_BT_HEADSET_CNCT_FAILED = 9;
    204     private static final int MSG_SET_ALL_VOLUMES = 10;
    205     private static final int MSG_PERSIST_MASTER_VOLUME_MUTE = 11;
    206     private static final int MSG_REPORT_NEW_ROUTES = 12;
    207     private static final int MSG_SET_FORCE_BT_A2DP_USE = 13;
    208     private static final int MSG_CHECK_MUSIC_ACTIVE = 14;
    209     private static final int MSG_BROADCAST_AUDIO_BECOMING_NOISY = 15;
    210     private static final int MSG_CONFIGURE_SAFE_MEDIA_VOLUME = 16;
    211     private static final int MSG_CONFIGURE_SAFE_MEDIA_VOLUME_FORCED = 17;
    212     private static final int MSG_PERSIST_SAFE_VOLUME_STATE = 18;
    213     private static final int MSG_BROADCAST_BT_CONNECTION_STATE = 19;
    214     private static final int MSG_UNLOAD_SOUND_EFFECTS = 20;
    215     private static final int MSG_SYSTEM_READY = 21;
    216     private static final int MSG_PERSIST_MUSIC_ACTIVE_MS = 22;
    217     private static final int MSG_PERSIST_MICROPHONE_MUTE = 23;
    218     private static final int MSG_UNMUTE_STREAM = 24;
    219     private static final int MSG_DYN_POLICY_MIX_STATE_UPDATE = 25;
    220     private static final int MSG_INDICATE_SYSTEM_READY = 26;
    221     // start of messages handled under wakelock
    222     //   these messages can only be queued, i.e. sent with queueMsgUnderWakeLock(),
    223     //   and not with sendMsg(..., ..., SENDMSG_QUEUE, ...)
    224     private static final int MSG_SET_WIRED_DEVICE_CONNECTION_STATE = 100;
    225     private static final int MSG_SET_A2DP_SRC_CONNECTION_STATE = 101;
    226     private static final int MSG_SET_A2DP_SINK_CONNECTION_STATE = 102;
    227     // end of messages handled under wakelock
    228 
    229     private static final int BTA2DP_DOCK_TIMEOUT_MILLIS = 8000;
    230     // Timeout for connection to bluetooth headset service
    231     private static final int BT_HEADSET_CNCT_TIMEOUT_MS = 3000;
    232 
    233     // retry delay in case of failure to indicate system ready to AudioFlinger
    234     private static final int INDICATE_SYSTEM_READY_RETRY_DELAY_MS = 1000;
    235 
    236     /** @see AudioSystemThread */
    237     private AudioSystemThread mAudioSystemThread;
    238     /** @see AudioHandler */
    239     private AudioHandler mAudioHandler;
    240     /** @see VolumeStreamState */
    241     private VolumeStreamState[] mStreamStates;
    242     private SettingsObserver mSettingsObserver;
    243 
    244     private int mMode = AudioSystem.MODE_NORMAL;
    245     // protects mRingerMode
    246     private final Object mSettingsLock = new Object();
    247 
    248     private SoundPool mSoundPool;
    249     private final Object mSoundEffectsLock = new Object();
    250     private static final int NUM_SOUNDPOOL_CHANNELS = 4;
    251 
    252     /* Sound effect file names  */
    253     private static final String SOUND_EFFECTS_PATH = "/media/audio/ui/";
    254     private static final List<String> SOUND_EFFECT_FILES = new ArrayList<String>();
    255 
    256     /* Sound effect file name mapping sound effect id (AudioManager.FX_xxx) to
    257      * file index in SOUND_EFFECT_FILES[] (first column) and indicating if effect
    258      * uses soundpool (second column) */
    259     private final int[][] SOUND_EFFECT_FILES_MAP = new int[AudioManager.NUM_SOUND_EFFECTS][2];
    260 
    261    /** Maximum volume index values for audio streams */
    262     private static int[] MAX_STREAM_VOLUME = new int[] {
    263         5,  // STREAM_VOICE_CALL
    264         7,  // STREAM_SYSTEM
    265         7,  // STREAM_RING
    266         15, // STREAM_MUSIC
    267         7,  // STREAM_ALARM
    268         7,  // STREAM_NOTIFICATION
    269         15, // STREAM_BLUETOOTH_SCO
    270         7,  // STREAM_SYSTEM_ENFORCED
    271         15, // STREAM_DTMF
    272         15  // STREAM_TTS
    273     };
    274 
    275     /** Minimum volume index values for audio streams */
    276     private static int[] MIN_STREAM_VOLUME = new int[] {
    277         1,  // STREAM_VOICE_CALL
    278         0,  // STREAM_SYSTEM
    279         0,  // STREAM_RING
    280         0,  // STREAM_MUSIC
    281         0,  // STREAM_ALARM
    282         0,  // STREAM_NOTIFICATION
    283         1,  // STREAM_BLUETOOTH_SCO
    284         0,  // STREAM_SYSTEM_ENFORCED
    285         0,  // STREAM_DTMF
    286         0   // STREAM_TTS
    287     };
    288 
    289     /* mStreamVolumeAlias[] indicates for each stream if it uses the volume settings
    290      * of another stream: This avoids multiplying the volume settings for hidden
    291      * stream types that follow other stream behavior for volume settings
    292      * NOTE: do not create loops in aliases!
    293      * Some streams alias to different streams according to device category (phone or tablet) or
    294      * use case (in call vs off call...). See updateStreamVolumeAlias() for more details.
    295      *  mStreamVolumeAlias contains STREAM_VOLUME_ALIAS_VOICE aliases for a voice capable device
    296      *  (phone), STREAM_VOLUME_ALIAS_TELEVISION for a television or set-top box and
    297      *  STREAM_VOLUME_ALIAS_DEFAULT for other devices (e.g. tablets).*/
    298     private final int[] STREAM_VOLUME_ALIAS_VOICE = new int[] {
    299         AudioSystem.STREAM_VOICE_CALL,      // STREAM_VOICE_CALL
    300         AudioSystem.STREAM_RING,            // STREAM_SYSTEM
    301         AudioSystem.STREAM_RING,            // STREAM_RING
    302         AudioSystem.STREAM_MUSIC,           // STREAM_MUSIC
    303         AudioSystem.STREAM_ALARM,           // STREAM_ALARM
    304         AudioSystem.STREAM_RING,            // STREAM_NOTIFICATION
    305         AudioSystem.STREAM_BLUETOOTH_SCO,   // STREAM_BLUETOOTH_SCO
    306         AudioSystem.STREAM_RING,            // STREAM_SYSTEM_ENFORCED
    307         AudioSystem.STREAM_RING,            // STREAM_DTMF
    308         AudioSystem.STREAM_MUSIC            // STREAM_TTS
    309     };
    310     private final int[] STREAM_VOLUME_ALIAS_TELEVISION = new int[] {
    311         AudioSystem.STREAM_MUSIC,       // STREAM_VOICE_CALL
    312         AudioSystem.STREAM_MUSIC,       // STREAM_SYSTEM
    313         AudioSystem.STREAM_MUSIC,       // STREAM_RING
    314         AudioSystem.STREAM_MUSIC,       // STREAM_MUSIC
    315         AudioSystem.STREAM_MUSIC,       // STREAM_ALARM
    316         AudioSystem.STREAM_MUSIC,       // STREAM_NOTIFICATION
    317         AudioSystem.STREAM_MUSIC,       // STREAM_BLUETOOTH_SCO
    318         AudioSystem.STREAM_MUSIC,       // STREAM_SYSTEM_ENFORCED
    319         AudioSystem.STREAM_MUSIC,       // STREAM_DTMF
    320         AudioSystem.STREAM_MUSIC        // STREAM_TTS
    321     };
    322     private final int[] STREAM_VOLUME_ALIAS_DEFAULT = new int[] {
    323         AudioSystem.STREAM_VOICE_CALL,      // STREAM_VOICE_CALL
    324         AudioSystem.STREAM_RING,            // STREAM_SYSTEM
    325         AudioSystem.STREAM_RING,            // STREAM_RING
    326         AudioSystem.STREAM_MUSIC,           // STREAM_MUSIC
    327         AudioSystem.STREAM_ALARM,           // STREAM_ALARM
    328         AudioSystem.STREAM_RING,            // STREAM_NOTIFICATION
    329         AudioSystem.STREAM_BLUETOOTH_SCO,   // STREAM_BLUETOOTH_SCO
    330         AudioSystem.STREAM_RING,            // STREAM_SYSTEM_ENFORCED
    331         AudioSystem.STREAM_RING,            // STREAM_DTMF
    332         AudioSystem.STREAM_MUSIC            // STREAM_TTS
    333     };
    334     private int[] mStreamVolumeAlias;
    335 
    336     /**
    337      * Map AudioSystem.STREAM_* constants to app ops.  This should be used
    338      * after mapping through mStreamVolumeAlias.
    339      */
    340     private static final int[] STREAM_VOLUME_OPS = new int[] {
    341         AppOpsManager.OP_AUDIO_VOICE_VOLUME,            // STREAM_VOICE_CALL
    342         AppOpsManager.OP_AUDIO_MEDIA_VOLUME,            // STREAM_SYSTEM
    343         AppOpsManager.OP_AUDIO_RING_VOLUME,             // STREAM_RING
    344         AppOpsManager.OP_AUDIO_MEDIA_VOLUME,            // STREAM_MUSIC
    345         AppOpsManager.OP_AUDIO_ALARM_VOLUME,            // STREAM_ALARM
    346         AppOpsManager.OP_AUDIO_NOTIFICATION_VOLUME,     // STREAM_NOTIFICATION
    347         AppOpsManager.OP_AUDIO_BLUETOOTH_VOLUME,        // STREAM_BLUETOOTH_SCO
    348         AppOpsManager.OP_AUDIO_MEDIA_VOLUME,            // STREAM_SYSTEM_ENFORCED
    349         AppOpsManager.OP_AUDIO_MEDIA_VOLUME,            // STREAM_DTMF
    350         AppOpsManager.OP_AUDIO_MEDIA_VOLUME,            // STREAM_TTS
    351     };
    352 
    353     private final boolean mUseFixedVolume;
    354 
    355     private final AudioSystem.ErrorCallback mAudioSystemCallback = new AudioSystem.ErrorCallback() {
    356         public void onError(int error) {
    357             switch (error) {
    358             case AudioSystem.AUDIO_STATUS_SERVER_DIED:
    359                 sendMsg(mAudioHandler, MSG_MEDIA_SERVER_DIED,
    360                         SENDMSG_NOOP, 0, 0, null, 0);
    361                 break;
    362             default:
    363                 break;
    364             }
    365         }
    366     };
    367 
    368     /**
    369      * Current ringer mode from one of {@link AudioManager#RINGER_MODE_NORMAL},
    370      * {@link AudioManager#RINGER_MODE_SILENT}, or
    371      * {@link AudioManager#RINGER_MODE_VIBRATE}.
    372      */
    373     // protected by mSettingsLock
    374     private int mRingerMode;  // internal ringer mode, affects muting of underlying streams
    375     private int mRingerModeExternal = -1;  // reported ringer mode to outside clients (AudioManager)
    376 
    377     /** @see System#MODE_RINGER_STREAMS_AFFECTED */
    378     private int mRingerModeAffectedStreams = 0;
    379 
    380     // Streams currently muted by ringer mode
    381     private int mRingerModeMutedStreams;
    382 
    383     /** Streams that can be muted. Do not resolve to aliases when checking.
    384      * @see System#MUTE_STREAMS_AFFECTED */
    385     private int mMuteAffectedStreams;
    386 
    387     /**
    388      * NOTE: setVibrateSetting(), getVibrateSetting(), shouldVibrate() are deprecated.
    389      * mVibrateSetting is just maintained during deprecation period but vibration policy is
    390      * now only controlled by mHasVibrator and mRingerMode
    391      */
    392     private int mVibrateSetting;
    393 
    394     // Is there a vibrator
    395     private final boolean mHasVibrator;
    396 
    397     // Broadcast receiver for device connections intent broadcasts
    398     private final BroadcastReceiver mReceiver = new AudioServiceBroadcastReceiver();
    399 
    400     // Devices currently connected
    401     // Use makeDeviceListKey() to make a unique key for this list.
    402     private class DeviceListSpec {
    403         int mDeviceType;
    404         String mDeviceName;
    405         String mDeviceAddress;
    406 
    407         public DeviceListSpec(int deviceType, String deviceName, String deviceAddress) {
    408             mDeviceType = deviceType;
    409             mDeviceName = deviceName;
    410             mDeviceAddress = deviceAddress;
    411         }
    412 
    413         public String toString() {
    414             return "[type:0x" + Integer.toHexString(mDeviceType) + " name:" + mDeviceName
    415                     + " address:" + mDeviceAddress + "]";
    416         }
    417     }
    418 
    419     // Generate a unique key for the mConnectedDevices List by composing the device "type"
    420     // and the "address" associated with a specific instance of that device type
    421     private String makeDeviceListKey(int device, String deviceAddress) {
    422         return "0x" + Integer.toHexString(device) + ":" + deviceAddress;
    423     }
    424 
    425     private final ArrayMap<String, DeviceListSpec> mConnectedDevices = new ArrayMap<>();
    426 
    427     // Forced device usage for communications
    428     private int mForcedUseForComm;
    429 
    430     // List of binder death handlers for setMode() client processes.
    431     // The last process to have called setMode() is at the top of the list.
    432     private final ArrayList <SetModeDeathHandler> mSetModeDeathHandlers = new ArrayList <SetModeDeathHandler>();
    433 
    434     // List of clients having issued a SCO start request
    435     private final ArrayList <ScoClient> mScoClients = new ArrayList <ScoClient>();
    436 
    437     // BluetoothHeadset API to control SCO connection
    438     private BluetoothHeadset mBluetoothHeadset;
    439 
    440     // Bluetooth headset device
    441     private BluetoothDevice mBluetoothHeadsetDevice;
    442 
    443     // Indicate if SCO audio connection is currently active and if the initiator is
    444     // audio service (internal) or bluetooth headset (external)
    445     private int mScoAudioState;
    446     // SCO audio state is not active
    447     private static final int SCO_STATE_INACTIVE = 0;
    448     // SCO audio activation request waiting for headset service to connect
    449     private static final int SCO_STATE_ACTIVATE_REQ = 1;
    450     // SCO audio state is active or starting due to a request from AudioManager API
    451     private static final int SCO_STATE_ACTIVE_INTERNAL = 3;
    452     // SCO audio deactivation request waiting for headset service to connect
    453     private static final int SCO_STATE_DEACTIVATE_REQ = 5;
    454 
    455     // SCO audio state is active due to an action in BT handsfree (either voice recognition or
    456     // in call audio)
    457     private static final int SCO_STATE_ACTIVE_EXTERNAL = 2;
    458     // Deactivation request for all SCO connections (initiated by audio mode change)
    459     // waiting for headset service to connect
    460     private static final int SCO_STATE_DEACTIVATE_EXT_REQ = 4;
    461 
    462     // Indicates the mode used for SCO audio connection. The mode is virtual call if the request
    463     // originated from an app targeting an API version before JB MR2 and raw audio after that.
    464     private int mScoAudioMode;
    465     // SCO audio mode is undefined
    466     private static final int SCO_MODE_UNDEFINED = -1;
    467     // SCO audio mode is virtual voice call (BluetoothHeadset.startScoUsingVirtualVoiceCall())
    468     private static final int SCO_MODE_VIRTUAL_CALL = 0;
    469     // SCO audio mode is raw audio (BluetoothHeadset.connectAudio())
    470     private static final int SCO_MODE_RAW = 1;
    471     // SCO audio mode is Voice Recognition (BluetoothHeadset.startVoiceRecognition())
    472     private static final int SCO_MODE_VR = 2;
    473 
    474     private static final int SCO_MODE_MAX = 2;
    475 
    476     // Current connection state indicated by bluetooth headset
    477     private int mScoConnectionState;
    478 
    479     // true if boot sequence has been completed
    480     private boolean mSystemReady;
    481     // listener for SoundPool sample load completion indication
    482     private SoundPoolCallback mSoundPoolCallBack;
    483     // thread for SoundPool listener
    484     private SoundPoolListenerThread mSoundPoolListenerThread;
    485     // message looper for SoundPool listener
    486     private Looper mSoundPoolLooper = null;
    487     // volume applied to sound played with playSoundEffect()
    488     private static int sSoundEffectVolumeDb;
    489     // previous volume adjustment direction received by checkForRingerModeChange()
    490     private int mPrevVolDirection = AudioManager.ADJUST_SAME;
    491     // Keyguard manager proxy
    492     private KeyguardManager mKeyguardManager;
    493     // mVolumeControlStream is set by VolumePanel to temporarily force the stream type which volume
    494     // is controlled by Vol keys.
    495     private int  mVolumeControlStream = -1;
    496     private final Object mForceControlStreamLock = new Object();
    497     // VolumePanel is currently the only client of forceVolumeControlStream() and runs in system
    498     // server process so in theory it is not necessary to monitor the client death.
    499     // However it is good to be ready for future evolutions.
    500     private ForceControlStreamClient mForceControlStreamClient = null;
    501     // Used to play ringtones outside system_server
    502     private volatile IRingtonePlayer mRingtonePlayer;
    503 
    504     private int mDeviceOrientation = Configuration.ORIENTATION_UNDEFINED;
    505     private int mDeviceRotation = Surface.ROTATION_0;
    506 
    507     // Request to override default use of A2DP for media.
    508     private boolean mBluetoothA2dpEnabled;
    509     private final Object mBluetoothA2dpEnabledLock = new Object();
    510 
    511     // Monitoring of audio routes.  Protected by mCurAudioRoutes.
    512     final AudioRoutesInfo mCurAudioRoutes = new AudioRoutesInfo();
    513     final RemoteCallbackList<IAudioRoutesObserver> mRoutesObservers
    514             = new RemoteCallbackList<IAudioRoutesObserver>();
    515 
    516     // Devices for which the volume is fixed and VolumePanel slider should be disabled
    517     int mFixedVolumeDevices = AudioSystem.DEVICE_OUT_HDMI |
    518             AudioSystem.DEVICE_OUT_DGTL_DOCK_HEADSET |
    519             AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET |
    520             AudioSystem.DEVICE_OUT_HDMI_ARC |
    521             AudioSystem.DEVICE_OUT_SPDIF |
    522             AudioSystem.DEVICE_OUT_AUX_LINE;
    523     int mFullVolumeDevices = 0;
    524 
    525     // TODO merge orientation and rotation
    526     private final boolean mMonitorOrientation;
    527     private final boolean mMonitorRotation;
    528 
    529     private boolean mDockAudioMediaEnabled = true;
    530 
    531     private int mDockState = Intent.EXTRA_DOCK_STATE_UNDOCKED;
    532 
    533     // Used when safe volume warning message display is requested by setStreamVolume(). In this
    534     // case, the new requested volume, stream type and device are stored in mPendingVolumeCommand
    535     // and used later when/if disableSafeMediaVolume() is called.
    536     private StreamVolumeCommand mPendingVolumeCommand;
    537 
    538     private PowerManager.WakeLock mAudioEventWakeLock;
    539 
    540     private final MediaFocusControl mMediaFocusControl;
    541 
    542     // Reference to BluetoothA2dp to query for AbsoluteVolume.
    543     private BluetoothA2dp mA2dp;
    544     // lock always taken synchronized on mConnectedDevices
    545     private final Object mA2dpAvrcpLock = new Object();
    546     // If absolute volume is supported in AVRCP device
    547     private boolean mAvrcpAbsVolSupported = false;
    548 
    549     private AudioOrientationEventListener mOrientationListener;
    550 
    551     private static Long mLastDeviceConnectMsgTime = new Long(0);
    552 
    553     private AudioManagerInternal.RingerModeDelegate mRingerModeDelegate;
    554     private VolumePolicy mVolumePolicy = VolumePolicy.DEFAULT;
    555     private long mLoweredFromNormalToVibrateTime;
    556 
    557     // Intent "extra" data keys.
    558     public static final String CONNECT_INTENT_KEY_PORT_NAME = "portName";
    559     public static final String CONNECT_INTENT_KEY_STATE = "state";
    560     public static final String CONNECT_INTENT_KEY_ADDRESS = "address";
    561     public static final String CONNECT_INTENT_KEY_HAS_PLAYBACK = "hasPlayback";
    562     public static final String CONNECT_INTENT_KEY_HAS_CAPTURE = "hasCapture";
    563     public static final String CONNECT_INTENT_KEY_HAS_MIDI = "hasMIDI";
    564     public static final String CONNECT_INTENT_KEY_DEVICE_CLASS = "class";
    565 
    566     // Defines the format for the connection "address" for ALSA devices
    567     public static String makeAlsaAddressString(int card, int device) {
    568         return "card=" + card + ";device=" + device + ";";
    569     }
    570 
    571     ///////////////////////////////////////////////////////////////////////////
    572     // Construction
    573     ///////////////////////////////////////////////////////////////////////////
    574 
    575     /** @hide */
    576     public AudioService(Context context) {
    577         mContext = context;
    578         mContentResolver = context.getContentResolver();
    579         mAppOps = (AppOpsManager)context.getSystemService(Context.APP_OPS_SERVICE);
    580 
    581         mPlatformType = AudioSystem.getPlatformType(context);
    582 
    583         PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
    584         mAudioEventWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "handleAudioEvent");
    585 
    586         Vibrator vibrator = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE);
    587         mHasVibrator = vibrator == null ? false : vibrator.hasVibrator();
    588 
    589         // Initialize volume
    590         int maxVolume = SystemProperties.getInt("ro.config.vc_call_vol_steps",
    591                 MAX_STREAM_VOLUME[AudioSystem.STREAM_VOICE_CALL]);
    592         if (maxVolume != MAX_STREAM_VOLUME[AudioSystem.STREAM_VOICE_CALL]) {
    593             MAX_STREAM_VOLUME[AudioSystem.STREAM_VOICE_CALL] = maxVolume;
    594             AudioSystem.DEFAULT_STREAM_VOLUME[AudioSystem.STREAM_VOICE_CALL] = (maxVolume * 3) / 4;
    595         }
    596         maxVolume = SystemProperties.getInt("ro.config.media_vol_steps",
    597                 MAX_STREAM_VOLUME[AudioSystem.STREAM_MUSIC]);
    598         if (maxVolume != MAX_STREAM_VOLUME[AudioSystem.STREAM_MUSIC]) {
    599             MAX_STREAM_VOLUME[AudioSystem.STREAM_MUSIC] = maxVolume;
    600             AudioSystem.DEFAULT_STREAM_VOLUME[AudioSystem.STREAM_MUSIC] = (maxVolume * 3) / 4;
    601         }
    602 
    603         sSoundEffectVolumeDb = context.getResources().getInteger(
    604                 com.android.internal.R.integer.config_soundEffectVolumeDb);
    605 
    606         mForcedUseForComm = AudioSystem.FORCE_NONE;
    607 
    608         createAudioSystemThread();
    609 
    610         AudioSystem.setErrorCallback(mAudioSystemCallback);
    611 
    612         boolean cameraSoundForced = readCameraSoundForced();
    613         mCameraSoundForced = new Boolean(cameraSoundForced);
    614         sendMsg(mAudioHandler,
    615                 MSG_SET_FORCE_USE,
    616                 SENDMSG_QUEUE,
    617                 AudioSystem.FOR_SYSTEM,
    618                 cameraSoundForced ?
    619                         AudioSystem.FORCE_SYSTEM_ENFORCED : AudioSystem.FORCE_NONE,
    620                 null,
    621                 0);
    622 
    623         mSafeMediaVolumeState = new Integer(Settings.Global.getInt(mContentResolver,
    624                                                         Settings.Global.AUDIO_SAFE_VOLUME_STATE,
    625                                                         SAFE_MEDIA_VOLUME_NOT_CONFIGURED));
    626         // The default safe volume index read here will be replaced by the actual value when
    627         // the mcc is read by onConfigureSafeVolume()
    628         mSafeMediaVolumeIndex = mContext.getResources().getInteger(
    629                 com.android.internal.R.integer.config_safe_media_volume_index) * 10;
    630 
    631         mUseFixedVolume = mContext.getResources().getBoolean(
    632                 com.android.internal.R.bool.config_useFixedVolume);
    633 
    634         // must be called before readPersistedSettings() which needs a valid mStreamVolumeAlias[]
    635         // array initialized by updateStreamVolumeAlias()
    636         updateStreamVolumeAlias(false /*updateVolumes*/, TAG);
    637         readPersistedSettings();
    638         mSettingsObserver = new SettingsObserver();
    639         createStreamStates();
    640 
    641         mMediaFocusControl = new MediaFocusControl(mAudioHandler.getLooper(),
    642                 mContext, mVolumeController, this);
    643 
    644         readAndSetLowRamDevice();
    645 
    646         // Call setRingerModeInt() to apply correct mute
    647         // state on streams affected by ringer mode.
    648         mRingerModeMutedStreams = 0;
    649         setRingerModeInt(getRingerModeInternal(), false);
    650 
    651         // Register for device connection intent broadcasts.
    652         IntentFilter intentFilter =
    653                 new IntentFilter(BluetoothHeadset.ACTION_AUDIO_STATE_CHANGED);
    654         intentFilter.addAction(BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED);
    655         intentFilter.addAction(Intent.ACTION_DOCK_EVENT);
    656         intentFilter.addAction(Intent.ACTION_SCREEN_ON);
    657         intentFilter.addAction(Intent.ACTION_SCREEN_OFF);
    658         intentFilter.addAction(Intent.ACTION_USER_SWITCHED);
    659         intentFilter.addAction(Intent.ACTION_USER_BACKGROUND);
    660         intentFilter.addAction(Intent.ACTION_USER_FOREGROUND);
    661         intentFilter.addAction(UsbManager.ACTION_USB_DEVICE_ATTACHED);
    662 
    663         intentFilter.addAction(Intent.ACTION_CONFIGURATION_CHANGED);
    664         // TODO merge orientation and rotation
    665         mMonitorOrientation = SystemProperties.getBoolean("ro.audio.monitorOrientation", false);
    666         if (mMonitorOrientation) {
    667             Log.v(TAG, "monitoring device orientation");
    668             // initialize orientation in AudioSystem
    669             setOrientationForAudioSystem();
    670         }
    671         mMonitorRotation = SystemProperties.getBoolean("ro.audio.monitorRotation", false);
    672         if (mMonitorRotation) {
    673             mDeviceRotation = ((WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE))
    674                     .getDefaultDisplay().getRotation();
    675             Log.v(TAG, "monitoring device rotation, initial=" + mDeviceRotation);
    676 
    677             mOrientationListener = new AudioOrientationEventListener(mContext);
    678             mOrientationListener.enable();
    679 
    680             // initialize rotation in AudioSystem
    681             setRotationForAudioSystem();
    682         }
    683 
    684         context.registerReceiverAsUser(mReceiver, UserHandle.ALL, intentFilter, null, null);
    685 
    686         LocalServices.addService(AudioManagerInternal.class, new AudioServiceInternal());
    687     }
    688 
    689     public void systemReady() {
    690         sendMsg(mAudioHandler, MSG_SYSTEM_READY, SENDMSG_QUEUE,
    691                 0, 0, null, 0);
    692     }
    693 
    694     public void onSystemReady() {
    695         mSystemReady = true;
    696         sendMsg(mAudioHandler, MSG_LOAD_SOUND_EFFECTS, SENDMSG_QUEUE,
    697                 0, 0, null, 0);
    698 
    699         mKeyguardManager =
    700                 (KeyguardManager) mContext.getSystemService(Context.KEYGUARD_SERVICE);
    701         mScoConnectionState = AudioManager.SCO_AUDIO_STATE_ERROR;
    702         resetBluetoothSco();
    703         getBluetoothHeadset();
    704         //FIXME: this is to maintain compatibility with deprecated intent
    705         // AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED. Remove when appropriate.
    706         Intent newIntent = new Intent(AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED);
    707         newIntent.putExtra(AudioManager.EXTRA_SCO_AUDIO_STATE,
    708                 AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
    709         sendStickyBroadcastToAll(newIntent);
    710 
    711         BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
    712         if (adapter != null) {
    713             adapter.getProfileProxy(mContext, mBluetoothProfileServiceListener,
    714                                     BluetoothProfile.A2DP);
    715         }
    716 
    717         mHdmiManager =
    718                 (HdmiControlManager) mContext.getSystemService(Context.HDMI_CONTROL_SERVICE);
    719         if (mHdmiManager != null) {
    720             synchronized (mHdmiManager) {
    721                 mHdmiTvClient = mHdmiManager.getTvClient();
    722                 if (mHdmiTvClient != null) {
    723                     mFixedVolumeDevices &= ~AudioSystem.DEVICE_ALL_HDMI_SYSTEM_AUDIO_AND_SPEAKER;
    724                 }
    725                 mHdmiPlaybackClient = mHdmiManager.getPlaybackClient();
    726                 mHdmiCecSink = false;
    727             }
    728         }
    729 
    730         sendMsg(mAudioHandler,
    731                 MSG_CONFIGURE_SAFE_MEDIA_VOLUME_FORCED,
    732                 SENDMSG_REPLACE,
    733                 0,
    734                 0,
    735                 TAG,
    736                 SAFE_VOLUME_CONFIGURE_TIMEOUT_MS);
    737 
    738         StreamOverride.init(mContext);
    739         mControllerService.init();
    740         onIndicateSystemReady();
    741     }
    742 
    743     void onIndicateSystemReady() {
    744         if (AudioSystem.systemReady() == AudioSystem.SUCCESS) {
    745             return;
    746         }
    747         sendMsg(mAudioHandler,
    748                 MSG_INDICATE_SYSTEM_READY,
    749                 SENDMSG_REPLACE,
    750                 0,
    751                 0,
    752                 null,
    753                 INDICATE_SYSTEM_READY_RETRY_DELAY_MS);
    754     }
    755 
    756     public void onMediaServerDied() {
    757         if (!mSystemReady ||
    758                 (AudioSystem.checkAudioFlinger() != AudioSystem.AUDIO_STATUS_OK)) {
    759             Log.e(TAG, "Media server died.");
    760             sendMsg(mAudioHandler, MSG_MEDIA_SERVER_DIED, SENDMSG_NOOP, 0, 0,
    761                     null, 500);
    762             return;
    763         }
    764         Log.e(TAG, "Media server started.");
    765 
    766         // indicate to audio HAL that we start the reconfiguration phase after a media
    767         // server crash
    768         // Note that we only execute this when the media server
    769         // process restarts after a crash, not the first time it is started.
    770         AudioSystem.setParameters("restarting=true");
    771 
    772         readAndSetLowRamDevice();
    773 
    774         // Restore device connection states
    775         synchronized (mConnectedDevices) {
    776             for (int i = 0; i < mConnectedDevices.size(); i++) {
    777                 DeviceListSpec spec = mConnectedDevices.valueAt(i);
    778                 AudioSystem.setDeviceConnectionState(
    779                                                 spec.mDeviceType,
    780                                                 AudioSystem.DEVICE_STATE_AVAILABLE,
    781                                                 spec.mDeviceAddress,
    782                                                 spec.mDeviceName);
    783             }
    784         }
    785         // Restore call state
    786         AudioSystem.setPhoneState(mMode);
    787 
    788         // Restore forced usage for communcations and record
    789         AudioSystem.setForceUse(AudioSystem.FOR_COMMUNICATION, mForcedUseForComm);
    790         AudioSystem.setForceUse(AudioSystem.FOR_RECORD, mForcedUseForComm);
    791         AudioSystem.setForceUse(AudioSystem.FOR_SYSTEM, mCameraSoundForced ?
    792                         AudioSystem.FORCE_SYSTEM_ENFORCED : AudioSystem.FORCE_NONE);
    793 
    794         // Restore stream volumes
    795         int numStreamTypes = AudioSystem.getNumStreamTypes();
    796         for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
    797             VolumeStreamState streamState = mStreamStates[streamType];
    798             AudioSystem.initStreamVolume(streamType, 0, (streamState.mIndexMax + 5) / 10);
    799 
    800             streamState.applyAllVolumes();
    801         }
    802 
    803         // Restore ringer mode
    804         setRingerModeInt(getRingerModeInternal(), false);
    805 
    806         // Reset device orientation (if monitored for this device)
    807         if (mMonitorOrientation) {
    808             setOrientationForAudioSystem();
    809         }
    810         if (mMonitorRotation) {
    811             setRotationForAudioSystem();
    812         }
    813 
    814         synchronized (mBluetoothA2dpEnabledLock) {
    815             AudioSystem.setForceUse(AudioSystem.FOR_MEDIA,
    816                     mBluetoothA2dpEnabled ?
    817                             AudioSystem.FORCE_NONE : AudioSystem.FORCE_NO_BT_A2DP);
    818         }
    819 
    820         synchronized (mSettingsLock) {
    821             AudioSystem.setForceUse(AudioSystem.FOR_DOCK,
    822                     mDockAudioMediaEnabled ?
    823                             AudioSystem.FORCE_ANALOG_DOCK : AudioSystem.FORCE_NONE);
    824         }
    825         if (mHdmiManager != null) {
    826             synchronized (mHdmiManager) {
    827                 if (mHdmiTvClient != null) {
    828                     setHdmiSystemAudioSupported(mHdmiSystemAudioSupported);
    829                 }
    830             }
    831         }
    832 
    833         synchronized (mAudioPolicies) {
    834             for (AudioPolicyProxy policy : mAudioPolicies.values()) {
    835                 policy.connectMixes();
    836             }
    837         }
    838 
    839         onIndicateSystemReady();
    840         // indicate the end of reconfiguration phase to audio HAL
    841         AudioSystem.setParameters("restarting=false");
    842     }
    843 
    844     private void createAudioSystemThread() {
    845         mAudioSystemThread = new AudioSystemThread();
    846         mAudioSystemThread.start();
    847         waitForAudioHandlerCreation();
    848     }
    849 
    850     /** Waits for the volume handler to be created by the other thread. */
    851     private void waitForAudioHandlerCreation() {
    852         synchronized(this) {
    853             while (mAudioHandler == null) {
    854                 try {
    855                     // Wait for mAudioHandler to be set by the other thread
    856                     wait();
    857                 } catch (InterruptedException e) {
    858                     Log.e(TAG, "Interrupted while waiting on volume handler.");
    859                 }
    860             }
    861         }
    862     }
    863 
    864     private void checkAllAliasStreamVolumes() {
    865         synchronized (VolumeStreamState.class) {
    866             int numStreamTypes = AudioSystem.getNumStreamTypes();
    867             for (int streamType = 0; streamType < numStreamTypes; streamType++) {
    868                 if (streamType != mStreamVolumeAlias[streamType]) {
    869                     mStreamStates[streamType].
    870                                     setAllIndexes(mStreamStates[mStreamVolumeAlias[streamType]],
    871                                             TAG);
    872                 }
    873                 // apply stream volume
    874                 if (!mStreamStates[streamType].mIsMuted) {
    875                     mStreamStates[streamType].applyAllVolumes();
    876                 }
    877             }
    878         }
    879     }
    880 
    881     private void checkAllFixedVolumeDevices()
    882     {
    883         int numStreamTypes = AudioSystem.getNumStreamTypes();
    884         for (int streamType = 0; streamType < numStreamTypes; streamType++) {
    885             mStreamStates[streamType].checkFixedVolumeDevices();
    886         }
    887     }
    888 
    889     private void checkAllFixedVolumeDevices(int streamType) {
    890         mStreamStates[streamType].checkFixedVolumeDevices();
    891     }
    892 
    893     private void checkMuteAffectedStreams() {
    894         // any stream with a min level > 0 is not muteable by definition
    895         for (int i = 0; i < mStreamStates.length; i++) {
    896             final VolumeStreamState vss = mStreamStates[i];
    897             if (vss.mIndexMin > 0) {
    898                 mMuteAffectedStreams &= ~(1 << vss.mStreamType);
    899             }
    900         }
    901     }
    902 
    903     private void createStreamStates() {
    904         int numStreamTypes = AudioSystem.getNumStreamTypes();
    905         VolumeStreamState[] streams = mStreamStates = new VolumeStreamState[numStreamTypes];
    906 
    907         for (int i = 0; i < numStreamTypes; i++) {
    908             streams[i] = new VolumeStreamState(System.VOLUME_SETTINGS[mStreamVolumeAlias[i]], i);
    909         }
    910 
    911         checkAllFixedVolumeDevices();
    912         checkAllAliasStreamVolumes();
    913         checkMuteAffectedStreams();
    914     }
    915 
    916     private void dumpStreamStates(PrintWriter pw) {
    917         pw.println("\nStream volumes (device: index)");
    918         int numStreamTypes = AudioSystem.getNumStreamTypes();
    919         for (int i = 0; i < numStreamTypes; i++) {
    920             pw.println("- " + AudioSystem.STREAM_NAMES[i] + ":");
    921             mStreamStates[i].dump(pw);
    922             pw.println("");
    923         }
    924         pw.print("\n- mute affected streams = 0x");
    925         pw.println(Integer.toHexString(mMuteAffectedStreams));
    926     }
    927 
    928     private void updateStreamVolumeAlias(boolean updateVolumes, String caller) {
    929         int dtmfStreamAlias;
    930 
    931         switch (mPlatformType) {
    932         case AudioSystem.PLATFORM_VOICE:
    933             mStreamVolumeAlias = STREAM_VOLUME_ALIAS_VOICE;
    934             dtmfStreamAlias = AudioSystem.STREAM_RING;
    935             break;
    936         case AudioSystem.PLATFORM_TELEVISION:
    937             mStreamVolumeAlias = STREAM_VOLUME_ALIAS_TELEVISION;
    938             dtmfStreamAlias = AudioSystem.STREAM_MUSIC;
    939             break;
    940         default:
    941             mStreamVolumeAlias = STREAM_VOLUME_ALIAS_DEFAULT;
    942             dtmfStreamAlias = AudioSystem.STREAM_MUSIC;
    943         }
    944 
    945         if (isPlatformTelevision()) {
    946             mRingerModeAffectedStreams = 0;
    947         } else {
    948             if (isInCommunication()) {
    949                 dtmfStreamAlias = AudioSystem.STREAM_VOICE_CALL;
    950                 mRingerModeAffectedStreams &= ~(1 << AudioSystem.STREAM_DTMF);
    951             } else {
    952                 mRingerModeAffectedStreams |= (1 << AudioSystem.STREAM_DTMF);
    953             }
    954         }
    955 
    956         mStreamVolumeAlias[AudioSystem.STREAM_DTMF] = dtmfStreamAlias;
    957         if (updateVolumes) {
    958             mStreamStates[AudioSystem.STREAM_DTMF].setAllIndexes(mStreamStates[dtmfStreamAlias],
    959                     caller);
    960             // apply stream mute states according to new value of mRingerModeAffectedStreams
    961             setRingerModeInt(getRingerModeInternal(), false);
    962             sendMsg(mAudioHandler,
    963                     MSG_SET_ALL_VOLUMES,
    964                     SENDMSG_QUEUE,
    965                     0,
    966                     0,
    967                     mStreamStates[AudioSystem.STREAM_DTMF], 0);
    968         }
    969     }
    970 
    971     private void readDockAudioSettings(ContentResolver cr)
    972     {
    973         mDockAudioMediaEnabled = Settings.Global.getInt(
    974                                         cr, Settings.Global.DOCK_AUDIO_MEDIA_ENABLED, 0) == 1;
    975 
    976         sendMsg(mAudioHandler,
    977                 MSG_SET_FORCE_USE,
    978                 SENDMSG_QUEUE,
    979                 AudioSystem.FOR_DOCK,
    980                 mDockAudioMediaEnabled ?
    981                         AudioSystem.FORCE_ANALOG_DOCK : AudioSystem.FORCE_NONE,
    982                 null,
    983                 0);
    984     }
    985 
    986     private void readPersistedSettings() {
    987         final ContentResolver cr = mContentResolver;
    988 
    989         int ringerModeFromSettings =
    990                 Settings.Global.getInt(
    991                         cr, Settings.Global.MODE_RINGER, AudioManager.RINGER_MODE_NORMAL);
    992         int ringerMode = ringerModeFromSettings;
    993         // sanity check in case the settings are restored from a device with incompatible
    994         // ringer modes
    995         if (!isValidRingerMode(ringerMode)) {
    996             ringerMode = AudioManager.RINGER_MODE_NORMAL;
    997         }
    998         if ((ringerMode == AudioManager.RINGER_MODE_VIBRATE) && !mHasVibrator) {
    999             ringerMode = AudioManager.RINGER_MODE_SILENT;
   1000         }
   1001         if (ringerMode != ringerModeFromSettings) {
   1002             Settings.Global.putInt(cr, Settings.Global.MODE_RINGER, ringerMode);
   1003         }
   1004         if (mUseFixedVolume || isPlatformTelevision()) {
   1005             ringerMode = AudioManager.RINGER_MODE_NORMAL;
   1006         }
   1007         synchronized(mSettingsLock) {
   1008             mRingerMode = ringerMode;
   1009             if (mRingerModeExternal == -1) {
   1010                 mRingerModeExternal = mRingerMode;
   1011             }
   1012 
   1013             // System.VIBRATE_ON is not used any more but defaults for mVibrateSetting
   1014             // are still needed while setVibrateSetting() and getVibrateSetting() are being
   1015             // deprecated.
   1016             mVibrateSetting = AudioSystem.getValueForVibrateSetting(0,
   1017                                             AudioManager.VIBRATE_TYPE_NOTIFICATION,
   1018                                             mHasVibrator ? AudioManager.VIBRATE_SETTING_ONLY_SILENT
   1019                                                             : AudioManager.VIBRATE_SETTING_OFF);
   1020             mVibrateSetting = AudioSystem.getValueForVibrateSetting(mVibrateSetting,
   1021                                             AudioManager.VIBRATE_TYPE_RINGER,
   1022                                             mHasVibrator ? AudioManager.VIBRATE_SETTING_ONLY_SILENT
   1023                                                             : AudioManager.VIBRATE_SETTING_OFF);
   1024 
   1025             updateRingerModeAffectedStreams();
   1026             readDockAudioSettings(cr);
   1027         }
   1028 
   1029         mMuteAffectedStreams = System.getIntForUser(cr,
   1030                 System.MUTE_STREAMS_AFFECTED, AudioSystem.DEFAULT_MUTE_STREAMS_AFFECTED,
   1031                 UserHandle.USER_CURRENT);
   1032 
   1033         boolean masterMute = System.getIntForUser(cr, System.VOLUME_MASTER_MUTE,
   1034                 0, UserHandle.USER_CURRENT) == 1;
   1035         if (mUseFixedVolume) {
   1036             masterMute = false;
   1037             AudioSystem.setMasterVolume(1.0f);
   1038         }
   1039         AudioSystem.setMasterMute(masterMute);
   1040         broadcastMasterMuteStatus(masterMute);
   1041 
   1042         boolean microphoneMute =
   1043                 System.getIntForUser(cr, System.MICROPHONE_MUTE, 0, UserHandle.USER_CURRENT) == 1;
   1044         AudioSystem.muteMicrophone(microphoneMute);
   1045 
   1046         // Each stream will read its own persisted settings
   1047 
   1048         // Broadcast the sticky intents
   1049         broadcastRingerMode(AudioManager.RINGER_MODE_CHANGED_ACTION, mRingerModeExternal);
   1050         broadcastRingerMode(AudioManager.INTERNAL_RINGER_MODE_CHANGED_ACTION, mRingerMode);
   1051 
   1052         // Broadcast vibrate settings
   1053         broadcastVibrateSetting(AudioManager.VIBRATE_TYPE_RINGER);
   1054         broadcastVibrateSetting(AudioManager.VIBRATE_TYPE_NOTIFICATION);
   1055 
   1056         // Load settings for the volume controller
   1057         mVolumeController.loadSettings(cr);
   1058     }
   1059 
   1060     private int rescaleIndex(int index, int srcStream, int dstStream) {
   1061         return (index * mStreamStates[dstStream].getMaxIndex() + mStreamStates[srcStream].getMaxIndex() / 2) / mStreamStates[srcStream].getMaxIndex();
   1062     }
   1063 
   1064     private class AudioOrientationEventListener
   1065             extends OrientationEventListener {
   1066         public AudioOrientationEventListener(Context context) {
   1067             super(context);
   1068         }
   1069 
   1070         @Override
   1071         public void onOrientationChanged(int orientation) {
   1072             //Even though we're responding to phone orientation events,
   1073             //use display rotation so audio stays in sync with video/dialogs
   1074             int newRotation = ((WindowManager) mContext.getSystemService(
   1075                     Context.WINDOW_SERVICE)).getDefaultDisplay().getRotation();
   1076             if (newRotation != mDeviceRotation) {
   1077                 mDeviceRotation = newRotation;
   1078                 setRotationForAudioSystem();
   1079             }
   1080         }
   1081     }
   1082 
   1083     ///////////////////////////////////////////////////////////////////////////
   1084     // IPC methods
   1085     ///////////////////////////////////////////////////////////////////////////
   1086     /** @see AudioManager#adjustVolume(int, int) */
   1087     public void adjustSuggestedStreamVolume(int direction, int suggestedStreamType, int flags,
   1088             String callingPackage, String caller) {
   1089         adjustSuggestedStreamVolume(direction, suggestedStreamType, flags, callingPackage,
   1090                 caller, Binder.getCallingUid());
   1091     }
   1092 
   1093     private void adjustSuggestedStreamVolume(int direction, int suggestedStreamType, int flags,
   1094             String callingPackage, String caller, int uid) {
   1095         if (DEBUG_VOL) Log.d(TAG, "adjustSuggestedStreamVolume() stream=" + suggestedStreamType
   1096                 + ", flags=" + flags + ", caller=" + caller);
   1097         int streamType;
   1098         boolean isMute = isMuteAdjust(direction);
   1099         if (mVolumeControlStream != -1) {
   1100             streamType = mVolumeControlStream;
   1101         } else {
   1102             streamType = getActiveStreamType(suggestedStreamType);
   1103         }
   1104         ensureValidStreamType(streamType);
   1105         final int resolvedStream = mStreamVolumeAlias[streamType];
   1106 
   1107         // Play sounds on STREAM_RING only.
   1108         if ((flags & AudioManager.FLAG_PLAY_SOUND) != 0 &&
   1109                 resolvedStream != AudioSystem.STREAM_RING) {
   1110             flags &= ~AudioManager.FLAG_PLAY_SOUND;
   1111         }
   1112 
   1113         // For notifications/ring, show the ui before making any adjustments
   1114         // Don't suppress mute/unmute requests
   1115         if (mVolumeController.suppressAdjustment(resolvedStream, flags, isMute)) {
   1116             direction = 0;
   1117             flags &= ~AudioManager.FLAG_PLAY_SOUND;
   1118             flags &= ~AudioManager.FLAG_VIBRATE;
   1119             if (DEBUG_VOL) Log.d(TAG, "Volume controller suppressed adjustment");
   1120         }
   1121 
   1122         adjustStreamVolume(streamType, direction, flags, callingPackage, caller, uid);
   1123     }
   1124 
   1125     /** @see AudioManager#adjustStreamVolume(int, int, int) */
   1126     public void adjustStreamVolume(int streamType, int direction, int flags,
   1127             String callingPackage) {
   1128         adjustStreamVolume(streamType, direction, flags, callingPackage, callingPackage,
   1129                 Binder.getCallingUid());
   1130     }
   1131 
   1132     private void adjustStreamVolume(int streamType, int direction, int flags,
   1133             String callingPackage, String caller, int uid) {
   1134         if (mUseFixedVolume) {
   1135             return;
   1136         }
   1137         if (DEBUG_VOL) Log.d(TAG, "adjustStreamVolume() stream=" + streamType + ", dir=" + direction
   1138                 + ", flags=" + flags + ", caller=" + caller);
   1139 
   1140         ensureValidDirection(direction);
   1141         ensureValidStreamType(streamType);
   1142 
   1143         boolean isMuteAdjust = isMuteAdjust(direction);
   1144 
   1145         if (isMuteAdjust && !isStreamAffectedByMute(streamType)) {
   1146             return;
   1147         }
   1148 
   1149         // use stream type alias here so that streams with same alias have the same behavior,
   1150         // including with regard to silent mode control (e.g the use of STREAM_RING below and in
   1151         // checkForRingerModeChange() in place of STREAM_RING or STREAM_NOTIFICATION)
   1152         int streamTypeAlias = mStreamVolumeAlias[streamType];
   1153 
   1154         VolumeStreamState streamState = mStreamStates[streamTypeAlias];
   1155 
   1156         final int device = getDeviceForStream(streamTypeAlias);
   1157 
   1158         int aliasIndex = streamState.getIndex(device);
   1159         boolean adjustVolume = true;
   1160         int step;
   1161 
   1162         // skip a2dp absolute volume control request when the device
   1163         // is not an a2dp device
   1164         if ((device & AudioSystem.DEVICE_OUT_ALL_A2DP) == 0 &&
   1165             (flags & AudioManager.FLAG_BLUETOOTH_ABS_VOLUME) != 0) {
   1166             return;
   1167         }
   1168 
   1169         // If we are being called by the system (e.g. hardware keys) check for current user
   1170         // so we handle user restrictions correctly.
   1171         if (uid == android.os.Process.SYSTEM_UID) {
   1172             uid = UserHandle.getUid(getCurrentUserId(), UserHandle.getAppId(uid));
   1173         }
   1174         if (mAppOps.noteOp(STREAM_VOLUME_OPS[streamTypeAlias], uid, callingPackage)
   1175                 != AppOpsManager.MODE_ALLOWED) {
   1176             return;
   1177         }
   1178 
   1179         // reset any pending volume command
   1180         synchronized (mSafeMediaVolumeState) {
   1181             mPendingVolumeCommand = null;
   1182         }
   1183 
   1184         flags &= ~AudioManager.FLAG_FIXED_VOLUME;
   1185         if ((streamTypeAlias == AudioSystem.STREAM_MUSIC) &&
   1186                ((device & mFixedVolumeDevices) != 0)) {
   1187             flags |= AudioManager.FLAG_FIXED_VOLUME;
   1188 
   1189             // Always toggle between max safe volume and 0 for fixed volume devices where safe
   1190             // volume is enforced, and max and 0 for the others.
   1191             // This is simulated by stepping by the full allowed volume range
   1192             if (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_ACTIVE &&
   1193                     (device & mSafeMediaVolumeDevices) != 0) {
   1194                 step = mSafeMediaVolumeIndex;
   1195             } else {
   1196                 step = streamState.getMaxIndex();
   1197             }
   1198             if (aliasIndex != 0) {
   1199                 aliasIndex = step;
   1200             }
   1201         } else {
   1202             // convert one UI step (+/-1) into a number of internal units on the stream alias
   1203             step = rescaleIndex(10, streamType, streamTypeAlias);
   1204         }
   1205 
   1206         // If either the client forces allowing ringer modes for this adjustment,
   1207         // or the stream type is one that is affected by ringer modes
   1208         if (((flags & AudioManager.FLAG_ALLOW_RINGER_MODES) != 0) ||
   1209                 (streamTypeAlias == getUiSoundsStreamType())) {
   1210             int ringerMode = getRingerModeInternal();
   1211             // do not vibrate if already in vibrate mode
   1212             if (ringerMode == AudioManager.RINGER_MODE_VIBRATE) {
   1213                 flags &= ~AudioManager.FLAG_VIBRATE;
   1214             }
   1215             // Check if the ringer mode handles this adjustment. If it does we don't
   1216             // need to adjust the volume further.
   1217             final int result = checkForRingerModeChange(aliasIndex, direction, step,
   1218                     streamState.mIsMuted);
   1219             adjustVolume = (result & FLAG_ADJUST_VOLUME) != 0;
   1220             // If suppressing a volume adjustment in silent mode, display the UI hint
   1221             if ((result & AudioManager.FLAG_SHOW_SILENT_HINT) != 0) {
   1222                 flags |= AudioManager.FLAG_SHOW_SILENT_HINT;
   1223             }
   1224             // If suppressing a volume down adjustment in vibrate mode, display the UI hint
   1225             if ((result & AudioManager.FLAG_SHOW_VIBRATE_HINT) != 0) {
   1226                 flags |= AudioManager.FLAG_SHOW_VIBRATE_HINT;
   1227             }
   1228         }
   1229         // If the ringermode is suppressing media, prevent changes
   1230         if (streamTypeAlias == AudioSystem.STREAM_MUSIC
   1231                 && (mRingerModeMutedStreams & (1 << AudioSystem.STREAM_MUSIC)) != 0) {
   1232             adjustVolume = false;
   1233         }
   1234 
   1235         int oldIndex = mStreamStates[streamType].getIndex(device);
   1236 
   1237         if (adjustVolume && (direction != AudioManager.ADJUST_SAME)) {
   1238             mAudioHandler.removeMessages(MSG_UNMUTE_STREAM);
   1239 
   1240             // Check if volume update should be send to AVRCP
   1241             if (streamTypeAlias == AudioSystem.STREAM_MUSIC &&
   1242                 (device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0 &&
   1243                 (flags & AudioManager.FLAG_BLUETOOTH_ABS_VOLUME) == 0) {
   1244                 synchronized (mA2dpAvrcpLock) {
   1245                     if (mA2dp != null && mAvrcpAbsVolSupported) {
   1246                         mA2dp.adjustAvrcpAbsoluteVolume(direction);
   1247                     }
   1248                 }
   1249             }
   1250 
   1251             if (isMuteAdjust) {
   1252                 boolean state;
   1253                 if (direction == AudioManager.ADJUST_TOGGLE_MUTE) {
   1254                     state = !streamState.mIsMuted;
   1255                 } else {
   1256                     state = direction == AudioManager.ADJUST_MUTE;
   1257                 }
   1258                 if (streamTypeAlias == AudioSystem.STREAM_MUSIC) {
   1259                     setSystemAudioMute(state);
   1260                 }
   1261                 for (int stream = 0; stream < mStreamStates.length; stream++) {
   1262                     if (streamTypeAlias == mStreamVolumeAlias[stream]) {
   1263                         if (!(readCameraSoundForced()
   1264                                     && (mStreamStates[stream].getStreamType()
   1265                                         == AudioSystem.STREAM_SYSTEM_ENFORCED))) {
   1266                             mStreamStates[stream].mute(state);
   1267                         }
   1268                     }
   1269                 }
   1270             } else if ((direction == AudioManager.ADJUST_RAISE) &&
   1271                     !checkSafeMediaVolume(streamTypeAlias, aliasIndex + step, device)) {
   1272                 Log.e(TAG, "adjustStreamVolume() safe volume index = " + oldIndex);
   1273                 mVolumeController.postDisplaySafeVolumeWarning(flags);
   1274             } else if (streamState.adjustIndex(direction * step, device, caller)
   1275                     || streamState.mIsMuted) {
   1276                 // Post message to set system volume (it in turn will post a
   1277                 // message to persist).
   1278                 if (streamState.mIsMuted) {
   1279                     // Unmute the stream if it was previously muted
   1280                     if (direction == AudioManager.ADJUST_RAISE) {
   1281                         // unmute immediately for volume up
   1282                         streamState.mute(false);
   1283                     } else if (direction == AudioManager.ADJUST_LOWER) {
   1284                         if (mPlatformType == AudioSystem.PLATFORM_TELEVISION) {
   1285                             sendMsg(mAudioHandler, MSG_UNMUTE_STREAM, SENDMSG_QUEUE,
   1286                                     streamTypeAlias, flags, null, UNMUTE_STREAM_DELAY);
   1287                         }
   1288                     }
   1289                 }
   1290                 sendMsg(mAudioHandler,
   1291                         MSG_SET_DEVICE_VOLUME,
   1292                         SENDMSG_QUEUE,
   1293                         device,
   1294                         0,
   1295                         streamState,
   1296                         0);
   1297             }
   1298 
   1299             // Check if volume update should be sent to Hdmi system audio.
   1300             int newIndex = mStreamStates[streamType].getIndex(device);
   1301             if (streamTypeAlias == AudioSystem.STREAM_MUSIC) {
   1302                 setSystemAudioVolume(oldIndex, newIndex, getStreamMaxVolume(streamType), flags);
   1303             }
   1304             if (mHdmiManager != null) {
   1305                 synchronized (mHdmiManager) {
   1306                     // mHdmiCecSink true => mHdmiPlaybackClient != null
   1307                     if (mHdmiCecSink &&
   1308                             streamTypeAlias == AudioSystem.STREAM_MUSIC &&
   1309                             oldIndex != newIndex) {
   1310                         synchronized (mHdmiPlaybackClient) {
   1311                             int keyCode = (direction == -1) ? KeyEvent.KEYCODE_VOLUME_DOWN :
   1312                                     KeyEvent.KEYCODE_VOLUME_UP;
   1313                             mHdmiPlaybackClient.sendKeyEvent(keyCode, true);
   1314                             mHdmiPlaybackClient.sendKeyEvent(keyCode, false);
   1315                         }
   1316                     }
   1317                 }
   1318             }
   1319         }
   1320         int index = mStreamStates[streamType].getIndex(device);
   1321         sendVolumeUpdate(streamType, oldIndex, index, flags);
   1322     }
   1323 
   1324     // Called after a delay when volume down is pressed while muted
   1325     private void onUnmuteStream(int stream, int flags) {
   1326         VolumeStreamState streamState = mStreamStates[stream];
   1327         streamState.mute(false);
   1328 
   1329         final int device = getDeviceForStream(stream);
   1330         final int index = mStreamStates[stream].getIndex(device);
   1331         sendVolumeUpdate(stream, index, index, flags);
   1332     }
   1333 
   1334     private void setSystemAudioVolume(int oldVolume, int newVolume, int maxVolume, int flags) {
   1335         if (mHdmiManager == null
   1336                 || mHdmiTvClient == null
   1337                 || oldVolume == newVolume
   1338                 || (flags & AudioManager.FLAG_HDMI_SYSTEM_AUDIO_VOLUME) != 0) return;
   1339 
   1340         // Sets the audio volume of AVR when we are in system audio mode. The new volume info
   1341         // is tranformed to HDMI-CEC commands and passed through CEC bus.
   1342         synchronized (mHdmiManager) {
   1343             if (!mHdmiSystemAudioSupported) return;
   1344             synchronized (mHdmiTvClient) {
   1345                 final long token = Binder.clearCallingIdentity();
   1346                 try {
   1347                     mHdmiTvClient.setSystemAudioVolume(oldVolume, newVolume, maxVolume);
   1348                 } finally {
   1349                     Binder.restoreCallingIdentity(token);
   1350                 }
   1351             }
   1352         }
   1353     }
   1354 
   1355     // StreamVolumeCommand contains the information needed to defer the process of
   1356     // setStreamVolume() in case the user has to acknowledge the safe volume warning message.
   1357     class StreamVolumeCommand {
   1358         public final int mStreamType;
   1359         public final int mIndex;
   1360         public final int mFlags;
   1361         public final int mDevice;
   1362 
   1363         StreamVolumeCommand(int streamType, int index, int flags, int device) {
   1364             mStreamType = streamType;
   1365             mIndex = index;
   1366             mFlags = flags;
   1367             mDevice = device;
   1368         }
   1369 
   1370         @Override
   1371         public String toString() {
   1372             return new StringBuilder().append("{streamType=").append(mStreamType).append(",index=")
   1373                     .append(mIndex).append(",flags=").append(mFlags).append(",device=")
   1374                     .append(mDevice).append('}').toString();
   1375         }
   1376     };
   1377 
   1378     private void onSetStreamVolume(int streamType, int index, int flags, int device,
   1379             String caller) {
   1380         final int stream = mStreamVolumeAlias[streamType];
   1381         setStreamVolumeInt(stream, index, device, false, caller);
   1382         // setting volume on ui sounds stream type also controls silent mode
   1383         if (((flags & AudioManager.FLAG_ALLOW_RINGER_MODES) != 0) ||
   1384                 (stream == getUiSoundsStreamType())) {
   1385             int newRingerMode;
   1386             if (index == 0) {
   1387                 newRingerMode = mHasVibrator ? AudioManager.RINGER_MODE_VIBRATE
   1388                         : mVolumePolicy.volumeDownToEnterSilent ? AudioManager.RINGER_MODE_SILENT
   1389                         : AudioManager.RINGER_MODE_NORMAL;
   1390             } else {
   1391                 newRingerMode = AudioManager.RINGER_MODE_NORMAL;
   1392             }
   1393             setRingerMode(newRingerMode, TAG + ".onSetStreamVolume", false /*external*/);
   1394         }
   1395         // setting non-zero volume for a muted stream unmutes the stream and vice versa
   1396         mStreamStates[stream].mute(index == 0);
   1397     }
   1398 
   1399     /** @see AudioManager#setStreamVolume(int, int, int) */
   1400     public void setStreamVolume(int streamType, int index, int flags, String callingPackage) {
   1401         setStreamVolume(streamType, index, flags, callingPackage, callingPackage,
   1402                 Binder.getCallingUid());
   1403     }
   1404 
   1405     private void setStreamVolume(int streamType, int index, int flags, String callingPackage,
   1406             String caller, int uid) {
   1407         if (mUseFixedVolume) {
   1408             return;
   1409         }
   1410 
   1411         ensureValidStreamType(streamType);
   1412         int streamTypeAlias = mStreamVolumeAlias[streamType];
   1413         VolumeStreamState streamState = mStreamStates[streamTypeAlias];
   1414 
   1415         final int device = getDeviceForStream(streamType);
   1416         int oldIndex;
   1417 
   1418         // skip a2dp absolute volume control request when the device
   1419         // is not an a2dp device
   1420         if ((device & AudioSystem.DEVICE_OUT_ALL_A2DP) == 0 &&
   1421             (flags & AudioManager.FLAG_BLUETOOTH_ABS_VOLUME) != 0) {
   1422             return;
   1423         }
   1424         // If we are being called by the system (e.g. hardware keys) check for current user
   1425         // so we handle user restrictions correctly.
   1426         if (uid == android.os.Process.SYSTEM_UID) {
   1427             uid = UserHandle.getUid(getCurrentUserId(), UserHandle.getAppId(uid));
   1428         }
   1429         if (mAppOps.noteOp(STREAM_VOLUME_OPS[streamTypeAlias], uid, callingPackage)
   1430                 != AppOpsManager.MODE_ALLOWED) {
   1431             return;
   1432         }
   1433 
   1434         synchronized (mSafeMediaVolumeState) {
   1435             // reset any pending volume command
   1436             mPendingVolumeCommand = null;
   1437 
   1438             oldIndex = streamState.getIndex(device);
   1439 
   1440             index = rescaleIndex(index * 10, streamType, streamTypeAlias);
   1441 
   1442             if (streamTypeAlias == AudioSystem.STREAM_MUSIC &&
   1443                 (device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0 &&
   1444                 (flags & AudioManager.FLAG_BLUETOOTH_ABS_VOLUME) == 0) {
   1445                 synchronized (mA2dpAvrcpLock) {
   1446                     if (mA2dp != null && mAvrcpAbsVolSupported) {
   1447                         mA2dp.setAvrcpAbsoluteVolume(index / 10);
   1448                     }
   1449                 }
   1450             }
   1451 
   1452             if (streamTypeAlias == AudioSystem.STREAM_MUSIC) {
   1453                 setSystemAudioVolume(oldIndex, index, getStreamMaxVolume(streamType), flags);
   1454             }
   1455 
   1456             flags &= ~AudioManager.FLAG_FIXED_VOLUME;
   1457             if ((streamTypeAlias == AudioSystem.STREAM_MUSIC) &&
   1458                     ((device & mFixedVolumeDevices) != 0)) {
   1459                 flags |= AudioManager.FLAG_FIXED_VOLUME;
   1460 
   1461                 // volume is either 0 or max allowed for fixed volume devices
   1462                 if (index != 0) {
   1463                     if (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_ACTIVE &&
   1464                             (device & mSafeMediaVolumeDevices) != 0) {
   1465                         index = mSafeMediaVolumeIndex;
   1466                     } else {
   1467                         index = streamState.getMaxIndex();
   1468                     }
   1469                 }
   1470             }
   1471 
   1472             if (!checkSafeMediaVolume(streamTypeAlias, index, device)) {
   1473                 mVolumeController.postDisplaySafeVolumeWarning(flags);
   1474                 mPendingVolumeCommand = new StreamVolumeCommand(
   1475                                                     streamType, index, flags, device);
   1476             } else {
   1477                 onSetStreamVolume(streamType, index, flags, device, caller);
   1478                 index = mStreamStates[streamType].getIndex(device);
   1479             }
   1480         }
   1481         sendVolumeUpdate(streamType, oldIndex, index, flags);
   1482     }
   1483 
   1484     /** @see AudioManager#forceVolumeControlStream(int) */
   1485     public void forceVolumeControlStream(int streamType, IBinder cb) {
   1486         synchronized(mForceControlStreamLock) {
   1487             mVolumeControlStream = streamType;
   1488             if (mVolumeControlStream == -1) {
   1489                 if (mForceControlStreamClient != null) {
   1490                     mForceControlStreamClient.release();
   1491                     mForceControlStreamClient = null;
   1492                 }
   1493             } else {
   1494                 mForceControlStreamClient = new ForceControlStreamClient(cb);
   1495             }
   1496         }
   1497     }
   1498 
   1499     private class ForceControlStreamClient implements IBinder.DeathRecipient {
   1500         private IBinder mCb; // To be notified of client's death
   1501 
   1502         ForceControlStreamClient(IBinder cb) {
   1503             if (cb != null) {
   1504                 try {
   1505                     cb.linkToDeath(this, 0);
   1506                 } catch (RemoteException e) {
   1507                     // Client has died!
   1508                     Log.w(TAG, "ForceControlStreamClient() could not link to "+cb+" binder death");
   1509                     cb = null;
   1510                 }
   1511             }
   1512             mCb = cb;
   1513         }
   1514 
   1515         public void binderDied() {
   1516             synchronized(mForceControlStreamLock) {
   1517                 Log.w(TAG, "SCO client died");
   1518                 if (mForceControlStreamClient != this) {
   1519                     Log.w(TAG, "unregistered control stream client died");
   1520                 } else {
   1521                     mForceControlStreamClient = null;
   1522                     mVolumeControlStream = -1;
   1523                 }
   1524             }
   1525         }
   1526 
   1527         public void release() {
   1528             if (mCb != null) {
   1529                 mCb.unlinkToDeath(this, 0);
   1530                 mCb = null;
   1531             }
   1532         }
   1533     }
   1534 
   1535     private void sendBroadcastToAll(Intent intent) {
   1536         intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
   1537         intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
   1538         final long ident = Binder.clearCallingIdentity();
   1539         try {
   1540             mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
   1541         } finally {
   1542             Binder.restoreCallingIdentity(ident);
   1543         }
   1544     }
   1545 
   1546     private void sendStickyBroadcastToAll(Intent intent) {
   1547         intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
   1548         final long ident = Binder.clearCallingIdentity();
   1549         try {
   1550             mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
   1551         } finally {
   1552             Binder.restoreCallingIdentity(ident);
   1553         }
   1554     }
   1555 
   1556     private int getCurrentUserId() {
   1557         final long ident = Binder.clearCallingIdentity();
   1558         try {
   1559             UserInfo currentUser = ActivityManagerNative.getDefault().getCurrentUser();
   1560             return currentUser.id;
   1561         } catch (RemoteException e) {
   1562             // Activity manager not running, nothing we can do assume user 0.
   1563         } finally {
   1564             Binder.restoreCallingIdentity(ident);
   1565         }
   1566         return UserHandle.USER_OWNER;
   1567     }
   1568 
   1569     // UI update and Broadcast Intent
   1570     private void sendVolumeUpdate(int streamType, int oldIndex, int index, int flags) {
   1571         streamType = mStreamVolumeAlias[streamType];
   1572 
   1573         if (streamType == AudioSystem.STREAM_MUSIC) {
   1574             flags = updateFlagsForSystemAudio(flags);
   1575         }
   1576         mVolumeController.postVolumeChanged(streamType, flags);
   1577     }
   1578 
   1579     // If Hdmi-CEC system audio mode is on, we show volume bar only when TV
   1580     // receives volume notification from Audio Receiver.
   1581     private int updateFlagsForSystemAudio(int flags) {
   1582         if (mHdmiTvClient != null) {
   1583             synchronized (mHdmiTvClient) {
   1584                 if (mHdmiSystemAudioSupported &&
   1585                         ((flags & AudioManager.FLAG_HDMI_SYSTEM_AUDIO_VOLUME) == 0)) {
   1586                     flags &= ~AudioManager.FLAG_SHOW_UI;
   1587                 }
   1588             }
   1589         }
   1590         return flags;
   1591     }
   1592 
   1593     // UI update and Broadcast Intent
   1594     private void sendMasterMuteUpdate(boolean muted, int flags) {
   1595         mVolumeController.postMasterMuteChanged(updateFlagsForSystemAudio(flags));
   1596         broadcastMasterMuteStatus(muted);
   1597     }
   1598 
   1599     private void broadcastMasterMuteStatus(boolean muted) {
   1600         Intent intent = new Intent(AudioManager.MASTER_MUTE_CHANGED_ACTION);
   1601         intent.putExtra(AudioManager.EXTRA_MASTER_VOLUME_MUTED, muted);
   1602         intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT
   1603                 | Intent.FLAG_RECEIVER_REPLACE_PENDING);
   1604         sendStickyBroadcastToAll(intent);
   1605     }
   1606 
   1607     /**
   1608      * Sets the stream state's index, and posts a message to set system volume.
   1609      * This will not call out to the UI. Assumes a valid stream type.
   1610      *
   1611      * @param streamType Type of the stream
   1612      * @param index Desired volume index of the stream
   1613      * @param device the device whose volume must be changed
   1614      * @param force If true, set the volume even if the desired volume is same
   1615      * as the current volume.
   1616      */
   1617     private void setStreamVolumeInt(int streamType,
   1618                                     int index,
   1619                                     int device,
   1620                                     boolean force,
   1621                                     String caller) {
   1622         VolumeStreamState streamState = mStreamStates[streamType];
   1623 
   1624         if (streamState.setIndex(index, device, caller) || force) {
   1625             // Post message to set system volume (it in turn will post a message
   1626             // to persist).
   1627             sendMsg(mAudioHandler,
   1628                     MSG_SET_DEVICE_VOLUME,
   1629                     SENDMSG_QUEUE,
   1630                     device,
   1631                     0,
   1632                     streamState,
   1633                     0);
   1634         }
   1635     }
   1636 
   1637     private void setSystemAudioMute(boolean state) {
   1638         if (mHdmiManager == null || mHdmiTvClient == null) return;
   1639         synchronized (mHdmiManager) {
   1640             if (!mHdmiSystemAudioSupported) return;
   1641             synchronized (mHdmiTvClient) {
   1642                 final long token = Binder.clearCallingIdentity();
   1643                 try {
   1644                     mHdmiTvClient.setSystemAudioMute(state);
   1645                 } finally {
   1646                     Binder.restoreCallingIdentity(token);
   1647                 }
   1648             }
   1649         }
   1650     }
   1651 
   1652     /** get stream mute state. */
   1653     public boolean isStreamMute(int streamType) {
   1654         if (streamType == AudioManager.USE_DEFAULT_STREAM_TYPE) {
   1655             streamType = getActiveStreamType(streamType);
   1656         }
   1657         synchronized (VolumeStreamState.class) {
   1658             return mStreamStates[streamType].mIsMuted;
   1659         }
   1660     }
   1661 
   1662     private class RmtSbmxFullVolDeathHandler implements IBinder.DeathRecipient {
   1663         private IBinder mICallback; // To be notified of client's death
   1664 
   1665         RmtSbmxFullVolDeathHandler(IBinder cb) {
   1666             mICallback = cb;
   1667             try {
   1668                 cb.linkToDeath(this, 0/*flags*/);
   1669             } catch (RemoteException e) {
   1670                 Log.e(TAG, "can't link to death", e);
   1671             }
   1672         }
   1673 
   1674         boolean isHandlerFor(IBinder cb) {
   1675             return mICallback.equals(cb);
   1676         }
   1677 
   1678         void forget() {
   1679             try {
   1680                 mICallback.unlinkToDeath(this, 0/*flags*/);
   1681             } catch (NoSuchElementException e) {
   1682                 Log.e(TAG, "error unlinking to death", e);
   1683             }
   1684         }
   1685 
   1686         public void binderDied() {
   1687             Log.w(TAG, "Recorder with remote submix at full volume died " + mICallback);
   1688             forceRemoteSubmixFullVolume(false, mICallback);
   1689         }
   1690     }
   1691 
   1692     /**
   1693      * call must be synchronized on mRmtSbmxFullVolDeathHandlers
   1694      * @return true if there is a registered death handler, false otherwise */
   1695     private boolean discardRmtSbmxFullVolDeathHandlerFor(IBinder cb) {
   1696         Iterator<RmtSbmxFullVolDeathHandler> it = mRmtSbmxFullVolDeathHandlers.iterator();
   1697         while (it.hasNext()) {
   1698             final RmtSbmxFullVolDeathHandler handler = it.next();
   1699             if (handler.isHandlerFor(cb)) {
   1700                 handler.forget();
   1701                 mRmtSbmxFullVolDeathHandlers.remove(handler);
   1702                 return true;
   1703             }
   1704         }
   1705         return false;
   1706     }
   1707 
   1708     /** call synchronized on mRmtSbmxFullVolDeathHandlers */
   1709     private boolean hasRmtSbmxFullVolDeathHandlerFor(IBinder cb) {
   1710         Iterator<RmtSbmxFullVolDeathHandler> it = mRmtSbmxFullVolDeathHandlers.iterator();
   1711         while (it.hasNext()) {
   1712             if (it.next().isHandlerFor(cb)) {
   1713                 return true;
   1714             }
   1715         }
   1716         return false;
   1717     }
   1718 
   1719     private int mRmtSbmxFullVolRefCount = 0;
   1720     private ArrayList<RmtSbmxFullVolDeathHandler> mRmtSbmxFullVolDeathHandlers =
   1721             new ArrayList<RmtSbmxFullVolDeathHandler>();
   1722 
   1723     public void forceRemoteSubmixFullVolume(boolean startForcing, IBinder cb) {
   1724         if (cb == null) {
   1725             return;
   1726         }
   1727         if ((PackageManager.PERMISSION_GRANTED != mContext.checkCallingOrSelfPermission(
   1728                         android.Manifest.permission.CAPTURE_AUDIO_OUTPUT))) {
   1729             Log.w(TAG, "Trying to call forceRemoteSubmixFullVolume() without CAPTURE_AUDIO_OUTPUT");
   1730             return;
   1731         }
   1732         synchronized(mRmtSbmxFullVolDeathHandlers) {
   1733             boolean applyRequired = false;
   1734             if (startForcing) {
   1735                 if (!hasRmtSbmxFullVolDeathHandlerFor(cb)) {
   1736                     mRmtSbmxFullVolDeathHandlers.add(new RmtSbmxFullVolDeathHandler(cb));
   1737                     if (mRmtSbmxFullVolRefCount == 0) {
   1738                         mFullVolumeDevices |= AudioSystem.DEVICE_OUT_REMOTE_SUBMIX;
   1739                         mFixedVolumeDevices |= AudioSystem.DEVICE_OUT_REMOTE_SUBMIX;
   1740                         applyRequired = true;
   1741                     }
   1742                     mRmtSbmxFullVolRefCount++;
   1743                 }
   1744             } else {
   1745                 if (discardRmtSbmxFullVolDeathHandlerFor(cb) && (mRmtSbmxFullVolRefCount > 0)) {
   1746                     mRmtSbmxFullVolRefCount--;
   1747                     if (mRmtSbmxFullVolRefCount == 0) {
   1748                         mFullVolumeDevices &= ~AudioSystem.DEVICE_OUT_REMOTE_SUBMIX;
   1749                         mFixedVolumeDevices &= ~AudioSystem.DEVICE_OUT_REMOTE_SUBMIX;
   1750                         applyRequired = true;
   1751                     }
   1752                 }
   1753             }
   1754             if (applyRequired) {
   1755                 // Assumes only STREAM_MUSIC going through DEVICE_OUT_REMOTE_SUBMIX
   1756                 checkAllFixedVolumeDevices(AudioSystem.STREAM_MUSIC);
   1757                 mStreamStates[AudioSystem.STREAM_MUSIC].applyAllVolumes();
   1758             }
   1759         }
   1760     }
   1761 
   1762     private void setMasterMuteInternal(boolean mute, int flags, String callingPackage, int uid,
   1763             int userId) {
   1764         // If we are being called by the system check for user we are going to change
   1765         // so we handle user restrictions correctly.
   1766         if (uid == android.os.Process.SYSTEM_UID) {
   1767             uid = UserHandle.getUid(userId, UserHandle.getAppId(uid));
   1768         }
   1769         if (mAppOps.noteOp(AppOpsManager.OP_AUDIO_MASTER_VOLUME, uid, callingPackage)
   1770                 != AppOpsManager.MODE_ALLOWED) {
   1771             return;
   1772         }
   1773         if (userId != UserHandle.getCallingUserId() &&
   1774                 mContext.checkCallingOrSelfPermission(
   1775                         android.Manifest.permission.INTERACT_ACROSS_USERS_FULL)
   1776                 != PackageManager.PERMISSION_GRANTED) {
   1777             return;
   1778         }
   1779         if (getCurrentUserId() == userId) {
   1780             if (mute != AudioSystem.getMasterMute()) {
   1781                 setSystemAudioMute(mute);
   1782                 AudioSystem.setMasterMute(mute);
   1783                 // Post a persist master volume msg
   1784                 sendMsg(mAudioHandler, MSG_PERSIST_MASTER_VOLUME_MUTE, SENDMSG_REPLACE, mute ? 1
   1785                         : 0, userId, null, PERSIST_DELAY);
   1786                 sendMasterMuteUpdate(mute, flags);
   1787 
   1788                 Intent intent = new Intent(AudioManager.MASTER_MUTE_CHANGED_ACTION);
   1789                 intent.putExtra(AudioManager.EXTRA_MASTER_VOLUME_MUTED, mute);
   1790                 sendBroadcastToAll(intent);
   1791             }
   1792         } else {
   1793             // If not the current user just persist the setting which will be loaded
   1794             // on user switch.
   1795             sendMsg(mAudioHandler, MSG_PERSIST_MASTER_VOLUME_MUTE, SENDMSG_REPLACE, mute ? 1
   1796                     : 0, userId, null, PERSIST_DELAY);
   1797         }
   1798     }
   1799 
   1800     /** get master mute state. */
   1801     public boolean isMasterMute() {
   1802         return AudioSystem.getMasterMute();
   1803     }
   1804 
   1805     public void setMasterMute(boolean mute, int flags, String callingPackage, int userId) {
   1806         setMasterMuteInternal(mute, flags, callingPackage, Binder.getCallingUid(),
   1807                 userId);
   1808     }
   1809 
   1810     /** @see AudioManager#getStreamVolume(int) */
   1811     public int getStreamVolume(int streamType) {
   1812         ensureValidStreamType(streamType);
   1813         int device = getDeviceForStream(streamType);
   1814         synchronized (VolumeStreamState.class) {
   1815             int index = mStreamStates[streamType].getIndex(device);
   1816 
   1817             // by convention getStreamVolume() returns 0 when a stream is muted.
   1818             if (mStreamStates[streamType].mIsMuted) {
   1819                 index = 0;
   1820             }
   1821             if (index != 0 && (mStreamVolumeAlias[streamType] == AudioSystem.STREAM_MUSIC) &&
   1822                     (device & mFixedVolumeDevices) != 0) {
   1823                 index = mStreamStates[streamType].getMaxIndex();
   1824             }
   1825             return (index + 5) / 10;
   1826         }
   1827     }
   1828 
   1829     /** @see AudioManager#getStreamMaxVolume(int) */
   1830     public int getStreamMaxVolume(int streamType) {
   1831         ensureValidStreamType(streamType);
   1832         return (mStreamStates[streamType].getMaxIndex() + 5) / 10;
   1833     }
   1834 
   1835     /** @see AudioManager#getStreamMinVolume(int) */
   1836     public int getStreamMinVolume(int streamType) {
   1837         ensureValidStreamType(streamType);
   1838         return (mStreamStates[streamType].getMinIndex() + 5) / 10;
   1839     }
   1840 
   1841     /** Get last audible volume before stream was muted. */
   1842     public int getLastAudibleStreamVolume(int streamType) {
   1843         ensureValidStreamType(streamType);
   1844         int device = getDeviceForStream(streamType);
   1845         return (mStreamStates[streamType].getIndex(device) + 5) / 10;
   1846     }
   1847 
   1848     /** @see AudioManager#getUiSoundsStreamType()  */
   1849     public int getUiSoundsStreamType() {
   1850         return mStreamVolumeAlias[AudioSystem.STREAM_SYSTEM];
   1851     }
   1852 
   1853     /** @see AudioManager#setMicrophoneMute(boolean, int) */
   1854     public void setMicrophoneMute(boolean on, String callingPackage, int userId) {
   1855         // If we are being called by the system check for user we are going to change
   1856         // so we handle user restrictions correctly.
   1857         int uid = Binder.getCallingUid();
   1858         if (uid == android.os.Process.SYSTEM_UID) {
   1859             uid = UserHandle.getUid(userId, UserHandle.getAppId(uid));
   1860         }
   1861         if (mAppOps.noteOp(AppOpsManager.OP_MUTE_MICROPHONE, uid, callingPackage)
   1862                 != AppOpsManager.MODE_ALLOWED) {
   1863             return;
   1864         }
   1865         if (!checkAudioSettingsPermission("setMicrophoneMute()")) {
   1866             return;
   1867         }
   1868         if (userId != UserHandle.getCallingUserId() &&
   1869                 mContext.checkCallingOrSelfPermission(
   1870                 android.Manifest.permission.INTERACT_ACROSS_USERS_FULL)
   1871                 != PackageManager.PERMISSION_GRANTED) {
   1872             return;
   1873         }
   1874 
   1875         // If mute is for current user actually mute, else just persist the setting
   1876         // which will be loaded on user switch.
   1877         if (getCurrentUserId() == userId) {
   1878             AudioSystem.muteMicrophone(on);
   1879         }
   1880         // Post a persist microphone msg.
   1881         sendMsg(mAudioHandler, MSG_PERSIST_MICROPHONE_MUTE, SENDMSG_REPLACE, on ? 1
   1882                 : 0, userId, null, PERSIST_DELAY);
   1883     }
   1884 
   1885     @Override
   1886     public int getRingerModeExternal() {
   1887         synchronized(mSettingsLock) {
   1888             return mRingerModeExternal;
   1889         }
   1890     }
   1891 
   1892     @Override
   1893     public int getRingerModeInternal() {
   1894         synchronized(mSettingsLock) {
   1895             return mRingerMode;
   1896         }
   1897     }
   1898 
   1899     private void ensureValidRingerMode(int ringerMode) {
   1900         if (!isValidRingerMode(ringerMode)) {
   1901             throw new IllegalArgumentException("Bad ringer mode " + ringerMode);
   1902         }
   1903     }
   1904 
   1905     /** @see AudioManager#isValidRingerMode(int) */
   1906     public boolean isValidRingerMode(int ringerMode) {
   1907         return ringerMode >= 0 && ringerMode <= AudioManager.RINGER_MODE_MAX;
   1908     }
   1909 
   1910     public void setRingerModeExternal(int ringerMode, String caller) {
   1911         setRingerMode(ringerMode, caller, true /*external*/);
   1912     }
   1913 
   1914     public void setRingerModeInternal(int ringerMode, String caller) {
   1915         enforceVolumeController("setRingerModeInternal");
   1916         setRingerMode(ringerMode, caller, false /*external*/);
   1917     }
   1918 
   1919     private void setRingerMode(int ringerMode, String caller, boolean external) {
   1920         if (mUseFixedVolume || isPlatformTelevision()) {
   1921             return;
   1922         }
   1923         if (caller == null || caller.length() == 0) {
   1924             throw new IllegalArgumentException("Bad caller: " + caller);
   1925         }
   1926         ensureValidRingerMode(ringerMode);
   1927         if ((ringerMode == AudioManager.RINGER_MODE_VIBRATE) && !mHasVibrator) {
   1928             ringerMode = AudioManager.RINGER_MODE_SILENT;
   1929         }
   1930         final long identity = Binder.clearCallingIdentity();
   1931         try {
   1932             synchronized (mSettingsLock) {
   1933                 final int ringerModeInternal = getRingerModeInternal();
   1934                 final int ringerModeExternal = getRingerModeExternal();
   1935                 if (external) {
   1936                     setRingerModeExt(ringerMode);
   1937                     if (mRingerModeDelegate != null) {
   1938                         ringerMode = mRingerModeDelegate.onSetRingerModeExternal(ringerModeExternal,
   1939                                 ringerMode, caller, ringerModeInternal, mVolumePolicy);
   1940                     }
   1941                     if (ringerMode != ringerModeInternal) {
   1942                         setRingerModeInt(ringerMode, true /*persist*/);
   1943                     }
   1944                 } else /*internal*/ {
   1945                     if (ringerMode != ringerModeInternal) {
   1946                         setRingerModeInt(ringerMode, true /*persist*/);
   1947                     }
   1948                     if (mRingerModeDelegate != null) {
   1949                         ringerMode = mRingerModeDelegate.onSetRingerModeInternal(ringerModeInternal,
   1950                                 ringerMode, caller, ringerModeExternal, mVolumePolicy);
   1951                     }
   1952                     setRingerModeExt(ringerMode);
   1953                 }
   1954             }
   1955         } finally {
   1956             Binder.restoreCallingIdentity(identity);
   1957         }
   1958     }
   1959 
   1960     private void setRingerModeExt(int ringerMode) {
   1961         synchronized(mSettingsLock) {
   1962             if (ringerMode == mRingerModeExternal) return;
   1963             mRingerModeExternal = ringerMode;
   1964         }
   1965         // Send sticky broadcast
   1966         broadcastRingerMode(AudioManager.RINGER_MODE_CHANGED_ACTION, ringerMode);
   1967     }
   1968 
   1969     private void muteRingerModeStreams() {
   1970         // Mute stream if not previously muted by ringer mode and ringer mode
   1971         // is not RINGER_MODE_NORMAL and stream is affected by ringer mode.
   1972         // Unmute stream if previously muted by ringer mode and ringer mode
   1973         // is RINGER_MODE_NORMAL or stream is not affected by ringer mode.
   1974         int numStreamTypes = AudioSystem.getNumStreamTypes();
   1975         final boolean ringerModeMute = mRingerMode == AudioManager.RINGER_MODE_VIBRATE
   1976                 || mRingerMode == AudioManager.RINGER_MODE_SILENT;
   1977         for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
   1978             final boolean isMuted = isStreamMutedByRingerMode(streamType);
   1979             final boolean shouldMute = ringerModeMute && isStreamAffectedByRingerMode(streamType);
   1980             if (isMuted == shouldMute) continue;
   1981             if (!shouldMute) {
   1982                 // unmute
   1983                 // ring and notifications volume should never be 0 when not silenced
   1984                 if (mStreamVolumeAlias[streamType] == AudioSystem.STREAM_RING) {
   1985                     synchronized (VolumeStreamState.class) {
   1986                         final VolumeStreamState vss = mStreamStates[streamType];
   1987                         for (int i = 0; i < vss.mIndexMap.size(); i++) {
   1988                             int device = vss.mIndexMap.keyAt(i);
   1989                             int value = vss.mIndexMap.valueAt(i);
   1990                             if (value == 0) {
   1991                                 vss.setIndex(10, device, TAG);
   1992                             }
   1993                         }
   1994                         // Persist volume for stream ring when it is changed here
   1995                       final int device = getDeviceForStream(streamType);
   1996                       sendMsg(mAudioHandler,
   1997                               MSG_PERSIST_VOLUME,
   1998                               SENDMSG_QUEUE,
   1999                               device,
   2000                               0,
   2001                               mStreamStates[streamType],
   2002                               PERSIST_DELAY);
   2003                     }
   2004                 }
   2005                 mStreamStates[streamType].mute(false);
   2006                 mRingerModeMutedStreams &= ~(1 << streamType);
   2007             } else {
   2008                 // mute
   2009                 mStreamStates[streamType].mute(true);
   2010                 mRingerModeMutedStreams |= (1 << streamType);
   2011             }
   2012         }
   2013     }
   2014 
   2015     private void setRingerModeInt(int ringerMode, boolean persist) {
   2016         final boolean change;
   2017         synchronized(mSettingsLock) {
   2018             change = mRingerMode != ringerMode;
   2019             mRingerMode = ringerMode;
   2020         }
   2021 
   2022         muteRingerModeStreams();
   2023 
   2024         // Post a persist ringer mode msg
   2025         if (persist) {
   2026             sendMsg(mAudioHandler, MSG_PERSIST_RINGER_MODE,
   2027                     SENDMSG_REPLACE, 0, 0, null, PERSIST_DELAY);
   2028         }
   2029         if (change) {
   2030             // Send sticky broadcast
   2031             broadcastRingerMode(AudioManager.INTERNAL_RINGER_MODE_CHANGED_ACTION, ringerMode);
   2032         }
   2033     }
   2034 
   2035     /** @see AudioManager#shouldVibrate(int) */
   2036     public boolean shouldVibrate(int vibrateType) {
   2037         if (!mHasVibrator) return false;
   2038 
   2039         switch (getVibrateSetting(vibrateType)) {
   2040 
   2041             case AudioManager.VIBRATE_SETTING_ON:
   2042                 return getRingerModeExternal() != AudioManager.RINGER_MODE_SILENT;
   2043 
   2044             case AudioManager.VIBRATE_SETTING_ONLY_SILENT:
   2045                 return getRingerModeExternal() == AudioManager.RINGER_MODE_VIBRATE;
   2046 
   2047             case AudioManager.VIBRATE_SETTING_OFF:
   2048                 // return false, even for incoming calls
   2049                 return false;
   2050 
   2051             default:
   2052                 return false;
   2053         }
   2054     }
   2055 
   2056     /** @see AudioManager#getVibrateSetting(int) */
   2057     public int getVibrateSetting(int vibrateType) {
   2058         if (!mHasVibrator) return AudioManager.VIBRATE_SETTING_OFF;
   2059         return (mVibrateSetting >> (vibrateType * 2)) & 3;
   2060     }
   2061 
   2062     /** @see AudioManager#setVibrateSetting(int, int) */
   2063     public void setVibrateSetting(int vibrateType, int vibrateSetting) {
   2064 
   2065         if (!mHasVibrator) return;
   2066 
   2067         mVibrateSetting = AudioSystem.getValueForVibrateSetting(mVibrateSetting, vibrateType,
   2068                 vibrateSetting);
   2069 
   2070         // Broadcast change
   2071         broadcastVibrateSetting(vibrateType);
   2072 
   2073     }
   2074 
   2075     private class SetModeDeathHandler implements IBinder.DeathRecipient {
   2076         private IBinder mCb; // To be notified of client's death
   2077         private int mPid;
   2078         private int mMode = AudioSystem.MODE_NORMAL; // Current mode set by this client
   2079 
   2080         SetModeDeathHandler(IBinder cb, int pid) {
   2081             mCb = cb;
   2082             mPid = pid;
   2083         }
   2084 
   2085         public void binderDied() {
   2086             int newModeOwnerPid = 0;
   2087             synchronized(mSetModeDeathHandlers) {
   2088                 Log.w(TAG, "setMode() client died");
   2089                 int index = mSetModeDeathHandlers.indexOf(this);
   2090                 if (index < 0) {
   2091                     Log.w(TAG, "unregistered setMode() client died");
   2092                 } else {
   2093                     newModeOwnerPid = setModeInt(AudioSystem.MODE_NORMAL, mCb, mPid, TAG);
   2094                 }
   2095             }
   2096             // when entering RINGTONE, IN_CALL or IN_COMMUNICATION mode, clear all
   2097             // SCO connections not started by the application changing the mode
   2098             if (newModeOwnerPid != 0) {
   2099                 final long ident = Binder.clearCallingIdentity();
   2100                 disconnectBluetoothSco(newModeOwnerPid);
   2101                 Binder.restoreCallingIdentity(ident);
   2102             }
   2103         }
   2104 
   2105         public int getPid() {
   2106             return mPid;
   2107         }
   2108 
   2109         public void setMode(int mode) {
   2110             mMode = mode;
   2111         }
   2112 
   2113         public int getMode() {
   2114             return mMode;
   2115         }
   2116 
   2117         public IBinder getBinder() {
   2118             return mCb;
   2119         }
   2120     }
   2121 
   2122     /** @see AudioManager#setMode(int) */
   2123     public void setMode(int mode, IBinder cb, String callingPackage) {
   2124         if (DEBUG_MODE) { Log.v(TAG, "setMode(mode=" + mode + ", callingPackage=" + callingPackage + ")"); }
   2125         if (!checkAudioSettingsPermission("setMode()")) {
   2126             return;
   2127         }
   2128 
   2129         if ( (mode == AudioSystem.MODE_IN_CALL) &&
   2130                 (mContext.checkCallingOrSelfPermission(
   2131                         android.Manifest.permission.MODIFY_PHONE_STATE)
   2132                             != PackageManager.PERMISSION_GRANTED)) {
   2133             Log.w(TAG, "MODIFY_PHONE_STATE Permission Denial: setMode(MODE_IN_CALL) from pid="
   2134                     + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid());
   2135             return;
   2136         }
   2137 
   2138         if (mode < AudioSystem.MODE_CURRENT || mode >= AudioSystem.NUM_MODES) {
   2139             return;
   2140         }
   2141 
   2142         int newModeOwnerPid = 0;
   2143         synchronized(mSetModeDeathHandlers) {
   2144             if (mode == AudioSystem.MODE_CURRENT) {
   2145                 mode = mMode;
   2146             }
   2147             newModeOwnerPid = setModeInt(mode, cb, Binder.getCallingPid(), callingPackage);
   2148         }
   2149         // when entering RINGTONE, IN_CALL or IN_COMMUNICATION mode, clear all
   2150         // SCO connections not started by the application changing the mode
   2151         if (newModeOwnerPid != 0) {
   2152              disconnectBluetoothSco(newModeOwnerPid);
   2153         }
   2154     }
   2155 
   2156     // must be called synchronized on mSetModeDeathHandlers
   2157     // setModeInt() returns a valid PID if the audio mode was successfully set to
   2158     // any mode other than NORMAL.
   2159     private int setModeInt(int mode, IBinder cb, int pid, String caller) {
   2160         if (DEBUG_MODE) { Log.v(TAG, "setModeInt(mode=" + mode + ", pid=" + pid + ", caller="
   2161                 + caller + ")"); }
   2162         int newModeOwnerPid = 0;
   2163         if (cb == null) {
   2164             Log.e(TAG, "setModeInt() called with null binder");
   2165             return newModeOwnerPid;
   2166         }
   2167 
   2168         SetModeDeathHandler hdlr = null;
   2169         Iterator iter = mSetModeDeathHandlers.iterator();
   2170         while (iter.hasNext()) {
   2171             SetModeDeathHandler h = (SetModeDeathHandler)iter.next();
   2172             if (h.getPid() == pid) {
   2173                 hdlr = h;
   2174                 // Remove from client list so that it is re-inserted at top of list
   2175                 iter.remove();
   2176                 hdlr.getBinder().unlinkToDeath(hdlr, 0);
   2177                 break;
   2178             }
   2179         }
   2180         int status = AudioSystem.AUDIO_STATUS_OK;
   2181         do {
   2182             if (mode == AudioSystem.MODE_NORMAL) {
   2183                 // get new mode from client at top the list if any
   2184                 if (!mSetModeDeathHandlers.isEmpty()) {
   2185                     hdlr = mSetModeDeathHandlers.get(0);
   2186                     cb = hdlr.getBinder();
   2187                     mode = hdlr.getMode();
   2188                     if (DEBUG_MODE) {
   2189                         Log.w(TAG, " using mode=" + mode + " instead due to death hdlr at pid="
   2190                                 + hdlr.mPid);
   2191                     }
   2192                 }
   2193             } else {
   2194                 if (hdlr == null) {
   2195                     hdlr = new SetModeDeathHandler(cb, pid);
   2196                 }
   2197                 // Register for client death notification
   2198                 try {
   2199                     cb.linkToDeath(hdlr, 0);
   2200                 } catch (RemoteException e) {
   2201                     // Client has died!
   2202                     Log.w(TAG, "setMode() could not link to "+cb+" binder death");
   2203                 }
   2204 
   2205                 // Last client to call setMode() is always at top of client list
   2206                 // as required by SetModeDeathHandler.binderDied()
   2207                 mSetModeDeathHandlers.add(0, hdlr);
   2208                 hdlr.setMode(mode);
   2209             }
   2210 
   2211             if (mode != mMode) {
   2212                 status = AudioSystem.setPhoneState(mode);
   2213                 if (status == AudioSystem.AUDIO_STATUS_OK) {
   2214                     if (DEBUG_MODE) { Log.v(TAG, " mode successfully set to " + mode); }
   2215                     mMode = mode;
   2216                 } else {
   2217                     if (hdlr != null) {
   2218                         mSetModeDeathHandlers.remove(hdlr);
   2219                         cb.unlinkToDeath(hdlr, 0);
   2220                     }
   2221                     // force reading new top of mSetModeDeathHandlers stack
   2222                     if (DEBUG_MODE) { Log.w(TAG, " mode set to MODE_NORMAL after phoneState pb"); }
   2223                     mode = AudioSystem.MODE_NORMAL;
   2224                 }
   2225             } else {
   2226                 status = AudioSystem.AUDIO_STATUS_OK;
   2227             }
   2228         } while (status != AudioSystem.AUDIO_STATUS_OK && !mSetModeDeathHandlers.isEmpty());
   2229 
   2230         if (status == AudioSystem.AUDIO_STATUS_OK) {
   2231             if (mode != AudioSystem.MODE_NORMAL) {
   2232                 if (mSetModeDeathHandlers.isEmpty()) {
   2233                     Log.e(TAG, "setMode() different from MODE_NORMAL with empty mode client stack");
   2234                 } else {
   2235                     newModeOwnerPid = mSetModeDeathHandlers.get(0).getPid();
   2236                 }
   2237             }
   2238             int streamType = getActiveStreamType(AudioManager.USE_DEFAULT_STREAM_TYPE);
   2239             int device = getDeviceForStream(streamType);
   2240             int index = mStreamStates[mStreamVolumeAlias[streamType]].getIndex(device);
   2241             setStreamVolumeInt(mStreamVolumeAlias[streamType], index, device, true, caller);
   2242 
   2243             updateStreamVolumeAlias(true /*updateVolumes*/, caller);
   2244         }
   2245         return newModeOwnerPid;
   2246     }
   2247 
   2248     /** @see AudioManager#getMode() */
   2249     public int getMode() {
   2250         return mMode;
   2251     }
   2252 
   2253     //==========================================================================================
   2254     // Sound Effects
   2255     //==========================================================================================
   2256 
   2257     private static final String TAG_AUDIO_ASSETS = "audio_assets";
   2258     private static final String ATTR_VERSION = "version";
   2259     private static final String TAG_GROUP = "group";
   2260     private static final String ATTR_GROUP_NAME = "name";
   2261     private static final String TAG_ASSET = "asset";
   2262     private static final String ATTR_ASSET_ID = "id";
   2263     private static final String ATTR_ASSET_FILE = "file";
   2264 
   2265     private static final String ASSET_FILE_VERSION = "1.0";
   2266     private static final String GROUP_TOUCH_SOUNDS = "touch_sounds";
   2267 
   2268     private static final int SOUND_EFFECTS_LOAD_TIMEOUT_MS = 5000;
   2269 
   2270     class LoadSoundEffectReply {
   2271         public int mStatus = 1;
   2272     };
   2273 
   2274     private void loadTouchSoundAssetDefaults() {
   2275         SOUND_EFFECT_FILES.add("Effect_Tick.ogg");
   2276         for (int i = 0; i < AudioManager.NUM_SOUND_EFFECTS; i++) {
   2277             SOUND_EFFECT_FILES_MAP[i][0] = 0;
   2278             SOUND_EFFECT_FILES_MAP[i][1] = -1;
   2279         }
   2280     }
   2281 
   2282     private void loadTouchSoundAssets() {
   2283         XmlResourceParser parser = null;
   2284 
   2285         // only load assets once.
   2286         if (!SOUND_EFFECT_FILES.isEmpty()) {
   2287             return;
   2288         }
   2289 
   2290         loadTouchSoundAssetDefaults();
   2291 
   2292         try {
   2293             parser = mContext.getResources().getXml(com.android.internal.R.xml.audio_assets);
   2294 
   2295             XmlUtils.beginDocument(parser, TAG_AUDIO_ASSETS);
   2296             String version = parser.getAttributeValue(null, ATTR_VERSION);
   2297             boolean inTouchSoundsGroup = false;
   2298 
   2299             if (ASSET_FILE_VERSION.equals(version)) {
   2300                 while (true) {
   2301                     XmlUtils.nextElement(parser);
   2302                     String element = parser.getName();
   2303                     if (element == null) {
   2304                         break;
   2305                     }
   2306                     if (element.equals(TAG_GROUP)) {
   2307                         String name = parser.getAttributeValue(null, ATTR_GROUP_NAME);
   2308                         if (GROUP_TOUCH_SOUNDS.equals(name)) {
   2309                             inTouchSoundsGroup = true;
   2310                             break;
   2311                         }
   2312                     }
   2313                 }
   2314                 while (inTouchSoundsGroup) {
   2315                     XmlUtils.nextElement(parser);
   2316                     String element = parser.getName();
   2317                     if (element == null) {
   2318                         break;
   2319                     }
   2320                     if (element.equals(TAG_ASSET)) {
   2321                         String id = parser.getAttributeValue(null, ATTR_ASSET_ID);
   2322                         String file = parser.getAttributeValue(null, ATTR_ASSET_FILE);
   2323                         int fx;
   2324 
   2325                         try {
   2326                             Field field = AudioManager.class.getField(id);
   2327                             fx = field.getInt(null);
   2328                         } catch (Exception e) {
   2329                             Log.w(TAG, "Invalid touch sound ID: "+id);
   2330                             continue;
   2331                         }
   2332 
   2333                         int i = SOUND_EFFECT_FILES.indexOf(file);
   2334                         if (i == -1) {
   2335                             i = SOUND_EFFECT_FILES.size();
   2336                             SOUND_EFFECT_FILES.add(file);
   2337                         }
   2338                         SOUND_EFFECT_FILES_MAP[fx][0] = i;
   2339                     } else {
   2340                         break;
   2341                     }
   2342                 }
   2343             }
   2344         } catch (Resources.NotFoundException e) {
   2345             Log.w(TAG, "audio assets file not found", e);
   2346         } catch (XmlPullParserException e) {
   2347             Log.w(TAG, "XML parser exception reading touch sound assets", e);
   2348         } catch (IOException e) {
   2349             Log.w(TAG, "I/O exception reading touch sound assets", e);
   2350         } finally {
   2351             if (parser != null) {
   2352                 parser.close();
   2353             }
   2354         }
   2355     }
   2356 
   2357     /** @see AudioManager#playSoundEffect(int) */
   2358     public void playSoundEffect(int effectType) {
   2359         playSoundEffectVolume(effectType, -1.0f);
   2360     }
   2361 
   2362     /** @see AudioManager#playSoundEffect(int, float) */
   2363     public void playSoundEffectVolume(int effectType, float volume) {
   2364         if (effectType >= AudioManager.NUM_SOUND_EFFECTS || effectType < 0) {
   2365             Log.w(TAG, "AudioService effectType value " + effectType + " out of range");
   2366             return;
   2367         }
   2368 
   2369         sendMsg(mAudioHandler, MSG_PLAY_SOUND_EFFECT, SENDMSG_QUEUE,
   2370                 effectType, (int) (volume * 1000), null, 0);
   2371     }
   2372 
   2373     /**
   2374      * Loads samples into the soundpool.
   2375      * This method must be called at first when sound effects are enabled
   2376      */
   2377     public boolean loadSoundEffects() {
   2378         int attempts = 3;
   2379         LoadSoundEffectReply reply = new LoadSoundEffectReply();
   2380 
   2381         synchronized (reply) {
   2382             sendMsg(mAudioHandler, MSG_LOAD_SOUND_EFFECTS, SENDMSG_QUEUE, 0, 0, reply, 0);
   2383             while ((reply.mStatus == 1) && (attempts-- > 0)) {
   2384                 try {
   2385                     reply.wait(SOUND_EFFECTS_LOAD_TIMEOUT_MS);
   2386                 } catch (InterruptedException e) {
   2387                     Log.w(TAG, "loadSoundEffects Interrupted while waiting sound pool loaded.");
   2388                 }
   2389             }
   2390         }
   2391         return (reply.mStatus == 0);
   2392     }
   2393 
   2394     /**
   2395      *  Unloads samples from the sound pool.
   2396      *  This method can be called to free some memory when
   2397      *  sound effects are disabled.
   2398      */
   2399     public void unloadSoundEffects() {
   2400         sendMsg(mAudioHandler, MSG_UNLOAD_SOUND_EFFECTS, SENDMSG_QUEUE, 0, 0, null, 0);
   2401     }
   2402 
   2403     class SoundPoolListenerThread extends Thread {
   2404         public SoundPoolListenerThread() {
   2405             super("SoundPoolListenerThread");
   2406         }
   2407 
   2408         @Override
   2409         public void run() {
   2410 
   2411             Looper.prepare();
   2412             mSoundPoolLooper = Looper.myLooper();
   2413 
   2414             synchronized (mSoundEffectsLock) {
   2415                 if (mSoundPool != null) {
   2416                     mSoundPoolCallBack = new SoundPoolCallback();
   2417                     mSoundPool.setOnLoadCompleteListener(mSoundPoolCallBack);
   2418                 }
   2419                 mSoundEffectsLock.notify();
   2420             }
   2421             Looper.loop();
   2422         }
   2423     }
   2424 
   2425     private final class SoundPoolCallback implements
   2426             android.media.SoundPool.OnLoadCompleteListener {
   2427 
   2428         int mStatus = 1; // 1 means neither error nor last sample loaded yet
   2429         List<Integer> mSamples = new ArrayList<Integer>();
   2430 
   2431         public int status() {
   2432             return mStatus;
   2433         }
   2434 
   2435         public void setSamples(int[] samples) {
   2436             for (int i = 0; i < samples.length; i++) {
   2437                 // do not wait ack for samples rejected upfront by SoundPool
   2438                 if (samples[i] > 0) {
   2439                     mSamples.add(samples[i]);
   2440                 }
   2441             }
   2442         }
   2443 
   2444         public void onLoadComplete(SoundPool soundPool, int sampleId, int status) {
   2445             synchronized (mSoundEffectsLock) {
   2446                 int i = mSamples.indexOf(sampleId);
   2447                 if (i >= 0) {
   2448                     mSamples.remove(i);
   2449                 }
   2450                 if ((status != 0) || mSamples. isEmpty()) {
   2451                     mStatus = status;
   2452                     mSoundEffectsLock.notify();
   2453                 }
   2454             }
   2455         }
   2456     }
   2457 
   2458     /** @see AudioManager#reloadAudioSettings() */
   2459     public void reloadAudioSettings() {
   2460         readAudioSettings(false /*userSwitch*/);
   2461     }
   2462 
   2463     private void readAudioSettings(boolean userSwitch) {
   2464         // restore ringer mode, ringer mode affected streams, mute affected streams and vibrate settings
   2465         readPersistedSettings();
   2466 
   2467         // restore volume settings
   2468         int numStreamTypes = AudioSystem.getNumStreamTypes();
   2469         for (int streamType = 0; streamType < numStreamTypes; streamType++) {
   2470             VolumeStreamState streamState = mStreamStates[streamType];
   2471 
   2472             if (userSwitch && mStreamVolumeAlias[streamType] == AudioSystem.STREAM_MUSIC) {
   2473                 continue;
   2474             }
   2475 
   2476             streamState.readSettings();
   2477             synchronized (VolumeStreamState.class) {
   2478                 // unmute stream that was muted but is not affect by mute anymore
   2479                 if (streamState.mIsMuted && ((!isStreamAffectedByMute(streamType) &&
   2480                         !isStreamMutedByRingerMode(streamType)) || mUseFixedVolume)) {
   2481                     streamState.mIsMuted = false;
   2482                 }
   2483             }
   2484         }
   2485 
   2486         // apply new ringer mode before checking volume for alias streams so that streams
   2487         // muted by ringer mode have the correct volume
   2488         setRingerModeInt(getRingerModeInternal(), false);
   2489 
   2490         checkAllFixedVolumeDevices();
   2491         checkAllAliasStreamVolumes();
   2492         checkMuteAffectedStreams();
   2493 
   2494         synchronized (mSafeMediaVolumeState) {
   2495             mMusicActiveMs = MathUtils.constrain(Settings.Secure.getIntForUser(mContentResolver,
   2496                     Settings.Secure.UNSAFE_VOLUME_MUSIC_ACTIVE_MS, 0, UserHandle.USER_CURRENT),
   2497                     0, UNSAFE_VOLUME_MUSIC_ACTIVE_MS_MAX);
   2498             if (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_ACTIVE) {
   2499                 enforceSafeMediaVolume(TAG);
   2500             }
   2501         }
   2502     }
   2503 
   2504     /** @see AudioManager#setSpeakerphoneOn(boolean) */
   2505     public void setSpeakerphoneOn(boolean on){
   2506         if (!checkAudioSettingsPermission("setSpeakerphoneOn()")) {
   2507             return;
   2508         }
   2509 
   2510         if (on) {
   2511             if (mForcedUseForComm == AudioSystem.FORCE_BT_SCO) {
   2512                     sendMsg(mAudioHandler, MSG_SET_FORCE_USE, SENDMSG_QUEUE,
   2513                             AudioSystem.FOR_RECORD, AudioSystem.FORCE_NONE, null, 0);
   2514             }
   2515             mForcedUseForComm = AudioSystem.FORCE_SPEAKER;
   2516         } else if (mForcedUseForComm == AudioSystem.FORCE_SPEAKER){
   2517             mForcedUseForComm = AudioSystem.FORCE_NONE;
   2518         }
   2519 
   2520         sendMsg(mAudioHandler, MSG_SET_FORCE_USE, SENDMSG_QUEUE,
   2521                 AudioSystem.FOR_COMMUNICATION, mForcedUseForComm, null, 0);
   2522     }
   2523 
   2524     /** @see AudioManager#isSpeakerphoneOn() */
   2525     public boolean isSpeakerphoneOn() {
   2526         return (mForcedUseForComm == AudioSystem.FORCE_SPEAKER);
   2527     }
   2528 
   2529     /** @see AudioManager#setBluetoothScoOn(boolean) */
   2530     public void setBluetoothScoOn(boolean on){
   2531         if (!checkAudioSettingsPermission("setBluetoothScoOn()")) {
   2532             return;
   2533         }
   2534 
   2535         if (on) {
   2536             mForcedUseForComm = AudioSystem.FORCE_BT_SCO;
   2537         } else if (mForcedUseForComm == AudioSystem.FORCE_BT_SCO) {
   2538             mForcedUseForComm = AudioSystem.FORCE_NONE;
   2539         }
   2540 
   2541         sendMsg(mAudioHandler, MSG_SET_FORCE_USE, SENDMSG_QUEUE,
   2542                 AudioSystem.FOR_COMMUNICATION, mForcedUseForComm, null, 0);
   2543         sendMsg(mAudioHandler, MSG_SET_FORCE_USE, SENDMSG_QUEUE,
   2544                 AudioSystem.FOR_RECORD, mForcedUseForComm, null, 0);
   2545     }
   2546 
   2547     /** @see AudioManager#isBluetoothScoOn() */
   2548     public boolean isBluetoothScoOn() {
   2549         return (mForcedUseForComm == AudioSystem.FORCE_BT_SCO);
   2550     }
   2551 
   2552     /** @see AudioManager#setBluetoothA2dpOn(boolean) */
   2553     public void setBluetoothA2dpOn(boolean on) {
   2554         synchronized (mBluetoothA2dpEnabledLock) {
   2555             mBluetoothA2dpEnabled = on;
   2556             sendMsg(mAudioHandler, MSG_SET_FORCE_BT_A2DP_USE, SENDMSG_QUEUE,
   2557                     AudioSystem.FOR_MEDIA,
   2558                     mBluetoothA2dpEnabled ? AudioSystem.FORCE_NONE : AudioSystem.FORCE_NO_BT_A2DP,
   2559                     null, 0);
   2560         }
   2561     }
   2562 
   2563     /** @see AudioManager#isBluetoothA2dpOn() */
   2564     public boolean isBluetoothA2dpOn() {
   2565         synchronized (mBluetoothA2dpEnabledLock) {
   2566             return mBluetoothA2dpEnabled;
   2567         }
   2568     }
   2569 
   2570     /** @see AudioManager#startBluetoothSco() */
   2571     public void startBluetoothSco(IBinder cb, int targetSdkVersion) {
   2572         int scoAudioMode =
   2573                 (targetSdkVersion < Build.VERSION_CODES.JELLY_BEAN_MR2) ?
   2574                         SCO_MODE_VIRTUAL_CALL : SCO_MODE_UNDEFINED;
   2575         startBluetoothScoInt(cb, scoAudioMode);
   2576     }
   2577 
   2578     /** @see AudioManager#startBluetoothScoVirtualCall() */
   2579     public void startBluetoothScoVirtualCall(IBinder cb) {
   2580         startBluetoothScoInt(cb, SCO_MODE_VIRTUAL_CALL);
   2581     }
   2582 
   2583     void startBluetoothScoInt(IBinder cb, int scoAudioMode){
   2584         if (!checkAudioSettingsPermission("startBluetoothSco()") ||
   2585                 !mSystemReady) {
   2586             return;
   2587         }
   2588         ScoClient client = getScoClient(cb, true);
   2589         // The calling identity must be cleared before calling ScoClient.incCount().
   2590         // inCount() calls requestScoState() which in turn can call BluetoothHeadset APIs
   2591         // and this must be done on behalf of system server to make sure permissions are granted.
   2592         // The caller identity must be cleared after getScoClient() because it is needed if a new
   2593         // client is created.
   2594         final long ident = Binder.clearCallingIdentity();
   2595         client.incCount(scoAudioMode);
   2596         Binder.restoreCallingIdentity(ident);
   2597     }
   2598 
   2599     /** @see AudioManager#stopBluetoothSco() */
   2600     public void stopBluetoothSco(IBinder cb){
   2601         if (!checkAudioSettingsPermission("stopBluetoothSco()") ||
   2602                 !mSystemReady) {
   2603             return;
   2604         }
   2605         ScoClient client = getScoClient(cb, false);
   2606         // The calling identity must be cleared before calling ScoClient.decCount().
   2607         // decCount() calls requestScoState() which in turn can call BluetoothHeadset APIs
   2608         // and this must be done on behalf of system server to make sure permissions are granted.
   2609         final long ident = Binder.clearCallingIdentity();
   2610         if (client != null) {
   2611             client.decCount();
   2612         }
   2613         Binder.restoreCallingIdentity(ident);
   2614     }
   2615 
   2616 
   2617     private class ScoClient implements IBinder.DeathRecipient {
   2618         private IBinder mCb; // To be notified of client's death
   2619         private int mCreatorPid;
   2620         private int mStartcount; // number of SCO connections started by this client
   2621 
   2622         ScoClient(IBinder cb) {
   2623             mCb = cb;
   2624             mCreatorPid = Binder.getCallingPid();
   2625             mStartcount = 0;
   2626         }
   2627 
   2628         public void binderDied() {
   2629             synchronized(mScoClients) {
   2630                 Log.w(TAG, "SCO client died");
   2631                 int index = mScoClients.indexOf(this);
   2632                 if (index < 0) {
   2633                     Log.w(TAG, "unregistered SCO client died");
   2634                 } else {
   2635                     clearCount(true);
   2636                     mScoClients.remove(this);
   2637                 }
   2638             }
   2639         }
   2640 
   2641         public void incCount(int scoAudioMode) {
   2642             synchronized(mScoClients) {
   2643                 requestScoState(BluetoothHeadset.STATE_AUDIO_CONNECTED, scoAudioMode);
   2644                 if (mStartcount == 0) {
   2645                     try {
   2646                         mCb.linkToDeath(this, 0);
   2647                     } catch (RemoteException e) {
   2648                         // client has already died!
   2649                         Log.w(TAG, "ScoClient  incCount() could not link to "+mCb+" binder death");
   2650                     }
   2651                 }
   2652                 mStartcount++;
   2653             }
   2654         }
   2655 
   2656         public void decCount() {
   2657             synchronized(mScoClients) {
   2658                 if (mStartcount == 0) {
   2659                     Log.w(TAG, "ScoClient.decCount() already 0");
   2660                 } else {
   2661                     mStartcount--;
   2662                     if (mStartcount == 0) {
   2663                         try {
   2664                             mCb.unlinkToDeath(this, 0);
   2665                         } catch (NoSuchElementException e) {
   2666                             Log.w(TAG, "decCount() going to 0 but not registered to binder");
   2667                         }
   2668                     }
   2669                     requestScoState(BluetoothHeadset.STATE_AUDIO_DISCONNECTED, 0);
   2670                 }
   2671             }
   2672         }
   2673 
   2674         public void clearCount(boolean stopSco) {
   2675             synchronized(mScoClients) {
   2676                 if (mStartcount != 0) {
   2677                     try {
   2678                         mCb.unlinkToDeath(this, 0);
   2679                     } catch (NoSuchElementException e) {
   2680                         Log.w(TAG, "clearCount() mStartcount: "+mStartcount+" != 0 but not registered to binder");
   2681                     }
   2682                 }
   2683                 mStartcount = 0;
   2684                 if (stopSco) {
   2685                     requestScoState(BluetoothHeadset.STATE_AUDIO_DISCONNECTED, 0);
   2686                 }
   2687             }
   2688         }
   2689 
   2690         public int getCount() {
   2691             return mStartcount;
   2692         }
   2693 
   2694         public IBinder getBinder() {
   2695             return mCb;
   2696         }
   2697 
   2698         public int getPid() {
   2699             return mCreatorPid;
   2700         }
   2701 
   2702         public int totalCount() {
   2703             synchronized(mScoClients) {
   2704                 int count = 0;
   2705                 int size = mScoClients.size();
   2706                 for (int i = 0; i < size; i++) {
   2707                     count += mScoClients.get(i).getCount();
   2708                 }
   2709                 return count;
   2710             }
   2711         }
   2712 
   2713         private void requestScoState(int state, int scoAudioMode) {
   2714             checkScoAudioState();
   2715             if (totalCount() == 0) {
   2716                 if (state == BluetoothHeadset.STATE_AUDIO_CONNECTED) {
   2717                     // Make sure that the state transitions to CONNECTING even if we cannot initiate
   2718                     // the connection.
   2719                     broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_CONNECTING);
   2720                     // Accept SCO audio activation only in NORMAL audio mode or if the mode is
   2721                     // currently controlled by the same client process.
   2722                     synchronized(mSetModeDeathHandlers) {
   2723                         if ((mSetModeDeathHandlers.isEmpty() ||
   2724                                 mSetModeDeathHandlers.get(0).getPid() == mCreatorPid) &&
   2725                                 (mScoAudioState == SCO_STATE_INACTIVE ||
   2726                                  mScoAudioState == SCO_STATE_DEACTIVATE_REQ)) {
   2727                             if (mScoAudioState == SCO_STATE_INACTIVE) {
   2728                                 mScoAudioMode = scoAudioMode;
   2729                                 if (scoAudioMode == SCO_MODE_UNDEFINED) {
   2730                                     if (mBluetoothHeadsetDevice != null) {
   2731                                         mScoAudioMode = new Integer(Settings.Global.getInt(
   2732                                                                 mContentResolver,
   2733                                                                 "bluetooth_sco_channel_"+
   2734                                                                 mBluetoothHeadsetDevice.getAddress(),
   2735                                                                 SCO_MODE_VIRTUAL_CALL));
   2736                                         if (mScoAudioMode > SCO_MODE_MAX || mScoAudioMode < 0) {
   2737                                             mScoAudioMode = SCO_MODE_VIRTUAL_CALL;
   2738                                         }
   2739                                     } else {
   2740                                         mScoAudioMode = SCO_MODE_RAW;
   2741                                     }
   2742                                 }
   2743                                 if (mBluetoothHeadset != null && mBluetoothHeadsetDevice != null) {
   2744                                     boolean status = false;
   2745                                     if (mScoAudioMode == SCO_MODE_RAW) {
   2746                                         status = mBluetoothHeadset.connectAudio();
   2747                                     } else if (mScoAudioMode == SCO_MODE_VIRTUAL_CALL) {
   2748                                         status = mBluetoothHeadset.startScoUsingVirtualVoiceCall(
   2749                                                                             mBluetoothHeadsetDevice);
   2750                                     } else if (mScoAudioMode == SCO_MODE_VR) {
   2751                                         status = mBluetoothHeadset.startVoiceRecognition(
   2752                                                                            mBluetoothHeadsetDevice);
   2753                                     }
   2754 
   2755                                     if (status) {
   2756                                         mScoAudioState = SCO_STATE_ACTIVE_INTERNAL;
   2757                                     } else {
   2758                                         broadcastScoConnectionState(
   2759                                                 AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
   2760                                     }
   2761                                 } else if (getBluetoothHeadset()) {
   2762                                     mScoAudioState = SCO_STATE_ACTIVATE_REQ;
   2763                                 }
   2764                             } else {
   2765                                 mScoAudioState = SCO_STATE_ACTIVE_INTERNAL;
   2766                                 broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_CONNECTED);
   2767                             }
   2768                         } else {
   2769                             broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
   2770                         }
   2771                     }
   2772                 } else if (state == BluetoothHeadset.STATE_AUDIO_DISCONNECTED &&
   2773                               (mScoAudioState == SCO_STATE_ACTIVE_INTERNAL ||
   2774                                mScoAudioState == SCO_STATE_ACTIVATE_REQ)) {
   2775                     if (mScoAudioState == SCO_STATE_ACTIVE_INTERNAL) {
   2776                         if (mBluetoothHeadset != null && mBluetoothHeadsetDevice != null) {
   2777                             boolean status = false;
   2778                             if (mScoAudioMode == SCO_MODE_RAW) {
   2779                                 status = mBluetoothHeadset.disconnectAudio();
   2780                             } else if (mScoAudioMode == SCO_MODE_VIRTUAL_CALL) {
   2781                                 status = mBluetoothHeadset.stopScoUsingVirtualVoiceCall(
   2782                                                                         mBluetoothHeadsetDevice);
   2783                             } else if (mScoAudioMode == SCO_MODE_VR) {
   2784                                         status = mBluetoothHeadset.stopVoiceRecognition(
   2785                                                                       mBluetoothHeadsetDevice);
   2786                             }
   2787 
   2788                             if (!status) {
   2789                                 mScoAudioState = SCO_STATE_INACTIVE;
   2790                                 broadcastScoConnectionState(
   2791                                         AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
   2792                             }
   2793                         } else if (getBluetoothHeadset()) {
   2794                             mScoAudioState = SCO_STATE_DEACTIVATE_REQ;
   2795                         }
   2796                     } else {
   2797                         mScoAudioState = SCO_STATE_INACTIVE;
   2798                         broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
   2799                     }
   2800                 }
   2801             }
   2802         }
   2803     }
   2804 
   2805     private void checkScoAudioState() {
   2806         if (mBluetoothHeadset != null && mBluetoothHeadsetDevice != null &&
   2807                 mScoAudioState == SCO_STATE_INACTIVE &&
   2808                 mBluetoothHeadset.getAudioState(mBluetoothHeadsetDevice)
   2809                 != BluetoothHeadset.STATE_AUDIO_DISCONNECTED) {
   2810             mScoAudioState = SCO_STATE_ACTIVE_EXTERNAL;
   2811         }
   2812     }
   2813 
   2814     private ScoClient getScoClient(IBinder cb, boolean create) {
   2815         synchronized(mScoClients) {
   2816             ScoClient client = null;
   2817             int size = mScoClients.size();
   2818             for (int i = 0; i < size; i++) {
   2819                 client = mScoClients.get(i);
   2820                 if (client.getBinder() == cb)
   2821                     return client;
   2822             }
   2823             if (create) {
   2824                 client = new ScoClient(cb);
   2825                 mScoClients.add(client);
   2826             }
   2827             return client;
   2828         }
   2829     }
   2830 
   2831     public void clearAllScoClients(int exceptPid, boolean stopSco) {
   2832         synchronized(mScoClients) {
   2833             ScoClient savedClient = null;
   2834             int size = mScoClients.size();
   2835             for (int i = 0; i < size; i++) {
   2836                 ScoClient cl = mScoClients.get(i);
   2837                 if (cl.getPid() != exceptPid) {
   2838                     cl.clearCount(stopSco);
   2839                 } else {
   2840                     savedClient = cl;
   2841                 }
   2842             }
   2843             mScoClients.clear();
   2844             if (savedClient != null) {
   2845                 mScoClients.add(savedClient);
   2846             }
   2847         }
   2848     }
   2849 
   2850     private boolean getBluetoothHeadset() {
   2851         boolean result = false;
   2852         BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
   2853         if (adapter != null) {
   2854             result = adapter.getProfileProxy(mContext, mBluetoothProfileServiceListener,
   2855                                     BluetoothProfile.HEADSET);
   2856         }
   2857         // If we could not get a bluetooth headset proxy, send a failure message
   2858         // without delay to reset the SCO audio state and clear SCO clients.
   2859         // If we could get a proxy, send a delayed failure message that will reset our state
   2860         // in case we don't receive onServiceConnected().
   2861         sendMsg(mAudioHandler, MSG_BT_HEADSET_CNCT_FAILED,
   2862                 SENDMSG_REPLACE, 0, 0, null, result ? BT_HEADSET_CNCT_TIMEOUT_MS : 0);
   2863         return result;
   2864     }
   2865 
   2866     private void disconnectBluetoothSco(int exceptPid) {
   2867         synchronized(mScoClients) {
   2868             checkScoAudioState();
   2869             if (mScoAudioState == SCO_STATE_ACTIVE_EXTERNAL ||
   2870                     mScoAudioState == SCO_STATE_DEACTIVATE_EXT_REQ) {
   2871                 if (mBluetoothHeadsetDevice != null) {
   2872                     if (mBluetoothHeadset != null) {
   2873                         if (!mBluetoothHeadset.stopVoiceRecognition(
   2874                                 mBluetoothHeadsetDevice)) {
   2875                             sendMsg(mAudioHandler, MSG_BT_HEADSET_CNCT_FAILED,
   2876                                     SENDMSG_REPLACE, 0, 0, null, 0);
   2877                         }
   2878                     } else if (mScoAudioState == SCO_STATE_ACTIVE_EXTERNAL &&
   2879                             getBluetoothHeadset()) {
   2880                         mScoAudioState = SCO_STATE_DEACTIVATE_EXT_REQ;
   2881                     }
   2882                 }
   2883             } else {
   2884                 clearAllScoClients(exceptPid, true);
   2885             }
   2886         }
   2887     }
   2888 
   2889     private void resetBluetoothSco() {
   2890         synchronized(mScoClients) {
   2891             clearAllScoClients(0, false);
   2892             mScoAudioState = SCO_STATE_INACTIVE;
   2893             broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
   2894         }
   2895     }
   2896 
   2897     private void broadcastScoConnectionState(int state) {
   2898         sendMsg(mAudioHandler, MSG_BROADCAST_BT_CONNECTION_STATE,
   2899                 SENDMSG_QUEUE, state, 0, null, 0);
   2900     }
   2901 
   2902     private void onBroadcastScoConnectionState(int state) {
   2903         if (state != mScoConnectionState) {
   2904             Intent newIntent = new Intent(AudioManager.ACTION_SCO_AUDIO_STATE_UPDATED);
   2905             newIntent.putExtra(AudioManager.EXTRA_SCO_AUDIO_STATE, state);
   2906             newIntent.putExtra(AudioManager.EXTRA_SCO_AUDIO_PREVIOUS_STATE,
   2907                     mScoConnectionState);
   2908             sendStickyBroadcastToAll(newIntent);
   2909             mScoConnectionState = state;
   2910         }
   2911     }
   2912 
   2913     void setBtScoDeviceConnectionState(BluetoothDevice btDevice, int state) {
   2914         if (btDevice == null) {
   2915             return;
   2916         }
   2917 
   2918         String address = btDevice.getAddress();
   2919         BluetoothClass btClass = btDevice.getBluetoothClass();
   2920         int outDevice = AudioSystem.DEVICE_OUT_BLUETOOTH_SCO;
   2921         int inDevice = AudioSystem.DEVICE_IN_BLUETOOTH_SCO_HEADSET;
   2922         if (btClass != null) {
   2923             switch (btClass.getDeviceClass()) {
   2924             case BluetoothClass.Device.AUDIO_VIDEO_WEARABLE_HEADSET:
   2925             case BluetoothClass.Device.AUDIO_VIDEO_HANDSFREE:
   2926                 outDevice = AudioSystem.DEVICE_OUT_BLUETOOTH_SCO_HEADSET;
   2927                 break;
   2928             case BluetoothClass.Device.AUDIO_VIDEO_CAR_AUDIO:
   2929                 outDevice = AudioSystem.DEVICE_OUT_BLUETOOTH_SCO_CARKIT;
   2930                 break;
   2931             }
   2932         }
   2933 
   2934         if (!BluetoothAdapter.checkBluetoothAddress(address)) {
   2935             address = "";
   2936         }
   2937 
   2938         boolean connected = (state == BluetoothProfile.STATE_CONNECTED);
   2939 
   2940         String btDeviceName =  btDevice.getName();
   2941         boolean success =
   2942             handleDeviceConnection(connected, outDevice, address, btDeviceName) &&
   2943             handleDeviceConnection(connected, inDevice, address, btDeviceName);
   2944         if (success) {
   2945             synchronized (mScoClients) {
   2946                 if (connected) {
   2947                     mBluetoothHeadsetDevice = btDevice;
   2948                 } else {
   2949                     mBluetoothHeadsetDevice = null;
   2950                     resetBluetoothSco();
   2951                 }
   2952             }
   2953         }
   2954     }
   2955 
   2956     private BluetoothProfile.ServiceListener mBluetoothProfileServiceListener =
   2957         new BluetoothProfile.ServiceListener() {
   2958         public void onServiceConnected(int profile, BluetoothProfile proxy) {
   2959             BluetoothDevice btDevice;
   2960             List<BluetoothDevice> deviceList;
   2961             switch(profile) {
   2962             case BluetoothProfile.A2DP:
   2963                 synchronized (mConnectedDevices) {
   2964                     synchronized (mA2dpAvrcpLock) {
   2965                         mA2dp = (BluetoothA2dp) proxy;
   2966                         deviceList = mA2dp.getConnectedDevices();
   2967                         if (deviceList.size() > 0) {
   2968                             btDevice = deviceList.get(0);
   2969                             int state = mA2dp.getConnectionState(btDevice);
   2970                             int delay = checkSendBecomingNoisyIntent(
   2971                                                 AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
   2972                                                 (state == BluetoothA2dp.STATE_CONNECTED) ? 1 : 0);
   2973                             queueMsgUnderWakeLock(mAudioHandler,
   2974                                     MSG_SET_A2DP_SINK_CONNECTION_STATE,
   2975                                     state,
   2976                                     0,
   2977                                     btDevice,
   2978                                     delay);
   2979                         }
   2980                     }
   2981                 }
   2982                 break;
   2983 
   2984             case BluetoothProfile.A2DP_SINK:
   2985                 deviceList = proxy.getConnectedDevices();
   2986                 if (deviceList.size() > 0) {
   2987                     btDevice = deviceList.get(0);
   2988                     synchronized (mConnectedDevices) {
   2989                         int state = proxy.getConnectionState(btDevice);
   2990                         queueMsgUnderWakeLock(mAudioHandler,
   2991                                 MSG_SET_A2DP_SRC_CONNECTION_STATE,
   2992                                 state,
   2993                                 0,
   2994                                 btDevice,
   2995                                 0 /* delay */);
   2996                     }
   2997                 }
   2998                 break;
   2999 
   3000             case BluetoothProfile.HEADSET:
   3001                 synchronized (mScoClients) {
   3002                     // Discard timeout message
   3003                     mAudioHandler.removeMessages(MSG_BT_HEADSET_CNCT_FAILED);
   3004                     mBluetoothHeadset = (BluetoothHeadset) proxy;
   3005                     deviceList = mBluetoothHeadset.getConnectedDevices();
   3006                     if (deviceList.size() > 0) {
   3007                         mBluetoothHeadsetDevice = deviceList.get(0);
   3008                     } else {
   3009                         mBluetoothHeadsetDevice = null;
   3010                     }
   3011                     // Refresh SCO audio state
   3012                     checkScoAudioState();
   3013                     // Continue pending action if any
   3014                     if (mScoAudioState == SCO_STATE_ACTIVATE_REQ ||
   3015                             mScoAudioState == SCO_STATE_DEACTIVATE_REQ ||
   3016                             mScoAudioState == SCO_STATE_DEACTIVATE_EXT_REQ) {
   3017                         boolean status = false;
   3018                         if (mBluetoothHeadsetDevice != null) {
   3019                             switch (mScoAudioState) {
   3020                             case SCO_STATE_ACTIVATE_REQ:
   3021                                 mScoAudioState = SCO_STATE_ACTIVE_INTERNAL;
   3022                                 if (mScoAudioMode == SCO_MODE_RAW) {
   3023                                     status = mBluetoothHeadset.connectAudio();
   3024                                 } else if (mScoAudioMode == SCO_MODE_VIRTUAL_CALL) {
   3025                                     status = mBluetoothHeadset.startScoUsingVirtualVoiceCall(
   3026                                                                         mBluetoothHeadsetDevice);
   3027                                 } else if (mScoAudioMode == SCO_MODE_VR) {
   3028                                     status = mBluetoothHeadset.startVoiceRecognition(
   3029                                                                       mBluetoothHeadsetDevice);
   3030                                 }
   3031                                 break;
   3032                             case SCO_STATE_DEACTIVATE_REQ:
   3033                                 if (mScoAudioMode == SCO_MODE_RAW) {
   3034                                     status = mBluetoothHeadset.disconnectAudio();
   3035                                 } else if (mScoAudioMode == SCO_MODE_VIRTUAL_CALL) {
   3036                                     status = mBluetoothHeadset.stopScoUsingVirtualVoiceCall(
   3037                                                                         mBluetoothHeadsetDevice);
   3038                                 } else if (mScoAudioMode == SCO_MODE_VR) {
   3039                                     status = mBluetoothHeadset.stopVoiceRecognition(
   3040                                                                       mBluetoothHeadsetDevice);
   3041                                 }
   3042                                 break;
   3043                             case SCO_STATE_DEACTIVATE_EXT_REQ:
   3044                                 status = mBluetoothHeadset.stopVoiceRecognition(
   3045                                         mBluetoothHeadsetDevice);
   3046                             }
   3047                         }
   3048                         if (!status) {
   3049                             sendMsg(mAudioHandler, MSG_BT_HEADSET_CNCT_FAILED,
   3050                                     SENDMSG_REPLACE, 0, 0, null, 0);
   3051                         }
   3052                     }
   3053                 }
   3054                 break;
   3055 
   3056             default:
   3057                 break;
   3058             }
   3059         }
   3060         public void onServiceDisconnected(int profile) {
   3061             ArraySet<String> toRemove = null;
   3062             switch (profile) {
   3063             case BluetoothProfile.A2DP:
   3064                 synchronized (mConnectedDevices) {
   3065                     synchronized (mA2dpAvrcpLock) {
   3066                         // Disconnect ALL DEVICE_OUT_BLUETOOTH_A2DP devices
   3067                         for (int i = 0; i < mConnectedDevices.size(); i++) {
   3068                             DeviceListSpec deviceSpec = mConnectedDevices.valueAt(i);
   3069                             if (deviceSpec.mDeviceType == AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP) {
   3070                                 toRemove = toRemove != null ? toRemove : new ArraySet<String>();
   3071                                 toRemove.add(deviceSpec.mDeviceAddress);
   3072                             }
   3073                         }
   3074                         if (toRemove != null) {
   3075                             int delay = checkSendBecomingNoisyIntent(
   3076                                                 AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
   3077                                                 0);
   3078                             for (int i = 0; i < toRemove.size(); i++) {
   3079                                 makeA2dpDeviceUnavailableLater(toRemove.valueAt(i), delay);
   3080                             }
   3081                         }
   3082                     }
   3083                 }
   3084                 break;
   3085 
   3086             case BluetoothProfile.A2DP_SINK:
   3087                 synchronized (mConnectedDevices) {
   3088                     // Disconnect ALL DEVICE_IN_BLUETOOTH_A2DP devices
   3089                     for(int i = 0; i < mConnectedDevices.size(); i++) {
   3090                         DeviceListSpec deviceSpec = mConnectedDevices.valueAt(i);
   3091                         if (deviceSpec.mDeviceType == AudioSystem.DEVICE_IN_BLUETOOTH_A2DP) {
   3092                             toRemove = toRemove != null ? toRemove : new ArraySet<String>();
   3093                             toRemove.add(deviceSpec.mDeviceAddress);
   3094                         }
   3095                     }
   3096                     if (toRemove != null) {
   3097                         for (int i = 0; i < toRemove.size(); i++) {
   3098                             makeA2dpSrcUnavailable(toRemove.valueAt(i));
   3099                         }
   3100                     }
   3101                 }
   3102                 break;
   3103 
   3104             case BluetoothProfile.HEADSET:
   3105                 synchronized (mScoClients) {
   3106                     if (mBluetoothHeadsetDevice != null) {
   3107                         setBtScoDeviceConnectionState(mBluetoothHeadsetDevice,
   3108                                 BluetoothProfile.STATE_DISCONNECTED);
   3109                     }
   3110                     mBluetoothHeadset = null;
   3111                 }
   3112                 break;
   3113 
   3114             default:
   3115                 break;
   3116             }
   3117         }
   3118     };
   3119 
   3120     private void onCheckMusicActive(String caller) {
   3121         synchronized (mSafeMediaVolumeState) {
   3122             if (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_INACTIVE) {
   3123                 int device = getDeviceForStream(AudioSystem.STREAM_MUSIC);
   3124 
   3125                 if ((device & mSafeMediaVolumeDevices) != 0) {
   3126                     sendMsg(mAudioHandler,
   3127                             MSG_CHECK_MUSIC_ACTIVE,
   3128                             SENDMSG_REPLACE,
   3129                             0,
   3130                             0,
   3131                             caller,
   3132                             MUSIC_ACTIVE_POLL_PERIOD_MS);
   3133                     int index = mStreamStates[AudioSystem.STREAM_MUSIC].getIndex(device);
   3134                     if (AudioSystem.isStreamActive(AudioSystem.STREAM_MUSIC, 0) &&
   3135                             (index > mSafeMediaVolumeIndex)) {
   3136                         // Approximate cumulative active music time
   3137                         mMusicActiveMs += MUSIC_ACTIVE_POLL_PERIOD_MS;
   3138                         if (mMusicActiveMs > UNSAFE_VOLUME_MUSIC_ACTIVE_MS_MAX) {
   3139                             setSafeMediaVolumeEnabled(true, caller);
   3140                             mMusicActiveMs = 0;
   3141                         }
   3142                         saveMusicActiveMs();
   3143                     }
   3144                 }
   3145             }
   3146         }
   3147     }
   3148 
   3149     private void saveMusicActiveMs() {
   3150         mAudioHandler.obtainMessage(MSG_PERSIST_MUSIC_ACTIVE_MS, mMusicActiveMs, 0).sendToTarget();
   3151     }
   3152 
   3153     private void onConfigureSafeVolume(boolean force, String caller) {
   3154         synchronized (mSafeMediaVolumeState) {
   3155             int mcc = mContext.getResources().getConfiguration().mcc;
   3156             if ((mMcc != mcc) || ((mMcc == 0) && force)) {
   3157                 mSafeMediaVolumeIndex = mContext.getResources().getInteger(
   3158                         com.android.internal.R.integer.config_safe_media_volume_index) * 10;
   3159                 boolean safeMediaVolumeEnabled =
   3160                         SystemProperties.getBoolean("audio.safemedia.force", false)
   3161                         || mContext.getResources().getBoolean(
   3162                                 com.android.internal.R.bool.config_safe_media_volume_enabled);
   3163 
   3164                 boolean safeMediaVolumeBypass =
   3165                         SystemProperties.getBoolean("audio.safemedia.bypass", false);
   3166 
   3167                 // The persisted state is either "disabled" or "active": this is the state applied
   3168                 // next time we boot and cannot be "inactive"
   3169                 int persistedState;
   3170                 if (safeMediaVolumeEnabled && !safeMediaVolumeBypass) {
   3171                     persistedState = SAFE_MEDIA_VOLUME_ACTIVE;
   3172                     // The state can already be "inactive" here if the user has forced it before
   3173                     // the 30 seconds timeout for forced configuration. In this case we don't reset
   3174                     // it to "active".
   3175                     if (mSafeMediaVolumeState != SAFE_MEDIA_VOLUME_INACTIVE) {
   3176                         if (mMusicActiveMs == 0) {
   3177                             mSafeMediaVolumeState = SAFE_MEDIA_VOLUME_ACTIVE;
   3178                             enforceSafeMediaVolume(caller);
   3179                         } else {
   3180                             // We have existing playback time recorded, already confirmed.
   3181                             mSafeMediaVolumeState = SAFE_MEDIA_VOLUME_INACTIVE;
   3182                         }
   3183                     }
   3184                 } else {
   3185                     persistedState = SAFE_MEDIA_VOLUME_DISABLED;
   3186                     mSafeMediaVolumeState = SAFE_MEDIA_VOLUME_DISABLED;
   3187                 }
   3188                 mMcc = mcc;
   3189                 sendMsg(mAudioHandler,
   3190                         MSG_PERSIST_SAFE_VOLUME_STATE,
   3191                         SENDMSG_QUEUE,
   3192                         persistedState,
   3193                         0,
   3194                         null,
   3195                         0);
   3196             }
   3197         }
   3198     }
   3199 
   3200     ///////////////////////////////////////////////////////////////////////////
   3201     // Internal methods
   3202     ///////////////////////////////////////////////////////////////////////////
   3203 
   3204     /**
   3205      * Checks if the adjustment should change ringer mode instead of just
   3206      * adjusting volume. If so, this will set the proper ringer mode and volume
   3207      * indices on the stream states.
   3208      */
   3209     private int checkForRingerModeChange(int oldIndex, int direction, int step, boolean isMuted) {
   3210         final boolean isTv = mPlatformType == AudioSystem.PLATFORM_TELEVISION;
   3211         int result = FLAG_ADJUST_VOLUME;
   3212         int ringerMode = getRingerModeInternal();
   3213 
   3214         switch (ringerMode) {
   3215         case RINGER_MODE_NORMAL:
   3216             if (direction == AudioManager.ADJUST_LOWER) {
   3217                 if (mHasVibrator) {
   3218                     // "step" is the delta in internal index units corresponding to a
   3219                     // change of 1 in UI index units.
   3220                     // Because of rounding when rescaling from one stream index range to its alias
   3221                     // index range, we cannot simply test oldIndex == step:
   3222                     //   (step <= oldIndex < 2 * step) is equivalent to: (old UI index == 1)
   3223                     if (step <= oldIndex && oldIndex < 2 * step) {
   3224                         ringerMode = RINGER_MODE_VIBRATE;
   3225                         mLoweredFromNormalToVibrateTime = SystemClock.uptimeMillis();
   3226                     }
   3227                 } else {
   3228                     if (oldIndex == step && mVolumePolicy.volumeDownToEnterSilent) {
   3229                         ringerMode = RINGER_MODE_SILENT;
   3230                     }
   3231                 }
   3232             } else if (isTv && (direction == AudioManager.ADJUST_TOGGLE_MUTE
   3233                     || direction == AudioManager.ADJUST_MUTE)) {
   3234                 if (mHasVibrator) {
   3235                     ringerMode = RINGER_MODE_VIBRATE;
   3236                 } else {
   3237                     ringerMode = RINGER_MODE_SILENT;
   3238                 }
   3239                 // Setting the ringer mode will toggle mute
   3240                 result &= ~FLAG_ADJUST_VOLUME;
   3241             }
   3242             break;
   3243         case RINGER_MODE_VIBRATE:
   3244             if (!mHasVibrator) {
   3245                 Log.e(TAG, "checkForRingerModeChange() current ringer mode is vibrate" +
   3246                         "but no vibrator is present");
   3247                 break;
   3248             }
   3249             if ((direction == AudioManager.ADJUST_LOWER)) {
   3250                 // This is the case we were muted with the volume turned up
   3251                 if (isTv && oldIndex >= 2 * step && isMuted) {
   3252                     ringerMode = RINGER_MODE_NORMAL;
   3253                 } else if (mPrevVolDirection != AudioManager.ADJUST_LOWER) {
   3254                     if (mVolumePolicy.volumeDownToEnterSilent) {
   3255                         final long diff = SystemClock.uptimeMillis()
   3256                                 - mLoweredFromNormalToVibrateTime;
   3257                         if (diff > mVolumePolicy.vibrateToSilentDebounce
   3258                                 && mRingerModeDelegate.canVolumeDownEnterSilent()) {
   3259                             ringerMode = RINGER_MODE_SILENT;
   3260                         }
   3261                     } else {
   3262                         result |= AudioManager.FLAG_SHOW_VIBRATE_HINT;
   3263                     }
   3264                 }
   3265             } else if (direction == AudioManager.ADJUST_RAISE
   3266                     || direction == AudioManager.ADJUST_TOGGLE_MUTE
   3267                     || direction == AudioManager.ADJUST_UNMUTE) {
   3268                 ringerMode = RINGER_MODE_NORMAL;
   3269             }
   3270             result &= ~FLAG_ADJUST_VOLUME;
   3271             break;
   3272         case RINGER_MODE_SILENT:
   3273             if (isTv && direction == AudioManager.ADJUST_LOWER && oldIndex >= 2 * step && isMuted) {
   3274                 // This is the case we were muted with the volume turned up
   3275                 ringerMode = RINGER_MODE_NORMAL;
   3276             } else if (direction == AudioManager.ADJUST_RAISE
   3277                     || direction == AudioManager.ADJUST_TOGGLE_MUTE
   3278                     || direction == AudioManager.ADJUST_UNMUTE) {
   3279                 if (!mVolumePolicy.volumeUpToExitSilent) {
   3280                     result |= AudioManager.FLAG_SHOW_SILENT_HINT;
   3281                 } else {
   3282                   if (mHasVibrator && direction == AudioManager.ADJUST_RAISE) {
   3283                       ringerMode = RINGER_MODE_VIBRATE;
   3284                   } else {
   3285                       // If we don't have a vibrator or they were toggling mute
   3286                       // go straight back to normal.
   3287                       ringerMode = RINGER_MODE_NORMAL;
   3288                   }
   3289                 }
   3290             }
   3291             result &= ~FLAG_ADJUST_VOLUME;
   3292             break;
   3293         default:
   3294             Log.e(TAG, "checkForRingerModeChange() wrong ringer mode: "+ringerMode);
   3295             break;
   3296         }
   3297 
   3298         setRingerMode(ringerMode, TAG + ".checkForRingerModeChange", false /*external*/);
   3299 
   3300         mPrevVolDirection = direction;
   3301 
   3302         return result;
   3303     }
   3304 
   3305     @Override
   3306     public boolean isStreamAffectedByRingerMode(int streamType) {
   3307         return (mRingerModeAffectedStreams & (1 << streamType)) != 0;
   3308     }
   3309 
   3310     private boolean isStreamMutedByRingerMode(int streamType) {
   3311         return (mRingerModeMutedStreams & (1 << streamType)) != 0;
   3312     }
   3313 
   3314     private boolean updateRingerModeAffectedStreams() {
   3315         int ringerModeAffectedStreams = Settings.System.getIntForUser(mContentResolver,
   3316                 Settings.System.MODE_RINGER_STREAMS_AFFECTED,
   3317                 ((1 << AudioSystem.STREAM_RING)|(1 << AudioSystem.STREAM_NOTIFICATION)|
   3318                  (1 << AudioSystem.STREAM_SYSTEM)|(1 << AudioSystem.STREAM_SYSTEM_ENFORCED)),
   3319                  UserHandle.USER_CURRENT);
   3320 
   3321         if (mPlatformType == AudioSystem.PLATFORM_TELEVISION) {
   3322             ringerModeAffectedStreams = 0;
   3323         } else if (mRingerModeDelegate != null) {
   3324             ringerModeAffectedStreams = mRingerModeDelegate
   3325                     .getRingerModeAffectedStreams(ringerModeAffectedStreams);
   3326         }
   3327         synchronized (mCameraSoundForced) {
   3328             if (mCameraSoundForced) {
   3329                 ringerModeAffectedStreams &= ~(1 << AudioSystem.STREAM_SYSTEM_ENFORCED);
   3330             } else {
   3331                 ringerModeAffectedStreams |= (1 << AudioSystem.STREAM_SYSTEM_ENFORCED);
   3332             }
   3333         }
   3334         if (mStreamVolumeAlias[AudioSystem.STREAM_DTMF] == AudioSystem.STREAM_RING) {
   3335             ringerModeAffectedStreams |= (1 << AudioSystem.STREAM_DTMF);
   3336         } else {
   3337             ringerModeAffectedStreams &= ~(1 << AudioSystem.STREAM_DTMF);
   3338         }
   3339 
   3340         if (ringerModeAffectedStreams != mRingerModeAffectedStreams) {
   3341             Settings.System.putIntForUser(mContentResolver,
   3342                     Settings.System.MODE_RINGER_STREAMS_AFFECTED,
   3343                     ringerModeAffectedStreams,
   3344                     UserHandle.USER_CURRENT);
   3345             mRingerModeAffectedStreams = ringerModeAffectedStreams;
   3346             return true;
   3347         }
   3348         return false;
   3349     }
   3350 
   3351     @Override
   3352     public boolean isStreamAffectedByMute(int streamType) {
   3353         return (mMuteAffectedStreams & (1 << streamType)) != 0;
   3354     }
   3355 
   3356     private void ensureValidDirection(int direction) {
   3357         switch (direction) {
   3358             case AudioManager.ADJUST_LOWER:
   3359             case AudioManager.ADJUST_RAISE:
   3360             case AudioManager.ADJUST_SAME:
   3361             case AudioManager.ADJUST_MUTE:
   3362             case AudioManager.ADJUST_UNMUTE:
   3363             case AudioManager.ADJUST_TOGGLE_MUTE:
   3364                 break;
   3365             default:
   3366                 throw new IllegalArgumentException("Bad direction " + direction);
   3367         }
   3368     }
   3369 
   3370     private void ensureValidStreamType(int streamType) {
   3371         if (streamType < 0 || streamType >= mStreamStates.length) {
   3372             throw new IllegalArgumentException("Bad stream type " + streamType);
   3373         }
   3374     }
   3375 
   3376     private boolean isMuteAdjust(int adjust) {
   3377         return adjust == AudioManager.ADJUST_MUTE || adjust == AudioManager.ADJUST_UNMUTE
   3378                 || adjust == AudioManager.ADJUST_TOGGLE_MUTE;
   3379     }
   3380 
   3381     private boolean isInCommunication() {
   3382         boolean IsInCall = false;
   3383 
   3384         TelecomManager telecomManager =
   3385                 (TelecomManager) mContext.getSystemService(Context.TELECOM_SERVICE);
   3386 
   3387         final long ident = Binder.clearCallingIdentity();
   3388         IsInCall = telecomManager.isInCall();
   3389         Binder.restoreCallingIdentity(ident);
   3390 
   3391         return (IsInCall || getMode() == AudioManager.MODE_IN_COMMUNICATION);
   3392     }
   3393 
   3394     /**
   3395      * For code clarity for getActiveStreamType(int)
   3396      * @param delay_ms max time since last STREAM_MUSIC activity to consider
   3397      * @return true if STREAM_MUSIC is active in streams handled by AudioFlinger now or
   3398      *     in the last "delay_ms" ms.
   3399      */
   3400     private boolean isAfMusicActiveRecently(int delay_ms) {
   3401         return AudioSystem.isStreamActive(AudioSystem.STREAM_MUSIC, delay_ms)
   3402                 || AudioSystem.isStreamActiveRemotely(AudioSystem.STREAM_MUSIC, delay_ms);
   3403     }
   3404 
   3405     private int getActiveStreamType(int suggestedStreamType) {
   3406         switch (mPlatformType) {
   3407         case AudioSystem.PLATFORM_VOICE:
   3408             if (isInCommunication()) {
   3409                 if (AudioSystem.getForceUse(AudioSystem.FOR_COMMUNICATION)
   3410                         == AudioSystem.FORCE_BT_SCO) {
   3411                     // Log.v(TAG, "getActiveStreamType: Forcing STREAM_BLUETOOTH_SCO...");
   3412                     return AudioSystem.STREAM_BLUETOOTH_SCO;
   3413                 } else {
   3414                     // Log.v(TAG, "getActiveStreamType: Forcing STREAM_VOICE_CALL...");
   3415                     return AudioSystem.STREAM_VOICE_CALL;
   3416                 }
   3417             } else if (suggestedStreamType == AudioManager.USE_DEFAULT_STREAM_TYPE) {
   3418                 if (isAfMusicActiveRecently(StreamOverride.sDelayMs)) {
   3419                     if (DEBUG_VOL)
   3420                         Log.v(TAG, "getActiveStreamType: Forcing STREAM_MUSIC stream active");
   3421                     return AudioSystem.STREAM_MUSIC;
   3422                     } else {
   3423                         if (DEBUG_VOL)
   3424                             Log.v(TAG, "getActiveStreamType: Forcing STREAM_RING b/c default");
   3425                         return AudioSystem.STREAM_RING;
   3426                 }
   3427             } else if (isAfMusicActiveRecently(0)) {
   3428                 if (DEBUG_VOL)
   3429                     Log.v(TAG, "getActiveStreamType: Forcing STREAM_MUSIC stream active");
   3430                 return AudioSystem.STREAM_MUSIC;
   3431             }
   3432             break;
   3433         case AudioSystem.PLATFORM_TELEVISION:
   3434             if (suggestedStreamType == AudioManager.USE_DEFAULT_STREAM_TYPE) {
   3435                     // TV always defaults to STREAM_MUSIC
   3436                     return AudioSystem.STREAM_MUSIC;
   3437             }
   3438             break;
   3439         default:
   3440             if (isInCommunication()) {
   3441                 if (AudioSystem.getForceUse(AudioSystem.FOR_COMMUNICATION)
   3442                         == AudioSystem.FORCE_BT_SCO) {
   3443                     if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: Forcing STREAM_BLUETOOTH_SCO");
   3444                     return AudioSystem.STREAM_BLUETOOTH_SCO;
   3445                 } else {
   3446                     if (DEBUG_VOL)  Log.v(TAG, "getActiveStreamType: Forcing STREAM_VOICE_CALL");
   3447                     return AudioSystem.STREAM_VOICE_CALL;
   3448                 }
   3449             } else if (AudioSystem.isStreamActive(AudioSystem.STREAM_NOTIFICATION,
   3450                     StreamOverride.sDelayMs) ||
   3451                     AudioSystem.isStreamActive(AudioSystem.STREAM_RING,
   3452                             StreamOverride.sDelayMs)) {
   3453                 if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: Forcing STREAM_NOTIFICATION");
   3454                 return AudioSystem.STREAM_NOTIFICATION;
   3455             } else if (suggestedStreamType == AudioManager.USE_DEFAULT_STREAM_TYPE) {
   3456                 if (isAfMusicActiveRecently(StreamOverride.sDelayMs)) {
   3457                     if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: forcing STREAM_MUSIC");
   3458                     return AudioSystem.STREAM_MUSIC;
   3459                 } else {
   3460                     if (DEBUG_VOL) Log.v(TAG,
   3461                             "getActiveStreamType: using STREAM_NOTIFICATION as default");
   3462                     return AudioSystem.STREAM_NOTIFICATION;
   3463                 }
   3464             }
   3465             break;
   3466         }
   3467         if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: Returning suggested type "
   3468                 + suggestedStreamType);
   3469         return suggestedStreamType;
   3470     }
   3471 
   3472     private void broadcastRingerMode(String action, int ringerMode) {
   3473         // Send sticky broadcast
   3474         Intent broadcast = new Intent(action);
   3475         broadcast.putExtra(AudioManager.EXTRA_RINGER_MODE, ringerMode);
   3476         broadcast.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT
   3477                 | Intent.FLAG_RECEIVER_REPLACE_PENDING);
   3478         sendStickyBroadcastToAll(broadcast);
   3479     }
   3480 
   3481     private void broadcastVibrateSetting(int vibrateType) {
   3482         // Send broadcast
   3483         if (ActivityManagerNative.isSystemReady()) {
   3484             Intent broadcast = new Intent(AudioManager.VIBRATE_SETTING_CHANGED_ACTION);
   3485             broadcast.putExtra(AudioManager.EXTRA_VIBRATE_TYPE, vibrateType);
   3486             broadcast.putExtra(AudioManager.EXTRA_VIBRATE_SETTING, getVibrateSetting(vibrateType));
   3487             sendBroadcastToAll(broadcast);
   3488         }
   3489     }
   3490 
   3491     // Message helper methods
   3492     /**
   3493      * Queue a message on the given handler's message queue, after acquiring the service wake lock.
   3494      * Note that the wake lock needs to be released after the message has been handled.
   3495      */
   3496     private void queueMsgUnderWakeLock(Handler handler, int msg,
   3497             int arg1, int arg2, Object obj, int delay) {
   3498         final long ident = Binder.clearCallingIdentity();
   3499         // Always acquire the wake lock as AudioService because it is released by the
   3500         // message handler.
   3501         mAudioEventWakeLock.acquire();
   3502         Binder.restoreCallingIdentity(ident);
   3503         sendMsg(handler, msg, SENDMSG_QUEUE, arg1, arg2, obj, delay);
   3504     }
   3505 
   3506     private static void sendMsg(Handler handler, int msg,
   3507             int existingMsgPolicy, int arg1, int arg2, Object obj, int delay) {
   3508 
   3509         if (existingMsgPolicy == SENDMSG_REPLACE) {
   3510             handler.removeMessages(msg);
   3511         } else if (existingMsgPolicy == SENDMSG_NOOP && handler.hasMessages(msg)) {
   3512             return;
   3513         }
   3514         synchronized (mLastDeviceConnectMsgTime) {
   3515             long time = SystemClock.uptimeMillis() + delay;
   3516             handler.sendMessageAtTime(handler.obtainMessage(msg, arg1, arg2, obj), time);
   3517             if (msg == MSG_SET_WIRED_DEVICE_CONNECTION_STATE ||
   3518                     msg == MSG_SET_A2DP_SRC_CONNECTION_STATE ||
   3519                     msg == MSG_SET_A2DP_SINK_CONNECTION_STATE) {
   3520                 mLastDeviceConnectMsgTime = time;
   3521             }
   3522         }
   3523     }
   3524 
   3525     boolean checkAudioSettingsPermission(String method) {
   3526         if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.MODIFY_AUDIO_SETTINGS)
   3527                 == PackageManager.PERMISSION_GRANTED) {
   3528             return true;
   3529         }
   3530         String msg = "Audio Settings Permission Denial: " + method + " from pid="
   3531                 + Binder.getCallingPid()
   3532                 + ", uid=" + Binder.getCallingUid();
   3533         Log.w(TAG, msg);
   3534         return false;
   3535     }
   3536 
   3537     private int getDeviceForStream(int stream) {
   3538         int device = getDevicesForStream(stream);
   3539         if ((device & (device - 1)) != 0) {
   3540             // Multiple device selection is either:
   3541             //  - speaker + one other device: give priority to speaker in this case.
   3542             //  - one A2DP device + another device: happens with duplicated output. In this case
   3543             // retain the device on the A2DP output as the other must not correspond to an active
   3544             // selection if not the speaker.
   3545             //  - HDMI-CEC system audio mode only output: give priority to available item in order.
   3546             if ((device & AudioSystem.DEVICE_OUT_SPEAKER) != 0) {
   3547                 device = AudioSystem.DEVICE_OUT_SPEAKER;
   3548             } else if ((device & AudioSystem.DEVICE_OUT_HDMI_ARC) != 0) {
   3549                 device = AudioSystem.DEVICE_OUT_HDMI_ARC;
   3550             } else if ((device & AudioSystem.DEVICE_OUT_SPDIF) != 0) {
   3551                 device = AudioSystem.DEVICE_OUT_SPDIF;
   3552             } else if ((device & AudioSystem.DEVICE_OUT_AUX_LINE) != 0) {
   3553                 device = AudioSystem.DEVICE_OUT_AUX_LINE;
   3554             } else {
   3555                 device &= AudioSystem.DEVICE_OUT_ALL_A2DP;
   3556             }
   3557         }
   3558         return device;
   3559     }
   3560 
   3561     private int getDevicesForStream(int stream) {
   3562         return getDevicesForStream(stream, true /*checkOthers*/);
   3563     }
   3564 
   3565     private int getDevicesForStream(int stream, boolean checkOthers) {
   3566         ensureValidStreamType(stream);
   3567         synchronized (VolumeStreamState.class) {
   3568             return mStreamStates[stream].observeDevicesForStream_syncVSS(checkOthers);
   3569         }
   3570     }
   3571 
   3572     private void observeDevicesForStreams(int skipStream) {
   3573         synchronized (VolumeStreamState.class) {
   3574             for (int stream = 0; stream < mStreamStates.length; stream++) {
   3575                 if (stream != skipStream) {
   3576                     mStreamStates[stream].observeDevicesForStream_syncVSS(false /*checkOthers*/);
   3577                 }
   3578             }
   3579         }
   3580     }
   3581 
   3582     /*
   3583      * A class just for packaging up a set of connection parameters.
   3584      */
   3585     private class WiredDeviceConnectionState {
   3586         public final int mType;
   3587         public final int mState;
   3588         public final String mAddress;
   3589         public final String mName;
   3590         public final String mCaller;
   3591 
   3592         public WiredDeviceConnectionState(int type, int state, String address, String name,
   3593                 String caller) {
   3594             mType = type;
   3595             mState = state;
   3596             mAddress = address;
   3597             mName = name;
   3598             mCaller = caller;
   3599         }
   3600     }
   3601 
   3602     public void setWiredDeviceConnectionState(int type, int state, String address, String name,
   3603             String caller) {
   3604         synchronized (mConnectedDevices) {
   3605             if (DEBUG_DEVICES) {
   3606                 Slog.i(TAG, "setWiredDeviceConnectionState(" + state + " nm: " + name + " addr:"
   3607                         + address + ")");
   3608             }
   3609             int delay = checkSendBecomingNoisyIntent(type, state);
   3610             queueMsgUnderWakeLock(mAudioHandler,
   3611                     MSG_SET_WIRED_DEVICE_CONNECTION_STATE,
   3612                     0,
   3613                     0,
   3614                     new WiredDeviceConnectionState(type, state, address, name, caller),
   3615                     delay);
   3616         }
   3617     }
   3618 
   3619     public int setBluetoothA2dpDeviceConnectionState(BluetoothDevice device, int state, int profile)
   3620     {
   3621         int delay;
   3622         if (profile != BluetoothProfile.A2DP && profile != BluetoothProfile.A2DP_SINK) {
   3623             throw new IllegalArgumentException("invalid profile " + profile);
   3624         }
   3625         synchronized (mConnectedDevices) {
   3626             if (profile == BluetoothProfile.A2DP) {
   3627                 delay = checkSendBecomingNoisyIntent(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
   3628                                                 (state == BluetoothA2dp.STATE_CONNECTED) ? 1 : 0);
   3629             } else {
   3630                 delay = 0;
   3631             }
   3632             queueMsgUnderWakeLock(mAudioHandler,
   3633                     (profile == BluetoothProfile.A2DP ?
   3634                         MSG_SET_A2DP_SINK_CONNECTION_STATE : MSG_SET_A2DP_SRC_CONNECTION_STATE),
   3635                     state,
   3636                     0,
   3637                     device,
   3638                     delay);
   3639         }
   3640         return delay;
   3641     }
   3642 
   3643     ///////////////////////////////////////////////////////////////////////////
   3644     // Inner classes
   3645     ///////////////////////////////////////////////////////////////////////////
   3646 
   3647     // NOTE: Locking order for synchronized objects related to volume or ringer mode management:
   3648     //  1 mScoclient OR mSafeMediaVolumeState
   3649     //  2   mSetModeDeathHandlers
   3650     //  3     mSettingsLock
   3651     //  4       VolumeStreamState.class
   3652     //  5         mCameraSoundForced
   3653     public class VolumeStreamState {
   3654         private final int mStreamType;
   3655         private final int mIndexMin;
   3656         private final int mIndexMax;
   3657 
   3658         private boolean mIsMuted;
   3659         private String mVolumeIndexSettingName;
   3660         private int mObservedDevices;
   3661 
   3662         private final SparseIntArray mIndexMap = new SparseIntArray(8);
   3663         private final Intent mVolumeChanged;
   3664         private final Intent mStreamDevicesChanged;
   3665 
   3666         private VolumeStreamState(String settingName, int streamType) {
   3667 
   3668             mVolumeIndexSettingName = settingName;
   3669 
   3670             mStreamType = streamType;
   3671             mIndexMin = MIN_STREAM_VOLUME[streamType] * 10;
   3672             mIndexMax = MAX_STREAM_VOLUME[streamType] * 10;
   3673             AudioSystem.initStreamVolume(streamType, mIndexMin / 10, mIndexMax / 10);
   3674 
   3675             readSettings();
   3676             mVolumeChanged = new Intent(AudioManager.VOLUME_CHANGED_ACTION);
   3677             mVolumeChanged.putExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, mStreamType);
   3678             mStreamDevicesChanged = new Intent(AudioManager.STREAM_DEVICES_CHANGED_ACTION);
   3679             mStreamDevicesChanged.putExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, mStreamType);
   3680         }
   3681 
   3682         public int observeDevicesForStream_syncVSS(boolean checkOthers) {
   3683             final int devices = AudioSystem.getDevicesForStream(mStreamType);
   3684             if (devices == mObservedDevices) {
   3685                 return devices;
   3686             }
   3687             final int prevDevices = mObservedDevices;
   3688             mObservedDevices = devices;
   3689             if (checkOthers) {
   3690                 // one stream's devices have changed, check the others
   3691                 observeDevicesForStreams(mStreamType);
   3692             }
   3693             // log base stream changes to the event log
   3694             if (mStreamVolumeAlias[mStreamType] == mStreamType) {
   3695                 EventLogTags.writeStreamDevicesChanged(mStreamType, prevDevices, devices);
   3696             }
   3697             sendBroadcastToAll(mStreamDevicesChanged
   3698                     .putExtra(AudioManager.EXTRA_PREV_VOLUME_STREAM_DEVICES, prevDevices)
   3699                     .putExtra(AudioManager.EXTRA_VOLUME_STREAM_DEVICES, devices));
   3700             return devices;
   3701         }
   3702 
   3703         public String getSettingNameForDevice(int device) {
   3704             String name = mVolumeIndexSettingName;
   3705             String suffix = AudioSystem.getOutputDeviceName(device);
   3706             if (suffix.isEmpty()) {
   3707                 return name;
   3708             }
   3709             return name + "_" + suffix;
   3710         }
   3711 
   3712         public void readSettings() {
   3713             synchronized (VolumeStreamState.class) {
   3714                 // force maximum volume on all streams if fixed volume property is set
   3715                 if (mUseFixedVolume) {
   3716                     mIndexMap.put(AudioSystem.DEVICE_OUT_DEFAULT, mIndexMax);
   3717                     return;
   3718                 }
   3719                 // do not read system stream volume from settings: this stream is always aliased
   3720                 // to another stream type and its volume is never persisted. Values in settings can
   3721                 // only be stale values
   3722                 if ((mStreamType == AudioSystem.STREAM_SYSTEM) ||
   3723                         (mStreamType == AudioSystem.STREAM_SYSTEM_ENFORCED)) {
   3724                     int index = 10 * AudioSystem.DEFAULT_STREAM_VOLUME[mStreamType];
   3725                     synchronized (mCameraSoundForced) {
   3726                         if (mCameraSoundForced) {
   3727                             index = mIndexMax;
   3728                         }
   3729                     }
   3730                     mIndexMap.put(AudioSystem.DEVICE_OUT_DEFAULT, index);
   3731                     return;
   3732                 }
   3733 
   3734                 int remainingDevices = AudioSystem.DEVICE_OUT_ALL;
   3735 
   3736                 for (int i = 0; remainingDevices != 0; i++) {
   3737                     int device = (1 << i);
   3738                     if ((device & remainingDevices) == 0) {
   3739                         continue;
   3740                     }
   3741                     remainingDevices &= ~device;
   3742 
   3743                     // retrieve current volume for device
   3744                     String name = getSettingNameForDevice(device);
   3745                     // if no volume stored for current stream and device, use default volume if default
   3746                     // device, continue otherwise
   3747                     int defaultIndex = (device == AudioSystem.DEVICE_OUT_DEFAULT) ?
   3748                             AudioSystem.DEFAULT_STREAM_VOLUME[mStreamType] : -1;
   3749                     int index = Settings.System.getIntForUser(
   3750                             mContentResolver, name, defaultIndex, UserHandle.USER_CURRENT);
   3751                     if (index == -1) {
   3752                         continue;
   3753                     }
   3754 
   3755                     mIndexMap.put(device, getValidIndex(10 * index));
   3756                 }
   3757             }
   3758         }
   3759 
   3760         // must be called while synchronized VolumeStreamState.class
   3761         public void applyDeviceVolume_syncVSS(int device) {
   3762             int index;
   3763             if (mIsMuted) {
   3764                 index = 0;
   3765             } else if (((device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0 && mAvrcpAbsVolSupported)
   3766                     || ((device & mFullVolumeDevices) != 0)) {
   3767                 index = (mIndexMax + 5)/10;
   3768             } else {
   3769                 index = (getIndex(device) + 5)/10;
   3770             }
   3771             AudioSystem.setStreamVolumeIndex(mStreamType, index, device);
   3772         }
   3773 
   3774         public void applyAllVolumes() {
   3775             synchronized (VolumeStreamState.class) {
   3776                 // apply default volume first: by convention this will reset all
   3777                 // devices volumes in audio policy manager to the supplied value
   3778                 int index;
   3779                 if (mIsMuted) {
   3780                     index = 0;
   3781                 } else {
   3782                     index = (getIndex(AudioSystem.DEVICE_OUT_DEFAULT) + 5)/10;
   3783                 }
   3784                 AudioSystem.setStreamVolumeIndex(mStreamType, index, AudioSystem.DEVICE_OUT_DEFAULT);
   3785                 // then apply device specific volumes
   3786                 for (int i = 0; i < mIndexMap.size(); i++) {
   3787                     int device = mIndexMap.keyAt(i);
   3788                     if (device != AudioSystem.DEVICE_OUT_DEFAULT) {
   3789                         if (mIsMuted) {
   3790                             index = 0;
   3791                         } else if (((device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0 &&
   3792                                 mAvrcpAbsVolSupported)
   3793                                     || ((device & mFullVolumeDevices) != 0))
   3794                         {
   3795                             index = (mIndexMax + 5)/10;
   3796                         } else {
   3797                             index = (mIndexMap.valueAt(i) + 5)/10;
   3798                         }
   3799                         AudioSystem.setStreamVolumeIndex(mStreamType, index, device);
   3800                     }
   3801                 }
   3802             }
   3803         }
   3804 
   3805         public boolean adjustIndex(int deltaIndex, int device, String caller) {
   3806             return setIndex(getIndex(device) + deltaIndex, device, caller);
   3807         }
   3808 
   3809         public boolean setIndex(int index, int device, String caller) {
   3810             boolean changed = false;
   3811             int oldIndex;
   3812             synchronized (VolumeStreamState.class) {
   3813                 oldIndex = getIndex(device);
   3814                 index = getValidIndex(index);
   3815                 synchronized (mCameraSoundForced) {
   3816                     if ((mStreamType == AudioSystem.STREAM_SYSTEM_ENFORCED) && mCameraSoundForced) {
   3817                         index = mIndexMax;
   3818                     }
   3819                 }
   3820                 mIndexMap.put(device, index);
   3821 
   3822                 changed = oldIndex != index;
   3823                 if (changed) {
   3824                     // Apply change to all streams using this one as alias
   3825                     // if changing volume of current device, also change volume of current
   3826                     // device on aliased stream
   3827                     boolean currentDevice = (device == getDeviceForStream(mStreamType));
   3828                     int numStreamTypes = AudioSystem.getNumStreamTypes();
   3829                     for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
   3830                         if (streamType != mStreamType &&
   3831                                 mStreamVolumeAlias[streamType] == mStreamType) {
   3832                             int scaledIndex = rescaleIndex(index, mStreamType, streamType);
   3833                             mStreamStates[streamType].setIndex(scaledIndex, device, caller);
   3834                             if (currentDevice) {
   3835                                 mStreamStates[streamType].setIndex(scaledIndex,
   3836                                         getDeviceForStream(streamType), caller);
   3837                             }
   3838                         }
   3839                     }
   3840                 }
   3841             }
   3842             if (changed) {
   3843                 oldIndex = (oldIndex + 5) / 10;
   3844                 index = (index + 5) / 10;
   3845                 // log base stream changes to the event log
   3846                 if (mStreamVolumeAlias[mStreamType] == mStreamType) {
   3847                     if (caller == null) {
   3848                         Log.w(TAG, "No caller for volume_changed event", new Throwable());
   3849                     }
   3850                     EventLogTags.writeVolumeChanged(mStreamType, oldIndex, index, mIndexMax / 10,
   3851                             caller);
   3852                 }
   3853                 // fire changed intents for all streams
   3854                 mVolumeChanged.putExtra(AudioManager.EXTRA_VOLUME_STREAM_VALUE, index);
   3855                 mVolumeChanged.putExtra(AudioManager.EXTRA_PREV_VOLUME_STREAM_VALUE, oldIndex);
   3856                 mVolumeChanged.putExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE_ALIAS,
   3857                         mStreamVolumeAlias[mStreamType]);
   3858                 sendBroadcastToAll(mVolumeChanged);
   3859             }
   3860             return changed;
   3861         }
   3862 
   3863         public int getIndex(int device) {
   3864             synchronized (VolumeStreamState.class) {
   3865                 int index = mIndexMap.get(device, -1);
   3866                 if (index == -1) {
   3867                     // there is always an entry for AudioSystem.DEVICE_OUT_DEFAULT
   3868                     index = mIndexMap.get(AudioSystem.DEVICE_OUT_DEFAULT);
   3869                 }
   3870                 return index;
   3871             }
   3872         }
   3873 
   3874         public int getMaxIndex() {
   3875             return mIndexMax;
   3876         }
   3877 
   3878         public int getMinIndex() {
   3879             return mIndexMin;
   3880         }
   3881 
   3882         public void setAllIndexes(VolumeStreamState srcStream, String caller) {
   3883             synchronized (VolumeStreamState.class) {
   3884                 int srcStreamType = srcStream.getStreamType();
   3885                 // apply default device volume from source stream to all devices first in case
   3886                 // some devices are present in this stream state but not in source stream state
   3887                 int index = srcStream.getIndex(AudioSystem.DEVICE_OUT_DEFAULT);
   3888                 index = rescaleIndex(index, srcStreamType, mStreamType);
   3889                 for (int i = 0; i < mIndexMap.size(); i++) {
   3890                     mIndexMap.put(mIndexMap.keyAt(i), index);
   3891                 }
   3892                 // Now apply actual volume for devices in source stream state
   3893                 SparseIntArray srcMap = srcStream.mIndexMap;
   3894                 for (int i = 0; i < srcMap.size(); i++) {
   3895                     int device = srcMap.keyAt(i);
   3896                     index = srcMap.valueAt(i);
   3897                     index = rescaleIndex(index, srcStreamType, mStreamType);
   3898 
   3899                     setIndex(index, device, caller);
   3900                 }
   3901             }
   3902         }
   3903 
   3904         public void setAllIndexesToMax() {
   3905             synchronized (VolumeStreamState.class) {
   3906                 for (int i = 0; i < mIndexMap.size(); i++) {
   3907                     mIndexMap.put(mIndexMap.keyAt(i), mIndexMax);
   3908                 }
   3909             }
   3910         }
   3911 
   3912         public void mute(boolean state) {
   3913             boolean changed = false;
   3914             synchronized (VolumeStreamState.class) {
   3915                 if (state != mIsMuted) {
   3916                     changed = true;
   3917                     mIsMuted = state;
   3918 
   3919                     // Set the new mute volume. This propagates the values to
   3920                     // the audio system, otherwise the volume won't be changed
   3921                     // at the lower level.
   3922                     sendMsg(mAudioHandler,
   3923                             MSG_SET_ALL_VOLUMES,
   3924                             SENDMSG_QUEUE,
   3925                             0,
   3926                             0,
   3927                             this, 0);
   3928                 }
   3929             }
   3930             if (changed) {
   3931                 // Stream mute changed, fire the intent.
   3932                 Intent intent = new Intent(AudioManager.STREAM_MUTE_CHANGED_ACTION);
   3933                 intent.putExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, mStreamType);
   3934                 intent.putExtra(AudioManager.EXTRA_STREAM_VOLUME_MUTED, state);
   3935                 sendBroadcastToAll(intent);
   3936             }
   3937         }
   3938 
   3939         public int getStreamType() {
   3940             return mStreamType;
   3941         }
   3942 
   3943         public void checkFixedVolumeDevices() {
   3944             synchronized (VolumeStreamState.class) {
   3945                 // ignore settings for fixed volume devices: volume should always be at max or 0
   3946                 if (mStreamVolumeAlias[mStreamType] == AudioSystem.STREAM_MUSIC) {
   3947                     for (int i = 0; i < mIndexMap.size(); i++) {
   3948                         int device = mIndexMap.keyAt(i);
   3949                         int index = mIndexMap.valueAt(i);
   3950                         if (((device & mFullVolumeDevices) != 0)
   3951                                 || (((device & mFixedVolumeDevices) != 0) && index != 0)) {
   3952                             mIndexMap.put(device, mIndexMax);
   3953                         }
   3954                         applyDeviceVolume_syncVSS(device);
   3955                     }
   3956                 }
   3957             }
   3958         }
   3959 
   3960         private int getValidIndex(int index) {
   3961             if (index < mIndexMin) {
   3962                 return mIndexMin;
   3963             } else if (mUseFixedVolume || index > mIndexMax) {
   3964                 return mIndexMax;
   3965             }
   3966 
   3967             return index;
   3968         }
   3969 
   3970         private void dump(PrintWriter pw) {
   3971             pw.print("   Muted: ");
   3972             pw.println(mIsMuted);
   3973             pw.print("   Min: ");
   3974             pw.println((mIndexMin + 5) / 10);
   3975             pw.print("   Max: ");
   3976             pw.println((mIndexMax + 5) / 10);
   3977             pw.print("   Current: ");
   3978             for (int i = 0; i < mIndexMap.size(); i++) {
   3979                 if (i > 0) {
   3980                     pw.print(", ");
   3981                 }
   3982                 final int device = mIndexMap.keyAt(i);
   3983                 pw.print(Integer.toHexString(device));
   3984                 final String deviceName = device == AudioSystem.DEVICE_OUT_DEFAULT ? "default"
   3985                         : AudioSystem.getOutputDeviceName(device);
   3986                 if (!deviceName.isEmpty()) {
   3987                     pw.print(" (");
   3988                     pw.print(deviceName);
   3989                     pw.print(")");
   3990                 }
   3991                 pw.print(": ");
   3992                 final int index = (mIndexMap.valueAt(i) + 5) / 10;
   3993                 pw.print(index);
   3994             }
   3995             pw.println();
   3996             pw.print("   Devices: ");
   3997             final int devices = getDevicesForStream(mStreamType);
   3998             int device, i = 0, n = 0;
   3999             // iterate all devices from 1 to DEVICE_OUT_DEFAULT exclusive
   4000             // (the default device is not returned by getDevicesForStream)
   4001             while ((device = 1 << i) != AudioSystem.DEVICE_OUT_DEFAULT) {
   4002                 if ((devices & device) != 0) {
   4003                     if (n++ > 0) {
   4004                         pw.print(", ");
   4005                     }
   4006                     pw.print(AudioSystem.getOutputDeviceName(device));
   4007                 }
   4008                 i++;
   4009             }
   4010         }
   4011     }
   4012 
   4013     /** Thread that handles native AudioSystem control. */
   4014     private class AudioSystemThread extends Thread {
   4015         AudioSystemThread() {
   4016             super("AudioService");
   4017         }
   4018 
   4019         @Override
   4020         public void run() {
   4021             // Set this thread up so the handler will work on it
   4022             Looper.prepare();
   4023 
   4024             synchronized(AudioService.this) {
   4025                 mAudioHandler = new AudioHandler();
   4026 
   4027                 // Notify that the handler has been created
   4028                 AudioService.this.notify();
   4029             }
   4030 
   4031             // Listen for volume change requests that are set by VolumePanel
   4032             Looper.loop();
   4033         }
   4034     }
   4035 
   4036     /** Handles internal volume messages in separate volume thread. */
   4037     private class AudioHandler extends Handler {
   4038 
   4039         private void setDeviceVolume(VolumeStreamState streamState, int device) {
   4040 
   4041             synchronized (VolumeStreamState.class) {
   4042                 // Apply volume
   4043                 streamState.applyDeviceVolume_syncVSS(device);
   4044 
   4045                 // Apply change to all streams using this one as alias
   4046                 int numStreamTypes = AudioSystem.getNumStreamTypes();
   4047                 for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
   4048                     if (streamType != streamState.mStreamType &&
   4049                             mStreamVolumeAlias[streamType] == streamState.mStreamType) {
   4050                         // Make sure volume is also maxed out on A2DP device for aliased stream
   4051                         // that may have a different device selected
   4052                         int streamDevice = getDeviceForStream(streamType);
   4053                         if ((device != streamDevice) && mAvrcpAbsVolSupported &&
   4054                                 ((device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0)) {
   4055                             mStreamStates[streamType].applyDeviceVolume_syncVSS(device);
   4056                         }
   4057                         mStreamStates[streamType].applyDeviceVolume_syncVSS(streamDevice);
   4058                     }
   4059                 }
   4060             }
   4061             // Post a persist volume msg
   4062             sendMsg(mAudioHandler,
   4063                     MSG_PERSIST_VOLUME,
   4064                     SENDMSG_QUEUE,
   4065                     device,
   4066                     0,
   4067                     streamState,
   4068                     PERSIST_DELAY);
   4069 
   4070         }
   4071 
   4072         private void setAllVolumes(VolumeStreamState streamState) {
   4073 
   4074             // Apply volume
   4075             streamState.applyAllVolumes();
   4076 
   4077             // Apply change to all streams using this one as alias
   4078             int numStreamTypes = AudioSystem.getNumStreamTypes();
   4079             for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
   4080                 if (streamType != streamState.mStreamType &&
   4081                         mStreamVolumeAlias[streamType] == streamState.mStreamType) {
   4082                     mStreamStates[streamType].applyAllVolumes();
   4083                 }
   4084             }
   4085         }
   4086 
   4087         private void persistVolume(VolumeStreamState streamState, int device) {
   4088             if (mUseFixedVolume) {
   4089                 return;
   4090             }
   4091             if (isPlatformTelevision() && (streamState.mStreamType != AudioSystem.STREAM_MUSIC)) {
   4092                 return;
   4093             }
   4094             System.putIntForUser(mContentResolver,
   4095                       streamState.getSettingNameForDevice(device),
   4096                       (streamState.getIndex(device) + 5)/ 10,
   4097                       UserHandle.USER_CURRENT);
   4098         }
   4099 
   4100         private void persistRingerMode(int ringerMode) {
   4101             if (mUseFixedVolume) {
   4102                 return;
   4103             }
   4104             Settings.Global.putInt(mContentResolver, Settings.Global.MODE_RINGER, ringerMode);
   4105         }
   4106 
   4107         private boolean onLoadSoundEffects() {
   4108             int status;
   4109 
   4110             synchronized (mSoundEffectsLock) {
   4111                 if (!mSystemReady) {
   4112                     Log.w(TAG, "onLoadSoundEffects() called before boot complete");
   4113                     return false;
   4114                 }
   4115 
   4116                 if (mSoundPool != null) {
   4117                     return true;
   4118                 }
   4119 
   4120                 loadTouchSoundAssets();
   4121 
   4122                 mSoundPool = new SoundPool.Builder()
   4123                         .setMaxStreams(NUM_SOUNDPOOL_CHANNELS)
   4124                         .setAudioAttributes(new AudioAttributes.Builder()
   4125                             .setUsage(AudioAttributes.USAGE_ASSISTANCE_SONIFICATION)
   4126                             .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
   4127                             .build())
   4128                         .build();
   4129                 mSoundPoolCallBack = null;
   4130                 mSoundPoolListenerThread = new SoundPoolListenerThread();
   4131                 mSoundPoolListenerThread.start();
   4132                 int attempts = 3;
   4133                 while ((mSoundPoolCallBack == null) && (attempts-- > 0)) {
   4134                     try {
   4135                         // Wait for mSoundPoolCallBack to be set by the other thread
   4136                         mSoundEffectsLock.wait(SOUND_EFFECTS_LOAD_TIMEOUT_MS);
   4137                     } catch (InterruptedException e) {
   4138                         Log.w(TAG, "Interrupted while waiting sound pool listener thread.");
   4139                     }
   4140                 }
   4141 
   4142                 if (mSoundPoolCallBack == null) {
   4143                     Log.w(TAG, "onLoadSoundEffects() SoundPool listener or thread creation error");
   4144                     if (mSoundPoolLooper != null) {
   4145                         mSoundPoolLooper.quit();
   4146                         mSoundPoolLooper = null;
   4147                     }
   4148                     mSoundPoolListenerThread = null;
   4149                     mSoundPool.release();
   4150                     mSoundPool = null;
   4151                     return false;
   4152                 }
   4153                 /*
   4154                  * poolId table: The value -1 in this table indicates that corresponding
   4155                  * file (same index in SOUND_EFFECT_FILES[] has not been loaded.
   4156                  * Once loaded, the value in poolId is the sample ID and the same
   4157                  * sample can be reused for another effect using the same file.
   4158                  */
   4159                 int[] poolId = new int[SOUND_EFFECT_FILES.size()];
   4160                 for (int fileIdx = 0; fileIdx < SOUND_EFFECT_FILES.size(); fileIdx++) {
   4161                     poolId[fileIdx] = -1;
   4162                 }
   4163                 /*
   4164                  * Effects whose value in SOUND_EFFECT_FILES_MAP[effect][1] is -1 must be loaded.
   4165                  * If load succeeds, value in SOUND_EFFECT_FILES_MAP[effect][1] is > 0:
   4166                  * this indicates we have a valid sample loaded for this effect.
   4167                  */
   4168 
   4169                 int numSamples = 0;
   4170                 for (int effect = 0; effect < AudioManager.NUM_SOUND_EFFECTS; effect++) {
   4171                     // Do not load sample if this effect uses the MediaPlayer
   4172                     if (SOUND_EFFECT_FILES_MAP[effect][1] == 0) {
   4173                         continue;
   4174                     }
   4175                     if (poolId[SOUND_EFFECT_FILES_MAP[effect][0]] == -1) {
   4176                         String filePath = Environment.getRootDirectory()
   4177                                 + SOUND_EFFECTS_PATH
   4178                                 + SOUND_EFFECT_FILES.get(SOUND_EFFECT_FILES_MAP[effect][0]);
   4179                         int sampleId = mSoundPool.load(filePath, 0);
   4180                         if (sampleId <= 0) {
   4181                             Log.w(TAG, "Soundpool could not load file: "+filePath);
   4182                         } else {
   4183                             SOUND_EFFECT_FILES_MAP[effect][1] = sampleId;
   4184                             poolId[SOUND_EFFECT_FILES_MAP[effect][0]] = sampleId;
   4185                             numSamples++;
   4186                         }
   4187                     } else {
   4188                         SOUND_EFFECT_FILES_MAP[effect][1] =
   4189                                 poolId[SOUND_EFFECT_FILES_MAP[effect][0]];
   4190                     }
   4191                 }
   4192                 // wait for all samples to be loaded
   4193                 if (numSamples > 0) {
   4194                     mSoundPoolCallBack.setSamples(poolId);
   4195 
   4196                     attempts = 3;
   4197                     status = 1;
   4198                     while ((status == 1) && (attempts-- > 0)) {
   4199                         try {
   4200                             mSoundEffectsLock.wait(SOUND_EFFECTS_LOAD_TIMEOUT_MS);
   4201                             status = mSoundPoolCallBack.status();
   4202                         } catch (InterruptedException e) {
   4203                             Log.w(TAG, "Interrupted while waiting sound pool callback.");
   4204                         }
   4205                     }
   4206                 } else {
   4207                     status = -1;
   4208                 }
   4209 
   4210                 if (mSoundPoolLooper != null) {
   4211                     mSoundPoolLooper.quit();
   4212                     mSoundPoolLooper = null;
   4213                 }
   4214                 mSoundPoolListenerThread = null;
   4215                 if (status != 0) {
   4216                     Log.w(TAG,
   4217                             "onLoadSoundEffects(), Error "+status+ " while loading samples");
   4218                     for (int effect = 0; effect < AudioManager.NUM_SOUND_EFFECTS; effect++) {
   4219                         if (SOUND_EFFECT_FILES_MAP[effect][1] > 0) {
   4220                             SOUND_EFFECT_FILES_MAP[effect][1] = -1;
   4221                         }
   4222                     }
   4223 
   4224                     mSoundPool.release();
   4225                     mSoundPool = null;
   4226                 }
   4227             }
   4228             return (status == 0);
   4229         }
   4230 
   4231         /**
   4232          *  Unloads samples from the sound pool.
   4233          *  This method can be called to free some memory when
   4234          *  sound effects are disabled.
   4235          */
   4236         private void onUnloadSoundEffects() {
   4237             synchronized (mSoundEffectsLock) {
   4238                 if (mSoundPool == null) {
   4239                     return;
   4240                 }
   4241 
   4242                 int[] poolId = new int[SOUND_EFFECT_FILES.size()];
   4243                 for (int fileIdx = 0; fileIdx < SOUND_EFFECT_FILES.size(); fileIdx++) {
   4244                     poolId[fileIdx] = 0;
   4245                 }
   4246 
   4247                 for (int effect = 0; effect < AudioManager.NUM_SOUND_EFFECTS; effect++) {
   4248                     if (SOUND_EFFECT_FILES_MAP[effect][1] <= 0) {
   4249                         continue;
   4250                     }
   4251                     if (poolId[SOUND_EFFECT_FILES_MAP[effect][0]] == 0) {
   4252                         mSoundPool.unload(SOUND_EFFECT_FILES_MAP[effect][1]);
   4253                         SOUND_EFFECT_FILES_MAP[effect][1] = -1;
   4254                         poolId[SOUND_EFFECT_FILES_MAP[effect][0]] = -1;
   4255                     }
   4256                 }
   4257                 mSoundPool.release();
   4258                 mSoundPool = null;
   4259             }
   4260         }
   4261 
   4262         private void onPlaySoundEffect(int effectType, int volume) {
   4263             synchronized (mSoundEffectsLock) {
   4264 
   4265                 onLoadSoundEffects();
   4266 
   4267                 if (mSoundPool == null) {
   4268                     return;
   4269                 }
   4270                 float volFloat;
   4271                 // use default if volume is not specified by caller
   4272                 if (volume < 0) {
   4273                     volFloat = (float)Math.pow(10, (float)sSoundEffectVolumeDb/20);
   4274                 } else {
   4275                     volFloat = volume / 1000.0f;
   4276                 }
   4277 
   4278                 if (SOUND_EFFECT_FILES_MAP[effectType][1] > 0) {
   4279                     mSoundPool.play(SOUND_EFFECT_FILES_MAP[effectType][1],
   4280                                         volFloat, volFloat, 0, 0, 1.0f);
   4281                 } else {
   4282                     MediaPlayer mediaPlayer = new MediaPlayer();
   4283                     try {
   4284                         String filePath = Environment.getRootDirectory() + SOUND_EFFECTS_PATH +
   4285                                     SOUND_EFFECT_FILES.get(SOUND_EFFECT_FILES_MAP[effectType][0]);
   4286                         mediaPlayer.setDataSource(filePath);
   4287                         mediaPlayer.setAudioStreamType(AudioSystem.STREAM_SYSTEM);
   4288                         mediaPlayer.prepare();
   4289                         mediaPlayer.setVolume(volFloat);
   4290                         mediaPlayer.setOnCompletionListener(new OnCompletionListener() {
   4291                             public void onCompletion(MediaPlayer mp) {
   4292                                 cleanupPlayer(mp);
   4293                             }
   4294                         });
   4295                         mediaPlayer.setOnErrorListener(new OnErrorListener() {
   4296                             public boolean onError(MediaPlayer mp, int what, int extra) {
   4297                                 cleanupPlayer(mp);
   4298                                 return true;
   4299                             }
   4300                         });
   4301                         mediaPlayer.start();
   4302                     } catch (IOException ex) {
   4303                         Log.w(TAG, "MediaPlayer IOException: "+ex);
   4304                     } catch (IllegalArgumentException ex) {
   4305                         Log.w(TAG, "MediaPlayer IllegalArgumentException: "+ex);
   4306                     } catch (IllegalStateException ex) {
   4307                         Log.w(TAG, "MediaPlayer IllegalStateException: "+ex);
   4308                     }
   4309                 }
   4310             }
   4311         }
   4312 
   4313         private void cleanupPlayer(MediaPlayer mp) {
   4314             if (mp != null) {
   4315                 try {
   4316                     mp.stop();
   4317                     mp.release();
   4318                 } catch (IllegalStateException ex) {
   4319                     Log.w(TAG, "MediaPlayer IllegalStateException: "+ex);
   4320                 }
   4321             }
   4322         }
   4323 
   4324         private void setForceUse(int usage, int config) {
   4325             synchronized (mConnectedDevices) {
   4326                 setForceUseInt_SyncDevices(usage, config);
   4327             }
   4328         }
   4329 
   4330         private void onPersistSafeVolumeState(int state) {
   4331             Settings.Global.putInt(mContentResolver,
   4332                     Settings.Global.AUDIO_SAFE_VOLUME_STATE,
   4333                     state);
   4334         }
   4335 
   4336         @Override
   4337         public void handleMessage(Message msg) {
   4338             switch (msg.what) {
   4339 
   4340                 case MSG_SET_DEVICE_VOLUME:
   4341                     setDeviceVolume((VolumeStreamState) msg.obj, msg.arg1);
   4342                     break;
   4343 
   4344                 case MSG_SET_ALL_VOLUMES:
   4345                     setAllVolumes((VolumeStreamState) msg.obj);
   4346                     break;
   4347 
   4348                 case MSG_PERSIST_VOLUME:
   4349                     persistVolume((VolumeStreamState) msg.obj, msg.arg1);
   4350                     break;
   4351 
   4352                 case MSG_PERSIST_MASTER_VOLUME_MUTE:
   4353                     if (mUseFixedVolume) {
   4354                         return;
   4355                     }
   4356                     Settings.System.putIntForUser(mContentResolver,
   4357                                                  Settings.System.VOLUME_MASTER_MUTE,
   4358                                                  msg.arg1,
   4359                                                  msg.arg2);
   4360                     break;
   4361 
   4362                 case MSG_PERSIST_RINGER_MODE:
   4363                     // note that the value persisted is the current ringer mode, not the
   4364                     // value of ringer mode as of the time the request was made to persist
   4365                     persistRingerMode(getRingerModeInternal());
   4366                     break;
   4367 
   4368                 case MSG_MEDIA_SERVER_DIED:
   4369                     onMediaServerDied();
   4370                     break;
   4371 
   4372                 case MSG_UNLOAD_SOUND_EFFECTS:
   4373                     onUnloadSoundEffects();
   4374                     break;
   4375 
   4376                 case MSG_LOAD_SOUND_EFFECTS:
   4377                     //FIXME: onLoadSoundEffects() should be executed in a separate thread as it
   4378                     // can take several dozens of milliseconds to complete
   4379                     boolean loaded = onLoadSoundEffects();
   4380                     if (msg.obj != null) {
   4381                         LoadSoundEffectReply reply = (LoadSoundEffectReply)msg.obj;
   4382                         synchronized (reply) {
   4383                             reply.mStatus = loaded ? 0 : -1;
   4384                             reply.notify();
   4385                         }
   4386                     }
   4387                     break;
   4388 
   4389                 case MSG_PLAY_SOUND_EFFECT:
   4390                     onPlaySoundEffect(msg.arg1, msg.arg2);
   4391                     break;
   4392 
   4393                 case MSG_BTA2DP_DOCK_TIMEOUT:
   4394                     // msg.obj  == address of BTA2DP device
   4395                     synchronized (mConnectedDevices) {
   4396                         makeA2dpDeviceUnavailableNow( (String) msg.obj );
   4397                     }
   4398                     break;
   4399 
   4400                 case MSG_SET_FORCE_USE:
   4401                 case MSG_SET_FORCE_BT_A2DP_USE:
   4402                     setForceUse(msg.arg1, msg.arg2);
   4403                     break;
   4404 
   4405                 case MSG_BT_HEADSET_CNCT_FAILED:
   4406                     resetBluetoothSco();
   4407                     break;
   4408 
   4409                 case MSG_SET_WIRED_DEVICE_CONNECTION_STATE:
   4410                     {   WiredDeviceConnectionState connectState =
   4411                             (WiredDeviceConnectionState)msg.obj;
   4412                         onSetWiredDeviceConnectionState(connectState.mType, connectState.mState,
   4413                                 connectState.mAddress, connectState.mName, connectState.mCaller);
   4414                         mAudioEventWakeLock.release();
   4415                     }
   4416                     break;
   4417 
   4418                 case MSG_SET_A2DP_SRC_CONNECTION_STATE:
   4419                     onSetA2dpSourceConnectionState((BluetoothDevice)msg.obj, msg.arg1);
   4420                     mAudioEventWakeLock.release();
   4421                     break;
   4422 
   4423                 case MSG_SET_A2DP_SINK_CONNECTION_STATE:
   4424                     onSetA2dpSinkConnectionState((BluetoothDevice)msg.obj, msg.arg1);
   4425                     mAudioEventWakeLock.release();
   4426                     break;
   4427 
   4428                 case MSG_REPORT_NEW_ROUTES: {
   4429                     int N = mRoutesObservers.beginBroadcast();
   4430                     if (N > 0) {
   4431                         AudioRoutesInfo routes;
   4432                         synchronized (mCurAudioRoutes) {
   4433                             routes = new AudioRoutesInfo(mCurAudioRoutes);
   4434                         }
   4435                         while (N > 0) {
   4436                             N--;
   4437                             IAudioRoutesObserver obs = mRoutesObservers.getBroadcastItem(N);
   4438                             try {
   4439                                 obs.dispatchAudioRoutesChanged(routes);
   4440                             } catch (RemoteException e) {
   4441                             }
   4442                         }
   4443                     }
   4444                     mRoutesObservers.finishBroadcast();
   4445                     observeDevicesForStreams(-1);
   4446                     break;
   4447                 }
   4448 
   4449                 case MSG_CHECK_MUSIC_ACTIVE:
   4450                     onCheckMusicActive((String) msg.obj);
   4451                     break;
   4452 
   4453                 case MSG_BROADCAST_AUDIO_BECOMING_NOISY:
   4454                     onSendBecomingNoisyIntent();
   4455                     break;
   4456 
   4457                 case MSG_CONFIGURE_SAFE_MEDIA_VOLUME_FORCED:
   4458                 case MSG_CONFIGURE_SAFE_MEDIA_VOLUME:
   4459                     onConfigureSafeVolume((msg.what == MSG_CONFIGURE_SAFE_MEDIA_VOLUME_FORCED),
   4460                             (String) msg.obj);
   4461                     break;
   4462                 case MSG_PERSIST_SAFE_VOLUME_STATE:
   4463                     onPersistSafeVolumeState(msg.arg1);
   4464                     break;
   4465 
   4466                 case MSG_BROADCAST_BT_CONNECTION_STATE:
   4467                     onBroadcastScoConnectionState(msg.arg1);
   4468                     break;
   4469 
   4470                 case MSG_SYSTEM_READY:
   4471                     onSystemReady();
   4472                     break;
   4473 
   4474                 case MSG_INDICATE_SYSTEM_READY:
   4475                     onIndicateSystemReady();
   4476                     break;
   4477 
   4478                 case MSG_PERSIST_MUSIC_ACTIVE_MS:
   4479                     final int musicActiveMs = msg.arg1;
   4480                     Settings.Secure.putIntForUser(mContentResolver,
   4481                             Settings.Secure.UNSAFE_VOLUME_MUSIC_ACTIVE_MS, musicActiveMs,
   4482                             UserHandle.USER_CURRENT);
   4483                     break;
   4484                 case MSG_PERSIST_MICROPHONE_MUTE:
   4485                     Settings.System.putIntForUser(mContentResolver,
   4486                                                  Settings.System.MICROPHONE_MUTE,
   4487                                                  msg.arg1,
   4488                                                  msg.arg2);
   4489                     break;
   4490                 case MSG_UNMUTE_STREAM:
   4491                     onUnmuteStream(msg.arg1, msg.arg2);
   4492                     break;
   4493                 case MSG_DYN_POLICY_MIX_STATE_UPDATE:
   4494                     onDynPolicyMixStateUpdate((String) msg.obj, msg.arg1);
   4495                     break;
   4496             }
   4497         }
   4498     }
   4499 
   4500     private class SettingsObserver extends ContentObserver {
   4501 
   4502         SettingsObserver() {
   4503             super(new Handler());
   4504             mContentResolver.registerContentObserver(Settings.System.getUriFor(
   4505                 Settings.System.MODE_RINGER_STREAMS_AFFECTED), false, this);
   4506             mContentResolver.registerContentObserver(Settings.Global.getUriFor(
   4507                 Settings.Global.DOCK_AUDIO_MEDIA_ENABLED), false, this);
   4508         }
   4509 
   4510         @Override
   4511         public void onChange(boolean selfChange) {
   4512             super.onChange(selfChange);
   4513             // FIXME This synchronized is not necessary if mSettingsLock only protects mRingerMode.
   4514             //       However there appear to be some missing locks around mRingerModeMutedStreams
   4515             //       and mRingerModeAffectedStreams, so will leave this synchronized for now.
   4516             //       mRingerModeMutedStreams and mMuteAffectedStreams are safe (only accessed once).
   4517             synchronized (mSettingsLock) {
   4518                 if (updateRingerModeAffectedStreams()) {
   4519                     /*
   4520                      * Ensure all stream types that should be affected by ringer mode
   4521                      * are in the proper state.
   4522                      */
   4523                     setRingerModeInt(getRingerModeInternal(), false);
   4524                 }
   4525                 readDockAudioSettings(mContentResolver);
   4526             }
   4527         }
   4528     }
   4529 
   4530     // must be called synchronized on mConnectedDevices
   4531     private void makeA2dpDeviceAvailable(String address, String name) {
   4532         // enable A2DP before notifying A2DP connection to avoid unecessary processing in
   4533         // audio policy manager
   4534         VolumeStreamState streamState = mStreamStates[AudioSystem.STREAM_MUSIC];
   4535         sendMsg(mAudioHandler, MSG_SET_DEVICE_VOLUME, SENDMSG_QUEUE,
   4536                 AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, 0, streamState, 0);
   4537         setBluetoothA2dpOnInt(true);
   4538         AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
   4539                 AudioSystem.DEVICE_STATE_AVAILABLE, address, name);
   4540         // Reset A2DP suspend state each time a new sink is connected
   4541         AudioSystem.setParameters("A2dpSuspended=false");
   4542         mConnectedDevices.put(
   4543                 makeDeviceListKey(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, address),
   4544                 new DeviceListSpec(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, name,
   4545                                    address));
   4546     }
   4547 
   4548     private void onSendBecomingNoisyIntent() {
   4549         sendBroadcastToAll(new Intent(AudioManager.ACTION_AUDIO_BECOMING_NOISY));
   4550     }
   4551 
   4552     // must be called synchronized on mConnectedDevices
   4553     private void makeA2dpDeviceUnavailableNow(String address) {
   4554         synchronized (mA2dpAvrcpLock) {
   4555             mAvrcpAbsVolSupported = false;
   4556         }
   4557         AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
   4558                 AudioSystem.DEVICE_STATE_UNAVAILABLE, address, "");
   4559         mConnectedDevices.remove(
   4560                 makeDeviceListKey(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, address));
   4561         synchronized (mCurAudioRoutes) {
   4562             // Remove A2DP routes as well
   4563             if (mCurAudioRoutes.bluetoothName != null) {
   4564                 mCurAudioRoutes.bluetoothName = null;
   4565                 sendMsg(mAudioHandler, MSG_REPORT_NEW_ROUTES,
   4566                         SENDMSG_NOOP, 0, 0, null, 0);
   4567             }
   4568         }
   4569     }
   4570 
   4571     // must be called synchronized on mConnectedDevices
   4572     private void makeA2dpDeviceUnavailableLater(String address, int delayMs) {
   4573         // prevent any activity on the A2DP audio output to avoid unwanted
   4574         // reconnection of the sink.
   4575         AudioSystem.setParameters("A2dpSuspended=true");
   4576         // the device will be made unavailable later, so consider it disconnected right away
   4577         mConnectedDevices.remove(
   4578                 makeDeviceListKey(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, address));
   4579         // send the delayed message to make the device unavailable later
   4580         Message msg = mAudioHandler.obtainMessage(MSG_BTA2DP_DOCK_TIMEOUT, address);
   4581         mAudioHandler.sendMessageDelayed(msg, delayMs);
   4582 
   4583     }
   4584 
   4585     // must be called synchronized on mConnectedDevices
   4586     private void makeA2dpSrcAvailable(String address) {
   4587         AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP,
   4588                 AudioSystem.DEVICE_STATE_AVAILABLE, address, "");
   4589         mConnectedDevices.put(
   4590                 makeDeviceListKey(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP, address),
   4591                 new DeviceListSpec(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP, "",
   4592                                    address));
   4593     }
   4594 
   4595     // must be called synchronized on mConnectedDevices
   4596     private void makeA2dpSrcUnavailable(String address) {
   4597         AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP,
   4598                 AudioSystem.DEVICE_STATE_UNAVAILABLE, address, "");
   4599         mConnectedDevices.remove(
   4600                 makeDeviceListKey(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP, address));
   4601     }
   4602 
   4603     // must be called synchronized on mConnectedDevices
   4604     private void cancelA2dpDeviceTimeout() {
   4605         mAudioHandler.removeMessages(MSG_BTA2DP_DOCK_TIMEOUT);
   4606     }
   4607 
   4608     // must be called synchronized on mConnectedDevices
   4609     private boolean hasScheduledA2dpDockTimeout() {
   4610         return mAudioHandler.hasMessages(MSG_BTA2DP_DOCK_TIMEOUT);
   4611     }
   4612 
   4613     private void onSetA2dpSinkConnectionState(BluetoothDevice btDevice, int state)
   4614     {
   4615         if (DEBUG_VOL) {
   4616             Log.d(TAG, "onSetA2dpSinkConnectionState btDevice="+btDevice+"state="+state);
   4617         }
   4618         if (btDevice == null) {
   4619             return;
   4620         }
   4621         String address = btDevice.getAddress();
   4622         if (!BluetoothAdapter.checkBluetoothAddress(address)) {
   4623             address = "";
   4624         }
   4625 
   4626         synchronized (mConnectedDevices) {
   4627             String key = makeDeviceListKey(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
   4628                                            btDevice.getAddress());
   4629             DeviceListSpec deviceSpec = mConnectedDevices.get(key);
   4630             boolean isConnected = deviceSpec != null;
   4631 
   4632             if (isConnected && state != BluetoothProfile.STATE_CONNECTED) {
   4633                 if (btDevice.isBluetoothDock()) {
   4634                     if (state == BluetoothProfile.STATE_DISCONNECTED) {
   4635                         // introduction of a delay for transient disconnections of docks when
   4636                         // power is rapidly turned off/on, this message will be canceled if
   4637                         // we reconnect the dock under a preset delay
   4638                         makeA2dpDeviceUnavailableLater(address, BTA2DP_DOCK_TIMEOUT_MILLIS);
   4639                         // the next time isConnected is evaluated, it will be false for the dock
   4640                     }
   4641                 } else {
   4642                     makeA2dpDeviceUnavailableNow(address);
   4643                 }
   4644                 synchronized (mCurAudioRoutes) {
   4645                     if (mCurAudioRoutes.bluetoothName != null) {
   4646                         mCurAudioRoutes.bluetoothName = null;
   4647                         sendMsg(mAudioHandler, MSG_REPORT_NEW_ROUTES,
   4648                                 SENDMSG_NOOP, 0, 0, null, 0);
   4649                     }
   4650                 }
   4651             } else if (!isConnected && state == BluetoothProfile.STATE_CONNECTED) {
   4652                 if (btDevice.isBluetoothDock()) {
   4653                     // this could be a reconnection after a transient disconnection
   4654                     cancelA2dpDeviceTimeout();
   4655                     mDockAddress = address;
   4656                 } else {
   4657                     // this could be a connection of another A2DP device before the timeout of
   4658                     // a dock: cancel the dock timeout, and make the dock unavailable now
   4659                     if(hasScheduledA2dpDockTimeout()) {
   4660                         cancelA2dpDeviceTimeout();
   4661                         makeA2dpDeviceUnavailableNow(mDockAddress);
   4662                     }
   4663                 }
   4664                 makeA2dpDeviceAvailable(address, btDevice.getName());
   4665                 synchronized (mCurAudioRoutes) {
   4666                     String name = btDevice.getAliasName();
   4667                     if (!TextUtils.equals(mCurAudioRoutes.bluetoothName, name)) {
   4668                         mCurAudioRoutes.bluetoothName = name;
   4669                         sendMsg(mAudioHandler, MSG_REPORT_NEW_ROUTES,
   4670                                 SENDMSG_NOOP, 0, 0, null, 0);
   4671                     }
   4672                 }
   4673             }
   4674         }
   4675     }
   4676 
   4677     private void onSetA2dpSourceConnectionState(BluetoothDevice btDevice, int state)
   4678     {
   4679         if (DEBUG_VOL) {
   4680             Log.d(TAG, "onSetA2dpSourceConnectionState btDevice="+btDevice+" state="+state);
   4681         }
   4682         if (btDevice == null) {
   4683             return;
   4684         }
   4685         String address = btDevice.getAddress();
   4686         if (!BluetoothAdapter.checkBluetoothAddress(address)) {
   4687             address = "";
   4688         }
   4689 
   4690         synchronized (mConnectedDevices) {
   4691             String key = makeDeviceListKey(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP, address);
   4692             DeviceListSpec deviceSpec = mConnectedDevices.get(key);
   4693             boolean isConnected = deviceSpec != null;
   4694 
   4695             if (isConnected && state != BluetoothProfile.STATE_CONNECTED) {
   4696                 makeA2dpSrcUnavailable(address);
   4697             } else if (!isConnected && state == BluetoothProfile.STATE_CONNECTED) {
   4698                 makeA2dpSrcAvailable(address);
   4699             }
   4700         }
   4701     }
   4702 
   4703     public void avrcpSupportsAbsoluteVolume(String address, boolean support) {
   4704         // address is not used for now, but may be used when multiple a2dp devices are supported
   4705         synchronized (mA2dpAvrcpLock) {
   4706             mAvrcpAbsVolSupported = support;
   4707             sendMsg(mAudioHandler, MSG_SET_DEVICE_VOLUME, SENDMSG_QUEUE,
   4708                     AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, 0,
   4709                     mStreamStates[AudioSystem.STREAM_MUSIC], 0);
   4710             sendMsg(mAudioHandler, MSG_SET_DEVICE_VOLUME, SENDMSG_QUEUE,
   4711                     AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, 0,
   4712                     mStreamStates[AudioSystem.STREAM_RING], 0);
   4713         }
   4714     }
   4715 
   4716     private boolean handleDeviceConnection(boolean connect, int device, String address,
   4717             String deviceName) {
   4718         if (DEBUG_DEVICES) {
   4719             Slog.i(TAG, "handleDeviceConnection(" + connect + " dev:" + Integer.toHexString(device)
   4720                     + " address:" + address + " name:" + deviceName + ")");
   4721         }
   4722         synchronized (mConnectedDevices) {
   4723             String deviceKey = makeDeviceListKey(device, address);
   4724             if (DEBUG_DEVICES) {
   4725                 Slog.i(TAG, "deviceKey:" + deviceKey);
   4726             }
   4727             DeviceListSpec deviceSpec = mConnectedDevices.get(deviceKey);
   4728             boolean isConnected = deviceSpec != null;
   4729             if (DEBUG_DEVICES) {
   4730                 Slog.i(TAG, "deviceSpec:" + deviceSpec + " is(already)Connected:" + isConnected);
   4731             }
   4732             if (connect && !isConnected) {
   4733                 final int res = AudioSystem.setDeviceConnectionState(device,
   4734                         AudioSystem.DEVICE_STATE_AVAILABLE, address, deviceName);
   4735                 if (res != AudioSystem.AUDIO_STATUS_OK) {
   4736                     Slog.e(TAG, "not connecting device 0x" + Integer.toHexString(device) +
   4737                             " due to command error " + res );
   4738                     return false;
   4739                 }
   4740                 mConnectedDevices.put(deviceKey, new DeviceListSpec(device, deviceName, address));
   4741                 return true;
   4742             } else if (!connect && isConnected) {
   4743                 AudioSystem.setDeviceConnectionState(device,
   4744                         AudioSystem.DEVICE_STATE_UNAVAILABLE, address, deviceName);
   4745                 // always remove even if disconnection failed
   4746                 mConnectedDevices.remove(deviceKey);
   4747                 return true;
   4748             }
   4749         }
   4750         return false;
   4751     }
   4752 
   4753     // Devices which removal triggers intent ACTION_AUDIO_BECOMING_NOISY. The intent is only
   4754     // sent if none of these devices is connected.
   4755     // Access synchronized on mConnectedDevices
   4756     int mBecomingNoisyIntentDevices =
   4757             AudioSystem.DEVICE_OUT_WIRED_HEADSET | AudioSystem.DEVICE_OUT_WIRED_HEADPHONE |
   4758             AudioSystem.DEVICE_OUT_ALL_A2DP | AudioSystem.DEVICE_OUT_HDMI |
   4759             AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET | AudioSystem.DEVICE_OUT_DGTL_DOCK_HEADSET |
   4760             AudioSystem.DEVICE_OUT_ALL_USB | AudioSystem.DEVICE_OUT_LINE;
   4761 
   4762     // must be called before removing the device from mConnectedDevices
   4763     // Called synchronized on mConnectedDevices
   4764     private int checkSendBecomingNoisyIntent(int device, int state) {
   4765         int delay = 0;
   4766         if ((state == 0) && ((device & mBecomingNoisyIntentDevices) != 0)) {
   4767             int devices = 0;
   4768             for (int i = 0; i < mConnectedDevices.size(); i++) {
   4769                 int dev = mConnectedDevices.valueAt(i).mDeviceType;
   4770                 if (((dev & AudioSystem.DEVICE_BIT_IN) == 0)
   4771                         && ((dev & mBecomingNoisyIntentDevices) != 0)) {
   4772                     devices |= dev;
   4773                 }
   4774             }
   4775             if (devices == device) {
   4776                 sendMsg(mAudioHandler,
   4777                         MSG_BROADCAST_AUDIO_BECOMING_NOISY,
   4778                         SENDMSG_REPLACE,
   4779                         0,
   4780                         0,
   4781                         null,
   4782                         0);
   4783                 delay = 1000;
   4784             }
   4785         }
   4786 
   4787         if (mAudioHandler.hasMessages(MSG_SET_A2DP_SRC_CONNECTION_STATE) ||
   4788                 mAudioHandler.hasMessages(MSG_SET_A2DP_SINK_CONNECTION_STATE) ||
   4789                 mAudioHandler.hasMessages(MSG_SET_WIRED_DEVICE_CONNECTION_STATE)) {
   4790             synchronized (mLastDeviceConnectMsgTime) {
   4791                 long time = SystemClock.uptimeMillis();
   4792                 if (mLastDeviceConnectMsgTime > time) {
   4793                     delay = (int)(mLastDeviceConnectMsgTime - time) + 30;
   4794                 }
   4795             }
   4796         }
   4797         return delay;
   4798     }
   4799 
   4800     private void sendDeviceConnectionIntent(int device, int state, String address,
   4801             String deviceName) {
   4802         if (DEBUG_DEVICES) {
   4803             Slog.i(TAG, "sendDeviceConnectionIntent(dev:0x" + Integer.toHexString(device) +
   4804                     " state:0x" + Integer.toHexString(state) + " address:" + address +
   4805                     " name:" + deviceName + ");");
   4806         }
   4807         Intent intent = new Intent();
   4808 
   4809         intent.putExtra(CONNECT_INTENT_KEY_STATE, state);
   4810         intent.putExtra(CONNECT_INTENT_KEY_ADDRESS, address);
   4811         intent.putExtra(CONNECT_INTENT_KEY_PORT_NAME, deviceName);
   4812 
   4813         intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
   4814 
   4815         int connType = 0;
   4816 
   4817         if (device == AudioSystem.DEVICE_OUT_WIRED_HEADSET) {
   4818             connType = AudioRoutesInfo.MAIN_HEADSET;
   4819             intent.setAction(Intent.ACTION_HEADSET_PLUG);
   4820             intent.putExtra("microphone", 1);
   4821         } else if (device == AudioSystem.DEVICE_OUT_WIRED_HEADPHONE ||
   4822                    device == AudioSystem.DEVICE_OUT_LINE) {
   4823             /*do apps care about line-out vs headphones?*/
   4824             connType = AudioRoutesInfo.MAIN_HEADPHONES;
   4825             intent.setAction(Intent.ACTION_HEADSET_PLUG);
   4826             intent.putExtra("microphone", 0);
   4827         } else if (device == AudioSystem.DEVICE_OUT_HDMI ||
   4828                 device == AudioSystem.DEVICE_OUT_HDMI_ARC) {
   4829             connType = AudioRoutesInfo.MAIN_HDMI;
   4830             configureHdmiPlugIntent(intent, state);
   4831         } else if (device == AudioSystem.DEVICE_OUT_USB_DEVICE) {
   4832             connType = AudioRoutesInfo.MAIN_USB;
   4833         }
   4834 
   4835         synchronized (mCurAudioRoutes) {
   4836             if (connType != 0) {
   4837                 int newConn = mCurAudioRoutes.mainType;
   4838                 if (state != 0) {
   4839                     newConn |= connType;
   4840                 } else {
   4841                     newConn &= ~connType;
   4842                 }
   4843                 if (newConn != mCurAudioRoutes.mainType) {
   4844                     mCurAudioRoutes.mainType = newConn;
   4845                     sendMsg(mAudioHandler, MSG_REPORT_NEW_ROUTES,
   4846                             SENDMSG_NOOP, 0, 0, null, 0);
   4847                 }
   4848             }
   4849         }
   4850 
   4851         final long ident = Binder.clearCallingIdentity();
   4852         try {
   4853             ActivityManagerNative.broadcastStickyIntent(intent, null, UserHandle.USER_ALL);
   4854         } finally {
   4855             Binder.restoreCallingIdentity(ident);
   4856         }
   4857     }
   4858 
   4859     private void onSetWiredDeviceConnectionState(int device, int state, String address,
   4860             String deviceName, String caller) {
   4861         if (DEBUG_DEVICES) {
   4862             Slog.i(TAG, "onSetWiredDeviceConnectionState(dev:" + Integer.toHexString(device)
   4863                     + " state:" + Integer.toHexString(state)
   4864                     + " address:" + address
   4865                     + " deviceName:" + deviceName
   4866                     + " caller: " + caller + ");");
   4867         }
   4868 
   4869         synchronized (mConnectedDevices) {
   4870             if ((state == 0) && ((device == AudioSystem.DEVICE_OUT_WIRED_HEADSET) ||
   4871                     (device == AudioSystem.DEVICE_OUT_WIRED_HEADPHONE) ||
   4872                     (device == AudioSystem.DEVICE_OUT_LINE))) {
   4873                 setBluetoothA2dpOnInt(true);
   4874             }
   4875             boolean isUsb = ((device & ~AudioSystem.DEVICE_OUT_ALL_USB) == 0) ||
   4876                             (((device & AudioSystem.DEVICE_BIT_IN) != 0) &&
   4877                              ((device & ~AudioSystem.DEVICE_IN_ALL_USB) == 0));
   4878             if (!handleDeviceConnection(state == 1, device, address, deviceName)) {
   4879                 // change of connection state failed, bailout
   4880                 return;
   4881             }
   4882             if (state != 0) {
   4883                 if ((device == AudioSystem.DEVICE_OUT_WIRED_HEADSET) ||
   4884                     (device == AudioSystem.DEVICE_OUT_WIRED_HEADPHONE) ||
   4885                     (device == AudioSystem.DEVICE_OUT_LINE)) {
   4886                     setBluetoothA2dpOnInt(false);
   4887                 }
   4888                 if ((device & mSafeMediaVolumeDevices) != 0) {
   4889                     sendMsg(mAudioHandler,
   4890                             MSG_CHECK_MUSIC_ACTIVE,
   4891                             SENDMSG_REPLACE,
   4892                             0,
   4893                             0,
   4894                             caller,
   4895                             MUSIC_ACTIVE_POLL_PERIOD_MS);
   4896                 }
   4897                 // Television devices without CEC service apply software volume on HDMI output
   4898                 if (isPlatformTelevision() && ((device & AudioSystem.DEVICE_OUT_HDMI) != 0)) {
   4899                     mFixedVolumeDevices |= AudioSystem.DEVICE_OUT_HDMI;
   4900                     checkAllFixedVolumeDevices();
   4901                     if (mHdmiManager != null) {
   4902                         synchronized (mHdmiManager) {
   4903                             if (mHdmiPlaybackClient != null) {
   4904                                 mHdmiCecSink = false;
   4905                                 mHdmiPlaybackClient.queryDisplayStatus(mHdmiDisplayStatusCallback);
   4906                             }
   4907                         }
   4908                     }
   4909                 }
   4910             } else {
   4911                 if (isPlatformTelevision() && ((device & AudioSystem.DEVICE_OUT_HDMI) != 0)) {
   4912                     if (mHdmiManager != null) {
   4913                         synchronized (mHdmiManager) {
   4914                             mHdmiCecSink = false;
   4915                         }
   4916                     }
   4917                 }
   4918             }
   4919             if (!isUsb && device != AudioSystem.DEVICE_IN_WIRED_HEADSET) {
   4920                 sendDeviceConnectionIntent(device, state, address, deviceName);
   4921             }
   4922         }
   4923     }
   4924 
   4925     private void configureHdmiPlugIntent(Intent intent, int state) {
   4926         intent.setAction(AudioManager.ACTION_HDMI_AUDIO_PLUG);
   4927         intent.putExtra(AudioManager.EXTRA_AUDIO_PLUG_STATE, state);
   4928         if (state == 1) {
   4929             ArrayList<AudioPort> ports = new ArrayList<AudioPort>();
   4930             int[] portGeneration = new int[1];
   4931             int status = AudioSystem.listAudioPorts(ports, portGeneration);
   4932             if (status == AudioManager.SUCCESS) {
   4933                 for (AudioPort port : ports) {
   4934                     if (port instanceof AudioDevicePort) {
   4935                         final AudioDevicePort devicePort = (AudioDevicePort) port;
   4936                         if (devicePort.type() == AudioManager.DEVICE_OUT_HDMI ||
   4937                                 devicePort.type() == AudioManager.DEVICE_OUT_HDMI_ARC) {
   4938                             // format the list of supported encodings
   4939                             int[] formats = AudioFormat.filterPublicFormats(devicePort.formats());
   4940                             if (formats.length > 0) {
   4941                                 ArrayList<Integer> encodingList = new ArrayList(1);
   4942                                 for (int format : formats) {
   4943                                     // a format in the list can be 0, skip it
   4944                                     if (format != AudioFormat.ENCODING_INVALID) {
   4945                                         encodingList.add(format);
   4946                                     }
   4947                                 }
   4948                                 int[] encodingArray = new int[encodingList.size()];
   4949                                 for (int i = 0 ; i < encodingArray.length ; i++) {
   4950                                     encodingArray[i] = encodingList.get(i);
   4951                                 }
   4952                                 intent.putExtra(AudioManager.EXTRA_ENCODINGS, encodingArray);
   4953                             }
   4954                             // find the maximum supported number of channels
   4955                             int maxChannels = 0;
   4956                             for (int mask : devicePort.channelMasks()) {
   4957                                 int channelCount = AudioFormat.channelCountFromOutChannelMask(mask);
   4958                                 if (channelCount > maxChannels) {
   4959                                     maxChannels = channelCount;
   4960                                 }
   4961                             }
   4962                             intent.putExtra(AudioManager.EXTRA_MAX_CHANNEL_COUNT, maxChannels);
   4963                         }
   4964                     }
   4965                 }
   4966             }
   4967         }
   4968     }
   4969 
   4970     /* cache of the address of the last dock the device was connected to */
   4971     private String mDockAddress;
   4972 
   4973     /**
   4974      * Receiver for misc intent broadcasts the Phone app cares about.
   4975      */
   4976     private class AudioServiceBroadcastReceiver extends BroadcastReceiver {
   4977         @Override
   4978         public void onReceive(Context context, Intent intent) {
   4979             String action = intent.getAction();
   4980             int outDevice;
   4981             int inDevice;
   4982             int state;
   4983 
   4984             if (action.equals(Intent.ACTION_DOCK_EVENT)) {
   4985                 int dockState = intent.getIntExtra(Intent.EXTRA_DOCK_STATE,
   4986                         Intent.EXTRA_DOCK_STATE_UNDOCKED);
   4987                 int config;
   4988                 switch (dockState) {
   4989                     case Intent.EXTRA_DOCK_STATE_DESK:
   4990                         config = AudioSystem.FORCE_BT_DESK_DOCK;
   4991                         break;
   4992                     case Intent.EXTRA_DOCK_STATE_CAR:
   4993                         config = AudioSystem.FORCE_BT_CAR_DOCK;
   4994                         break;
   4995                     case Intent.EXTRA_DOCK_STATE_LE_DESK:
   4996                         config = AudioSystem.FORCE_ANALOG_DOCK;
   4997                         break;
   4998                     case Intent.EXTRA_DOCK_STATE_HE_DESK:
   4999                         config = AudioSystem.FORCE_DIGITAL_DOCK;
   5000                         break;
   5001                     case Intent.EXTRA_DOCK_STATE_UNDOCKED:
   5002                     default:
   5003                         config = AudioSystem.FORCE_NONE;
   5004                 }
   5005                 // Low end docks have a menu to enable or disable audio
   5006                 // (see mDockAudioMediaEnabled)
   5007                 if (!((dockState == Intent.EXTRA_DOCK_STATE_LE_DESK) ||
   5008                       ((dockState == Intent.EXTRA_DOCK_STATE_UNDOCKED) &&
   5009                        (mDockState == Intent.EXTRA_DOCK_STATE_LE_DESK)))) {
   5010                     AudioSystem.setForceUse(AudioSystem.FOR_DOCK, config);
   5011                 }
   5012                 mDockState = dockState;
   5013             } else if (action.equals(BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED)) {
   5014                 state = intent.getIntExtra(BluetoothProfile.EXTRA_STATE,
   5015                                                BluetoothProfile.STATE_DISCONNECTED);
   5016                 BluetoothDevice btDevice = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
   5017 
   5018                 setBtScoDeviceConnectionState(btDevice, state);
   5019             } else if (action.equals(BluetoothHeadset.ACTION_AUDIO_STATE_CHANGED)) {
   5020                 boolean broadcast = false;
   5021                 int scoAudioState = AudioManager.SCO_AUDIO_STATE_ERROR;
   5022                 synchronized (mScoClients) {
   5023                     int btState = intent.getIntExtra(BluetoothProfile.EXTRA_STATE, -1);
   5024                     // broadcast intent if the connection was initated by AudioService
   5025                     if (!mScoClients.isEmpty() &&
   5026                             (mScoAudioState == SCO_STATE_ACTIVE_INTERNAL ||
   5027                              mScoAudioState == SCO_STATE_ACTIVATE_REQ ||
   5028                              mScoAudioState == SCO_STATE_DEACTIVATE_REQ)) {
   5029                         broadcast = true;
   5030                     }
   5031                     switch (btState) {
   5032                     case BluetoothHeadset.STATE_AUDIO_CONNECTED:
   5033                         scoAudioState = AudioManager.SCO_AUDIO_STATE_CONNECTED;
   5034                         if (mScoAudioState != SCO_STATE_ACTIVE_INTERNAL &&
   5035                             mScoAudioState != SCO_STATE_DEACTIVATE_REQ &&
   5036                             mScoAudioState != SCO_STATE_DEACTIVATE_EXT_REQ) {
   5037                             mScoAudioState = SCO_STATE_ACTIVE_EXTERNAL;
   5038                         }
   5039                         break;
   5040                     case BluetoothHeadset.STATE_AUDIO_DISCONNECTED:
   5041                         scoAudioState = AudioManager.SCO_AUDIO_STATE_DISCONNECTED;
   5042                         mScoAudioState = SCO_STATE_INACTIVE;
   5043                         clearAllScoClients(0, false);
   5044                         break;
   5045                     case BluetoothHeadset.STATE_AUDIO_CONNECTING:
   5046                         if (mScoAudioState != SCO_STATE_ACTIVE_INTERNAL &&
   5047                             mScoAudioState != SCO_STATE_DEACTIVATE_REQ &&
   5048                             mScoAudioState != SCO_STATE_DEACTIVATE_EXT_REQ) {
   5049                             mScoAudioState = SCO_STATE_ACTIVE_EXTERNAL;
   5050                         }
   5051                     default:
   5052                         // do not broadcast CONNECTING or invalid state
   5053                         broadcast = false;
   5054                         break;
   5055                     }
   5056                 }
   5057                 if (broadcast) {
   5058                     broadcastScoConnectionState(scoAudioState);
   5059                     //FIXME: this is to maintain compatibility with deprecated intent
   5060                     // AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED. Remove when appropriate.
   5061                     Intent newIntent = new Intent(AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED);
   5062                     newIntent.putExtra(AudioManager.EXTRA_SCO_AUDIO_STATE, scoAudioState);
   5063                     sendStickyBroadcastToAll(newIntent);
   5064                 }
   5065             } else if (action.equals(Intent.ACTION_SCREEN_ON)) {
   5066                 if (mMonitorRotation) {
   5067                     mOrientationListener.onOrientationChanged(0); //argument is ignored anyway
   5068                     mOrientationListener.enable();
   5069                 }
   5070                 AudioSystem.setParameters("screen_state=on");
   5071             } else if (action.equals(Intent.ACTION_SCREEN_OFF)) {
   5072                 if (mMonitorRotation) {
   5073                     //reduce wakeups (save current) by only listening when display is on
   5074                     mOrientationListener.disable();
   5075                 }
   5076                 AudioSystem.setParameters("screen_state=off");
   5077             } else if (action.equals(Intent.ACTION_CONFIGURATION_CHANGED)) {
   5078                 handleConfigurationChanged(context);
   5079             } else if (action.equals(Intent.ACTION_USER_SWITCHED)) {
   5080                 // attempt to stop music playback for background user
   5081                 sendMsg(mAudioHandler,
   5082                         MSG_BROADCAST_AUDIO_BECOMING_NOISY,
   5083                         SENDMSG_REPLACE,
   5084                         0,
   5085                         0,
   5086                         null,
   5087                         0);
   5088                 // the current audio focus owner is no longer valid
   5089                 mMediaFocusControl.discardAudioFocusOwner();
   5090 
   5091                 // load volume settings for new user
   5092                 readAudioSettings(true /*userSwitch*/);
   5093                 // preserve STREAM_MUSIC volume from one user to the next.
   5094                 sendMsg(mAudioHandler,
   5095                         MSG_SET_ALL_VOLUMES,
   5096                         SENDMSG_QUEUE,
   5097                         0,
   5098                         0,
   5099                         mStreamStates[AudioSystem.STREAM_MUSIC], 0);
   5100             } else if (action.equals(Intent.ACTION_USER_BACKGROUND)) {
   5101                 // Disable audio recording for the background user/profile
   5102                 int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
   5103                 if (userId >= 0) {
   5104                     // TODO Kill recording streams instead of killing processes holding permission
   5105                     UserInfo userInfo = UserManagerService.getInstance().getUserInfo(userId);
   5106                     killBackgroundUserProcessesWithRecordAudioPermission(userInfo);
   5107                 }
   5108                 UserManagerService.getInstance().setSystemControlledUserRestriction(
   5109                         UserManager.DISALLOW_RECORD_AUDIO, true, userId);
   5110             } else if (action.equals(Intent.ACTION_USER_FOREGROUND)) {
   5111                 // Enable audio recording for foreground user/profile
   5112                 int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
   5113                 UserManagerService.getInstance().setSystemControlledUserRestriction(
   5114                         UserManager.DISALLOW_RECORD_AUDIO, false, userId);
   5115             }
   5116         }
   5117     } // end class AudioServiceBroadcastReceiver
   5118 
   5119     private void killBackgroundUserProcessesWithRecordAudioPermission(UserInfo oldUser) {
   5120         PackageManager pm = mContext.getPackageManager();
   5121         // Find the home activity of the user. It should not be killed to avoid expensive restart,
   5122         // when the user switches back. For managed profiles, we should kill all recording apps
   5123         ComponentName homeActivityName = null;
   5124         if (!oldUser.isManagedProfile()) {
   5125             homeActivityName = LocalServices.getService(ActivityManagerInternal.class)
   5126                     .getHomeActivityForUser(oldUser.id);
   5127         }
   5128         final String[] permissions = { Manifest.permission.RECORD_AUDIO };
   5129         List<PackageInfo> packages;
   5130         try {
   5131             packages = AppGlobals.getPackageManager()
   5132                     .getPackagesHoldingPermissions(permissions, 0, oldUser.id).getList();
   5133         } catch (RemoteException e) {
   5134             throw new AndroidRuntimeException(e);
   5135         }
   5136         for (int j = packages.size() - 1; j >= 0; j--) {
   5137             PackageInfo pkg = packages.get(j);
   5138             // Skip system processes
   5139             if (UserHandle.getAppId(pkg.applicationInfo.uid) < FIRST_APPLICATION_UID) {
   5140                 continue;
   5141             }
   5142             // Skip packages that have permission to interact across users
   5143             if (pm.checkPermission(Manifest.permission.INTERACT_ACROSS_USERS, pkg.packageName)
   5144                     == PackageManager.PERMISSION_GRANTED) {
   5145                 continue;
   5146             }
   5147             if (homeActivityName != null
   5148                     && pkg.packageName.equals(homeActivityName.getPackageName())
   5149                     && pkg.applicationInfo.isSystemApp()) {
   5150                 continue;
   5151             }
   5152             try {
   5153                 final int uid = pkg.applicationInfo.uid;
   5154                 ActivityManagerNative.getDefault().killUid(UserHandle.getAppId(uid),
   5155                         UserHandle.getUserId(uid),
   5156                         "killBackgroundUserProcessesWithAudioRecordPermission");
   5157             } catch (RemoteException e) {
   5158                 Log.w(TAG, "Error calling killUid", e);
   5159             }
   5160         }
   5161     }
   5162 
   5163     //==========================================================================================
   5164     // RemoteControlDisplay / RemoteControlClient / Remote info
   5165     //==========================================================================================
   5166     public boolean registerRemoteController(IRemoteControlDisplay rcd, int w, int h,
   5167             ComponentName listenerComp) {
   5168         return mMediaFocusControl.registerRemoteController(rcd, w, h, listenerComp);
   5169     }
   5170 
   5171     public boolean registerRemoteControlDisplay(IRemoteControlDisplay rcd, int w, int h) {
   5172         return mMediaFocusControl.registerRemoteControlDisplay(rcd, w, h);
   5173     }
   5174 
   5175     public void unregisterRemoteControlDisplay(IRemoteControlDisplay rcd) {
   5176         mMediaFocusControl.unregisterRemoteControlDisplay(rcd);
   5177     }
   5178 
   5179     public void remoteControlDisplayUsesBitmapSize(IRemoteControlDisplay rcd, int w, int h) {
   5180         mMediaFocusControl.remoteControlDisplayUsesBitmapSize(rcd, w, h);
   5181     }
   5182 
   5183     public void remoteControlDisplayWantsPlaybackPositionSync(IRemoteControlDisplay rcd,
   5184             boolean wantsSync) {
   5185         mMediaFocusControl.remoteControlDisplayWantsPlaybackPositionSync(rcd, wantsSync);
   5186     }
   5187 
   5188     @Override
   5189     public void setRemoteStreamVolume(int index) {
   5190         enforceVolumeController("set the remote stream volume");
   5191         mMediaFocusControl.setRemoteStreamVolume(index);
   5192     }
   5193 
   5194     //==========================================================================================
   5195     // Audio Focus
   5196     //==========================================================================================
   5197     public int requestAudioFocus(AudioAttributes aa, int durationHint, IBinder cb,
   5198             IAudioFocusDispatcher fd, String clientId, String callingPackageName, int flags,
   5199             IAudioPolicyCallback pcb) {
   5200         // permission checks
   5201         if ((flags & AudioManager.AUDIOFOCUS_FLAG_LOCK) == AudioManager.AUDIOFOCUS_FLAG_LOCK) {
   5202             if (AudioSystem.IN_VOICE_COMM_FOCUS_ID.equals(clientId)) {
   5203                 if (PackageManager.PERMISSION_GRANTED != mContext.checkCallingOrSelfPermission(
   5204                             android.Manifest.permission.MODIFY_PHONE_STATE)) {
   5205                     Log.e(TAG, "Invalid permission to (un)lock audio focus", new Exception());
   5206                     return AudioManager.AUDIOFOCUS_REQUEST_FAILED;
   5207                 }
   5208             } else {
   5209                 // only a registered audio policy can be used to lock focus
   5210                 synchronized (mAudioPolicies) {
   5211                     if (!mAudioPolicies.containsKey(pcb.asBinder())) {
   5212                         Log.e(TAG, "Invalid unregistered AudioPolicy to (un)lock audio focus");
   5213                         return AudioManager.AUDIOFOCUS_REQUEST_FAILED;
   5214                     }
   5215                 }
   5216             }
   5217         }
   5218 
   5219         return mMediaFocusControl.requestAudioFocus(aa, durationHint, cb, fd,
   5220                 clientId, callingPackageName, flags);
   5221     }
   5222 
   5223     public int abandonAudioFocus(IAudioFocusDispatcher fd, String clientId, AudioAttributes aa) {
   5224         return mMediaFocusControl.abandonAudioFocus(fd, clientId, aa);
   5225     }
   5226 
   5227     public void unregisterAudioFocusClient(String clientId) {
   5228         mMediaFocusControl.unregisterAudioFocusClient(clientId);
   5229     }
   5230 
   5231     public int getCurrentAudioFocus() {
   5232         return mMediaFocusControl.getCurrentAudioFocus();
   5233     }
   5234 
   5235     private boolean readCameraSoundForced() {
   5236         return SystemProperties.getBoolean("audio.camerasound.force", false) ||
   5237                 mContext.getResources().getBoolean(
   5238                         com.android.internal.R.bool.config_camera_sound_forced);
   5239     }
   5240 
   5241     //==========================================================================================
   5242     // Device orientation
   5243     //==========================================================================================
   5244     /**
   5245      * Handles device configuration changes that may map to a change in the orientation
   5246      * or orientation.
   5247      * Monitoring orientation and rotation is optional, and is defined by the definition and value
   5248      * of the "ro.audio.monitorOrientation" and "ro.audio.monitorRotation" system properties.
   5249      */
   5250     private void handleConfigurationChanged(Context context) {
   5251         try {
   5252             // reading new orientation "safely" (i.e. under try catch) in case anything
   5253             // goes wrong when obtaining resources and configuration
   5254             Configuration config = context.getResources().getConfiguration();
   5255             // TODO merge rotation and orientation
   5256             if (mMonitorOrientation) {
   5257                 int newOrientation = config.orientation;
   5258                 if (newOrientation != mDeviceOrientation) {
   5259                     mDeviceOrientation = newOrientation;
   5260                     setOrientationForAudioSystem();
   5261                 }
   5262             }
   5263             sendMsg(mAudioHandler,
   5264                     MSG_CONFIGURE_SAFE_MEDIA_VOLUME,
   5265                     SENDMSG_REPLACE,
   5266                     0,
   5267                     0,
   5268                     TAG,
   5269                     0);
   5270 
   5271             boolean cameraSoundForced = readCameraSoundForced();
   5272             synchronized (mSettingsLock) {
   5273                 boolean cameraSoundForcedChanged = false;
   5274                 synchronized (mCameraSoundForced) {
   5275                     if (cameraSoundForced != mCameraSoundForced) {
   5276                         mCameraSoundForced = cameraSoundForced;
   5277                         cameraSoundForcedChanged = true;
   5278                     }
   5279                 }
   5280                 if (cameraSoundForcedChanged) {
   5281                     if (!isPlatformTelevision()) {
   5282                         VolumeStreamState s = mStreamStates[AudioSystem.STREAM_SYSTEM_ENFORCED];
   5283                         if (cameraSoundForced) {
   5284                             s.setAllIndexesToMax();
   5285                             mRingerModeAffectedStreams &=
   5286                                     ~(1 << AudioSystem.STREAM_SYSTEM_ENFORCED);
   5287                         } else {
   5288                             s.setAllIndexes(mStreamStates[AudioSystem.STREAM_SYSTEM], TAG);
   5289                             mRingerModeAffectedStreams |=
   5290                                     (1 << AudioSystem.STREAM_SYSTEM_ENFORCED);
   5291                         }
   5292                         // take new state into account for streams muted by ringer mode
   5293                         setRingerModeInt(getRingerModeInternal(), false);
   5294                     }
   5295 
   5296                     sendMsg(mAudioHandler,
   5297                             MSG_SET_FORCE_USE,
   5298                             SENDMSG_QUEUE,
   5299                             AudioSystem.FOR_SYSTEM,
   5300                             cameraSoundForced ?
   5301                                     AudioSystem.FORCE_SYSTEM_ENFORCED : AudioSystem.FORCE_NONE,
   5302                             null,
   5303                             0);
   5304 
   5305                     sendMsg(mAudioHandler,
   5306                             MSG_SET_ALL_VOLUMES,
   5307                             SENDMSG_QUEUE,
   5308                             0,
   5309                             0,
   5310                             mStreamStates[AudioSystem.STREAM_SYSTEM_ENFORCED], 0);
   5311                 }
   5312             }
   5313             mVolumeController.setLayoutDirection(config.getLayoutDirection());
   5314         } catch (Exception e) {
   5315             Log.e(TAG, "Error handling configuration change: ", e);
   5316         }
   5317     }
   5318 
   5319     private void setOrientationForAudioSystem() {
   5320         switch (mDeviceOrientation) {
   5321             case Configuration.ORIENTATION_LANDSCAPE:
   5322                 //Log.i(TAG, "orientation is landscape");
   5323                 AudioSystem.setParameters("orientation=landscape");
   5324                 break;
   5325             case Configuration.ORIENTATION_PORTRAIT:
   5326                 //Log.i(TAG, "orientation is portrait");
   5327                 AudioSystem.setParameters("orientation=portrait");
   5328                 break;
   5329             case Configuration.ORIENTATION_SQUARE:
   5330                 //Log.i(TAG, "orientation is square");
   5331                 AudioSystem.setParameters("orientation=square");
   5332                 break;
   5333             case Configuration.ORIENTATION_UNDEFINED:
   5334                 //Log.i(TAG, "orientation is undefined");
   5335                 AudioSystem.setParameters("orientation=undefined");
   5336                 break;
   5337             default:
   5338                 Log.e(TAG, "Unknown orientation");
   5339         }
   5340     }
   5341 
   5342     private void setRotationForAudioSystem() {
   5343         switch (mDeviceRotation) {
   5344             case Surface.ROTATION_0:
   5345                 AudioSystem.setParameters("rotation=0");
   5346                 break;
   5347             case Surface.ROTATION_90:
   5348                 AudioSystem.setParameters("rotation=90");
   5349                 break;
   5350             case Surface.ROTATION_180:
   5351                 AudioSystem.setParameters("rotation=180");
   5352                 break;
   5353             case Surface.ROTATION_270:
   5354                 AudioSystem.setParameters("rotation=270");
   5355                 break;
   5356             default:
   5357                 Log.e(TAG, "Unknown device rotation");
   5358         }
   5359     }
   5360 
   5361 
   5362     // Handles request to override default use of A2DP for media.
   5363     // Must be called synchronized on mConnectedDevices
   5364     public void setBluetoothA2dpOnInt(boolean on) {
   5365         synchronized (mBluetoothA2dpEnabledLock) {
   5366             mBluetoothA2dpEnabled = on;
   5367             mAudioHandler.removeMessages(MSG_SET_FORCE_BT_A2DP_USE);
   5368             setForceUseInt_SyncDevices(AudioSystem.FOR_MEDIA,
   5369                     mBluetoothA2dpEnabled ? AudioSystem.FORCE_NONE : AudioSystem.FORCE_NO_BT_A2DP);
   5370         }
   5371     }
   5372 
   5373     // Must be called synchronized on mConnectedDevices
   5374     private void setForceUseInt_SyncDevices(int usage, int config) {
   5375         switch (usage) {
   5376             case AudioSystem.FOR_MEDIA:
   5377                 if (config == AudioSystem.FORCE_NO_BT_A2DP) {
   5378                     mBecomingNoisyIntentDevices &= ~AudioSystem.DEVICE_OUT_ALL_A2DP;
   5379                 } else { // config == AudioSystem.FORCE_NONE
   5380                     mBecomingNoisyIntentDevices |= AudioSystem.DEVICE_OUT_ALL_A2DP;
   5381                 }
   5382                 break;
   5383             case AudioSystem.FOR_DOCK:
   5384                 if (config == AudioSystem.FORCE_ANALOG_DOCK) {
   5385                     mBecomingNoisyIntentDevices |= AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET;
   5386                 } else { // config == AudioSystem.FORCE_NONE
   5387                     mBecomingNoisyIntentDevices &= ~AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET;
   5388                 }
   5389                 break;
   5390             default:
   5391                 // usage doesn't affect the broadcast of ACTION_AUDIO_BECOMING_NOISY
   5392         }
   5393         AudioSystem.setForceUse(usage, config);
   5394     }
   5395 
   5396     @Override
   5397     public void setRingtonePlayer(IRingtonePlayer player) {
   5398         mContext.enforceCallingOrSelfPermission(REMOTE_AUDIO_PLAYBACK, null);
   5399         mRingtonePlayer = player;
   5400     }
   5401 
   5402     @Override
   5403     public IRingtonePlayer getRingtonePlayer() {
   5404         return mRingtonePlayer;
   5405     }
   5406 
   5407     @Override
   5408     public AudioRoutesInfo startWatchingRoutes(IAudioRoutesObserver observer) {
   5409         synchronized (mCurAudioRoutes) {
   5410             AudioRoutesInfo routes = new AudioRoutesInfo(mCurAudioRoutes);
   5411             mRoutesObservers.register(observer);
   5412             return routes;
   5413         }
   5414     }
   5415 
   5416 
   5417     //==========================================================================================
   5418     // Safe media volume management.
   5419     // MUSIC stream volume level is limited when headphones are connected according to safety
   5420     // regulation. When the user attempts to raise the volume above the limit, a warning is
   5421     // displayed and the user has to acknowlegde before the volume is actually changed.
   5422     // The volume index corresponding to the limit is stored in config_safe_media_volume_index
   5423     // property. Platforms with a different limit must set this property accordingly in their
   5424     // overlay.
   5425     //==========================================================================================
   5426 
   5427     // mSafeMediaVolumeState indicates whether the media volume is limited over headphones.
   5428     // It is SAFE_MEDIA_VOLUME_NOT_CONFIGURED at boot time until a network service is connected
   5429     // or the configure time is elapsed. It is then set to SAFE_MEDIA_VOLUME_ACTIVE or
   5430     // SAFE_MEDIA_VOLUME_DISABLED according to country option. If not SAFE_MEDIA_VOLUME_DISABLED, it
   5431     // can be set to SAFE_MEDIA_VOLUME_INACTIVE by calling AudioService.disableSafeMediaVolume()
   5432     // (when user opts out).
   5433     private static final int SAFE_MEDIA_VOLUME_NOT_CONFIGURED = 0;
   5434     private static final int SAFE_MEDIA_VOLUME_DISABLED = 1;
   5435     private static final int SAFE_MEDIA_VOLUME_INACTIVE = 2;  // confirmed
   5436     private static final int SAFE_MEDIA_VOLUME_ACTIVE = 3;  // unconfirmed
   5437     private Integer mSafeMediaVolumeState;
   5438 
   5439     private int mMcc = 0;
   5440     // mSafeMediaVolumeIndex is the cached value of config_safe_media_volume_index property
   5441     private int mSafeMediaVolumeIndex;
   5442     // mSafeMediaVolumeDevices lists the devices for which safe media volume is enforced,
   5443     private final int mSafeMediaVolumeDevices = AudioSystem.DEVICE_OUT_WIRED_HEADSET |
   5444                                                 AudioSystem.DEVICE_OUT_WIRED_HEADPHONE;
   5445     // mMusicActiveMs is the cumulative time of music activity since safe volume was disabled.
   5446     // When this time reaches UNSAFE_VOLUME_MUSIC_ACTIVE_MS_MAX, the safe media volume is re-enabled
   5447     // automatically. mMusicActiveMs is rounded to a multiple of MUSIC_ACTIVE_POLL_PERIOD_MS.
   5448     private int mMusicActiveMs;
   5449     private static final int UNSAFE_VOLUME_MUSIC_ACTIVE_MS_MAX = (20 * 3600 * 1000); // 20 hours
   5450     private static final int MUSIC_ACTIVE_POLL_PERIOD_MS = 60000;  // 1 minute polling interval
   5451     private static final int SAFE_VOLUME_CONFIGURE_TIMEOUT_MS = 30000;  // 30s after boot completed
   5452 
   5453     private void setSafeMediaVolumeEnabled(boolean on, String caller) {
   5454         synchronized (mSafeMediaVolumeState) {
   5455             if ((mSafeMediaVolumeState != SAFE_MEDIA_VOLUME_NOT_CONFIGURED) &&
   5456                     (mSafeMediaVolumeState != SAFE_MEDIA_VOLUME_DISABLED)) {
   5457                 if (on && (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_INACTIVE)) {
   5458                     mSafeMediaVolumeState = SAFE_MEDIA_VOLUME_ACTIVE;
   5459                     enforceSafeMediaVolume(caller);
   5460                 } else if (!on && (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_ACTIVE)) {
   5461                     mSafeMediaVolumeState = SAFE_MEDIA_VOLUME_INACTIVE;
   5462                     mMusicActiveMs = 1;  // nonzero = confirmed
   5463                     saveMusicActiveMs();
   5464                     sendMsg(mAudioHandler,
   5465                             MSG_CHECK_MUSIC_ACTIVE,
   5466                             SENDMSG_REPLACE,
   5467                             0,
   5468                             0,
   5469                             caller,
   5470                             MUSIC_ACTIVE_POLL_PERIOD_MS);
   5471                 }
   5472             }
   5473         }
   5474     }
   5475 
   5476     private void enforceSafeMediaVolume(String caller) {
   5477         VolumeStreamState streamState = mStreamStates[AudioSystem.STREAM_MUSIC];
   5478         int devices = mSafeMediaVolumeDevices;
   5479         int i = 0;
   5480 
   5481         while (devices != 0) {
   5482             int device = 1 << i++;
   5483             if ((device & devices) == 0) {
   5484                 continue;
   5485             }
   5486             int index = streamState.getIndex(device);
   5487             if (index > mSafeMediaVolumeIndex) {
   5488                 streamState.setIndex(mSafeMediaVolumeIndex, device, caller);
   5489                 sendMsg(mAudioHandler,
   5490                         MSG_SET_DEVICE_VOLUME,
   5491                         SENDMSG_QUEUE,
   5492                         device,
   5493                         0,
   5494                         streamState,
   5495                         0);
   5496             }
   5497             devices &= ~device;
   5498         }
   5499     }
   5500 
   5501     private boolean checkSafeMediaVolume(int streamType, int index, int device) {
   5502         synchronized (mSafeMediaVolumeState) {
   5503             if ((mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_ACTIVE) &&
   5504                     (mStreamVolumeAlias[streamType] == AudioSystem.STREAM_MUSIC) &&
   5505                     ((device & mSafeMediaVolumeDevices) != 0) &&
   5506                     (index > mSafeMediaVolumeIndex)) {
   5507                 return false;
   5508             }
   5509             return true;
   5510         }
   5511     }
   5512 
   5513     @Override
   5514     public void disableSafeMediaVolume(String callingPackage) {
   5515         enforceVolumeController("disable the safe media volume");
   5516         synchronized (mSafeMediaVolumeState) {
   5517             setSafeMediaVolumeEnabled(false, callingPackage);
   5518             if (mPendingVolumeCommand != null) {
   5519                 onSetStreamVolume(mPendingVolumeCommand.mStreamType,
   5520                                   mPendingVolumeCommand.mIndex,
   5521                                   mPendingVolumeCommand.mFlags,
   5522                                   mPendingVolumeCommand.mDevice,
   5523                                   callingPackage);
   5524                 mPendingVolumeCommand = null;
   5525             }
   5526         }
   5527     }
   5528 
   5529     //==========================================================================================
   5530     // Hdmi Cec system audio mode.
   5531     // If Hdmi Cec's system audio mode is on, audio service should send the volume change
   5532     // to HdmiControlService so that the audio receiver can handle it.
   5533     //==========================================================================================
   5534 
   5535     private class MyDisplayStatusCallback implements HdmiPlaybackClient.DisplayStatusCallback {
   5536         public void onComplete(int status) {
   5537             if (mHdmiManager != null) {
   5538                 synchronized (mHdmiManager) {
   5539                     mHdmiCecSink = (status != HdmiControlManager.POWER_STATUS_UNKNOWN);
   5540                     // Television devices without CEC service apply software volume on HDMI output
   5541                     if (isPlatformTelevision() && !mHdmiCecSink) {
   5542                         mFixedVolumeDevices &= ~AudioSystem.DEVICE_OUT_HDMI;
   5543                     }
   5544                     checkAllFixedVolumeDevices();
   5545                 }
   5546             }
   5547         }
   5548     };
   5549 
   5550     // If HDMI-CEC system audio is supported
   5551     private boolean mHdmiSystemAudioSupported = false;
   5552     // Set only when device is tv.
   5553     private HdmiTvClient mHdmiTvClient;
   5554     // true if the device has system feature PackageManager.FEATURE_LEANBACK.
   5555     // cached HdmiControlManager interface
   5556     private HdmiControlManager mHdmiManager;
   5557     // Set only when device is a set-top box.
   5558     private HdmiPlaybackClient mHdmiPlaybackClient;
   5559     // true if we are a set-top box, an HDMI sink is connected and it supports CEC.
   5560     private boolean mHdmiCecSink;
   5561 
   5562     private MyDisplayStatusCallback mHdmiDisplayStatusCallback = new MyDisplayStatusCallback();
   5563 
   5564     @Override
   5565     public int setHdmiSystemAudioSupported(boolean on) {
   5566         int device = AudioSystem.DEVICE_NONE;
   5567         if (mHdmiManager != null) {
   5568             synchronized (mHdmiManager) {
   5569                 if (mHdmiTvClient == null) {
   5570                     Log.w(TAG, "Only Hdmi-Cec enabled TV device supports system audio mode.");
   5571                     return device;
   5572                 }
   5573 
   5574                 synchronized (mHdmiTvClient) {
   5575                     if (mHdmiSystemAudioSupported != on) {
   5576                         mHdmiSystemAudioSupported = on;
   5577                         AudioSystem.setForceUse(AudioSystem.FOR_HDMI_SYSTEM_AUDIO,
   5578                                 on ? AudioSystem.FORCE_HDMI_SYSTEM_AUDIO_ENFORCED :
   5579                                      AudioSystem.FORCE_NONE);
   5580                     }
   5581                     device = getDevicesForStream(AudioSystem.STREAM_MUSIC);
   5582                 }
   5583             }
   5584         }
   5585         return device;
   5586     }
   5587 
   5588     @Override
   5589     public boolean isHdmiSystemAudioSupported() {
   5590         return mHdmiSystemAudioSupported;
   5591     }
   5592 
   5593     //==========================================================================================
   5594     // Accessibility: taking touch exploration into account for selecting the default
   5595     //   stream override timeout when adjusting volume
   5596     //==========================================================================================
   5597     private static class StreamOverride
   5598             implements AccessibilityManager.TouchExplorationStateChangeListener {
   5599 
   5600         // AudioService.getActiveStreamType() will return:
   5601         // - STREAM_NOTIFICATION on tablets during this period after a notification stopped
   5602         // - STREAM_MUSIC on phones during this period after music or talkback/voice search prompt
   5603         // stopped
   5604         private static final int DEFAULT_STREAM_TYPE_OVERRIDE_DELAY_MS = 0;
   5605         private static final int TOUCH_EXPLORE_STREAM_TYPE_OVERRIDE_DELAY_MS = 1000;
   5606 
   5607         static int sDelayMs;
   5608 
   5609         static void init(Context ctxt) {
   5610             AccessibilityManager accessibilityManager =
   5611                     (AccessibilityManager) ctxt.getSystemService(Context.ACCESSIBILITY_SERVICE);
   5612             updateDefaultStreamOverrideDelay(
   5613                     accessibilityManager.isTouchExplorationEnabled());
   5614             accessibilityManager.addTouchExplorationStateChangeListener(
   5615                     new StreamOverride());
   5616         }
   5617 
   5618         @Override
   5619         public void onTouchExplorationStateChanged(boolean enabled) {
   5620             updateDefaultStreamOverrideDelay(enabled);
   5621         }
   5622 
   5623         private static void updateDefaultStreamOverrideDelay(boolean touchExploreEnabled) {
   5624             if (touchExploreEnabled) {
   5625                 sDelayMs = TOUCH_EXPLORE_STREAM_TYPE_OVERRIDE_DELAY_MS;
   5626             } else {
   5627                 sDelayMs = DEFAULT_STREAM_TYPE_OVERRIDE_DELAY_MS;
   5628             }
   5629             if (DEBUG_VOL) Log.d(TAG, "Touch exploration enabled=" + touchExploreEnabled
   5630                     + " stream override delay is now " + sDelayMs + " ms");
   5631         }
   5632     }
   5633 
   5634     //==========================================================================================
   5635     // Camera shutter sound policy.
   5636     // config_camera_sound_forced configuration option in config.xml defines if the camera shutter
   5637     // sound is forced (sound even if the device is in silent mode) or not. This option is false by
   5638     // default and can be overridden by country specific overlay in values-mccXXX/config.xml.
   5639     //==========================================================================================
   5640 
   5641     // cached value of com.android.internal.R.bool.config_camera_sound_forced
   5642     private Boolean mCameraSoundForced;
   5643 
   5644     // called by android.hardware.Camera to populate CameraInfo.canDisableShutterSound
   5645     public boolean isCameraSoundForced() {
   5646         synchronized (mCameraSoundForced) {
   5647             return mCameraSoundForced;
   5648         }
   5649     }
   5650 
   5651     private static final String[] RINGER_MODE_NAMES = new String[] {
   5652             "SILENT",
   5653             "VIBRATE",
   5654             "NORMAL"
   5655     };
   5656 
   5657     private void dumpRingerMode(PrintWriter pw) {
   5658         pw.println("\nRinger mode: ");
   5659         pw.println("- mode (internal) = " + RINGER_MODE_NAMES[mRingerMode]);
   5660         pw.println("- mode (external) = " + RINGER_MODE_NAMES[mRingerModeExternal]);
   5661         dumpRingerModeStreams(pw, "affected", mRingerModeAffectedStreams);
   5662         dumpRingerModeStreams(pw, "muted", mRingerModeMutedStreams);
   5663         pw.print("- delegate = "); pw.println(mRingerModeDelegate);
   5664     }
   5665 
   5666     private void dumpRingerModeStreams(PrintWriter pw, String type, int streams) {
   5667         pw.print("- ringer mode "); pw.print(type); pw.print(" streams = 0x");
   5668         pw.print(Integer.toHexString(streams));
   5669         if (streams != 0) {
   5670             pw.print(" (");
   5671             boolean first = true;
   5672             for (int i = 0; i < AudioSystem.STREAM_NAMES.length; i++) {
   5673                 final int stream = (1 << i);
   5674                 if ((streams & stream) != 0) {
   5675                     if (!first) pw.print(',');
   5676                     pw.print(AudioSystem.STREAM_NAMES[i]);
   5677                     streams &= ~stream;
   5678                     first = false;
   5679                 }
   5680             }
   5681             if (streams != 0) {
   5682                 if (!first) pw.print(',');
   5683                 pw.print(streams);
   5684             }
   5685             pw.print(')');
   5686         }
   5687         pw.println();
   5688     }
   5689 
   5690     @Override
   5691     protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
   5692         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DUMP, TAG);
   5693 
   5694         mMediaFocusControl.dump(pw);
   5695         dumpStreamStates(pw);
   5696         dumpRingerMode(pw);
   5697         pw.println("\nAudio routes:");
   5698         pw.print("  mMainType=0x"); pw.println(Integer.toHexString(mCurAudioRoutes.mainType));
   5699         pw.print("  mBluetoothName="); pw.println(mCurAudioRoutes.bluetoothName);
   5700 
   5701         pw.println("\nOther state:");
   5702         pw.print("  mVolumeController="); pw.println(mVolumeController);
   5703         pw.print("  mSafeMediaVolumeState=");
   5704         pw.println(safeMediaVolumeStateToString(mSafeMediaVolumeState));
   5705         pw.print("  mSafeMediaVolumeIndex="); pw.println(mSafeMediaVolumeIndex);
   5706         pw.print("  mPendingVolumeCommand="); pw.println(mPendingVolumeCommand);
   5707         pw.print("  mMusicActiveMs="); pw.println(mMusicActiveMs);
   5708         pw.print("  mMcc="); pw.println(mMcc);
   5709         pw.print("  mCameraSoundForced="); pw.println(mCameraSoundForced);
   5710         pw.print("  mHasVibrator="); pw.println(mHasVibrator);
   5711         pw.print("  mControllerService="); pw.println(mControllerService);
   5712         pw.print("  mVolumePolicy="); pw.println(mVolumePolicy);
   5713 
   5714         dumpAudioPolicies(pw);
   5715     }
   5716 
   5717     private static String safeMediaVolumeStateToString(Integer state) {
   5718         switch(state) {
   5719             case SAFE_MEDIA_VOLUME_NOT_CONFIGURED: return "SAFE_MEDIA_VOLUME_NOT_CONFIGURED";
   5720             case SAFE_MEDIA_VOLUME_DISABLED: return "SAFE_MEDIA_VOLUME_DISABLED";
   5721             case SAFE_MEDIA_VOLUME_INACTIVE: return "SAFE_MEDIA_VOLUME_INACTIVE";
   5722             case SAFE_MEDIA_VOLUME_ACTIVE: return "SAFE_MEDIA_VOLUME_ACTIVE";
   5723         }
   5724         return null;
   5725     }
   5726 
   5727     // Inform AudioFlinger of our device's low RAM attribute
   5728     private static void readAndSetLowRamDevice()
   5729     {
   5730         int status = AudioSystem.setLowRamDevice(ActivityManager.isLowRamDeviceStatic());
   5731         if (status != 0) {
   5732             Log.w(TAG, "AudioFlinger informed of device's low RAM attribute; status " + status);
   5733         }
   5734     }
   5735 
   5736     private void enforceVolumeController(String action) {
   5737         if (mControllerService.mUid != 0 && Binder.getCallingUid() == mControllerService.mUid) {
   5738             return;
   5739         }
   5740         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.STATUS_BAR_SERVICE,
   5741                 "Only SystemUI can " + action);
   5742     }
   5743 
   5744     @Override
   5745     public void setVolumeController(final IVolumeController controller) {
   5746         enforceVolumeController("set the volume controller");
   5747 
   5748         // return early if things are not actually changing
   5749         if (mVolumeController.isSameBinder(controller)) {
   5750             return;
   5751         }
   5752 
   5753         // dismiss the old volume controller
   5754         mVolumeController.postDismiss();
   5755         if (controller != null) {
   5756             // we are about to register a new controller, listen for its death
   5757             try {
   5758                 controller.asBinder().linkToDeath(new DeathRecipient() {
   5759                     @Override
   5760                     public void binderDied() {
   5761                         if (mVolumeController.isSameBinder(controller)) {
   5762                             Log.w(TAG, "Current remote volume controller died, unregistering");
   5763                             setVolumeController(null);
   5764                         }
   5765                     }
   5766                 }, 0);
   5767             } catch (RemoteException e) {
   5768                 // noop
   5769             }
   5770         }
   5771         mVolumeController.setController(controller);
   5772         if (DEBUG_VOL) Log.d(TAG, "Volume controller: " + mVolumeController);
   5773     }
   5774 
   5775     @Override
   5776     public void notifyVolumeControllerVisible(final IVolumeController controller, boolean visible) {
   5777         enforceVolumeController("notify about volume controller visibility");
   5778 
   5779         // return early if the controller is not current
   5780         if (!mVolumeController.isSameBinder(controller)) {
   5781             return;
   5782         }
   5783 
   5784         mVolumeController.setVisible(visible);
   5785         if (DEBUG_VOL) Log.d(TAG, "Volume controller visible: " + visible);
   5786     }
   5787 
   5788     @Override
   5789     public void setVolumePolicy(VolumePolicy policy) {
   5790         enforceVolumeController("set volume policy");
   5791         if (policy != null && !policy.equals(mVolumePolicy)) {
   5792             mVolumePolicy = policy;
   5793             if (DEBUG_VOL) Log.d(TAG, "Volume policy changed: " + mVolumePolicy);
   5794         }
   5795     }
   5796 
   5797     public static class VolumeController {
   5798         private static final String TAG = "VolumeController";
   5799 
   5800         private IVolumeController mController;
   5801         private boolean mVisible;
   5802         private long mNextLongPress;
   5803         private int mLongPressTimeout;
   5804 
   5805         public void setController(IVolumeController controller) {
   5806             mController = controller;
   5807             mVisible = false;
   5808         }
   5809 
   5810         public void loadSettings(ContentResolver cr) {
   5811             mLongPressTimeout = Settings.Secure.getIntForUser(cr,
   5812                     Settings.Secure.LONG_PRESS_TIMEOUT, 500, UserHandle.USER_CURRENT);
   5813         }
   5814 
   5815         public boolean suppressAdjustment(int resolvedStream, int flags, boolean isMute) {
   5816             if (isMute) {
   5817                 return false;
   5818             }
   5819             boolean suppress = false;
   5820             if (resolvedStream == AudioSystem.STREAM_RING && mController != null) {
   5821                 final long now = SystemClock.uptimeMillis();
   5822                 if ((flags & AudioManager.FLAG_SHOW_UI) != 0 && !mVisible) {
   5823                     // ui will become visible
   5824                     if (mNextLongPress < now) {
   5825                         mNextLongPress = now + mLongPressTimeout;
   5826                     }
   5827                     suppress = true;
   5828                 } else if (mNextLongPress > 0) {  // in a long-press
   5829                     if (now > mNextLongPress) {
   5830                         // long press triggered, no more suppression
   5831                         mNextLongPress = 0;
   5832                     } else {
   5833                         // keep suppressing until the long press triggers
   5834                         suppress = true;
   5835                     }
   5836                 }
   5837             }
   5838             return suppress;
   5839         }
   5840 
   5841         public void setVisible(boolean visible) {
   5842             mVisible = visible;
   5843         }
   5844 
   5845         public boolean isSameBinder(IVolumeController controller) {
   5846             return Objects.equals(asBinder(), binder(controller));
   5847         }
   5848 
   5849         public IBinder asBinder() {
   5850             return binder(mController);
   5851         }
   5852 
   5853         private static IBinder binder(IVolumeController controller) {
   5854             return controller == null ? null : controller.asBinder();
   5855         }
   5856 
   5857         @Override
   5858         public String toString() {
   5859             return "VolumeController(" + asBinder() + ",mVisible=" + mVisible + ")";
   5860         }
   5861 
   5862         public void postDisplaySafeVolumeWarning(int flags) {
   5863             if (mController == null)
   5864                 return;
   5865             try {
   5866                 mController.displaySafeVolumeWarning(flags);
   5867             } catch (RemoteException e) {
   5868                 Log.w(TAG, "Error calling displaySafeVolumeWarning", e);
   5869             }
   5870         }
   5871 
   5872         public void postVolumeChanged(int streamType, int flags) {
   5873             if (mController == null)
   5874                 return;
   5875             try {
   5876                 mController.volumeChanged(streamType, flags);
   5877             } catch (RemoteException e) {
   5878                 Log.w(TAG, "Error calling volumeChanged", e);
   5879             }
   5880         }
   5881 
   5882         public void postMasterMuteChanged(int flags) {
   5883             if (mController == null)
   5884                 return;
   5885             try {
   5886                 mController.masterMuteChanged(flags);
   5887             } catch (RemoteException e) {
   5888                 Log.w(TAG, "Error calling masterMuteChanged", e);
   5889             }
   5890         }
   5891 
   5892         public void setLayoutDirection(int layoutDirection) {
   5893             if (mController == null)
   5894                 return;
   5895             try {
   5896                 mController.setLayoutDirection(layoutDirection);
   5897             } catch (RemoteException e) {
   5898                 Log.w(TAG, "Error calling setLayoutDirection", e);
   5899             }
   5900         }
   5901 
   5902         public void postDismiss() {
   5903             if (mController == null)
   5904                 return;
   5905             try {
   5906                 mController.dismiss();
   5907             } catch (RemoteException e) {
   5908                 Log.w(TAG, "Error calling dismiss", e);
   5909             }
   5910         }
   5911     }
   5912 
   5913     /**
   5914      * Interface for system components to get some extra functionality through
   5915      * LocalServices.
   5916      */
   5917     final class AudioServiceInternal extends AudioManagerInternal {
   5918         @Override
   5919         public void setRingerModeDelegate(RingerModeDelegate delegate) {
   5920             mRingerModeDelegate = delegate;
   5921             if (mRingerModeDelegate != null) {
   5922                 updateRingerModeAffectedStreams();
   5923                 setRingerModeInternal(getRingerModeInternal(), TAG + ".setRingerModeDelegate");
   5924             }
   5925         }
   5926 
   5927         @Override
   5928         public void adjustSuggestedStreamVolumeForUid(int streamType, int direction, int flags,
   5929                 String callingPackage, int uid) {
   5930             // direction and stream type swap here because the public
   5931             // adjustSuggested has a different order than the other methods.
   5932             adjustSuggestedStreamVolume(direction, streamType, flags, callingPackage,
   5933                     callingPackage, uid);
   5934         }
   5935 
   5936         @Override
   5937         public void adjustStreamVolumeForUid(int streamType, int direction, int flags,
   5938                 String callingPackage, int uid) {
   5939             adjustStreamVolume(streamType, direction, flags, callingPackage,
   5940                     callingPackage, uid);
   5941         }
   5942 
   5943         @Override
   5944         public void setStreamVolumeForUid(int streamType, int direction, int flags,
   5945                 String callingPackage, int uid) {
   5946             setStreamVolume(streamType, direction, flags, callingPackage, callingPackage, uid);
   5947         }
   5948 
   5949         @Override
   5950         public int getRingerModeInternal() {
   5951             return AudioService.this.getRingerModeInternal();
   5952         }
   5953 
   5954         @Override
   5955         public void setRingerModeInternal(int ringerMode, String caller) {
   5956             AudioService.this.setRingerModeInternal(ringerMode, caller);
   5957         }
   5958 
   5959         @Override
   5960         public int getVolumeControllerUid() {
   5961             return mControllerService.mUid;
   5962         }
   5963 
   5964         @Override
   5965         public void updateRingerModeAffectedStreamsInternal() {
   5966             synchronized (mSettingsLock) {
   5967                 if (updateRingerModeAffectedStreams()) {
   5968                     setRingerModeInt(getRingerModeInternal(), false);
   5969                 }
   5970             }
   5971         }
   5972     }
   5973 
   5974     //==========================================================================================
   5975     // Audio policy management
   5976     //==========================================================================================
   5977     public String registerAudioPolicy(AudioPolicyConfig policyConfig, IAudioPolicyCallback pcb,
   5978             boolean hasFocusListener) {
   5979         AudioSystem.setDynamicPolicyCallback(mDynPolicyCallback);
   5980 
   5981         if (DEBUG_AP) Log.d(TAG, "registerAudioPolicy for " + pcb.asBinder()
   5982                 + " with config:" + policyConfig);
   5983         String regId = null;
   5984         // error handling
   5985         boolean hasPermissionForPolicy =
   5986                 (PackageManager.PERMISSION_GRANTED == mContext.checkCallingPermission(
   5987                         android.Manifest.permission.MODIFY_AUDIO_ROUTING));
   5988         if (!hasPermissionForPolicy) {
   5989             Slog.w(TAG, "Can't register audio policy for pid " + Binder.getCallingPid() + " / uid "
   5990                     + Binder.getCallingUid() + ", need MODIFY_AUDIO_ROUTING");
   5991             return null;
   5992         }
   5993 
   5994         synchronized (mAudioPolicies) {
   5995             try {
   5996                 if (mAudioPolicies.containsKey(pcb.asBinder())) {
   5997                     Slog.e(TAG, "Cannot re-register policy");
   5998                     return null;
   5999                 }
   6000                 AudioPolicyProxy app = new AudioPolicyProxy(policyConfig, pcb, hasFocusListener);
   6001                 pcb.asBinder().linkToDeath(app, 0/*flags*/);
   6002                 regId = app.getRegistrationId();
   6003                 mAudioPolicies.put(pcb.asBinder(), app);
   6004             } catch (RemoteException e) {
   6005                 // audio policy owner has already died!
   6006                 Slog.w(TAG, "Audio policy registration failed, could not link to " + pcb +
   6007                         " binder death", e);
   6008                 return null;
   6009             }
   6010         }
   6011         return regId;
   6012     }
   6013 
   6014     public void unregisterAudioPolicyAsync(IAudioPolicyCallback pcb) {
   6015         if (DEBUG_AP) Log.d(TAG, "unregisterAudioPolicyAsync for " + pcb.asBinder());
   6016         synchronized (mAudioPolicies) {
   6017             AudioPolicyProxy app = mAudioPolicies.remove(pcb.asBinder());
   6018             if (app == null) {
   6019                 Slog.w(TAG, "Trying to unregister unknown audio policy for pid "
   6020                         + Binder.getCallingPid() + " / uid " + Binder.getCallingUid());
   6021                 return;
   6022             } else {
   6023                 pcb.asBinder().unlinkToDeath(app, 0/*flags*/);
   6024             }
   6025             app.release();
   6026         }
   6027         // TODO implement clearing mix attribute matching info in native audio policy
   6028     }
   6029 
   6030     public int setFocusPropertiesForPolicy(int duckingBehavior, IAudioPolicyCallback pcb) {
   6031         if (DEBUG_AP) Log.d(TAG, "setFocusPropertiesForPolicy() duck behavior=" + duckingBehavior
   6032                 + " policy " +  pcb.asBinder());
   6033         // error handling
   6034         boolean hasPermissionForPolicy =
   6035                 (PackageManager.PERMISSION_GRANTED == mContext.checkCallingPermission(
   6036                         android.Manifest.permission.MODIFY_AUDIO_ROUTING));
   6037         if (!hasPermissionForPolicy) {
   6038             Slog.w(TAG, "Cannot change audio policy ducking handling for pid " +
   6039                     + Binder.getCallingPid() + " / uid "
   6040                     + Binder.getCallingUid() + ", need MODIFY_AUDIO_ROUTING");
   6041             return AudioManager.ERROR;
   6042         }
   6043 
   6044         synchronized (mAudioPolicies) {
   6045             if (!mAudioPolicies.containsKey(pcb.asBinder())) {
   6046                 Slog.e(TAG, "Cannot change audio policy focus properties, unregistered policy");
   6047                 return AudioManager.ERROR;
   6048             }
   6049             final AudioPolicyProxy app = mAudioPolicies.get(pcb.asBinder());
   6050             if (duckingBehavior == AudioPolicy.FOCUS_POLICY_DUCKING_IN_POLICY) {
   6051                 // is there already one policy managing ducking?
   6052                 for (AudioPolicyProxy policy : mAudioPolicies.values()) {
   6053                     if (policy.mFocusDuckBehavior == AudioPolicy.FOCUS_POLICY_DUCKING_IN_POLICY) {
   6054                         Slog.e(TAG, "Cannot change audio policy ducking behavior, already handled");
   6055                         return AudioManager.ERROR;
   6056                     }
   6057                 }
   6058             }
   6059             app.mFocusDuckBehavior = duckingBehavior;
   6060             mMediaFocusControl.setDuckingInExtPolicyAvailable(
   6061                     duckingBehavior == AudioPolicy.FOCUS_POLICY_DUCKING_IN_POLICY);
   6062         }
   6063         return AudioManager.SUCCESS;
   6064     }
   6065 
   6066     private void dumpAudioPolicies(PrintWriter pw) {
   6067         pw.println("\nAudio policies:");
   6068         synchronized (mAudioPolicies) {
   6069             for (AudioPolicyProxy policy : mAudioPolicies.values()) {
   6070                 pw.println(policy.toLogFriendlyString());
   6071             }
   6072         }
   6073     }
   6074 
   6075     //======================
   6076     // Audio policy callback from AudioSystem
   6077     //======================
   6078     private final AudioSystem.DynamicPolicyCallback mDynPolicyCallback =
   6079             new AudioSystem.DynamicPolicyCallback() {
   6080         public void onDynamicPolicyMixStateUpdate(String regId, int state) {
   6081             if (!TextUtils.isEmpty(regId)) {
   6082                 sendMsg(mAudioHandler, MSG_DYN_POLICY_MIX_STATE_UPDATE, SENDMSG_QUEUE,
   6083                         state /*arg1*/, 0 /*arg2 ignored*/, regId /*obj*/, 0 /*delay*/);
   6084             }
   6085         }
   6086     };
   6087 
   6088     private void onDynPolicyMixStateUpdate(String regId, int state) {
   6089         if (DEBUG_AP) Log.d(TAG, "onDynamicPolicyMixStateUpdate("+ regId + ", " + state +")");
   6090         synchronized (mAudioPolicies) {
   6091             for (AudioPolicyProxy policy : mAudioPolicies.values()) {
   6092                 for (AudioMix mix : policy.getMixes()) {
   6093                     if (mix.getRegistration().equals(regId)) {
   6094                         try {
   6095                             policy.mPolicyCallback.notifyMixStateUpdate(regId, state);
   6096                         } catch (RemoteException e) {
   6097                             Log.e(TAG, "Can't call notifyMixStateUpdate() on IAudioPolicyCallback "
   6098                                     + policy.mPolicyCallback.asBinder(), e);
   6099                         }
   6100                         return;
   6101                     }
   6102                 }
   6103             }
   6104         }
   6105 
   6106     }
   6107 
   6108     //======================
   6109     // Audio policy proxy
   6110     //======================
   6111     /**
   6112      * This internal class inherits from AudioPolicyConfig, each instance contains all the
   6113      * mixes of an AudioPolicy and their configurations.
   6114      */
   6115     public class AudioPolicyProxy extends AudioPolicyConfig implements IBinder.DeathRecipient {
   6116         private static final String TAG = "AudioPolicyProxy";
   6117         IAudioPolicyCallback mPolicyCallback;
   6118         boolean mHasFocusListener;
   6119         /**
   6120          * Audio focus ducking behavior for an audio policy.
   6121          * This variable reflects the value that was successfully set in
   6122          * {@link AudioService#setFocusPropertiesForPolicy(int, IAudioPolicyCallback)}. This
   6123          * implies that a value of FOCUS_POLICY_DUCKING_IN_POLICY means the corresponding policy
   6124          * is handling ducking for audio focus.
   6125          */
   6126         int mFocusDuckBehavior = AudioPolicy.FOCUS_POLICY_DUCKING_DEFAULT;
   6127 
   6128         AudioPolicyProxy(AudioPolicyConfig config, IAudioPolicyCallback token,
   6129                 boolean hasFocusListener) {
   6130             super(config);
   6131             setRegistration(new String(config.hashCode() + ":ap:" + mAudioPolicyCounter++));
   6132             mPolicyCallback = token;
   6133             mHasFocusListener = hasFocusListener;
   6134             if (mHasFocusListener) {
   6135                 mMediaFocusControl.addFocusFollower(mPolicyCallback);
   6136             }
   6137             connectMixes();
   6138         }
   6139 
   6140         public void binderDied() {
   6141             synchronized (mAudioPolicies) {
   6142                 Log.i(TAG, "audio policy " + mPolicyCallback + " died");
   6143                 release();
   6144                 mAudioPolicies.remove(mPolicyCallback.asBinder());
   6145             }
   6146         }
   6147 
   6148         String getRegistrationId() {
   6149             return getRegistration();
   6150         }
   6151 
   6152         void release() {
   6153             if (mFocusDuckBehavior == AudioPolicy.FOCUS_POLICY_DUCKING_IN_POLICY) {
   6154                 mMediaFocusControl.setDuckingInExtPolicyAvailable(false);
   6155             }
   6156             if (mHasFocusListener) {
   6157                 mMediaFocusControl.removeFocusFollower(mPolicyCallback);
   6158             }
   6159             AudioSystem.registerPolicyMixes(mMixes, false);
   6160         }
   6161 
   6162         void connectMixes() {
   6163             AudioSystem.registerPolicyMixes(mMixes, true);
   6164         }
   6165     };
   6166 
   6167     private HashMap<IBinder, AudioPolicyProxy> mAudioPolicies =
   6168             new HashMap<IBinder, AudioPolicyProxy>();
   6169     private int mAudioPolicyCounter = 0; // always accessed synchronized on mAudioPolicies
   6170 
   6171     private class ControllerService extends ContentObserver {
   6172         private int mUid;
   6173         private ComponentName mComponent;
   6174 
   6175         public ControllerService() {
   6176             super(null);
   6177         }
   6178 
   6179         @Override
   6180         public String toString() {
   6181             return String.format("{mUid=%d,mComponent=%s}", mUid, mComponent);
   6182         }
   6183 
   6184         public void init() {
   6185             onChange(true);
   6186             mContentResolver.registerContentObserver(Settings.Secure.getUriFor(
   6187                     Settings.Secure.VOLUME_CONTROLLER_SERVICE_COMPONENT), false, this);
   6188         }
   6189 
   6190         @Override
   6191         public void onChange(boolean selfChange) {
   6192             mUid = 0;
   6193             mComponent = null;
   6194             final String setting = Settings.Secure.getString(mContentResolver,
   6195                     Settings.Secure.VOLUME_CONTROLLER_SERVICE_COMPONENT);
   6196             if (setting == null) return;
   6197             try {
   6198                 mComponent = ComponentName.unflattenFromString(setting);
   6199                 if (mComponent == null) return;
   6200                 mUid = mContext.getPackageManager()
   6201                         .getApplicationInfo(mComponent.getPackageName(), 0).uid;
   6202             } catch (Exception e) {
   6203                 Log.w(TAG, "Error loading controller service", e);
   6204             }
   6205             if (DEBUG_VOL) Log.d(TAG, "Reloaded controller service: " + this);
   6206         }
   6207     }
   6208 }
   6209