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