AudioService.java revision fb917e019f04d60f4924114fe2684c0d67981af6
19066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/*
29066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Copyright (C) 2006 The Android Open Source Project
39066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
49066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License");
59066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * you may not use this file except in compliance with the License.
69066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * You may obtain a copy of the License at
79066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
89066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *      http://www.apache.org/licenses/LICENSE-2.0
99066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Unless required by applicable law or agreed to in writing, software
119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS,
129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * See the License for the specific language governing permissions and
149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * limitations under the License.
159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */
169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectpackage android.media;
189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
19098d580cc2bb6c0891c756a4e5230c6c6b0d2376Jeff Sharkeyimport static android.Manifest.permission.REMOTE_AUDIO_PLAYBACK;
20c696a53d1fe4d61373c5dc64dd057d322da90c8fAmith Yamasaniimport static android.media.AudioManager.RINGER_MODE_NORMAL;
21c696a53d1fe4d61373c5dc64dd057d322da90c8fAmith Yamasaniimport static android.media.AudioManager.RINGER_MODE_SILENT;
22c696a53d1fe4d61373c5dc64dd057d322da90c8fAmith Yamasaniimport static android.media.AudioManager.RINGER_MODE_VIBRATE;
23c696a53d1fe4d61373c5dc64dd057d322da90c8fAmith Yamasani
24fd116ad1ab02f6060a0b2201f018317fa32e28b4Glenn Kastenimport android.app.ActivityManager;
259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.app.ActivityManagerNative;
26ba50b97cff80e73620a0e3d13cae169e095974a7Dianne Hackbornimport android.app.AppOpsManager;
276243edd818b84adfbe712d5d233d6414b33653acAmith Yamasaniimport android.app.KeyguardManager;
28f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Triviimport android.app.PendingIntent;
2982aa7f017daaaeb96c13e6e3491d5037ab471085Jaikumar Ganeshimport android.bluetooth.BluetoothA2dp;
3082aa7f017daaaeb96c13e6e3491d5037ab471085Jaikumar Ganeshimport android.bluetooth.BluetoothAdapter;
3182aa7f017daaaeb96c13e6e3491d5037ab471085Jaikumar Ganeshimport android.bluetooth.BluetoothClass;
3282aa7f017daaaeb96c13e6e3491d5037ab471085Jaikumar Ganeshimport android.bluetooth.BluetoothDevice;
3382aa7f017daaaeb96c13e6e3491d5037ab471085Jaikumar Ganeshimport android.bluetooth.BluetoothHeadset;
3482aa7f017daaaeb96c13e6e3491d5037ab471085Jaikumar Ganeshimport android.bluetooth.BluetoothProfile;
35bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pellyimport android.content.BroadcastReceiver;
36d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Triviimport android.content.ComponentName;
379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.ContentResolver;
389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.Context;
399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.Intent;
40a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurentimport android.content.IntentFilter;
419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.pm.PackageManager;
42f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Triviimport android.content.res.Configuration;
43e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurentimport android.content.res.Resources;
44e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurentimport android.content.res.XmlResourceParser;
45b109615ebebd6f3b9ae789412279f576c3ace46bJason Parekhimport android.database.ContentObserver;
46c837a451946b64d70ed7c642fbde03c182c28b6fPaul McLeanimport android.hardware.usb.UsbManager;
479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.media.MediaPlayer.OnCompletionListener;
489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.media.MediaPlayer.OnErrorListener;
498a2cfc309ab9126e90022916967c65a793c034f0RoboErikimport android.media.session.MediaSessionLegacyHelper;
509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.Binder;
51c18c9138cee0f0859bcab636a004ce92ca4a9ab5Eric Laurentimport android.os.Build;
529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.Environment;
539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.Handler;
549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.IBinder;
559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.Looper;
569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.Message;
57c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Triviimport android.os.PowerManager;
58632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackbornimport android.os.RemoteCallbackList;
599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.RemoteException;
609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.ServiceManager;
6182aa7f017daaaeb96c13e6e3491d5037ab471085Jaikumar Ganeshimport android.os.SystemProperties;
625ac72a29593ab9a20337a2225df52bdf4754be02Dianne Hackbornimport android.os.UserHandle;
63bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurentimport android.os.Vibrator;
649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.provider.Settings;
659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.provider.Settings.System;
66632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackbornimport android.text.TextUtils;
679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.util.Log;
68d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Triviimport android.view.KeyEvent;
69bb6f8711a7f804d39c45218db2d6339940cc5d35Jean-Michel Triviimport android.view.Surface;
70bb6f8711a7f804d39c45218db2d6339940cc5d35Jean-Michel Triviimport android.view.WindowManager;
719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport com.android.internal.telephony.ITelephony;
73e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurentimport com.android.internal.util.XmlUtils;
74e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent
75e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurentimport org.xmlpull.v1.XmlPullParserException;
769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
77d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Triviimport java.io.FileDescriptor;
789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.io.IOException;
79d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Triviimport java.io.PrintWriter;
80e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurentimport java.lang.reflect.Field;
819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.ArrayList;
823172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurentimport java.util.concurrent.ConcurrentHashMap;
83c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurentimport java.util.HashMap;
84c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurentimport java.util.Iterator;
855a1e4cf83f5be1b5d79e2643fa791aa269b6a4bcJaikumar Ganeshimport java.util.List;
86c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurentimport java.util.Map;
8782aa7f017daaaeb96c13e6e3491d5037ab471085Jaikumar Ganeshimport java.util.NoSuchElementException;
88d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErikimport java.util.Objects;
89c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurentimport java.util.Set;
909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/**
929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * The implementation of the volume manager service.
939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * <p>
949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * This implementation focuses on delivering a responsive UI. Most methods are
959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * asynchronous to external calls. For example, the task of setting a volume
969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * will update our internal state, but in a separate thread will set the system
979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * volume and later persist to the database. Similarly, setting the ringer mode
989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * will update the state and broadcast a change and in a separate thread later
999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * persist the ringer mode.
1009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
1019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @hide
1029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */
103fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivipublic class AudioService extends IAudioService.Stub {
1049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final String TAG = "AudioService";
1069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10718e7bce52318f00b5023f33933a571c477f2b61cJean-Michel Trivi    /** Debug remote control client/display feature */
1087ff866e8cf43afc64111e98863dab549b57447b4Jean-Michel Trivi    protected static final boolean DEBUG_RC = false;
1093114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    /** Debug volumes */
1103114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    protected static final boolean DEBUG_VOL = false;
11118e7bce52318f00b5023f33933a571c477f2b61cJean-Michel Trivi
112430fc48865e5a371b08f180390946b96d73848feRoboErik    /** debug calls to media session apis */
1138a2cfc309ab9126e90022916967c65a793c034f0RoboErik    private static final boolean DEBUG_SESSIONS = true;
1148a2cfc309ab9126e90022916967c65a793c034f0RoboErik
1158600534df66c2ff5846ed230b50c56229322d48aJohn Spurlock    /** Allow volume changes to set ringer mode to silent? */
1168600534df66c2ff5846ed230b50c56229322d48aJohn Spurlock    private static final boolean VOLUME_SETS_RINGER_MODE_SILENT = false;
1178600534df66c2ff5846ed230b50c56229322d48aJohn Spurlock
118a11b4affcad3d255aa723a89b768ea222506f2e8John Spurlock    /** In silent mode, are volume adjustments (raises) prevented? */
119a11b4affcad3d255aa723a89b768ea222506f2e8John Spurlock    private static final boolean PREVENT_VOLUME_ADJUSTMENT_IF_SILENT = true;
120a11b4affcad3d255aa723a89b768ea222506f2e8John Spurlock
1219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** How long to delay before persisting a change in volume/ringer mode. */
12245edba1b8b0377dfe70a4f2b0afb0f04dd8e1ee9RoboErik    private static final int PERSIST_DELAY = 500;
1239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1243346a802087f621c6441bc512dfcc17b07143fc6John Spurlock    /**
1253346a802087f621c6441bc512dfcc17b07143fc6John Spurlock     * The delay before playing a sound. This small period exists so the user
1263346a802087f621c6441bc512dfcc17b07143fc6John Spurlock     * can press another key (non-volume keys, too) to have it NOT be audible.
1273346a802087f621c6441bc512dfcc17b07143fc6John Spurlock     * <p>
1283346a802087f621c6441bc512dfcc17b07143fc6John Spurlock     * PhoneWindow will implement this part.
1293346a802087f621c6441bc512dfcc17b07143fc6John Spurlock     */
1303346a802087f621c6441bc512dfcc17b07143fc6John Spurlock    public static final int PLAY_SOUND_DELAY = 300;
1313346a802087f621c6441bc512dfcc17b07143fc6John Spurlock
132a11b4affcad3d255aa723a89b768ea222506f2e8John Spurlock    /**
133a11b4affcad3d255aa723a89b768ea222506f2e8John Spurlock     * Only used in the result from {@link #checkForRingerModeChange(int, int, int)}
134a11b4affcad3d255aa723a89b768ea222506f2e8John Spurlock     */
135a11b4affcad3d255aa723a89b768ea222506f2e8John Spurlock    private static final int FLAG_ADJUST_VOLUME = 1;
136a11b4affcad3d255aa723a89b768ea222506f2e8John Spurlock
137ba50b97cff80e73620a0e3d13cae169e095974a7Dianne Hackborn    private final Context mContext;
138ba50b97cff80e73620a0e3d13cae169e095974a7Dianne Hackborn    private final ContentResolver mContentResolver;
139ba50b97cff80e73620a0e3d13cae169e095974a7Dianne Hackborn    private final AppOpsManager mAppOps;
140ba50b97cff80e73620a0e3d13cae169e095974a7Dianne Hackborn    private final boolean mVoiceCapable;
141d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi
1423346a802087f621c6441bc512dfcc17b07143fc6John Spurlock    /** The controller for the volume UI. */
1433346a802087f621c6441bc512dfcc17b07143fc6John Spurlock    private final VolumeController mVolumeController = new VolumeController();
1449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // sendMsg() flags
1469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** If the msg is already queued, replace it with this one. */
1479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final int SENDMSG_REPLACE = 0;
1489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** If the msg is already queued, ignore this one and leave the old. */
1499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final int SENDMSG_NOOP = 1;
1509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** If the msg is already queued, queue this one and leave the old. */
1519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final int SENDMSG_QUEUE = 2;
1529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1533114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    // AudioHandler messages
1549bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent    private static final int MSG_SET_DEVICE_VOLUME = 0;
1559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final int MSG_PERSIST_VOLUME = 1;
1565c55a051ad7d86a464fb91426f1ea3c0250e38b3Mike Lockwood    private static final int MSG_PERSIST_MASTER_VOLUME = 2;
1579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final int MSG_PERSIST_RINGER_MODE = 3;
158bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent    private static final int MSG_MEDIA_SERVER_DIED = 4;
159dfb881f96af7898151940a4bbc52e45e6043d38bEric Laurent    private static final int MSG_PLAY_SOUND_EFFECT = 5;
160dfb881f96af7898151940a4bbc52e45e6043d38bEric Laurent    private static final int MSG_BTA2DP_DOCK_TIMEOUT = 6;
161dfb881f96af7898151940a4bbc52e45e6043d38bEric Laurent    private static final int MSG_LOAD_SOUND_EFFECTS = 7;
162dfb881f96af7898151940a4bbc52e45e6043d38bEric Laurent    private static final int MSG_SET_FORCE_USE = 8;
163dfb881f96af7898151940a4bbc52e45e6043d38bEric Laurent    private static final int MSG_BT_HEADSET_CNCT_FAILED = 9;
164dfb881f96af7898151940a4bbc52e45e6043d38bEric Laurent    private static final int MSG_SET_ALL_VOLUMES = 10;
165dfb881f96af7898151940a4bbc52e45e6043d38bEric Laurent    private static final int MSG_PERSIST_MASTER_VOLUME_MUTE = 11;
166dfb881f96af7898151940a4bbc52e45e6043d38bEric Laurent    private static final int MSG_REPORT_NEW_ROUTES = 12;
167dfb881f96af7898151940a4bbc52e45e6043d38bEric Laurent    private static final int MSG_SET_FORCE_BT_A2DP_USE = 13;
168dfb881f96af7898151940a4bbc52e45e6043d38bEric Laurent    private static final int MSG_CHECK_MUSIC_ACTIVE = 14;
169dfb881f96af7898151940a4bbc52e45e6043d38bEric Laurent    private static final int MSG_BROADCAST_AUDIO_BECOMING_NOISY = 15;
170dfb881f96af7898151940a4bbc52e45e6043d38bEric Laurent    private static final int MSG_CONFIGURE_SAFE_MEDIA_VOLUME = 16;
171dfb881f96af7898151940a4bbc52e45e6043d38bEric Laurent    private static final int MSG_CONFIGURE_SAFE_MEDIA_VOLUME_FORCED = 17;
172dfb881f96af7898151940a4bbc52e45e6043d38bEric Laurent    private static final int MSG_PERSIST_SAFE_VOLUME_STATE = 18;
173dfb881f96af7898151940a4bbc52e45e6043d38bEric Laurent    private static final int MSG_BROADCAST_BT_CONNECTION_STATE = 19;
174dfb881f96af7898151940a4bbc52e45e6043d38bEric Laurent    private static final int MSG_UNLOAD_SOUND_EFFECTS = 20;
1754a5eeb9c727d77bb57fef87a70c8c9cc23dbfee3Eric Laurent    private static final int MSG_SYSTEM_READY = 21;
1763114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    // start of messages handled under wakelock
1773114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    //   these messages can only be queued, i.e. sent with queueMsgUnderWakeLock(),
178e12c39bb9cedb8b363658979872694eb55b1386eJean-Michel Trivi    //   and not with sendMsg(..., ..., SENDMSG_QUEUE, ...)
179fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    private static final int MSG_SET_WIRED_DEVICE_CONNECTION_STATE = 100;
1800a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood    private static final int MSG_SET_A2DP_SRC_CONNECTION_STATE = 101;
1810a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood    private static final int MSG_SET_A2DP_SINK_CONNECTION_STATE = 102;
1823114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    // end of messages handled under wakelock
183afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent
1844c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi    private static final int BTA2DP_DOCK_TIMEOUT_MILLIS = 8000;
185dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent    // Timeout for connection to bluetooth headset service
186dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent    private static final int BT_HEADSET_CNCT_TIMEOUT_MS = 3000;
187dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent
1889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** @see AudioSystemThread */
1899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private AudioSystemThread mAudioSystemThread;
1909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** @see AudioHandler */
1919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private AudioHandler mAudioHandler;
1929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** @see VolumeStreamState */
1939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private VolumeStreamState[] mStreamStates;
194b109615ebebd6f3b9ae789412279f576c3ace46bJason Parekh    private SettingsObserver mSettingsObserver;
195a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent
196fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    private int mMode = AudioSystem.MODE_NORMAL;
197ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten    // protects mRingerMode
198ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten    private final Object mSettingsLock = new Object();
19945c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent
2009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private SoundPool mSoundPool;
20130c918ce7fbe171944b28fc91b3f22b3d631872dGlenn Kasten    private final Object mSoundEffectsLock = new Object();
2029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final int NUM_SOUNDPOOL_CHANNELS = 4;
2039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2044767690f09ea3447b8c5c32fb28d27650aa18e00Mike Lockwood    // Internally master volume is a float in the 0.0 - 1.0 range,
2054767690f09ea3447b8c5c32fb28d27650aa18e00Mike Lockwood    // but to support integer based AudioManager API we translate it to 0 - 100
2064767690f09ea3447b8c5c32fb28d27650aa18e00Mike Lockwood    private static final int MAX_MASTER_VOLUME = 100;
2074767690f09ea3447b8c5c32fb28d27650aa18e00Mike Lockwood
2086c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang    // Maximum volume adjust steps allowed in a single batch call.
2096c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang    private static final int MAX_BATCH_VOLUME_ADJUST_STEPS = 4;
2106c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang
2119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /* Sound effect file names  */
2129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final String SOUND_EFFECTS_PATH = "/media/audio/ui/";
213e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent    private static final List<String> SOUND_EFFECT_FILES = new ArrayList<String>();
2149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /* Sound effect file name mapping sound effect id (AudioManager.FX_xxx) to
2169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * file index in SOUND_EFFECT_FILES[] (first column) and indicating if effect
2179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * uses soundpool (second column) */
218e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent    private final int[][] SOUND_EFFECT_FILES_MAP = new int[AudioManager.NUM_SOUND_EFFECTS][2];
2199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2205982013cfc8274ff0bafaba83c676b3a8890cba9Jared Suttles   /** @hide Maximum volume index values for audio streams */
221fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    private static final int[] MAX_STREAM_VOLUME = new int[] {
2226ee9952bc20be72b9419cb653c9e2e833889a3d3Eric Laurent        5,  // STREAM_VOICE_CALL
2236ee9952bc20be72b9419cb653c9e2e833889a3d3Eric Laurent        7,  // STREAM_SYSTEM
2246ee9952bc20be72b9419cb653c9e2e833889a3d3Eric Laurent        7,  // STREAM_RING
2256ee9952bc20be72b9419cb653c9e2e833889a3d3Eric Laurent        15, // STREAM_MUSIC
2266ee9952bc20be72b9419cb653c9e2e833889a3d3Eric Laurent        7,  // STREAM_ALARM
2276ee9952bc20be72b9419cb653c9e2e833889a3d3Eric Laurent        7,  // STREAM_NOTIFICATION
2286ee9952bc20be72b9419cb653c9e2e833889a3d3Eric Laurent        15, // STREAM_BLUETOOTH_SCO
2296ee9952bc20be72b9419cb653c9e2e833889a3d3Eric Laurent        7,  // STREAM_SYSTEM_ENFORCED
2306ee9952bc20be72b9419cb653c9e2e833889a3d3Eric Laurent        15, // STREAM_DTMF
2316ee9952bc20be72b9419cb653c9e2e833889a3d3Eric Laurent        15  // STREAM_TTS
2325982013cfc8274ff0bafaba83c676b3a8890cba9Jared Suttles    };
2336d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent    /* mStreamVolumeAlias[] indicates for each stream if it uses the volume settings
234a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent     * of another stream: This avoids multiplying the volume settings for hidden
235a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent     * stream types that follow other stream behavior for volume settings
2366d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent     * NOTE: do not create loops in aliases!
2376d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent     * Some streams alias to different streams according to device category (phone or tablet) or
23824e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent     * use case (in call vs off call...). See updateStreamVolumeAlias() for more details.
2396d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent     *  mStreamVolumeAlias contains the default aliases for a voice capable device (phone) and
2406d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent     *  STREAM_VOLUME_ALIAS_NON_VOICE for a non voice capable device (tablet).*/
24130c918ce7fbe171944b28fc91b3f22b3d631872dGlenn Kasten    private final int[] STREAM_VOLUME_ALIAS = new int[] {
2426d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent        AudioSystem.STREAM_VOICE_CALL,      // STREAM_VOICE_CALL
2436d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent        AudioSystem.STREAM_RING,            // STREAM_SYSTEM
2446d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent        AudioSystem.STREAM_RING,            // STREAM_RING
2456d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent        AudioSystem.STREAM_MUSIC,           // STREAM_MUSIC
2466d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent        AudioSystem.STREAM_ALARM,           // STREAM_ALARM
2476d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent        AudioSystem.STREAM_RING,            // STREAM_NOTIFICATION
2486d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent        AudioSystem.STREAM_BLUETOOTH_SCO,   // STREAM_BLUETOOTH_SCO
2496d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent        AudioSystem.STREAM_RING,            // STREAM_SYSTEM_ENFORCED
2506d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent        AudioSystem.STREAM_RING,            // STREAM_DTMF
2516d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent        AudioSystem.STREAM_MUSIC            // STREAM_TTS
252a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent    };
2536d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent    private final int[] STREAM_VOLUME_ALIAS_NON_VOICE = new int[] {
2546d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent        AudioSystem.STREAM_VOICE_CALL,      // STREAM_VOICE_CALL
2556d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent        AudioSystem.STREAM_MUSIC,           // STREAM_SYSTEM
2566d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent        AudioSystem.STREAM_RING,            // STREAM_RING
2576d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent        AudioSystem.STREAM_MUSIC,           // STREAM_MUSIC
2586d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent        AudioSystem.STREAM_ALARM,           // STREAM_ALARM
2596d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent        AudioSystem.STREAM_RING,            // STREAM_NOTIFICATION
2606d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent        AudioSystem.STREAM_BLUETOOTH_SCO,   // STREAM_BLUETOOTH_SCO
2616d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent        AudioSystem.STREAM_MUSIC,           // STREAM_SYSTEM_ENFORCED
2626d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent        AudioSystem.STREAM_MUSIC,           // STREAM_DTMF
2636d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent        AudioSystem.STREAM_MUSIC            // STREAM_TTS
2646d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent    };
2656d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent    private int[] mStreamVolumeAlias;
266a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent
267ba50b97cff80e73620a0e3d13cae169e095974a7Dianne Hackborn    /**
268ba50b97cff80e73620a0e3d13cae169e095974a7Dianne Hackborn     * Map AudioSystem.STREAM_* constants to app ops.  This should be used
269ba50b97cff80e73620a0e3d13cae169e095974a7Dianne Hackborn     * after mapping through mStreamVolumeAlias.
270ba50b97cff80e73620a0e3d13cae169e095974a7Dianne Hackborn     */
271ba50b97cff80e73620a0e3d13cae169e095974a7Dianne Hackborn    private static final int[] STEAM_VOLUME_OPS = new int[] {
272ba50b97cff80e73620a0e3d13cae169e095974a7Dianne Hackborn        AppOpsManager.OP_AUDIO_VOICE_VOLUME,            // STREAM_VOICE_CALL
273ba50b97cff80e73620a0e3d13cae169e095974a7Dianne Hackborn        AppOpsManager.OP_AUDIO_MEDIA_VOLUME,            // STREAM_SYSTEM
274ba50b97cff80e73620a0e3d13cae169e095974a7Dianne Hackborn        AppOpsManager.OP_AUDIO_RING_VOLUME,             // STREAM_RING
275ba50b97cff80e73620a0e3d13cae169e095974a7Dianne Hackborn        AppOpsManager.OP_AUDIO_MEDIA_VOLUME,            // STREAM_MUSIC
276ba50b97cff80e73620a0e3d13cae169e095974a7Dianne Hackborn        AppOpsManager.OP_AUDIO_ALARM_VOLUME,            // STREAM_ALARM
277ba50b97cff80e73620a0e3d13cae169e095974a7Dianne Hackborn        AppOpsManager.OP_AUDIO_NOTIFICATION_VOLUME,     // STREAM_NOTIFICATION
278ba50b97cff80e73620a0e3d13cae169e095974a7Dianne Hackborn        AppOpsManager.OP_AUDIO_BLUETOOTH_VOLUME,        // STREAM_BLUETOOTH_SCO
279ba50b97cff80e73620a0e3d13cae169e095974a7Dianne Hackborn        AppOpsManager.OP_AUDIO_MEDIA_VOLUME,            // STREAM_SYSTEM_ENFORCED
280ba50b97cff80e73620a0e3d13cae169e095974a7Dianne Hackborn        AppOpsManager.OP_AUDIO_MEDIA_VOLUME,            // STREAM_DTMF
281ba50b97cff80e73620a0e3d13cae169e095974a7Dianne Hackborn        AppOpsManager.OP_AUDIO_MEDIA_VOLUME,            // STREAM_TTS
282ba50b97cff80e73620a0e3d13cae169e095974a7Dianne Hackborn    };
283ba50b97cff80e73620a0e3d13cae169e095974a7Dianne Hackborn
28483a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent    private final boolean mUseFixedVolume;
28583a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent
286bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent    // stream names used by dumpStreamStates()
2871af30c7ac480e5d335f267a3ac3b2e6c748ce240John Spurlock    private static final String[] STREAM_NAMES = new String[] {
288bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent            "STREAM_VOICE_CALL",
289bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent            "STREAM_SYSTEM",
290bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent            "STREAM_RING",
291bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent            "STREAM_MUSIC",
292bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent            "STREAM_ALARM",
293bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent            "STREAM_NOTIFICATION",
294bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent            "STREAM_BLUETOOTH_SCO",
295bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent            "STREAM_SYSTEM_ENFORCED",
296bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent            "STREAM_DTMF",
297bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent            "STREAM_TTS"
298bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent    };
299bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent
30030c918ce7fbe171944b28fc91b3f22b3d631872dGlenn Kasten    private final AudioSystem.ErrorCallback mAudioSystemCallback = new AudioSystem.ErrorCallback() {
3019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public void onError(int error) {
3029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            switch (error) {
3039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            case AudioSystem.AUDIO_STATUS_SERVER_DIED:
304dfb881f96af7898151940a4bbc52e45e6043d38bEric Laurent                sendMsg(mAudioHandler, MSG_MEDIA_SERVER_DIED,
305dfb881f96af7898151940a4bbc52e45e6043d38bEric Laurent                        SENDMSG_NOOP, 0, 0, null, 0);
3069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                break;
3079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            default:
3089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                break;
3099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
310dfb881f96af7898151940a4bbc52e45e6043d38bEric Laurent        }
3119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    };
3129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
3149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Current ringer mode from one of {@link AudioManager#RINGER_MODE_NORMAL},
3159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * {@link AudioManager#RINGER_MODE_SILENT}, or
3169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * {@link AudioManager#RINGER_MODE_VIBRATE}.
3179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
318ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten    // protected by mSettingsLock
3199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private int mRingerMode;
3209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3219bcf401d13d47416043a704430388abd59aef7cdEric Laurent    /** @see System#MODE_RINGER_STREAMS_AFFECTED */
32224e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent    private int mRingerModeAffectedStreams = 0;
3239bcf401d13d47416043a704430388abd59aef7cdEric Laurent
3245b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent    // Streams currently muted by ringer mode
3255b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent    private int mRingerModeMutedStreams;
3265b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent
3279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** @see System#MUTE_STREAMS_AFFECTED */
3289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private int mMuteAffectedStreams;
3299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
331bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent     * NOTE: setVibrateSetting(), getVibrateSetting(), shouldVibrate() are deprecated.
332bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent     * mVibrateSetting is just maintained during deprecation period but vibration policy is
333bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent     * now only controlled by mHasVibrator and mRingerMode
3349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
3359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private int mVibrateSetting;
3369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
337bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent    // Is there a vibrator
338bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent    private final boolean mHasVibrator;
339bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent
340a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent    // Broadcast receiver for device connections intent broadcasts
341a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent    private final BroadcastReceiver mReceiver = new AudioServiceBroadcastReceiver();
342a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent
343c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent    // Devices currently connected
34430c918ce7fbe171944b28fc91b3f22b3d631872dGlenn Kasten    private final HashMap <Integer, String> mConnectedDevices = new HashMap <Integer, String>();
345c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent
346c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent    // Forced device usage for communications
347c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent    private int mForcedUseForComm;
348c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent
3490dc37cce9d564ae43883c8dc8672b9266b881e63Mike Lockwood    // True if we have master volume support
3500dc37cce9d564ae43883c8dc8672b9266b881e63Mike Lockwood    private final boolean mUseMasterVolume;
3510dc37cce9d564ae43883c8dc8672b9266b881e63Mike Lockwood
3529760647dd0ee67e7c20f3e9d661d2006b1df0b54Mike Lockwood    private final int[] mMasterVolumeRamp;
3539760647dd0ee67e7c20f3e9d661d2006b1df0b54Mike Lockwood
3549272b4b4a44fe1f33e3030810618194f817caaecEric Laurent    // List of binder death handlers for setMode() client processes.
3559272b4b4a44fe1f33e3030810618194f817caaecEric Laurent    // The last process to have called setMode() is at the top of the list.
35630c918ce7fbe171944b28fc91b3f22b3d631872dGlenn Kasten    private final ArrayList <SetModeDeathHandler> mSetModeDeathHandlers = new ArrayList <SetModeDeathHandler>();
357eb14a783be073b5fd6e8c8c9bc87d2d1919f2c9eEric Laurent
3583def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent    // List of clients having issued a SCO start request
35930c918ce7fbe171944b28fc91b3f22b3d631872dGlenn Kasten    private final ArrayList <ScoClient> mScoClients = new ArrayList <ScoClient>();
3603def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent
3613def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent    // BluetoothHeadset API to control SCO connection
3623def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent    private BluetoothHeadset mBluetoothHeadset;
3633def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent
36482aa7f017daaaeb96c13e6e3491d5037ab471085Jaikumar Ganesh    // Bluetooth headset device
36582aa7f017daaaeb96c13e6e3491d5037ab471085Jaikumar Ganesh    private BluetoothDevice mBluetoothHeadsetDevice;
3663def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent
36762ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent    // Indicate if SCO audio connection is currently active and if the initiator is
36862ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent    // audio service (internal) or bluetooth headset (external)
36962ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent    private int mScoAudioState;
37062ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent    // SCO audio state is not active
37162ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent    private static final int SCO_STATE_INACTIVE = 0;
372dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent    // SCO audio activation request waiting for headset service to connect
373dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent    private static final int SCO_STATE_ACTIVATE_REQ = 1;
37425fc29b3691a1d2a84164988dc74b2e7d301868eEric Laurent    // SCO audio state is active or starting due to a request from AudioManager API
375dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent    private static final int SCO_STATE_ACTIVE_INTERNAL = 3;
376dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent    // SCO audio deactivation request waiting for headset service to connect
377dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent    private static final int SCO_STATE_DEACTIVATE_REQ = 5;
378dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent
37962ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent    // SCO audio state is active due to an action in BT handsfree (either voice recognition or
38062ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent    // in call audio)
38162ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent    private static final int SCO_STATE_ACTIVE_EXTERNAL = 2;
382dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent    // Deactivation request for all SCO connections (initiated by audio mode change)
383dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent    // waiting for headset service to connect
384dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent    private static final int SCO_STATE_DEACTIVATE_EXT_REQ = 4;
385dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent
386c18c9138cee0f0859bcab636a004ce92ca4a9ab5Eric Laurent    // Indicates the mode used for SCO audio connection. The mode is virtual call if the request
387c18c9138cee0f0859bcab636a004ce92ca4a9ab5Eric Laurent    // originated from an app targeting an API version before JB MR2 and raw audio after that.
388c18c9138cee0f0859bcab636a004ce92ca4a9ab5Eric Laurent    private int mScoAudioMode;
389c18c9138cee0f0859bcab636a004ce92ca4a9ab5Eric Laurent    // SCO audio mode is virtual voice call (BluetoothHeadset.startScoUsingVirtualVoiceCall())
390c18c9138cee0f0859bcab636a004ce92ca4a9ab5Eric Laurent    private static final int SCO_MODE_VIRTUAL_CALL = 0;
391c18c9138cee0f0859bcab636a004ce92ca4a9ab5Eric Laurent    // SCO audio mode is raw audio (BluetoothHeadset.connectAudio())
392c18c9138cee0f0859bcab636a004ce92ca4a9ab5Eric Laurent    private static final int SCO_MODE_RAW = 1;
393c18c9138cee0f0859bcab636a004ce92ca4a9ab5Eric Laurent
394dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent    // Current connection state indicated by bluetooth headset
395dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent    private int mScoConnectionState;
39662ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent
397a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent    // true if boot sequence has been completed
3984a5eeb9c727d77bb57fef87a70c8c9cc23dbfee3Eric Laurent    private boolean mSystemReady;
399a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent    // listener for SoundPool sample load completion indication
400a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent    private SoundPoolCallback mSoundPoolCallBack;
401a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent    // thread for SoundPool listener
402a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent    private SoundPoolListenerThread mSoundPoolListenerThread;
403a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent    // message looper for SoundPool listener
404a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent    private Looper mSoundPoolLooper = null;
405c55b393efd462490cd5e27fc373bceafdd25662eJean-Michel Trivi    // volume applied to sound played with playSoundEffect()
406f2b0c11f4e797e183131261724d8de310dac5431Jean-Michel Trivi    private static int sSoundEffectVolumeDb;
4079903e2638a6c502d96413680d3ebae4fb77fc412Eric Laurent    // getActiveStreamType() will return:
4089903e2638a6c502d96413680d3ebae4fb77fc412Eric Laurent    // - STREAM_NOTIFICATION on tablets during this period after a notification stopped
4099903e2638a6c502d96413680d3ebae4fb77fc412Eric Laurent    // - STREAM_MUSIC on phones during this period after music or talkback/voice search prompt
41025101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent    // stopped
4119903e2638a6c502d96413680d3ebae4fb77fc412Eric Laurent    private static final int DEFAULT_STREAM_TYPE_OVERRIDE_DELAY_MS = 5000;
41225101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent    // previous volume adjustment direction received by checkForRingerModeChange()
41325101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent    private int mPrevVolDirection = AudioManager.ADJUST_SAME;
4146243edd818b84adfbe712d5d233d6414b33653acAmith Yamasani    // Keyguard manager proxy
4156243edd818b84adfbe712d5d233d6414b33653acAmith Yamasani    private KeyguardManager mKeyguardManager;
41645c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent    // mVolumeControlStream is set by VolumePanel to temporarily force the stream type which volume
41745c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent    // is controlled by Vol keys.
41845c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent    private int  mVolumeControlStream = -1;
41945c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent    private final Object mForceControlStreamLock = new Object();
42045c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent    // VolumePanel is currently the only client of forceVolumeControlStream() and runs in system
42145c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent    // server process so in theory it is not necessary to monitor the client death.
42245c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent    // However it is good to be ready for future evolutions.
42345c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent    private ForceControlStreamClient mForceControlStreamClient = null;
424098d580cc2bb6c0891c756a4e5230c6c6b0d2376Jeff Sharkey    // Used to play ringtones outside system_server
425098d580cc2bb6c0891c756a4e5230c6c6b0d2376Jeff Sharkey    private volatile IRingtonePlayer mRingtonePlayer;
4269bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent
427f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi    private int mDeviceOrientation = Configuration.ORIENTATION_UNDEFINED;
428bb6f8711a7f804d39c45218db2d6339940cc5d35Jean-Michel Trivi    private int mDeviceRotation = Surface.ROTATION_0;
429f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi
4307847211fb4699bf6018e29d214a918ed6657319bEric Laurent    // Request to override default use of A2DP for media.
4317847211fb4699bf6018e29d214a918ed6657319bEric Laurent    private boolean mBluetoothA2dpEnabled;
4327847211fb4699bf6018e29d214a918ed6657319bEric Laurent    private final Object mBluetoothA2dpEnabledLock = new Object();
4337847211fb4699bf6018e29d214a918ed6657319bEric Laurent
434632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn    // Monitoring of audio routes.  Protected by mCurAudioRoutes.
435632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn    final AudioRoutesInfo mCurAudioRoutes = new AudioRoutesInfo();
436632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn    final RemoteCallbackList<IAudioRoutesObserver> mRoutesObservers
437632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn            = new RemoteCallbackList<IAudioRoutesObserver>();
438632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn
4393114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    /**
4403114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     * A fake stream type to match the notion of remote media playback
4413114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     */
4423114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    public final static int STREAM_REMOTE_MUSIC = -200;
4433114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi
4444bbcc6549738f3d69831b2bd9eb4accec3e9920eEric Laurent    // Devices for which the volume is fixed and VolumePanel slider should be disabled
445948d32748caaac5be06c991ebf00f74265a7849fEric Laurent    final int mFixedVolumeDevices = AudioSystem.DEVICE_OUT_HDMI |
4464bbcc6549738f3d69831b2bd9eb4accec3e9920eEric Laurent            AudioSystem.DEVICE_OUT_DGTL_DOCK_HEADSET |
447fb917e019f04d60f4924114fe2684c0d67981af6Paul McLean            AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET;
4484bbcc6549738f3d69831b2bd9eb4accec3e9920eEric Laurent
449bb6f8711a7f804d39c45218db2d6339940cc5d35Jean-Michel Trivi    // TODO merge orientation and rotation
450d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent    private final boolean mMonitorOrientation;
451bb6f8711a7f804d39c45218db2d6339940cc5d35Jean-Michel Trivi    private final boolean mMonitorRotation;
452d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent
4537ee1e4ff7346a278a6722108fbc1869240b3e866Eric Laurent    private boolean mDockAudioMediaEnabled = true;
4547ee1e4ff7346a278a6722108fbc1869240b3e866Eric Laurent
45508ed1b9d2099ec8231b21353b33b901492ea9885Eric Laurent    private int mDockState = Intent.EXTRA_DOCK_STATE_UNDOCKED;
45608ed1b9d2099ec8231b21353b33b901492ea9885Eric Laurent
457fde16d5879ea88a971004c984093409468b6139cEric Laurent    // Used when safe volume warning message display is requested by setStreamVolume(). In this
458fde16d5879ea88a971004c984093409468b6139cEric Laurent    // case, the new requested volume, stream type and device are stored in mPendingVolumeCommand
459fde16d5879ea88a971004c984093409468b6139cEric Laurent    // and used later when/if disableSafeMediaVolume() is called.
460fde16d5879ea88a971004c984093409468b6139cEric Laurent    private StreamVolumeCommand mPendingVolumeCommand;
461fde16d5879ea88a971004c984093409468b6139cEric Laurent
462fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    private PowerManager.WakeLock mAudioEventWakeLock;
463fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi
464fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    private final MediaFocusControl mMediaFocusControl;
465fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi
4665a0cf7a27f3953a1266af48543ccd9024f4cd89fJohn Du    // Reference to BluetoothA2dp to query for AbsoluteVolume.
4675a0cf7a27f3953a1266af48543ccd9024f4cd89fJohn Du    private BluetoothA2dp mA2dp;
4685a0cf7a27f3953a1266af48543ccd9024f4cd89fJohn Du    private final Object mA2dpAvrcpLock = new Object();
4695a0cf7a27f3953a1266af48543ccd9024f4cd89fJohn Du    // If absolute volume is supported in AVRCP device
4705a0cf7a27f3953a1266af48543ccd9024f4cd89fJohn Du    private boolean mAvrcpAbsVolSupported = false;
4715a0cf7a27f3953a1266af48543ccd9024f4cd89fJohn Du
4729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    ///////////////////////////////////////////////////////////////////////////
4739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // Construction
4749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    ///////////////////////////////////////////////////////////////////////////
4759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** @hide */
4779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public AudioService(Context context) {
4789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext = context;
4799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContentResolver = context.getContentResolver();
480ba50b97cff80e73620a0e3d13cae169e095974a7Dianne Hackborn        mAppOps = (AppOpsManager)context.getSystemService(Context.APP_OPS_SERVICE);
481c7fcba4b7bd3d78e7cfe975a3f8e4dde2f6738b7Joe Onorato        mVoiceCapable = mContext.getResources().getBoolean(
482c7fcba4b7bd3d78e7cfe975a3f8e4dde2f6738b7Joe Onorato                com.android.internal.R.bool.config_voice_capable);
4835982013cfc8274ff0bafaba83c676b3a8890cba9Jared Suttles
484c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi        PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
485fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        mAudioEventWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "handleAudioEvent");
486c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi
487bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent        Vibrator vibrator = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE);
488bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent        mHasVibrator = vibrator == null ? false : vibrator.hasVibrator();
489bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent
4905982013cfc8274ff0bafaba83c676b3a8890cba9Jared Suttles       // Intialized volume
4915982013cfc8274ff0bafaba83c676b3a8890cba9Jared Suttles        MAX_STREAM_VOLUME[AudioSystem.STREAM_VOICE_CALL] = SystemProperties.getInt(
4925982013cfc8274ff0bafaba83c676b3a8890cba9Jared Suttles            "ro.config.vc_call_vol_steps",
4935982013cfc8274ff0bafaba83c676b3a8890cba9Jared Suttles           MAX_STREAM_VOLUME[AudioSystem.STREAM_VOICE_CALL]);
4945982013cfc8274ff0bafaba83c676b3a8890cba9Jared Suttles
495f2b0c11f4e797e183131261724d8de310dac5431Jean-Michel Trivi        sSoundEffectVolumeDb = context.getResources().getInteger(
496c55b393efd462490cd5e27fc373bceafdd25662eJean-Michel Trivi                com.android.internal.R.integer.config_soundEffectVolumeDb);
49725101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent
498c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent        mForcedUseForComm = AudioSystem.FORCE_NONE;
499dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent
5009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        createAudioSystemThread();
501dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent
502fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        mMediaFocusControl = new MediaFocusControl(mAudioHandler.getLooper(),
5033346a802087f621c6441bc512dfcc17b07143fc6John Spurlock                mContext, mVolumeController, this);
504fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi
505dfb881f96af7898151940a4bbc52e45e6043d38bEric Laurent        AudioSystem.setErrorCallback(mAudioSystemCallback);
506dfb881f96af7898151940a4bbc52e45e6043d38bEric Laurent
507dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent        boolean cameraSoundForced = mContext.getResources().getBoolean(
508dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent                com.android.internal.R.bool.config_camera_sound_forced);
509dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent        mCameraSoundForced = new Boolean(cameraSoundForced);
510dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent        sendMsg(mAudioHandler,
511dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent                MSG_SET_FORCE_USE,
512dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent                SENDMSG_QUEUE,
513dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent                AudioSystem.FOR_SYSTEM,
514dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent                cameraSoundForced ?
515dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent                        AudioSystem.FORCE_SYSTEM_ENFORCED : AudioSystem.FORCE_NONE,
516dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent                null,
517dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent                0);
518dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent
51905274f348e12983eb8613cc6eb9ae561e8197e28Eric Laurent        mSafeMediaVolumeState = new Integer(Settings.Global.getInt(mContentResolver,
52005274f348e12983eb8613cc6eb9ae561e8197e28Eric Laurent                                                        Settings.Global.AUDIO_SAFE_VOLUME_STATE,
52105274f348e12983eb8613cc6eb9ae561e8197e28Eric Laurent                                                        SAFE_MEDIA_VOLUME_NOT_CONFIGURED));
52205274f348e12983eb8613cc6eb9ae561e8197e28Eric Laurent        // The default safe volume index read here will be replaced by the actual value when
52305274f348e12983eb8613cc6eb9ae561e8197e28Eric Laurent        // the mcc is read by onConfigureSafeVolume()
52405274f348e12983eb8613cc6eb9ae561e8197e28Eric Laurent        mSafeMediaVolumeIndex = mContext.getResources().getInteger(
52505274f348e12983eb8613cc6eb9ae561e8197e28Eric Laurent                com.android.internal.R.integer.config_safe_media_volume_index) * 10;
52605274f348e12983eb8613cc6eb9ae561e8197e28Eric Laurent
52783a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent        mUseFixedVolume = mContext.getResources().getBoolean(
52883a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent                com.android.internal.R.bool.config_useFixedVolume);
52983a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent
53024e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent        // must be called before readPersistedSettings() which needs a valid mStreamVolumeAlias[]
53124e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent        // array initialized by updateStreamVolumeAlias()
53224e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent        updateStreamVolumeAlias(false /*updateVolumes*/);
5339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        readPersistedSettings();
534c1d4166289ce016965d1147f7e8d37862ee347ecEric Laurent        mSettingsObserver = new SettingsObserver();
535a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent        createStreamStates();
5369f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent
537fd116ad1ab02f6060a0b2201f018317fa32e28b4Glenn Kasten        readAndSetLowRamDevice();
5383891c4cc918e8062abb97c542a8625d556dccc59Eric Laurent
5393891c4cc918e8062abb97c542a8625d556dccc59Eric Laurent        // Call setRingerModeInt() to apply correct mute
5403891c4cc918e8062abb97c542a8625d556dccc59Eric Laurent        // state on streams affected by ringer mode.
5413891c4cc918e8062abb97c542a8625d556dccc59Eric Laurent        mRingerModeMutedStreams = 0;
5423891c4cc918e8062abb97c542a8625d556dccc59Eric Laurent        setRingerModeInt(getRingerMode(), false);
5433891c4cc918e8062abb97c542a8625d556dccc59Eric Laurent
544a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent        // Register for device connection intent broadcasts.
545a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent        IntentFilter intentFilter =
546b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent                new IntentFilter(BluetoothHeadset.ACTION_AUDIO_STATE_CHANGED);
54782aa7f017daaaeb96c13e6e3491d5037ab471085Jaikumar Ganesh        intentFilter.addAction(BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED);
54882aa7f017daaaeb96c13e6e3491d5037ab471085Jaikumar Ganesh        intentFilter.addAction(Intent.ACTION_DOCK_EVENT);
54959f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent        intentFilter.addAction(Intent.ACTION_USB_AUDIO_ACCESSORY_PLUG);
55059f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent        intentFilter.addAction(Intent.ACTION_USB_AUDIO_DEVICE_PLUG);
551950e8cb40a6d826af4cc2eef9d3908c1b70486e6Eric Laurent        intentFilter.addAction(Intent.ACTION_SCREEN_ON);
552950e8cb40a6d826af4cc2eef9d3908c1b70486e6Eric Laurent        intentFilter.addAction(Intent.ACTION_SCREEN_OFF);
553bc0fab1fc2db832ef86d8a33466ec4d68b103ca0Eric Laurent        intentFilter.addAction(Intent.ACTION_USER_SWITCHED);
554c837a451946b64d70ed7c642fbde03c182c28b6fPaul McLean        intentFilter.addAction(UsbManager.ACTION_USB_DEVICE_ATTACHED);
555f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi
556d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent        intentFilter.addAction(Intent.ACTION_CONFIGURATION_CHANGED);
557bb6f8711a7f804d39c45218db2d6339940cc5d35Jean-Michel Trivi        // TODO merge orientation and rotation
558d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent        mMonitorOrientation = SystemProperties.getBoolean("ro.audio.monitorOrientation", false);
559d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent        if (mMonitorOrientation) {
560f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi            Log.v(TAG, "monitoring device orientation");
561f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi            // initialize orientation in AudioSystem
562f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi            setOrientationForAudioSystem();
563f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi        }
564bb6f8711a7f804d39c45218db2d6339940cc5d35Jean-Michel Trivi        mMonitorRotation = SystemProperties.getBoolean("ro.audio.monitorRotation", false);
565bb6f8711a7f804d39c45218db2d6339940cc5d35Jean-Michel Trivi        if (mMonitorRotation) {
566bb6f8711a7f804d39c45218db2d6339940cc5d35Jean-Michel Trivi            mDeviceRotation = ((WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE))
567bb6f8711a7f804d39c45218db2d6339940cc5d35Jean-Michel Trivi                    .getDefaultDisplay().getRotation();
568bb6f8711a7f804d39c45218db2d6339940cc5d35Jean-Michel Trivi            Log.v(TAG, "monitoring device rotation, initial=" + mDeviceRotation);
569bb6f8711a7f804d39c45218db2d6339940cc5d35Jean-Michel Trivi            // initialize rotation in AudioSystem
570bb6f8711a7f804d39c45218db2d6339940cc5d35Jean-Michel Trivi            setRotationForAudioSystem();
571bb6f8711a7f804d39c45218db2d6339940cc5d35Jean-Michel Trivi        }
572f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi
573a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent        context.registerReceiver(mReceiver, intentFilter);
5745982013cfc8274ff0bafaba83c676b3a8890cba9Jared Suttles
5750dc37cce9d564ae43883c8dc8672b9266b881e63Mike Lockwood        mUseMasterVolume = context.getResources().getBoolean(
5760dc37cce9d564ae43883c8dc8672b9266b881e63Mike Lockwood                com.android.internal.R.bool.config_useMasterVolume);
5779063154a793b0ab38b3c5992cbaed046427b4a82Mike Lockwood        restoreMasterVolume();
5789760647dd0ee67e7c20f3e9d661d2006b1df0b54Mike Lockwood
5799760647dd0ee67e7c20f3e9d661d2006b1df0b54Mike Lockwood        mMasterVolumeRamp = context.getResources().getIntArray(
5809760647dd0ee67e7c20f3e9d661d2006b1df0b54Mike Lockwood                com.android.internal.R.array.config_masterVolumeRamp);
5817847211fb4699bf6018e29d214a918ed6657319bEric Laurent
5829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
5839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5844a5eeb9c727d77bb57fef87a70c8c9cc23dbfee3Eric Laurent    public void systemReady() {
5854a5eeb9c727d77bb57fef87a70c8c9cc23dbfee3Eric Laurent        sendMsg(mAudioHandler, MSG_SYSTEM_READY, SENDMSG_QUEUE,
5864a5eeb9c727d77bb57fef87a70c8c9cc23dbfee3Eric Laurent                0, 0, null, 0);
5874a5eeb9c727d77bb57fef87a70c8c9cc23dbfee3Eric Laurent    }
5884a5eeb9c727d77bb57fef87a70c8c9cc23dbfee3Eric Laurent
5894a5eeb9c727d77bb57fef87a70c8c9cc23dbfee3Eric Laurent    public void onSystemReady() {
5904a5eeb9c727d77bb57fef87a70c8c9cc23dbfee3Eric Laurent        mSystemReady = true;
5914a5eeb9c727d77bb57fef87a70c8c9cc23dbfee3Eric Laurent        sendMsg(mAudioHandler, MSG_LOAD_SOUND_EFFECTS, SENDMSG_QUEUE,
5924a5eeb9c727d77bb57fef87a70c8c9cc23dbfee3Eric Laurent                0, 0, null, 0);
5934a5eeb9c727d77bb57fef87a70c8c9cc23dbfee3Eric Laurent
5944a5eeb9c727d77bb57fef87a70c8c9cc23dbfee3Eric Laurent        mKeyguardManager =
5954a5eeb9c727d77bb57fef87a70c8c9cc23dbfee3Eric Laurent                (KeyguardManager) mContext.getSystemService(Context.KEYGUARD_SERVICE);
5964a5eeb9c727d77bb57fef87a70c8c9cc23dbfee3Eric Laurent        mScoConnectionState = AudioManager.SCO_AUDIO_STATE_ERROR;
5974a5eeb9c727d77bb57fef87a70c8c9cc23dbfee3Eric Laurent        resetBluetoothSco();
5984a5eeb9c727d77bb57fef87a70c8c9cc23dbfee3Eric Laurent        getBluetoothHeadset();
5994a5eeb9c727d77bb57fef87a70c8c9cc23dbfee3Eric Laurent        //FIXME: this is to maintain compatibility with deprecated intent
6004a5eeb9c727d77bb57fef87a70c8c9cc23dbfee3Eric Laurent        // AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED. Remove when appropriate.
6014a5eeb9c727d77bb57fef87a70c8c9cc23dbfee3Eric Laurent        Intent newIntent = new Intent(AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED);
6024a5eeb9c727d77bb57fef87a70c8c9cc23dbfee3Eric Laurent        newIntent.putExtra(AudioManager.EXTRA_SCO_AUDIO_STATE,
6034a5eeb9c727d77bb57fef87a70c8c9cc23dbfee3Eric Laurent                AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
6044a5eeb9c727d77bb57fef87a70c8c9cc23dbfee3Eric Laurent        sendStickyBroadcastToAll(newIntent);
6054a5eeb9c727d77bb57fef87a70c8c9cc23dbfee3Eric Laurent
6064a5eeb9c727d77bb57fef87a70c8c9cc23dbfee3Eric Laurent        BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
6074a5eeb9c727d77bb57fef87a70c8c9cc23dbfee3Eric Laurent        if (adapter != null) {
6084a5eeb9c727d77bb57fef87a70c8c9cc23dbfee3Eric Laurent            adapter.getProfileProxy(mContext, mBluetoothProfileServiceListener,
6094a5eeb9c727d77bb57fef87a70c8c9cc23dbfee3Eric Laurent                                    BluetoothProfile.A2DP);
6104a5eeb9c727d77bb57fef87a70c8c9cc23dbfee3Eric Laurent        }
6114a5eeb9c727d77bb57fef87a70c8c9cc23dbfee3Eric Laurent
6124a5eeb9c727d77bb57fef87a70c8c9cc23dbfee3Eric Laurent        sendMsg(mAudioHandler,
6134a5eeb9c727d77bb57fef87a70c8c9cc23dbfee3Eric Laurent                MSG_CONFIGURE_SAFE_MEDIA_VOLUME_FORCED,
6144a5eeb9c727d77bb57fef87a70c8c9cc23dbfee3Eric Laurent                SENDMSG_REPLACE,
6154a5eeb9c727d77bb57fef87a70c8c9cc23dbfee3Eric Laurent                0,
6164a5eeb9c727d77bb57fef87a70c8c9cc23dbfee3Eric Laurent                0,
6174a5eeb9c727d77bb57fef87a70c8c9cc23dbfee3Eric Laurent                null,
6184a5eeb9c727d77bb57fef87a70c8c9cc23dbfee3Eric Laurent                SAFE_VOLUME_CONFIGURE_TIMEOUT_MS);
6194a5eeb9c727d77bb57fef87a70c8c9cc23dbfee3Eric Laurent    }
6204a5eeb9c727d77bb57fef87a70c8c9cc23dbfee3Eric Laurent
6219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private void createAudioSystemThread() {
6229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mAudioSystemThread = new AudioSystemThread();
6239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mAudioSystemThread.start();
6249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        waitForAudioHandlerCreation();
6259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
6269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** Waits for the volume handler to be created by the other thread. */
6289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private void waitForAudioHandlerCreation() {
6299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        synchronized(this) {
6309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            while (mAudioHandler == null) {
6319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                try {
6329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    // Wait for mAudioHandler to be set by the other thread
6339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    wait();
6349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                } catch (InterruptedException e) {
6359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    Log.e(TAG, "Interrupted while waiting on volume handler.");
6369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
6379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
6389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
6399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
6409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
641244820185269991186d07068b92985624cede4a5Eric Laurent    private void checkAllAliasStreamVolumes() {
642244820185269991186d07068b92985624cede4a5Eric Laurent        int numStreamTypes = AudioSystem.getNumStreamTypes();
643244820185269991186d07068b92985624cede4a5Eric Laurent        for (int streamType = 0; streamType < numStreamTypes; streamType++) {
644244820185269991186d07068b92985624cede4a5Eric Laurent            if (streamType != mStreamVolumeAlias[streamType]) {
645244820185269991186d07068b92985624cede4a5Eric Laurent                mStreamStates[streamType].
64642b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                                    setAllIndexes(mStreamStates[mStreamVolumeAlias[streamType]]);
647244820185269991186d07068b92985624cede4a5Eric Laurent            }
648244820185269991186d07068b92985624cede4a5Eric Laurent            // apply stream volume
64942b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent            if (!mStreamStates[streamType].isMuted()) {
650244820185269991186d07068b92985624cede4a5Eric Laurent                mStreamStates[streamType].applyAllVolumes();
651244820185269991186d07068b92985624cede4a5Eric Laurent            }
652244820185269991186d07068b92985624cede4a5Eric Laurent        }
653244820185269991186d07068b92985624cede4a5Eric Laurent    }
654244820185269991186d07068b92985624cede4a5Eric Laurent
6559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private void createStreamStates() {
6569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int numStreamTypes = AudioSystem.getNumStreamTypes();
6579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        VolumeStreamState[] streams = mStreamStates = new VolumeStreamState[numStreamTypes];
6589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        for (int i = 0; i < numStreamTypes; i++) {
6606d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent            streams[i] = new VolumeStreamState(System.VOLUME_SETTINGS[mStreamVolumeAlias[i]], i);
6619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
6629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
663244820185269991186d07068b92985624cede4a5Eric Laurent        checkAllAliasStreamVolumes();
6649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
6659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
666bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent    private void dumpStreamStates(PrintWriter pw) {
667bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent        pw.println("\nStream volumes (device: index)");
668bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent        int numStreamTypes = AudioSystem.getNumStreamTypes();
669bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent        for (int i = 0; i < numStreamTypes; i++) {
670bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent            pw.println("- "+STREAM_NAMES[i]+":");
671bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent            mStreamStates[i].dump(pw);
672bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent            pw.println("");
673bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent        }
674dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent        pw.print("\n- mute affected streams = 0x");
675dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent        pw.println(Integer.toHexString(mMuteAffectedStreams));
676bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent    }
677bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent
6781af30c7ac480e5d335f267a3ac3b2e6c748ce240John Spurlock    /** @hide */
6791af30c7ac480e5d335f267a3ac3b2e6c748ce240John Spurlock    public static String streamToString(int stream) {
6801af30c7ac480e5d335f267a3ac3b2e6c748ce240John Spurlock        if (stream >= 0 && stream < STREAM_NAMES.length) return STREAM_NAMES[stream];
6811af30c7ac480e5d335f267a3ac3b2e6c748ce240John Spurlock        if (stream == AudioManager.USE_DEFAULT_STREAM_TYPE) return "USE_DEFAULT_STREAM_TYPE";
6821af30c7ac480e5d335f267a3ac3b2e6c748ce240John Spurlock        return "UNKNOWN_STREAM_" + stream;
6831af30c7ac480e5d335f267a3ac3b2e6c748ce240John Spurlock    }
6846d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent
6856d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent    private void updateStreamVolumeAlias(boolean updateVolumes) {
6866d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent        int dtmfStreamAlias;
6876d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent        if (mVoiceCapable) {
6886d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent            mStreamVolumeAlias = STREAM_VOLUME_ALIAS;
6896d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent            dtmfStreamAlias = AudioSystem.STREAM_RING;
6906d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent        } else {
6916d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent            mStreamVolumeAlias = STREAM_VOLUME_ALIAS_NON_VOICE;
6926d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent            dtmfStreamAlias = AudioSystem.STREAM_MUSIC;
6936d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent        }
6946d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent        if (isInCommunication()) {
6956d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent            dtmfStreamAlias = AudioSystem.STREAM_VOICE_CALL;
69624e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent            mRingerModeAffectedStreams &= ~(1 << AudioSystem.STREAM_DTMF);
69724e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent        } else {
69824e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent            mRingerModeAffectedStreams |= (1 << AudioSystem.STREAM_DTMF);
6996d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent        }
7006d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent        mStreamVolumeAlias[AudioSystem.STREAM_DTMF] = dtmfStreamAlias;
7016d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent        if (updateVolumes) {
70242b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent            mStreamStates[AudioSystem.STREAM_DTMF].setAllIndexes(mStreamStates[dtmfStreamAlias]);
70324e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent            // apply stream mute states according to new value of mRingerModeAffectedStreams
70424e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent            setRingerModeInt(getRingerMode(), false);
7056d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent            sendMsg(mAudioHandler,
7066d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent                    MSG_SET_ALL_VOLUMES,
7076d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent                    SENDMSG_QUEUE,
7086d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent                    0,
7096d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent                    0,
7106d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent                    mStreamStates[AudioSystem.STREAM_DTMF], 0);
7116d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent        }
7126d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent    }
7136d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent
7147ee1e4ff7346a278a6722108fbc1869240b3e866Eric Laurent    private void readDockAudioSettings(ContentResolver cr)
7157ee1e4ff7346a278a6722108fbc1869240b3e866Eric Laurent    {
7167ee1e4ff7346a278a6722108fbc1869240b3e866Eric Laurent        mDockAudioMediaEnabled = Settings.Global.getInt(
7175ba0ffa0237a5c300545e4c72591613c6e5b2ed9Eric Laurent                                        cr, Settings.Global.DOCK_AUDIO_MEDIA_ENABLED, 0) == 1;
7187ee1e4ff7346a278a6722108fbc1869240b3e866Eric Laurent
7197ee1e4ff7346a278a6722108fbc1869240b3e866Eric Laurent        if (mDockAudioMediaEnabled) {
7207ee1e4ff7346a278a6722108fbc1869240b3e866Eric Laurent            mBecomingNoisyIntentDevices |= AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET;
7217ee1e4ff7346a278a6722108fbc1869240b3e866Eric Laurent        } else {
7227ee1e4ff7346a278a6722108fbc1869240b3e866Eric Laurent            mBecomingNoisyIntentDevices &= ~AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET;
7237ee1e4ff7346a278a6722108fbc1869240b3e866Eric Laurent        }
7247ee1e4ff7346a278a6722108fbc1869240b3e866Eric Laurent
7257ee1e4ff7346a278a6722108fbc1869240b3e866Eric Laurent        sendMsg(mAudioHandler,
7267ee1e4ff7346a278a6722108fbc1869240b3e866Eric Laurent                MSG_SET_FORCE_USE,
7277ee1e4ff7346a278a6722108fbc1869240b3e866Eric Laurent                SENDMSG_QUEUE,
7287ee1e4ff7346a278a6722108fbc1869240b3e866Eric Laurent                AudioSystem.FOR_DOCK,
7297ee1e4ff7346a278a6722108fbc1869240b3e866Eric Laurent                mDockAudioMediaEnabled ?
7307ee1e4ff7346a278a6722108fbc1869240b3e866Eric Laurent                        AudioSystem.FORCE_ANALOG_DOCK : AudioSystem.FORCE_NONE,
7317ee1e4ff7346a278a6722108fbc1869240b3e866Eric Laurent                null,
7327ee1e4ff7346a278a6722108fbc1869240b3e866Eric Laurent                0);
7337ee1e4ff7346a278a6722108fbc1869240b3e866Eric Laurent    }
7347ee1e4ff7346a278a6722108fbc1869240b3e866Eric Laurent
7359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private void readPersistedSettings() {
7369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final ContentResolver cr = mContentResolver;
7379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
738bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent        int ringerModeFromSettings =
7398d9a1f66d9d3dbbd45a56d441a746ec11dba7645Jeff Sharkey                Settings.Global.getInt(
7408d9a1f66d9d3dbbd45a56d441a746ec11dba7645Jeff Sharkey                        cr, Settings.Global.MODE_RINGER, AudioManager.RINGER_MODE_NORMAL);
741bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent        int ringerMode = ringerModeFromSettings;
74272668b2c040b581b298b069f3b5af5ed7f212d89Eric Laurent        // sanity check in case the settings are restored from a device with incompatible
74372668b2c040b581b298b069f3b5af5ed7f212d89Eric Laurent        // ringer modes
744ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten        if (!AudioManager.isValidRingerMode(ringerMode)) {
745ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten            ringerMode = AudioManager.RINGER_MODE_NORMAL;
746bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent        }
747bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent        if ((ringerMode == AudioManager.RINGER_MODE_VIBRATE) && !mHasVibrator) {
748bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent            ringerMode = AudioManager.RINGER_MODE_SILENT;
749bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent        }
750bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent        if (ringerMode != ringerModeFromSettings) {
7518d9a1f66d9d3dbbd45a56d441a746ec11dba7645Jeff Sharkey            Settings.Global.putInt(cr, Settings.Global.MODE_RINGER, ringerMode);
752ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten        }
75383a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent        if (mUseFixedVolume) {
75483a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent            ringerMode = AudioManager.RINGER_MODE_NORMAL;
75583a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent        }
756ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten        synchronized(mSettingsLock) {
757ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten            mRingerMode = ringerMode;
7589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
759dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent            // System.VIBRATE_ON is not used any more but defaults for mVibrateSetting
760dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent            // are still needed while setVibrateSetting() and getVibrateSetting() are being
761dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent            // deprecated.
762dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent            mVibrateSetting = getValueForVibrateSetting(0,
763dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent                                            AudioManager.VIBRATE_TYPE_NOTIFICATION,
764dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent                                            mHasVibrator ? AudioManager.VIBRATE_SETTING_ONLY_SILENT
765dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent                                                            : AudioManager.VIBRATE_SETTING_OFF);
766dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent            mVibrateSetting = getValueForVibrateSetting(mVibrateSetting,
767dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent                                            AudioManager.VIBRATE_TYPE_RINGER,
768dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent                                            mHasVibrator ? AudioManager.VIBRATE_SETTING_ONLY_SILENT
769dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent                                                            : AudioManager.VIBRATE_SETTING_OFF);
770dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent
77124e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent            updateRingerModeAffectedStreams();
7727ee1e4ff7346a278a6722108fbc1869240b3e866Eric Laurent            readDockAudioSettings(cr);
773402f7f29634a9f68e7929be828a927a3e2f5efe9Eric Laurent        }
774c1d4166289ce016965d1147f7e8d37862ee347ecEric Laurent
775bc0fab1fc2db832ef86d8a33466ec4d68b103ca0Eric Laurent        mMuteAffectedStreams = System.getIntForUser(cr,
7769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                System.MUTE_STREAMS_AFFECTED,
777bc0fab1fc2db832ef86d8a33466ec4d68b103ca0Eric Laurent                ((1 << AudioSystem.STREAM_MUSIC)|
778bc0fab1fc2db832ef86d8a33466ec4d68b103ca0Eric Laurent                 (1 << AudioSystem.STREAM_RING)|
779bc0fab1fc2db832ef86d8a33466ec4d68b103ca0Eric Laurent                 (1 << AudioSystem.STREAM_SYSTEM)),
780bc0fab1fc2db832ef86d8a33466ec4d68b103ca0Eric Laurent                 UserHandle.USER_CURRENT);
7819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
782bc0fab1fc2db832ef86d8a33466ec4d68b103ca0Eric Laurent        boolean masterMute = System.getIntForUser(cr, System.VOLUME_MASTER_MUTE,
783bc0fab1fc2db832ef86d8a33466ec4d68b103ca0Eric Laurent                                                  0, UserHandle.USER_CURRENT) == 1;
78483a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent        if (mUseFixedVolume) {
78583a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent            masterMute = false;
78683a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent            AudioSystem.setMasterVolume(1.0f);
78783a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent        }
78857978ed86286a33d5b1a0fd000ca3406ba9d87b3Justin Koh        AudioSystem.setMasterMute(masterMute);
78957978ed86286a33d5b1a0fd000ca3406ba9d87b3Justin Koh        broadcastMasterMuteStatus(masterMute);
79057978ed86286a33d5b1a0fd000ca3406ba9d87b3Justin Koh
7919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // Each stream will read its own persisted settings
7929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // Broadcast the sticky intent
794ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten        broadcastRingerMode(ringerMode);
7959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // Broadcast vibrate settings
7979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        broadcastVibrateSetting(AudioManager.VIBRATE_TYPE_RINGER);
7989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        broadcastVibrateSetting(AudioManager.VIBRATE_TYPE_NOTIFICATION);
799d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi
800d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi        // Restore the default media button receiver from the system settings
801fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        mMediaFocusControl.restoreMediaButtonReceiver();
8029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
8039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
804a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent    private int rescaleIndex(int index, int srcStream, int dstStream) {
805a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent        return (index * mStreamStates[dstStream].getMaxIndex() + mStreamStates[srcStream].getMaxIndex() / 2) / mStreamStates[srcStream].getMaxIndex();
806a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent    }
8079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    ///////////////////////////////////////////////////////////////////////////
8099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // IPC methods
8109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    ///////////////////////////////////////////////////////////////////////////
811fca1e603236b8d1681f784e77e3719d1d59c1428Jean-Michel Trivi    /** @see AudioManager#isLocalOrRemoteMusicActive() */
812fca1e603236b8d1681f784e77e3719d1d59c1428Jean-Michel Trivi    public boolean isLocalOrRemoteMusicActive() {
813fca1e603236b8d1681f784e77e3719d1d59c1428Jean-Michel Trivi        if (AudioSystem.isStreamActive(AudioSystem.STREAM_MUSIC, 0)) {
814fca1e603236b8d1681f784e77e3719d1d59c1428Jean-Michel Trivi            // local / wired / BT playback active
815fca1e603236b8d1681f784e77e3719d1d59c1428Jean-Michel Trivi            if (DEBUG_VOL) Log.d(TAG, "isLocalOrRemoteMusicActive(): local");
816fca1e603236b8d1681f784e77e3719d1d59c1428Jean-Michel Trivi            return true;
817fca1e603236b8d1681f784e77e3719d1d59c1428Jean-Michel Trivi        }
818fca1e603236b8d1681f784e77e3719d1d59c1428Jean-Michel Trivi        if (mMediaFocusControl.checkUpdateRemoteStateIfActive(AudioSystem.STREAM_MUSIC)) {
819fca1e603236b8d1681f784e77e3719d1d59c1428Jean-Michel Trivi            // remote "cast-like" playback active
820fca1e603236b8d1681f784e77e3719d1d59c1428Jean-Michel Trivi            if (DEBUG_VOL) Log.d(TAG, "isLocalOrRemoteMusicActive(): has PLAYBACK_TYPE_REMOTE");
821fca1e603236b8d1681f784e77e3719d1d59c1428Jean-Michel Trivi            return true;
822fca1e603236b8d1681f784e77e3719d1d59c1428Jean-Michel Trivi        }
823fca1e603236b8d1681f784e77e3719d1d59c1428Jean-Michel Trivi        if (AudioSystem.isStreamActiveRemotely(AudioSystem.STREAM_MUSIC, 0)) {
824fca1e603236b8d1681f784e77e3719d1d59c1428Jean-Michel Trivi            // remote submix playback active
825fca1e603236b8d1681f784e77e3719d1d59c1428Jean-Michel Trivi            if (DEBUG_VOL) Log.d(TAG, "isLocalOrRemoteMusicActive(): remote submix");
826fca1e603236b8d1681f784e77e3719d1d59c1428Jean-Michel Trivi            return true;
827fca1e603236b8d1681f784e77e3719d1d59c1428Jean-Michel Trivi        }
828fca1e603236b8d1681f784e77e3719d1d59c1428Jean-Michel Trivi        if (DEBUG_VOL) Log.d(TAG, "isLocalOrRemoteMusicActive(): no");
829fca1e603236b8d1681f784e77e3719d1d59c1428Jean-Michel Trivi        return false;
830fca1e603236b8d1681f784e77e3719d1d59c1428Jean-Michel Trivi    }
8319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** @see AudioManager#adjustVolume(int, int) */
833ba50b97cff80e73620a0e3d13cae169e095974a7Dianne Hackborn    public void adjustSuggestedStreamVolume(int direction, int suggestedStreamType, int flags,
834ba50b97cff80e73620a0e3d13cae169e095974a7Dianne Hackborn            String callingPackage) {
8353114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        if (DEBUG_VOL) Log.d(TAG, "adjustSuggestedStreamVolume() stream="+suggestedStreamType);
836402f7f29634a9f68e7929be828a927a3e2f5efe9Eric Laurent        int streamType;
83745c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent        if (mVolumeControlStream != -1) {
83845c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent            streamType = mVolumeControlStream;
839402f7f29634a9f68e7929be828a927a3e2f5efe9Eric Laurent        } else {
840402f7f29634a9f68e7929be828a927a3e2f5efe9Eric Laurent            streamType = getActiveStreamType(suggestedStreamType);
841402f7f29634a9f68e7929be828a927a3e2f5efe9Eric Laurent        }
8429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8436243edd818b84adfbe712d5d233d6414b33653acAmith Yamasani        // Play sounds on STREAM_RING only and if lock screen is not on.
8443114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        if ((streamType != STREAM_REMOTE_MUSIC) &&
8453114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                (flags & AudioManager.FLAG_PLAY_SOUND) != 0 &&
8466d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent                ((mStreamVolumeAlias[streamType] != AudioSystem.STREAM_RING)
8476243edd818b84adfbe712d5d233d6414b33653acAmith Yamasani                 || (mKeyguardManager != null && mKeyguardManager.isKeyguardLocked()))) {
8489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            flags &= ~AudioManager.FLAG_PLAY_SOUND;
8499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
8509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8513114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        if (streamType == STREAM_REMOTE_MUSIC) {
85219c9518f6a817d53d5234de0020313cab6950b2fRoboErik            // TODO bounce it to MediaSessionService to find an appropriate
85319c9518f6a817d53d5234de0020313cab6950b2fRoboErik            // session
8543114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        } else {
855ba50b97cff80e73620a0e3d13cae169e095974a7Dianne Hackborn            adjustStreamVolume(streamType, direction, flags, callingPackage);
8563114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        }
8579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
8589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** @see AudioManager#adjustStreamVolume(int, int, int) */
860ba50b97cff80e73620a0e3d13cae169e095974a7Dianne Hackborn    public void adjustStreamVolume(int streamType, int direction, int flags,
861ba50b97cff80e73620a0e3d13cae169e095974a7Dianne Hackborn            String callingPackage) {
86283a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent        if (mUseFixedVolume) {
86383a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent            return;
86483a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent        }
8653114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        if (DEBUG_VOL) Log.d(TAG, "adjustStreamVolume() stream="+streamType+", dir="+direction);
8663114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi
8679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        ensureValidDirection(direction);
8689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        ensureValidStreamType(streamType);
8699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
87096a33d1caad2fab0bc28891cfbf553f4b050bf0bEric Laurent        // use stream type alias here so that streams with same alias have the same behavior,
87196a33d1caad2fab0bc28891cfbf553f4b050bf0bEric Laurent        // including with regard to silent mode control (e.g the use of STREAM_RING below and in
87296a33d1caad2fab0bc28891cfbf553f4b050bf0bEric Laurent        // checkForRingerModeChange() in place of STREAM_RING or STREAM_NOTIFICATION)
8736d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent        int streamTypeAlias = mStreamVolumeAlias[streamType];
874b024c30a80684ac08daef3137b7ba0d347fe3ce5Eric Laurent        VolumeStreamState streamState = mStreamStates[streamTypeAlias];
8759bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent
8769bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent        final int device = getDeviceForStream(streamTypeAlias);
8773ef7549876a159dae1568429edcb57e4e7d08459Eric Laurent
87842b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent        int aliasIndex = streamState.getIndex(device);
8799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        boolean adjustVolume = true;
8803ef7549876a159dae1568429edcb57e4e7d08459Eric Laurent        int step;
881244820185269991186d07068b92985624cede4a5Eric Laurent
882c9d1d5f35091226e96fcfa91817480f589eb36e2Matthew Xie        // skip a2dp absolute volume control request when the device
883c9d1d5f35091226e96fcfa91817480f589eb36e2Matthew Xie        // is not an a2dp device
884c9d1d5f35091226e96fcfa91817480f589eb36e2Matthew Xie        if ((device & AudioSystem.DEVICE_OUT_ALL_A2DP) == 0 &&
885c9d1d5f35091226e96fcfa91817480f589eb36e2Matthew Xie            (flags & AudioManager.FLAG_BLUETOOTH_ABS_VOLUME) != 0) {
886c9d1d5f35091226e96fcfa91817480f589eb36e2Matthew Xie            return;
887c9d1d5f35091226e96fcfa91817480f589eb36e2Matthew Xie        }
888c9d1d5f35091226e96fcfa91817480f589eb36e2Matthew Xie
889ba50b97cff80e73620a0e3d13cae169e095974a7Dianne Hackborn        if (mAppOps.noteOp(STEAM_VOLUME_OPS[streamTypeAlias], Binder.getCallingUid(),
890ba50b97cff80e73620a0e3d13cae169e095974a7Dianne Hackborn                callingPackage) != AppOpsManager.MODE_ALLOWED) {
891ba50b97cff80e73620a0e3d13cae169e095974a7Dianne Hackborn            return;
892ba50b97cff80e73620a0e3d13cae169e095974a7Dianne Hackborn        }
893ba50b97cff80e73620a0e3d13cae169e095974a7Dianne Hackborn
894fde16d5879ea88a971004c984093409468b6139cEric Laurent        // reset any pending volume command
895fde16d5879ea88a971004c984093409468b6139cEric Laurent        synchronized (mSafeMediaVolumeState) {
896fde16d5879ea88a971004c984093409468b6139cEric Laurent            mPendingVolumeCommand = null;
897fde16d5879ea88a971004c984093409468b6139cEric Laurent        }
898fde16d5879ea88a971004c984093409468b6139cEric Laurent
8993ef7549876a159dae1568429edcb57e4e7d08459Eric Laurent        flags &= ~AudioManager.FLAG_FIXED_VOLUME;
9003ef7549876a159dae1568429edcb57e4e7d08459Eric Laurent        if ((streamTypeAlias == AudioSystem.STREAM_MUSIC) &&
9013ef7549876a159dae1568429edcb57e4e7d08459Eric Laurent               ((device & mFixedVolumeDevices) != 0)) {
9023ef7549876a159dae1568429edcb57e4e7d08459Eric Laurent            flags |= AudioManager.FLAG_FIXED_VOLUME;
9033ef7549876a159dae1568429edcb57e4e7d08459Eric Laurent
9043ef7549876a159dae1568429edcb57e4e7d08459Eric Laurent            // Always toggle between max safe volume and 0 for fixed volume devices where safe
9053ef7549876a159dae1568429edcb57e4e7d08459Eric Laurent            // volume is enforced, and max and 0 for the others.
9063ef7549876a159dae1568429edcb57e4e7d08459Eric Laurent            // This is simulated by stepping by the full allowed volume range
9073ef7549876a159dae1568429edcb57e4e7d08459Eric Laurent            if (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_ACTIVE &&
9083ef7549876a159dae1568429edcb57e4e7d08459Eric Laurent                    (device & mSafeMediaVolumeDevices) != 0) {
9093ef7549876a159dae1568429edcb57e4e7d08459Eric Laurent                step = mSafeMediaVolumeIndex;
9103ef7549876a159dae1568429edcb57e4e7d08459Eric Laurent            } else {
9113ef7549876a159dae1568429edcb57e4e7d08459Eric Laurent                step = streamState.getMaxIndex();
9123ef7549876a159dae1568429edcb57e4e7d08459Eric Laurent            }
9133ef7549876a159dae1568429edcb57e4e7d08459Eric Laurent            if (aliasIndex != 0) {
9143ef7549876a159dae1568429edcb57e4e7d08459Eric Laurent                aliasIndex = step;
9153ef7549876a159dae1568429edcb57e4e7d08459Eric Laurent            }
9163ef7549876a159dae1568429edcb57e4e7d08459Eric Laurent        } else {
9173ef7549876a159dae1568429edcb57e4e7d08459Eric Laurent            // convert one UI step (+/-1) into a number of internal units on the stream alias
9183ef7549876a159dae1568429edcb57e4e7d08459Eric Laurent            step = rescaleIndex(10, streamType, streamTypeAlias);
9193ef7549876a159dae1568429edcb57e4e7d08459Eric Laurent        }
9203ef7549876a159dae1568429edcb57e4e7d08459Eric Laurent
92142b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent        // If either the client forces allowing ringer modes for this adjustment,
92242b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent        // or the stream type is one that is affected by ringer modes
92342b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent        if (((flags & AudioManager.FLAG_ALLOW_RINGER_MODES) != 0) ||
92442b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                (streamTypeAlias == getMasterStreamType())) {
92542b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent            int ringerMode = getRingerMode();
92642b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent            // do not vibrate if already in vibrate mode
92742b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent            if (ringerMode == AudioManager.RINGER_MODE_VIBRATE) {
92842b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                flags &= ~AudioManager.FLAG_VIBRATE;
92942b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent            }
93042b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent            // Check if the ringer mode changes with this volume adjustment. If
93142b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent            // it does, it will handle adjusting the volume, so we won't below
932a11b4affcad3d255aa723a89b768ea222506f2e8John Spurlock            final int result = checkForRingerModeChange(aliasIndex, direction, step);
933a11b4affcad3d255aa723a89b768ea222506f2e8John Spurlock            adjustVolume = (result & FLAG_ADJUST_VOLUME) != 0;
934a11b4affcad3d255aa723a89b768ea222506f2e8John Spurlock            // If suppressing a volume adjustment in silent mode, display the UI hint
935a11b4affcad3d255aa723a89b768ea222506f2e8John Spurlock            if ((result & AudioManager.FLAG_SHOW_SILENT_HINT) != 0) {
936a11b4affcad3d255aa723a89b768ea222506f2e8John Spurlock                flags |= AudioManager.FLAG_SHOW_SILENT_HINT;
937a11b4affcad3d255aa723a89b768ea222506f2e8John Spurlock            }
93842b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent        }
93942b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent
94042b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent        int oldIndex = mStreamStates[streamType].getIndex(device);
94142b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent
94242b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent        if (adjustVolume && (direction != AudioManager.ADJUST_SAME)) {
943c9d1d5f35091226e96fcfa91817480f589eb36e2Matthew Xie
9445a0cf7a27f3953a1266af48543ccd9024f4cd89fJohn Du            // Check if volume update should be send to AVRCP
945c9d1d5f35091226e96fcfa91817480f589eb36e2Matthew Xie            if (streamTypeAlias == AudioSystem.STREAM_MUSIC &&
946c9d1d5f35091226e96fcfa91817480f589eb36e2Matthew Xie                (device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0 &&
947c9d1d5f35091226e96fcfa91817480f589eb36e2Matthew Xie                (flags & AudioManager.FLAG_BLUETOOTH_ABS_VOLUME) == 0) {
948c9d1d5f35091226e96fcfa91817480f589eb36e2Matthew Xie                synchronized (mA2dpAvrcpLock) {
949c9d1d5f35091226e96fcfa91817480f589eb36e2Matthew Xie                    if (mA2dp != null && mAvrcpAbsVolSupported) {
950c9d1d5f35091226e96fcfa91817480f589eb36e2Matthew Xie                        mA2dp.adjustAvrcpAbsoluteVolume(direction);
951c9d1d5f35091226e96fcfa91817480f589eb36e2Matthew Xie                    }
9525a0cf7a27f3953a1266af48543ccd9024f4cd89fJohn Du                }
9535a0cf7a27f3953a1266af48543ccd9024f4cd89fJohn Du            }
954c9d1d5f35091226e96fcfa91817480f589eb36e2Matthew Xie
95542b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent            if ((direction == AudioManager.ADJUST_RAISE) &&
95642b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                    !checkSafeMediaVolume(streamTypeAlias, aliasIndex + step, device)) {
95742b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                Log.e(TAG, "adjustStreamVolume() safe volume index = "+oldIndex);
9583346a802087f621c6441bc512dfcc17b07143fc6John Spurlock                mVolumeController.postDisplaySafeVolumeWarning(flags);
95942b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent            } else if (streamState.adjustIndex(direction * step, device)) {
96042b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                // Post message to set system volume (it in turn will post a message
96142b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                // to persist). Do not change volume if stream is muted.
96242b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                sendMsg(mAudioHandler,
96342b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                        MSG_SET_DEVICE_VOLUME,
96442b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                        SENDMSG_QUEUE,
96542b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                        device,
96642b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                        0,
96742b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                        streamState,
96842b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                        0);
9694bbcc6549738f3d69831b2bd9eb4accec3e9920eEric Laurent            }
9704bbcc6549738f3d69831b2bd9eb4accec3e9920eEric Laurent        }
97142b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent        int index = mStreamStates[streamType].getIndex(device);
97225101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent        sendVolumeUpdate(streamType, oldIndex, index, flags);
9739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
9749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
975961cae92540763226648813d111c5b5c3b0f1597Dianne Hackborn    /** @see AudioManager#adjustMasterVolume(int, int) */
976ba50b97cff80e73620a0e3d13cae169e095974a7Dianne Hackborn    public void adjustMasterVolume(int steps, int flags, String callingPackage) {
97783a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent        if (mUseFixedVolume) {
97883a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent            return;
97983a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent        }
9806c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang        ensureValidSteps(steps);
9819760647dd0ee67e7c20f3e9d661d2006b1df0b54Mike Lockwood        int volume = Math.round(AudioSystem.getMasterVolume() * MAX_MASTER_VOLUME);
9829760647dd0ee67e7c20f3e9d661d2006b1df0b54Mike Lockwood        int delta = 0;
9836c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang        int numSteps = Math.abs(steps);
9846c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang        int direction = steps > 0 ? AudioManager.ADJUST_RAISE : AudioManager.ADJUST_LOWER;
9856c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang        for (int i = 0; i < numSteps; ++i) {
9866c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang            delta = findVolumeDelta(direction, volume);
9876c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang            volume += delta;
988cbdb49dc5e1b993a0bc5c68dbfb9486bfa0cd762Mike Lockwood        }
98924b082f87e96c00d5c17d60c735423900be40e70RoboErik
9906c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang        //Log.d(TAG, "adjustMasterVolume volume: " + volume + " steps: " + steps);
991ba50b97cff80e73620a0e3d13cae169e095974a7Dianne Hackborn        setMasterVolume(volume, flags, callingPackage);
992cbdb49dc5e1b993a0bc5c68dbfb9486bfa0cd762Mike Lockwood    }
993cbdb49dc5e1b993a0bc5c68dbfb9486bfa0cd762Mike Lockwood
994fde16d5879ea88a971004c984093409468b6139cEric Laurent    // StreamVolumeCommand contains the information needed to defer the process of
995fde16d5879ea88a971004c984093409468b6139cEric Laurent    // setStreamVolume() in case the user has to acknowledge the safe volume warning message.
996fde16d5879ea88a971004c984093409468b6139cEric Laurent    class StreamVolumeCommand {
997fde16d5879ea88a971004c984093409468b6139cEric Laurent        public final int mStreamType;
998fde16d5879ea88a971004c984093409468b6139cEric Laurent        public final int mIndex;
999fde16d5879ea88a971004c984093409468b6139cEric Laurent        public final int mFlags;
1000fde16d5879ea88a971004c984093409468b6139cEric Laurent        public final int mDevice;
10013ef7549876a159dae1568429edcb57e4e7d08459Eric Laurent
1002fde16d5879ea88a971004c984093409468b6139cEric Laurent        StreamVolumeCommand(int streamType, int index, int flags, int device) {
1003fde16d5879ea88a971004c984093409468b6139cEric Laurent            mStreamType = streamType;
1004fde16d5879ea88a971004c984093409468b6139cEric Laurent            mIndex = index;
1005fde16d5879ea88a971004c984093409468b6139cEric Laurent            mFlags = flags;
1006fde16d5879ea88a971004c984093409468b6139cEric Laurent            mDevice = device;
10074bbcc6549738f3d69831b2bd9eb4accec3e9920eEric Laurent        }
1008fde16d5879ea88a971004c984093409468b6139cEric Laurent    };
10093ef7549876a159dae1568429edcb57e4e7d08459Eric Laurent
1010fde16d5879ea88a971004c984093409468b6139cEric Laurent    private void onSetStreamVolume(int streamType, int index, int flags, int device) {
101142b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent        setStreamVolumeInt(mStreamVolumeAlias[streamType], index, device, false);
10123ef7549876a159dae1568429edcb57e4e7d08459Eric Laurent        // setting volume on master stream type also controls silent mode
10133ef7549876a159dae1568429edcb57e4e7d08459Eric Laurent        if (((flags & AudioManager.FLAG_ALLOW_RINGER_MODES) != 0) ||
10143ef7549876a159dae1568429edcb57e4e7d08459Eric Laurent                (mStreamVolumeAlias[streamType] == getMasterStreamType())) {
10153ef7549876a159dae1568429edcb57e4e7d08459Eric Laurent            int newRingerMode;
10163ef7549876a159dae1568429edcb57e4e7d08459Eric Laurent            if (index == 0) {
10173ef7549876a159dae1568429edcb57e4e7d08459Eric Laurent                newRingerMode = mHasVibrator ? AudioManager.RINGER_MODE_VIBRATE
10188600534df66c2ff5846ed230b50c56229322d48aJohn Spurlock                        : VOLUME_SETS_RINGER_MODE_SILENT ? AudioManager.RINGER_MODE_SILENT
10198600534df66c2ff5846ed230b50c56229322d48aJohn Spurlock                        : AudioManager.RINGER_MODE_NORMAL;
10203ef7549876a159dae1568429edcb57e4e7d08459Eric Laurent            } else {
10213ef7549876a159dae1568429edcb57e4e7d08459Eric Laurent                newRingerMode = AudioManager.RINGER_MODE_NORMAL;
10223ef7549876a159dae1568429edcb57e4e7d08459Eric Laurent            }
10233ef7549876a159dae1568429edcb57e4e7d08459Eric Laurent            setRingerMode(newRingerMode);
10243ef7549876a159dae1568429edcb57e4e7d08459Eric Laurent        }
1025fde16d5879ea88a971004c984093409468b6139cEric Laurent    }
1026fde16d5879ea88a971004c984093409468b6139cEric Laurent
1027fde16d5879ea88a971004c984093409468b6139cEric Laurent    /** @see AudioManager#setStreamVolume(int, int, int) */
1028ba50b97cff80e73620a0e3d13cae169e095974a7Dianne Hackborn    public void setStreamVolume(int streamType, int index, int flags, String callingPackage) {
102983a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent        if (mUseFixedVolume) {
103083a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent            return;
103183a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent        }
103283a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent
1033fde16d5879ea88a971004c984093409468b6139cEric Laurent        ensureValidStreamType(streamType);
1034ba50b97cff80e73620a0e3d13cae169e095974a7Dianne Hackborn        int streamTypeAlias = mStreamVolumeAlias[streamType];
1035ba50b97cff80e73620a0e3d13cae169e095974a7Dianne Hackborn        VolumeStreamState streamState = mStreamStates[streamTypeAlias];
1036fde16d5879ea88a971004c984093409468b6139cEric Laurent
1037fde16d5879ea88a971004c984093409468b6139cEric Laurent        final int device = getDeviceForStream(streamType);
1038fde16d5879ea88a971004c984093409468b6139cEric Laurent        int oldIndex;
1039fde16d5879ea88a971004c984093409468b6139cEric Laurent
1040c9d1d5f35091226e96fcfa91817480f589eb36e2Matthew Xie        // skip a2dp absolute volume control request when the device
1041c9d1d5f35091226e96fcfa91817480f589eb36e2Matthew Xie        // is not an a2dp device
1042c9d1d5f35091226e96fcfa91817480f589eb36e2Matthew Xie        if ((device & AudioSystem.DEVICE_OUT_ALL_A2DP) == 0 &&
1043c9d1d5f35091226e96fcfa91817480f589eb36e2Matthew Xie            (flags & AudioManager.FLAG_BLUETOOTH_ABS_VOLUME) != 0) {
1044c9d1d5f35091226e96fcfa91817480f589eb36e2Matthew Xie            return;
1045c9d1d5f35091226e96fcfa91817480f589eb36e2Matthew Xie        }
1046c9d1d5f35091226e96fcfa91817480f589eb36e2Matthew Xie
1047ba50b97cff80e73620a0e3d13cae169e095974a7Dianne Hackborn        if (mAppOps.noteOp(STEAM_VOLUME_OPS[streamTypeAlias], Binder.getCallingUid(),
1048ba50b97cff80e73620a0e3d13cae169e095974a7Dianne Hackborn                callingPackage) != AppOpsManager.MODE_ALLOWED) {
1049ba50b97cff80e73620a0e3d13cae169e095974a7Dianne Hackborn            return;
1050ba50b97cff80e73620a0e3d13cae169e095974a7Dianne Hackborn        }
1051ba50b97cff80e73620a0e3d13cae169e095974a7Dianne Hackborn
1052fde16d5879ea88a971004c984093409468b6139cEric Laurent        synchronized (mSafeMediaVolumeState) {
1053fde16d5879ea88a971004c984093409468b6139cEric Laurent            // reset any pending volume command
1054fde16d5879ea88a971004c984093409468b6139cEric Laurent            mPendingVolumeCommand = null;
1055fde16d5879ea88a971004c984093409468b6139cEric Laurent
105642b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent            oldIndex = streamState.getIndex(device);
1057fde16d5879ea88a971004c984093409468b6139cEric Laurent
1058ba50b97cff80e73620a0e3d13cae169e095974a7Dianne Hackborn            index = rescaleIndex(index * 10, streamType, streamTypeAlias);
1059fde16d5879ea88a971004c984093409468b6139cEric Laurent
1060c9d1d5f35091226e96fcfa91817480f589eb36e2Matthew Xie            if (streamTypeAlias == AudioSystem.STREAM_MUSIC &&
1061c9d1d5f35091226e96fcfa91817480f589eb36e2Matthew Xie                (device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0 &&
1062c9d1d5f35091226e96fcfa91817480f589eb36e2Matthew Xie                (flags & AudioManager.FLAG_BLUETOOTH_ABS_VOLUME) == 0) {
1063c9d1d5f35091226e96fcfa91817480f589eb36e2Matthew Xie                synchronized (mA2dpAvrcpLock) {
1064c9d1d5f35091226e96fcfa91817480f589eb36e2Matthew Xie                    if (mA2dp != null && mAvrcpAbsVolSupported) {
10652f4a2b139b4c1dde7be1d14333ad02553734c528Zhihai Xu                        mA2dp.setAvrcpAbsoluteVolume(index / 10);
1066c9d1d5f35091226e96fcfa91817480f589eb36e2Matthew Xie                    }
10675a0cf7a27f3953a1266af48543ccd9024f4cd89fJohn Du                }
10685a0cf7a27f3953a1266af48543ccd9024f4cd89fJohn Du            }
10695a0cf7a27f3953a1266af48543ccd9024f4cd89fJohn Du
1070fde16d5879ea88a971004c984093409468b6139cEric Laurent            flags &= ~AudioManager.FLAG_FIXED_VOLUME;
1071ba50b97cff80e73620a0e3d13cae169e095974a7Dianne Hackborn            if ((streamTypeAlias == AudioSystem.STREAM_MUSIC) &&
1072fde16d5879ea88a971004c984093409468b6139cEric Laurent                    ((device & mFixedVolumeDevices) != 0)) {
1073fde16d5879ea88a971004c984093409468b6139cEric Laurent                flags |= AudioManager.FLAG_FIXED_VOLUME;
1074fde16d5879ea88a971004c984093409468b6139cEric Laurent
1075fde16d5879ea88a971004c984093409468b6139cEric Laurent                // volume is either 0 or max allowed for fixed volume devices
1076fde16d5879ea88a971004c984093409468b6139cEric Laurent                if (index != 0) {
1077fde16d5879ea88a971004c984093409468b6139cEric Laurent                    if (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_ACTIVE &&
1078fde16d5879ea88a971004c984093409468b6139cEric Laurent                            (device & mSafeMediaVolumeDevices) != 0) {
1079fde16d5879ea88a971004c984093409468b6139cEric Laurent                        index = mSafeMediaVolumeIndex;
1080fde16d5879ea88a971004c984093409468b6139cEric Laurent                    } else {
1081fde16d5879ea88a971004c984093409468b6139cEric Laurent                        index = streamState.getMaxIndex();
1082fde16d5879ea88a971004c984093409468b6139cEric Laurent                    }
1083fde16d5879ea88a971004c984093409468b6139cEric Laurent                }
1084fde16d5879ea88a971004c984093409468b6139cEric Laurent            }
1085fde16d5879ea88a971004c984093409468b6139cEric Laurent
1086ba50b97cff80e73620a0e3d13cae169e095974a7Dianne Hackborn            if (!checkSafeMediaVolume(streamTypeAlias, index, device)) {
10873346a802087f621c6441bc512dfcc17b07143fc6John Spurlock                mVolumeController.postDisplaySafeVolumeWarning(flags);
1088fde16d5879ea88a971004c984093409468b6139cEric Laurent                mPendingVolumeCommand = new StreamVolumeCommand(
1089fde16d5879ea88a971004c984093409468b6139cEric Laurent                                                    streamType, index, flags, device);
1090fde16d5879ea88a971004c984093409468b6139cEric Laurent            } else {
1091fde16d5879ea88a971004c984093409468b6139cEric Laurent                onSetStreamVolume(streamType, index, flags, device);
109242b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                index = mStreamStates[streamType].getIndex(device);
1093fde16d5879ea88a971004c984093409468b6139cEric Laurent            }
1094fde16d5879ea88a971004c984093409468b6139cEric Laurent        }
109525101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent        sendVolumeUpdate(streamType, oldIndex, index, flags);
10969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
10979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
109845c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent    /** @see AudioManager#forceVolumeControlStream(int) */
109945c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent    public void forceVolumeControlStream(int streamType, IBinder cb) {
110045c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent        synchronized(mForceControlStreamLock) {
110145c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent            mVolumeControlStream = streamType;
110245c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent            if (mVolumeControlStream == -1) {
110345c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent                if (mForceControlStreamClient != null) {
110445c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent                    mForceControlStreamClient.release();
110545c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent                    mForceControlStreamClient = null;
110645c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent                }
110745c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent            } else {
110845c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent                mForceControlStreamClient = new ForceControlStreamClient(cb);
110945c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent            }
111045c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent        }
111145c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent    }
111245c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent
111345c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent    private class ForceControlStreamClient implements IBinder.DeathRecipient {
111445c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent        private IBinder mCb; // To be notified of client's death
111545c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent
111645c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent        ForceControlStreamClient(IBinder cb) {
111745c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent            if (cb != null) {
111845c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent                try {
111945c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent                    cb.linkToDeath(this, 0);
112045c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent                } catch (RemoteException e) {
112145c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent                    // Client has died!
112245c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent                    Log.w(TAG, "ForceControlStreamClient() could not link to "+cb+" binder death");
112345c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent                    cb = null;
112445c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent                }
112545c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent            }
112645c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent            mCb = cb;
112745c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent        }
112845c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent
112945c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent        public void binderDied() {
113045c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent            synchronized(mForceControlStreamLock) {
113145c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent                Log.w(TAG, "SCO client died");
113245c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent                if (mForceControlStreamClient != this) {
113345c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent                    Log.w(TAG, "unregistered control stream client died");
113445c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent                } else {
113545c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent                    mForceControlStreamClient = null;
113645c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent                    mVolumeControlStream = -1;
113745c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent                }
113845c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent            }
113945c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent        }
114045c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent
114145c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent        public void release() {
114245c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent            if (mCb != null) {
114345c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent                mCb.unlinkToDeath(this, 0);
114445c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent                mCb = null;
114545c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent            }
114645c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent        }
114745c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent    }
114845c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent
11496c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang    private int findVolumeDelta(int direction, int volume) {
11506c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang        int delta = 0;
11516c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang        if (direction == AudioManager.ADJUST_RAISE) {
11526c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang            if (volume == MAX_MASTER_VOLUME) {
11536c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang                return 0;
11546c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang            }
11556c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang            // This is the default value if we make it to the end
11566c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang            delta = mMasterVolumeRamp[1];
11576c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang            // If we're raising the volume move down the ramp array until we
11586c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang            // find the volume we're above and use that groups delta.
11596c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang            for (int i = mMasterVolumeRamp.length - 1; i > 1; i -= 2) {
11606c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang                if (volume >= mMasterVolumeRamp[i - 1]) {
11616c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang                    delta = mMasterVolumeRamp[i];
11626c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang                    break;
11636c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang                }
11646c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang            }
11656c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang        } else if (direction == AudioManager.ADJUST_LOWER){
11666c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang            if (volume == 0) {
11676c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang                return 0;
11686c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang            }
11696c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang            int length = mMasterVolumeRamp.length;
11706c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang            // This is the default value if we make it to the end
11716c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang            delta = -mMasterVolumeRamp[length - 1];
11726c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang            // If we're lowering the volume move up the ramp array until we
11736c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang            // find the volume we're below and use the group below it's delta
11746c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang            for (int i = 2; i < length; i += 2) {
11756c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang                if (volume <= mMasterVolumeRamp[i]) {
11766c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang                    delta = -mMasterVolumeRamp[i - 1];
11776c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang                    break;
11786c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang                }
11796c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang            }
11806c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang        }
11816c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang        return delta;
11826c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang    }
11836c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang
11845ac72a29593ab9a20337a2225df52bdf4754be02Dianne Hackborn    private void sendBroadcastToAll(Intent intent) {
11855ac72a29593ab9a20337a2225df52bdf4754be02Dianne Hackborn        final long ident = Binder.clearCallingIdentity();
11865ac72a29593ab9a20337a2225df52bdf4754be02Dianne Hackborn        try {
11875ac72a29593ab9a20337a2225df52bdf4754be02Dianne Hackborn            mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
11885ac72a29593ab9a20337a2225df52bdf4754be02Dianne Hackborn        } finally {
11895ac72a29593ab9a20337a2225df52bdf4754be02Dianne Hackborn            Binder.restoreCallingIdentity(ident);
11905ac72a29593ab9a20337a2225df52bdf4754be02Dianne Hackborn        }
11915ac72a29593ab9a20337a2225df52bdf4754be02Dianne Hackborn    }
11925ac72a29593ab9a20337a2225df52bdf4754be02Dianne Hackborn
11935ac72a29593ab9a20337a2225df52bdf4754be02Dianne Hackborn    private void sendStickyBroadcastToAll(Intent intent) {
11945ac72a29593ab9a20337a2225df52bdf4754be02Dianne Hackborn        final long ident = Binder.clearCallingIdentity();
11955ac72a29593ab9a20337a2225df52bdf4754be02Dianne Hackborn        try {
11965ac72a29593ab9a20337a2225df52bdf4754be02Dianne Hackborn            mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
11975ac72a29593ab9a20337a2225df52bdf4754be02Dianne Hackborn        } finally {
11985ac72a29593ab9a20337a2225df52bdf4754be02Dianne Hackborn            Binder.restoreCallingIdentity(ident);
11995ac72a29593ab9a20337a2225df52bdf4754be02Dianne Hackborn        }
12005ac72a29593ab9a20337a2225df52bdf4754be02Dianne Hackborn    }
12015ac72a29593ab9a20337a2225df52bdf4754be02Dianne Hackborn
120225101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent    // UI update and Broadcast Intent
120325101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent    private void sendVolumeUpdate(int streamType, int oldIndex, int index, int flags) {
120425101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent        if (!mVoiceCapable && (streamType == AudioSystem.STREAM_RING)) {
120525101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent            streamType = AudioSystem.STREAM_NOTIFICATION;
120625101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent        }
120725101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent
12083346a802087f621c6441bc512dfcc17b07143fc6John Spurlock        mVolumeController.postVolumeChanged(streamType, flags);
120925101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent
12104bbcc6549738f3d69831b2bd9eb4accec3e9920eEric Laurent        if ((flags & AudioManager.FLAG_FIXED_VOLUME) == 0) {
12114bbcc6549738f3d69831b2bd9eb4accec3e9920eEric Laurent            oldIndex = (oldIndex + 5) / 10;
12124bbcc6549738f3d69831b2bd9eb4accec3e9920eEric Laurent            index = (index + 5) / 10;
12134bbcc6549738f3d69831b2bd9eb4accec3e9920eEric Laurent            Intent intent = new Intent(AudioManager.VOLUME_CHANGED_ACTION);
12144bbcc6549738f3d69831b2bd9eb4accec3e9920eEric Laurent            intent.putExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, streamType);
12154bbcc6549738f3d69831b2bd9eb4accec3e9920eEric Laurent            intent.putExtra(AudioManager.EXTRA_VOLUME_STREAM_VALUE, index);
12164bbcc6549738f3d69831b2bd9eb4accec3e9920eEric Laurent            intent.putExtra(AudioManager.EXTRA_PREV_VOLUME_STREAM_VALUE, oldIndex);
12174bbcc6549738f3d69831b2bd9eb4accec3e9920eEric Laurent            sendBroadcastToAll(intent);
12184bbcc6549738f3d69831b2bd9eb4accec3e9920eEric Laurent        }
12199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
12209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12210dc37cce9d564ae43883c8dc8672b9266b881e63Mike Lockwood    // UI update and Broadcast Intent
12220dc37cce9d564ae43883c8dc8672b9266b881e63Mike Lockwood    private void sendMasterVolumeUpdate(int flags, int oldVolume, int newVolume) {
12233346a802087f621c6441bc512dfcc17b07143fc6John Spurlock        mVolumeController.postMasterVolumeChanged(flags);
12240dc37cce9d564ae43883c8dc8672b9266b881e63Mike Lockwood
12250dc37cce9d564ae43883c8dc8672b9266b881e63Mike Lockwood        Intent intent = new Intent(AudioManager.MASTER_VOLUME_CHANGED_ACTION);
12260dc37cce9d564ae43883c8dc8672b9266b881e63Mike Lockwood        intent.putExtra(AudioManager.EXTRA_PREV_MASTER_VOLUME_VALUE, oldVolume);
12270dc37cce9d564ae43883c8dc8672b9266b881e63Mike Lockwood        intent.putExtra(AudioManager.EXTRA_MASTER_VOLUME_VALUE, newVolume);
12285ac72a29593ab9a20337a2225df52bdf4754be02Dianne Hackborn        sendBroadcastToAll(intent);
12290dc37cce9d564ae43883c8dc8672b9266b881e63Mike Lockwood    }
12300dc37cce9d564ae43883c8dc8672b9266b881e63Mike Lockwood
12310dc37cce9d564ae43883c8dc8672b9266b881e63Mike Lockwood    // UI update and Broadcast Intent
12320dc37cce9d564ae43883c8dc8672b9266b881e63Mike Lockwood    private void sendMasterMuteUpdate(boolean muted, int flags) {
12333346a802087f621c6441bc512dfcc17b07143fc6John Spurlock        mVolumeController.postMasterMuteChanged(flags);
123457978ed86286a33d5b1a0fd000ca3406ba9d87b3Justin Koh        broadcastMasterMuteStatus(muted);
123557978ed86286a33d5b1a0fd000ca3406ba9d87b3Justin Koh    }
12360dc37cce9d564ae43883c8dc8672b9266b881e63Mike Lockwood
123757978ed86286a33d5b1a0fd000ca3406ba9d87b3Justin Koh    private void broadcastMasterMuteStatus(boolean muted) {
12380dc37cce9d564ae43883c8dc8672b9266b881e63Mike Lockwood        Intent intent = new Intent(AudioManager.MASTER_MUTE_CHANGED_ACTION);
12390dc37cce9d564ae43883c8dc8672b9266b881e63Mike Lockwood        intent.putExtra(AudioManager.EXTRA_MASTER_VOLUME_MUTED, muted);
124057978ed86286a33d5b1a0fd000ca3406ba9d87b3Justin Koh        intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT
124157978ed86286a33d5b1a0fd000ca3406ba9d87b3Justin Koh                | Intent.FLAG_RECEIVER_REPLACE_PENDING);
12425ac72a29593ab9a20337a2225df52bdf4754be02Dianne Hackborn        sendStickyBroadcastToAll(intent);
12430dc37cce9d564ae43883c8dc8672b9266b881e63Mike Lockwood    }
12440dc37cce9d564ae43883c8dc8672b9266b881e63Mike Lockwood
12459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
12469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Sets the stream state's index, and posts a message to set system volume.
12479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * This will not call out to the UI. Assumes a valid stream type.
12489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
12499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param streamType Type of the stream
12509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param index Desired volume index of the stream
12519bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent     * @param device the device whose volume must be changed
12529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param force If true, set the volume even if the desired volume is same
12539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * as the current volume.
12549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
12559bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent    private void setStreamVolumeInt(int streamType,
12569bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                                    int index,
12579bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                                    int device,
125842b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                                    boolean force) {
12599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        VolumeStreamState streamState = mStreamStates[streamType];
12605b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent
126142b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent        if (streamState.setIndex(index, device) || force) {
126242b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent            // Post message to set system volume (it in turn will post a message
126342b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent            // to persist).
126442b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent            sendMsg(mAudioHandler,
126542b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                    MSG_SET_DEVICE_VOLUME,
126642b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                    SENDMSG_QUEUE,
126742b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                    device,
126842b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                    0,
126942b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                    streamState,
127042b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                    0);
12719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
12729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
12739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** @see AudioManager#setStreamSolo(int, boolean) */
12759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void setStreamSolo(int streamType, boolean state, IBinder cb) {
127683a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent        if (mUseFixedVolume) {
127783a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent            return;
127883a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent        }
127983a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent
12809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        for (int stream = 0; stream < mStreamStates.length; stream++) {
12819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (!isStreamAffectedByMute(stream) || stream == streamType) continue;
12829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mStreamStates[stream].mute(cb, state);
12839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         }
12849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
12859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** @see AudioManager#setStreamMute(int, boolean) */
12879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void setStreamMute(int streamType, boolean state, IBinder cb) {
128883a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent        if (mUseFixedVolume) {
128983a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent            return;
129083a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent        }
129183a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent
12929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (isStreamAffectedByMute(streamType)) {
12939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mStreamStates[streamType].mute(cb, state);
12949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
12959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
12969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
129725101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent    /** get stream mute state. */
129825101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent    public boolean isStreamMute(int streamType) {
129942b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent        return mStreamStates[streamType].isMuted();
130025101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent    }
130125101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent
1302961cae92540763226648813d111c5b5c3b0f1597Dianne Hackborn    /** @see AudioManager#setMasterMute(boolean, int) */
13034a21b25fad62e4f19d13ba814263841c931f56efJulia Reynolds    public void setMasterMute(boolean state, int flags, String callingPackage, IBinder cb) {
130483a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent        if (mUseFixedVolume) {
130583a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent            return;
130683a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent        }
130783a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent
13084a21b25fad62e4f19d13ba814263841c931f56efJulia Reynolds        if (mAppOps.noteOp(AppOpsManager.OP_AUDIO_MASTER_VOLUME, Binder.getCallingUid(),
13094a21b25fad62e4f19d13ba814263841c931f56efJulia Reynolds                callingPackage) != AppOpsManager.MODE_ALLOWED) {
13104a21b25fad62e4f19d13ba814263841c931f56efJulia Reynolds            return;
13114a21b25fad62e4f19d13ba814263841c931f56efJulia Reynolds        }
13124a21b25fad62e4f19d13ba814263841c931f56efJulia Reynolds
13131ce5b26d707e0086e09af3cd0428f1b441145261Jason Simmons        if (state != AudioSystem.getMasterMute()) {
13141ce5b26d707e0086e09af3cd0428f1b441145261Jason Simmons            AudioSystem.setMasterMute(state);
131557978ed86286a33d5b1a0fd000ca3406ba9d87b3Justin Koh            // Post a persist master volume msg
131675cf9e19a575c28c200c02c0ab6f83bb79f5c50dJustin Koh            sendMsg(mAudioHandler, MSG_PERSIST_MASTER_VOLUME_MUTE, SENDMSG_REPLACE, state ? 1
131757978ed86286a33d5b1a0fd000ca3406ba9d87b3Justin Koh                    : 0, 0, null, PERSIST_DELAY);
13180273af55cf68d54d26d154b44d105d40fed79701Justin Koh            sendMasterMuteUpdate(state, flags);
13191ce5b26d707e0086e09af3cd0428f1b441145261Jason Simmons        }
1320ce952c8e13c535bedde77bcdb94dfcc7508475aaMike Lockwood    }
1321ce952c8e13c535bedde77bcdb94dfcc7508475aaMike Lockwood
1322ce952c8e13c535bedde77bcdb94dfcc7508475aaMike Lockwood    /** get master mute state. */
1323ce952c8e13c535bedde77bcdb94dfcc7508475aaMike Lockwood    public boolean isMasterMute() {
13243194ea94348bce8e7ee9f803698d877f46f8279aMike Lockwood        return AudioSystem.getMasterMute();
1325ce952c8e13c535bedde77bcdb94dfcc7508475aaMike Lockwood    }
1326ce952c8e13c535bedde77bcdb94dfcc7508475aaMike Lockwood
1327fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    protected static int getMaxStreamVolume(int streamType) {
1328fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        return MAX_STREAM_VOLUME[streamType];
1329fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    }
1330fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi
13319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** @see AudioManager#getStreamVolume(int) */
13329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public int getStreamVolume(int streamType) {
13339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        ensureValidStreamType(streamType);
13349bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent        int device = getDeviceForStream(streamType);
133542b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent        int index = mStreamStates[streamType].getIndex(device);
13364bbcc6549738f3d69831b2bd9eb4accec3e9920eEric Laurent
133742b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent        // by convention getStreamVolume() returns 0 when a stream is muted.
133842b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent        if (mStreamStates[streamType].isMuted()) {
133942b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent            index = 0;
134042b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent        }
13413ef7549876a159dae1568429edcb57e4e7d08459Eric Laurent        if (index != 0 && (mStreamVolumeAlias[streamType] == AudioSystem.STREAM_MUSIC) &&
13424bbcc6549738f3d69831b2bd9eb4accec3e9920eEric Laurent                (device & mFixedVolumeDevices) != 0) {
13434bbcc6549738f3d69831b2bd9eb4accec3e9920eEric Laurent            index = mStreamStates[streamType].getMaxIndex();
13444bbcc6549738f3d69831b2bd9eb4accec3e9920eEric Laurent        }
13454bbcc6549738f3d69831b2bd9eb4accec3e9920eEric Laurent        return (index + 5) / 10;
13469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
13479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
13484767690f09ea3447b8c5c32fb28d27650aa18e00Mike Lockwood    public int getMasterVolume() {
1349ce952c8e13c535bedde77bcdb94dfcc7508475aaMike Lockwood        if (isMasterMute()) return 0;
1350ce952c8e13c535bedde77bcdb94dfcc7508475aaMike Lockwood        return getLastAudibleMasterVolume();
13518dc1dabd254249b7ddb8743e88fdb96580ffc585Mike Lockwood    }
13528dc1dabd254249b7ddb8743e88fdb96580ffc585Mike Lockwood
1353ba50b97cff80e73620a0e3d13cae169e095974a7Dianne Hackborn    public void setMasterVolume(int volume, int flags, String callingPackage) {
135483a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent        if (mUseFixedVolume) {
135583a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent            return;
135683a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent        }
135783a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent
1358ba50b97cff80e73620a0e3d13cae169e095974a7Dianne Hackborn        if (mAppOps.noteOp(AppOpsManager.OP_AUDIO_MASTER_VOLUME, Binder.getCallingUid(),
1359ba50b97cff80e73620a0e3d13cae169e095974a7Dianne Hackborn                callingPackage) != AppOpsManager.MODE_ALLOWED) {
1360ba50b97cff80e73620a0e3d13cae169e095974a7Dianne Hackborn            return;
1361ba50b97cff80e73620a0e3d13cae169e095974a7Dianne Hackborn        }
1362ba50b97cff80e73620a0e3d13cae169e095974a7Dianne Hackborn
13639760647dd0ee67e7c20f3e9d661d2006b1df0b54Mike Lockwood        if (volume < 0) {
13649760647dd0ee67e7c20f3e9d661d2006b1df0b54Mike Lockwood            volume = 0;
13659760647dd0ee67e7c20f3e9d661d2006b1df0b54Mike Lockwood        } else if (volume > MAX_MASTER_VOLUME) {
13669760647dd0ee67e7c20f3e9d661d2006b1df0b54Mike Lockwood            volume = MAX_MASTER_VOLUME;
13679760647dd0ee67e7c20f3e9d661d2006b1df0b54Mike Lockwood        }
13685c55a051ad7d86a464fb91426f1ea3c0250e38b3Mike Lockwood        doSetMasterVolume((float)volume / MAX_MASTER_VOLUME, flags);
13695c55a051ad7d86a464fb91426f1ea3c0250e38b3Mike Lockwood    }
13705c55a051ad7d86a464fb91426f1ea3c0250e38b3Mike Lockwood
13715c55a051ad7d86a464fb91426f1ea3c0250e38b3Mike Lockwood    private void doSetMasterVolume(float volume, int flags) {
13725c55a051ad7d86a464fb91426f1ea3c0250e38b3Mike Lockwood        // don't allow changing master volume when muted
13735c55a051ad7d86a464fb91426f1ea3c0250e38b3Mike Lockwood        if (!AudioSystem.getMasterMute()) {
13745c55a051ad7d86a464fb91426f1ea3c0250e38b3Mike Lockwood            int oldVolume = getMasterVolume();
13755c55a051ad7d86a464fb91426f1ea3c0250e38b3Mike Lockwood            AudioSystem.setMasterVolume(volume);
13765c55a051ad7d86a464fb91426f1ea3c0250e38b3Mike Lockwood
13775c55a051ad7d86a464fb91426f1ea3c0250e38b3Mike Lockwood            int newVolume = getMasterVolume();
13785c55a051ad7d86a464fb91426f1ea3c0250e38b3Mike Lockwood            if (newVolume != oldVolume) {
13795c55a051ad7d86a464fb91426f1ea3c0250e38b3Mike Lockwood                // Post a persist master volume msg
13805c55a051ad7d86a464fb91426f1ea3c0250e38b3Mike Lockwood                sendMsg(mAudioHandler, MSG_PERSIST_MASTER_VOLUME, SENDMSG_REPLACE,
13815c55a051ad7d86a464fb91426f1ea3c0250e38b3Mike Lockwood                        Math.round(volume * (float)1000.0), 0, null, PERSIST_DELAY);
13825c55a051ad7d86a464fb91426f1ea3c0250e38b3Mike Lockwood            }
13833caba517253d1703fc29b50740c4567b932279fbJustin Koh            // Send the volume update regardless whether there was a change.
13843caba517253d1703fc29b50740c4567b932279fbJustin Koh            sendMasterVolumeUpdate(flags, oldVolume, newVolume);
13855c55a051ad7d86a464fb91426f1ea3c0250e38b3Mike Lockwood        }
13868dc1dabd254249b7ddb8743e88fdb96580ffc585Mike Lockwood    }
13878dc1dabd254249b7ddb8743e88fdb96580ffc585Mike Lockwood
13889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** @see AudioManager#getStreamMaxVolume(int) */
13899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public int getStreamMaxVolume(int streamType) {
13909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        ensureValidStreamType(streamType);
1391a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent        return (mStreamStates[streamType].getMaxIndex() + 5) / 10;
13929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
13939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
13944767690f09ea3447b8c5c32fb28d27650aa18e00Mike Lockwood    public int getMasterMaxVolume() {
13954767690f09ea3447b8c5c32fb28d27650aa18e00Mike Lockwood        return MAX_MASTER_VOLUME;
13964767690f09ea3447b8c5c32fb28d27650aa18e00Mike Lockwood    }
139725101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent
139825101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent    /** Get last audible volume before stream was muted. */
139925101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent    public int getLastAudibleStreamVolume(int streamType) {
140025101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent        ensureValidStreamType(streamType);
14019bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent        int device = getDeviceForStream(streamType);
140242b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent        return (mStreamStates[streamType].getIndex(device) + 5) / 10;
140325101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent    }
140425101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent
1405ce952c8e13c535bedde77bcdb94dfcc7508475aaMike Lockwood    /** Get last audible master volume before it was muted. */
1406ce952c8e13c535bedde77bcdb94dfcc7508475aaMike Lockwood    public int getLastAudibleMasterVolume() {
1407ce952c8e13c535bedde77bcdb94dfcc7508475aaMike Lockwood        return Math.round(AudioSystem.getMasterVolume() * MAX_MASTER_VOLUME);
1408ce952c8e13c535bedde77bcdb94dfcc7508475aaMike Lockwood    }
1409ce952c8e13c535bedde77bcdb94dfcc7508475aaMike Lockwood
1410961cae92540763226648813d111c5b5c3b0f1597Dianne Hackborn    /** @see AudioManager#getMasterStreamType()  */
14116d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent    public int getMasterStreamType() {
14126d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent        if (mVoiceCapable) {
14136d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent            return AudioSystem.STREAM_RING;
14146d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent        } else {
14156d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent            return AudioSystem.STREAM_MUSIC;
14166d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent        }
14176d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent    }
14186d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent
141922c921a910d236abf3a1705a02541a49fdaf3a14Emily Bernier    /** @see AudioManager#setMicrophoneMute(boolean) */
142022c921a910d236abf3a1705a02541a49fdaf3a14Emily Bernier    public void setMicrophoneMute(boolean on, String callingPackage) {
142122c921a910d236abf3a1705a02541a49fdaf3a14Emily Bernier        if (mAppOps.noteOp(AppOpsManager.OP_MUTE_MICROPHONE, Binder.getCallingUid(),
142222c921a910d236abf3a1705a02541a49fdaf3a14Emily Bernier                callingPackage) != AppOpsManager.MODE_ALLOWED) {
142322c921a910d236abf3a1705a02541a49fdaf3a14Emily Bernier            return;
142422c921a910d236abf3a1705a02541a49fdaf3a14Emily Bernier        }
142522c921a910d236abf3a1705a02541a49fdaf3a14Emily Bernier
142622c921a910d236abf3a1705a02541a49fdaf3a14Emily Bernier        AudioSystem.muteMicrophone(on);
142722c921a910d236abf3a1705a02541a49fdaf3a14Emily Bernier    }
142822c921a910d236abf3a1705a02541a49fdaf3a14Emily Bernier
14299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** @see AudioManager#getRingerMode() */
14309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public int getRingerMode() {
1431ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten        synchronized(mSettingsLock) {
1432ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten            return mRingerMode;
1433ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten        }
1434ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten    }
1435ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten
1436ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten    private void ensureValidRingerMode(int ringerMode) {
1437ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten        if (!AudioManager.isValidRingerMode(ringerMode)) {
1438ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten            throw new IllegalArgumentException("Bad ringer mode " + ringerMode);
1439ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten        }
14409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
14419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
14429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** @see AudioManager#setRingerMode(int) */
14439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void setRingerMode(int ringerMode) {
144483a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent        if (mUseFixedVolume) {
144583a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent            return;
144683a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent        }
144783a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent
1448244820185269991186d07068b92985624cede4a5Eric Laurent        if ((ringerMode == AudioManager.RINGER_MODE_VIBRATE) && !mHasVibrator) {
1449244820185269991186d07068b92985624cede4a5Eric Laurent            ringerMode = AudioManager.RINGER_MODE_SILENT;
1450244820185269991186d07068b92985624cede4a5Eric Laurent        }
1451ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten        if (ringerMode != getRingerMode()) {
1452ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten            setRingerModeInt(ringerMode, true);
1453ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten            // Send sticky broadcast
1454ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten            broadcastRingerMode(ringerMode);
1455b109615ebebd6f3b9ae789412279f576c3ace46bJason Parekh        }
1456b109615ebebd6f3b9ae789412279f576c3ace46bJason Parekh    }
14579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
14584050c93601b3c3609b21cc1e18a29b64747e7fa9Eric Laurent    private void setRingerModeInt(int ringerMode, boolean persist) {
1459ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten        synchronized(mSettingsLock) {
1460ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten            mRingerMode = ringerMode;
1461ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten        }
1462b109615ebebd6f3b9ae789412279f576c3ace46bJason Parekh
14635b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent        // Mute stream if not previously muted by ringer mode and ringer mode
14645b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent        // is not RINGER_MODE_NORMAL and stream is affected by ringer mode.
14655b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent        // Unmute stream if previously muted by ringer mode and ringer mode
14665b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent        // is RINGER_MODE_NORMAL or stream is not affected by ringer mode.
1467b109615ebebd6f3b9ae789412279f576c3ace46bJason Parekh        int numStreamTypes = AudioSystem.getNumStreamTypes();
14685b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent        for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
14695b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent            if (isStreamMutedByRingerMode(streamType)) {
14705b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent                if (!isStreamAffectedByRingerMode(streamType) ||
1471ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten                    ringerMode == AudioManager.RINGER_MODE_NORMAL) {
1472b024c30a80684ac08daef3137b7ba0d347fe3ce5Eric Laurent                    // ring and notifications volume should never be 0 when not silenced
1473b024c30a80684ac08daef3137b7ba0d347fe3ce5Eric Laurent                    // on voice capable devices
1474b024c30a80684ac08daef3137b7ba0d347fe3ce5Eric Laurent                    if (mVoiceCapable &&
14756d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent                            mStreamVolumeAlias[streamType] == AudioSystem.STREAM_RING) {
14763172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                        synchronized (mStreamStates[streamType]) {
147742b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                            Set set = mStreamStates[streamType].mIndex.entrySet();
14783172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                            Iterator i = set.iterator();
14793172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                            while (i.hasNext()) {
14803172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                                Map.Entry entry = (Map.Entry)i.next();
14813172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                                if ((Integer)entry.getValue() == 0) {
14823172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                                    entry.setValue(10);
14833172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                                }
14849bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                            }
14859bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                        }
1486b024c30a80684ac08daef3137b7ba0d347fe3ce5Eric Laurent                    }
14875b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent                    mStreamStates[streamType].mute(null, false);
14885b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent                    mRingerModeMutedStreams &= ~(1 << streamType);
14899bcf401d13d47416043a704430388abd59aef7cdEric Laurent                }
14905b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent            } else {
14915b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent                if (isStreamAffectedByRingerMode(streamType) &&
1492ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten                    ringerMode != AudioManager.RINGER_MODE_NORMAL) {
14935b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent                   mStreamStates[streamType].mute(null, true);
14945b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent                   mRingerModeMutedStreams |= (1 << streamType);
14955b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent               }
1496b109615ebebd6f3b9ae789412279f576c3ace46bJason Parekh            }
14979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1498a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent
1499b109615ebebd6f3b9ae789412279f576c3ace46bJason Parekh        // Post a persist ringer mode msg
15004050c93601b3c3609b21cc1e18a29b64747e7fa9Eric Laurent        if (persist) {
1501afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent            sendMsg(mAudioHandler, MSG_PERSIST_RINGER_MODE,
15024050c93601b3c3609b21cc1e18a29b64747e7fa9Eric Laurent                    SENDMSG_REPLACE, 0, 0, null, PERSIST_DELAY);
15034050c93601b3c3609b21cc1e18a29b64747e7fa9Eric Laurent        }
15049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
15059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
15069063154a793b0ab38b3c5992cbaed046427b4a82Mike Lockwood    private void restoreMasterVolume() {
150783a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent        if (mUseFixedVolume) {
150883a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent            AudioSystem.setMasterVolume(1.0f);
150983a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent            return;
151083a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent        }
15119063154a793b0ab38b3c5992cbaed046427b4a82Mike Lockwood        if (mUseMasterVolume) {
1512bc0fab1fc2db832ef86d8a33466ec4d68b103ca0Eric Laurent            float volume = Settings.System.getFloatForUser(mContentResolver,
1513bc0fab1fc2db832ef86d8a33466ec4d68b103ca0Eric Laurent                    Settings.System.VOLUME_MASTER, -1.0f, UserHandle.USER_CURRENT);
15149063154a793b0ab38b3c5992cbaed046427b4a82Mike Lockwood            if (volume >= 0.0f) {
15159063154a793b0ab38b3c5992cbaed046427b4a82Mike Lockwood                AudioSystem.setMasterVolume(volume);
15169063154a793b0ab38b3c5992cbaed046427b4a82Mike Lockwood            }
15179063154a793b0ab38b3c5992cbaed046427b4a82Mike Lockwood        }
15189063154a793b0ab38b3c5992cbaed046427b4a82Mike Lockwood    }
15199063154a793b0ab38b3c5992cbaed046427b4a82Mike Lockwood
15209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** @see AudioManager#shouldVibrate(int) */
15219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public boolean shouldVibrate(int vibrateType) {
1522bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent        if (!mHasVibrator) return false;
15239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
15249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        switch (getVibrateSetting(vibrateType)) {
15259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
15269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            case AudioManager.VIBRATE_SETTING_ON:
1527ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten                return getRingerMode() != AudioManager.RINGER_MODE_SILENT;
15289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
15299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            case AudioManager.VIBRATE_SETTING_ONLY_SILENT:
1530ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten                return getRingerMode() == AudioManager.RINGER_MODE_VIBRATE;
15319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
15329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            case AudioManager.VIBRATE_SETTING_OFF:
1533bcac496076ef6f439147e7a2be71e8a2b76ddedeDaniel Sandler                // return false, even for incoming calls
1534bcac496076ef6f439147e7a2be71e8a2b76ddedeDaniel Sandler                return false;
15359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
15369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            default:
15379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return false;
15389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
15399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
15409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
15419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** @see AudioManager#getVibrateSetting(int) */
15429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public int getVibrateSetting(int vibrateType) {
1543bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent        if (!mHasVibrator) return AudioManager.VIBRATE_SETTING_OFF;
15449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return (mVibrateSetting >> (vibrateType * 2)) & 3;
15459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
15469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
15479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** @see AudioManager#setVibrateSetting(int, int) */
15489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void setVibrateSetting(int vibrateType, int vibrateSetting) {
15499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1550bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent        if (!mHasVibrator) return;
1551bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent
15529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mVibrateSetting = getValueForVibrateSetting(mVibrateSetting, vibrateType, vibrateSetting);
15539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
15549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // Broadcast change
15559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        broadcastVibrateSetting(vibrateType);
15569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
15579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
15589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
15599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
15609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @see #setVibrateSetting(int, int)
15619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
15629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static int getValueForVibrateSetting(int existingValue, int vibrateType,
15639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int vibrateSetting) {
15649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
15659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // First clear the existing setting. Each vibrate type has two bits in
15669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // the value. Note '3' is '11' in binary.
15679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        existingValue &= ~(3 << (vibrateType * 2));
15689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
15699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // Set into the old value
15709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        existingValue |= (vibrateSetting & 3) << (vibrateType * 2);
15719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
15729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return existingValue;
15739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
15749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
15759272b4b4a44fe1f33e3030810618194f817caaecEric Laurent    private class SetModeDeathHandler implements IBinder.DeathRecipient {
15769272b4b4a44fe1f33e3030810618194f817caaecEric Laurent        private IBinder mCb; // To be notified of client's death
1577f1ddd51f9cd2f92b922bc636c307210a8d587c25Marco Nelissen        private int mPid;
15789272b4b4a44fe1f33e3030810618194f817caaecEric Laurent        private int mMode = AudioSystem.MODE_NORMAL; // Current mode set by this client
15799272b4b4a44fe1f33e3030810618194f817caaecEric Laurent
15809f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent        SetModeDeathHandler(IBinder cb, int pid) {
15819272b4b4a44fe1f33e3030810618194f817caaecEric Laurent            mCb = cb;
15829f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent            mPid = pid;
15839272b4b4a44fe1f33e3030810618194f817caaecEric Laurent        }
15849272b4b4a44fe1f33e3030810618194f817caaecEric Laurent
15859272b4b4a44fe1f33e3030810618194f817caaecEric Laurent        public void binderDied() {
1586d7454be47f4111c0478a502353e11dea401378bdEric Laurent            int newModeOwnerPid = 0;
15879272b4b4a44fe1f33e3030810618194f817caaecEric Laurent            synchronized(mSetModeDeathHandlers) {
15889272b4b4a44fe1f33e3030810618194f817caaecEric Laurent                Log.w(TAG, "setMode() client died");
15899272b4b4a44fe1f33e3030810618194f817caaecEric Laurent                int index = mSetModeDeathHandlers.indexOf(this);
15909272b4b4a44fe1f33e3030810618194f817caaecEric Laurent                if (index < 0) {
15919272b4b4a44fe1f33e3030810618194f817caaecEric Laurent                    Log.w(TAG, "unregistered setMode() client died");
15929272b4b4a44fe1f33e3030810618194f817caaecEric Laurent                } else {
1593d7454be47f4111c0478a502353e11dea401378bdEric Laurent                    newModeOwnerPid = setModeInt(AudioSystem.MODE_NORMAL, mCb, mPid);
15949272b4b4a44fe1f33e3030810618194f817caaecEric Laurent                }
15959272b4b4a44fe1f33e3030810618194f817caaecEric Laurent            }
15969f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent            // when entering RINGTONE, IN_CALL or IN_COMMUNICATION mode, clear all
15979f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent            // SCO connections not started by the application changing the mode
1598d7454be47f4111c0478a502353e11dea401378bdEric Laurent            if (newModeOwnerPid != 0) {
15996b5e22d52c69cb6d80ff09bd32395b0034ada343Eric Laurent                final long ident = Binder.clearCallingIdentity();
16006b5e22d52c69cb6d80ff09bd32395b0034ada343Eric Laurent                disconnectBluetoothSco(newModeOwnerPid);
16016b5e22d52c69cb6d80ff09bd32395b0034ada343Eric Laurent                Binder.restoreCallingIdentity(ident);
16029f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent            }
16039272b4b4a44fe1f33e3030810618194f817caaecEric Laurent        }
16049272b4b4a44fe1f33e3030810618194f817caaecEric Laurent
1605f1ddd51f9cd2f92b922bc636c307210a8d587c25Marco Nelissen        public int getPid() {
1606f1ddd51f9cd2f92b922bc636c307210a8d587c25Marco Nelissen            return mPid;
1607f1ddd51f9cd2f92b922bc636c307210a8d587c25Marco Nelissen        }
1608f1ddd51f9cd2f92b922bc636c307210a8d587c25Marco Nelissen
16099272b4b4a44fe1f33e3030810618194f817caaecEric Laurent        public void setMode(int mode) {
16109272b4b4a44fe1f33e3030810618194f817caaecEric Laurent            mMode = mode;
16119272b4b4a44fe1f33e3030810618194f817caaecEric Laurent        }
16129272b4b4a44fe1f33e3030810618194f817caaecEric Laurent
16139272b4b4a44fe1f33e3030810618194f817caaecEric Laurent        public int getMode() {
16149272b4b4a44fe1f33e3030810618194f817caaecEric Laurent            return mMode;
16159272b4b4a44fe1f33e3030810618194f817caaecEric Laurent        }
16169272b4b4a44fe1f33e3030810618194f817caaecEric Laurent
16179272b4b4a44fe1f33e3030810618194f817caaecEric Laurent        public IBinder getBinder() {
16189272b4b4a44fe1f33e3030810618194f817caaecEric Laurent            return mCb;
16199272b4b4a44fe1f33e3030810618194f817caaecEric Laurent        }
16209272b4b4a44fe1f33e3030810618194f817caaecEric Laurent    }
16219272b4b4a44fe1f33e3030810618194f817caaecEric Laurent
16229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** @see AudioManager#setMode(int) */
16239272b4b4a44fe1f33e3030810618194f817caaecEric Laurent    public void setMode(int mode, IBinder cb) {
16249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (!checkAudioSettingsPermission("setMode()")) {
16259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return;
16269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1627a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent
16288f677d66d9c3ba34c97e69b2bb9e161f129af0eeJean-Michel Trivi        if (mode < AudioSystem.MODE_CURRENT || mode >= AudioSystem.NUM_MODES) {
1629a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent            return;
1630a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent        }
1631a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent
1632d7454be47f4111c0478a502353e11dea401378bdEric Laurent        int newModeOwnerPid = 0;
16339f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent        synchronized(mSetModeDeathHandlers) {
1634a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent            if (mode == AudioSystem.MODE_CURRENT) {
1635a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent                mode = mMode;
1636a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent            }
1637d7454be47f4111c0478a502353e11dea401378bdEric Laurent            newModeOwnerPid = setModeInt(mode, cb, Binder.getCallingPid());
16389f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent        }
16399f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent        // when entering RINGTONE, IN_CALL or IN_COMMUNICATION mode, clear all
16409f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent        // SCO connections not started by the application changing the mode
1641d7454be47f4111c0478a502353e11dea401378bdEric Laurent        if (newModeOwnerPid != 0) {
1642d7454be47f4111c0478a502353e11dea401378bdEric Laurent             disconnectBluetoothSco(newModeOwnerPid);
16439f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent        }
16449f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent    }
16452ade576148fe33c5ff6098d30ccfbcf28df70e8eJean-Michel Trivi
16469f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent    // must be called synchronized on mSetModeDeathHandlers
1647d7454be47f4111c0478a502353e11dea401378bdEric Laurent    // setModeInt() returns a valid PID if the audio mode was successfully set to
16489f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent    // any mode other than NORMAL.
1649d7454be47f4111c0478a502353e11dea401378bdEric Laurent    int setModeInt(int mode, IBinder cb, int pid) {
1650d7454be47f4111c0478a502353e11dea401378bdEric Laurent        int newModeOwnerPid = 0;
16519f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent        if (cb == null) {
16529f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent            Log.e(TAG, "setModeInt() called with null binder");
1653d7454be47f4111c0478a502353e11dea401378bdEric Laurent            return newModeOwnerPid;
16549f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent        }
16552ade576148fe33c5ff6098d30ccfbcf28df70e8eJean-Michel Trivi
16569f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent        SetModeDeathHandler hdlr = null;
16579f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent        Iterator iter = mSetModeDeathHandlers.iterator();
16589f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent        while (iter.hasNext()) {
16599f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent            SetModeDeathHandler h = (SetModeDeathHandler)iter.next();
16609f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent            if (h.getPid() == pid) {
16619f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                hdlr = h;
16629f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                // Remove from client list so that it is re-inserted at top of list
16639f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                iter.remove();
16649f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                hdlr.getBinder().unlinkToDeath(hdlr, 0);
16659f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                break;
16669f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent            }
16679f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent        }
16689f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent        int status = AudioSystem.AUDIO_STATUS_OK;
16699f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent        do {
16709f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent            if (mode == AudioSystem.MODE_NORMAL) {
16719f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                // get new mode from client at top the list if any
16729f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                if (!mSetModeDeathHandlers.isEmpty()) {
16739f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                    hdlr = mSetModeDeathHandlers.get(0);
16749f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                    cb = hdlr.getBinder();
16759f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                    mode = hdlr.getMode();
16769f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                }
16779f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent            } else {
16789f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                if (hdlr == null) {
16799f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                    hdlr = new SetModeDeathHandler(cb, pid);
16809f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                }
16819f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                // Register for client death notification
16829f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                try {
16839f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                    cb.linkToDeath(hdlr, 0);
16849f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                } catch (RemoteException e) {
16859f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                    // Client has died!
16869f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                    Log.w(TAG, "setMode() could not link to "+cb+" binder death");
16879f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                }
16889272b4b4a44fe1f33e3030810618194f817caaecEric Laurent
16899f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                // Last client to call setMode() is always at top of client list
16909f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                // as required by SetModeDeathHandler.binderDied()
16919f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                mSetModeDeathHandlers.add(0, hdlr);
16929f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                hdlr.setMode(mode);
16939f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent            }
16943def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent
16959f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent            if (mode != mMode) {
16969f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                status = AudioSystem.setPhoneState(mode);
16979f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                if (status == AudioSystem.AUDIO_STATUS_OK) {
16989f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                    mMode = mode;
16999f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                } else {
17009f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                    if (hdlr != null) {
17019f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                        mSetModeDeathHandlers.remove(hdlr);
17029f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                        cb.unlinkToDeath(hdlr, 0);
17033def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                    }
17049f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                    // force reading new top of mSetModeDeathHandlers stack
17059f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                    mode = AudioSystem.MODE_NORMAL;
1706b9c9d260f21b321527c4622a123af9767630d94dEric Laurent                }
17079f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent            } else {
17089f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                status = AudioSystem.AUDIO_STATUS_OK;
17099f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent            }
17109f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent        } while (status != AudioSystem.AUDIO_STATUS_OK && !mSetModeDeathHandlers.isEmpty());
17119f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent
17129f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent        if (status == AudioSystem.AUDIO_STATUS_OK) {
17139f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent            if (mode != AudioSystem.MODE_NORMAL) {
1714d7454be47f4111c0478a502353e11dea401378bdEric Laurent                if (mSetModeDeathHandlers.isEmpty()) {
1715d7454be47f4111c0478a502353e11dea401378bdEric Laurent                    Log.e(TAG, "setMode() different from MODE_NORMAL with empty mode client stack");
1716d7454be47f4111c0478a502353e11dea401378bdEric Laurent                } else {
1717d7454be47f4111c0478a502353e11dea401378bdEric Laurent                    newModeOwnerPid = mSetModeDeathHandlers.get(0).getPid();
1718d7454be47f4111c0478a502353e11dea401378bdEric Laurent                }
17199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
17209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int streamType = getActiveStreamType(AudioManager.USE_DEFAULT_STREAM_TYPE);
17213114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi            if (streamType == STREAM_REMOTE_MUSIC) {
17223114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                // here handle remote media playback the same way as local playback
17233114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                streamType = AudioManager.STREAM_MUSIC;
17243114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi            }
17259bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent            int device = getDeviceForStream(streamType);
172642b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent            int index = mStreamStates[mStreamVolumeAlias[streamType]].getIndex(device);
172742b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent            setStreamVolumeInt(mStreamVolumeAlias[streamType], index, device, true);
17286d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent
17296d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent            updateStreamVolumeAlias(true /*updateVolumes*/);
17309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1731d7454be47f4111c0478a502353e11dea401378bdEric Laurent        return newModeOwnerPid;
17329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
17339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
17349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** @see AudioManager#getMode() */
17359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public int getMode() {
17369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return mMode;
17379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
17389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1739e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent    //==========================================================================================
1740e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent    // Sound Effects
1741e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent    //==========================================================================================
1742e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent
1743e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent    private static final String TAG_AUDIO_ASSETS = "audio_assets";
1744e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent    private static final String ATTR_VERSION = "version";
1745e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent    private static final String TAG_GROUP = "group";
1746e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent    private static final String ATTR_GROUP_NAME = "name";
1747e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent    private static final String TAG_ASSET = "asset";
1748e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent    private static final String ATTR_ASSET_ID = "id";
1749e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent    private static final String ATTR_ASSET_FILE = "file";
1750e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent
1751e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent    private static final String ASSET_FILE_VERSION = "1.0";
1752e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent    private static final String GROUP_TOUCH_SOUNDS = "touch_sounds";
1753e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent
1754167d1a27713ab64cd3c0aa70de96434083ef0400Glenn Kasten    private static final int SOUND_EFFECTS_LOAD_TIMEOUT_MS = 5000;
17555d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent
17565d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent    class LoadSoundEffectReply {
17575d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent        public int mStatus = 1;
17585d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent    };
17595d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent
1760e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent    private void loadTouchSoundAssetDefaults() {
1761e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent        SOUND_EFFECT_FILES.add("Effect_Tick.ogg");
1762e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent        for (int i = 0; i < AudioManager.NUM_SOUND_EFFECTS; i++) {
1763e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent            SOUND_EFFECT_FILES_MAP[i][0] = 0;
1764e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent            SOUND_EFFECT_FILES_MAP[i][1] = -1;
1765e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent        }
1766e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent    }
1767e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent
1768e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent    private void loadTouchSoundAssets() {
1769e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent        XmlResourceParser parser = null;
1770e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent
17715d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent        // only load assets once.
17725d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent        if (!SOUND_EFFECT_FILES.isEmpty()) {
17735d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent            return;
17745d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent        }
17755d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent
1776e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent        loadTouchSoundAssetDefaults();
1777e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent
1778e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent        try {
1779e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent            parser = mContext.getResources().getXml(com.android.internal.R.xml.audio_assets);
1780e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent
1781e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent            XmlUtils.beginDocument(parser, TAG_AUDIO_ASSETS);
1782e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent            String version = parser.getAttributeValue(null, ATTR_VERSION);
1783e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent            boolean inTouchSoundsGroup = false;
1784e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent
1785e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent            if (ASSET_FILE_VERSION.equals(version)) {
1786e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent                while (true) {
1787e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent                    XmlUtils.nextElement(parser);
1788e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent                    String element = parser.getName();
1789e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent                    if (element == null) {
1790e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent                        break;
1791e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent                    }
1792e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent                    if (element.equals(TAG_GROUP)) {
1793e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent                        String name = parser.getAttributeValue(null, ATTR_GROUP_NAME);
1794e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent                        if (GROUP_TOUCH_SOUNDS.equals(name)) {
1795e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent                            inTouchSoundsGroup = true;
1796e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent                            break;
1797e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent                        }
1798e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent                    }
1799e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent                }
1800e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent                while (inTouchSoundsGroup) {
1801e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent                    XmlUtils.nextElement(parser);
1802e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent                    String element = parser.getName();
1803e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent                    if (element == null) {
1804e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent                        break;
1805e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent                    }
1806e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent                    if (element.equals(TAG_ASSET)) {
1807e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent                        String id = parser.getAttributeValue(null, ATTR_ASSET_ID);
1808e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent                        String file = parser.getAttributeValue(null, ATTR_ASSET_FILE);
1809e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent                        int fx;
1810e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent
1811e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent                        try {
1812e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent                            Field field = AudioManager.class.getField(id);
1813e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent                            fx = field.getInt(null);
1814e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent                        } catch (Exception e) {
1815e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent                            Log.w(TAG, "Invalid touch sound ID: "+id);
1816e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent                            continue;
1817e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent                        }
1818e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent
1819e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent                        int i = SOUND_EFFECT_FILES.indexOf(file);
1820e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent                        if (i == -1) {
1821e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent                            i = SOUND_EFFECT_FILES.size();
1822e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent                            SOUND_EFFECT_FILES.add(file);
1823e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent                        }
1824e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent                        SOUND_EFFECT_FILES_MAP[fx][0] = i;
1825e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent                    } else {
1826e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent                        break;
1827e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent                    }
1828e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent                }
1829e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent            }
1830e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent        } catch (Resources.NotFoundException e) {
1831e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent            Log.w(TAG, "audio assets file not found", e);
1832e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent        } catch (XmlPullParserException e) {
1833e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent            Log.w(TAG, "XML parser exception reading touch sound assets", e);
1834e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent        } catch (IOException e) {
1835e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent            Log.w(TAG, "I/O exception reading touch sound assets", e);
1836e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent        } finally {
1837e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent            if (parser != null) {
1838e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent                parser.close();
1839e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent            }
1840e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent        }
1841e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent    }
1842e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent
18439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** @see AudioManager#playSoundEffect(int) */
18449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void playSoundEffect(int effectType) {
18455d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent        playSoundEffectVolume(effectType, -1.0f);
18469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
18479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
18489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** @see AudioManager#playSoundEffect(int, float) */
18499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void playSoundEffectVolume(int effectType, float volume) {
1850559c76dbc37ff25b204ed1f060d3ec2fa43d718cNatalie Silvanovich        if (effectType >= AudioManager.NUM_SOUND_EFFECTS || effectType < 0) {
1851559c76dbc37ff25b204ed1f060d3ec2fa43d718cNatalie Silvanovich            Log.w(TAG, "AudioService effectType value " + effectType + " out of range");
1852559c76dbc37ff25b204ed1f060d3ec2fa43d718cNatalie Silvanovich            return;
1853559c76dbc37ff25b204ed1f060d3ec2fa43d718cNatalie Silvanovich        }
1854559c76dbc37ff25b204ed1f060d3ec2fa43d718cNatalie Silvanovich
18555d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent        sendMsg(mAudioHandler, MSG_PLAY_SOUND_EFFECT, SENDMSG_QUEUE,
18569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                effectType, (int) (volume * 1000), null, 0);
18579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
18589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
18599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
18609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Loads samples into the soundpool.
18615c17a820f9e46e0756c11795b3e6f89105f2f539Glenn Kasten     * This method must be called at first when sound effects are enabled
18629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
18639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public boolean loadSoundEffects() {
18645d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent        int attempts = 3;
18655d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent        LoadSoundEffectReply reply = new LoadSoundEffectReply();
1866117b7bb5b5a4457711f59bde3dcc83d8f111c524Eric Laurent
18675d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent        synchronized (reply) {
18685d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent            sendMsg(mAudioHandler, MSG_LOAD_SOUND_EFFECTS, SENDMSG_QUEUE, 0, 0, reply, 0);
18695d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent            while ((reply.mStatus == 1) && (attempts-- > 0)) {
1870117b7bb5b5a4457711f59bde3dcc83d8f111c524Eric Laurent                try {
1871167d1a27713ab64cd3c0aa70de96434083ef0400Glenn Kasten                    reply.wait(SOUND_EFFECTS_LOAD_TIMEOUT_MS);
18725d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                } catch (InterruptedException e) {
18735d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    Log.w(TAG, "loadSoundEffects Interrupted while waiting sound pool loaded.");
1874117b7bb5b5a4457711f59bde3dcc83d8f111c524Eric Laurent                }
1875a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent            }
18769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
18775d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent        return (reply.mStatus == 0);
18789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
18799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
18809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
18819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *  Unloads samples from the sound pool.
18829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *  This method can be called to free some memory when
18839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *  sound effects are disabled.
18849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
18859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void unloadSoundEffects() {
18865d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent        sendMsg(mAudioHandler, MSG_UNLOAD_SOUND_EFFECTS, SENDMSG_QUEUE, 0, 0, null, 0);
18879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
18889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1889a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent    class SoundPoolListenerThread extends Thread {
1890a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent        public SoundPoolListenerThread() {
1891a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent            super("SoundPoolListenerThread");
1892a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent        }
1893a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent
1894a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent        @Override
1895a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent        public void run() {
1896a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent
1897a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent            Looper.prepare();
1898a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent            mSoundPoolLooper = Looper.myLooper();
1899a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent
1900a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent            synchronized (mSoundEffectsLock) {
1901a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent                if (mSoundPool != null) {
1902a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent                    mSoundPoolCallBack = new SoundPoolCallback();
1903a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent                    mSoundPool.setOnLoadCompleteListener(mSoundPoolCallBack);
1904a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent                }
1905a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent                mSoundEffectsLock.notify();
1906a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent            }
1907a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent            Looper.loop();
1908a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent        }
1909a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent    }
1910a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent
1911a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent    private final class SoundPoolCallback implements
1912a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent            android.media.SoundPool.OnLoadCompleteListener {
1913a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent
19145d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent        int mStatus = 1; // 1 means neither error nor last sample loaded yet
19155d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent        List<Integer> mSamples = new ArrayList<Integer>();
1916a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent
1917a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent        public int status() {
1918a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent            return mStatus;
1919a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent        }
1920a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent
19215d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent        public void setSamples(int[] samples) {
19225d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent            for (int i = 0; i < samples.length; i++) {
19235d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                // do not wait ack for samples rejected upfront by SoundPool
19245d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                if (samples[i] > 0) {
19255d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    mSamples.add(samples[i]);
19265d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                }
19275d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent            }
1928a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent        }
1929a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent
1930a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent        public void onLoadComplete(SoundPool soundPool, int sampleId, int status) {
1931a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent            synchronized (mSoundEffectsLock) {
19325d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                int i = mSamples.indexOf(sampleId);
19335d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                if (i >= 0) {
19345d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    mSamples.remove(i);
1935a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent                }
19365d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                if ((status != 0) || mSamples. isEmpty()) {
19375d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    mStatus = status;
1938a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent                    mSoundEffectsLock.notify();
1939a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent                }
1940a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent            }
1941a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent        }
1942a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent    }
1943a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent
19444050c93601b3c3609b21cc1e18a29b64747e7fa9Eric Laurent    /** @see AudioManager#reloadAudioSettings() */
19454050c93601b3c3609b21cc1e18a29b64747e7fa9Eric Laurent    public void reloadAudioSettings() {
1946bc0fab1fc2db832ef86d8a33466ec4d68b103ca0Eric Laurent        readAudioSettings(false /*userSwitch*/);
1947bc0fab1fc2db832ef86d8a33466ec4d68b103ca0Eric Laurent    }
1948bc0fab1fc2db832ef86d8a33466ec4d68b103ca0Eric Laurent
1949bc0fab1fc2db832ef86d8a33466ec4d68b103ca0Eric Laurent    private void readAudioSettings(boolean userSwitch) {
19504050c93601b3c3609b21cc1e18a29b64747e7fa9Eric Laurent        // restore ringer mode, ringer mode affected streams, mute affected streams and vibrate settings
19514050c93601b3c3609b21cc1e18a29b64747e7fa9Eric Laurent        readPersistedSettings();
19524050c93601b3c3609b21cc1e18a29b64747e7fa9Eric Laurent
19534050c93601b3c3609b21cc1e18a29b64747e7fa9Eric Laurent        // restore volume settings
19544050c93601b3c3609b21cc1e18a29b64747e7fa9Eric Laurent        int numStreamTypes = AudioSystem.getNumStreamTypes();
19554050c93601b3c3609b21cc1e18a29b64747e7fa9Eric Laurent        for (int streamType = 0; streamType < numStreamTypes; streamType++) {
19564050c93601b3c3609b21cc1e18a29b64747e7fa9Eric Laurent            VolumeStreamState streamState = mStreamStates[streamType];
19574050c93601b3c3609b21cc1e18a29b64747e7fa9Eric Laurent
1958bc0fab1fc2db832ef86d8a33466ec4d68b103ca0Eric Laurent            if (userSwitch && mStreamVolumeAlias[streamType] == AudioSystem.STREAM_MUSIC) {
1959bc0fab1fc2db832ef86d8a33466ec4d68b103ca0Eric Laurent                continue;
1960bc0fab1fc2db832ef86d8a33466ec4d68b103ca0Eric Laurent            }
1961bc0fab1fc2db832ef86d8a33466ec4d68b103ca0Eric Laurent
19623172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent            synchronized (streamState) {
19633172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                streamState.readSettings();
1964a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent
19653172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                // unmute stream that was muted but is not affect by mute anymore
196642b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                if (streamState.isMuted() && ((!isStreamAffectedByMute(streamType) &&
196783a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent                        !isStreamMutedByRingerMode(streamType)) || mUseFixedVolume)) {
19683172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                    int size = streamState.mDeathHandlers.size();
19693172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                    for (int i = 0; i < size; i++) {
19703172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                        streamState.mDeathHandlers.get(i).mMuteCount = 1;
19713172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                        streamState.mDeathHandlers.get(i).mute(false);
19723172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                    }
19733172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                }
19744050c93601b3c3609b21cc1e18a29b64747e7fa9Eric Laurent            }
19754050c93601b3c3609b21cc1e18a29b64747e7fa9Eric Laurent        }
19764050c93601b3c3609b21cc1e18a29b64747e7fa9Eric Laurent
197733902db75011d863009585682bd08560c5b89a75Eric Laurent        // apply new ringer mode before checking volume for alias streams so that streams
197833902db75011d863009585682bd08560c5b89a75Eric Laurent        // muted by ringer mode have the correct volume
197933902db75011d863009585682bd08560c5b89a75Eric Laurent        setRingerModeInt(getRingerMode(), false);
198033902db75011d863009585682bd08560c5b89a75Eric Laurent
1981244820185269991186d07068b92985624cede4a5Eric Laurent        checkAllAliasStreamVolumes();
1982244820185269991186d07068b92985624cede4a5Eric Laurent
1983d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent        synchronized (mSafeMediaVolumeState) {
1984d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent            if (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_ACTIVE) {
1985f1a457d06c53a901ea08d2d3fb6e766bc06c4d4fEric Laurent                enforceSafeMediaVolume();
1986f1a457d06c53a901ea08d2d3fb6e766bc06c4d4fEric Laurent            }
1987c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent        }
19884050c93601b3c3609b21cc1e18a29b64747e7fa9Eric Laurent    }
19894050c93601b3c3609b21cc1e18a29b64747e7fa9Eric Laurent
1990961cae92540763226648813d111c5b5c3b0f1597Dianne Hackborn    /** @see AudioManager#setSpeakerphoneOn(boolean) */
1991c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent    public void setSpeakerphoneOn(boolean on){
1992dc1d17a1dbfc2ae01c20012133a836b62f5b6930Eric Laurent        if (!checkAudioSettingsPermission("setSpeakerphoneOn()")) {
1993dc1d17a1dbfc2ae01c20012133a836b62f5b6930Eric Laurent            return;
1994dc1d17a1dbfc2ae01c20012133a836b62f5b6930Eric Laurent        }
19957337bee7839238f244fad31112a45389f6ef907cJohan Gustavsson
19967337bee7839238f244fad31112a45389f6ef907cJohan Gustavsson        if (on) {
19977337bee7839238f244fad31112a45389f6ef907cJohan Gustavsson            if (mForcedUseForComm == AudioSystem.FORCE_BT_SCO) {
19987337bee7839238f244fad31112a45389f6ef907cJohan Gustavsson                    sendMsg(mAudioHandler, MSG_SET_FORCE_USE, SENDMSG_QUEUE,
19997337bee7839238f244fad31112a45389f6ef907cJohan Gustavsson                            AudioSystem.FOR_RECORD, AudioSystem.FORCE_NONE, null, 0);
20007337bee7839238f244fad31112a45389f6ef907cJohan Gustavsson            }
20017337bee7839238f244fad31112a45389f6ef907cJohan Gustavsson            mForcedUseForComm = AudioSystem.FORCE_SPEAKER;
20027337bee7839238f244fad31112a45389f6ef907cJohan Gustavsson        } else if (mForcedUseForComm == AudioSystem.FORCE_SPEAKER){
20037337bee7839238f244fad31112a45389f6ef907cJohan Gustavsson            mForcedUseForComm = AudioSystem.FORCE_NONE;
20047337bee7839238f244fad31112a45389f6ef907cJohan Gustavsson        }
2005fa640154f1f42121d81242b2f1a10f03e52f0014Eric Laurent
2006afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent        sendMsg(mAudioHandler, MSG_SET_FORCE_USE, SENDMSG_QUEUE,
2007fa640154f1f42121d81242b2f1a10f03e52f0014Eric Laurent                AudioSystem.FOR_COMMUNICATION, mForcedUseForComm, null, 0);
2008c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent    }
2009c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent
2010c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent    /** @see AudioManager#isSpeakerphoneOn() */
2011c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent    public boolean isSpeakerphoneOn() {
2012fa640154f1f42121d81242b2f1a10f03e52f0014Eric Laurent        return (mForcedUseForComm == AudioSystem.FORCE_SPEAKER);
2013c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent    }
2014c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent
2015961cae92540763226648813d111c5b5c3b0f1597Dianne Hackborn    /** @see AudioManager#setBluetoothScoOn(boolean) */
2016c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent    public void setBluetoothScoOn(boolean on){
2017dc1d17a1dbfc2ae01c20012133a836b62f5b6930Eric Laurent        if (!checkAudioSettingsPermission("setBluetoothScoOn()")) {
2018dc1d17a1dbfc2ae01c20012133a836b62f5b6930Eric Laurent            return;
2019dc1d17a1dbfc2ae01c20012133a836b62f5b6930Eric Laurent        }
20207337bee7839238f244fad31112a45389f6ef907cJohan Gustavsson
20217337bee7839238f244fad31112a45389f6ef907cJohan Gustavsson        if (on) {
20227337bee7839238f244fad31112a45389f6ef907cJohan Gustavsson            mForcedUseForComm = AudioSystem.FORCE_BT_SCO;
20237337bee7839238f244fad31112a45389f6ef907cJohan Gustavsson        } else if (mForcedUseForComm == AudioSystem.FORCE_BT_SCO) {
20247337bee7839238f244fad31112a45389f6ef907cJohan Gustavsson            mForcedUseForComm = AudioSystem.FORCE_NONE;
20257337bee7839238f244fad31112a45389f6ef907cJohan Gustavsson        }
2026fa640154f1f42121d81242b2f1a10f03e52f0014Eric Laurent
2027afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent        sendMsg(mAudioHandler, MSG_SET_FORCE_USE, SENDMSG_QUEUE,
2028fa640154f1f42121d81242b2f1a10f03e52f0014Eric Laurent                AudioSystem.FOR_COMMUNICATION, mForcedUseForComm, null, 0);
2029afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent        sendMsg(mAudioHandler, MSG_SET_FORCE_USE, SENDMSG_QUEUE,
2030fa640154f1f42121d81242b2f1a10f03e52f0014Eric Laurent                AudioSystem.FOR_RECORD, mForcedUseForComm, null, 0);
2031c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent    }
2032c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent
2033c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent    /** @see AudioManager#isBluetoothScoOn() */
2034c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent    public boolean isBluetoothScoOn() {
2035fa640154f1f42121d81242b2f1a10f03e52f0014Eric Laurent        return (mForcedUseForComm == AudioSystem.FORCE_BT_SCO);
2036c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent    }
2037c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent
2038961cae92540763226648813d111c5b5c3b0f1597Dianne Hackborn    /** @see AudioManager#setBluetoothA2dpOn(boolean) */
20397847211fb4699bf6018e29d214a918ed6657319bEric Laurent    public void setBluetoothA2dpOn(boolean on) {
2040c390bed06b4a572e273ead1254da9a932e04dce3Eric Laurent        synchronized (mBluetoothA2dpEnabledLock) {
2041c390bed06b4a572e273ead1254da9a932e04dce3Eric Laurent            mBluetoothA2dpEnabled = on;
2042c390bed06b4a572e273ead1254da9a932e04dce3Eric Laurent            sendMsg(mAudioHandler, MSG_SET_FORCE_BT_A2DP_USE, SENDMSG_QUEUE,
2043c390bed06b4a572e273ead1254da9a932e04dce3Eric Laurent                    AudioSystem.FOR_MEDIA,
2044c390bed06b4a572e273ead1254da9a932e04dce3Eric Laurent                    mBluetoothA2dpEnabled ? AudioSystem.FORCE_NONE : AudioSystem.FORCE_NO_BT_A2DP,
2045c390bed06b4a572e273ead1254da9a932e04dce3Eric Laurent                    null, 0);
2046c390bed06b4a572e273ead1254da9a932e04dce3Eric Laurent        }
20477847211fb4699bf6018e29d214a918ed6657319bEric Laurent    }
20487847211fb4699bf6018e29d214a918ed6657319bEric Laurent
20497847211fb4699bf6018e29d214a918ed6657319bEric Laurent    /** @see AudioManager#isBluetoothA2dpOn() */
20507847211fb4699bf6018e29d214a918ed6657319bEric Laurent    public boolean isBluetoothA2dpOn() {
20517847211fb4699bf6018e29d214a918ed6657319bEric Laurent        synchronized (mBluetoothA2dpEnabledLock) {
20527847211fb4699bf6018e29d214a918ed6657319bEric Laurent            return mBluetoothA2dpEnabled;
20537847211fb4699bf6018e29d214a918ed6657319bEric Laurent        }
20547847211fb4699bf6018e29d214a918ed6657319bEric Laurent    }
20557847211fb4699bf6018e29d214a918ed6657319bEric Laurent
20563def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent    /** @see AudioManager#startBluetoothSco() */
205783900754f357616b9e56eaf7fc85f49b8906e987Eric Laurent    public void startBluetoothSco(IBinder cb, int targetSdkVersion) {
205883900754f357616b9e56eaf7fc85f49b8906e987Eric Laurent        int scoAudioMode =
205983900754f357616b9e56eaf7fc85f49b8906e987Eric Laurent                (targetSdkVersion < Build.VERSION_CODES.JELLY_BEAN_MR2) ?
206083900754f357616b9e56eaf7fc85f49b8906e987Eric Laurent                        SCO_MODE_VIRTUAL_CALL : SCO_MODE_RAW;
206183900754f357616b9e56eaf7fc85f49b8906e987Eric Laurent        startBluetoothScoInt(cb, scoAudioMode);
206283900754f357616b9e56eaf7fc85f49b8906e987Eric Laurent    }
206383900754f357616b9e56eaf7fc85f49b8906e987Eric Laurent
206483900754f357616b9e56eaf7fc85f49b8906e987Eric Laurent    /** @see AudioManager#startBluetoothScoVirtualCall() */
206583900754f357616b9e56eaf7fc85f49b8906e987Eric Laurent    public void startBluetoothScoVirtualCall(IBinder cb) {
206683900754f357616b9e56eaf7fc85f49b8906e987Eric Laurent        startBluetoothScoInt(cb, SCO_MODE_VIRTUAL_CALL);
206783900754f357616b9e56eaf7fc85f49b8906e987Eric Laurent    }
206883900754f357616b9e56eaf7fc85f49b8906e987Eric Laurent
206983900754f357616b9e56eaf7fc85f49b8906e987Eric Laurent    void startBluetoothScoInt(IBinder cb, int scoAudioMode){
2070dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent        if (!checkAudioSettingsPermission("startBluetoothSco()") ||
20714a5eeb9c727d77bb57fef87a70c8c9cc23dbfee3Eric Laurent                !mSystemReady) {
20723def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent            return;
20733def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent        }
2074854938a72d968c1bc0de4e2b0ea87777cfebc045Eric Laurent        ScoClient client = getScoClient(cb, true);
2075f5a1fc3c0fd733acd21e1437f153ba27220be8ceEric Laurent        // The calling identity must be cleared before calling ScoClient.incCount().
2076f5a1fc3c0fd733acd21e1437f153ba27220be8ceEric Laurent        // inCount() calls requestScoState() which in turn can call BluetoothHeadset APIs
2077f5a1fc3c0fd733acd21e1437f153ba27220be8ceEric Laurent        // and this must be done on behalf of system server to make sure permissions are granted.
2078f5a1fc3c0fd733acd21e1437f153ba27220be8ceEric Laurent        // The caller identity must be cleared after getScoClient() because it is needed if a new
2079f5a1fc3c0fd733acd21e1437f153ba27220be8ceEric Laurent        // client is created.
2080f5a1fc3c0fd733acd21e1437f153ba27220be8ceEric Laurent        final long ident = Binder.clearCallingIdentity();
208183900754f357616b9e56eaf7fc85f49b8906e987Eric Laurent        client.incCount(scoAudioMode);
20822a57ca931fefe817b6110101289721acaacfc808Eric Laurent        Binder.restoreCallingIdentity(ident);
20833def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent    }
20843def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent
20853def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent    /** @see AudioManager#stopBluetoothSco() */
20863def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent    public void stopBluetoothSco(IBinder cb){
2087dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent        if (!checkAudioSettingsPermission("stopBluetoothSco()") ||
20884a5eeb9c727d77bb57fef87a70c8c9cc23dbfee3Eric Laurent                !mSystemReady) {
20893def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent            return;
20903def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent        }
2091854938a72d968c1bc0de4e2b0ea87777cfebc045Eric Laurent        ScoClient client = getScoClient(cb, false);
2092f5a1fc3c0fd733acd21e1437f153ba27220be8ceEric Laurent        // The calling identity must be cleared before calling ScoClient.decCount().
2093f5a1fc3c0fd733acd21e1437f153ba27220be8ceEric Laurent        // decCount() calls requestScoState() which in turn can call BluetoothHeadset APIs
2094f5a1fc3c0fd733acd21e1437f153ba27220be8ceEric Laurent        // and this must be done on behalf of system server to make sure permissions are granted.
2095f5a1fc3c0fd733acd21e1437f153ba27220be8ceEric Laurent        final long ident = Binder.clearCallingIdentity();
2096854938a72d968c1bc0de4e2b0ea87777cfebc045Eric Laurent        if (client != null) {
2097854938a72d968c1bc0de4e2b0ea87777cfebc045Eric Laurent            client.decCount();
2098854938a72d968c1bc0de4e2b0ea87777cfebc045Eric Laurent        }
20992a57ca931fefe817b6110101289721acaacfc808Eric Laurent        Binder.restoreCallingIdentity(ident);
21003def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent    }
21013def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent
21027847211fb4699bf6018e29d214a918ed6657319bEric Laurent
21033def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent    private class ScoClient implements IBinder.DeathRecipient {
21043def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent        private IBinder mCb; // To be notified of client's death
2105f1ddd51f9cd2f92b922bc636c307210a8d587c25Marco Nelissen        private int mCreatorPid;
21063def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent        private int mStartcount; // number of SCO connections started by this client
21073def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent
21083def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent        ScoClient(IBinder cb) {
21093def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent            mCb = cb;
2110f1ddd51f9cd2f92b922bc636c307210a8d587c25Marco Nelissen            mCreatorPid = Binder.getCallingPid();
21113def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent            mStartcount = 0;
21123def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent        }
21133def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent
21143def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent        public void binderDied() {
21153def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent            synchronized(mScoClients) {
21163def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                Log.w(TAG, "SCO client died");
21173def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                int index = mScoClients.indexOf(this);
21183def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                if (index < 0) {
21193def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                    Log.w(TAG, "unregistered SCO client died");
21203def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                } else {
21213def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                    clearCount(true);
21223def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                    mScoClients.remove(this);
21233def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                }
21243def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent            }
21253def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent        }
21263def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent
212783900754f357616b9e56eaf7fc85f49b8906e987Eric Laurent        public void incCount(int scoAudioMode) {
21283def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent            synchronized(mScoClients) {
212983900754f357616b9e56eaf7fc85f49b8906e987Eric Laurent                requestScoState(BluetoothHeadset.STATE_AUDIO_CONNECTED, scoAudioMode);
21303def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                if (mStartcount == 0) {
21313def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                    try {
21323def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                        mCb.linkToDeath(this, 0);
21333def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                    } catch (RemoteException e) {
21343def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                        // client has already died!
21353def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                        Log.w(TAG, "ScoClient  incCount() could not link to "+mCb+" binder death");
21363def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                    }
21373def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                }
21383def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                mStartcount++;
21393def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent            }
21403def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent        }
21413def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent
21423def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent        public void decCount() {
21433def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent            synchronized(mScoClients) {
21443def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                if (mStartcount == 0) {
21453def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                    Log.w(TAG, "ScoClient.decCount() already 0");
21463def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                } else {
21473def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                    mStartcount--;
21483def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                    if (mStartcount == 0) {
2149e2dd8c4592762414c2c27e4589be7edc91a5ecaeEric Laurent                        try {
2150e2dd8c4592762414c2c27e4589be7edc91a5ecaeEric Laurent                            mCb.unlinkToDeath(this, 0);
2151e2dd8c4592762414c2c27e4589be7edc91a5ecaeEric Laurent                        } catch (NoSuchElementException e) {
2152e2dd8c4592762414c2c27e4589be7edc91a5ecaeEric Laurent                            Log.w(TAG, "decCount() going to 0 but not registered to binder");
2153e2dd8c4592762414c2c27e4589be7edc91a5ecaeEric Laurent                        }
21543def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                    }
2155c18c9138cee0f0859bcab636a004ce92ca4a9ab5Eric Laurent                    requestScoState(BluetoothHeadset.STATE_AUDIO_DISCONNECTED, 0);
21563def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                }
21573def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent            }
21583def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent        }
21593def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent
21603def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent        public void clearCount(boolean stopSco) {
21613def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent            synchronized(mScoClients) {
2162e2dd8c4592762414c2c27e4589be7edc91a5ecaeEric Laurent                if (mStartcount != 0) {
2163e2dd8c4592762414c2c27e4589be7edc91a5ecaeEric Laurent                    try {
2164e2dd8c4592762414c2c27e4589be7edc91a5ecaeEric Laurent                        mCb.unlinkToDeath(this, 0);
2165e2dd8c4592762414c2c27e4589be7edc91a5ecaeEric Laurent                    } catch (NoSuchElementException e) {
2166e2dd8c4592762414c2c27e4589be7edc91a5ecaeEric Laurent                        Log.w(TAG, "clearCount() mStartcount: "+mStartcount+" != 0 but not registered to binder");
2167e2dd8c4592762414c2c27e4589be7edc91a5ecaeEric Laurent                    }
2168e2dd8c4592762414c2c27e4589be7edc91a5ecaeEric Laurent                }
21693def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                mStartcount = 0;
21703def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                if (stopSco) {
2171c18c9138cee0f0859bcab636a004ce92ca4a9ab5Eric Laurent                    requestScoState(BluetoothHeadset.STATE_AUDIO_DISCONNECTED, 0);
21723def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                }
21733def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent            }
21743def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent        }
21753def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent
21763def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent        public int getCount() {
21773def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent            return mStartcount;
21783def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent        }
21793def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent
21803def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent        public IBinder getBinder() {
21813def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent            return mCb;
21823def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent        }
21833def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent
2184d7454be47f4111c0478a502353e11dea401378bdEric Laurent        public int getPid() {
2185d7454be47f4111c0478a502353e11dea401378bdEric Laurent            return mCreatorPid;
2186d7454be47f4111c0478a502353e11dea401378bdEric Laurent        }
2187d7454be47f4111c0478a502353e11dea401378bdEric Laurent
21883def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent        public int totalCount() {
21893def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent            synchronized(mScoClients) {
21903def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                int count = 0;
21913def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                int size = mScoClients.size();
21923def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                for (int i = 0; i < size; i++) {
21933def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                    count += mScoClients.get(i).getCount();
21943def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                }
21953def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                return count;
21963def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent            }
21973def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent        }
21983def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent
219983900754f357616b9e56eaf7fc85f49b8906e987Eric Laurent        private void requestScoState(int state, int scoAudioMode) {
220062ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent            checkScoAudioState();
2201dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent            if (totalCount() == 0) {
2202dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                if (state == BluetoothHeadset.STATE_AUDIO_CONNECTED) {
2203dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                    // Make sure that the state transitions to CONNECTING even if we cannot initiate
2204dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                    // the connection.
2205dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                    broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_CONNECTING);
2206dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                    // Accept SCO audio activation only in NORMAL audio mode or if the mode is
2207f1ddd51f9cd2f92b922bc636c307210a8d587c25Marco Nelissen                    // currently controlled by the same client process.
22089f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                    synchronized(mSetModeDeathHandlers) {
22099f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                        if ((mSetModeDeathHandlers.isEmpty() ||
22109f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                                mSetModeDeathHandlers.get(0).getPid() == mCreatorPid) &&
22119f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                                (mScoAudioState == SCO_STATE_INACTIVE ||
22129f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                                 mScoAudioState == SCO_STATE_DEACTIVATE_REQ)) {
22139f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                            if (mScoAudioState == SCO_STATE_INACTIVE) {
221483900754f357616b9e56eaf7fc85f49b8906e987Eric Laurent                                mScoAudioMode = scoAudioMode;
22159f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                                if (mBluetoothHeadset != null && mBluetoothHeadsetDevice != null) {
2216c18c9138cee0f0859bcab636a004ce92ca4a9ab5Eric Laurent                                    boolean status;
2217c18c9138cee0f0859bcab636a004ce92ca4a9ab5Eric Laurent                                    if (mScoAudioMode == SCO_MODE_RAW) {
2218c18c9138cee0f0859bcab636a004ce92ca4a9ab5Eric Laurent                                        status = mBluetoothHeadset.connectAudio();
2219c18c9138cee0f0859bcab636a004ce92ca4a9ab5Eric Laurent                                    } else {
2220c18c9138cee0f0859bcab636a004ce92ca4a9ab5Eric Laurent                                        status = mBluetoothHeadset.startScoUsingVirtualVoiceCall(
2221c18c9138cee0f0859bcab636a004ce92ca4a9ab5Eric Laurent                                                                            mBluetoothHeadsetDevice);
2222c18c9138cee0f0859bcab636a004ce92ca4a9ab5Eric Laurent                                    }
2223c18c9138cee0f0859bcab636a004ce92ca4a9ab5Eric Laurent                                    if (status) {
22249f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                                        mScoAudioState = SCO_STATE_ACTIVE_INTERNAL;
22259f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                                    } else {
22269f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                                        broadcastScoConnectionState(
22279f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                                                AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
22289f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                                    }
22299f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                                } else if (getBluetoothHeadset()) {
22309f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                                    mScoAudioState = SCO_STATE_ACTIVATE_REQ;
2231dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                                }
22329f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                            } else {
22339f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                                mScoAudioState = SCO_STATE_ACTIVE_INTERNAL;
22349f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                                broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_CONNECTED);
2235dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                            }
2236dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                        } else {
22379f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                            broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
2238dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                        }
2239dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                    }
224062ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent                } else if (state == BluetoothHeadset.STATE_AUDIO_DISCONNECTED &&
2241dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                              (mScoAudioState == SCO_STATE_ACTIVE_INTERNAL ||
2242dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                               mScoAudioState == SCO_STATE_ACTIVATE_REQ)) {
2243dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                    if (mScoAudioState == SCO_STATE_ACTIVE_INTERNAL) {
2244671db6f3ba1fdb3c907e0735fe6d0d284f5c34deMarco Nelissen                        if (mBluetoothHeadset != null && mBluetoothHeadsetDevice != null) {
2245c18c9138cee0f0859bcab636a004ce92ca4a9ab5Eric Laurent                            boolean status;
2246c18c9138cee0f0859bcab636a004ce92ca4a9ab5Eric Laurent                            if (mScoAudioMode == SCO_MODE_RAW) {
2247c18c9138cee0f0859bcab636a004ce92ca4a9ab5Eric Laurent                                status = mBluetoothHeadset.disconnectAudio();
2248c18c9138cee0f0859bcab636a004ce92ca4a9ab5Eric Laurent                            } else {
2249c18c9138cee0f0859bcab636a004ce92ca4a9ab5Eric Laurent                                status = mBluetoothHeadset.stopScoUsingVirtualVoiceCall(
2250c18c9138cee0f0859bcab636a004ce92ca4a9ab5Eric Laurent                                                                        mBluetoothHeadsetDevice);
2251c18c9138cee0f0859bcab636a004ce92ca4a9ab5Eric Laurent                            }
2252c18c9138cee0f0859bcab636a004ce92ca4a9ab5Eric Laurent                            if (!status) {
2253dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                                mScoAudioState = SCO_STATE_INACTIVE;
2254dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                                broadcastScoConnectionState(
2255dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                                        AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
2256dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                            }
2257dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                        } else if (getBluetoothHeadset()) {
2258dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                            mScoAudioState = SCO_STATE_DEACTIVATE_REQ;
2259dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                        }
2260dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                    } else {
2261dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                        mScoAudioState = SCO_STATE_INACTIVE;
2262dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                        broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
2263dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                    }
22643def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                }
22653def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent            }
22663def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent        }
22673def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent    }
22683def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent
226962ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent    private void checkScoAudioState() {
227062ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent        if (mBluetoothHeadset != null && mBluetoothHeadsetDevice != null &&
2271dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                mScoAudioState == SCO_STATE_INACTIVE &&
227262ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent                mBluetoothHeadset.getAudioState(mBluetoothHeadsetDevice)
227362ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent                != BluetoothHeadset.STATE_AUDIO_DISCONNECTED) {
227462ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent            mScoAudioState = SCO_STATE_ACTIVE_EXTERNAL;
227562ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent        }
227662ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent    }
227762ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent
2278854938a72d968c1bc0de4e2b0ea87777cfebc045Eric Laurent    private ScoClient getScoClient(IBinder cb, boolean create) {
22793def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent        synchronized(mScoClients) {
2280854938a72d968c1bc0de4e2b0ea87777cfebc045Eric Laurent            ScoClient client = null;
22813def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent            int size = mScoClients.size();
22823def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent            for (int i = 0; i < size; i++) {
22833def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                client = mScoClients.get(i);
22843def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                if (client.getBinder() == cb)
22853def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                    return client;
22863def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent            }
2287854938a72d968c1bc0de4e2b0ea87777cfebc045Eric Laurent            if (create) {
2288854938a72d968c1bc0de4e2b0ea87777cfebc045Eric Laurent                client = new ScoClient(cb);
2289854938a72d968c1bc0de4e2b0ea87777cfebc045Eric Laurent                mScoClients.add(client);
2290854938a72d968c1bc0de4e2b0ea87777cfebc045Eric Laurent            }
22913def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent            return client;
22923def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent        }
22933def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent    }
22943def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent
2295d7454be47f4111c0478a502353e11dea401378bdEric Laurent    public void clearAllScoClients(int exceptPid, boolean stopSco) {
22963def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent        synchronized(mScoClients) {
2297854938a72d968c1bc0de4e2b0ea87777cfebc045Eric Laurent            ScoClient savedClient = null;
22983def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent            int size = mScoClients.size();
22993def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent            for (int i = 0; i < size; i++) {
2300854938a72d968c1bc0de4e2b0ea87777cfebc045Eric Laurent                ScoClient cl = mScoClients.get(i);
2301d7454be47f4111c0478a502353e11dea401378bdEric Laurent                if (cl.getPid() != exceptPid) {
2302854938a72d968c1bc0de4e2b0ea87777cfebc045Eric Laurent                    cl.clearCount(stopSco);
2303854938a72d968c1bc0de4e2b0ea87777cfebc045Eric Laurent                } else {
2304854938a72d968c1bc0de4e2b0ea87777cfebc045Eric Laurent                    savedClient = cl;
2305854938a72d968c1bc0de4e2b0ea87777cfebc045Eric Laurent                }
2306854938a72d968c1bc0de4e2b0ea87777cfebc045Eric Laurent            }
2307854938a72d968c1bc0de4e2b0ea87777cfebc045Eric Laurent            mScoClients.clear();
2308854938a72d968c1bc0de4e2b0ea87777cfebc045Eric Laurent            if (savedClient != null) {
2309854938a72d968c1bc0de4e2b0ea87777cfebc045Eric Laurent                mScoClients.add(savedClient);
23103def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent            }
23113def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent        }
23123def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent    }
23133def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent
2314dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent    private boolean getBluetoothHeadset() {
2315dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent        boolean result = false;
2316dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent        BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
2317dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent        if (adapter != null) {
2318dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent            result = adapter.getProfileProxy(mContext, mBluetoothProfileServiceListener,
2319dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                                    BluetoothProfile.HEADSET);
2320dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent        }
2321dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent        // If we could not get a bluetooth headset proxy, send a failure message
2322dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent        // without delay to reset the SCO audio state and clear SCO clients.
2323dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent        // If we could get a proxy, send a delayed failure message that will reset our state
2324dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent        // in case we don't receive onServiceConnected().
2325afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent        sendMsg(mAudioHandler, MSG_BT_HEADSET_CNCT_FAILED,
2326dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                SENDMSG_REPLACE, 0, 0, null, result ? BT_HEADSET_CNCT_TIMEOUT_MS : 0);
2327dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent        return result;
2328dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent    }
2329dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent
2330d7454be47f4111c0478a502353e11dea401378bdEric Laurent    private void disconnectBluetoothSco(int exceptPid) {
2331dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent        synchronized(mScoClients) {
2332dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent            checkScoAudioState();
2333dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent            if (mScoAudioState == SCO_STATE_ACTIVE_EXTERNAL ||
2334dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                    mScoAudioState == SCO_STATE_DEACTIVATE_EXT_REQ) {
2335dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                if (mBluetoothHeadsetDevice != null) {
2336dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                    if (mBluetoothHeadset != null) {
2337dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                        if (!mBluetoothHeadset.stopVoiceRecognition(
2338b06ac839dd2d0437fc8314f6deb7233af5af521eEric Laurent                                mBluetoothHeadsetDevice)) {
2339afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent                            sendMsg(mAudioHandler, MSG_BT_HEADSET_CNCT_FAILED,
2340dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                                    SENDMSG_REPLACE, 0, 0, null, 0);
2341dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                        }
2342dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                    } else if (mScoAudioState == SCO_STATE_ACTIVE_EXTERNAL &&
2343dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                            getBluetoothHeadset()) {
2344dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                        mScoAudioState = SCO_STATE_DEACTIVATE_EXT_REQ;
2345dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                    }
2346dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                }
2347dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent            } else {
2348d7454be47f4111c0478a502353e11dea401378bdEric Laurent                clearAllScoClients(exceptPid, true);
2349dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent            }
2350dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent        }
2351dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent    }
2352dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent
2353dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent    private void resetBluetoothSco() {
2354dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent        synchronized(mScoClients) {
2355d7454be47f4111c0478a502353e11dea401378bdEric Laurent            clearAllScoClients(0, false);
2356dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent            mScoAudioState = SCO_STATE_INACTIVE;
2357dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent            broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
2358dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent        }
2359dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent    }
2360dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent
2361dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent    private void broadcastScoConnectionState(int state) {
23622a57ca931fefe817b6110101289721acaacfc808Eric Laurent        sendMsg(mAudioHandler, MSG_BROADCAST_BT_CONNECTION_STATE,
23632a57ca931fefe817b6110101289721acaacfc808Eric Laurent                SENDMSG_QUEUE, state, 0, null, 0);
23642a57ca931fefe817b6110101289721acaacfc808Eric Laurent    }
23652a57ca931fefe817b6110101289721acaacfc808Eric Laurent
23662a57ca931fefe817b6110101289721acaacfc808Eric Laurent    private void onBroadcastScoConnectionState(int state) {
2367dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent        if (state != mScoConnectionState) {
2368dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent            Intent newIntent = new Intent(AudioManager.ACTION_SCO_AUDIO_STATE_UPDATED);
2369dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent            newIntent.putExtra(AudioManager.EXTRA_SCO_AUDIO_STATE, state);
2370dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent            newIntent.putExtra(AudioManager.EXTRA_SCO_AUDIO_PREVIOUS_STATE,
2371dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                    mScoConnectionState);
23725ac72a29593ab9a20337a2225df52bdf4754be02Dianne Hackborn            sendStickyBroadcastToAll(newIntent);
2373dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent            mScoConnectionState = state;
2374dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent        }
2375dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent    }
2376dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent
237782aa7f017daaaeb96c13e6e3491d5037ab471085Jaikumar Ganesh    private BluetoothProfile.ServiceListener mBluetoothProfileServiceListener =
237882aa7f017daaaeb96c13e6e3491d5037ab471085Jaikumar Ganesh        new BluetoothProfile.ServiceListener() {
237982aa7f017daaaeb96c13e6e3491d5037ab471085Jaikumar Ganesh        public void onServiceConnected(int profile, BluetoothProfile proxy) {
23806bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent            BluetoothDevice btDevice;
23816bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent            List<BluetoothDevice> deviceList;
23826bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent            switch(profile) {
23836bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent            case BluetoothProfile.A2DP:
23845a0cf7a27f3953a1266af48543ccd9024f4cd89fJohn Du                synchronized (mA2dpAvrcpLock) {
23855a0cf7a27f3953a1266af48543ccd9024f4cd89fJohn Du                    mA2dp = (BluetoothA2dp) proxy;
23865a0cf7a27f3953a1266af48543ccd9024f4cd89fJohn Du                    deviceList = mA2dp.getConnectedDevices();
23875a0cf7a27f3953a1266af48543ccd9024f4cd89fJohn Du                    if (deviceList.size() > 0) {
23885a0cf7a27f3953a1266af48543ccd9024f4cd89fJohn Du                        btDevice = deviceList.get(0);
23895a0cf7a27f3953a1266af48543ccd9024f4cd89fJohn Du                        synchronized (mConnectedDevices) {
23905a0cf7a27f3953a1266af48543ccd9024f4cd89fJohn Du                            int state = mA2dp.getConnectionState(btDevice);
23915a0cf7a27f3953a1266af48543ccd9024f4cd89fJohn Du                            int delay = checkSendBecomingNoisyIntent(
23920a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood                                                AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
23930a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood                                                (state == BluetoothA2dp.STATE_CONNECTED) ? 1 : 0);
23945a0cf7a27f3953a1266af48543ccd9024f4cd89fJohn Du                            queueMsgUnderWakeLock(mAudioHandler,
23950a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood                                    MSG_SET_A2DP_SINK_CONNECTION_STATE,
23965a0cf7a27f3953a1266af48543ccd9024f4cd89fJohn Du                                    state,
23975a0cf7a27f3953a1266af48543ccd9024f4cd89fJohn Du                                    0,
23985a0cf7a27f3953a1266af48543ccd9024f4cd89fJohn Du                                    btDevice,
23995a0cf7a27f3953a1266af48543ccd9024f4cd89fJohn Du                                    delay);
24005a0cf7a27f3953a1266af48543ccd9024f4cd89fJohn Du                        }
2401b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent                    }
24026bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                }
24036bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                break;
24046bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent
24050a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood            case BluetoothProfile.A2DP_SINK:
24060a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood                deviceList = proxy.getConnectedDevices();
24070a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood                if (deviceList.size() > 0) {
24080a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood                    btDevice = deviceList.get(0);
24090a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood                    synchronized (mConnectedDevices) {
24100a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood                        int state = proxy.getConnectionState(btDevice);
24110a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood                        queueMsgUnderWakeLock(mAudioHandler,
24120a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood                                MSG_SET_A2DP_SRC_CONNECTION_STATE,
24130a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood                                state,
24140a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood                                0,
24150a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood                                btDevice,
24160a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood                                0 /* delay */);
24170a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood                    }
24180a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood                }
24190a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood                break;
24200a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood
24216bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent            case BluetoothProfile.HEADSET:
24226bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                synchronized (mScoClients) {
24236bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                    // Discard timeout message
24246bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                    mAudioHandler.removeMessages(MSG_BT_HEADSET_CNCT_FAILED);
24256bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                    mBluetoothHeadset = (BluetoothHeadset) proxy;
24266bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                    deviceList = mBluetoothHeadset.getConnectedDevices();
24276bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                    if (deviceList.size() > 0) {
24286bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                        mBluetoothHeadsetDevice = deviceList.get(0);
24296bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                    } else {
24306bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                        mBluetoothHeadsetDevice = null;
2431dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                    }
24326bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                    // Refresh SCO audio state
24336bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                    checkScoAudioState();
24346bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                    // Continue pending action if any
24356bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                    if (mScoAudioState == SCO_STATE_ACTIVATE_REQ ||
24366bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                            mScoAudioState == SCO_STATE_DEACTIVATE_REQ ||
24376bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                            mScoAudioState == SCO_STATE_DEACTIVATE_EXT_REQ) {
24386bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                        boolean status = false;
24396bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                        if (mBluetoothHeadsetDevice != null) {
24406bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                            switch (mScoAudioState) {
24416bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                            case SCO_STATE_ACTIVATE_REQ:
24426bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                                mScoAudioState = SCO_STATE_ACTIVE_INTERNAL;
2443c18c9138cee0f0859bcab636a004ce92ca4a9ab5Eric Laurent                                if (mScoAudioMode == SCO_MODE_RAW) {
2444c18c9138cee0f0859bcab636a004ce92ca4a9ab5Eric Laurent                                    status = mBluetoothHeadset.connectAudio();
2445c18c9138cee0f0859bcab636a004ce92ca4a9ab5Eric Laurent                                } else {
2446c18c9138cee0f0859bcab636a004ce92ca4a9ab5Eric Laurent                                    status = mBluetoothHeadset.startScoUsingVirtualVoiceCall(
2447c18c9138cee0f0859bcab636a004ce92ca4a9ab5Eric Laurent                                                                        mBluetoothHeadsetDevice);
2448c18c9138cee0f0859bcab636a004ce92ca4a9ab5Eric Laurent                                }
24496bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                                break;
24506bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                            case SCO_STATE_DEACTIVATE_REQ:
2451c18c9138cee0f0859bcab636a004ce92ca4a9ab5Eric Laurent                                if (mScoAudioMode == SCO_MODE_RAW) {
2452c18c9138cee0f0859bcab636a004ce92ca4a9ab5Eric Laurent                                    status = mBluetoothHeadset.disconnectAudio();
2453c18c9138cee0f0859bcab636a004ce92ca4a9ab5Eric Laurent                                } else {
2454c18c9138cee0f0859bcab636a004ce92ca4a9ab5Eric Laurent                                    status = mBluetoothHeadset.stopScoUsingVirtualVoiceCall(
2455c18c9138cee0f0859bcab636a004ce92ca4a9ab5Eric Laurent                                                                        mBluetoothHeadsetDevice);
2456c18c9138cee0f0859bcab636a004ce92ca4a9ab5Eric Laurent                                }
24576bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                                break;
24586bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                            case SCO_STATE_DEACTIVATE_EXT_REQ:
24596bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                                status = mBluetoothHeadset.stopVoiceRecognition(
24606bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                                        mBluetoothHeadsetDevice);
24616bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                            }
24626bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                        }
24636bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                        if (!status) {
2464afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent                            sendMsg(mAudioHandler, MSG_BT_HEADSET_CNCT_FAILED,
24656bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                                    SENDMSG_REPLACE, 0, 0, null, 0);
24666bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                        }
2467dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                    }
2468dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                }
24696bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                break;
24706bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent
24716bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent            default:
24726bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                break;
24733def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent            }
24743def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent        }
247582aa7f017daaaeb96c13e6e3491d5037ab471085Jaikumar Ganesh        public void onServiceDisconnected(int profile) {
24766bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent            switch(profile) {
24776bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent            case BluetoothProfile.A2DP:
24785a0cf7a27f3953a1266af48543ccd9024f4cd89fJohn Du                synchronized (mA2dpAvrcpLock) {
24795a0cf7a27f3953a1266af48543ccd9024f4cd89fJohn Du                    mA2dp = null;
24805a0cf7a27f3953a1266af48543ccd9024f4cd89fJohn Du                    synchronized (mConnectedDevices) {
24815a0cf7a27f3953a1266af48543ccd9024f4cd89fJohn Du                        if (mConnectedDevices.containsKey(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP)) {
24825a0cf7a27f3953a1266af48543ccd9024f4cd89fJohn Du                            makeA2dpDeviceUnavailableNow(
24835a0cf7a27f3953a1266af48543ccd9024f4cd89fJohn Du                                    mConnectedDevices.get(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP));
24845a0cf7a27f3953a1266af48543ccd9024f4cd89fJohn Du                        }
24856bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                    }
24866bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                }
24876bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                break;
24886bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent
24890a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood            case BluetoothProfile.A2DP_SINK:
24900a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood                synchronized (mConnectedDevices) {
24910a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood                    if (mConnectedDevices.containsKey(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP)) {
24920a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood                        makeA2dpSrcUnavailable(
24930a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood                                mConnectedDevices.get(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP));
24940a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood                    }
24950a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood                }
24960a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood                break;
24970a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood
24986bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent            case BluetoothProfile.HEADSET:
24996bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                synchronized (mScoClients) {
25006bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                    mBluetoothHeadset = null;
25016bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                }
25026bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                break;
25036bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent
25046bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent            default:
25056bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                break;
25063def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent            }
25073def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent        }
25083def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent    };
2509d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi
2510c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent    private void onCheckMusicActive() {
2511d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent        synchronized (mSafeMediaVolumeState) {
2512d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent            if (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_INACTIVE) {
2513c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent                int device = getDeviceForStream(AudioSystem.STREAM_MUSIC);
2514c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent
2515c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent                if ((device & mSafeMediaVolumeDevices) != 0) {
2516c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent                    sendMsg(mAudioHandler,
2517c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent                            MSG_CHECK_MUSIC_ACTIVE,
2518c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent                            SENDMSG_REPLACE,
2519f1a457d06c53a901ea08d2d3fb6e766bc06c4d4fEric Laurent                            0,
2520c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent                            0,
2521c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent                            null,
2522c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent                            MUSIC_ACTIVE_POLL_PERIOD_MS);
252342b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                    int index = mStreamStates[AudioSystem.STREAM_MUSIC].getIndex(device);
2524f1a457d06c53a901ea08d2d3fb6e766bc06c4d4fEric Laurent                    if (AudioSystem.isStreamActive(AudioSystem.STREAM_MUSIC, 0) &&
2525f1a457d06c53a901ea08d2d3fb6e766bc06c4d4fEric Laurent                            (index > mSafeMediaVolumeIndex)) {
2526c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent                        // Approximate cumulative active music time
2527c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent                        mMusicActiveMs += MUSIC_ACTIVE_POLL_PERIOD_MS;
2528c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent                        if (mMusicActiveMs > UNSAFE_VOLUME_MUSIC_ACTIVE_MS_MAX) {
2529c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent                            setSafeMediaVolumeEnabled(true);
2530c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent                            mMusicActiveMs = 0;
2531c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent                        }
2532c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent                    }
2533c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent                }
2534c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent            }
2535c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent        }
2536c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent    }
2537c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent
2538d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent    private void onConfigureSafeVolume(boolean force) {
2539d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent        synchronized (mSafeMediaVolumeState) {
2540d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent            int mcc = mContext.getResources().getConfiguration().mcc;
2541d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent            if ((mMcc != mcc) || ((mMcc == 0) && force)) {
2542d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent                mSafeMediaVolumeIndex = mContext.getResources().getInteger(
2543d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent                        com.android.internal.R.integer.config_safe_media_volume_index) * 10;
2544d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent                boolean safeMediaVolumeEnabled = mContext.getResources().getBoolean(
2545d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent                        com.android.internal.R.bool.config_safe_media_volume_enabled);
254605274f348e12983eb8613cc6eb9ae561e8197e28Eric Laurent
254705274f348e12983eb8613cc6eb9ae561e8197e28Eric Laurent                // The persisted state is either "disabled" or "active": this is the state applied
254805274f348e12983eb8613cc6eb9ae561e8197e28Eric Laurent                // next time we boot and cannot be "inactive"
254905274f348e12983eb8613cc6eb9ae561e8197e28Eric Laurent                int persistedState;
2550d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent                if (safeMediaVolumeEnabled) {
255105274f348e12983eb8613cc6eb9ae561e8197e28Eric Laurent                    persistedState = SAFE_MEDIA_VOLUME_ACTIVE;
255205274f348e12983eb8613cc6eb9ae561e8197e28Eric Laurent                    // The state can already be "inactive" here if the user has forced it before
255305274f348e12983eb8613cc6eb9ae561e8197e28Eric Laurent                    // the 30 seconds timeout for forced configuration. In this case we don't reset
255405274f348e12983eb8613cc6eb9ae561e8197e28Eric Laurent                    // it to "active".
255505274f348e12983eb8613cc6eb9ae561e8197e28Eric Laurent                    if (mSafeMediaVolumeState != SAFE_MEDIA_VOLUME_INACTIVE) {
255605274f348e12983eb8613cc6eb9ae561e8197e28Eric Laurent                        mSafeMediaVolumeState = SAFE_MEDIA_VOLUME_ACTIVE;
255705274f348e12983eb8613cc6eb9ae561e8197e28Eric Laurent                        enforceSafeMediaVolume();
255805274f348e12983eb8613cc6eb9ae561e8197e28Eric Laurent                    }
2559d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent                } else {
256005274f348e12983eb8613cc6eb9ae561e8197e28Eric Laurent                    persistedState = SAFE_MEDIA_VOLUME_DISABLED;
2561d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent                    mSafeMediaVolumeState = SAFE_MEDIA_VOLUME_DISABLED;
2562d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent                }
2563d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent                mMcc = mcc;
256405274f348e12983eb8613cc6eb9ae561e8197e28Eric Laurent                sendMsg(mAudioHandler,
256505274f348e12983eb8613cc6eb9ae561e8197e28Eric Laurent                        MSG_PERSIST_SAFE_VOLUME_STATE,
256605274f348e12983eb8613cc6eb9ae561e8197e28Eric Laurent                        SENDMSG_QUEUE,
256705274f348e12983eb8613cc6eb9ae561e8197e28Eric Laurent                        persistedState,
256805274f348e12983eb8613cc6eb9ae561e8197e28Eric Laurent                        0,
256905274f348e12983eb8613cc6eb9ae561e8197e28Eric Laurent                        null,
257005274f348e12983eb8613cc6eb9ae561e8197e28Eric Laurent                        0);
2571d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent            }
2572d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent        }
2573d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent    }
2574d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent
25759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    ///////////////////////////////////////////////////////////////////////////
25769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // Internal methods
25779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    ///////////////////////////////////////////////////////////////////////////
25789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
25799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
25809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Checks if the adjustment should change ringer mode instead of just
25819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * adjusting volume. If so, this will set the proper ringer mode and volume
25829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * indices on the stream states.
25839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
2584a11b4affcad3d255aa723a89b768ea222506f2e8John Spurlock    private int checkForRingerModeChange(int oldIndex, int direction,  int step) {
2585a11b4affcad3d255aa723a89b768ea222506f2e8John Spurlock        int result = FLAG_ADJUST_VOLUME;
2586ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten        int ringerMode = getRingerMode();
2587bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent
2588bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent        switch (ringerMode) {
2589bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent        case RINGER_MODE_NORMAL:
2590bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent            if (direction == AudioManager.ADJUST_LOWER) {
2591bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent                if (mHasVibrator) {
2592244820185269991186d07068b92985624cede4a5Eric Laurent                    // "step" is the delta in internal index units corresponding to a
2593244820185269991186d07068b92985624cede4a5Eric Laurent                    // change of 1 in UI index units.
2594244820185269991186d07068b92985624cede4a5Eric Laurent                    // Because of rounding when rescaling from one stream index range to its alias
2595244820185269991186d07068b92985624cede4a5Eric Laurent                    // index range, we cannot simply test oldIndex == step:
2596244820185269991186d07068b92985624cede4a5Eric Laurent                    //   (step <= oldIndex < 2 * step) is equivalent to: (old UI index == 1)
2597244820185269991186d07068b92985624cede4a5Eric Laurent                    if (step <= oldIndex && oldIndex < 2 * step) {
2598bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent                        ringerMode = RINGER_MODE_VIBRATE;
2599bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent                    }
2600bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent                } else {
2601244820185269991186d07068b92985624cede4a5Eric Laurent                    // (oldIndex < step) is equivalent to (old UI index == 0)
26028600534df66c2ff5846ed230b50c56229322d48aJohn Spurlock                    if ((oldIndex < step)
26038600534df66c2ff5846ed230b50c56229322d48aJohn Spurlock                            && VOLUME_SETS_RINGER_MODE_SILENT
26048600534df66c2ff5846ed230b50c56229322d48aJohn Spurlock                            && mPrevVolDirection != AudioManager.ADJUST_LOWER) {
2605bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent                        ringerMode = RINGER_MODE_SILENT;
2606bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent                    }
26073d4c06f90726a85e89dab13c41ddc15b9c912a3fEric Laurent                }
26086329bf7b1e2217c6c9477bd57349a1edade18417Daniel Sandler            }
2609bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent            break;
2610bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent        case RINGER_MODE_VIBRATE:
2611bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent            if (!mHasVibrator) {
2612bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent                Log.e(TAG, "checkForRingerModeChange() current ringer mode is vibrate" +
2613bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent                        "but no vibrator is present");
2614bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent                break;
2615bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent            }
2616c696a53d1fe4d61373c5dc64dd057d322da90c8fAmith Yamasani            if ((direction == AudioManager.ADJUST_LOWER)) {
26178600534df66c2ff5846ed230b50c56229322d48aJohn Spurlock                if (VOLUME_SETS_RINGER_MODE_SILENT
26188600534df66c2ff5846ed230b50c56229322d48aJohn Spurlock                        && mPrevVolDirection != AudioManager.ADJUST_LOWER) {
2619bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent                    ringerMode = RINGER_MODE_SILENT;
2620c696a53d1fe4d61373c5dc64dd057d322da90c8fAmith Yamasani                }
2621c696a53d1fe4d61373c5dc64dd057d322da90c8fAmith Yamasani            } else if (direction == AudioManager.ADJUST_RAISE) {
2622bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent                ringerMode = RINGER_MODE_NORMAL;
2623c696a53d1fe4d61373c5dc64dd057d322da90c8fAmith Yamasani            }
2624a11b4affcad3d255aa723a89b768ea222506f2e8John Spurlock            result &= ~FLAG_ADJUST_VOLUME;
2625bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent            break;
2626bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent        case RINGER_MODE_SILENT:
26279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (direction == AudioManager.ADJUST_RAISE) {
2628a11b4affcad3d255aa723a89b768ea222506f2e8John Spurlock                if (PREVENT_VOLUME_ADJUSTMENT_IF_SILENT) {
2629a11b4affcad3d255aa723a89b768ea222506f2e8John Spurlock                    result |= AudioManager.FLAG_SHOW_SILENT_HINT;
2630bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent                } else {
2631a11b4affcad3d255aa723a89b768ea222506f2e8John Spurlock                  if (mHasVibrator) {
2632a11b4affcad3d255aa723a89b768ea222506f2e8John Spurlock                      ringerMode = RINGER_MODE_VIBRATE;
2633a11b4affcad3d255aa723a89b768ea222506f2e8John Spurlock                  } else {
2634a11b4affcad3d255aa723a89b768ea222506f2e8John Spurlock                      ringerMode = RINGER_MODE_NORMAL;
2635a11b4affcad3d255aa723a89b768ea222506f2e8John Spurlock                  }
2636bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent                }
26379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
2638a11b4affcad3d255aa723a89b768ea222506f2e8John Spurlock            result &= ~FLAG_ADJUST_VOLUME;
2639bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent            break;
2640bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent        default:
2641bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent            Log.e(TAG, "checkForRingerModeChange() wrong ringer mode: "+ringerMode);
2642bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent            break;
26439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
26449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2645bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent        setRingerMode(ringerMode);
26469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
264725101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent        mPrevVolDirection = direction;
264825101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent
2649a11b4affcad3d255aa723a89b768ea222506f2e8John Spurlock        return result;
26509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
26519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
26523346a802087f621c6441bc512dfcc17b07143fc6John Spurlock    @Override
26539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public boolean isStreamAffectedByRingerMode(int streamType) {
26549bcf401d13d47416043a704430388abd59aef7cdEric Laurent        return (mRingerModeAffectedStreams & (1 << streamType)) != 0;
26559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
26569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
26575b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent    private boolean isStreamMutedByRingerMode(int streamType) {
26585b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent        return (mRingerModeMutedStreams & (1 << streamType)) != 0;
26595b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent    }
26605b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent
266124e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent    boolean updateRingerModeAffectedStreams() {
266224e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent        int ringerModeAffectedStreams;
266324e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent        // make sure settings for ringer mode are consistent with device type: non voice capable
266424e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent        // devices (tablets) include media stream in silent mode whereas phones don't.
266524e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent        ringerModeAffectedStreams = Settings.System.getIntForUser(mContentResolver,
266624e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent                Settings.System.MODE_RINGER_STREAMS_AFFECTED,
266724e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent                ((1 << AudioSystem.STREAM_RING)|(1 << AudioSystem.STREAM_NOTIFICATION)|
266824e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent                 (1 << AudioSystem.STREAM_SYSTEM)|(1 << AudioSystem.STREAM_SYSTEM_ENFORCED)),
266924e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent                 UserHandle.USER_CURRENT);
267024e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent
267124e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent        // ringtone, notification and system streams are always affected by ringer mode
267224e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent        ringerModeAffectedStreams |= (1 << AudioSystem.STREAM_RING)|
267324e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent                                        (1 << AudioSystem.STREAM_NOTIFICATION)|
267424e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent                                        (1 << AudioSystem.STREAM_SYSTEM);
267524e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent
267624e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent        if (mVoiceCapable) {
267724e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent            ringerModeAffectedStreams &= ~(1 << AudioSystem.STREAM_MUSIC);
267824e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent        } else {
267924e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent            ringerModeAffectedStreams |= (1 << AudioSystem.STREAM_MUSIC);
268024e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent        }
268124e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent        synchronized (mCameraSoundForced) {
268224e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent            if (mCameraSoundForced) {
268324e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent                ringerModeAffectedStreams &= ~(1 << AudioSystem.STREAM_SYSTEM_ENFORCED);
268424e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent            } else {
268524e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent                ringerModeAffectedStreams |= (1 << AudioSystem.STREAM_SYSTEM_ENFORCED);
268624e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent            }
268724e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent        }
268824e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent        if (mStreamVolumeAlias[AudioSystem.STREAM_DTMF] == AudioSystem.STREAM_RING) {
268924e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent            ringerModeAffectedStreams |= (1 << AudioSystem.STREAM_DTMF);
269024e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent        } else {
269124e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent            ringerModeAffectedStreams &= ~(1 << AudioSystem.STREAM_DTMF);
269224e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent        }
269324e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent
269424e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent        if (ringerModeAffectedStreams != mRingerModeAffectedStreams) {
269524e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent            Settings.System.putIntForUser(mContentResolver,
269624e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent                    Settings.System.MODE_RINGER_STREAMS_AFFECTED,
269724e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent                    ringerModeAffectedStreams,
269824e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent                    UserHandle.USER_CURRENT);
269924e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent            mRingerModeAffectedStreams = ringerModeAffectedStreams;
270024e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent            return true;
270124e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent        }
270224e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent        return false;
270324e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent    }
270424e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent
27059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public boolean isStreamAffectedByMute(int streamType) {
27069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return (mMuteAffectedStreams & (1 << streamType)) != 0;
27079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
27089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
27099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private void ensureValidDirection(int direction) {
27109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (direction < AudioManager.ADJUST_LOWER || direction > AudioManager.ADJUST_RAISE) {
27119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            throw new IllegalArgumentException("Bad direction " + direction);
27129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
27139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
27149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
27156c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang    private void ensureValidSteps(int steps) {
27166c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang        if (Math.abs(steps) > MAX_BATCH_VOLUME_ADJUST_STEPS) {
27176c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang            throw new IllegalArgumentException("Bad volume adjust steps " + steps);
27186c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang        }
27196c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang    }
27206c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang
27219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private void ensureValidStreamType(int streamType) {
27229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (streamType < 0 || streamType >= mStreamStates.length) {
27239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            throw new IllegalArgumentException("Bad stream type " + streamType);
27249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
27259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
27269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
27276d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent    private boolean isInCommunication() {
27286d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent        boolean isOffhook = false;
272925101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent
273025101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent        if (mVoiceCapable) {
273125101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent            try {
273225101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent                ITelephony phone = ITelephony.Stub.asInterface(ServiceManager.checkService("phone"));
273325101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent                if (phone != null) isOffhook = phone.isOffhook();
273425101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent            } catch (RemoteException e) {
273525101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent                Log.w(TAG, "Couldn't connect to phone service", e);
273625101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent            }
27376d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent        }
27386d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent        return (isOffhook || getMode() == AudioManager.MODE_IN_COMMUNICATION);
27396d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent    }
274025101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent
2741fca1e603236b8d1681f784e77e3719d1d59c1428Jean-Michel Trivi    /**
2742fca1e603236b8d1681f784e77e3719d1d59c1428Jean-Michel Trivi     * For code clarity for getActiveStreamType(int)
2743fca1e603236b8d1681f784e77e3719d1d59c1428Jean-Michel Trivi     * @param delay_ms max time since last STREAM_MUSIC activity to consider
2744fca1e603236b8d1681f784e77e3719d1d59c1428Jean-Michel Trivi     * @return true if STREAM_MUSIC is active in streams handled by AudioFlinger now or
2745fca1e603236b8d1681f784e77e3719d1d59c1428Jean-Michel Trivi     *     in the last "delay_ms" ms.
2746fca1e603236b8d1681f784e77e3719d1d59c1428Jean-Michel Trivi     */
2747fca1e603236b8d1681f784e77e3719d1d59c1428Jean-Michel Trivi    private boolean isAfMusicActiveRecently(int delay_ms) {
2748fca1e603236b8d1681f784e77e3719d1d59c1428Jean-Michel Trivi        return AudioSystem.isStreamActive(AudioSystem.STREAM_MUSIC, delay_ms)
2749fca1e603236b8d1681f784e77e3719d1d59c1428Jean-Michel Trivi                || AudioSystem.isStreamActiveRemotely(AudioSystem.STREAM_MUSIC, delay_ms);
2750fca1e603236b8d1681f784e77e3719d1d59c1428Jean-Michel Trivi    }
2751fca1e603236b8d1681f784e77e3719d1d59c1428Jean-Michel Trivi
27526d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent    private int getActiveStreamType(int suggestedStreamType) {
27536d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent        if (mVoiceCapable) {
27546d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent            if (isInCommunication()) {
275525101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent                if (AudioSystem.getForceUse(AudioSystem.FOR_COMMUNICATION)
275625101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent                        == AudioSystem.FORCE_BT_SCO) {
275725101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent                    // Log.v(TAG, "getActiveStreamType: Forcing STREAM_BLUETOOTH_SCO...");
275825101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent                    return AudioSystem.STREAM_BLUETOOTH_SCO;
275925101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent                } else {
276025101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent                    // Log.v(TAG, "getActiveStreamType: Forcing STREAM_VOICE_CALL...");
276125101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent                    return AudioSystem.STREAM_VOICE_CALL;
276225101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent                }
27633114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi            } else if (suggestedStreamType == AudioManager.USE_DEFAULT_STREAM_TYPE) {
2764fca1e603236b8d1681f784e77e3719d1d59c1428Jean-Michel Trivi                if (isAfMusicActiveRecently(DEFAULT_STREAM_TYPE_OVERRIDE_DELAY_MS)) {
27653114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                    if (DEBUG_VOL)
27663114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                        Log.v(TAG, "getActiveStreamType: Forcing STREAM_MUSIC stream active");
27673114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                    return AudioSystem.STREAM_MUSIC;
2768fca1e603236b8d1681f784e77e3719d1d59c1428Jean-Michel Trivi                } else
2769fca1e603236b8d1681f784e77e3719d1d59c1428Jean-Michel Trivi                    if (mMediaFocusControl.checkUpdateRemoteStateIfActive(AudioSystem.STREAM_MUSIC))
2770fca1e603236b8d1681f784e77e3719d1d59c1428Jean-Michel Trivi                    {
2771fca1e603236b8d1681f784e77e3719d1d59c1428Jean-Michel Trivi                        if (DEBUG_VOL)
2772fca1e603236b8d1681f784e77e3719d1d59c1428Jean-Michel Trivi                            Log.v(TAG, "getActiveStreamType: Forcing STREAM_REMOTE_MUSIC");
2773fca1e603236b8d1681f784e77e3719d1d59c1428Jean-Michel Trivi                        return STREAM_REMOTE_MUSIC;
2774fca1e603236b8d1681f784e77e3719d1d59c1428Jean-Michel Trivi                    } else {
2775fca1e603236b8d1681f784e77e3719d1d59c1428Jean-Michel Trivi                        if (DEBUG_VOL)
2776fca1e603236b8d1681f784e77e3719d1d59c1428Jean-Michel Trivi                            Log.v(TAG, "getActiveStreamType: Forcing STREAM_RING b/c default");
2777fca1e603236b8d1681f784e77e3719d1d59c1428Jean-Michel Trivi                        return AudioSystem.STREAM_RING;
27783114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                }
2779fca1e603236b8d1681f784e77e3719d1d59c1428Jean-Michel Trivi            } else if (isAfMusicActiveRecently(0)) {
27803114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                if (DEBUG_VOL)
27813114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                    Log.v(TAG, "getActiveStreamType: Forcing STREAM_MUSIC stream active");
278225101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent                return AudioSystem.STREAM_MUSIC;
2783c7fcba4b7bd3d78e7cfe975a3f8e4dde2f6738b7Joe Onorato            } else {
27843114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: Returning suggested type "
27853114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                        + suggestedStreamType);
278625101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent                return suggestedStreamType;
278725101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent            }
278825101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent        } else {
27896d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent            if (isInCommunication()) {
279025101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent                if (AudioSystem.getForceUse(AudioSystem.FOR_COMMUNICATION)
279125101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent                        == AudioSystem.FORCE_BT_SCO) {
27923114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                    if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: Forcing STREAM_BLUETOOTH_SCO");
279325101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent                    return AudioSystem.STREAM_BLUETOOTH_SCO;
279425101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent                } else {
27953114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                    if (DEBUG_VOL)  Log.v(TAG, "getActiveStreamType: Forcing STREAM_VOICE_CALL");
279625101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent                    return AudioSystem.STREAM_VOICE_CALL;
279725101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent                }
279825101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent            } else if (AudioSystem.isStreamActive(AudioSystem.STREAM_NOTIFICATION,
27999903e2638a6c502d96413680d3ebae4fb77fc412Eric Laurent                    DEFAULT_STREAM_TYPE_OVERRIDE_DELAY_MS) ||
28003114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                    AudioSystem.isStreamActive(AudioSystem.STREAM_RING,
28019903e2638a6c502d96413680d3ebae4fb77fc412Eric Laurent                            DEFAULT_STREAM_TYPE_OVERRIDE_DELAY_MS)) {
28023114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: Forcing STREAM_NOTIFICATION");
280325101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent                return AudioSystem.STREAM_NOTIFICATION;
28043114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi            } else if (suggestedStreamType == AudioManager.USE_DEFAULT_STREAM_TYPE) {
2805fca1e603236b8d1681f784e77e3719d1d59c1428Jean-Michel Trivi                if (isAfMusicActiveRecently(DEFAULT_STREAM_TYPE_OVERRIDE_DELAY_MS)) {
2806fca1e603236b8d1681f784e77e3719d1d59c1428Jean-Michel Trivi                    if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: forcing STREAM_MUSIC");
2807fca1e603236b8d1681f784e77e3719d1d59c1428Jean-Michel Trivi                    return AudioSystem.STREAM_MUSIC;
2808fca1e603236b8d1681f784e77e3719d1d59c1428Jean-Michel Trivi                } else
2809fca1e603236b8d1681f784e77e3719d1d59c1428Jean-Michel Trivi                    if (mMediaFocusControl.checkUpdateRemoteStateIfActive(AudioSystem.STREAM_MUSIC))
2810fca1e603236b8d1681f784e77e3719d1d59c1428Jean-Michel Trivi                    {
2811fca1e603236b8d1681f784e77e3719d1d59c1428Jean-Michel Trivi                        if (DEBUG_VOL)
2812fca1e603236b8d1681f784e77e3719d1d59c1428Jean-Michel Trivi                            Log.v(TAG, "getActiveStreamType: Forcing STREAM_REMOTE_MUSIC");
2813fca1e603236b8d1681f784e77e3719d1d59c1428Jean-Michel Trivi                        return STREAM_REMOTE_MUSIC;
28143114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                } else {
2815fca1e603236b8d1681f784e77e3719d1d59c1428Jean-Michel Trivi                    if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: using STREAM_MUSIC as default");
28163114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                    return AudioSystem.STREAM_MUSIC;
28173114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                }
281825101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent            } else {
28193114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: Returning suggested type "
28203114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                        + suggestedStreamType);
282125101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent                return suggestedStreamType;
2822c7fcba4b7bd3d78e7cfe975a3f8e4dde2f6738b7Joe Onorato            }
28239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
28249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
28259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2826ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten    private void broadcastRingerMode(int ringerMode) {
28279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // Send sticky broadcast
28281c633fc89bae9bf0af6fe643ac7ad2e744f27bedDianne Hackborn        Intent broadcast = new Intent(AudioManager.RINGER_MODE_CHANGED_ACTION);
2829ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten        broadcast.putExtra(AudioManager.EXTRA_RINGER_MODE, ringerMode);
28301c633fc89bae9bf0af6fe643ac7ad2e744f27bedDianne Hackborn        broadcast.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT
28311c633fc89bae9bf0af6fe643ac7ad2e744f27bedDianne Hackborn                | Intent.FLAG_RECEIVER_REPLACE_PENDING);
28325ac72a29593ab9a20337a2225df52bdf4754be02Dianne Hackborn        sendStickyBroadcastToAll(broadcast);
28339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
28349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
28359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private void broadcastVibrateSetting(int vibrateType) {
28369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // Send broadcast
28379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (ActivityManagerNative.isSystemReady()) {
28389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            Intent broadcast = new Intent(AudioManager.VIBRATE_SETTING_CHANGED_ACTION);
28399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            broadcast.putExtra(AudioManager.EXTRA_VIBRATE_TYPE, vibrateType);
28409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            broadcast.putExtra(AudioManager.EXTRA_VIBRATE_SETTING, getVibrateSetting(vibrateType));
28415ac72a29593ab9a20337a2225df52bdf4754be02Dianne Hackborn            sendBroadcastToAll(broadcast);
28429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
28439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
28449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
28459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // Message helper methods
28462d8dab5a549b25b6f36df4614d7c0166d4d099e2Jean-Michel Trivi    /**
28472d8dab5a549b25b6f36df4614d7c0166d4d099e2Jean-Michel Trivi     * Queue a message on the given handler's message queue, after acquiring the service wake lock.
28482d8dab5a549b25b6f36df4614d7c0166d4d099e2Jean-Michel Trivi     * Note that the wake lock needs to be released after the message has been handled.
28492d8dab5a549b25b6f36df4614d7c0166d4d099e2Jean-Michel Trivi     */
28502d8dab5a549b25b6f36df4614d7c0166d4d099e2Jean-Michel Trivi    private void queueMsgUnderWakeLock(Handler handler, int msg,
28512d8dab5a549b25b6f36df4614d7c0166d4d099e2Jean-Michel Trivi            int arg1, int arg2, Object obj, int delay) {
2852a4dfbdc54d8898491d3a7d1d9d818c7db3fd773dEric Laurent        final long ident = Binder.clearCallingIdentity();
2853a4dfbdc54d8898491d3a7d1d9d818c7db3fd773dEric Laurent        // Always acquire the wake lock as AudioService because it is released by the
2854a4dfbdc54d8898491d3a7d1d9d818c7db3fd773dEric Laurent        // message handler.
2855fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        mAudioEventWakeLock.acquire();
2856a4dfbdc54d8898491d3a7d1d9d818c7db3fd773dEric Laurent        Binder.restoreCallingIdentity(ident);
28572d8dab5a549b25b6f36df4614d7c0166d4d099e2Jean-Michel Trivi        sendMsg(handler, msg, SENDMSG_QUEUE, arg1, arg2, obj, delay);
28582d8dab5a549b25b6f36df4614d7c0166d4d099e2Jean-Michel Trivi    }
28599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2860afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent    private static void sendMsg(Handler handler, int msg,
28619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int existingMsgPolicy, int arg1, int arg2, Object obj, int delay) {
28629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
28639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (existingMsgPolicy == SENDMSG_REPLACE) {
28649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            handler.removeMessages(msg);
28659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else if (existingMsgPolicy == SENDMSG_NOOP && handler.hasMessages(msg)) {
28669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return;
28679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
28689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2869afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent        handler.sendMessageDelayed(handler.obtainMessage(msg, arg1, arg2, obj), delay);
28709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
28719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
28729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    boolean checkAudioSettingsPermission(String method) {
28739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mContext.checkCallingOrSelfPermission("android.permission.MODIFY_AUDIO_SETTINGS")
28749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                == PackageManager.PERMISSION_GRANTED) {
28759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return true;
28769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
28779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        String msg = "Audio Settings Permission Denial: " + method + " from pid="
28789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                + Binder.getCallingPid()
28799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                + ", uid=" + Binder.getCallingUid();
28809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        Log.w(TAG, msg);
28819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return false;
28829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
28839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
28849bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent    private int getDeviceForStream(int stream) {
28859bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent        int device = AudioSystem.getDevicesForStream(stream);
28869bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent        if ((device & (device - 1)) != 0) {
28879bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent            // Multiple device selection is either:
28889bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent            //  - speaker + one other device: give priority to speaker in this case.
28899bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent            //  - one A2DP device + another device: happens with duplicated output. In this case
28909bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent            // retain the device on the A2DP output as the other must not correspond to an active
28919bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent            // selection if not the speaker.
28929bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent            if ((device & AudioSystem.DEVICE_OUT_SPEAKER) != 0) {
28939bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                device = AudioSystem.DEVICE_OUT_SPEAKER;
28949bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent            } else {
28959bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                device &= AudioSystem.DEVICE_OUT_ALL_A2DP;
28969bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent            }
28979bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent        }
28989bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent        return device;
28999bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent    }
29009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2901b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent    public void setWiredDeviceConnectionState(int device, int state, String name) {
2902b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent        synchronized (mConnectedDevices) {
2903b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent            int delay = checkSendBecomingNoisyIntent(device, state);
29042d8dab5a549b25b6f36df4614d7c0166d4d099e2Jean-Michel Trivi            queueMsgUnderWakeLock(mAudioHandler,
2905b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent                    MSG_SET_WIRED_DEVICE_CONNECTION_STATE,
2906b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent                    device,
2907b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent                    state,
2908b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent                    name,
2909b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent                    delay);
2910b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent        }
2911b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent    }
2912b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent
29130a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood    public int setBluetoothA2dpDeviceConnectionState(BluetoothDevice device, int state, int profile)
2914b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent    {
2915b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent        int delay;
29160a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood        if (profile != BluetoothProfile.A2DP && profile != BluetoothProfile.A2DP_SINK) {
29170a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood            throw new IllegalArgumentException("invalid profile " + profile);
29180a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood        }
2919b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent        synchronized (mConnectedDevices) {
29200a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood            if (profile == BluetoothProfile.A2DP) {
29210a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood                delay = checkSendBecomingNoisyIntent(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
29220a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood                                                (state == BluetoothA2dp.STATE_CONNECTED) ? 1 : 0);
29230a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood            } else {
29240a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood                delay = 0;
29250a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood            }
29262d8dab5a549b25b6f36df4614d7c0166d4d099e2Jean-Michel Trivi            queueMsgUnderWakeLock(mAudioHandler,
29270a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood                    (profile == BluetoothProfile.A2DP ?
29280a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood                        MSG_SET_A2DP_SINK_CONNECTION_STATE : MSG_SET_A2DP_SRC_CONNECTION_STATE),
2929b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent                    state,
2930b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent                    0,
2931b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent                    device,
2932b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent                    delay);
2933b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent        }
2934b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent        return delay;
2935b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent    }
2936b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent
29379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    ///////////////////////////////////////////////////////////////////////////
29389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // Inner classes
29399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    ///////////////////////////////////////////////////////////////////////////
29409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
29419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public class VolumeStreamState {
29429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        private final int mStreamType;
29439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
294411a74a75653197a3d31fe91590cd8312f5270c44Jean-Michel Trivi        private String mVolumeIndexSettingName;
2945a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent        private int mIndexMax;
29463172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent        private final ConcurrentHashMap<Integer, Integer> mIndex =
29473172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                                            new ConcurrentHashMap<Integer, Integer>(8, 0.75f, 4);
29489bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent        private ArrayList<VolumeDeathHandler> mDeathHandlers; //handles mute/solo clients death
29499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2950a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent        private VolumeStreamState(String settingName, int streamType) {
29519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
29529bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent            mVolumeIndexSettingName = settingName;
29539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
29549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mStreamType = streamType;
29555982013cfc8274ff0bafaba83c676b3a8890cba9Jared Suttles            mIndexMax = MAX_STREAM_VOLUME[streamType];
2956a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent            AudioSystem.initStreamVolume(streamType, 0, mIndexMax);
2957a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent            mIndexMax *= 10;
29589bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent
295933902db75011d863009585682bd08560c5b89a75Eric Laurent            // mDeathHandlers must be created before calling readSettings()
29609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mDeathHandlers = new ArrayList<VolumeDeathHandler>();
296133902db75011d863009585682bd08560c5b89a75Eric Laurent
296233902db75011d863009585682bd08560c5b89a75Eric Laurent            readSettings();
29639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
29649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
296542b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent        public String getSettingNameForDevice(int device) {
296642b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent            String name = mVolumeIndexSettingName;
2967948d32748caaac5be06c991ebf00f74265a7849fEric Laurent            String suffix = AudioSystem.getOutputDeviceName(device);
29689bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent            if (suffix.isEmpty()) {
29699bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                return name;
29709bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent            }
29719bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent            return name + "_" + suffix;
29729bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent        }
29739bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent
2974fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent        public void readSettings() {
2975fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent            synchronized (VolumeStreamState.class) {
2976fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                // force maximum volume on all streams if fixed volume property is set
2977fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                if (mUseFixedVolume) {
2978fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                    mIndex.put(AudioSystem.DEVICE_OUT_DEFAULT, mIndexMax);
2979fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                    return;
2980fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                }
2981fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                // do not read system stream volume from settings: this stream is always aliased
2982fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                // to another stream type and its volume is never persisted. Values in settings can
2983fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                // only be stale values
2984fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                if ((mStreamType == AudioSystem.STREAM_SYSTEM) ||
2985fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                        (mStreamType == AudioSystem.STREAM_SYSTEM_ENFORCED)) {
2986fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                    int index = 10 * AudioManager.DEFAULT_STREAM_VOLUME[mStreamType];
2987fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                    synchronized (mCameraSoundForced) {
2988fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                        if (mCameraSoundForced) {
2989fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                            index = mIndexMax;
2990fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                        }
2991dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent                    }
2992fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                    mIndex.put(AudioSystem.DEVICE_OUT_DEFAULT, index);
2993fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                    return;
2994dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent                }
2995002e9d382d2daa7ed41636463ecdbddbd4897abaEric Laurent
2996fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                int remainingDevices = AudioSystem.DEVICE_OUT_ALL;
299783a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent
2998fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                for (int i = 0; remainingDevices != 0; i++) {
2999fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                    int device = (1 << i);
3000fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                    if ((device & remainingDevices) == 0) {
3001fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                        continue;
3002fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                    }
3003fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                    remainingDevices &= ~device;
3004fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent
3005fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                    // retrieve current volume for device
3006fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                    String name = getSettingNameForDevice(device);
3007fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                    // if no volume stored for current stream and device, use default volume if default
3008fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                    // device, continue otherwise
3009fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                    int defaultIndex = (device == AudioSystem.DEVICE_OUT_DEFAULT) ?
3010fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                                            AudioManager.DEFAULT_STREAM_VOLUME[mStreamType] : -1;
3011fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                    int index = Settings.System.getIntForUser(
3012fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                            mContentResolver, name, defaultIndex, UserHandle.USER_CURRENT);
3013fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                    if (index == -1) {
3014fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                        continue;
3015fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                    }
30169bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent
3017fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                    // ignore settings for fixed volume devices: volume should always be at max or 0
3018fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                    if ((mStreamVolumeAlias[mStreamType] == AudioSystem.STREAM_MUSIC) &&
3019fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                            ((device & mFixedVolumeDevices) != 0)) {
3020fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                        mIndex.put(device, (index != 0) ? mIndexMax : 0);
3021fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                    } else {
3022fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                        mIndex.put(device, getValidIndex(10 * index));
3023fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                    }
3024dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent                }
30259bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent            }
30269bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent        }
30279bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent
30289bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent        public void applyDeviceVolume(int device) {
302942b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent            int index;
303042b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent            if (isMuted()) {
303142b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                index = 0;
3032cd772d04345850e160a45613fcf6b86da0dce4cfEric Laurent            } else if ((device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0 &&
3033c9d1d5f35091226e96fcfa91817480f589eb36e2Matthew Xie                       mAvrcpAbsVolSupported) {
3034c9d1d5f35091226e96fcfa91817480f589eb36e2Matthew Xie                index = (mIndexMax + 5)/10;
3035cd772d04345850e160a45613fcf6b86da0dce4cfEric Laurent            } else {
303642b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                index = (getIndex(device) + 5)/10;
303742b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent            }
303842b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent            AudioSystem.setStreamVolumeIndex(mStreamType, index, device);
30399bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent        }
30409bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent
3041fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent        public void applyAllVolumes() {
3042fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent            synchronized (VolumeStreamState.class) {
3043fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                // apply default volume first: by convention this will reset all
3044fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                // devices volumes in audio policy manager to the supplied value
3045fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                int index;
3046fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                if (isMuted()) {
3047fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                    index = 0;
3048fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                } else {
3049fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                    index = (getIndex(AudioSystem.DEVICE_OUT_DEFAULT) + 5)/10;
3050fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                }
3051fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                AudioSystem.setStreamVolumeIndex(mStreamType, index, AudioSystem.DEVICE_OUT_DEFAULT);
3052fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                // then apply device specific volumes
3053fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                Set set = mIndex.entrySet();
3054fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                Iterator i = set.iterator();
3055fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                while (i.hasNext()) {
3056fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                    Map.Entry entry = (Map.Entry)i.next();
3057fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                    int device = ((Integer)entry.getKey()).intValue();
3058fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                    if (device != AudioSystem.DEVICE_OUT_DEFAULT) {
3059fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                        if (isMuted()) {
3060fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                            index = 0;
3061fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                        } else if ((device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0 &&
3062fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                                mAvrcpAbsVolSupported) {
3063fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                            index = (mIndexMax + 5)/10;
3064fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                        } else {
3065fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                            index = ((Integer)entry.getValue() + 5)/10;
3066fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                        }
3067fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                        AudioSystem.setStreamVolumeIndex(mStreamType, index, device);
306842b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                    }
30699bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                }
30709bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent            }
307111a74a75653197a3d31fe91590cd8312f5270c44Jean-Michel Trivi        }
307211a74a75653197a3d31fe91590cd8312f5270c44Jean-Michel Trivi
30739bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent        public boolean adjustIndex(int deltaIndex, int device) {
307442b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent            return setIndex(getIndex(device) + deltaIndex,
307542b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                            device);
30769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
30779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3078fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent        public boolean setIndex(int index, int device) {
3079fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent            synchronized (VolumeStreamState.class) {
3080fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                int oldIndex = getIndex(device);
3081fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                index = getValidIndex(index);
3082fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                synchronized (mCameraSoundForced) {
3083fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                    if ((mStreamType == AudioSystem.STREAM_SYSTEM_ENFORCED) && mCameraSoundForced) {
3084fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                        index = mIndexMax;
3085fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                    }
3086dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent                }
3087fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                mIndex.put(device, index);
3088fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent
3089fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                if (oldIndex != index) {
3090fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                    // Apply change to all streams using this one as alias
3091fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                    // if changing volume of current device, also change volume of current
3092fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                    // device on aliased stream
3093fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                    boolean currentDevice = (device == getDeviceForStream(mStreamType));
3094fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                    int numStreamTypes = AudioSystem.getNumStreamTypes();
3095fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                    for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
3096fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                        if (streamType != mStreamType &&
3097fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                                mStreamVolumeAlias[streamType] == mStreamType) {
3098fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                            int scaledIndex = rescaleIndex(index, mStreamType, streamType);
3099bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent                            mStreamStates[streamType].setIndex(scaledIndex,
3100fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                                                               device);
3101fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                            if (currentDevice) {
3102fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                                mStreamStates[streamType].setIndex(scaledIndex,
3103fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                                                                   getDeviceForStream(streamType));
3104fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                            }
3105bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent                        }
3106a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent                    }
3107fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                    return true;
3108fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                } else {
3109fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                    return false;
3110a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent                }
31119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
31129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
31139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3114fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent        public int getIndex(int device) {
3115fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent            synchronized (VolumeStreamState.class) {
3116fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                Integer index = mIndex.get(device);
3117fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                if (index == null) {
3118fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                    // there is always an entry for AudioSystem.DEVICE_OUT_DEFAULT
3119fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                    index = mIndex.get(AudioSystem.DEVICE_OUT_DEFAULT);
3120fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                }
3121fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                return index.intValue();
31229bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent            }
31239bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent        }
31249bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent
31259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public int getMaxIndex() {
3126a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent            return mIndexMax;
31279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
31289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3129fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent        public void setAllIndexes(VolumeStreamState srcStream) {
3130fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent            synchronized (VolumeStreamState.class) {
3131fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                int srcStreamType = srcStream.getStreamType();
3132fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                // apply default device volume from source stream to all devices first in case
3133fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                // some devices are present in this stream state but not in source stream state
3134fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                int index = srcStream.getIndex(AudioSystem.DEVICE_OUT_DEFAULT);
313524e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent                index = rescaleIndex(index, srcStreamType, mStreamType);
3136fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                Set set = mIndex.entrySet();
3137fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                Iterator i = set.iterator();
3138fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                while (i.hasNext()) {
3139fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                    Map.Entry entry = (Map.Entry)i.next();
3140fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                    entry.setValue(index);
3141fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                }
3142fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                // Now apply actual volume for devices in source stream state
3143fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                set = srcStream.mIndex.entrySet();
3144fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                i = set.iterator();
3145fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                while (i.hasNext()) {
3146fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                    Map.Entry entry = (Map.Entry)i.next();
3147fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                    int device = ((Integer)entry.getKey()).intValue();
3148fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                    index = ((Integer)entry.getValue()).intValue();
3149fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                    index = rescaleIndex(index, srcStreamType, mStreamType);
3150fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent
3151fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                    setIndex(index, device);
3152fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                }
31536d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent            }
31546d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent        }
31556d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent
3156fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent        public void setAllIndexesToMax() {
3157fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent            synchronized (VolumeStreamState.class) {
3158fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                Set set = mIndex.entrySet();
3159fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                Iterator i = set.iterator();
3160fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                while (i.hasNext()) {
3161fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                    Map.Entry entry = (Map.Entry)i.next();
3162fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                    entry.setValue(mIndexMax);
3163fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                }
3164dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent            }
3165dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent        }
3166dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent
3167fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent        public void mute(IBinder cb, boolean state) {
3168fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent            synchronized (VolumeStreamState.class) {
3169fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                VolumeDeathHandler handler = getDeathHandler(cb, state);
3170fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                if (handler == null) {
3171fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                    Log.e(TAG, "Could not get client death handler for stream: "+mStreamType);
3172fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                    return;
3173fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                }
3174fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                handler.mute(state);
31759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
31769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
31779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
31786d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent        public int getStreamType() {
31796d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent            return mStreamType;
31806d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent        }
31816d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent
31829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        private int getValidIndex(int index) {
31839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (index < 0) {
31849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return 0;
318583a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent            } else if (mUseFixedVolume || index > mIndexMax) {
3186a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent                return mIndexMax;
31879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
31889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
31899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return index;
31909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
31919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
31929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        private class VolumeDeathHandler implements IBinder.DeathRecipient {
31939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            private IBinder mICallback; // To be notified of client's death
31949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            private int mMuteCount; // Number of active mutes for this client
31959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
31969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            VolumeDeathHandler(IBinder cb) {
31979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mICallback = cb;
31989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
31999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
32003172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent            // must be called while synchronized on parent VolumeStreamState
32019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            public void mute(boolean state) {
320242b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                boolean updateVolume = false;
32033172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                if (state) {
32043172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                    if (mMuteCount == 0) {
32053172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                        // Register for client death notification
32063172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                        try {
32073172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                            // mICallback can be 0 if muted by AudioService
32083172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                            if (mICallback != null) {
32093172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                                mICallback.linkToDeath(this, 0);
32103172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                            }
321142b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                            VolumeStreamState.this.mDeathHandlers.add(this);
32123172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                            // If the stream is not yet muted by any client, set level to 0
321342b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                            if (!VolumeStreamState.this.isMuted()) {
321442b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                                updateVolume = true;
32153172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                            }
32163172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                        } catch (RemoteException e) {
32173172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                            // Client has died!
32183172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                            binderDied();
32193172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                            return;
32203172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                        }
32213172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                    } else {
32223172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                        Log.w(TAG, "stream: "+mStreamType+" was already muted by this client");
32233172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                    }
32243172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                    mMuteCount++;
32253172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                } else {
32263172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                    if (mMuteCount == 0) {
32273172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                        Log.e(TAG, "unexpected unmute for stream: "+mStreamType);
32283172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                    } else {
32293172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                        mMuteCount--;
32303172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                        if (mMuteCount == 0) {
32313172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                            // Unregister from client death notification
323242b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                            VolumeStreamState.this.mDeathHandlers.remove(this);
32333172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                            // mICallback can be 0 if muted by AudioService
32343172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                            if (mICallback != null) {
32353172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                                mICallback.unlinkToDeath(this, 0);
32363172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                            }
323742b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                            if (!VolumeStreamState.this.isMuted()) {
323842b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                                updateVolume = true;
32399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            }
32409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        }
32419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    }
32429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
324342b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                if (updateVolume) {
324442b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                    sendMsg(mAudioHandler,
324542b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                            MSG_SET_ALL_VOLUMES,
324642b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                            SENDMSG_QUEUE,
324742b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                            0,
324842b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                            0,
324942b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                            VolumeStreamState.this, 0);
325042b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                }
32519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
32529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
32539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            public void binderDied() {
32549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                Log.w(TAG, "Volume service client died for stream: "+mStreamType);
32559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (mMuteCount != 0) {
32569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    // Reset all active mute requests from this client.
32579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    mMuteCount = 1;
32589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    mute(false);
32599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
32609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
32619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
32629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
32633172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent        private synchronized int muteCount() {
32649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int count = 0;
32659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int size = mDeathHandlers.size();
32669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            for (int i = 0; i < size; i++) {
32679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                count += mDeathHandlers.get(i).mMuteCount;
32689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
32699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return count;
32709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
32719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
327242b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent        private synchronized boolean isMuted() {
327342b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent            return muteCount() != 0;
327442b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent        }
327542b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent
32763172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent        // only called by mute() which is already synchronized
32779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        private VolumeDeathHandler getDeathHandler(IBinder cb, boolean state) {
32783172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent            VolumeDeathHandler handler;
32793172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent            int size = mDeathHandlers.size();
32803172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent            for (int i = 0; i < size; i++) {
32813172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                handler = mDeathHandlers.get(i);
32823172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                if (cb == handler.mICallback) {
32833172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                    return handler;
3284ce952c8e13c535bedde77bcdb94dfcc7508475aaMike Lockwood                }
3285ce952c8e13c535bedde77bcdb94dfcc7508475aaMike Lockwood            }
32863172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent            // If this is the first mute request for this client, create a new
32873172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent            // client death handler. Otherwise, it is an out of sequence unmute request.
32883172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent            if (state) {
32893172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                handler = new VolumeDeathHandler(cb);
32903172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent            } else {
32913172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                Log.w(TAG, "stream was not muted by this client");
32923172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                handler = null;
32933172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent            }
32943172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent            return handler;
3295ce952c8e13c535bedde77bcdb94dfcc7508475aaMike Lockwood        }
3296bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent
3297bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent        private void dump(PrintWriter pw) {
3298dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent            pw.print("   Mute count: ");
3299dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent            pw.println(muteCount());
3300bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent            pw.print("   Current: ");
3301bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent            Set set = mIndex.entrySet();
3302bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent            Iterator i = set.iterator();
3303bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent            while (i.hasNext()) {
3304bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent                Map.Entry entry = (Map.Entry)i.next();
3305bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent                pw.print(Integer.toHexString(((Integer)entry.getKey()).intValue())
3306bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent                             + ": " + ((((Integer)entry.getValue()).intValue() + 5) / 10)+", ");
3307bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent            }
3308bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent        }
3309ce952c8e13c535bedde77bcdb94dfcc7508475aaMike Lockwood    }
3310ce952c8e13c535bedde77bcdb94dfcc7508475aaMike Lockwood
33119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** Thread that handles native AudioSystem control. */
33129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private class AudioSystemThread extends Thread {
33139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        AudioSystemThread() {
33149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            super("AudioService");
33159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
33169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
33179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        @Override
33189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public void run() {
33199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // Set this thread up so the handler will work on it
33209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            Looper.prepare();
33219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
33229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            synchronized(AudioService.this) {
33239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mAudioHandler = new AudioHandler();
33249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
33259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // Notify that the handler has been created
33269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                AudioService.this.notify();
33279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
33289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
33299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // Listen for volume change requests that are set by VolumePanel
33309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            Looper.loop();
33319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
33329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
33339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
33349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** Handles internal volume messages in separate volume thread. */
33359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private class AudioHandler extends Handler {
33369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
33379bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent        private void setDeviceVolume(VolumeStreamState streamState, int device) {
33389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
33399bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent            // Apply volume
33409bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent            streamState.applyDeviceVolume(device);
3341a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent
3342a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent            // Apply change to all streams using this one as alias
3343a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent            int numStreamTypes = AudioSystem.getNumStreamTypes();
3344a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent            for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
3345a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent                if (streamType != streamState.mStreamType &&
33466d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent                        mStreamVolumeAlias[streamType] == streamState.mStreamType) {
3347cd772d04345850e160a45613fcf6b86da0dce4cfEric Laurent                    // Make sure volume is also maxed out on A2DP device for aliased stream
3348cd772d04345850e160a45613fcf6b86da0dce4cfEric Laurent                    // that may have a different device selected
3349cd772d04345850e160a45613fcf6b86da0dce4cfEric Laurent                    int streamDevice = getDeviceForStream(streamType);
3350cd772d04345850e160a45613fcf6b86da0dce4cfEric Laurent                    if ((device != streamDevice) && mAvrcpAbsVolSupported &&
3351cd772d04345850e160a45613fcf6b86da0dce4cfEric Laurent                            ((device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0)) {
3352cd772d04345850e160a45613fcf6b86da0dce4cfEric Laurent                        mStreamStates[streamType].applyDeviceVolume(device);
3353cd772d04345850e160a45613fcf6b86da0dce4cfEric Laurent                    }
3354cd772d04345850e160a45613fcf6b86da0dce4cfEric Laurent                    mStreamStates[streamType].applyDeviceVolume(streamDevice);
3355a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent                }
3356a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent            }
33579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
33589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // Post a persist volume msg
3359afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent            sendMsg(mAudioHandler,
3360afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent                    MSG_PERSIST_VOLUME,
336198ad9b9d6fd34aad487933170f50b5519313df61Eric Laurent                    SENDMSG_QUEUE,
33629bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                    device,
336342b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                    0,
3364afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent                    streamState,
3365afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent                    PERSIST_DELAY);
3366afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent
33679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
33689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
33699bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent        private void setAllVolumes(VolumeStreamState streamState) {
33709bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent
33719bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent            // Apply volume
33729bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent            streamState.applyAllVolumes();
33739bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent
33749bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent            // Apply change to all streams using this one as alias
33759bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent            int numStreamTypes = AudioSystem.getNumStreamTypes();
33769bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent            for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
33779bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                if (streamType != streamState.mStreamType &&
33786d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent                        mStreamVolumeAlias[streamType] == streamState.mStreamType) {
33799bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                    mStreamStates[streamType].applyAllVolumes();
33809bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                }
33819bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent            }
33829bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent        }
33839bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent
338442b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent        private void persistVolume(VolumeStreamState streamState, int device) {
338583a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent            if (mUseFixedVolume) {
338683a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent                return;
338783a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent            }
338842b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent            System.putIntForUser(mContentResolver,
338942b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                      streamState.getSettingNameForDevice(device),
339042b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                      (streamState.getIndex(device) + 5)/ 10,
339142b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                      UserHandle.USER_CURRENT);
33929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
33939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3394ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten        private void persistRingerMode(int ringerMode) {
339583a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent            if (mUseFixedVolume) {
339683a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent                return;
339783a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent            }
33988d9a1f66d9d3dbbd45a56d441a746ec11dba7645Jeff Sharkey            Settings.Global.putInt(mContentResolver, Settings.Global.MODE_RINGER, ringerMode);
33999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
34009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
34015d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent        private boolean onLoadSoundEffects() {
34025d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent            int status;
34035d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent
34045d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent            synchronized (mSoundEffectsLock) {
34054a5eeb9c727d77bb57fef87a70c8c9cc23dbfee3Eric Laurent                if (!mSystemReady) {
34065d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    Log.w(TAG, "onLoadSoundEffects() called before boot complete");
34075d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    return false;
34085d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                }
34095d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent
34105d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                if (mSoundPool != null) {
34115d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    return true;
34125d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                }
34135d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent
34145d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                loadTouchSoundAssets();
34155d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent
34165d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                mSoundPool = new SoundPool(NUM_SOUNDPOOL_CHANNELS, AudioSystem.STREAM_SYSTEM, 0);
34175d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                mSoundPoolCallBack = null;
34185d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                mSoundPoolListenerThread = new SoundPoolListenerThread();
34195d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                mSoundPoolListenerThread.start();
34205d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                int attempts = 3;
34215d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                while ((mSoundPoolCallBack == null) && (attempts-- > 0)) {
34225d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    try {
34235d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                        // Wait for mSoundPoolCallBack to be set by the other thread
3424167d1a27713ab64cd3c0aa70de96434083ef0400Glenn Kasten                        mSoundEffectsLock.wait(SOUND_EFFECTS_LOAD_TIMEOUT_MS);
34255d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    } catch (InterruptedException e) {
34265d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                        Log.w(TAG, "Interrupted while waiting sound pool listener thread.");
34275d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    }
34285d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                }
34295d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent
34305d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                if (mSoundPoolCallBack == null) {
34315d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    Log.w(TAG, "onLoadSoundEffects() SoundPool listener or thread creation error");
34325d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    if (mSoundPoolLooper != null) {
34335d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                        mSoundPoolLooper.quit();
34345d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                        mSoundPoolLooper = null;
34355d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    }
34365d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    mSoundPoolListenerThread = null;
34375d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    mSoundPool.release();
34385d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    mSoundPool = null;
34395d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    return false;
34405d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                }
34415d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                /*
34425d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                 * poolId table: The value -1 in this table indicates that corresponding
34435d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                 * file (same index in SOUND_EFFECT_FILES[] has not been loaded.
34445d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                 * Once loaded, the value in poolId is the sample ID and the same
34455d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                 * sample can be reused for another effect using the same file.
34465d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                 */
34475d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                int[] poolId = new int[SOUND_EFFECT_FILES.size()];
34485d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                for (int fileIdx = 0; fileIdx < SOUND_EFFECT_FILES.size(); fileIdx++) {
34495d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    poolId[fileIdx] = -1;
34505d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                }
34515d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                /*
34525d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                 * Effects whose value in SOUND_EFFECT_FILES_MAP[effect][1] is -1 must be loaded.
34535d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                 * If load succeeds, value in SOUND_EFFECT_FILES_MAP[effect][1] is > 0:
34545d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                 * this indicates we have a valid sample loaded for this effect.
34555d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                 */
34565d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent
34575d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                int numSamples = 0;
34585d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                for (int effect = 0; effect < AudioManager.NUM_SOUND_EFFECTS; effect++) {
34595d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    // Do not load sample if this effect uses the MediaPlayer
34605d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    if (SOUND_EFFECT_FILES_MAP[effect][1] == 0) {
34615d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                        continue;
34625d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    }
34635d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    if (poolId[SOUND_EFFECT_FILES_MAP[effect][0]] == -1) {
34645d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                        String filePath = Environment.getRootDirectory()
34655d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                                + SOUND_EFFECTS_PATH
34665d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                                + SOUND_EFFECT_FILES.get(SOUND_EFFECT_FILES_MAP[effect][0]);
34675d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                        int sampleId = mSoundPool.load(filePath, 0);
34685d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                        if (sampleId <= 0) {
34695d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                            Log.w(TAG, "Soundpool could not load file: "+filePath);
34705d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                        } else {
34715d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                            SOUND_EFFECT_FILES_MAP[effect][1] = sampleId;
34725d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                            poolId[SOUND_EFFECT_FILES_MAP[effect][0]] = sampleId;
34735d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                            numSamples++;
34745d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                        }
34755d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    } else {
34765d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                        SOUND_EFFECT_FILES_MAP[effect][1] =
34775d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                                poolId[SOUND_EFFECT_FILES_MAP[effect][0]];
34785d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    }
34795d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                }
34805d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                // wait for all samples to be loaded
34815d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                if (numSamples > 0) {
34825d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    mSoundPoolCallBack.setSamples(poolId);
34835d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent
34845d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    attempts = 3;
34855d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    status = 1;
34865d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    while ((status == 1) && (attempts-- > 0)) {
34875d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                        try {
3488167d1a27713ab64cd3c0aa70de96434083ef0400Glenn Kasten                            mSoundEffectsLock.wait(SOUND_EFFECTS_LOAD_TIMEOUT_MS);
34895d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                            status = mSoundPoolCallBack.status();
34905d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                        } catch (InterruptedException e) {
34915d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                            Log.w(TAG, "Interrupted while waiting sound pool callback.");
34925d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                        }
34935d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    }
34945d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                } else {
34955d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    status = -1;
34965d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                }
34975d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent
34985d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                if (mSoundPoolLooper != null) {
34995d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    mSoundPoolLooper.quit();
35005d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    mSoundPoolLooper = null;
35015d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                }
35025d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                mSoundPoolListenerThread = null;
35035d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                if (status != 0) {
35045d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    Log.w(TAG,
35055d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                            "onLoadSoundEffects(), Error "+status+ " while loading samples");
35065d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    for (int effect = 0; effect < AudioManager.NUM_SOUND_EFFECTS; effect++) {
35075d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                        if (SOUND_EFFECT_FILES_MAP[effect][1] > 0) {
35085d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                            SOUND_EFFECT_FILES_MAP[effect][1] = -1;
35095d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                        }
35105d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    }
35115d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent
35125d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    mSoundPool.release();
35135d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    mSoundPool = null;
35145d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                }
35155d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent            }
35165d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent            return (status == 0);
35175d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent        }
35185d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent
35195d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent        /**
35205d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent         *  Unloads samples from the sound pool.
35215d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent         *  This method can be called to free some memory when
35225d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent         *  sound effects are disabled.
35235d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent         */
35245d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent        private void onUnloadSoundEffects() {
35255d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent            synchronized (mSoundEffectsLock) {
35265d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                if (mSoundPool == null) {
35275d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    return;
35285d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                }
35295d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent
35305d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                int[] poolId = new int[SOUND_EFFECT_FILES.size()];
35315d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                for (int fileIdx = 0; fileIdx < SOUND_EFFECT_FILES.size(); fileIdx++) {
35325d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    poolId[fileIdx] = 0;
35335d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                }
35345d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent
35355d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                for (int effect = 0; effect < AudioManager.NUM_SOUND_EFFECTS; effect++) {
35365d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    if (SOUND_EFFECT_FILES_MAP[effect][1] <= 0) {
35375d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                        continue;
35385d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    }
35395d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    if (poolId[SOUND_EFFECT_FILES_MAP[effect][0]] == 0) {
35405d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                        mSoundPool.unload(SOUND_EFFECT_FILES_MAP[effect][1]);
35415d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                        SOUND_EFFECT_FILES_MAP[effect][1] = -1;
35425d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                        poolId[SOUND_EFFECT_FILES_MAP[effect][0]] = -1;
35435d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    }
35445d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                }
35455d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                mSoundPool.release();
35465d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                mSoundPool = null;
35475d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent            }
35485d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent        }
35495d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent
35505d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent        private void onPlaySoundEffect(int effectType, int volume) {
35519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            synchronized (mSoundEffectsLock) {
35525d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent
35535d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                onLoadSoundEffects();
35545d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent
35559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (mSoundPool == null) {
35569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    return;
35579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
3558a2ef57dba9ac77d8eccacd646b2b8a8d99fe9d8bEric Laurent                float volFloat;
355925101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent                // use default if volume is not specified by caller
3560a2ef57dba9ac77d8eccacd646b2b8a8d99fe9d8bEric Laurent                if (volume < 0) {
3561f2b0c11f4e797e183131261724d8de310dac5431Jean-Michel Trivi                    volFloat = (float)Math.pow(10, (float)sSoundEffectVolumeDb/20);
3562a2ef57dba9ac77d8eccacd646b2b8a8d99fe9d8bEric Laurent                } else {
35638a2cfc309ab9126e90022916967c65a793c034f0RoboErik                    volFloat = volume / 1000.0f;
3564a2ef57dba9ac77d8eccacd646b2b8a8d99fe9d8bEric Laurent                }
35659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
35669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (SOUND_EFFECT_FILES_MAP[effectType][1] > 0) {
35675d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    mSoundPool.play(SOUND_EFFECT_FILES_MAP[effectType][1],
35685d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                                        volFloat, volFloat, 0, 0, 1.0f);
35699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                } else {
35709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    MediaPlayer mediaPlayer = new MediaPlayer();
357162b9aec7a0a4e1cf8cfec7e39ea3103ab510d72eGlenn Kasten                    try {
3572e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent                        String filePath = Environment.getRootDirectory() + SOUND_EFFECTS_PATH +
3573e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent                                    SOUND_EFFECT_FILES.get(SOUND_EFFECT_FILES_MAP[effectType][0]);
357462b9aec7a0a4e1cf8cfec7e39ea3103ab510d72eGlenn Kasten                        mediaPlayer.setDataSource(filePath);
357562b9aec7a0a4e1cf8cfec7e39ea3103ab510d72eGlenn Kasten                        mediaPlayer.setAudioStreamType(AudioSystem.STREAM_SYSTEM);
357662b9aec7a0a4e1cf8cfec7e39ea3103ab510d72eGlenn Kasten                        mediaPlayer.prepare();
3577068225de0197df07a0247b2877666ea91c22c992Glenn Kasten                        mediaPlayer.setVolume(volFloat);
357862b9aec7a0a4e1cf8cfec7e39ea3103ab510d72eGlenn Kasten                        mediaPlayer.setOnCompletionListener(new OnCompletionListener() {
357962b9aec7a0a4e1cf8cfec7e39ea3103ab510d72eGlenn Kasten                            public void onCompletion(MediaPlayer mp) {
358062b9aec7a0a4e1cf8cfec7e39ea3103ab510d72eGlenn Kasten                                cleanupPlayer(mp);
358162b9aec7a0a4e1cf8cfec7e39ea3103ab510d72eGlenn Kasten                            }
358262b9aec7a0a4e1cf8cfec7e39ea3103ab510d72eGlenn Kasten                        });
358362b9aec7a0a4e1cf8cfec7e39ea3103ab510d72eGlenn Kasten                        mediaPlayer.setOnErrorListener(new OnErrorListener() {
358462b9aec7a0a4e1cf8cfec7e39ea3103ab510d72eGlenn Kasten                            public boolean onError(MediaPlayer mp, int what, int extra) {
358562b9aec7a0a4e1cf8cfec7e39ea3103ab510d72eGlenn Kasten                                cleanupPlayer(mp);
358662b9aec7a0a4e1cf8cfec7e39ea3103ab510d72eGlenn Kasten                                return true;
358762b9aec7a0a4e1cf8cfec7e39ea3103ab510d72eGlenn Kasten                            }
358862b9aec7a0a4e1cf8cfec7e39ea3103ab510d72eGlenn Kasten                        });
358962b9aec7a0a4e1cf8cfec7e39ea3103ab510d72eGlenn Kasten                        mediaPlayer.start();
359062b9aec7a0a4e1cf8cfec7e39ea3103ab510d72eGlenn Kasten                    } catch (IOException ex) {
359162b9aec7a0a4e1cf8cfec7e39ea3103ab510d72eGlenn Kasten                        Log.w(TAG, "MediaPlayer IOException: "+ex);
359262b9aec7a0a4e1cf8cfec7e39ea3103ab510d72eGlenn Kasten                    } catch (IllegalArgumentException ex) {
359362b9aec7a0a4e1cf8cfec7e39ea3103ab510d72eGlenn Kasten                        Log.w(TAG, "MediaPlayer IllegalArgumentException: "+ex);
359462b9aec7a0a4e1cf8cfec7e39ea3103ab510d72eGlenn Kasten                    } catch (IllegalStateException ex) {
359562b9aec7a0a4e1cf8cfec7e39ea3103ab510d72eGlenn Kasten                        Log.w(TAG, "MediaPlayer IllegalStateException: "+ex);
35969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    }
35979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
35989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
35999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
36009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
36019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        private void cleanupPlayer(MediaPlayer mp) {
36029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (mp != null) {
36039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                try {
36049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    mp.stop();
36059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    mp.release();
36069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                } catch (IllegalStateException ex) {
36079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    Log.w(TAG, "MediaPlayer IllegalStateException: "+ex);
36089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
36099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
36109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
36119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3612fa640154f1f42121d81242b2f1a10f03e52f0014Eric Laurent        private void setForceUse(int usage, int config) {
3613fa640154f1f42121d81242b2f1a10f03e52f0014Eric Laurent            AudioSystem.setForceUse(usage, config);
3614fa640154f1f42121d81242b2f1a10f03e52f0014Eric Laurent        }
3615fa640154f1f42121d81242b2f1a10f03e52f0014Eric Laurent
361605274f348e12983eb8613cc6eb9ae561e8197e28Eric Laurent        private void onPersistSafeVolumeState(int state) {
361705274f348e12983eb8613cc6eb9ae561e8197e28Eric Laurent            Settings.Global.putInt(mContentResolver,
361805274f348e12983eb8613cc6eb9ae561e8197e28Eric Laurent                    Settings.Global.AUDIO_SAFE_VOLUME_STATE,
361905274f348e12983eb8613cc6eb9ae561e8197e28Eric Laurent                    state);
362005274f348e12983eb8613cc6eb9ae561e8197e28Eric Laurent        }
362105274f348e12983eb8613cc6eb9ae561e8197e28Eric Laurent
36229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        @Override
36239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public void handleMessage(Message msg) {
36249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3625afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent            switch (msg.what) {
36269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
36279bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                case MSG_SET_DEVICE_VOLUME:
36289bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                    setDeviceVolume((VolumeStreamState) msg.obj, msg.arg1);
36299bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                    break;
36309bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent
36319bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                case MSG_SET_ALL_VOLUMES:
36329bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                    setAllVolumes((VolumeStreamState) msg.obj);
36339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    break;
36349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
36359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                case MSG_PERSIST_VOLUME:
363642b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                    persistVolume((VolumeStreamState) msg.obj, msg.arg1);
36379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    break;
36389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
36395c55a051ad7d86a464fb91426f1ea3c0250e38b3Mike Lockwood                case MSG_PERSIST_MASTER_VOLUME:
364083a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent                    if (mUseFixedVolume) {
364183a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent                        return;
364283a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent                    }
3643bc0fab1fc2db832ef86d8a33466ec4d68b103ca0Eric Laurent                    Settings.System.putFloatForUser(mContentResolver,
3644bc0fab1fc2db832ef86d8a33466ec4d68b103ca0Eric Laurent                                                    Settings.System.VOLUME_MASTER,
36458a2cfc309ab9126e90022916967c65a793c034f0RoboErik                                                    msg.arg1 / (float)1000.0,
3646bc0fab1fc2db832ef86d8a33466ec4d68b103ca0Eric Laurent                                                    UserHandle.USER_CURRENT);
36475c55a051ad7d86a464fb91426f1ea3c0250e38b3Mike Lockwood                    break;
36485c55a051ad7d86a464fb91426f1ea3c0250e38b3Mike Lockwood
364957978ed86286a33d5b1a0fd000ca3406ba9d87b3Justin Koh                case MSG_PERSIST_MASTER_VOLUME_MUTE:
365083a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent                    if (mUseFixedVolume) {
365183a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent                        return;
365283a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent                    }
3653bc0fab1fc2db832ef86d8a33466ec4d68b103ca0Eric Laurent                    Settings.System.putIntForUser(mContentResolver,
3654bc0fab1fc2db832ef86d8a33466ec4d68b103ca0Eric Laurent                                                 Settings.System.VOLUME_MASTER_MUTE,
3655bc0fab1fc2db832ef86d8a33466ec4d68b103ca0Eric Laurent                                                 msg.arg1,
3656bc0fab1fc2db832ef86d8a33466ec4d68b103ca0Eric Laurent                                                 UserHandle.USER_CURRENT);
365757978ed86286a33d5b1a0fd000ca3406ba9d87b3Justin Koh                    break;
365857978ed86286a33d5b1a0fd000ca3406ba9d87b3Justin Koh
36599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                case MSG_PERSIST_RINGER_MODE:
3660ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten                    // note that the value persisted is the current ringer mode, not the
3661ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten                    // value of ringer mode as of the time the request was made to persist
3662ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten                    persistRingerMode(getRingerMode());
36639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    break;
36649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
36659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                case MSG_MEDIA_SERVER_DIED:
3666dfb881f96af7898151940a4bbc52e45e6043d38bEric Laurent                    if (AudioSystem.checkAudioFlinger() != AudioSystem.AUDIO_STATUS_OK) {
366789e74ba1419732dd5c7f939e48d4aa7989fd3a51Eric Laurent                        Log.e(TAG, "Media server died.");
3668afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent                        sendMsg(mAudioHandler, MSG_MEDIA_SERVER_DIED, SENDMSG_NOOP, 0, 0,
366989e74ba1419732dd5c7f939e48d4aa7989fd3a51Eric Laurent                                null, 500);
3670dfb881f96af7898151940a4bbc52e45e6043d38bEric Laurent                        break;
367189e74ba1419732dd5c7f939e48d4aa7989fd3a51Eric Laurent                    }
36729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    Log.e(TAG, "Media server started.");
3673dfb881f96af7898151940a4bbc52e45e6043d38bEric Laurent
36743c652ca5a546e7227a5f4bdbf0f81552b2c91383Eric Laurent                    // indicate to audio HAL that we start the reconfiguration phase after a media
36753c652ca5a546e7227a5f4bdbf0f81552b2c91383Eric Laurent                    // server crash
3676dfb881f96af7898151940a4bbc52e45e6043d38bEric Laurent                    // Note that we only execute this when the media server
36773c652ca5a546e7227a5f4bdbf0f81552b2c91383Eric Laurent                    // process restarts after a crash, not the first time it is started.
36783c652ca5a546e7227a5f4bdbf0f81552b2c91383Eric Laurent                    AudioSystem.setParameters("restarting=true");
36793c652ca5a546e7227a5f4bdbf0f81552b2c91383Eric Laurent
3680fd116ad1ab02f6060a0b2201f018317fa32e28b4Glenn Kasten                    readAndSetLowRamDevice();
3681fd116ad1ab02f6060a0b2201f018317fa32e28b4Glenn Kasten
3682c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent                    // Restore device connection states
36836bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                    synchronized (mConnectedDevices) {
36846bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                        Set set = mConnectedDevices.entrySet();
36856bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                        Iterator i = set.iterator();
36869bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                        while (i.hasNext()) {
36876bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                            Map.Entry device = (Map.Entry)i.next();
36886bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                            AudioSystem.setDeviceConnectionState(
36896bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                                                            ((Integer)device.getKey()).intValue(),
36906bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                                                            AudioSystem.DEVICE_STATE_AVAILABLE,
36916bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                                                            (String)device.getValue());
36926bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                        }
3693c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent                    }
3694c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent                    // Restore call state
3695c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent                    AudioSystem.setPhoneState(mMode);
3696c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent
3697d5603c126acdd94d9f7400bb1d04188020a425b4Eric Laurent                    // Restore forced usage for communcations and record
3698c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent                    AudioSystem.setForceUse(AudioSystem.FOR_COMMUNICATION, mForcedUseForComm);
3699d5603c126acdd94d9f7400bb1d04188020a425b4Eric Laurent                    AudioSystem.setForceUse(AudioSystem.FOR_RECORD, mForcedUseForComm);
3700dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent                    AudioSystem.setForceUse(AudioSystem.FOR_SYSTEM, mCameraSoundForced ?
3701dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent                                    AudioSystem.FORCE_SYSTEM_ENFORCED : AudioSystem.FORCE_NONE);
3702c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent
3703a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent                    // Restore stream volumes
37049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    int numStreamTypes = AudioSystem.getNumStreamTypes();
37059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
37069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        VolumeStreamState streamState = mStreamStates[streamType];
3707c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent                        AudioSystem.initStreamVolume(streamType, 0, (streamState.mIndexMax + 5) / 10);
37089bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent
37099bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                        streamState.applyAllVolumes();
37109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    }
3711c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent
3712c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent                    // Restore ringer mode
3713c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent                    setRingerModeInt(getRingerMode(), false);
37143c652ca5a546e7227a5f4bdbf0f81552b2c91383Eric Laurent
37159063154a793b0ab38b3c5992cbaed046427b4a82Mike Lockwood                    // Restore master volume
37169063154a793b0ab38b3c5992cbaed046427b4a82Mike Lockwood                    restoreMasterVolume();
37179063154a793b0ab38b3c5992cbaed046427b4a82Mike Lockwood
3718f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi                    // Reset device orientation (if monitored for this device)
3719d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent                    if (mMonitorOrientation) {
3720f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi                        setOrientationForAudioSystem();
3721f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi                    }
3722bb6f8711a7f804d39c45218db2d6339940cc5d35Jean-Michel Trivi                    if (mMonitorRotation) {
3723bb6f8711a7f804d39c45218db2d6339940cc5d35Jean-Michel Trivi                        setRotationForAudioSystem();
3724bb6f8711a7f804d39c45218db2d6339940cc5d35Jean-Michel Trivi                    }
3725f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi
37267847211fb4699bf6018e29d214a918ed6657319bEric Laurent                    synchronized (mBluetoothA2dpEnabledLock) {
37277847211fb4699bf6018e29d214a918ed6657319bEric Laurent                        AudioSystem.setForceUse(AudioSystem.FOR_MEDIA,
37287847211fb4699bf6018e29d214a918ed6657319bEric Laurent                                mBluetoothA2dpEnabled ?
37297847211fb4699bf6018e29d214a918ed6657319bEric Laurent                                        AudioSystem.FORCE_NONE : AudioSystem.FORCE_NO_BT_A2DP);
37307847211fb4699bf6018e29d214a918ed6657319bEric Laurent                    }
3731bff5ca576ef55bfdd51a0d2ff39f4bac614fa728Eric Laurent
3732bff5ca576ef55bfdd51a0d2ff39f4bac614fa728Eric Laurent                    synchronized (mSettingsLock) {
3733bff5ca576ef55bfdd51a0d2ff39f4bac614fa728Eric Laurent                        AudioSystem.setForceUse(AudioSystem.FOR_DOCK,
3734bff5ca576ef55bfdd51a0d2ff39f4bac614fa728Eric Laurent                                mDockAudioMediaEnabled ?
3735bff5ca576ef55bfdd51a0d2ff39f4bac614fa728Eric Laurent                                        AudioSystem.FORCE_ANALOG_DOCK : AudioSystem.FORCE_NONE);
3736bff5ca576ef55bfdd51a0d2ff39f4bac614fa728Eric Laurent                    }
3737bff5ca576ef55bfdd51a0d2ff39f4bac614fa728Eric Laurent
37383c652ca5a546e7227a5f4bdbf0f81552b2c91383Eric Laurent                    // indicate the end of reconfiguration phase to audio HAL
37393c652ca5a546e7227a5f4bdbf0f81552b2c91383Eric Laurent                    AudioSystem.setParameters("restarting=false");
37409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    break;
37419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
37425d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                case MSG_UNLOAD_SOUND_EFFECTS:
37435d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    onUnloadSoundEffects();
37445d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    break;
37455d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent
3746117b7bb5b5a4457711f59bde3dcc83d8f111c524Eric Laurent                case MSG_LOAD_SOUND_EFFECTS:
37475d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    //FIXME: onLoadSoundEffects() should be executed in a separate thread as it
37485d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    // can take several dozens of milliseconds to complete
37495d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    boolean loaded = onLoadSoundEffects();
37505d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    if (msg.obj != null) {
37515d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                        LoadSoundEffectReply reply = (LoadSoundEffectReply)msg.obj;
37525d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                        synchronized (reply) {
37535d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                            reply.mStatus = loaded ? 0 : -1;
37545d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                            reply.notify();
37555d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                        }
37565d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    }
3757117b7bb5b5a4457711f59bde3dcc83d8f111c524Eric Laurent                    break;
3758117b7bb5b5a4457711f59bde3dcc83d8f111c524Eric Laurent
37599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                case MSG_PLAY_SOUND_EFFECT:
37605d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    onPlaySoundEffect(msg.arg1, msg.arg2);
37619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    break;
37624c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi
37634c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi                case MSG_BTA2DP_DOCK_TIMEOUT:
37644c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi                    // msg.obj  == address of BTA2DP device
37656bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                    synchronized (mConnectedDevices) {
37666bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                        makeA2dpDeviceUnavailableNow( (String) msg.obj );
37676bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                    }
37684c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi                    break;
3769fa640154f1f42121d81242b2f1a10f03e52f0014Eric Laurent
3770fa640154f1f42121d81242b2f1a10f03e52f0014Eric Laurent                case MSG_SET_FORCE_USE:
3771c390bed06b4a572e273ead1254da9a932e04dce3Eric Laurent                case MSG_SET_FORCE_BT_A2DP_USE:
3772fa640154f1f42121d81242b2f1a10f03e52f0014Eric Laurent                    setForceUse(msg.arg1, msg.arg2);
3773fa640154f1f42121d81242b2f1a10f03e52f0014Eric Laurent                    break;
3774d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi
3775dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                case MSG_BT_HEADSET_CNCT_FAILED:
3776dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                    resetBluetoothSco();
3777dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                    break;
3778b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent
3779b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent                case MSG_SET_WIRED_DEVICE_CONNECTION_STATE:
3780b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent                    onSetWiredDeviceConnectionState(msg.arg1, msg.arg2, (String)msg.obj);
3781fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                    mAudioEventWakeLock.release();
3782b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent                    break;
3783b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent
37840a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood                case MSG_SET_A2DP_SRC_CONNECTION_STATE:
37850a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood                    onSetA2dpSourceConnectionState((BluetoothDevice)msg.obj, msg.arg1);
37860a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood                    mAudioEventWakeLock.release();
37870a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood                    break;
37880a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood
37890a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood                case MSG_SET_A2DP_SINK_CONNECTION_STATE:
37900a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood                    onSetA2dpSinkConnectionState((BluetoothDevice)msg.obj, msg.arg1);
3791fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                    mAudioEventWakeLock.release();
3792b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent                    break;
3793632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn
3794632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                case MSG_REPORT_NEW_ROUTES: {
3795632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                    int N = mRoutesObservers.beginBroadcast();
3796632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                    if (N > 0) {
3797632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                        AudioRoutesInfo routes;
3798632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                        synchronized (mCurAudioRoutes) {
3799632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                            routes = new AudioRoutesInfo(mCurAudioRoutes);
3800632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                        }
3801632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                        while (N > 0) {
3802632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                            N--;
3803632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                            IAudioRoutesObserver obs = mRoutesObservers.getBroadcastItem(N);
3804632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                            try {
3805632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                                obs.dispatchAudioRoutesChanged(routes);
3806632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                            } catch (RemoteException e) {
3807632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                            }
3808632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                        }
3809632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                    }
3810632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                    mRoutesObservers.finishBroadcast();
3811632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                    break;
3812632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                }
38133114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi
3814c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent                case MSG_CHECK_MUSIC_ACTIVE:
3815c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent                    onCheckMusicActive();
3816c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent                    break;
38175bfaeaef3fc348d66f48b86be08655e91dff910aEric Laurent
38185bfaeaef3fc348d66f48b86be08655e91dff910aEric Laurent                case MSG_BROADCAST_AUDIO_BECOMING_NOISY:
38195bfaeaef3fc348d66f48b86be08655e91dff910aEric Laurent                    onSendBecomingNoisyIntent();
38205bfaeaef3fc348d66f48b86be08655e91dff910aEric Laurent                    break;
3821d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent
3822d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent                case MSG_CONFIGURE_SAFE_MEDIA_VOLUME_FORCED:
3823d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent                case MSG_CONFIGURE_SAFE_MEDIA_VOLUME:
3824d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent                    onConfigureSafeVolume((msg.what == MSG_CONFIGURE_SAFE_MEDIA_VOLUME_FORCED));
3825d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent                    break;
382605274f348e12983eb8613cc6eb9ae561e8197e28Eric Laurent                case MSG_PERSIST_SAFE_VOLUME_STATE:
382705274f348e12983eb8613cc6eb9ae561e8197e28Eric Laurent                    onPersistSafeVolumeState(msg.arg1);
382805274f348e12983eb8613cc6eb9ae561e8197e28Eric Laurent                    break;
3829a578c48e6c8677bcb54340aadb9470f8a275e56cJean-Michel Trivi
38302a57ca931fefe817b6110101289721acaacfc808Eric Laurent                case MSG_BROADCAST_BT_CONNECTION_STATE:
38312a57ca931fefe817b6110101289721acaacfc808Eric Laurent                    onBroadcastScoConnectionState(msg.arg1);
38322a57ca931fefe817b6110101289721acaacfc808Eric Laurent                    break;
38334a5eeb9c727d77bb57fef87a70c8c9cc23dbfee3Eric Laurent
38344a5eeb9c727d77bb57fef87a70c8c9cc23dbfee3Eric Laurent                case MSG_SYSTEM_READY:
38354a5eeb9c727d77bb57fef87a70c8c9cc23dbfee3Eric Laurent                    onSystemReady();
38364a5eeb9c727d77bb57fef87a70c8c9cc23dbfee3Eric Laurent                    break;
38379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
38389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
38399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
38409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3841b109615ebebd6f3b9ae789412279f576c3ace46bJason Parekh    private class SettingsObserver extends ContentObserver {
3842a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent
3843b109615ebebd6f3b9ae789412279f576c3ace46bJason Parekh        SettingsObserver() {
3844b109615ebebd6f3b9ae789412279f576c3ace46bJason Parekh            super(new Handler());
3845b109615ebebd6f3b9ae789412279f576c3ace46bJason Parekh            mContentResolver.registerContentObserver(Settings.System.getUriFor(
3846b109615ebebd6f3b9ae789412279f576c3ace46bJason Parekh                Settings.System.MODE_RINGER_STREAMS_AFFECTED), false, this);
38477ee1e4ff7346a278a6722108fbc1869240b3e866Eric Laurent            mContentResolver.registerContentObserver(Settings.Global.getUriFor(
38487ee1e4ff7346a278a6722108fbc1869240b3e866Eric Laurent                Settings.Global.DOCK_AUDIO_MEDIA_ENABLED), false, this);
3849b109615ebebd6f3b9ae789412279f576c3ace46bJason Parekh        }
3850b109615ebebd6f3b9ae789412279f576c3ace46bJason Parekh
3851b109615ebebd6f3b9ae789412279f576c3ace46bJason Parekh        @Override
3852b109615ebebd6f3b9ae789412279f576c3ace46bJason Parekh        public void onChange(boolean selfChange) {
3853b109615ebebd6f3b9ae789412279f576c3ace46bJason Parekh            super.onChange(selfChange);
3854ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten            // FIXME This synchronized is not necessary if mSettingsLock only protects mRingerMode.
3855ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten            //       However there appear to be some missing locks around mRingerModeMutedStreams
3856ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten            //       and mRingerModeAffectedStreams, so will leave this synchronized for now.
3857ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten            //       mRingerModeMutedStreams and mMuteAffectedStreams are safe (only accessed once).
3858a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent            synchronized (mSettingsLock) {
385924e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent                if (updateRingerModeAffectedStreams()) {
3860a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent                    /*
3861a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent                     * Ensure all stream types that should be affected by ringer mode
3862a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent                     * are in the proper state.
3863a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent                     */
3864a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent                    setRingerModeInt(getRingerMode(), false);
3865a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent                }
38667ee1e4ff7346a278a6722108fbc1869240b3e866Eric Laurent                readDockAudioSettings(mContentResolver);
3867a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent            }
3868b109615ebebd6f3b9ae789412279f576c3ace46bJason Parekh        }
3869b109615ebebd6f3b9ae789412279f576c3ace46bJason Parekh    }
3870a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent
38716bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent    // must be called synchronized on mConnectedDevices
38724c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi    private void makeA2dpDeviceAvailable(String address) {
38737847211fb4699bf6018e29d214a918ed6657319bEric Laurent        // enable A2DP before notifying A2DP connection to avoid unecessary processing in
38747847211fb4699bf6018e29d214a918ed6657319bEric Laurent        // audio policy manager
3875c9d1d5f35091226e96fcfa91817480f589eb36e2Matthew Xie        VolumeStreamState streamState = mStreamStates[AudioSystem.STREAM_MUSIC];
3876c9d1d5f35091226e96fcfa91817480f589eb36e2Matthew Xie        sendMsg(mAudioHandler, MSG_SET_DEVICE_VOLUME, SENDMSG_QUEUE,
3877c9d1d5f35091226e96fcfa91817480f589eb36e2Matthew Xie                AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, 0, streamState, 0);
38787847211fb4699bf6018e29d214a918ed6657319bEric Laurent        setBluetoothA2dpOnInt(true);
38794c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi        AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
38804c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi                AudioSystem.DEVICE_STATE_AVAILABLE,
38814c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi                address);
38824c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi        // Reset A2DP suspend state each time a new sink is connected
38834c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi        AudioSystem.setParameters("A2dpSuspended=false");
38844c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi        mConnectedDevices.put( new Integer(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP),
38854c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi                address);
38864c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi    }
38874c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi
38885bfaeaef3fc348d66f48b86be08655e91dff910aEric Laurent    private void onSendBecomingNoisyIntent() {
38895ac72a29593ab9a20337a2225df52bdf4754be02Dianne Hackborn        sendBroadcastToAll(new Intent(AudioManager.ACTION_AUDIO_BECOMING_NOISY));
38909841818b9a0280abf59343c9e00a2976dbc084faMike Lockwood    }
38919841818b9a0280abf59343c9e00a2976dbc084faMike Lockwood
38926bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent    // must be called synchronized on mConnectedDevices
38934c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi    private void makeA2dpDeviceUnavailableNow(String address) {
3894c9d1d5f35091226e96fcfa91817480f589eb36e2Matthew Xie        synchronized (mA2dpAvrcpLock) {
3895c9d1d5f35091226e96fcfa91817480f589eb36e2Matthew Xie            mAvrcpAbsVolSupported = false;
3896c9d1d5f35091226e96fcfa91817480f589eb36e2Matthew Xie        }
38974c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi        AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
38984c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi                AudioSystem.DEVICE_STATE_UNAVAILABLE,
38994c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi                address);
39004c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi        mConnectedDevices.remove(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP);
39014c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi    }
39024c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi
39036bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent    // must be called synchronized on mConnectedDevices
39044c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi    private void makeA2dpDeviceUnavailableLater(String address) {
39053b5912602bec6ccbe8eef8a576730b1565f0067cEric Laurent        // prevent any activity on the A2DP audio output to avoid unwanted
39063b5912602bec6ccbe8eef8a576730b1565f0067cEric Laurent        // reconnection of the sink.
39073b5912602bec6ccbe8eef8a576730b1565f0067cEric Laurent        AudioSystem.setParameters("A2dpSuspended=true");
39084c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi        // the device will be made unavailable later, so consider it disconnected right away
39094c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi        mConnectedDevices.remove(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP);
39104c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi        // send the delayed message to make the device unavailable later
39114c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi        Message msg = mAudioHandler.obtainMessage(MSG_BTA2DP_DOCK_TIMEOUT, address);
39124c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi        mAudioHandler.sendMessageDelayed(msg, BTA2DP_DOCK_TIMEOUT_MILLIS);
39134c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi
39144c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi    }
39154c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi
39166bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent    // must be called synchronized on mConnectedDevices
39170a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood    private void makeA2dpSrcAvailable(String address) {
39180a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood        AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP,
39190a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood                AudioSystem.DEVICE_STATE_AVAILABLE,
39200a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood                address);
39210a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood        mConnectedDevices.put( new Integer(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP),
39220a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood                address);
39230a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood    }
39240a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood
39250a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood    // must be called synchronized on mConnectedDevices
39260a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood    private void makeA2dpSrcUnavailable(String address) {
39270a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood        AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP,
39280a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood                AudioSystem.DEVICE_STATE_UNAVAILABLE,
39290a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood                address);
39300a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood        mConnectedDevices.remove(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP);
39310a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood    }
39320a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood
39330a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood    // must be called synchronized on mConnectedDevices
3934a847ba4080675d395de725cfac5dfd9d5a993d4eJean-Michel Trivi    private void cancelA2dpDeviceTimeout() {
39354c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi        mAudioHandler.removeMessages(MSG_BTA2DP_DOCK_TIMEOUT);
39364c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi    }
39374c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi
39386bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent    // must be called synchronized on mConnectedDevices
3939a847ba4080675d395de725cfac5dfd9d5a993d4eJean-Michel Trivi    private boolean hasScheduledA2dpDockTimeout() {
3940a847ba4080675d395de725cfac5dfd9d5a993d4eJean-Michel Trivi        return mAudioHandler.hasMessages(MSG_BTA2DP_DOCK_TIMEOUT);
3941a847ba4080675d395de725cfac5dfd9d5a993d4eJean-Michel Trivi    }
3942a847ba4080675d395de725cfac5dfd9d5a993d4eJean-Michel Trivi
39430a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood    private void onSetA2dpSinkConnectionState(BluetoothDevice btDevice, int state)
39446bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent    {
39450a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood        if (DEBUG_VOL) {
39460a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood            Log.d(TAG, "onSetA2dpSinkConnectionState btDevice="+btDevice+"state="+state);
39470a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood        }
39486bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent        if (btDevice == null) {
39496bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent            return;
39506bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent        }
39516bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent        String address = btDevice.getAddress();
39526bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent        if (!BluetoothAdapter.checkBluetoothAddress(address)) {
39536bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent            address = "";
39546bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent        }
39555a0cf7a27f3953a1266af48543ccd9024f4cd89fJohn Du
39566bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent        synchronized (mConnectedDevices) {
39576bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent            boolean isConnected =
39586bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                (mConnectedDevices.containsKey(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP) &&
39596bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                 mConnectedDevices.get(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP).equals(address));
39606bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent
39616bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent            if (isConnected && state != BluetoothProfile.STATE_CONNECTED) {
39626bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                if (btDevice.isBluetoothDock()) {
39636bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                    if (state == BluetoothProfile.STATE_DISCONNECTED) {
39646bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                        // introduction of a delay for transient disconnections of docks when
39656bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                        // power is rapidly turned off/on, this message will be canceled if
39666bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                        // we reconnect the dock under a preset delay
39676bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                        makeA2dpDeviceUnavailableLater(address);
39686bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                        // the next time isConnected is evaluated, it will be false for the dock
39696bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                    }
39706bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                } else {
39716bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                    makeA2dpDeviceUnavailableNow(address);
39726bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                }
3973632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                synchronized (mCurAudioRoutes) {
3974632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                    if (mCurAudioRoutes.mBluetoothName != null) {
3975632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                        mCurAudioRoutes.mBluetoothName = null;
3976632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                        sendMsg(mAudioHandler, MSG_REPORT_NEW_ROUTES,
3977632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                                SENDMSG_NOOP, 0, 0, null, 0);
3978632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                    }
3979632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                }
39806bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent            } else if (!isConnected && state == BluetoothProfile.STATE_CONNECTED) {
39816bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                if (btDevice.isBluetoothDock()) {
39826bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                    // this could be a reconnection after a transient disconnection
39836bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                    cancelA2dpDeviceTimeout();
39846bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                    mDockAddress = address;
39856bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                } else {
39866bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                    // this could be a connection of another A2DP device before the timeout of
39876bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                    // a dock: cancel the dock timeout, and make the dock unavailable now
39886bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                    if(hasScheduledA2dpDockTimeout()) {
39896bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                        cancelA2dpDeviceTimeout();
39906bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                        makeA2dpDeviceUnavailableNow(mDockAddress);
39916bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                    }
39926bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                }
39936bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                makeA2dpDeviceAvailable(address);
3994632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                synchronized (mCurAudioRoutes) {
3995632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                    String name = btDevice.getAliasName();
3996632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                    if (!TextUtils.equals(mCurAudioRoutes.mBluetoothName, name)) {
3997632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                        mCurAudioRoutes.mBluetoothName = name;
3998632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                        sendMsg(mAudioHandler, MSG_REPORT_NEW_ROUTES,
3999632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                                SENDMSG_NOOP, 0, 0, null, 0);
4000632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                    }
4001632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                }
40026bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent            }
40036bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent        }
40046bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent    }
40056bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent
40060a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood    private void onSetA2dpSourceConnectionState(BluetoothDevice btDevice, int state)
40070a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood    {
40080a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood        if (DEBUG_VOL) {
40090a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood            Log.d(TAG, "onSetA2dpSourceConnectionState btDevice="+btDevice+" state="+state);
40100a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood        }
40110a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood        if (btDevice == null) {
40120a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood            return;
40130a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood        }
40140a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood        String address = btDevice.getAddress();
40150a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood        if (!BluetoothAdapter.checkBluetoothAddress(address)) {
40160a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood            address = "";
40170a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood        }
40180a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood
40190a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood        synchronized (mConnectedDevices) {
40200a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood                boolean isConnected =
40210a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood                (mConnectedDevices.containsKey(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP) &&
40220a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood                 mConnectedDevices.get(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP).equals(address));
40230a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood
40240a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood            if (isConnected && state != BluetoothProfile.STATE_CONNECTED) {
40250a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood                makeA2dpSrcUnavailable(address);
40260a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood            } else if (!isConnected && state == BluetoothProfile.STATE_CONNECTED) {
40270a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood                makeA2dpSrcAvailable(address);
40280a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood            }
40290a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood        }
40300a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood    }
40310a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood
40325a0cf7a27f3953a1266af48543ccd9024f4cd89fJohn Du    public void avrcpSupportsAbsoluteVolume(String address, boolean support) {
40335a0cf7a27f3953a1266af48543ccd9024f4cd89fJohn Du        // address is not used for now, but may be used when multiple a2dp devices are supported
40345a0cf7a27f3953a1266af48543ccd9024f4cd89fJohn Du        synchronized (mA2dpAvrcpLock) {
40355a0cf7a27f3953a1266af48543ccd9024f4cd89fJohn Du            mAvrcpAbsVolSupported = support;
4036c9d1d5f35091226e96fcfa91817480f589eb36e2Matthew Xie            sendMsg(mAudioHandler, MSG_SET_DEVICE_VOLUME, SENDMSG_QUEUE,
4037cd772d04345850e160a45613fcf6b86da0dce4cfEric Laurent                    AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, 0,
4038cd772d04345850e160a45613fcf6b86da0dce4cfEric Laurent                    mStreamStates[AudioSystem.STREAM_MUSIC], 0);
4039cd772d04345850e160a45613fcf6b86da0dce4cfEric Laurent            sendMsg(mAudioHandler, MSG_SET_DEVICE_VOLUME, SENDMSG_QUEUE,
4040cd772d04345850e160a45613fcf6b86da0dce4cfEric Laurent                    AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, 0,
4041cd772d04345850e160a45613fcf6b86da0dce4cfEric Laurent                    mStreamStates[AudioSystem.STREAM_RING], 0);
40425a0cf7a27f3953a1266af48543ccd9024f4cd89fJohn Du        }
40435a0cf7a27f3953a1266af48543ccd9024f4cd89fJohn Du    }
40445a0cf7a27f3953a1266af48543ccd9024f4cd89fJohn Du
404559f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent    private boolean handleDeviceConnection(boolean connected, int device, String params) {
404659f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent        synchronized (mConnectedDevices) {
404759f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent            boolean isConnected = (mConnectedDevices.containsKey(device) &&
40489841818b9a0280abf59343c9e00a2976dbc084faMike Lockwood                    (params.isEmpty() || mConnectedDevices.get(device).equals(params)));
404959f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent
405059f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent            if (isConnected && !connected) {
405159f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent                AudioSystem.setDeviceConnectionState(device,
405259f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent                                              AudioSystem.DEVICE_STATE_UNAVAILABLE,
40539841818b9a0280abf59343c9e00a2976dbc084faMike Lockwood                                              mConnectedDevices.get(device));
405459f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent                 mConnectedDevices.remove(device);
405559f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent                 return true;
405659f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent            } else if (!isConnected && connected) {
405759f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent                 AudioSystem.setDeviceConnectionState(device,
405859f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent                                                      AudioSystem.DEVICE_STATE_AVAILABLE,
405959f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent                                                      params);
406059f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent                 mConnectedDevices.put(new Integer(device), params);
406159f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent                 return true;
406259f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent            }
406359f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent        }
406459f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent        return false;
406559f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent    }
406659f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent
4067b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent    // Devices which removal triggers intent ACTION_AUDIO_BECOMING_NOISY. The intent is only
4068b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent    // sent if none of these devices is connected.
4069b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent    int mBecomingNoisyIntentDevices =
4070b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent            AudioSystem.DEVICE_OUT_WIRED_HEADSET | AudioSystem.DEVICE_OUT_WIRED_HEADPHONE |
4071948d32748caaac5be06c991ebf00f74265a7849fEric Laurent            AudioSystem.DEVICE_OUT_ALL_A2DP | AudioSystem.DEVICE_OUT_HDMI |
4072794da7a0543cbecffefb73794aa68d1a93e41adfEric Laurent            AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET | AudioSystem.DEVICE_OUT_DGTL_DOCK_HEADSET |
4073794da7a0543cbecffefb73794aa68d1a93e41adfEric Laurent            AudioSystem.DEVICE_OUT_ALL_USB;
4074b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent
4075b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent    // must be called before removing the device from mConnectedDevices
4076b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent    private int checkSendBecomingNoisyIntent(int device, int state) {
4077b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent        int delay = 0;
4078b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent        if ((state == 0) && ((device & mBecomingNoisyIntentDevices) != 0)) {
4079b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent            int devices = 0;
4080b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent            for (int dev : mConnectedDevices.keySet()) {
4081b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent                if ((dev & mBecomingNoisyIntentDevices) != 0) {
4082b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent                   devices |= dev;
4083b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent                }
4084b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent            }
4085b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent            if (devices == device) {
40865bfaeaef3fc348d66f48b86be08655e91dff910aEric Laurent                sendMsg(mAudioHandler,
40875bfaeaef3fc348d66f48b86be08655e91dff910aEric Laurent                        MSG_BROADCAST_AUDIO_BECOMING_NOISY,
40885bfaeaef3fc348d66f48b86be08655e91dff910aEric Laurent                        SENDMSG_REPLACE,
40895bfaeaef3fc348d66f48b86be08655e91dff910aEric Laurent                        0,
40905bfaeaef3fc348d66f48b86be08655e91dff910aEric Laurent                        0,
40915bfaeaef3fc348d66f48b86be08655e91dff910aEric Laurent                        null,
40925bfaeaef3fc348d66f48b86be08655e91dff910aEric Laurent                        0);
4093b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent                delay = 1000;
4094b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent            }
4095b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent        }
4096b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent
40970a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood        if (mAudioHandler.hasMessages(MSG_SET_A2DP_SRC_CONNECTION_STATE) ||
40980a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood                mAudioHandler.hasMessages(MSG_SET_A2DP_SINK_CONNECTION_STATE) ||
4099b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent                mAudioHandler.hasMessages(MSG_SET_WIRED_DEVICE_CONNECTION_STATE)) {
4100b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent            delay = 1000;
4101b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent        }
4102b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent        return delay;
4103b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent    }
4104b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent
4105b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent    private void sendDeviceConnectionIntent(int device, int state, String name)
4106b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent    {
4107b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent        Intent intent = new Intent();
4108b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent
4109b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent        intent.putExtra("state", state);
4110b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent        intent.putExtra("name", name);
4111b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent        intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
4112b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent
4113632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn        int connType = 0;
4114632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn
4115b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent        if (device == AudioSystem.DEVICE_OUT_WIRED_HEADSET) {
4116632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn            connType = AudioRoutesInfo.MAIN_HEADSET;
4117b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent            intent.setAction(Intent.ACTION_HEADSET_PLUG);
4118b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent            intent.putExtra("microphone", 1);
4119b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent        } else if (device == AudioSystem.DEVICE_OUT_WIRED_HEADPHONE) {
4120632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn            connType = AudioRoutesInfo.MAIN_HEADPHONES;
4121b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent            intent.setAction(Intent.ACTION_HEADSET_PLUG);
4122b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent            intent.putExtra("microphone", 0);
4123b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent        } else if (device == AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET) {
4124632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn            connType = AudioRoutesInfo.MAIN_DOCK_SPEAKERS;
4125b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent            intent.setAction(Intent.ACTION_ANALOG_AUDIO_DOCK_PLUG);
4126b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent        } else if (device == AudioSystem.DEVICE_OUT_DGTL_DOCK_HEADSET) {
4127632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn            connType = AudioRoutesInfo.MAIN_DOCK_SPEAKERS;
4128b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent            intent.setAction(Intent.ACTION_DIGITAL_AUDIO_DOCK_PLUG);
4129948d32748caaac5be06c991ebf00f74265a7849fEric Laurent        } else if (device == AudioSystem.DEVICE_OUT_HDMI) {
4130632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn            connType = AudioRoutesInfo.MAIN_HDMI;
4131b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent            intent.setAction(Intent.ACTION_HDMI_AUDIO_PLUG);
4132b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent        }
4133b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent
4134632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn        synchronized (mCurAudioRoutes) {
4135632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn            if (connType != 0) {
4136632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                int newConn = mCurAudioRoutes.mMainType;
4137632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                if (state != 0) {
4138632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                    newConn |= connType;
4139632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                } else {
4140632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                    newConn &= ~connType;
4141632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                }
4142632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                if (newConn != mCurAudioRoutes.mMainType) {
4143632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                    mCurAudioRoutes.mMainType = newConn;
4144632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                    sendMsg(mAudioHandler, MSG_REPORT_NEW_ROUTES,
4145632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                            SENDMSG_NOOP, 0, 0, null, 0);
4146632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                }
4147632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn            }
4148632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn        }
4149632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn
41505ac72a29593ab9a20337a2225df52bdf4754be02Dianne Hackborn        final long ident = Binder.clearCallingIdentity();
41515ac72a29593ab9a20337a2225df52bdf4754be02Dianne Hackborn        try {
41525ac72a29593ab9a20337a2225df52bdf4754be02Dianne Hackborn            ActivityManagerNative.broadcastStickyIntent(intent, null, UserHandle.USER_ALL);
41535ac72a29593ab9a20337a2225df52bdf4754be02Dianne Hackborn        } finally {
41545ac72a29593ab9a20337a2225df52bdf4754be02Dianne Hackborn            Binder.restoreCallingIdentity(ident);
41555ac72a29593ab9a20337a2225df52bdf4754be02Dianne Hackborn        }
4156b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent    }
4157b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent
4158b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent    private void onSetWiredDeviceConnectionState(int device, int state, String name)
4159b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent    {
4160b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent        synchronized (mConnectedDevices) {
4161b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent            if ((state == 0) && ((device == AudioSystem.DEVICE_OUT_WIRED_HEADSET) ||
4162b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent                    (device == AudioSystem.DEVICE_OUT_WIRED_HEADPHONE))) {
4163b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent                setBluetoothA2dpOnInt(true);
4164b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent            }
4165ae4506e9b5fc3e0c6d9862fbc05b9af7d6742a6eEric Laurent            boolean isUsb = ((device & ~AudioSystem.DEVICE_OUT_ALL_USB) == 0) ||
4166ae4506e9b5fc3e0c6d9862fbc05b9af7d6742a6eEric Laurent                            (((device & AudioSystem.DEVICE_BIT_IN) != 0) &&
4167ae4506e9b5fc3e0c6d9862fbc05b9af7d6742a6eEric Laurent                             ((device & ~AudioSystem.DEVICE_IN_ALL_USB) == 0));
4168db45484e4b5858d14da93d3a06311b93bf0cf320Mike Lockwood            handleDeviceConnection((state == 1), device, (isUsb ? name : ""));
4169f1a457d06c53a901ea08d2d3fb6e766bc06c4d4fEric Laurent            if (state != 0) {
4170f1a457d06c53a901ea08d2d3fb6e766bc06c4d4fEric Laurent                if ((device == AudioSystem.DEVICE_OUT_WIRED_HEADSET) ||
4171f1a457d06c53a901ea08d2d3fb6e766bc06c4d4fEric Laurent                    (device == AudioSystem.DEVICE_OUT_WIRED_HEADPHONE)) {
4172f1a457d06c53a901ea08d2d3fb6e766bc06c4d4fEric Laurent                    setBluetoothA2dpOnInt(false);
4173f1a457d06c53a901ea08d2d3fb6e766bc06c4d4fEric Laurent                }
4174f1a457d06c53a901ea08d2d3fb6e766bc06c4d4fEric Laurent                if ((device & mSafeMediaVolumeDevices) != 0) {
4175f1a457d06c53a901ea08d2d3fb6e766bc06c4d4fEric Laurent                    sendMsg(mAudioHandler,
4176f1a457d06c53a901ea08d2d3fb6e766bc06c4d4fEric Laurent                            MSG_CHECK_MUSIC_ACTIVE,
4177f1a457d06c53a901ea08d2d3fb6e766bc06c4d4fEric Laurent                            SENDMSG_REPLACE,
4178f1a457d06c53a901ea08d2d3fb6e766bc06c4d4fEric Laurent                            0,
4179f1a457d06c53a901ea08d2d3fb6e766bc06c4d4fEric Laurent                            0,
4180f1a457d06c53a901ea08d2d3fb6e766bc06c4d4fEric Laurent                            null,
4181f1a457d06c53a901ea08d2d3fb6e766bc06c4d4fEric Laurent                            MUSIC_ACTIVE_POLL_PERIOD_MS);
4182f1a457d06c53a901ea08d2d3fb6e766bc06c4d4fEric Laurent                }
4183b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent            }
4184ae4506e9b5fc3e0c6d9862fbc05b9af7d6742a6eEric Laurent            if (!isUsb && (device != AudioSystem.DEVICE_IN_WIRED_HEADSET)) {
4185db45484e4b5858d14da93d3a06311b93bf0cf320Mike Lockwood                sendDeviceConnectionIntent(device, state, name);
4186db45484e4b5858d14da93d3a06311b93bf0cf320Mike Lockwood            }
4187b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent        }
4188b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent    }
4189b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent
4190a847ba4080675d395de725cfac5dfd9d5a993d4eJean-Michel Trivi    /* cache of the address of the last dock the device was connected to */
4191a847ba4080675d395de725cfac5dfd9d5a993d4eJean-Michel Trivi    private String mDockAddress;
4192a847ba4080675d395de725cfac5dfd9d5a993d4eJean-Michel Trivi
4193a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent    /**
4194a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent     * Receiver for misc intent broadcasts the Phone app cares about.
4195a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent     */
4196a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent    private class AudioServiceBroadcastReceiver extends BroadcastReceiver {
4197a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent        @Override
4198a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent        public void onReceive(Context context, Intent intent) {
4199a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent            String action = intent.getAction();
4200ae4506e9b5fc3e0c6d9862fbc05b9af7d6742a6eEric Laurent            int outDevice;
4201ae4506e9b5fc3e0c6d9862fbc05b9af7d6742a6eEric Laurent            int inDevice;
420259f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent            int state;
4203a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent
4204758559e6b7e310cf46cc269437f44decd58d68d6Jean-Michel Trivi            if (action.equals(Intent.ACTION_DOCK_EVENT)) {
4205758559e6b7e310cf46cc269437f44decd58d68d6Jean-Michel Trivi                int dockState = intent.getIntExtra(Intent.EXTRA_DOCK_STATE,
4206758559e6b7e310cf46cc269437f44decd58d68d6Jean-Michel Trivi                        Intent.EXTRA_DOCK_STATE_UNDOCKED);
4207758559e6b7e310cf46cc269437f44decd58d68d6Jean-Michel Trivi                int config;
4208758559e6b7e310cf46cc269437f44decd58d68d6Jean-Michel Trivi                switch (dockState) {
4209758559e6b7e310cf46cc269437f44decd58d68d6Jean-Michel Trivi                    case Intent.EXTRA_DOCK_STATE_DESK:
4210758559e6b7e310cf46cc269437f44decd58d68d6Jean-Michel Trivi                        config = AudioSystem.FORCE_BT_DESK_DOCK;
4211758559e6b7e310cf46cc269437f44decd58d68d6Jean-Michel Trivi                        break;
4212758559e6b7e310cf46cc269437f44decd58d68d6Jean-Michel Trivi                    case Intent.EXTRA_DOCK_STATE_CAR:
4213758559e6b7e310cf46cc269437f44decd58d68d6Jean-Michel Trivi                        config = AudioSystem.FORCE_BT_CAR_DOCK;
4214758559e6b7e310cf46cc269437f44decd58d68d6Jean-Michel Trivi                        break;
421521e941bf43362ddc6639a9f2d0828053360f53d7Praveen Bharathi                    case Intent.EXTRA_DOCK_STATE_LE_DESK:
421608ed1b9d2099ec8231b21353b33b901492ea9885Eric Laurent                        config = AudioSystem.FORCE_ANALOG_DOCK;
421721e941bf43362ddc6639a9f2d0828053360f53d7Praveen Bharathi                        break;
421821e941bf43362ddc6639a9f2d0828053360f53d7Praveen Bharathi                    case Intent.EXTRA_DOCK_STATE_HE_DESK:
421921e941bf43362ddc6639a9f2d0828053360f53d7Praveen Bharathi                        config = AudioSystem.FORCE_DIGITAL_DOCK;
422021e941bf43362ddc6639a9f2d0828053360f53d7Praveen Bharathi                        break;
4221758559e6b7e310cf46cc269437f44decd58d68d6Jean-Michel Trivi                    case Intent.EXTRA_DOCK_STATE_UNDOCKED:
4222758559e6b7e310cf46cc269437f44decd58d68d6Jean-Michel Trivi                    default:
4223758559e6b7e310cf46cc269437f44decd58d68d6Jean-Michel Trivi                        config = AudioSystem.FORCE_NONE;
4224758559e6b7e310cf46cc269437f44decd58d68d6Jean-Michel Trivi                }
422508ed1b9d2099ec8231b21353b33b901492ea9885Eric Laurent                // Low end docks have a menu to enable or disable audio
422608ed1b9d2099ec8231b21353b33b901492ea9885Eric Laurent                // (see mDockAudioMediaEnabled)
422708ed1b9d2099ec8231b21353b33b901492ea9885Eric Laurent                if (!((dockState == Intent.EXTRA_DOCK_STATE_LE_DESK) ||
422808ed1b9d2099ec8231b21353b33b901492ea9885Eric Laurent                      ((dockState == Intent.EXTRA_DOCK_STATE_UNDOCKED) &&
422908ed1b9d2099ec8231b21353b33b901492ea9885Eric Laurent                       (mDockState == Intent.EXTRA_DOCK_STATE_LE_DESK)))) {
423008ed1b9d2099ec8231b21353b33b901492ea9885Eric Laurent                    AudioSystem.setForceUse(AudioSystem.FOR_DOCK, config);
423108ed1b9d2099ec8231b21353b33b901492ea9885Eric Laurent                }
423208ed1b9d2099ec8231b21353b33b901492ea9885Eric Laurent                mDockState = dockState;
423382aa7f017daaaeb96c13e6e3491d5037ab471085Jaikumar Ganesh            } else if (action.equals(BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED)) {
423459f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent                state = intent.getIntExtra(BluetoothProfile.EXTRA_STATE,
423582aa7f017daaaeb96c13e6e3491d5037ab471085Jaikumar Ganesh                                               BluetoothProfile.STATE_DISCONNECTED);
4236ae4506e9b5fc3e0c6d9862fbc05b9af7d6742a6eEric Laurent                outDevice = AudioSystem.DEVICE_OUT_BLUETOOTH_SCO;
4237ae4506e9b5fc3e0c6d9862fbc05b9af7d6742a6eEric Laurent                inDevice = AudioSystem.DEVICE_IN_BLUETOOTH_SCO_HEADSET;
4238a56d1c72190462aa9e377906583eceb58e0efcddNick Pelly                String address = null;
4239dca56b9432e2cc851d1a58920071fed2e1e3d142Eric Laurent
4240dca56b9432e2cc851d1a58920071fed2e1e3d142Eric Laurent                BluetoothDevice btDevice = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
4241dca56b9432e2cc851d1a58920071fed2e1e3d142Eric Laurent                if (btDevice == null) {
4242dca56b9432e2cc851d1a58920071fed2e1e3d142Eric Laurent                    return;
4243dca56b9432e2cc851d1a58920071fed2e1e3d142Eric Laurent                }
4244dca56b9432e2cc851d1a58920071fed2e1e3d142Eric Laurent
4245dca56b9432e2cc851d1a58920071fed2e1e3d142Eric Laurent                address = btDevice.getAddress();
4246dca56b9432e2cc851d1a58920071fed2e1e3d142Eric Laurent                BluetoothClass btClass = btDevice.getBluetoothClass();
4247dca56b9432e2cc851d1a58920071fed2e1e3d142Eric Laurent                if (btClass != null) {
4248dca56b9432e2cc851d1a58920071fed2e1e3d142Eric Laurent                    switch (btClass.getDeviceClass()) {
4249dca56b9432e2cc851d1a58920071fed2e1e3d142Eric Laurent                    case BluetoothClass.Device.AUDIO_VIDEO_WEARABLE_HEADSET:
4250dca56b9432e2cc851d1a58920071fed2e1e3d142Eric Laurent                    case BluetoothClass.Device.AUDIO_VIDEO_HANDSFREE:
4251ae4506e9b5fc3e0c6d9862fbc05b9af7d6742a6eEric Laurent                        outDevice = AudioSystem.DEVICE_OUT_BLUETOOTH_SCO_HEADSET;
4252dca56b9432e2cc851d1a58920071fed2e1e3d142Eric Laurent                        break;
4253dca56b9432e2cc851d1a58920071fed2e1e3d142Eric Laurent                    case BluetoothClass.Device.AUDIO_VIDEO_CAR_AUDIO:
4254ae4506e9b5fc3e0c6d9862fbc05b9af7d6742a6eEric Laurent                        outDevice = AudioSystem.DEVICE_OUT_BLUETOOTH_SCO_CARKIT;
4255dca56b9432e2cc851d1a58920071fed2e1e3d142Eric Laurent                        break;
4256d5603c126acdd94d9f7400bb1d04188020a425b4Eric Laurent                    }
4257d5603c126acdd94d9f7400bb1d04188020a425b4Eric Laurent                }
4258d5603c126acdd94d9f7400bb1d04188020a425b4Eric Laurent
4259dca56b9432e2cc851d1a58920071fed2e1e3d142Eric Laurent                if (!BluetoothAdapter.checkBluetoothAddress(address)) {
4260dca56b9432e2cc851d1a58920071fed2e1e3d142Eric Laurent                    address = "";
4261dca56b9432e2cc851d1a58920071fed2e1e3d142Eric Laurent                }
4262d5603c126acdd94d9f7400bb1d04188020a425b4Eric Laurent
426359f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent                boolean connected = (state == BluetoothProfile.STATE_CONNECTED);
4264ae4506e9b5fc3e0c6d9862fbc05b9af7d6742a6eEric Laurent                boolean success = handleDeviceConnection(connected, outDevice, address) &&
4265ae4506e9b5fc3e0c6d9862fbc05b9af7d6742a6eEric Laurent                                      handleDeviceConnection(connected, inDevice, address);
4266ae4506e9b5fc3e0c6d9862fbc05b9af7d6742a6eEric Laurent                if (success) {
42676bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                    synchronized (mScoClients) {
426859f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent                        if (connected) {
426959f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent                            mBluetoothHeadsetDevice = btDevice;
427059f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent                        } else {
42716bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                            mBluetoothHeadsetDevice = null;
42726bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                            resetBluetoothSco();
42736bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                        }
427462ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent                    }
4275a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent                }
4276df3614693dd4fe52a116dcd28bd74eae80818a4fPaul McLean            } else if (action.equals(Intent.ACTION_USB_AUDIO_ACCESSORY_PLUG)) {
4277df3614693dd4fe52a116dcd28bd74eae80818a4fPaul McLean                state = intent.getIntExtra("state", 0);
4278df3614693dd4fe52a116dcd28bd74eae80818a4fPaul McLean
4279df3614693dd4fe52a116dcd28bd74eae80818a4fPaul McLean                int alsaCard = intent.getIntExtra("card", -1);
4280df3614693dd4fe52a116dcd28bd74eae80818a4fPaul McLean                int alsaDevice = intent.getIntExtra("device", -1);
4281df3614693dd4fe52a116dcd28bd74eae80818a4fPaul McLean
4282df3614693dd4fe52a116dcd28bd74eae80818a4fPaul McLean                String params = (alsaCard == -1 && alsaDevice == -1 ? ""
4283df3614693dd4fe52a116dcd28bd74eae80818a4fPaul McLean                                    : "card=" + alsaCard + ";device=" + alsaDevice);
4284df3614693dd4fe52a116dcd28bd74eae80818a4fPaul McLean
4285df3614693dd4fe52a116dcd28bd74eae80818a4fPaul McLean                // Playback Device
4286ae4506e9b5fc3e0c6d9862fbc05b9af7d6742a6eEric Laurent                outDevice = AudioSystem.DEVICE_OUT_USB_ACCESSORY;
4287ae4506e9b5fc3e0c6d9862fbc05b9af7d6742a6eEric Laurent                setWiredDeviceConnectionState(outDevice, state, params);
4288df3614693dd4fe52a116dcd28bd74eae80818a4fPaul McLean            } else if (action.equals(Intent.ACTION_USB_AUDIO_DEVICE_PLUG)) {
428959f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent                state = intent.getIntExtra("state", 0);
4290c837a451946b64d70ed7c642fbde03c182c28b6fPaul McLean
429159f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent                int alsaCard = intent.getIntExtra("card", -1);
429259f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent                int alsaDevice = intent.getIntExtra("device", -1);
4293c837a451946b64d70ed7c642fbde03c182c28b6fPaul McLean                boolean hasPlayback = intent.getBooleanExtra("hasPlayback", false);
4294c837a451946b64d70ed7c642fbde03c182c28b6fPaul McLean                boolean hasCapture = intent.getBooleanExtra("hasCapture", false);
4295c837a451946b64d70ed7c642fbde03c182c28b6fPaul McLean                boolean hasMIDI = intent.getBooleanExtra("hasMIDI", false);
4296c837a451946b64d70ed7c642fbde03c182c28b6fPaul McLean
42979841818b9a0280abf59343c9e00a2976dbc084faMike Lockwood                String params = (alsaCard == -1 && alsaDevice == -1 ? ""
42989841818b9a0280abf59343c9e00a2976dbc084faMike Lockwood                                    : "card=" + alsaCard + ";device=" + alsaDevice);
4299c837a451946b64d70ed7c642fbde03c182c28b6fPaul McLean
4300c837a451946b64d70ed7c642fbde03c182c28b6fPaul McLean                // Playback Device
4301df3614693dd4fe52a116dcd28bd74eae80818a4fPaul McLean                if (hasPlayback) {
4302ae4506e9b5fc3e0c6d9862fbc05b9af7d6742a6eEric Laurent                    outDevice = AudioSystem.DEVICE_OUT_USB_DEVICE;
4303ae4506e9b5fc3e0c6d9862fbc05b9af7d6742a6eEric Laurent                    setWiredDeviceConnectionState(outDevice, state, params);
4304df3614693dd4fe52a116dcd28bd74eae80818a4fPaul McLean                }
4305c837a451946b64d70ed7c642fbde03c182c28b6fPaul McLean
4306c837a451946b64d70ed7c642fbde03c182c28b6fPaul McLean                // Capture Device
4307df3614693dd4fe52a116dcd28bd74eae80818a4fPaul McLean                if (hasCapture) {
4308ae4506e9b5fc3e0c6d9862fbc05b9af7d6742a6eEric Laurent                    inDevice = AudioSystem.DEVICE_IN_USB_DEVICE;
4309ae4506e9b5fc3e0c6d9862fbc05b9af7d6742a6eEric Laurent                    setWiredDeviceConnectionState(inDevice, state, params);
4310df3614693dd4fe52a116dcd28bd74eae80818a4fPaul McLean                }
4311df3614693dd4fe52a116dcd28bd74eae80818a4fPaul McLean            } else if (action.equals(BluetoothHeadset.ACTION_AUDIO_STATE_CHANGED)) {
431262ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent                boolean broadcast = false;
431359f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent                int scoAudioState = AudioManager.SCO_AUDIO_STATE_ERROR;
43143def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                synchronized (mScoClients) {
431562ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent                    int btState = intent.getIntExtra(BluetoothProfile.EXTRA_STATE, -1);
4316dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                    // broadcast intent if the connection was initated by AudioService
4317dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                    if (!mScoClients.isEmpty() &&
4318dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                            (mScoAudioState == SCO_STATE_ACTIVE_INTERNAL ||
4319dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                             mScoAudioState == SCO_STATE_ACTIVATE_REQ ||
4320dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                             mScoAudioState == SCO_STATE_DEACTIVATE_REQ)) {
432162ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent                        broadcast = true;
432262ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent                    }
432362ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent                    switch (btState) {
432462ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent                    case BluetoothHeadset.STATE_AUDIO_CONNECTED:
432559f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent                        scoAudioState = AudioManager.SCO_AUDIO_STATE_CONNECTED;
4326dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                        if (mScoAudioState != SCO_STATE_ACTIVE_INTERNAL &&
4327dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                            mScoAudioState != SCO_STATE_DEACTIVATE_REQ &&
4328dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                            mScoAudioState != SCO_STATE_DEACTIVATE_EXT_REQ) {
432962ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent                            mScoAudioState = SCO_STATE_ACTIVE_EXTERNAL;
43303def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                        }
433162ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent                        break;
433262ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent                    case BluetoothHeadset.STATE_AUDIO_DISCONNECTED:
433359f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent                        scoAudioState = AudioManager.SCO_AUDIO_STATE_DISCONNECTED;
433462ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent                        mScoAudioState = SCO_STATE_INACTIVE;
4335d7454be47f4111c0478a502353e11dea401378bdEric Laurent                        clearAllScoClients(0, false);
433662ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent                        break;
433762ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent                    case BluetoothHeadset.STATE_AUDIO_CONNECTING:
4338dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                        if (mScoAudioState != SCO_STATE_ACTIVE_INTERNAL &&
4339dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                            mScoAudioState != SCO_STATE_DEACTIVATE_REQ &&
4340dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                            mScoAudioState != SCO_STATE_DEACTIVATE_EXT_REQ) {
434162ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent                            mScoAudioState = SCO_STATE_ACTIVE_EXTERNAL;
43423def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                        }
434362ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent                    default:
434462ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent                        // do not broadcast CONNECTING or invalid state
434562ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent                        broadcast = false;
434662ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent                        break;
43473def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                    }
43483def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                }
434962ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent                if (broadcast) {
435059f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent                    broadcastScoConnectionState(scoAudioState);
4351dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                    //FIXME: this is to maintain compatibility with deprecated intent
4352dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                    // AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED. Remove when appropriate.
435362ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent                    Intent newIntent = new Intent(AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED);
435459f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent                    newIntent.putExtra(AudioManager.EXTRA_SCO_AUDIO_STATE, scoAudioState);
43555ac72a29593ab9a20337a2225df52bdf4754be02Dianne Hackborn                    sendStickyBroadcastToAll(newIntent);
435662ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent                }
4357950e8cb40a6d826af4cc2eef9d3908c1b70486e6Eric Laurent            } else if (action.equals(Intent.ACTION_SCREEN_ON)) {
4358950e8cb40a6d826af4cc2eef9d3908c1b70486e6Eric Laurent                AudioSystem.setParameters("screen_state=on");
4359950e8cb40a6d826af4cc2eef9d3908c1b70486e6Eric Laurent            } else if (action.equals(Intent.ACTION_SCREEN_OFF)) {
4360950e8cb40a6d826af4cc2eef9d3908c1b70486e6Eric Laurent                AudioSystem.setParameters("screen_state=off");
4361961cae92540763226648813d111c5b5c3b0f1597Dianne Hackborn            } else if (action.equals(Intent.ACTION_CONFIGURATION_CHANGED)) {
4362f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi                handleConfigurationChanged(context);
4363bc0fab1fc2db832ef86d8a33466ec4d68b103ca0Eric Laurent            } else if (action.equals(Intent.ACTION_USER_SWITCHED)) {
4364f4a8eb22112c534f436357b50f231778c5c15c25Jean-Michel Trivi                // attempt to stop music playback for background user
43655bfaeaef3fc348d66f48b86be08655e91dff910aEric Laurent                sendMsg(mAudioHandler,
43665bfaeaef3fc348d66f48b86be08655e91dff910aEric Laurent                        MSG_BROADCAST_AUDIO_BECOMING_NOISY,
43675bfaeaef3fc348d66f48b86be08655e91dff910aEric Laurent                        SENDMSG_REPLACE,
43685bfaeaef3fc348d66f48b86be08655e91dff910aEric Laurent                        0,
43695bfaeaef3fc348d66f48b86be08655e91dff910aEric Laurent                        0,
43705bfaeaef3fc348d66f48b86be08655e91dff910aEric Laurent                        null,
43715bfaeaef3fc348d66f48b86be08655e91dff910aEric Laurent                        0);
4372f4a8eb22112c534f436357b50f231778c5c15c25Jean-Michel Trivi                // the current audio focus owner is no longer valid
4373fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                mMediaFocusControl.discardAudioFocusOwner();
4374f4a8eb22112c534f436357b50f231778c5c15c25Jean-Michel Trivi
43755bfaeaef3fc348d66f48b86be08655e91dff910aEric Laurent                // load volume settings for new user
4376bc0fab1fc2db832ef86d8a33466ec4d68b103ca0Eric Laurent                readAudioSettings(true /*userSwitch*/);
4377bc0fab1fc2db832ef86d8a33466ec4d68b103ca0Eric Laurent                // preserve STREAM_MUSIC volume from one user to the next.
4378bc0fab1fc2db832ef86d8a33466ec4d68b103ca0Eric Laurent                sendMsg(mAudioHandler,
4379bc0fab1fc2db832ef86d8a33466ec4d68b103ca0Eric Laurent                        MSG_SET_ALL_VOLUMES,
4380bc0fab1fc2db832ef86d8a33466ec4d68b103ca0Eric Laurent                        SENDMSG_QUEUE,
4381bc0fab1fc2db832ef86d8a33466ec4d68b103ca0Eric Laurent                        0,
4382bc0fab1fc2db832ef86d8a33466ec4d68b103ca0Eric Laurent                        0,
4383bc0fab1fc2db832ef86d8a33466ec4d68b103ca0Eric Laurent                        mStreamStates[AudioSystem.STREAM_MUSIC], 0);
4384a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent            }
4385a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent        }
4386c837a451946b64d70ed7c642fbde03c182c28b6fPaul McLean    } // end class AudioServiceBroadcastReceiver
4387d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi
4388d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi    //==========================================================================================
4389fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    // RemoteControlDisplay / RemoteControlClient / Remote info
4390d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi    //==========================================================================================
4391f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi    public boolean registerRemoteController(IRemoteControlDisplay rcd, int w, int h,
4392f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi            ComponentName listenerComp) {
4393f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi        return mMediaFocusControl.registerRemoteController(rcd, w, h, listenerComp);
4394f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi    }
4395f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi
43967ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi    public boolean registerRemoteControlDisplay(IRemoteControlDisplay rcd, int w, int h) {
4397f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi        return mMediaFocusControl.registerRemoteControlDisplay(rcd, w, h);
4398e5e1e870fdb35f5291790e6d178bde7126f6fe35Jean-Michel Trivi    }
4399e5e1e870fdb35f5291790e6d178bde7126f6fe35Jean-Michel Trivi
4400fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    public void unregisterRemoteControlDisplay(IRemoteControlDisplay rcd) {
4401fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        mMediaFocusControl.unregisterRemoteControlDisplay(rcd);
4402d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi    }
4403d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi
4404fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    public void remoteControlDisplayUsesBitmapSize(IRemoteControlDisplay rcd, int w, int h) {
4405fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        mMediaFocusControl.remoteControlDisplayUsesBitmapSize(rcd, w, h);
4406d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi    }
4407d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi
4408fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    public void remoteControlDisplayWantsPlaybackPositionSync(IRemoteControlDisplay rcd,
4409fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            boolean wantsSync) {
4410fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        mMediaFocusControl.remoteControlDisplayWantsPlaybackPositionSync(rcd, wantsSync);
4411d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi    }
4412d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi
44133346a802087f621c6441bc512dfcc17b07143fc6John Spurlock    @Override
4414fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    public void setRemoteStreamVolume(int index) {
44153346a802087f621c6441bc512dfcc17b07143fc6John Spurlock        enforceSelfOrSystemUI("set the remote stream volume");
4416fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        mMediaFocusControl.setRemoteStreamVolume(index);
4417d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi    }
4418d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi
4419fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    //==========================================================================================
4420fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    // Audio Focus
4421fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    //==========================================================================================
4422fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    public int requestAudioFocus(int mainStreamType, int durationHint, IBinder cb,
4423fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            IAudioFocusDispatcher fd, String clientId, String callingPackageName) {
4424fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        return mMediaFocusControl.requestAudioFocus(mainStreamType, durationHint, cb, fd,
4425fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                clientId, callingPackageName);
44264294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi    }
44274294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi
4428fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    public int abandonAudioFocus(IAudioFocusDispatcher fd, String clientId) {
4429fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        return mMediaFocusControl.abandonAudioFocus(fd, clientId);
4430c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi    }
4431c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi
4432fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    public void unregisterAudioFocusClient(String clientId) {
4433fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        mMediaFocusControl.unregisterAudioFocusClient(clientId);
44343114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    }
44353114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi
44362380566debfc57eb1cc07db1306ccee23b84ddd4Jean-Michel Trivi    public int getCurrentAudioFocus() {
44372380566debfc57eb1cc07db1306ccee23b84ddd4Jean-Michel Trivi        return mMediaFocusControl.getCurrentAudioFocus();
44382380566debfc57eb1cc07db1306ccee23b84ddd4Jean-Michel Trivi    }
44392380566debfc57eb1cc07db1306ccee23b84ddd4Jean-Michel Trivi
4440f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi    //==========================================================================================
4441f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi    // Device orientation
4442f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi    //==========================================================================================
4443f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi    /**
4444bb6f8711a7f804d39c45218db2d6339940cc5d35Jean-Michel Trivi     * Handles device configuration changes that may map to a change in the orientation
4445bb6f8711a7f804d39c45218db2d6339940cc5d35Jean-Michel Trivi     * or orientation.
4446bb6f8711a7f804d39c45218db2d6339940cc5d35Jean-Michel Trivi     * Monitoring orientation and rotation is optional, and is defined by the definition and value
4447bb6f8711a7f804d39c45218db2d6339940cc5d35Jean-Michel Trivi     * of the "ro.audio.monitorOrientation" and "ro.audio.monitorRotation" system properties.
4448f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi     */
4449f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi    private void handleConfigurationChanged(Context context) {
4450f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi        try {
4451f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi            // reading new orientation "safely" (i.e. under try catch) in case anything
4452f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi            // goes wrong when obtaining resources and configuration
4453d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent            Configuration config = context.getResources().getConfiguration();
4454bb6f8711a7f804d39c45218db2d6339940cc5d35Jean-Michel Trivi            // TODO merge rotation and orientation
4455d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent            if (mMonitorOrientation) {
4456d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent                int newOrientation = config.orientation;
4457d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent                if (newOrientation != mDeviceOrientation) {
4458d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent                    mDeviceOrientation = newOrientation;
4459d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent                    setOrientationForAudioSystem();
4460d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent                }
4461f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi            }
4462bb6f8711a7f804d39c45218db2d6339940cc5d35Jean-Michel Trivi            if (mMonitorRotation) {
4463bb6f8711a7f804d39c45218db2d6339940cc5d35Jean-Michel Trivi                int newRotation = ((WindowManager) context.getSystemService(
4464bb6f8711a7f804d39c45218db2d6339940cc5d35Jean-Michel Trivi                        Context.WINDOW_SERVICE)).getDefaultDisplay().getRotation();
4465bb6f8711a7f804d39c45218db2d6339940cc5d35Jean-Michel Trivi                if (newRotation != mDeviceRotation) {
4466bb6f8711a7f804d39c45218db2d6339940cc5d35Jean-Michel Trivi                    mDeviceRotation = newRotation;
4467bb6f8711a7f804d39c45218db2d6339940cc5d35Jean-Michel Trivi                    setRotationForAudioSystem();
4468bb6f8711a7f804d39c45218db2d6339940cc5d35Jean-Michel Trivi                }
4469bb6f8711a7f804d39c45218db2d6339940cc5d35Jean-Michel Trivi            }
4470d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent            sendMsg(mAudioHandler,
4471d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent                    MSG_CONFIGURE_SAFE_MEDIA_VOLUME,
4472d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent                    SENDMSG_REPLACE,
4473d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent                    0,
4474d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent                    0,
4475d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent                    null,
4476d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent                    0);
4477dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent
4478dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent            boolean cameraSoundForced = mContext.getResources().getBoolean(
4479dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent                    com.android.internal.R.bool.config_camera_sound_forced);
4480dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent            synchronized (mSettingsLock) {
4481dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent                synchronized (mCameraSoundForced) {
4482dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent                    if (cameraSoundForced != mCameraSoundForced) {
4483dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent                        mCameraSoundForced = cameraSoundForced;
4484dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent
4485dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent                        VolumeStreamState s = mStreamStates[AudioSystem.STREAM_SYSTEM_ENFORCED];
4486dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent                        if (cameraSoundForced) {
4487dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent                            s.setAllIndexesToMax();
4488dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent                            mRingerModeAffectedStreams &=
4489dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent                                    ~(1 << AudioSystem.STREAM_SYSTEM_ENFORCED);
4490dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent                        } else {
449142b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                            s.setAllIndexes(mStreamStates[AudioSystem.STREAM_SYSTEM]);
4492dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent                            mRingerModeAffectedStreams |=
4493dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent                                    (1 << AudioSystem.STREAM_SYSTEM_ENFORCED);
4494dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent                        }
4495dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent                        // take new state into account for streams muted by ringer mode
4496dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent                        setRingerModeInt(getRingerMode(), false);
4497dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent
4498dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent                        sendMsg(mAudioHandler,
4499dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent                                MSG_SET_FORCE_USE,
4500dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent                                SENDMSG_QUEUE,
4501dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent                                AudioSystem.FOR_SYSTEM,
4502dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent                                cameraSoundForced ?
4503dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent                                        AudioSystem.FORCE_SYSTEM_ENFORCED : AudioSystem.FORCE_NONE,
4504dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent                                null,
4505dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent                                0);
4506dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent
4507dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent                        sendMsg(mAudioHandler,
4508dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent                                MSG_SET_ALL_VOLUMES,
4509dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent                                SENDMSG_QUEUE,
4510dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent                                0,
4511dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent                                0,
4512dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent                                mStreamStates[AudioSystem.STREAM_SYSTEM_ENFORCED], 0);
4513dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent                    }
4514dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent                }
4515dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent            }
45163346a802087f621c6441bc512dfcc17b07143fc6John Spurlock            mVolumeController.setLayoutDirection(config.getLayoutDirection());
4517f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi        } catch (Exception e) {
4518bb6f8711a7f804d39c45218db2d6339940cc5d35Jean-Michel Trivi            Log.e(TAG, "Error handling configuration change: ", e);
4519f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi        }
4520f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi    }
4521f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi
4522f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi    private void setOrientationForAudioSystem() {
4523f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi        switch (mDeviceOrientation) {
4524f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi            case Configuration.ORIENTATION_LANDSCAPE:
4525f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi                //Log.i(TAG, "orientation is landscape");
4526f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi                AudioSystem.setParameters("orientation=landscape");
4527f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi                break;
4528f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi            case Configuration.ORIENTATION_PORTRAIT:
4529f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi                //Log.i(TAG, "orientation is portrait");
4530f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi                AudioSystem.setParameters("orientation=portrait");
4531f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi                break;
4532f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi            case Configuration.ORIENTATION_SQUARE:
4533f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi                //Log.i(TAG, "orientation is square");
4534f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi                AudioSystem.setParameters("orientation=square");
4535f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi                break;
4536f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi            case Configuration.ORIENTATION_UNDEFINED:
4537f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi                //Log.i(TAG, "orientation is undefined");
4538f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi                AudioSystem.setParameters("orientation=undefined");
4539f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi                break;
4540f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi            default:
4541f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi                Log.e(TAG, "Unknown orientation");
4542f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi        }
4543f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi    }
4544f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi
4545bb6f8711a7f804d39c45218db2d6339940cc5d35Jean-Michel Trivi    private void setRotationForAudioSystem() {
4546bb6f8711a7f804d39c45218db2d6339940cc5d35Jean-Michel Trivi        switch (mDeviceRotation) {
4547bb6f8711a7f804d39c45218db2d6339940cc5d35Jean-Michel Trivi            case Surface.ROTATION_0:
4548bb6f8711a7f804d39c45218db2d6339940cc5d35Jean-Michel Trivi                AudioSystem.setParameters("rotation=0");
4549bb6f8711a7f804d39c45218db2d6339940cc5d35Jean-Michel Trivi                break;
4550bb6f8711a7f804d39c45218db2d6339940cc5d35Jean-Michel Trivi            case Surface.ROTATION_90:
4551bb6f8711a7f804d39c45218db2d6339940cc5d35Jean-Michel Trivi                AudioSystem.setParameters("rotation=90");
4552bb6f8711a7f804d39c45218db2d6339940cc5d35Jean-Michel Trivi                break;
4553bb6f8711a7f804d39c45218db2d6339940cc5d35Jean-Michel Trivi            case Surface.ROTATION_180:
4554bb6f8711a7f804d39c45218db2d6339940cc5d35Jean-Michel Trivi                AudioSystem.setParameters("rotation=180");
4555bb6f8711a7f804d39c45218db2d6339940cc5d35Jean-Michel Trivi                break;
4556bb6f8711a7f804d39c45218db2d6339940cc5d35Jean-Michel Trivi            case Surface.ROTATION_270:
4557bb6f8711a7f804d39c45218db2d6339940cc5d35Jean-Michel Trivi                AudioSystem.setParameters("rotation=270");
4558bb6f8711a7f804d39c45218db2d6339940cc5d35Jean-Michel Trivi                break;
4559bb6f8711a7f804d39c45218db2d6339940cc5d35Jean-Michel Trivi            default:
4560bb6f8711a7f804d39c45218db2d6339940cc5d35Jean-Michel Trivi                Log.e(TAG, "Unknown device rotation");
4561bb6f8711a7f804d39c45218db2d6339940cc5d35Jean-Michel Trivi        }
4562bb6f8711a7f804d39c45218db2d6339940cc5d35Jean-Michel Trivi    }
4563bb6f8711a7f804d39c45218db2d6339940cc5d35Jean-Michel Trivi
4564f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi
45657847211fb4699bf6018e29d214a918ed6657319bEric Laurent    // Handles request to override default use of A2DP for media.
45667847211fb4699bf6018e29d214a918ed6657319bEric Laurent    public void setBluetoothA2dpOnInt(boolean on) {
45677847211fb4699bf6018e29d214a918ed6657319bEric Laurent        synchronized (mBluetoothA2dpEnabledLock) {
45687847211fb4699bf6018e29d214a918ed6657319bEric Laurent            mBluetoothA2dpEnabled = on;
4569c390bed06b4a572e273ead1254da9a932e04dce3Eric Laurent            mAudioHandler.removeMessages(MSG_SET_FORCE_BT_A2DP_USE);
4570c390bed06b4a572e273ead1254da9a932e04dce3Eric Laurent            AudioSystem.setForceUse(AudioSystem.FOR_MEDIA,
4571c390bed06b4a572e273ead1254da9a932e04dce3Eric Laurent                    mBluetoothA2dpEnabled ? AudioSystem.FORCE_NONE : AudioSystem.FORCE_NO_BT_A2DP);
45727847211fb4699bf6018e29d214a918ed6657319bEric Laurent        }
45737847211fb4699bf6018e29d214a918ed6657319bEric Laurent    }
45747847211fb4699bf6018e29d214a918ed6657319bEric Laurent
4575d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi    @Override
4576098d580cc2bb6c0891c756a4e5230c6c6b0d2376Jeff Sharkey    public void setRingtonePlayer(IRingtonePlayer player) {
4577098d580cc2bb6c0891c756a4e5230c6c6b0d2376Jeff Sharkey        mContext.enforceCallingOrSelfPermission(REMOTE_AUDIO_PLAYBACK, null);
4578098d580cc2bb6c0891c756a4e5230c6c6b0d2376Jeff Sharkey        mRingtonePlayer = player;
4579098d580cc2bb6c0891c756a4e5230c6c6b0d2376Jeff Sharkey    }
4580098d580cc2bb6c0891c756a4e5230c6c6b0d2376Jeff Sharkey
4581098d580cc2bb6c0891c756a4e5230c6c6b0d2376Jeff Sharkey    @Override
4582098d580cc2bb6c0891c756a4e5230c6c6b0d2376Jeff Sharkey    public IRingtonePlayer getRingtonePlayer() {
4583098d580cc2bb6c0891c756a4e5230c6c6b0d2376Jeff Sharkey        return mRingtonePlayer;
4584098d580cc2bb6c0891c756a4e5230c6c6b0d2376Jeff Sharkey    }
4585098d580cc2bb6c0891c756a4e5230c6c6b0d2376Jeff Sharkey
4586098d580cc2bb6c0891c756a4e5230c6c6b0d2376Jeff Sharkey    @Override
4587632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn    public AudioRoutesInfo startWatchingRoutes(IAudioRoutesObserver observer) {
4588632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn        synchronized (mCurAudioRoutes) {
4589632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn            AudioRoutesInfo routes = new AudioRoutesInfo(mCurAudioRoutes);
4590632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn            mRoutesObservers.register(observer);
4591632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn            return routes;
4592632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn        }
4593632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn    }
4594632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn
4595c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent
4596c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent    //==========================================================================================
4597c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent    // Safe media volume management.
4598c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent    // MUSIC stream volume level is limited when headphones are connected according to safety
4599c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent    // regulation. When the user attempts to raise the volume above the limit, a warning is
4600c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent    // displayed and the user has to acknowlegde before the volume is actually changed.
4601c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent    // The volume index corresponding to the limit is stored in config_safe_media_volume_index
4602c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent    // property. Platforms with a different limit must set this property accordingly in their
4603c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent    // overlay.
4604c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent    //==========================================================================================
4605c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent
4606d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent    // mSafeMediaVolumeState indicates whether the media volume is limited over headphones.
4607d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent    // It is SAFE_MEDIA_VOLUME_NOT_CONFIGURED at boot time until a network service is connected
4608d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent    // or the configure time is elapsed. It is then set to SAFE_MEDIA_VOLUME_ACTIVE or
4609d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent    // SAFE_MEDIA_VOLUME_DISABLED according to country option. If not SAFE_MEDIA_VOLUME_DISABLED, it
4610d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent    // can be set to SAFE_MEDIA_VOLUME_INACTIVE by calling AudioService.disableSafeMediaVolume()
4611d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent    // (when user opts out).
4612d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent    private final int SAFE_MEDIA_VOLUME_NOT_CONFIGURED = 0;
4613d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent    private final int SAFE_MEDIA_VOLUME_DISABLED = 1;
4614d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent    private final int SAFE_MEDIA_VOLUME_INACTIVE = 2;
4615d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent    private final int SAFE_MEDIA_VOLUME_ACTIVE = 3;
4616d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent    private Integer mSafeMediaVolumeState;
4617d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent
4618d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent    private int mMcc = 0;
4619c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent    // mSafeMediaVolumeIndex is the cached value of config_safe_media_volume_index property
4620d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent    private int mSafeMediaVolumeIndex;
4621c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent    // mSafeMediaVolumeDevices lists the devices for which safe media volume is enforced,
4622c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent    private final int mSafeMediaVolumeDevices = AudioSystem.DEVICE_OUT_WIRED_HEADSET |
4623c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent                                                AudioSystem.DEVICE_OUT_WIRED_HEADPHONE;
4624c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent    // mMusicActiveMs is the cumulative time of music activity since safe volume was disabled.
4625c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent    // When this time reaches UNSAFE_VOLUME_MUSIC_ACTIVE_MS_MAX, the safe media volume is re-enabled
4626c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent    // automatically. mMusicActiveMs is rounded to a multiple of MUSIC_ACTIVE_POLL_PERIOD_MS.
4627c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent    private int mMusicActiveMs;
4628c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent    private static final int UNSAFE_VOLUME_MUSIC_ACTIVE_MS_MAX = (20 * 3600 * 1000); // 20 hours
4629c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent    private static final int MUSIC_ACTIVE_POLL_PERIOD_MS = 60000;  // 1 minute polling interval
4630d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent    private static final int SAFE_VOLUME_CONFIGURE_TIMEOUT_MS = 30000;  // 30s after boot completed
4631c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent
4632c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent    private void setSafeMediaVolumeEnabled(boolean on) {
4633d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent        synchronized (mSafeMediaVolumeState) {
4634d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent            if ((mSafeMediaVolumeState != SAFE_MEDIA_VOLUME_NOT_CONFIGURED) &&
4635d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent                    (mSafeMediaVolumeState != SAFE_MEDIA_VOLUME_DISABLED)) {
4636d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent                if (on && (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_INACTIVE)) {
4637d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent                    mSafeMediaVolumeState = SAFE_MEDIA_VOLUME_ACTIVE;
4638d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent                    enforceSafeMediaVolume();
4639d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent                } else if (!on && (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_ACTIVE)) {
4640d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent                    mSafeMediaVolumeState = SAFE_MEDIA_VOLUME_INACTIVE;
4641d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent                    mMusicActiveMs = 0;
4642d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent                    sendMsg(mAudioHandler,
4643d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent                            MSG_CHECK_MUSIC_ACTIVE,
4644d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent                            SENDMSG_REPLACE,
4645d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent                            0,
4646d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent                            0,
4647d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent                            null,
4648d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent                            MUSIC_ACTIVE_POLL_PERIOD_MS);
4649d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent                }
4650c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent            }
4651c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent        }
4652c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent    }
4653c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent
4654c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent    private void enforceSafeMediaVolume() {
4655c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent        VolumeStreamState streamState = mStreamStates[AudioSystem.STREAM_MUSIC];
4656c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent        int devices = mSafeMediaVolumeDevices;
4657c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent        int i = 0;
4658c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent
4659c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent        while (devices != 0) {
4660c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent            int device = 1 << i++;
4661c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent            if ((device & devices) == 0) {
4662c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent                continue;
4663c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent            }
466442b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent            int index = streamState.getIndex(device);
4665c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent            if (index > mSafeMediaVolumeIndex) {
466642b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                streamState.setIndex(mSafeMediaVolumeIndex, device);
466742b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                sendMsg(mAudioHandler,
466842b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                        MSG_SET_DEVICE_VOLUME,
466942b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                        SENDMSG_QUEUE,
467042b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                        device,
467142b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                        0,
467242b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                        streamState,
467342b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                        0);
4674c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent            }
4675c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent            devices &= ~device;
4676c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent        }
4677c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent    }
4678c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent
4679c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent    private boolean checkSafeMediaVolume(int streamType, int index, int device) {
4680d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent        synchronized (mSafeMediaVolumeState) {
4681d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent            if ((mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_ACTIVE) &&
4682c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent                    (mStreamVolumeAlias[streamType] == AudioSystem.STREAM_MUSIC) &&
4683c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent                    ((device & mSafeMediaVolumeDevices) != 0) &&
4684c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent                    (index > mSafeMediaVolumeIndex)) {
4685c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent                return false;
4686c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent            }
4687c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent            return true;
4688c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent        }
4689c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent    }
4690c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent
46913346a802087f621c6441bc512dfcc17b07143fc6John Spurlock    @Override
4692c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent    public void disableSafeMediaVolume() {
46933346a802087f621c6441bc512dfcc17b07143fc6John Spurlock        enforceSelfOrSystemUI("disable the safe media volume");
4694d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent        synchronized (mSafeMediaVolumeState) {
4695c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent            setSafeMediaVolumeEnabled(false);
4696fde16d5879ea88a971004c984093409468b6139cEric Laurent            if (mPendingVolumeCommand != null) {
4697fde16d5879ea88a971004c984093409468b6139cEric Laurent                onSetStreamVolume(mPendingVolumeCommand.mStreamType,
4698fde16d5879ea88a971004c984093409468b6139cEric Laurent                                  mPendingVolumeCommand.mIndex,
4699fde16d5879ea88a971004c984093409468b6139cEric Laurent                                  mPendingVolumeCommand.mFlags,
4700fde16d5879ea88a971004c984093409468b6139cEric Laurent                                  mPendingVolumeCommand.mDevice);
4701fde16d5879ea88a971004c984093409468b6139cEric Laurent                mPendingVolumeCommand = null;
4702fde16d5879ea88a971004c984093409468b6139cEric Laurent            }
4703c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent        }
4704c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent    }
4705c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent
4706c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent
4707dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent    //==========================================================================================
4708dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent    // Camera shutter sound policy.
4709dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent    // config_camera_sound_forced configuration option in config.xml defines if the camera shutter
4710dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent    // sound is forced (sound even if the device is in silent mode) or not. This option is false by
4711dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent    // default and can be overridden by country specific overlay in values-mccXXX/config.xml.
4712dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent    //==========================================================================================
4713dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent
4714dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent    // cached value of com.android.internal.R.bool.config_camera_sound_forced
4715dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent    private Boolean mCameraSoundForced;
4716dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent
4717dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent    // called by android.hardware.Camera to populate CameraInfo.canDisableShutterSound
4718dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent    public boolean isCameraSoundForced() {
4719dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent        synchronized (mCameraSoundForced) {
4720dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent            return mCameraSoundForced;
4721dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent        }
4722dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent    }
4723dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent
4724dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent    private static final String[] RINGER_MODE_NAMES = new String[] {
4725dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent            "SILENT",
4726dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent            "VIBRATE",
4727dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent            "NORMAL"
4728dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent    };
4729dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent
4730dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent    private void dumpRingerMode(PrintWriter pw) {
4731dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent        pw.println("\nRinger mode: ");
4732dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent        pw.println("- mode: "+RINGER_MODE_NAMES[mRingerMode]);
4733dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent        pw.print("- ringer mode affected streams = 0x");
4734dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent        pw.println(Integer.toHexString(mRingerModeAffectedStreams));
4735dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent        pw.print("- ringer mode muted streams = 0x");
4736dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent        pw.println(Integer.toHexString(mRingerModeMutedStreams));
4737dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent    }
4738dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent
4739632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn    @Override
4740d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi    protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
4741eb4cc492c93ab9635dde78b958a834120412e72aJeff Sharkey        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DUMP, TAG);
4742eb4cc492c93ab9635dde78b958a834120412e72aJeff Sharkey
4743fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        mMediaFocusControl.dump(pw);
4744bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent        dumpStreamStates(pw);
4745dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent        dumpRingerMode(pw);
4746632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn        pw.println("\nAudio routes:");
4747632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn        pw.print("  mMainType=0x"); pw.println(Integer.toHexString(mCurAudioRoutes.mMainType));
4748632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn        pw.print("  mBluetoothName="); pw.println(mCurAudioRoutes.mBluetoothName);
47493346a802087f621c6441bc512dfcc17b07143fc6John Spurlock        pw.print("  mVolumeController="); pw.println(mVolumeController);
4750d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi    }
4751fd116ad1ab02f6060a0b2201f018317fa32e28b4Glenn Kasten
4752fd116ad1ab02f6060a0b2201f018317fa32e28b4Glenn Kasten    // Inform AudioFlinger of our device's low RAM attribute
4753fd116ad1ab02f6060a0b2201f018317fa32e28b4Glenn Kasten    private static void readAndSetLowRamDevice()
4754fd116ad1ab02f6060a0b2201f018317fa32e28b4Glenn Kasten    {
4755fd116ad1ab02f6060a0b2201f018317fa32e28b4Glenn Kasten        int status = AudioSystem.setLowRamDevice(ActivityManager.isLowRamDeviceStatic());
4756fd116ad1ab02f6060a0b2201f018317fa32e28b4Glenn Kasten        if (status != 0) {
4757fd116ad1ab02f6060a0b2201f018317fa32e28b4Glenn Kasten            Log.w(TAG, "AudioFlinger informed of device's low RAM attribute; status " + status);
4758fd116ad1ab02f6060a0b2201f018317fa32e28b4Glenn Kasten        }
4759fd116ad1ab02f6060a0b2201f018317fa32e28b4Glenn Kasten    }
47603346a802087f621c6441bc512dfcc17b07143fc6John Spurlock
47613346a802087f621c6441bc512dfcc17b07143fc6John Spurlock    private void enforceSelfOrSystemUI(String action) {
47623346a802087f621c6441bc512dfcc17b07143fc6John Spurlock        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.STATUS_BAR_SERVICE,
47633346a802087f621c6441bc512dfcc17b07143fc6John Spurlock                "Only SystemUI can " + action);
47643346a802087f621c6441bc512dfcc17b07143fc6John Spurlock    }
47653346a802087f621c6441bc512dfcc17b07143fc6John Spurlock
47663346a802087f621c6441bc512dfcc17b07143fc6John Spurlock    @Override
47673346a802087f621c6441bc512dfcc17b07143fc6John Spurlock    public void setVolumeController(final IVolumeController controller) {
47683346a802087f621c6441bc512dfcc17b07143fc6John Spurlock        enforceSelfOrSystemUI("set the volume controller");
47693346a802087f621c6441bc512dfcc17b07143fc6John Spurlock
47703346a802087f621c6441bc512dfcc17b07143fc6John Spurlock        // return early if things are not actually changing
47713346a802087f621c6441bc512dfcc17b07143fc6John Spurlock        if (mVolumeController.isSameBinder(controller)) {
47723346a802087f621c6441bc512dfcc17b07143fc6John Spurlock            return;
47733346a802087f621c6441bc512dfcc17b07143fc6John Spurlock        }
47743346a802087f621c6441bc512dfcc17b07143fc6John Spurlock
47753346a802087f621c6441bc512dfcc17b07143fc6John Spurlock        // dismiss the old volume controller
47763346a802087f621c6441bc512dfcc17b07143fc6John Spurlock        mVolumeController.postDismiss();
47773346a802087f621c6441bc512dfcc17b07143fc6John Spurlock        if (controller != null) {
47783346a802087f621c6441bc512dfcc17b07143fc6John Spurlock            // we are about to register a new controller, listen for its death
47793346a802087f621c6441bc512dfcc17b07143fc6John Spurlock            try {
47803346a802087f621c6441bc512dfcc17b07143fc6John Spurlock                controller.asBinder().linkToDeath(new DeathRecipient() {
47813346a802087f621c6441bc512dfcc17b07143fc6John Spurlock                    @Override
47823346a802087f621c6441bc512dfcc17b07143fc6John Spurlock                    public void binderDied() {
47833346a802087f621c6441bc512dfcc17b07143fc6John Spurlock                        if (mVolumeController.isSameBinder(controller)) {
47843346a802087f621c6441bc512dfcc17b07143fc6John Spurlock                            Log.w(TAG, "Current remote volume controller died, unregistering");
47853346a802087f621c6441bc512dfcc17b07143fc6John Spurlock                            setVolumeController(null);
47863346a802087f621c6441bc512dfcc17b07143fc6John Spurlock                        }
47873346a802087f621c6441bc512dfcc17b07143fc6John Spurlock                    }
47883346a802087f621c6441bc512dfcc17b07143fc6John Spurlock                }, 0);
47893346a802087f621c6441bc512dfcc17b07143fc6John Spurlock            } catch (RemoteException e) {
47903346a802087f621c6441bc512dfcc17b07143fc6John Spurlock                // noop
47913346a802087f621c6441bc512dfcc17b07143fc6John Spurlock            }
47923346a802087f621c6441bc512dfcc17b07143fc6John Spurlock        }
47933346a802087f621c6441bc512dfcc17b07143fc6John Spurlock        mVolumeController.setController(controller);
47943346a802087f621c6441bc512dfcc17b07143fc6John Spurlock    }
4795d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik
4796d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik    public static class VolumeController {
4797d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik        private static final String TAG = "VolumeController";
4798d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik
4799d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik        private IVolumeController mController;
4800d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik
4801d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik        public void setController(IVolumeController controller) {
4802d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik            mController = controller;
4803d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik        }
4804d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik
4805d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik        public boolean isSameBinder(IVolumeController controller) {
4806d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik            return Objects.equals(asBinder(), binder(controller));
4807d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik        }
4808d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik
4809d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik        public IBinder asBinder() {
4810d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik            return binder(mController);
4811d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik        }
4812d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik
4813d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik        private static IBinder binder(IVolumeController controller) {
4814d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik            return controller == null ? null : controller.asBinder();
4815d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik        }
4816d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik
4817d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik        @Override
4818d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik        public String toString() {
4819d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik            return "VolumeController(" + asBinder() + ")";
4820d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik        }
4821d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik
4822d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik        public void postDisplaySafeVolumeWarning(int flags) {
4823d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik            if (mController == null)
4824d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik                return;
4825d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik            try {
4826d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik                mController.displaySafeVolumeWarning(flags);
4827d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik            } catch (RemoteException e) {
4828d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik                Log.w(TAG, "Error calling displaySafeVolumeWarning", e);
4829d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik            }
4830d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik        }
4831d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik
4832d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik        public void postVolumeChanged(int streamType, int flags) {
4833d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik            if (mController == null)
4834d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik                return;
4835d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik            try {
4836d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik                mController.volumeChanged(streamType, flags);
4837d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik            } catch (RemoteException e) {
4838d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik                Log.w(TAG, "Error calling volumeChanged", e);
4839d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik            }
4840d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik        }
4841d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik
4842d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik        public void postMasterVolumeChanged(int flags) {
4843d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik            if (mController == null)
4844d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik                return;
4845d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik            try {
4846d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik                mController.masterVolumeChanged(flags);
4847d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik            } catch (RemoteException e) {
4848d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik                Log.w(TAG, "Error calling masterVolumeChanged", e);
4849d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik            }
4850d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik        }
4851d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik
4852d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik        public void postMasterMuteChanged(int flags) {
4853d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik            if (mController == null)
4854d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik                return;
4855d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik            try {
4856d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik                mController.masterMuteChanged(flags);
4857d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik            } catch (RemoteException e) {
4858d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik                Log.w(TAG, "Error calling masterMuteChanged", e);
4859d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik            }
4860d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik        }
4861d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik
4862d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik        public void setLayoutDirection(int layoutDirection) {
4863d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik            if (mController == null)
4864d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik                return;
4865d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik            try {
4866d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik                mController.setLayoutDirection(layoutDirection);
4867d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik            } catch (RemoteException e) {
4868d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik                Log.w(TAG, "Error calling setLayoutDirection", e);
4869d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik            }
4870d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik        }
4871d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik
4872d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik        public void postDismiss() {
4873d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik            if (mController == null)
4874d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik                return;
4875d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik            try {
4876d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik                mController.dismiss();
4877d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik            } catch (RemoteException e) {
4878d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik                Log.w(TAG, "Error calling dismiss", e);
4879d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik            }
4880d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik        }
4881d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik    }
48829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
4883