AudioService.java revision 6fa4245589c93025d91aab7dc6681babdd91ee41
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;
2882aa7f017daaaeb96c13e6e3491d5037ab471085Jaikumar Ganeshimport android.bluetooth.BluetoothA2dp;
2982aa7f017daaaeb96c13e6e3491d5037ab471085Jaikumar Ganeshimport android.bluetooth.BluetoothAdapter;
3082aa7f017daaaeb96c13e6e3491d5037ab471085Jaikumar Ganeshimport android.bluetooth.BluetoothClass;
3182aa7f017daaaeb96c13e6e3491d5037ab471085Jaikumar Ganeshimport android.bluetooth.BluetoothDevice;
3282aa7f017daaaeb96c13e6e3491d5037ab471085Jaikumar Ganeshimport android.bluetooth.BluetoothHeadset;
3382aa7f017daaaeb96c13e6e3491d5037ab471085Jaikumar Ganeshimport android.bluetooth.BluetoothProfile;
34bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pellyimport android.content.BroadcastReceiver;
35d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Triviimport android.content.ComponentName;
369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.ContentResolver;
379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.Context;
389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.Intent;
39a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurentimport android.content.IntentFilter;
409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.pm.PackageManager;
41f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Triviimport android.content.res.Configuration;
42e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurentimport android.content.res.Resources;
43e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurentimport android.content.res.XmlResourceParser;
44b109615ebebd6f3b9ae789412279f576c3ace46bJason Parekhimport android.database.ContentObserver;
4541d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jangimport android.hardware.hdmi.HdmiControlManager;
46212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurentimport android.hardware.hdmi.HdmiPlaybackClient;
4741d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jangimport android.hardware.hdmi.HdmiTvClient;
48c837a451946b64d70ed7c642fbde03c182c28b6fPaul McLeanimport android.hardware.usb.UsbManager;
499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.media.MediaPlayer.OnCompletionListener;
509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.media.MediaPlayer.OnErrorListener;
518fdb0d4defb6ee2ca8057d3442ead36b408b6c17Jean-Michel Triviimport android.media.audiopolicy.AudioMix;
52958876fe55ea0fdeb73c72240a2f2bab32833443Jean-Michel Triviimport android.media.audiopolicy.AudioPolicy;
53a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Triviimport android.media.audiopolicy.AudioPolicyConfig;
540212be5150fb9fb3c340f3c7e51f6126372cc6f9Jean-Michel Triviimport android.media.audiopolicy.IAudioPolicyCallback;
559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.Binder;
56c18c9138cee0f0859bcab636a004ce92ca4a9ab5Eric Laurentimport android.os.Build;
579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.Environment;
589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.Handler;
599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.IBinder;
609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.Looper;
619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.Message;
62c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Triviimport android.os.PowerManager;
63632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackbornimport android.os.RemoteCallbackList;
649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.RemoteException;
6533f4e04e32fac42f158733d6a731e50490fa9951John Spurlockimport android.os.SystemClock;
6682aa7f017daaaeb96c13e6e3491d5037ab471085Jaikumar Ganeshimport android.os.SystemProperties;
675ac72a29593ab9a20337a2225df52bdf4754be02Dianne Hackbornimport android.os.UserHandle;
68bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurentimport android.os.Vibrator;
699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.provider.Settings;
709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.provider.Settings.System;
71ef9f6f957d897ea0ed82114185b8fa3fefd4917bTyler Gunnimport android.telecom.TelecomManager;
72632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackbornimport android.text.TextUtils;
739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.util.Log;
74aa5ee4d65f8788e2a0afcd198367450853fd72acJohn Spurlockimport android.util.MathUtils;
75a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Triviimport android.util.Slog;
76d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Triviimport android.view.KeyEvent;
77519c7744b522aa07e12bc3244ac3de14aa2a4ad0RoboErikimport android.view.OrientationEventListener;
78bb6f8711a7f804d39c45218db2d6339940cc5d35Jean-Michel Triviimport android.view.Surface;
79bb6f8711a7f804d39c45218db2d6339940cc5d35Jean-Michel Triviimport android.view.WindowManager;
80873cc45da2463a11182fe94a2565364d7e1709bbJean-Michel Triviimport android.view.accessibility.AccessibilityManager;
819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
82e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurentimport com.android.internal.util.XmlUtils;
830dac35af2c6aa42bcd181981b041747cfd1afa5fRoboErikimport com.android.server.LocalServices;
84e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent
85e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurentimport org.xmlpull.v1.XmlPullParserException;
869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
87d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Triviimport java.io.FileDescriptor;
889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.io.IOException;
89d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Triviimport java.io.PrintWriter;
90e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurentimport java.lang.reflect.Field;
919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.ArrayList;
92c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurentimport java.util.HashMap;
93c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurentimport java.util.Iterator;
945a1e4cf83f5be1b5d79e2643fa791aa269b6a4bcJaikumar Ganeshimport java.util.List;
95c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurentimport java.util.Map;
9682aa7f017daaaeb96c13e6e3491d5037ab471085Jaikumar Ganeshimport java.util.NoSuchElementException;
97d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErikimport java.util.Objects;
98c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurentimport java.util.Set;
99519c7744b522aa07e12bc3244ac3de14aa2a4ad0RoboErikimport java.util.concurrent.ConcurrentHashMap;
1009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/**
1029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * The implementation of the volume manager service.
1039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * <p>
1049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * This implementation focuses on delivering a responsive UI. Most methods are
1059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * asynchronous to external calls. For example, the task of setting a volume
1069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * will update our internal state, but in a separate thread will set the system
1079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * volume and later persist to the database. Similarly, setting the ringer mode
1089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * will update the state and broadcast a change and in a separate thread later
1099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * persist the ringer mode.
1109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
1119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @hide
1129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */
113fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivipublic class AudioService extends IAudioService.Stub {
1149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final String TAG = "AudioService";
1169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
117339567d5c91a8dc9228913ed1e5deb0ebb8a4a64Jean-Michel Trivi    /** Debug audio mode */
118339567d5c91a8dc9228913ed1e5deb0ebb8a4a64Jean-Michel Trivi    protected static final boolean DEBUG_MODE = Log.isLoggable(TAG + ".MOD", Log.DEBUG);
1198fdb0d4defb6ee2ca8057d3442ead36b408b6c17Jean-Michel Trivi
1208fdb0d4defb6ee2ca8057d3442ead36b408b6c17Jean-Michel Trivi    /** Debug audio policy feature */
1218fdb0d4defb6ee2ca8057d3442ead36b408b6c17Jean-Michel Trivi    protected static final boolean DEBUG_AP = Log.isLoggable(TAG + ".AP", Log.DEBUG);
1228fdb0d4defb6ee2ca8057d3442ead36b408b6c17Jean-Michel Trivi
1233114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    /** Debug volumes */
124ae641c9ccd3f81214cee54a5f13804f1765187adJohn Spurlock    protected static final boolean DEBUG_VOL = Log.isLoggable(TAG + ".VOL", Log.DEBUG);
12518e7bce52318f00b5023f33933a571c477f2b61cJean-Michel Trivi
126430fc48865e5a371b08f180390946b96d73848feRoboErik    /** debug calls to media session apis */
127ae641c9ccd3f81214cee54a5f13804f1765187adJohn Spurlock    private static final boolean DEBUG_SESSIONS = Log.isLoggable(TAG + ".SESSIONS", Log.DEBUG);
1288a2cfc309ab9126e90022916967c65a793c034f0RoboErik
1298600534df66c2ff5846ed230b50c56229322d48aJohn Spurlock    /** Allow volume changes to set ringer mode to silent? */
1308600534df66c2ff5846ed230b50c56229322d48aJohn Spurlock    private static final boolean VOLUME_SETS_RINGER_MODE_SILENT = false;
1318600534df66c2ff5846ed230b50c56229322d48aJohn Spurlock
132a11b4affcad3d255aa723a89b768ea222506f2e8John Spurlock    /** In silent mode, are volume adjustments (raises) prevented? */
133a11b4affcad3d255aa723a89b768ea222506f2e8John Spurlock    private static final boolean PREVENT_VOLUME_ADJUSTMENT_IF_SILENT = true;
134a11b4affcad3d255aa723a89b768ea222506f2e8John Spurlock
1359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** How long to delay before persisting a change in volume/ringer mode. */
13645edba1b8b0377dfe70a4f2b0afb0f04dd8e1ee9RoboErik    private static final int PERSIST_DELAY = 500;
1379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1383346a802087f621c6441bc512dfcc17b07143fc6John Spurlock    /**
1393346a802087f621c6441bc512dfcc17b07143fc6John Spurlock     * The delay before playing a sound. This small period exists so the user
1403346a802087f621c6441bc512dfcc17b07143fc6John Spurlock     * can press another key (non-volume keys, too) to have it NOT be audible.
1413346a802087f621c6441bc512dfcc17b07143fc6John Spurlock     * <p>
1423346a802087f621c6441bc512dfcc17b07143fc6John Spurlock     * PhoneWindow will implement this part.
1433346a802087f621c6441bc512dfcc17b07143fc6John Spurlock     */
1443346a802087f621c6441bc512dfcc17b07143fc6John Spurlock    public static final int PLAY_SOUND_DELAY = 300;
1453346a802087f621c6441bc512dfcc17b07143fc6John Spurlock
146a11b4affcad3d255aa723a89b768ea222506f2e8John Spurlock    /**
147a11b4affcad3d255aa723a89b768ea222506f2e8John Spurlock     * Only used in the result from {@link #checkForRingerModeChange(int, int, int)}
148a11b4affcad3d255aa723a89b768ea222506f2e8John Spurlock     */
149a11b4affcad3d255aa723a89b768ea222506f2e8John Spurlock    private static final int FLAG_ADJUST_VOLUME = 1;
150a11b4affcad3d255aa723a89b768ea222506f2e8John Spurlock
151ba50b97cff80e73620a0e3d13cae169e095974a7Dianne Hackborn    private final Context mContext;
152ba50b97cff80e73620a0e3d13cae169e095974a7Dianne Hackborn    private final ContentResolver mContentResolver;
153ba50b97cff80e73620a0e3d13cae169e095974a7Dianne Hackborn    private final AppOpsManager mAppOps;
154212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent
155212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent    // the platform has no specific capabilities
156212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent    private static final int PLATFORM_DEFAULT = 0;
157212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent    // the platform is voice call capable (a phone)
158212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent    private static final int PLATFORM_VOICE = 1;
159212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent    // the platform is a television or a set-top box
160212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent    private static final int PLATFORM_TELEVISION = 2;
161212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent    // the platform type affects volume and silent mode behavior
162212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent    private final int mPlatformType;
163212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent
164212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent    private boolean isPlatformVoice() {
165212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent        return mPlatformType == PLATFORM_VOICE;
166212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent    }
167212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent
168212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent    private boolean isPlatformTelevision() {
169212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent        return mPlatformType == PLATFORM_TELEVISION;
170212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent    }
171d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi
1723346a802087f621c6441bc512dfcc17b07143fc6John Spurlock    /** The controller for the volume UI. */
1733346a802087f621c6441bc512dfcc17b07143fc6John Spurlock    private final VolumeController mVolumeController = new VolumeController();
1749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // sendMsg() flags
1769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** If the msg is already queued, replace it with this one. */
1779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final int SENDMSG_REPLACE = 0;
1789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** If the msg is already queued, ignore this one and leave the old. */
1799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final int SENDMSG_NOOP = 1;
1809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** If the msg is already queued, queue this one and leave the old. */
1819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final int SENDMSG_QUEUE = 2;
1829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1833114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    // AudioHandler messages
1849bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent    private static final int MSG_SET_DEVICE_VOLUME = 0;
1859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final int MSG_PERSIST_VOLUME = 1;
1865c55a051ad7d86a464fb91426f1ea3c0250e38b3Mike Lockwood    private static final int MSG_PERSIST_MASTER_VOLUME = 2;
1879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final int MSG_PERSIST_RINGER_MODE = 3;
188bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent    private static final int MSG_MEDIA_SERVER_DIED = 4;
189dfb881f96af7898151940a4bbc52e45e6043d38bEric Laurent    private static final int MSG_PLAY_SOUND_EFFECT = 5;
190dfb881f96af7898151940a4bbc52e45e6043d38bEric Laurent    private static final int MSG_BTA2DP_DOCK_TIMEOUT = 6;
191dfb881f96af7898151940a4bbc52e45e6043d38bEric Laurent    private static final int MSG_LOAD_SOUND_EFFECTS = 7;
192dfb881f96af7898151940a4bbc52e45e6043d38bEric Laurent    private static final int MSG_SET_FORCE_USE = 8;
193dfb881f96af7898151940a4bbc52e45e6043d38bEric Laurent    private static final int MSG_BT_HEADSET_CNCT_FAILED = 9;
194dfb881f96af7898151940a4bbc52e45e6043d38bEric Laurent    private static final int MSG_SET_ALL_VOLUMES = 10;
195dfb881f96af7898151940a4bbc52e45e6043d38bEric Laurent    private static final int MSG_PERSIST_MASTER_VOLUME_MUTE = 11;
196dfb881f96af7898151940a4bbc52e45e6043d38bEric Laurent    private static final int MSG_REPORT_NEW_ROUTES = 12;
197dfb881f96af7898151940a4bbc52e45e6043d38bEric Laurent    private static final int MSG_SET_FORCE_BT_A2DP_USE = 13;
198dfb881f96af7898151940a4bbc52e45e6043d38bEric Laurent    private static final int MSG_CHECK_MUSIC_ACTIVE = 14;
199dfb881f96af7898151940a4bbc52e45e6043d38bEric Laurent    private static final int MSG_BROADCAST_AUDIO_BECOMING_NOISY = 15;
200dfb881f96af7898151940a4bbc52e45e6043d38bEric Laurent    private static final int MSG_CONFIGURE_SAFE_MEDIA_VOLUME = 16;
201dfb881f96af7898151940a4bbc52e45e6043d38bEric Laurent    private static final int MSG_CONFIGURE_SAFE_MEDIA_VOLUME_FORCED = 17;
202dfb881f96af7898151940a4bbc52e45e6043d38bEric Laurent    private static final int MSG_PERSIST_SAFE_VOLUME_STATE = 18;
203dfb881f96af7898151940a4bbc52e45e6043d38bEric Laurent    private static final int MSG_BROADCAST_BT_CONNECTION_STATE = 19;
204dfb881f96af7898151940a4bbc52e45e6043d38bEric Laurent    private static final int MSG_UNLOAD_SOUND_EFFECTS = 20;
2054a5eeb9c727d77bb57fef87a70c8c9cc23dbfee3Eric Laurent    private static final int MSG_SYSTEM_READY = 21;
206aa5ee4d65f8788e2a0afcd198367450853fd72acJohn Spurlock    private static final int MSG_PERSIST_MUSIC_ACTIVE_MS = 22;
207b53453fae037d67e421011936c8fdffe7ba43922Julia Reynolds    private static final int MSG_PERSIST_MICROPHONE_MUTE = 23;
2083114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    // start of messages handled under wakelock
2093114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    //   these messages can only be queued, i.e. sent with queueMsgUnderWakeLock(),
210e12c39bb9cedb8b363658979872694eb55b1386eJean-Michel Trivi    //   and not with sendMsg(..., ..., SENDMSG_QUEUE, ...)
211fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    private static final int MSG_SET_WIRED_DEVICE_CONNECTION_STATE = 100;
2120a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood    private static final int MSG_SET_A2DP_SRC_CONNECTION_STATE = 101;
2130a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood    private static final int MSG_SET_A2DP_SINK_CONNECTION_STATE = 102;
2143114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    // end of messages handled under wakelock
215afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent
2164c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi    private static final int BTA2DP_DOCK_TIMEOUT_MILLIS = 8000;
217dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent    // Timeout for connection to bluetooth headset service
218dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent    private static final int BT_HEADSET_CNCT_TIMEOUT_MS = 3000;
219dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent
2209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** @see AudioSystemThread */
2219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private AudioSystemThread mAudioSystemThread;
2229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** @see AudioHandler */
2239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private AudioHandler mAudioHandler;
2249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** @see VolumeStreamState */
2259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private VolumeStreamState[] mStreamStates;
226b109615ebebd6f3b9ae789412279f576c3ace46bJason Parekh    private SettingsObserver mSettingsObserver;
227a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent
228fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    private int mMode = AudioSystem.MODE_NORMAL;
229ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten    // protects mRingerMode
230ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten    private final Object mSettingsLock = new Object();
23145c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent
2329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private SoundPool mSoundPool;
23330c918ce7fbe171944b28fc91b3f22b3d631872dGlenn Kasten    private final Object mSoundEffectsLock = new Object();
2349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final int NUM_SOUNDPOOL_CHANNELS = 4;
2359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2364767690f09ea3447b8c5c32fb28d27650aa18e00Mike Lockwood    // Internally master volume is a float in the 0.0 - 1.0 range,
2374767690f09ea3447b8c5c32fb28d27650aa18e00Mike Lockwood    // but to support integer based AudioManager API we translate it to 0 - 100
2384767690f09ea3447b8c5c32fb28d27650aa18e00Mike Lockwood    private static final int MAX_MASTER_VOLUME = 100;
2394767690f09ea3447b8c5c32fb28d27650aa18e00Mike Lockwood
2406c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang    // Maximum volume adjust steps allowed in a single batch call.
2416c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang    private static final int MAX_BATCH_VOLUME_ADJUST_STEPS = 4;
2426c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang
2439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /* Sound effect file names  */
2449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final String SOUND_EFFECTS_PATH = "/media/audio/ui/";
245e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent    private static final List<String> SOUND_EFFECT_FILES = new ArrayList<String>();
2469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /* Sound effect file name mapping sound effect id (AudioManager.FX_xxx) to
2489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * file index in SOUND_EFFECT_FILES[] (first column) and indicating if effect
2499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * uses soundpool (second column) */
250e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent    private final int[][] SOUND_EFFECT_FILES_MAP = new int[AudioManager.NUM_SOUND_EFFECTS][2];
2519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2525982013cfc8274ff0bafaba83c676b3a8890cba9Jared Suttles   /** @hide Maximum volume index values for audio streams */
25391377de6f23af2b0b08adae22810cae6fc35cb1aEric Laurent    private static int[] MAX_STREAM_VOLUME = new int[] {
2546ee9952bc20be72b9419cb653c9e2e833889a3d3Eric Laurent        5,  // STREAM_VOICE_CALL
2556ee9952bc20be72b9419cb653c9e2e833889a3d3Eric Laurent        7,  // STREAM_SYSTEM
2566ee9952bc20be72b9419cb653c9e2e833889a3d3Eric Laurent        7,  // STREAM_RING
2576ee9952bc20be72b9419cb653c9e2e833889a3d3Eric Laurent        15, // STREAM_MUSIC
2586ee9952bc20be72b9419cb653c9e2e833889a3d3Eric Laurent        7,  // STREAM_ALARM
2596ee9952bc20be72b9419cb653c9e2e833889a3d3Eric Laurent        7,  // STREAM_NOTIFICATION
2606ee9952bc20be72b9419cb653c9e2e833889a3d3Eric Laurent        15, // STREAM_BLUETOOTH_SCO
2616ee9952bc20be72b9419cb653c9e2e833889a3d3Eric Laurent        7,  // STREAM_SYSTEM_ENFORCED
2626ee9952bc20be72b9419cb653c9e2e833889a3d3Eric Laurent        15, // STREAM_DTMF
2636ee9952bc20be72b9419cb653c9e2e833889a3d3Eric Laurent        15  // STREAM_TTS
2645982013cfc8274ff0bafaba83c676b3a8890cba9Jared Suttles    };
26591377de6f23af2b0b08adae22810cae6fc35cb1aEric Laurent
26691377de6f23af2b0b08adae22810cae6fc35cb1aEric Laurent    private static int[] DEFAULT_STREAM_VOLUME = new int[] {
26791377de6f23af2b0b08adae22810cae6fc35cb1aEric Laurent        4,  // STREAM_VOICE_CALL
26891377de6f23af2b0b08adae22810cae6fc35cb1aEric Laurent        7,  // STREAM_SYSTEM
26991377de6f23af2b0b08adae22810cae6fc35cb1aEric Laurent        5,  // STREAM_RING
27091377de6f23af2b0b08adae22810cae6fc35cb1aEric Laurent        11, // STREAM_MUSIC
27191377de6f23af2b0b08adae22810cae6fc35cb1aEric Laurent        6,  // STREAM_ALARM
27291377de6f23af2b0b08adae22810cae6fc35cb1aEric Laurent        5,  // STREAM_NOTIFICATION
27391377de6f23af2b0b08adae22810cae6fc35cb1aEric Laurent        7,  // STREAM_BLUETOOTH_SCO
27491377de6f23af2b0b08adae22810cae6fc35cb1aEric Laurent        7,  // STREAM_SYSTEM_ENFORCED
27591377de6f23af2b0b08adae22810cae6fc35cb1aEric Laurent        11, // STREAM_DTMF
27691377de6f23af2b0b08adae22810cae6fc35cb1aEric Laurent        11  // STREAM_TTS
27791377de6f23af2b0b08adae22810cae6fc35cb1aEric Laurent    };
27891377de6f23af2b0b08adae22810cae6fc35cb1aEric Laurent
2796d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent    /* mStreamVolumeAlias[] indicates for each stream if it uses the volume settings
280a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent     * of another stream: This avoids multiplying the volume settings for hidden
281a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent     * stream types that follow other stream behavior for volume settings
2826d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent     * NOTE: do not create loops in aliases!
2836d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent     * Some streams alias to different streams according to device category (phone or tablet) or
28424e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent     * use case (in call vs off call...). See updateStreamVolumeAlias() for more details.
285212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent     *  mStreamVolumeAlias contains STREAM_VOLUME_ALIAS_VOICE aliases for a voice capable device
286212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent     *  (phone), STREAM_VOLUME_ALIAS_TELEVISION for a television or set-top box and
287212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent     *  STREAM_VOLUME_ALIAS_DEFAULT for other devices (e.g. tablets).*/
288212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent    private final int[] STREAM_VOLUME_ALIAS_VOICE = new int[] {
2896d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent        AudioSystem.STREAM_VOICE_CALL,      // STREAM_VOICE_CALL
2906d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent        AudioSystem.STREAM_RING,            // STREAM_SYSTEM
2916d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent        AudioSystem.STREAM_RING,            // STREAM_RING
2926d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent        AudioSystem.STREAM_MUSIC,           // STREAM_MUSIC
2936d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent        AudioSystem.STREAM_ALARM,           // STREAM_ALARM
2946d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent        AudioSystem.STREAM_RING,            // STREAM_NOTIFICATION
2956d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent        AudioSystem.STREAM_BLUETOOTH_SCO,   // STREAM_BLUETOOTH_SCO
2966d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent        AudioSystem.STREAM_RING,            // STREAM_SYSTEM_ENFORCED
2976d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent        AudioSystem.STREAM_RING,            // STREAM_DTMF
2986d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent        AudioSystem.STREAM_MUSIC            // STREAM_TTS
299a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent    };
300212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent    private final int[] STREAM_VOLUME_ALIAS_TELEVISION = new int[] {
301212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent        AudioSystem.STREAM_MUSIC,       // STREAM_VOICE_CALL
302212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent        AudioSystem.STREAM_MUSIC,       // STREAM_SYSTEM
303212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent        AudioSystem.STREAM_MUSIC,       // STREAM_RING
304212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent        AudioSystem.STREAM_MUSIC,       // STREAM_MUSIC
305212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent        AudioSystem.STREAM_MUSIC,       // STREAM_ALARM
306212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent        AudioSystem.STREAM_MUSIC,       // STREAM_NOTIFICATION
307212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent        AudioSystem.STREAM_MUSIC,       // STREAM_BLUETOOTH_SCO
308212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent        AudioSystem.STREAM_MUSIC,       // STREAM_SYSTEM_ENFORCED
309212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent        AudioSystem.STREAM_MUSIC,       // STREAM_DTMF
310212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent        AudioSystem.STREAM_MUSIC        // STREAM_TTS
311212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent    };
312212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent    private final int[] STREAM_VOLUME_ALIAS_DEFAULT = new int[] {
3136d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent        AudioSystem.STREAM_VOICE_CALL,      // STREAM_VOICE_CALL
3144f0f120316cfcee5880191264885772677fff921John Spurlock        AudioSystem.STREAM_RING,            // STREAM_SYSTEM
3156d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent        AudioSystem.STREAM_RING,            // STREAM_RING
3166d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent        AudioSystem.STREAM_MUSIC,           // STREAM_MUSIC
3176d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent        AudioSystem.STREAM_ALARM,           // STREAM_ALARM
3186d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent        AudioSystem.STREAM_RING,            // STREAM_NOTIFICATION
3196d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent        AudioSystem.STREAM_BLUETOOTH_SCO,   // STREAM_BLUETOOTH_SCO
3204f0f120316cfcee5880191264885772677fff921John Spurlock        AudioSystem.STREAM_RING,            // STREAM_SYSTEM_ENFORCED
3214f0f120316cfcee5880191264885772677fff921John Spurlock        AudioSystem.STREAM_RING,            // STREAM_DTMF
3226d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent        AudioSystem.STREAM_MUSIC            // STREAM_TTS
3236d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent    };
3246d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent    private int[] mStreamVolumeAlias;
325a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent
326ba50b97cff80e73620a0e3d13cae169e095974a7Dianne Hackborn    /**
327ba50b97cff80e73620a0e3d13cae169e095974a7Dianne Hackborn     * Map AudioSystem.STREAM_* constants to app ops.  This should be used
328ba50b97cff80e73620a0e3d13cae169e095974a7Dianne Hackborn     * after mapping through mStreamVolumeAlias.
329ba50b97cff80e73620a0e3d13cae169e095974a7Dianne Hackborn     */
330ba50b97cff80e73620a0e3d13cae169e095974a7Dianne Hackborn    private static final int[] STEAM_VOLUME_OPS = new int[] {
331ba50b97cff80e73620a0e3d13cae169e095974a7Dianne Hackborn        AppOpsManager.OP_AUDIO_VOICE_VOLUME,            // STREAM_VOICE_CALL
332ba50b97cff80e73620a0e3d13cae169e095974a7Dianne Hackborn        AppOpsManager.OP_AUDIO_MEDIA_VOLUME,            // STREAM_SYSTEM
333ba50b97cff80e73620a0e3d13cae169e095974a7Dianne Hackborn        AppOpsManager.OP_AUDIO_RING_VOLUME,             // STREAM_RING
334ba50b97cff80e73620a0e3d13cae169e095974a7Dianne Hackborn        AppOpsManager.OP_AUDIO_MEDIA_VOLUME,            // STREAM_MUSIC
335ba50b97cff80e73620a0e3d13cae169e095974a7Dianne Hackborn        AppOpsManager.OP_AUDIO_ALARM_VOLUME,            // STREAM_ALARM
336ba50b97cff80e73620a0e3d13cae169e095974a7Dianne Hackborn        AppOpsManager.OP_AUDIO_NOTIFICATION_VOLUME,     // STREAM_NOTIFICATION
337ba50b97cff80e73620a0e3d13cae169e095974a7Dianne Hackborn        AppOpsManager.OP_AUDIO_BLUETOOTH_VOLUME,        // STREAM_BLUETOOTH_SCO
338ba50b97cff80e73620a0e3d13cae169e095974a7Dianne Hackborn        AppOpsManager.OP_AUDIO_MEDIA_VOLUME,            // STREAM_SYSTEM_ENFORCED
339ba50b97cff80e73620a0e3d13cae169e095974a7Dianne Hackborn        AppOpsManager.OP_AUDIO_MEDIA_VOLUME,            // STREAM_DTMF
340ba50b97cff80e73620a0e3d13cae169e095974a7Dianne Hackborn        AppOpsManager.OP_AUDIO_MEDIA_VOLUME,            // STREAM_TTS
341ba50b97cff80e73620a0e3d13cae169e095974a7Dianne Hackborn    };
342ba50b97cff80e73620a0e3d13cae169e095974a7Dianne Hackborn
34383a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent    private final boolean mUseFixedVolume;
34483a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent
345bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent    // stream names used by dumpStreamStates()
3461af30c7ac480e5d335f267a3ac3b2e6c748ce240John Spurlock    private static final String[] STREAM_NAMES = new String[] {
347bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent            "STREAM_VOICE_CALL",
348bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent            "STREAM_SYSTEM",
349bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent            "STREAM_RING",
350bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent            "STREAM_MUSIC",
351bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent            "STREAM_ALARM",
352bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent            "STREAM_NOTIFICATION",
353bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent            "STREAM_BLUETOOTH_SCO",
354bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent            "STREAM_SYSTEM_ENFORCED",
355bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent            "STREAM_DTMF",
356bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent            "STREAM_TTS"
357bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent    };
358bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent
35930c918ce7fbe171944b28fc91b3f22b3d631872dGlenn Kasten    private final AudioSystem.ErrorCallback mAudioSystemCallback = new AudioSystem.ErrorCallback() {
3609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public void onError(int error) {
3619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            switch (error) {
3629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            case AudioSystem.AUDIO_STATUS_SERVER_DIED:
363dfb881f96af7898151940a4bbc52e45e6043d38bEric Laurent                sendMsg(mAudioHandler, MSG_MEDIA_SERVER_DIED,
364dfb881f96af7898151940a4bbc52e45e6043d38bEric Laurent                        SENDMSG_NOOP, 0, 0, null, 0);
3659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                break;
3669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            default:
3679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                break;
3689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
369dfb881f96af7898151940a4bbc52e45e6043d38bEric Laurent        }
3709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    };
3719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
3739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Current ringer mode from one of {@link AudioManager#RINGER_MODE_NORMAL},
3749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * {@link AudioManager#RINGER_MODE_SILENT}, or
3759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * {@link AudioManager#RINGER_MODE_VIBRATE}.
3769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
377ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten    // protected by mSettingsLock
378661f2cf45860d2e10924e6b69966a9afe255f28bJohn Spurlock    private int mRingerMode;  // internal ringer mode, affects muting of underlying streams
379661f2cf45860d2e10924e6b69966a9afe255f28bJohn Spurlock    private int mRingerModeExternal = -1;  // reported ringer mode to outside clients (AudioManager)
3809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3819bcf401d13d47416043a704430388abd59aef7cdEric Laurent    /** @see System#MODE_RINGER_STREAMS_AFFECTED */
38224e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent    private int mRingerModeAffectedStreams = 0;
3839bcf401d13d47416043a704430388abd59aef7cdEric Laurent
3845b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent    // Streams currently muted by ringer mode
3855b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent    private int mRingerModeMutedStreams;
3865b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent
3879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** @see System#MUTE_STREAMS_AFFECTED */
3889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private int mMuteAffectedStreams;
3899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
391bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent     * NOTE: setVibrateSetting(), getVibrateSetting(), shouldVibrate() are deprecated.
392bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent     * mVibrateSetting is just maintained during deprecation period but vibration policy is
393bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent     * now only controlled by mHasVibrator and mRingerMode
3949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
3959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private int mVibrateSetting;
3969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
397bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent    // Is there a vibrator
398bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent    private final boolean mHasVibrator;
399bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent
400a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent    // Broadcast receiver for device connections intent broadcasts
401a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent    private final BroadcastReceiver mReceiver = new AudioServiceBroadcastReceiver();
402a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent
403c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent    // Devices currently connected
40430c918ce7fbe171944b28fc91b3f22b3d631872dGlenn Kasten    private final HashMap <Integer, String> mConnectedDevices = new HashMap <Integer, String>();
405c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent
406c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent    // Forced device usage for communications
407c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent    private int mForcedUseForComm;
408c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent
4090dc37cce9d564ae43883c8dc8672b9266b881e63Mike Lockwood    // True if we have master volume support
4100dc37cce9d564ae43883c8dc8672b9266b881e63Mike Lockwood    private final boolean mUseMasterVolume;
4110dc37cce9d564ae43883c8dc8672b9266b881e63Mike Lockwood
4129760647dd0ee67e7c20f3e9d661d2006b1df0b54Mike Lockwood    private final int[] mMasterVolumeRamp;
4139760647dd0ee67e7c20f3e9d661d2006b1df0b54Mike Lockwood
4149272b4b4a44fe1f33e3030810618194f817caaecEric Laurent    // List of binder death handlers for setMode() client processes.
4159272b4b4a44fe1f33e3030810618194f817caaecEric Laurent    // The last process to have called setMode() is at the top of the list.
41630c918ce7fbe171944b28fc91b3f22b3d631872dGlenn Kasten    private final ArrayList <SetModeDeathHandler> mSetModeDeathHandlers = new ArrayList <SetModeDeathHandler>();
417eb14a783be073b5fd6e8c8c9bc87d2d1919f2c9eEric Laurent
4183def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent    // List of clients having issued a SCO start request
41930c918ce7fbe171944b28fc91b3f22b3d631872dGlenn Kasten    private final ArrayList <ScoClient> mScoClients = new ArrayList <ScoClient>();
4203def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent
4213def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent    // BluetoothHeadset API to control SCO connection
4223def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent    private BluetoothHeadset mBluetoothHeadset;
4233def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent
42482aa7f017daaaeb96c13e6e3491d5037ab471085Jaikumar Ganesh    // Bluetooth headset device
42582aa7f017daaaeb96c13e6e3491d5037ab471085Jaikumar Ganesh    private BluetoothDevice mBluetoothHeadsetDevice;
4263def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent
42762ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent    // Indicate if SCO audio connection is currently active and if the initiator is
42862ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent    // audio service (internal) or bluetooth headset (external)
42962ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent    private int mScoAudioState;
43062ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent    // SCO audio state is not active
43162ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent    private static final int SCO_STATE_INACTIVE = 0;
432dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent    // SCO audio activation request waiting for headset service to connect
433dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent    private static final int SCO_STATE_ACTIVATE_REQ = 1;
43425fc29b3691a1d2a84164988dc74b2e7d301868eEric Laurent    // SCO audio state is active or starting due to a request from AudioManager API
435dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent    private static final int SCO_STATE_ACTIVE_INTERNAL = 3;
436dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent    // SCO audio deactivation request waiting for headset service to connect
437dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent    private static final int SCO_STATE_DEACTIVATE_REQ = 5;
438dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent
43962ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent    // SCO audio state is active due to an action in BT handsfree (either voice recognition or
44062ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent    // in call audio)
44162ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent    private static final int SCO_STATE_ACTIVE_EXTERNAL = 2;
442dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent    // Deactivation request for all SCO connections (initiated by audio mode change)
443dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent    // waiting for headset service to connect
444dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent    private static final int SCO_STATE_DEACTIVATE_EXT_REQ = 4;
445dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent
446c18c9138cee0f0859bcab636a004ce92ca4a9ab5Eric Laurent    // Indicates the mode used for SCO audio connection. The mode is virtual call if the request
447c18c9138cee0f0859bcab636a004ce92ca4a9ab5Eric Laurent    // originated from an app targeting an API version before JB MR2 and raw audio after that.
448c18c9138cee0f0859bcab636a004ce92ca4a9ab5Eric Laurent    private int mScoAudioMode;
449f4e51d82d2e34e6832903f01eaecc15ded6c3241Liejun Tao    // SCO audio mode is undefined
450f4e51d82d2e34e6832903f01eaecc15ded6c3241Liejun Tao    private static final int SCO_MODE_UNDEFINED = -1;
451c18c9138cee0f0859bcab636a004ce92ca4a9ab5Eric Laurent    // SCO audio mode is virtual voice call (BluetoothHeadset.startScoUsingVirtualVoiceCall())
452c18c9138cee0f0859bcab636a004ce92ca4a9ab5Eric Laurent    private static final int SCO_MODE_VIRTUAL_CALL = 0;
453c18c9138cee0f0859bcab636a004ce92ca4a9ab5Eric Laurent    // SCO audio mode is raw audio (BluetoothHeadset.connectAudio())
454c18c9138cee0f0859bcab636a004ce92ca4a9ab5Eric Laurent    private static final int SCO_MODE_RAW = 1;
455f4e51d82d2e34e6832903f01eaecc15ded6c3241Liejun Tao    // SCO audio mode is Voice Recognition (BluetoothHeadset.startVoiceRecognition())
456f4e51d82d2e34e6832903f01eaecc15ded6c3241Liejun Tao    private static final int SCO_MODE_VR = 2;
457f4e51d82d2e34e6832903f01eaecc15ded6c3241Liejun Tao
458f4e51d82d2e34e6832903f01eaecc15ded6c3241Liejun Tao    private static final int SCO_MODE_MAX = 2;
459c18c9138cee0f0859bcab636a004ce92ca4a9ab5Eric Laurent
460dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent    // Current connection state indicated by bluetooth headset
461dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent    private int mScoConnectionState;
46262ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent
463a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent    // true if boot sequence has been completed
4644a5eeb9c727d77bb57fef87a70c8c9cc23dbfee3Eric Laurent    private boolean mSystemReady;
465a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent    // listener for SoundPool sample load completion indication
466a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent    private SoundPoolCallback mSoundPoolCallBack;
467a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent    // thread for SoundPool listener
468a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent    private SoundPoolListenerThread mSoundPoolListenerThread;
469a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent    // message looper for SoundPool listener
470a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent    private Looper mSoundPoolLooper = null;
471c55b393efd462490cd5e27fc373bceafdd25662eJean-Michel Trivi    // volume applied to sound played with playSoundEffect()
472f2b0c11f4e797e183131261724d8de310dac5431Jean-Michel Trivi    private static int sSoundEffectVolumeDb;
47325101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent    // previous volume adjustment direction received by checkForRingerModeChange()
47425101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent    private int mPrevVolDirection = AudioManager.ADJUST_SAME;
4756243edd818b84adfbe712d5d233d6414b33653acAmith Yamasani    // Keyguard manager proxy
4766243edd818b84adfbe712d5d233d6414b33653acAmith Yamasani    private KeyguardManager mKeyguardManager;
47745c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent    // mVolumeControlStream is set by VolumePanel to temporarily force the stream type which volume
47845c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent    // is controlled by Vol keys.
47945c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent    private int  mVolumeControlStream = -1;
48045c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent    private final Object mForceControlStreamLock = new Object();
48145c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent    // VolumePanel is currently the only client of forceVolumeControlStream() and runs in system
48245c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent    // server process so in theory it is not necessary to monitor the client death.
48345c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent    // However it is good to be ready for future evolutions.
48445c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent    private ForceControlStreamClient mForceControlStreamClient = null;
485098d580cc2bb6c0891c756a4e5230c6c6b0d2376Jeff Sharkey    // Used to play ringtones outside system_server
486098d580cc2bb6c0891c756a4e5230c6c6b0d2376Jeff Sharkey    private volatile IRingtonePlayer mRingtonePlayer;
4879bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent
488f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi    private int mDeviceOrientation = Configuration.ORIENTATION_UNDEFINED;
489bb6f8711a7f804d39c45218db2d6339940cc5d35Jean-Michel Trivi    private int mDeviceRotation = Surface.ROTATION_0;
490f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi
4917847211fb4699bf6018e29d214a918ed6657319bEric Laurent    // Request to override default use of A2DP for media.
4927847211fb4699bf6018e29d214a918ed6657319bEric Laurent    private boolean mBluetoothA2dpEnabled;
4937847211fb4699bf6018e29d214a918ed6657319bEric Laurent    private final Object mBluetoothA2dpEnabledLock = new Object();
4947847211fb4699bf6018e29d214a918ed6657319bEric Laurent
495632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn    // Monitoring of audio routes.  Protected by mCurAudioRoutes.
496632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn    final AudioRoutesInfo mCurAudioRoutes = new AudioRoutesInfo();
497632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn    final RemoteCallbackList<IAudioRoutesObserver> mRoutesObservers
498632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn            = new RemoteCallbackList<IAudioRoutesObserver>();
499632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn
5004bbcc6549738f3d69831b2bd9eb4accec3e9920eEric Laurent    // Devices for which the volume is fixed and VolumePanel slider should be disabled
501212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent    int mFixedVolumeDevices = AudioSystem.DEVICE_OUT_HDMI |
5024bbcc6549738f3d69831b2bd9eb4accec3e9920eEric Laurent            AudioSystem.DEVICE_OUT_DGTL_DOCK_HEADSET |
503212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent            AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET |
504212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent            AudioSystem.DEVICE_OUT_HDMI_ARC |
505212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent            AudioSystem.DEVICE_OUT_SPDIF |
506212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent            AudioSystem.DEVICE_OUT_AUX_LINE;
507ba5270b88798c66fefc17a1b25b27894e4fb7862Jean-Michel Trivi    int mFullVolumeDevices = 0;
5084bbcc6549738f3d69831b2bd9eb4accec3e9920eEric Laurent
509bb6f8711a7f804d39c45218db2d6339940cc5d35Jean-Michel Trivi    // TODO merge orientation and rotation
510d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent    private final boolean mMonitorOrientation;
511bb6f8711a7f804d39c45218db2d6339940cc5d35Jean-Michel Trivi    private final boolean mMonitorRotation;
512d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent
5137ee1e4ff7346a278a6722108fbc1869240b3e866Eric Laurent    private boolean mDockAudioMediaEnabled = true;
5147ee1e4ff7346a278a6722108fbc1869240b3e866Eric Laurent
51508ed1b9d2099ec8231b21353b33b901492ea9885Eric Laurent    private int mDockState = Intent.EXTRA_DOCK_STATE_UNDOCKED;
51608ed1b9d2099ec8231b21353b33b901492ea9885Eric Laurent
517fde16d5879ea88a971004c984093409468b6139cEric Laurent    // Used when safe volume warning message display is requested by setStreamVolume(). In this
518fde16d5879ea88a971004c984093409468b6139cEric Laurent    // case, the new requested volume, stream type and device are stored in mPendingVolumeCommand
519fde16d5879ea88a971004c984093409468b6139cEric Laurent    // and used later when/if disableSafeMediaVolume() is called.
520fde16d5879ea88a971004c984093409468b6139cEric Laurent    private StreamVolumeCommand mPendingVolumeCommand;
521fde16d5879ea88a971004c984093409468b6139cEric Laurent
522fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    private PowerManager.WakeLock mAudioEventWakeLock;
523fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi
524fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    private final MediaFocusControl mMediaFocusControl;
525fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi
5265a0cf7a27f3953a1266af48543ccd9024f4cd89fJohn Du    // Reference to BluetoothA2dp to query for AbsoluteVolume.
5275a0cf7a27f3953a1266af48543ccd9024f4cd89fJohn Du    private BluetoothA2dp mA2dp;
5285a0cf7a27f3953a1266af48543ccd9024f4cd89fJohn Du    private final Object mA2dpAvrcpLock = new Object();
5295a0cf7a27f3953a1266af48543ccd9024f4cd89fJohn Du    // If absolute volume is supported in AVRCP device
5305a0cf7a27f3953a1266af48543ccd9024f4cd89fJohn Du    private boolean mAvrcpAbsVolSupported = false;
5315a0cf7a27f3953a1266af48543ccd9024f4cd89fJohn Du
532318f0fe43bdc4b2f6764edd91d6b78d9875ffdebJon Eklund    private AudioOrientationEventListener mOrientationListener;
533318f0fe43bdc4b2f6764edd91d6b78d9875ffdebJon Eklund
534adbe8bf85f3c8230d16ae5cb3f5d9736e09ed84aEric Laurent    private static Long mLastDeviceConnectMsgTime = new Long(0);
535adbe8bf85f3c8230d16ae5cb3f5d9736e09ed84aEric Laurent
536661f2cf45860d2e10924e6b69966a9afe255f28bJohn Spurlock    private AudioManagerInternal.RingerModeDelegate mRingerModeDelegate;
537661f2cf45860d2e10924e6b69966a9afe255f28bJohn Spurlock
5389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    ///////////////////////////////////////////////////////////////////////////
5399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // Construction
5409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    ///////////////////////////////////////////////////////////////////////////
5419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** @hide */
5439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public AudioService(Context context) {
5449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext = context;
5459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContentResolver = context.getContentResolver();
546ba50b97cff80e73620a0e3d13cae169e095974a7Dianne Hackborn        mAppOps = (AppOpsManager)context.getSystemService(Context.APP_OPS_SERVICE);
547212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent
548212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent        if (mContext.getResources().getBoolean(
549212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent                com.android.internal.R.bool.config_voice_capable)) {
550212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent            mPlatformType = PLATFORM_VOICE;
551212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent        } else if (context.getPackageManager().hasSystemFeature(
5520b03f9909be438f45b32ce2a6a2c2c5208a82cc9Eric Laurent                                                            PackageManager.FEATURE_LEANBACK)) {
553212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent            mPlatformType = PLATFORM_TELEVISION;
554212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent        } else {
555212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent            mPlatformType = PLATFORM_DEFAULT;
556212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent        }
5575982013cfc8274ff0bafaba83c676b3a8890cba9Jared Suttles
558c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi        PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
559fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        mAudioEventWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "handleAudioEvent");
560c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi
561bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent        Vibrator vibrator = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE);
562bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent        mHasVibrator = vibrator == null ? false : vibrator.hasVibrator();
563bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent
5645982013cfc8274ff0bafaba83c676b3a8890cba9Jared Suttles       // Intialized volume
56591377de6f23af2b0b08adae22810cae6fc35cb1aEric Laurent        int maxVolume = SystemProperties.getInt("ro.config.vc_call_vol_steps",
56691377de6f23af2b0b08adae22810cae6fc35cb1aEric Laurent                MAX_STREAM_VOLUME[AudioSystem.STREAM_VOICE_CALL]);
56791377de6f23af2b0b08adae22810cae6fc35cb1aEric Laurent        if (maxVolume != MAX_STREAM_VOLUME[AudioSystem.STREAM_VOICE_CALL]) {
56891377de6f23af2b0b08adae22810cae6fc35cb1aEric Laurent            MAX_STREAM_VOLUME[AudioSystem.STREAM_VOICE_CALL] = maxVolume;
56991377de6f23af2b0b08adae22810cae6fc35cb1aEric Laurent            DEFAULT_STREAM_VOLUME[AudioSystem.STREAM_VOICE_CALL] = (maxVolume * 3) / 4;
57091377de6f23af2b0b08adae22810cae6fc35cb1aEric Laurent        }
57191377de6f23af2b0b08adae22810cae6fc35cb1aEric Laurent        maxVolume = SystemProperties.getInt("ro.config.media_vol_steps",
57291377de6f23af2b0b08adae22810cae6fc35cb1aEric Laurent                MAX_STREAM_VOLUME[AudioSystem.STREAM_MUSIC]);
57391377de6f23af2b0b08adae22810cae6fc35cb1aEric Laurent        if (maxVolume != MAX_STREAM_VOLUME[AudioSystem.STREAM_MUSIC]) {
57491377de6f23af2b0b08adae22810cae6fc35cb1aEric Laurent            MAX_STREAM_VOLUME[AudioSystem.STREAM_MUSIC] = maxVolume;
57591377de6f23af2b0b08adae22810cae6fc35cb1aEric Laurent            DEFAULT_STREAM_VOLUME[AudioSystem.STREAM_MUSIC] = (maxVolume * 3) / 4;
57691377de6f23af2b0b08adae22810cae6fc35cb1aEric Laurent        }
5775982013cfc8274ff0bafaba83c676b3a8890cba9Jared Suttles
578f2b0c11f4e797e183131261724d8de310dac5431Jean-Michel Trivi        sSoundEffectVolumeDb = context.getResources().getInteger(
579c55b393efd462490cd5e27fc373bceafdd25662eJean-Michel Trivi                com.android.internal.R.integer.config_soundEffectVolumeDb);
58025101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent
581c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent        mForcedUseForComm = AudioSystem.FORCE_NONE;
582dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent
5839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        createAudioSystemThread();
584dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent
585fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        mMediaFocusControl = new MediaFocusControl(mAudioHandler.getLooper(),
5863346a802087f621c6441bc512dfcc17b07143fc6John Spurlock                mContext, mVolumeController, this);
587fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi
588dfb881f96af7898151940a4bbc52e45e6043d38bEric Laurent        AudioSystem.setErrorCallback(mAudioSystemCallback);
589dfb881f96af7898151940a4bbc52e45e6043d38bEric Laurent
590dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent        boolean cameraSoundForced = mContext.getResources().getBoolean(
591dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent                com.android.internal.R.bool.config_camera_sound_forced);
592dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent        mCameraSoundForced = new Boolean(cameraSoundForced);
593dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent        sendMsg(mAudioHandler,
594dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent                MSG_SET_FORCE_USE,
595dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent                SENDMSG_QUEUE,
596dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent                AudioSystem.FOR_SYSTEM,
597dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent                cameraSoundForced ?
598dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent                        AudioSystem.FORCE_SYSTEM_ENFORCED : AudioSystem.FORCE_NONE,
599dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent                null,
600dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent                0);
601dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent
60205274f348e12983eb8613cc6eb9ae561e8197e28Eric Laurent        mSafeMediaVolumeState = new Integer(Settings.Global.getInt(mContentResolver,
60305274f348e12983eb8613cc6eb9ae561e8197e28Eric Laurent                                                        Settings.Global.AUDIO_SAFE_VOLUME_STATE,
60405274f348e12983eb8613cc6eb9ae561e8197e28Eric Laurent                                                        SAFE_MEDIA_VOLUME_NOT_CONFIGURED));
60505274f348e12983eb8613cc6eb9ae561e8197e28Eric Laurent        // The default safe volume index read here will be replaced by the actual value when
60605274f348e12983eb8613cc6eb9ae561e8197e28Eric Laurent        // the mcc is read by onConfigureSafeVolume()
60705274f348e12983eb8613cc6eb9ae561e8197e28Eric Laurent        mSafeMediaVolumeIndex = mContext.getResources().getInteger(
60805274f348e12983eb8613cc6eb9ae561e8197e28Eric Laurent                com.android.internal.R.integer.config_safe_media_volume_index) * 10;
60905274f348e12983eb8613cc6eb9ae561e8197e28Eric Laurent
61083a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent        mUseFixedVolume = mContext.getResources().getBoolean(
61183a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent                com.android.internal.R.bool.config_useFixedVolume);
612da39290460b30e5080769f039d6dff352b3c7808Wally Yau        mUseMasterVolume = context.getResources().getBoolean(
613da39290460b30e5080769f039d6dff352b3c7808Wally Yau                com.android.internal.R.bool.config_useMasterVolume);
614da39290460b30e5080769f039d6dff352b3c7808Wally Yau        mMasterVolumeRamp = context.getResources().getIntArray(
615da39290460b30e5080769f039d6dff352b3c7808Wally Yau                com.android.internal.R.array.config_masterVolumeRamp);
61683a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent
61724e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent        // must be called before readPersistedSettings() which needs a valid mStreamVolumeAlias[]
61824e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent        // array initialized by updateStreamVolumeAlias()
61924e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent        updateStreamVolumeAlias(false /*updateVolumes*/);
6209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        readPersistedSettings();
621c1d4166289ce016965d1147f7e8d37862ee347ecEric Laurent        mSettingsObserver = new SettingsObserver();
622a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent        createStreamStates();
6239f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent
624fd116ad1ab02f6060a0b2201f018317fa32e28b4Glenn Kasten        readAndSetLowRamDevice();
6253891c4cc918e8062abb97c542a8625d556dccc59Eric Laurent
6263891c4cc918e8062abb97c542a8625d556dccc59Eric Laurent        // Call setRingerModeInt() to apply correct mute
6273891c4cc918e8062abb97c542a8625d556dccc59Eric Laurent        // state on streams affected by ringer mode.
6283891c4cc918e8062abb97c542a8625d556dccc59Eric Laurent        mRingerModeMutedStreams = 0;
629661f2cf45860d2e10924e6b69966a9afe255f28bJohn Spurlock        setRingerModeInt(getRingerModeInternal(), false);
6303891c4cc918e8062abb97c542a8625d556dccc59Eric Laurent
631a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent        // Register for device connection intent broadcasts.
632a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent        IntentFilter intentFilter =
633b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent                new IntentFilter(BluetoothHeadset.ACTION_AUDIO_STATE_CHANGED);
63482aa7f017daaaeb96c13e6e3491d5037ab471085Jaikumar Ganesh        intentFilter.addAction(BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED);
63582aa7f017daaaeb96c13e6e3491d5037ab471085Jaikumar Ganesh        intentFilter.addAction(Intent.ACTION_DOCK_EVENT);
636c5258433dd353769ccfa2e5e769a7379378a3a0bJean-Michel Trivi        intentFilter.addAction(AudioManager.ACTION_USB_AUDIO_ACCESSORY_PLUG);
637c5258433dd353769ccfa2e5e769a7379378a3a0bJean-Michel Trivi        intentFilter.addAction(AudioManager.ACTION_USB_AUDIO_DEVICE_PLUG);
638950e8cb40a6d826af4cc2eef9d3908c1b70486e6Eric Laurent        intentFilter.addAction(Intent.ACTION_SCREEN_ON);
639950e8cb40a6d826af4cc2eef9d3908c1b70486e6Eric Laurent        intentFilter.addAction(Intent.ACTION_SCREEN_OFF);
640bc0fab1fc2db832ef86d8a33466ec4d68b103ca0Eric Laurent        intentFilter.addAction(Intent.ACTION_USER_SWITCHED);
641c837a451946b64d70ed7c642fbde03c182c28b6fPaul McLean        intentFilter.addAction(UsbManager.ACTION_USB_DEVICE_ATTACHED);
642f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi
643d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent        intentFilter.addAction(Intent.ACTION_CONFIGURATION_CHANGED);
644bb6f8711a7f804d39c45218db2d6339940cc5d35Jean-Michel Trivi        // TODO merge orientation and rotation
645d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent        mMonitorOrientation = SystemProperties.getBoolean("ro.audio.monitorOrientation", false);
646d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent        if (mMonitorOrientation) {
647f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi            Log.v(TAG, "monitoring device orientation");
648f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi            // initialize orientation in AudioSystem
649f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi            setOrientationForAudioSystem();
650f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi        }
651bb6f8711a7f804d39c45218db2d6339940cc5d35Jean-Michel Trivi        mMonitorRotation = SystemProperties.getBoolean("ro.audio.monitorRotation", false);
652bb6f8711a7f804d39c45218db2d6339940cc5d35Jean-Michel Trivi        if (mMonitorRotation) {
653bb6f8711a7f804d39c45218db2d6339940cc5d35Jean-Michel Trivi            mDeviceRotation = ((WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE))
654bb6f8711a7f804d39c45218db2d6339940cc5d35Jean-Michel Trivi                    .getDefaultDisplay().getRotation();
655bb6f8711a7f804d39c45218db2d6339940cc5d35Jean-Michel Trivi            Log.v(TAG, "monitoring device rotation, initial=" + mDeviceRotation);
656318f0fe43bdc4b2f6764edd91d6b78d9875ffdebJon Eklund
657318f0fe43bdc4b2f6764edd91d6b78d9875ffdebJon Eklund            mOrientationListener = new AudioOrientationEventListener(mContext);
658318f0fe43bdc4b2f6764edd91d6b78d9875ffdebJon Eklund            mOrientationListener.enable();
659318f0fe43bdc4b2f6764edd91d6b78d9875ffdebJon Eklund
660bb6f8711a7f804d39c45218db2d6339940cc5d35Jean-Michel Trivi            // initialize rotation in AudioSystem
661bb6f8711a7f804d39c45218db2d6339940cc5d35Jean-Michel Trivi            setRotationForAudioSystem();
662bb6f8711a7f804d39c45218db2d6339940cc5d35Jean-Michel Trivi        }
663f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi
664a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent        context.registerReceiver(mReceiver, intentFilter);
6655982013cfc8274ff0bafaba83c676b3a8890cba9Jared Suttles
6669063154a793b0ab38b3c5992cbaed046427b4a82Mike Lockwood        restoreMasterVolume();
6679760647dd0ee67e7c20f3e9d661d2006b1df0b54Mike Lockwood
6680dac35af2c6aa42bcd181981b041747cfd1afa5fRoboErik        LocalServices.addService(AudioManagerInternal.class, new AudioServiceInternal());
6699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
6709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6714a5eeb9c727d77bb57fef87a70c8c9cc23dbfee3Eric Laurent    public void systemReady() {
6724a5eeb9c727d77bb57fef87a70c8c9cc23dbfee3Eric Laurent        sendMsg(mAudioHandler, MSG_SYSTEM_READY, SENDMSG_QUEUE,
6734a5eeb9c727d77bb57fef87a70c8c9cc23dbfee3Eric Laurent                0, 0, null, 0);
6744a5eeb9c727d77bb57fef87a70c8c9cc23dbfee3Eric Laurent    }
6754a5eeb9c727d77bb57fef87a70c8c9cc23dbfee3Eric Laurent
6764a5eeb9c727d77bb57fef87a70c8c9cc23dbfee3Eric Laurent    public void onSystemReady() {
6774a5eeb9c727d77bb57fef87a70c8c9cc23dbfee3Eric Laurent        mSystemReady = true;
6784a5eeb9c727d77bb57fef87a70c8c9cc23dbfee3Eric Laurent        sendMsg(mAudioHandler, MSG_LOAD_SOUND_EFFECTS, SENDMSG_QUEUE,
6794a5eeb9c727d77bb57fef87a70c8c9cc23dbfee3Eric Laurent                0, 0, null, 0);
6804a5eeb9c727d77bb57fef87a70c8c9cc23dbfee3Eric Laurent
6814a5eeb9c727d77bb57fef87a70c8c9cc23dbfee3Eric Laurent        mKeyguardManager =
6824a5eeb9c727d77bb57fef87a70c8c9cc23dbfee3Eric Laurent                (KeyguardManager) mContext.getSystemService(Context.KEYGUARD_SERVICE);
6834a5eeb9c727d77bb57fef87a70c8c9cc23dbfee3Eric Laurent        mScoConnectionState = AudioManager.SCO_AUDIO_STATE_ERROR;
6844a5eeb9c727d77bb57fef87a70c8c9cc23dbfee3Eric Laurent        resetBluetoothSco();
6854a5eeb9c727d77bb57fef87a70c8c9cc23dbfee3Eric Laurent        getBluetoothHeadset();
6864a5eeb9c727d77bb57fef87a70c8c9cc23dbfee3Eric Laurent        //FIXME: this is to maintain compatibility with deprecated intent
6874a5eeb9c727d77bb57fef87a70c8c9cc23dbfee3Eric Laurent        // AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED. Remove when appropriate.
6884a5eeb9c727d77bb57fef87a70c8c9cc23dbfee3Eric Laurent        Intent newIntent = new Intent(AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED);
6894a5eeb9c727d77bb57fef87a70c8c9cc23dbfee3Eric Laurent        newIntent.putExtra(AudioManager.EXTRA_SCO_AUDIO_STATE,
6904a5eeb9c727d77bb57fef87a70c8c9cc23dbfee3Eric Laurent                AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
6914a5eeb9c727d77bb57fef87a70c8c9cc23dbfee3Eric Laurent        sendStickyBroadcastToAll(newIntent);
6924a5eeb9c727d77bb57fef87a70c8c9cc23dbfee3Eric Laurent
6934a5eeb9c727d77bb57fef87a70c8c9cc23dbfee3Eric Laurent        BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
6944a5eeb9c727d77bb57fef87a70c8c9cc23dbfee3Eric Laurent        if (adapter != null) {
6954a5eeb9c727d77bb57fef87a70c8c9cc23dbfee3Eric Laurent            adapter.getProfileProxy(mContext, mBluetoothProfileServiceListener,
6964a5eeb9c727d77bb57fef87a70c8c9cc23dbfee3Eric Laurent                                    BluetoothProfile.A2DP);
6974a5eeb9c727d77bb57fef87a70c8c9cc23dbfee3Eric Laurent        }
6984a5eeb9c727d77bb57fef87a70c8c9cc23dbfee3Eric Laurent
699212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent        mHdmiManager =
7007f4342e5b8e086fc96a4cb4d6df7e4d0bd3256baWonsik Kim                (HdmiControlManager) mContext.getSystemService(Context.HDMI_CONTROL_SERVICE);
701212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent        if (mHdmiManager != null) {
702212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent            synchronized (mHdmiManager) {
703212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent                mHdmiTvClient = mHdmiManager.getTvClient();
704c9ff968787d4744194f9985ebaf8ce7efdd12256Jungshik Jang                if (mHdmiTvClient != null) {
705c9ff968787d4744194f9985ebaf8ce7efdd12256Jungshik Jang                    mFixedVolumeDevices &= ~AudioSystem.DEVICE_ALL_HDMI_SYSTEM_AUDIO_AND_SPEAKER;
706c9ff968787d4744194f9985ebaf8ce7efdd12256Jungshik Jang                }
707212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent                mHdmiPlaybackClient = mHdmiManager.getPlaybackClient();
708212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent                mHdmiCecSink = false;
709212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent            }
710212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent        }
7117f4342e5b8e086fc96a4cb4d6df7e4d0bd3256baWonsik Kim
7124a5eeb9c727d77bb57fef87a70c8c9cc23dbfee3Eric Laurent        sendMsg(mAudioHandler,
7134a5eeb9c727d77bb57fef87a70c8c9cc23dbfee3Eric Laurent                MSG_CONFIGURE_SAFE_MEDIA_VOLUME_FORCED,
7144a5eeb9c727d77bb57fef87a70c8c9cc23dbfee3Eric Laurent                SENDMSG_REPLACE,
7154a5eeb9c727d77bb57fef87a70c8c9cc23dbfee3Eric Laurent                0,
7164a5eeb9c727d77bb57fef87a70c8c9cc23dbfee3Eric Laurent                0,
7174a5eeb9c727d77bb57fef87a70c8c9cc23dbfee3Eric Laurent                null,
7184a5eeb9c727d77bb57fef87a70c8c9cc23dbfee3Eric Laurent                SAFE_VOLUME_CONFIGURE_TIMEOUT_MS);
719873cc45da2463a11182fe94a2565364d7e1709bbJean-Michel Trivi
720873cc45da2463a11182fe94a2565364d7e1709bbJean-Michel Trivi        StreamOverride.init(mContext);
7214a5eeb9c727d77bb57fef87a70c8c9cc23dbfee3Eric Laurent    }
7224a5eeb9c727d77bb57fef87a70c8c9cc23dbfee3Eric Laurent
7239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private void createAudioSystemThread() {
7249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mAudioSystemThread = new AudioSystemThread();
7259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mAudioSystemThread.start();
7269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        waitForAudioHandlerCreation();
7279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
7289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** Waits for the volume handler to be created by the other thread. */
7309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private void waitForAudioHandlerCreation() {
7319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        synchronized(this) {
7329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            while (mAudioHandler == null) {
7339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                try {
7349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    // Wait for mAudioHandler to be set by the other thread
7359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    wait();
7369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                } catch (InterruptedException e) {
7379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    Log.e(TAG, "Interrupted while waiting on volume handler.");
7389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
7399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
7409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
7419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
7429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
743244820185269991186d07068b92985624cede4a5Eric Laurent    private void checkAllAliasStreamVolumes() {
7448fa4d6f585f40ff5cf5f9bed316d92c64a306f21Eric Laurent        synchronized (VolumeStreamState.class) {
7458fa4d6f585f40ff5cf5f9bed316d92c64a306f21Eric Laurent            int numStreamTypes = AudioSystem.getNumStreamTypes();
7468fa4d6f585f40ff5cf5f9bed316d92c64a306f21Eric Laurent            for (int streamType = 0; streamType < numStreamTypes; streamType++) {
7478fa4d6f585f40ff5cf5f9bed316d92c64a306f21Eric Laurent                if (streamType != mStreamVolumeAlias[streamType]) {
7488fa4d6f585f40ff5cf5f9bed316d92c64a306f21Eric Laurent                    mStreamStates[streamType].
74942b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                                    setAllIndexes(mStreamStates[mStreamVolumeAlias[streamType]]);
7508fa4d6f585f40ff5cf5f9bed316d92c64a306f21Eric Laurent                }
7518fa4d6f585f40ff5cf5f9bed316d92c64a306f21Eric Laurent                // apply stream volume
7528fa4d6f585f40ff5cf5f9bed316d92c64a306f21Eric Laurent                if (!mStreamStates[streamType].isMuted_syncVSS()) {
7538fa4d6f585f40ff5cf5f9bed316d92c64a306f21Eric Laurent                    mStreamStates[streamType].applyAllVolumes();
7548fa4d6f585f40ff5cf5f9bed316d92c64a306f21Eric Laurent                }
755244820185269991186d07068b92985624cede4a5Eric Laurent            }
756244820185269991186d07068b92985624cede4a5Eric Laurent        }
757244820185269991186d07068b92985624cede4a5Eric Laurent    }
758244820185269991186d07068b92985624cede4a5Eric Laurent
759212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent    private void checkAllFixedVolumeDevices()
760212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent    {
761212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent        int numStreamTypes = AudioSystem.getNumStreamTypes();
762212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent        for (int streamType = 0; streamType < numStreamTypes; streamType++) {
763212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent            mStreamStates[streamType].checkFixedVolumeDevices();
764212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent        }
765212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent    }
766212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent
767ba5270b88798c66fefc17a1b25b27894e4fb7862Jean-Michel Trivi    private void checkAllFixedVolumeDevices(int streamType) {
768ba5270b88798c66fefc17a1b25b27894e4fb7862Jean-Michel Trivi        mStreamStates[streamType].checkFixedVolumeDevices();
769ba5270b88798c66fefc17a1b25b27894e4fb7862Jean-Michel Trivi    }
770ba5270b88798c66fefc17a1b25b27894e4fb7862Jean-Michel Trivi
7719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private void createStreamStates() {
7729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int numStreamTypes = AudioSystem.getNumStreamTypes();
7739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        VolumeStreamState[] streams = mStreamStates = new VolumeStreamState[numStreamTypes];
7749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        for (int i = 0; i < numStreamTypes; i++) {
7766d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent            streams[i] = new VolumeStreamState(System.VOLUME_SETTINGS[mStreamVolumeAlias[i]], i);
7779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
7789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
779212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent        checkAllFixedVolumeDevices();
780244820185269991186d07068b92985624cede4a5Eric Laurent        checkAllAliasStreamVolumes();
7819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
7829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
783bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent    private void dumpStreamStates(PrintWriter pw) {
784bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent        pw.println("\nStream volumes (device: index)");
785bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent        int numStreamTypes = AudioSystem.getNumStreamTypes();
786bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent        for (int i = 0; i < numStreamTypes; i++) {
787bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent            pw.println("- "+STREAM_NAMES[i]+":");
788bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent            mStreamStates[i].dump(pw);
789bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent            pw.println("");
790bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent        }
791dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent        pw.print("\n- mute affected streams = 0x");
792dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent        pw.println(Integer.toHexString(mMuteAffectedStreams));
793bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent    }
794bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent
7951af30c7ac480e5d335f267a3ac3b2e6c748ce240John Spurlock    /** @hide */
7961af30c7ac480e5d335f267a3ac3b2e6c748ce240John Spurlock    public static String streamToString(int stream) {
7971af30c7ac480e5d335f267a3ac3b2e6c748ce240John Spurlock        if (stream >= 0 && stream < STREAM_NAMES.length) return STREAM_NAMES[stream];
7981af30c7ac480e5d335f267a3ac3b2e6c748ce240John Spurlock        if (stream == AudioManager.USE_DEFAULT_STREAM_TYPE) return "USE_DEFAULT_STREAM_TYPE";
7991af30c7ac480e5d335f267a3ac3b2e6c748ce240John Spurlock        return "UNKNOWN_STREAM_" + stream;
8001af30c7ac480e5d335f267a3ac3b2e6c748ce240John Spurlock    }
8016d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent
8026d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent    private void updateStreamVolumeAlias(boolean updateVolumes) {
8036d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent        int dtmfStreamAlias;
804212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent
805212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent        switch (mPlatformType) {
806212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent        case PLATFORM_VOICE:
807212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent            mStreamVolumeAlias = STREAM_VOLUME_ALIAS_VOICE;
8086d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent            dtmfStreamAlias = AudioSystem.STREAM_RING;
809212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent            break;
810212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent        case PLATFORM_TELEVISION:
811212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent            mStreamVolumeAlias = STREAM_VOLUME_ALIAS_TELEVISION;
812212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent            dtmfStreamAlias = AudioSystem.STREAM_MUSIC;
813212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent            break;
814212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent        default:
815212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent            mStreamVolumeAlias = STREAM_VOLUME_ALIAS_DEFAULT;
8166d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent            dtmfStreamAlias = AudioSystem.STREAM_MUSIC;
8176d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent        }
818212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent
819212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent        if (isPlatformTelevision()) {
820212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent            mRingerModeAffectedStreams = 0;
82124e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent        } else {
822212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent            if (isInCommunication()) {
823212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent                dtmfStreamAlias = AudioSystem.STREAM_VOICE_CALL;
824212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent                mRingerModeAffectedStreams &= ~(1 << AudioSystem.STREAM_DTMF);
825212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent            } else {
826212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent                mRingerModeAffectedStreams |= (1 << AudioSystem.STREAM_DTMF);
827212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent            }
8286d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent        }
829212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent
8306d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent        mStreamVolumeAlias[AudioSystem.STREAM_DTMF] = dtmfStreamAlias;
8316d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent        if (updateVolumes) {
83242b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent            mStreamStates[AudioSystem.STREAM_DTMF].setAllIndexes(mStreamStates[dtmfStreamAlias]);
83324e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent            // apply stream mute states according to new value of mRingerModeAffectedStreams
834661f2cf45860d2e10924e6b69966a9afe255f28bJohn Spurlock            setRingerModeInt(getRingerModeInternal(), false);
8356d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent            sendMsg(mAudioHandler,
8366d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent                    MSG_SET_ALL_VOLUMES,
8376d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent                    SENDMSG_QUEUE,
8386d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent                    0,
8396d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent                    0,
8406d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent                    mStreamStates[AudioSystem.STREAM_DTMF], 0);
8416d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent        }
8426d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent    }
8436d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent
8447ee1e4ff7346a278a6722108fbc1869240b3e866Eric Laurent    private void readDockAudioSettings(ContentResolver cr)
8457ee1e4ff7346a278a6722108fbc1869240b3e866Eric Laurent    {
8467ee1e4ff7346a278a6722108fbc1869240b3e866Eric Laurent        mDockAudioMediaEnabled = Settings.Global.getInt(
8475ba0ffa0237a5c300545e4c72591613c6e5b2ed9Eric Laurent                                        cr, Settings.Global.DOCK_AUDIO_MEDIA_ENABLED, 0) == 1;
8487ee1e4ff7346a278a6722108fbc1869240b3e866Eric Laurent
8497ee1e4ff7346a278a6722108fbc1869240b3e866Eric Laurent        if (mDockAudioMediaEnabled) {
8507ee1e4ff7346a278a6722108fbc1869240b3e866Eric Laurent            mBecomingNoisyIntentDevices |= AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET;
8517ee1e4ff7346a278a6722108fbc1869240b3e866Eric Laurent        } else {
8527ee1e4ff7346a278a6722108fbc1869240b3e866Eric Laurent            mBecomingNoisyIntentDevices &= ~AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET;
8537ee1e4ff7346a278a6722108fbc1869240b3e866Eric Laurent        }
8547ee1e4ff7346a278a6722108fbc1869240b3e866Eric Laurent
8557ee1e4ff7346a278a6722108fbc1869240b3e866Eric Laurent        sendMsg(mAudioHandler,
8567ee1e4ff7346a278a6722108fbc1869240b3e866Eric Laurent                MSG_SET_FORCE_USE,
8577ee1e4ff7346a278a6722108fbc1869240b3e866Eric Laurent                SENDMSG_QUEUE,
8587ee1e4ff7346a278a6722108fbc1869240b3e866Eric Laurent                AudioSystem.FOR_DOCK,
8597ee1e4ff7346a278a6722108fbc1869240b3e866Eric Laurent                mDockAudioMediaEnabled ?
8607ee1e4ff7346a278a6722108fbc1869240b3e866Eric Laurent                        AudioSystem.FORCE_ANALOG_DOCK : AudioSystem.FORCE_NONE,
8617ee1e4ff7346a278a6722108fbc1869240b3e866Eric Laurent                null,
8627ee1e4ff7346a278a6722108fbc1869240b3e866Eric Laurent                0);
8637ee1e4ff7346a278a6722108fbc1869240b3e866Eric Laurent    }
8647ee1e4ff7346a278a6722108fbc1869240b3e866Eric Laurent
8659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private void readPersistedSettings() {
8669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final ContentResolver cr = mContentResolver;
8679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
868bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent        int ringerModeFromSettings =
8698d9a1f66d9d3dbbd45a56d441a746ec11dba7645Jeff Sharkey                Settings.Global.getInt(
8708d9a1f66d9d3dbbd45a56d441a746ec11dba7645Jeff Sharkey                        cr, Settings.Global.MODE_RINGER, AudioManager.RINGER_MODE_NORMAL);
871bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent        int ringerMode = ringerModeFromSettings;
87272668b2c040b581b298b069f3b5af5ed7f212d89Eric Laurent        // sanity check in case the settings are restored from a device with incompatible
87372668b2c040b581b298b069f3b5af5ed7f212d89Eric Laurent        // ringer modes
8749755937ed90f06db45ff5fe4510950ae1516f8f9John Spurlock        if (!isValidRingerMode(ringerMode)) {
875ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten            ringerMode = AudioManager.RINGER_MODE_NORMAL;
876bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent        }
877bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent        if ((ringerMode == AudioManager.RINGER_MODE_VIBRATE) && !mHasVibrator) {
878bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent            ringerMode = AudioManager.RINGER_MODE_SILENT;
879bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent        }
880bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent        if (ringerMode != ringerModeFromSettings) {
8818d9a1f66d9d3dbbd45a56d441a746ec11dba7645Jeff Sharkey            Settings.Global.putInt(cr, Settings.Global.MODE_RINGER, ringerMode);
882ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten        }
883212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent        if (mUseFixedVolume || isPlatformTelevision()) {
88483a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent            ringerMode = AudioManager.RINGER_MODE_NORMAL;
88583a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent        }
886ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten        synchronized(mSettingsLock) {
887ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten            mRingerMode = ringerMode;
888661f2cf45860d2e10924e6b69966a9afe255f28bJohn Spurlock            if (mRingerModeExternal == -1) {
889661f2cf45860d2e10924e6b69966a9afe255f28bJohn Spurlock                mRingerModeExternal = mRingerMode;
890661f2cf45860d2e10924e6b69966a9afe255f28bJohn Spurlock            }
8919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
892dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent            // System.VIBRATE_ON is not used any more but defaults for mVibrateSetting
893dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent            // are still needed while setVibrateSetting() and getVibrateSetting() are being
894dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent            // deprecated.
895dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent            mVibrateSetting = getValueForVibrateSetting(0,
896dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent                                            AudioManager.VIBRATE_TYPE_NOTIFICATION,
897dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent                                            mHasVibrator ? AudioManager.VIBRATE_SETTING_ONLY_SILENT
898dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent                                                            : AudioManager.VIBRATE_SETTING_OFF);
899dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent            mVibrateSetting = getValueForVibrateSetting(mVibrateSetting,
900dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent                                            AudioManager.VIBRATE_TYPE_RINGER,
901dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent                                            mHasVibrator ? AudioManager.VIBRATE_SETTING_ONLY_SILENT
902dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent                                                            : AudioManager.VIBRATE_SETTING_OFF);
903dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent
90424e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent            updateRingerModeAffectedStreams();
9057ee1e4ff7346a278a6722108fbc1869240b3e866Eric Laurent            readDockAudioSettings(cr);
906402f7f29634a9f68e7929be828a927a3e2f5efe9Eric Laurent        }
907c1d4166289ce016965d1147f7e8d37862ee347ecEric Laurent
908bc0fab1fc2db832ef86d8a33466ec4d68b103ca0Eric Laurent        mMuteAffectedStreams = System.getIntForUser(cr,
9099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                System.MUTE_STREAMS_AFFECTED,
910bc0fab1fc2db832ef86d8a33466ec4d68b103ca0Eric Laurent                ((1 << AudioSystem.STREAM_MUSIC)|
911bc0fab1fc2db832ef86d8a33466ec4d68b103ca0Eric Laurent                 (1 << AudioSystem.STREAM_RING)|
912bc0fab1fc2db832ef86d8a33466ec4d68b103ca0Eric Laurent                 (1 << AudioSystem.STREAM_SYSTEM)),
913bc0fab1fc2db832ef86d8a33466ec4d68b103ca0Eric Laurent                 UserHandle.USER_CURRENT);
9149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
915bc0fab1fc2db832ef86d8a33466ec4d68b103ca0Eric Laurent        boolean masterMute = System.getIntForUser(cr, System.VOLUME_MASTER_MUTE,
916bc0fab1fc2db832ef86d8a33466ec4d68b103ca0Eric Laurent                                                  0, UserHandle.USER_CURRENT) == 1;
91783a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent        if (mUseFixedVolume) {
91883a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent            masterMute = false;
91983a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent            AudioSystem.setMasterVolume(1.0f);
92083a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent        }
92157978ed86286a33d5b1a0fd000ca3406ba9d87b3Justin Koh        AudioSystem.setMasterMute(masterMute);
92257978ed86286a33d5b1a0fd000ca3406ba9d87b3Justin Koh        broadcastMasterMuteStatus(masterMute);
92357978ed86286a33d5b1a0fd000ca3406ba9d87b3Justin Koh
924b53453fae037d67e421011936c8fdffe7ba43922Julia Reynolds        boolean microphoneMute =
925b53453fae037d67e421011936c8fdffe7ba43922Julia Reynolds                System.getIntForUser(cr, System.MICROPHONE_MUTE, 0, UserHandle.USER_CURRENT) == 1;
926b53453fae037d67e421011936c8fdffe7ba43922Julia Reynolds        AudioSystem.muteMicrophone(microphoneMute);
927b53453fae037d67e421011936c8fdffe7ba43922Julia Reynolds
9289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // Each stream will read its own persisted settings
9299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
930bcc1087af40a0e1bb35dbe8a39c830ecdea8280bJohn Spurlock        // Broadcast the sticky intents
931bcc1087af40a0e1bb35dbe8a39c830ecdea8280bJohn Spurlock        broadcastRingerMode(AudioManager.RINGER_MODE_CHANGED_ACTION, mRingerModeExternal);
932bcc1087af40a0e1bb35dbe8a39c830ecdea8280bJohn Spurlock        broadcastRingerMode(AudioManager.INTERNAL_RINGER_MODE_CHANGED_ACTION, mRingerMode);
9339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // Broadcast vibrate settings
9359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        broadcastVibrateSetting(AudioManager.VIBRATE_TYPE_RINGER);
9369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        broadcastVibrateSetting(AudioManager.VIBRATE_TYPE_NOTIFICATION);
937d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi
93833f4e04e32fac42f158733d6a731e50490fa9951John Spurlock        // Load settings for the volume controller
93933f4e04e32fac42f158733d6a731e50490fa9951John Spurlock        mVolumeController.loadSettings(cr);
9409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
9419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
942a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent    private int rescaleIndex(int index, int srcStream, int dstStream) {
943a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent        return (index * mStreamStates[dstStream].getMaxIndex() + mStreamStates[srcStream].getMaxIndex() / 2) / mStreamStates[srcStream].getMaxIndex();
944a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent    }
9459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
946318f0fe43bdc4b2f6764edd91d6b78d9875ffdebJon Eklund    private class AudioOrientationEventListener
947318f0fe43bdc4b2f6764edd91d6b78d9875ffdebJon Eklund            extends OrientationEventListener {
948318f0fe43bdc4b2f6764edd91d6b78d9875ffdebJon Eklund        public AudioOrientationEventListener(Context context) {
949318f0fe43bdc4b2f6764edd91d6b78d9875ffdebJon Eklund            super(context);
950318f0fe43bdc4b2f6764edd91d6b78d9875ffdebJon Eklund        }
951318f0fe43bdc4b2f6764edd91d6b78d9875ffdebJon Eklund
952318f0fe43bdc4b2f6764edd91d6b78d9875ffdebJon Eklund        @Override
953318f0fe43bdc4b2f6764edd91d6b78d9875ffdebJon Eklund        public void onOrientationChanged(int orientation) {
954318f0fe43bdc4b2f6764edd91d6b78d9875ffdebJon Eklund            //Even though we're responding to phone orientation events,
955318f0fe43bdc4b2f6764edd91d6b78d9875ffdebJon Eklund            //use display rotation so audio stays in sync with video/dialogs
956318f0fe43bdc4b2f6764edd91d6b78d9875ffdebJon Eklund            int newRotation = ((WindowManager) mContext.getSystemService(
957318f0fe43bdc4b2f6764edd91d6b78d9875ffdebJon Eklund                    Context.WINDOW_SERVICE)).getDefaultDisplay().getRotation();
958318f0fe43bdc4b2f6764edd91d6b78d9875ffdebJon Eklund            if (newRotation != mDeviceRotation) {
959318f0fe43bdc4b2f6764edd91d6b78d9875ffdebJon Eklund                mDeviceRotation = newRotation;
960318f0fe43bdc4b2f6764edd91d6b78d9875ffdebJon Eklund                setRotationForAudioSystem();
961318f0fe43bdc4b2f6764edd91d6b78d9875ffdebJon Eklund            }
962318f0fe43bdc4b2f6764edd91d6b78d9875ffdebJon Eklund        }
963318f0fe43bdc4b2f6764edd91d6b78d9875ffdebJon Eklund    }
964318f0fe43bdc4b2f6764edd91d6b78d9875ffdebJon Eklund
9659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    ///////////////////////////////////////////////////////////////////////////
9669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // IPC methods
9679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    ///////////////////////////////////////////////////////////////////////////
9689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** @see AudioManager#adjustVolume(int, int) */
969ba50b97cff80e73620a0e3d13cae169e095974a7Dianne Hackborn    public void adjustSuggestedStreamVolume(int direction, int suggestedStreamType, int flags,
970ba50b97cff80e73620a0e3d13cae169e095974a7Dianne Hackborn            String callingPackage) {
971272e161c1a200900cb10b5b0cdab8ae1f123cabdRoboErik        adjustSuggestedStreamVolume(direction, suggestedStreamType, flags, callingPackage,
972272e161c1a200900cb10b5b0cdab8ae1f123cabdRoboErik                Binder.getCallingUid());
973272e161c1a200900cb10b5b0cdab8ae1f123cabdRoboErik    }
974272e161c1a200900cb10b5b0cdab8ae1f123cabdRoboErik
975272e161c1a200900cb10b5b0cdab8ae1f123cabdRoboErik    private void adjustSuggestedStreamVolume(int direction, int suggestedStreamType, int flags,
976272e161c1a200900cb10b5b0cdab8ae1f123cabdRoboErik            String callingPackage, int uid) {
977ae641c9ccd3f81214cee54a5f13804f1765187adJohn Spurlock        if (DEBUG_VOL) Log.d(TAG, "adjustSuggestedStreamVolume() stream="+suggestedStreamType
978ae641c9ccd3f81214cee54a5f13804f1765187adJohn Spurlock                + ", flags=" + flags);
979402f7f29634a9f68e7929be828a927a3e2f5efe9Eric Laurent        int streamType;
98045c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent        if (mVolumeControlStream != -1) {
98145c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent            streamType = mVolumeControlStream;
982402f7f29634a9f68e7929be828a927a3e2f5efe9Eric Laurent        } else {
983402f7f29634a9f68e7929be828a927a3e2f5efe9Eric Laurent            streamType = getActiveStreamType(suggestedStreamType);
984402f7f29634a9f68e7929be828a927a3e2f5efe9Eric Laurent        }
98533f4e04e32fac42f158733d6a731e50490fa9951John Spurlock        final int resolvedStream = mStreamVolumeAlias[streamType];
9869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9872811dd337262934ea82477f9598f3e49092edb5eRoboErik        // Play sounds on STREAM_RING only.
9882811dd337262934ea82477f9598f3e49092edb5eRoboErik        if ((flags & AudioManager.FLAG_PLAY_SOUND) != 0 &&
98933f4e04e32fac42f158733d6a731e50490fa9951John Spurlock                resolvedStream != AudioSystem.STREAM_RING) {
99033f4e04e32fac42f158733d6a731e50490fa9951John Spurlock            flags &= ~AudioManager.FLAG_PLAY_SOUND;
99133f4e04e32fac42f158733d6a731e50490fa9951John Spurlock        }
99233f4e04e32fac42f158733d6a731e50490fa9951John Spurlock
99333f4e04e32fac42f158733d6a731e50490fa9951John Spurlock        // For notifications/ring, show the ui before making any adjustments
99433f4e04e32fac42f158733d6a731e50490fa9951John Spurlock        if (mVolumeController.suppressAdjustment(resolvedStream, flags)) {
99533f4e04e32fac42f158733d6a731e50490fa9951John Spurlock            direction = 0;
9969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            flags &= ~AudioManager.FLAG_PLAY_SOUND;
99733f4e04e32fac42f158733d6a731e50490fa9951John Spurlock            flags &= ~AudioManager.FLAG_VIBRATE;
99833f4e04e32fac42f158733d6a731e50490fa9951John Spurlock            if (DEBUG_VOL) Log.d(TAG, "Volume controller suppressed adjustment");
9999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
10009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1001272e161c1a200900cb10b5b0cdab8ae1f123cabdRoboErik        adjustStreamVolume(streamType, direction, flags, callingPackage, uid);
10029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
10039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** @see AudioManager#adjustStreamVolume(int, int, int) */
1005ba50b97cff80e73620a0e3d13cae169e095974a7Dianne Hackborn    public void adjustStreamVolume(int streamType, int direction, int flags,
1006ba50b97cff80e73620a0e3d13cae169e095974a7Dianne Hackborn            String callingPackage) {
10070dac35af2c6aa42bcd181981b041747cfd1afa5fRoboErik        adjustStreamVolume(streamType, direction, flags, callingPackage, Binder.getCallingUid());
10080dac35af2c6aa42bcd181981b041747cfd1afa5fRoboErik    }
10090dac35af2c6aa42bcd181981b041747cfd1afa5fRoboErik
10100dac35af2c6aa42bcd181981b041747cfd1afa5fRoboErik    private void adjustStreamVolume(int streamType, int direction, int flags,
10110dac35af2c6aa42bcd181981b041747cfd1afa5fRoboErik            String callingPackage, int uid) {
101283a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent        if (mUseFixedVolume) {
101383a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent            return;
101483a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent        }
1015ae641c9ccd3f81214cee54a5f13804f1765187adJohn Spurlock        if (DEBUG_VOL) Log.d(TAG, "adjustStreamVolume() stream="+streamType+", dir="+direction
1016ae641c9ccd3f81214cee54a5f13804f1765187adJohn Spurlock                + ", flags="+flags);
10173114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi
10189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        ensureValidDirection(direction);
10199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        ensureValidStreamType(streamType);
10209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
102196a33d1caad2fab0bc28891cfbf553f4b050bf0bEric Laurent        // use stream type alias here so that streams with same alias have the same behavior,
102296a33d1caad2fab0bc28891cfbf553f4b050bf0bEric Laurent        // including with regard to silent mode control (e.g the use of STREAM_RING below and in
102396a33d1caad2fab0bc28891cfbf553f4b050bf0bEric Laurent        // checkForRingerModeChange() in place of STREAM_RING or STREAM_NOTIFICATION)
10246d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent        int streamTypeAlias = mStreamVolumeAlias[streamType];
1025b024c30a80684ac08daef3137b7ba0d347fe3ce5Eric Laurent        VolumeStreamState streamState = mStreamStates[streamTypeAlias];
10269bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent
10279bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent        final int device = getDeviceForStream(streamTypeAlias);
10283ef7549876a159dae1568429edcb57e4e7d08459Eric Laurent
102942b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent        int aliasIndex = streamState.getIndex(device);
10309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        boolean adjustVolume = true;
10313ef7549876a159dae1568429edcb57e4e7d08459Eric Laurent        int step;
1032244820185269991186d07068b92985624cede4a5Eric Laurent
1033c9d1d5f35091226e96fcfa91817480f589eb36e2Matthew Xie        // skip a2dp absolute volume control request when the device
1034c9d1d5f35091226e96fcfa91817480f589eb36e2Matthew Xie        // is not an a2dp device
1035c9d1d5f35091226e96fcfa91817480f589eb36e2Matthew Xie        if ((device & AudioSystem.DEVICE_OUT_ALL_A2DP) == 0 &&
1036c9d1d5f35091226e96fcfa91817480f589eb36e2Matthew Xie            (flags & AudioManager.FLAG_BLUETOOTH_ABS_VOLUME) != 0) {
1037c9d1d5f35091226e96fcfa91817480f589eb36e2Matthew Xie            return;
1038c9d1d5f35091226e96fcfa91817480f589eb36e2Matthew Xie        }
1039c9d1d5f35091226e96fcfa91817480f589eb36e2Matthew Xie
10400dac35af2c6aa42bcd181981b041747cfd1afa5fRoboErik        if (mAppOps.noteOp(STEAM_VOLUME_OPS[streamTypeAlias], uid, callingPackage)
10410dac35af2c6aa42bcd181981b041747cfd1afa5fRoboErik                != AppOpsManager.MODE_ALLOWED) {
1042ba50b97cff80e73620a0e3d13cae169e095974a7Dianne Hackborn            return;
1043ba50b97cff80e73620a0e3d13cae169e095974a7Dianne Hackborn        }
1044ba50b97cff80e73620a0e3d13cae169e095974a7Dianne Hackborn
1045fde16d5879ea88a971004c984093409468b6139cEric Laurent        // reset any pending volume command
1046fde16d5879ea88a971004c984093409468b6139cEric Laurent        synchronized (mSafeMediaVolumeState) {
1047fde16d5879ea88a971004c984093409468b6139cEric Laurent            mPendingVolumeCommand = null;
1048fde16d5879ea88a971004c984093409468b6139cEric Laurent        }
1049fde16d5879ea88a971004c984093409468b6139cEric Laurent
10503ef7549876a159dae1568429edcb57e4e7d08459Eric Laurent        flags &= ~AudioManager.FLAG_FIXED_VOLUME;
10513ef7549876a159dae1568429edcb57e4e7d08459Eric Laurent        if ((streamTypeAlias == AudioSystem.STREAM_MUSIC) &&
10523ef7549876a159dae1568429edcb57e4e7d08459Eric Laurent               ((device & mFixedVolumeDevices) != 0)) {
10533ef7549876a159dae1568429edcb57e4e7d08459Eric Laurent            flags |= AudioManager.FLAG_FIXED_VOLUME;
10543ef7549876a159dae1568429edcb57e4e7d08459Eric Laurent
10553ef7549876a159dae1568429edcb57e4e7d08459Eric Laurent            // Always toggle between max safe volume and 0 for fixed volume devices where safe
10563ef7549876a159dae1568429edcb57e4e7d08459Eric Laurent            // volume is enforced, and max and 0 for the others.
10573ef7549876a159dae1568429edcb57e4e7d08459Eric Laurent            // This is simulated by stepping by the full allowed volume range
10583ef7549876a159dae1568429edcb57e4e7d08459Eric Laurent            if (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_ACTIVE &&
10593ef7549876a159dae1568429edcb57e4e7d08459Eric Laurent                    (device & mSafeMediaVolumeDevices) != 0) {
10603ef7549876a159dae1568429edcb57e4e7d08459Eric Laurent                step = mSafeMediaVolumeIndex;
10613ef7549876a159dae1568429edcb57e4e7d08459Eric Laurent            } else {
10623ef7549876a159dae1568429edcb57e4e7d08459Eric Laurent                step = streamState.getMaxIndex();
10633ef7549876a159dae1568429edcb57e4e7d08459Eric Laurent            }
10643ef7549876a159dae1568429edcb57e4e7d08459Eric Laurent            if (aliasIndex != 0) {
10653ef7549876a159dae1568429edcb57e4e7d08459Eric Laurent                aliasIndex = step;
10663ef7549876a159dae1568429edcb57e4e7d08459Eric Laurent            }
10673ef7549876a159dae1568429edcb57e4e7d08459Eric Laurent        } else {
10683ef7549876a159dae1568429edcb57e4e7d08459Eric Laurent            // convert one UI step (+/-1) into a number of internal units on the stream alias
10693ef7549876a159dae1568429edcb57e4e7d08459Eric Laurent            step = rescaleIndex(10, streamType, streamTypeAlias);
10703ef7549876a159dae1568429edcb57e4e7d08459Eric Laurent        }
10713ef7549876a159dae1568429edcb57e4e7d08459Eric Laurent
107242b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent        // If either the client forces allowing ringer modes for this adjustment,
107342b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent        // or the stream type is one that is affected by ringer modes
107442b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent        if (((flags & AudioManager.FLAG_ALLOW_RINGER_MODES) != 0) ||
107542b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                (streamTypeAlias == getMasterStreamType())) {
1076661f2cf45860d2e10924e6b69966a9afe255f28bJohn Spurlock            int ringerMode = getRingerModeInternal();
107742b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent            // do not vibrate if already in vibrate mode
107842b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent            if (ringerMode == AudioManager.RINGER_MODE_VIBRATE) {
107942b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                flags &= ~AudioManager.FLAG_VIBRATE;
108042b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent            }
108142b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent            // Check if the ringer mode changes with this volume adjustment. If
108242b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent            // it does, it will handle adjusting the volume, so we won't below
1083a11b4affcad3d255aa723a89b768ea222506f2e8John Spurlock            final int result = checkForRingerModeChange(aliasIndex, direction, step);
1084a11b4affcad3d255aa723a89b768ea222506f2e8John Spurlock            adjustVolume = (result & FLAG_ADJUST_VOLUME) != 0;
1085a11b4affcad3d255aa723a89b768ea222506f2e8John Spurlock            // If suppressing a volume adjustment in silent mode, display the UI hint
1086a11b4affcad3d255aa723a89b768ea222506f2e8John Spurlock            if ((result & AudioManager.FLAG_SHOW_SILENT_HINT) != 0) {
1087a11b4affcad3d255aa723a89b768ea222506f2e8John Spurlock                flags |= AudioManager.FLAG_SHOW_SILENT_HINT;
1088a11b4affcad3d255aa723a89b768ea222506f2e8John Spurlock            }
1089661f2cf45860d2e10924e6b69966a9afe255f28bJohn Spurlock            // If suppressing a volume down adjustment in vibrate mode, display the UI hint
1090661f2cf45860d2e10924e6b69966a9afe255f28bJohn Spurlock            if ((result & AudioManager.FLAG_SHOW_VIBRATE_HINT) != 0) {
1091661f2cf45860d2e10924e6b69966a9afe255f28bJohn Spurlock                flags |= AudioManager.FLAG_SHOW_VIBRATE_HINT;
1092661f2cf45860d2e10924e6b69966a9afe255f28bJohn Spurlock            }
109342b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent        }
109442b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent
109542b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent        int oldIndex = mStreamStates[streamType].getIndex(device);
109642b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent
109742b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent        if (adjustVolume && (direction != AudioManager.ADJUST_SAME)) {
1098c9d1d5f35091226e96fcfa91817480f589eb36e2Matthew Xie
10995a0cf7a27f3953a1266af48543ccd9024f4cd89fJohn Du            // Check if volume update should be send to AVRCP
1100c9d1d5f35091226e96fcfa91817480f589eb36e2Matthew Xie            if (streamTypeAlias == AudioSystem.STREAM_MUSIC &&
1101c9d1d5f35091226e96fcfa91817480f589eb36e2Matthew Xie                (device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0 &&
1102c9d1d5f35091226e96fcfa91817480f589eb36e2Matthew Xie                (flags & AudioManager.FLAG_BLUETOOTH_ABS_VOLUME) == 0) {
1103c9d1d5f35091226e96fcfa91817480f589eb36e2Matthew Xie                synchronized (mA2dpAvrcpLock) {
1104c9d1d5f35091226e96fcfa91817480f589eb36e2Matthew Xie                    if (mA2dp != null && mAvrcpAbsVolSupported) {
1105c9d1d5f35091226e96fcfa91817480f589eb36e2Matthew Xie                        mA2dp.adjustAvrcpAbsoluteVolume(direction);
1106c9d1d5f35091226e96fcfa91817480f589eb36e2Matthew Xie                    }
11075a0cf7a27f3953a1266af48543ccd9024f4cd89fJohn Du                }
11085a0cf7a27f3953a1266af48543ccd9024f4cd89fJohn Du            }
1109c9d1d5f35091226e96fcfa91817480f589eb36e2Matthew Xie
111042b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent            if ((direction == AudioManager.ADJUST_RAISE) &&
111142b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                    !checkSafeMediaVolume(streamTypeAlias, aliasIndex + step, device)) {
111242b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                Log.e(TAG, "adjustStreamVolume() safe volume index = "+oldIndex);
11133346a802087f621c6441bc512dfcc17b07143fc6John Spurlock                mVolumeController.postDisplaySafeVolumeWarning(flags);
111442b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent            } else if (streamState.adjustIndex(direction * step, device)) {
111542b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                // Post message to set system volume (it in turn will post a message
111642b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                // to persist). Do not change volume if stream is muted.
111742b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                sendMsg(mAudioHandler,
111842b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                        MSG_SET_DEVICE_VOLUME,
111942b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                        SENDMSG_QUEUE,
112042b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                        device,
112142b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                        0,
112242b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                        streamState,
112342b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                        0);
11244bbcc6549738f3d69831b2bd9eb4accec3e9920eEric Laurent            }
112541d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang
112641d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang            // Check if volume update should be send to Hdmi system audio.
112741d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang            int newIndex = mStreamStates[streamType].getIndex(device);
1128336cdb488ff0e5ec6709c66f55072d3ad22b82edJinsuk Kim            if (streamTypeAlias == AudioSystem.STREAM_MUSIC) {
1129336cdb488ff0e5ec6709c66f55072d3ad22b82edJinsuk Kim                setSystemAudioVolume(oldIndex, newIndex, getStreamMaxVolume(streamType), flags);
1130336cdb488ff0e5ec6709c66f55072d3ad22b82edJinsuk Kim            }
1131212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent            if (mHdmiManager != null) {
1132212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent                synchronized (mHdmiManager) {
1133212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent                    // mHdmiCecSink true => mHdmiPlaybackClient != null
1134212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent                    if (mHdmiCecSink &&
1135212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent                            streamTypeAlias == AudioSystem.STREAM_MUSIC &&
1136212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent                            oldIndex != newIndex) {
1137212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent                        synchronized (mHdmiPlaybackClient) {
1138212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent                            int keyCode = (direction == -1) ? KeyEvent.KEYCODE_VOLUME_DOWN :
1139212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent                                                               KeyEvent.KEYCODE_VOLUME_UP;
1140212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent                            mHdmiPlaybackClient.sendKeyEvent(keyCode, true);
1141212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent                            mHdmiPlaybackClient.sendKeyEvent(keyCode, false);
1142212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent                        }
114341d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang                    }
114441d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang                }
114541d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang            }
11464bbcc6549738f3d69831b2bd9eb4accec3e9920eEric Laurent        }
114742b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent        int index = mStreamStates[streamType].getIndex(device);
114825101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent        sendVolumeUpdate(streamType, oldIndex, index, flags);
11499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
11509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1151336cdb488ff0e5ec6709c66f55072d3ad22b82edJinsuk Kim    private void setSystemAudioVolume(int oldVolume, int newVolume, int maxVolume, int flags) {
1152336cdb488ff0e5ec6709c66f55072d3ad22b82edJinsuk Kim        if (mHdmiManager == null
1153336cdb488ff0e5ec6709c66f55072d3ad22b82edJinsuk Kim                || mHdmiTvClient == null
1154336cdb488ff0e5ec6709c66f55072d3ad22b82edJinsuk Kim                || oldVolume == newVolume
1155336cdb488ff0e5ec6709c66f55072d3ad22b82edJinsuk Kim                || (flags & AudioManager.FLAG_HDMI_SYSTEM_AUDIO_VOLUME) != 0) return;
1156336cdb488ff0e5ec6709c66f55072d3ad22b82edJinsuk Kim
1157336cdb488ff0e5ec6709c66f55072d3ad22b82edJinsuk Kim        // Sets the audio volume of AVR when we are in system audio mode. The new volume info
1158336cdb488ff0e5ec6709c66f55072d3ad22b82edJinsuk Kim        // is tranformed to HDMI-CEC commands and passed through CEC bus.
1159336cdb488ff0e5ec6709c66f55072d3ad22b82edJinsuk Kim        synchronized (mHdmiManager) {
1160336cdb488ff0e5ec6709c66f55072d3ad22b82edJinsuk Kim            if (!mHdmiSystemAudioSupported) return;
1161336cdb488ff0e5ec6709c66f55072d3ad22b82edJinsuk Kim            synchronized (mHdmiTvClient) {
116248cbf292ba9ad550af7e44d950a441b1812428e2Jinsuk Kim                final long token = Binder.clearCallingIdentity();
116348cbf292ba9ad550af7e44d950a441b1812428e2Jinsuk Kim                try {
116448cbf292ba9ad550af7e44d950a441b1812428e2Jinsuk Kim                    mHdmiTvClient.setSystemAudioVolume(
116548cbf292ba9ad550af7e44d950a441b1812428e2Jinsuk Kim                            (oldVolume + 5) / 10, (newVolume + 5) / 10, maxVolume);
116648cbf292ba9ad550af7e44d950a441b1812428e2Jinsuk Kim                } finally {
116748cbf292ba9ad550af7e44d950a441b1812428e2Jinsuk Kim                    Binder.restoreCallingIdentity(token);
116848cbf292ba9ad550af7e44d950a441b1812428e2Jinsuk Kim                }
1169336cdb488ff0e5ec6709c66f55072d3ad22b82edJinsuk Kim            }
1170336cdb488ff0e5ec6709c66f55072d3ad22b82edJinsuk Kim        }
1171336cdb488ff0e5ec6709c66f55072d3ad22b82edJinsuk Kim    }
1172336cdb488ff0e5ec6709c66f55072d3ad22b82edJinsuk Kim
1173961cae92540763226648813d111c5b5c3b0f1597Dianne Hackborn    /** @see AudioManager#adjustMasterVolume(int, int) */
1174ba50b97cff80e73620a0e3d13cae169e095974a7Dianne Hackborn    public void adjustMasterVolume(int steps, int flags, String callingPackage) {
1175519c7744b522aa07e12bc3244ac3de14aa2a4ad0RoboErik        adjustMasterVolume(steps, flags, callingPackage, Binder.getCallingUid());
1176519c7744b522aa07e12bc3244ac3de14aa2a4ad0RoboErik    }
1177519c7744b522aa07e12bc3244ac3de14aa2a4ad0RoboErik
1178519c7744b522aa07e12bc3244ac3de14aa2a4ad0RoboErik    public void adjustMasterVolume(int steps, int flags, String callingPackage, int uid) {
117983a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent        if (mUseFixedVolume) {
118083a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent            return;
118183a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent        }
11826c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang        ensureValidSteps(steps);
11839760647dd0ee67e7c20f3e9d661d2006b1df0b54Mike Lockwood        int volume = Math.round(AudioSystem.getMasterVolume() * MAX_MASTER_VOLUME);
11849760647dd0ee67e7c20f3e9d661d2006b1df0b54Mike Lockwood        int delta = 0;
11856c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang        int numSteps = Math.abs(steps);
11866c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang        int direction = steps > 0 ? AudioManager.ADJUST_RAISE : AudioManager.ADJUST_LOWER;
11876c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang        for (int i = 0; i < numSteps; ++i) {
11886c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang            delta = findVolumeDelta(direction, volume);
11896c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang            volume += delta;
1190cbdb49dc5e1b993a0bc5c68dbfb9486bfa0cd762Mike Lockwood        }
119124b082f87e96c00d5c17d60c735423900be40e70RoboErik
11926c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang        //Log.d(TAG, "adjustMasterVolume volume: " + volume + " steps: " + steps);
1193519c7744b522aa07e12bc3244ac3de14aa2a4ad0RoboErik        setMasterVolume(volume, flags, callingPackage, uid);
1194cbdb49dc5e1b993a0bc5c68dbfb9486bfa0cd762Mike Lockwood    }
1195cbdb49dc5e1b993a0bc5c68dbfb9486bfa0cd762Mike Lockwood
1196fde16d5879ea88a971004c984093409468b6139cEric Laurent    // StreamVolumeCommand contains the information needed to defer the process of
1197fde16d5879ea88a971004c984093409468b6139cEric Laurent    // setStreamVolume() in case the user has to acknowledge the safe volume warning message.
1198fde16d5879ea88a971004c984093409468b6139cEric Laurent    class StreamVolumeCommand {
1199fde16d5879ea88a971004c984093409468b6139cEric Laurent        public final int mStreamType;
1200fde16d5879ea88a971004c984093409468b6139cEric Laurent        public final int mIndex;
1201fde16d5879ea88a971004c984093409468b6139cEric Laurent        public final int mFlags;
1202fde16d5879ea88a971004c984093409468b6139cEric Laurent        public final int mDevice;
12033ef7549876a159dae1568429edcb57e4e7d08459Eric Laurent
1204fde16d5879ea88a971004c984093409468b6139cEric Laurent        StreamVolumeCommand(int streamType, int index, int flags, int device) {
1205fde16d5879ea88a971004c984093409468b6139cEric Laurent            mStreamType = streamType;
1206fde16d5879ea88a971004c984093409468b6139cEric Laurent            mIndex = index;
1207fde16d5879ea88a971004c984093409468b6139cEric Laurent            mFlags = flags;
1208fde16d5879ea88a971004c984093409468b6139cEric Laurent            mDevice = device;
12094bbcc6549738f3d69831b2bd9eb4accec3e9920eEric Laurent        }
1210351346092acdfbfcc1d9ebf98d539d2a1196c5e8John Spurlock
1211351346092acdfbfcc1d9ebf98d539d2a1196c5e8John Spurlock        @Override
1212351346092acdfbfcc1d9ebf98d539d2a1196c5e8John Spurlock        public String toString() {
1213351346092acdfbfcc1d9ebf98d539d2a1196c5e8John Spurlock            return new StringBuilder().append("{streamType=").append(mStreamType).append(",index=")
1214351346092acdfbfcc1d9ebf98d539d2a1196c5e8John Spurlock                    .append(mIndex).append(",flags=").append(mFlags).append(",device=")
1215351346092acdfbfcc1d9ebf98d539d2a1196c5e8John Spurlock                    .append(mDevice).append('}').toString();
1216351346092acdfbfcc1d9ebf98d539d2a1196c5e8John Spurlock        }
1217fde16d5879ea88a971004c984093409468b6139cEric Laurent    };
12183ef7549876a159dae1568429edcb57e4e7d08459Eric Laurent
1219fde16d5879ea88a971004c984093409468b6139cEric Laurent    private void onSetStreamVolume(int streamType, int index, int flags, int device) {
122042b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent        setStreamVolumeInt(mStreamVolumeAlias[streamType], index, device, false);
12213ef7549876a159dae1568429edcb57e4e7d08459Eric Laurent        // setting volume on master stream type also controls silent mode
12223ef7549876a159dae1568429edcb57e4e7d08459Eric Laurent        if (((flags & AudioManager.FLAG_ALLOW_RINGER_MODES) != 0) ||
12233ef7549876a159dae1568429edcb57e4e7d08459Eric Laurent                (mStreamVolumeAlias[streamType] == getMasterStreamType())) {
12243ef7549876a159dae1568429edcb57e4e7d08459Eric Laurent            int newRingerMode;
12253ef7549876a159dae1568429edcb57e4e7d08459Eric Laurent            if (index == 0) {
12263ef7549876a159dae1568429edcb57e4e7d08459Eric Laurent                newRingerMode = mHasVibrator ? AudioManager.RINGER_MODE_VIBRATE
12278600534df66c2ff5846ed230b50c56229322d48aJohn Spurlock                        : VOLUME_SETS_RINGER_MODE_SILENT ? AudioManager.RINGER_MODE_SILENT
12288600534df66c2ff5846ed230b50c56229322d48aJohn Spurlock                        : AudioManager.RINGER_MODE_NORMAL;
12293ef7549876a159dae1568429edcb57e4e7d08459Eric Laurent            } else {
12303ef7549876a159dae1568429edcb57e4e7d08459Eric Laurent                newRingerMode = AudioManager.RINGER_MODE_NORMAL;
12313ef7549876a159dae1568429edcb57e4e7d08459Eric Laurent            }
1232661f2cf45860d2e10924e6b69966a9afe255f28bJohn Spurlock            setRingerMode(newRingerMode, TAG + ".onSetStreamVolume", false /*external*/);
12333ef7549876a159dae1568429edcb57e4e7d08459Eric Laurent        }
1234fde16d5879ea88a971004c984093409468b6139cEric Laurent    }
1235fde16d5879ea88a971004c984093409468b6139cEric Laurent
1236fde16d5879ea88a971004c984093409468b6139cEric Laurent    /** @see AudioManager#setStreamVolume(int, int, int) */
1237ba50b97cff80e73620a0e3d13cae169e095974a7Dianne Hackborn    public void setStreamVolume(int streamType, int index, int flags, String callingPackage) {
12380dac35af2c6aa42bcd181981b041747cfd1afa5fRoboErik        setStreamVolume(streamType, index, flags, callingPackage, Binder.getCallingUid());
12390dac35af2c6aa42bcd181981b041747cfd1afa5fRoboErik    }
12400dac35af2c6aa42bcd181981b041747cfd1afa5fRoboErik
12410dac35af2c6aa42bcd181981b041747cfd1afa5fRoboErik    private void setStreamVolume(int streamType, int index, int flags, String callingPackage,
12420dac35af2c6aa42bcd181981b041747cfd1afa5fRoboErik            int uid) {
124383a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent        if (mUseFixedVolume) {
124483a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent            return;
124583a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent        }
124683a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent
1247fde16d5879ea88a971004c984093409468b6139cEric Laurent        ensureValidStreamType(streamType);
1248ba50b97cff80e73620a0e3d13cae169e095974a7Dianne Hackborn        int streamTypeAlias = mStreamVolumeAlias[streamType];
1249ba50b97cff80e73620a0e3d13cae169e095974a7Dianne Hackborn        VolumeStreamState streamState = mStreamStates[streamTypeAlias];
1250fde16d5879ea88a971004c984093409468b6139cEric Laurent
1251fde16d5879ea88a971004c984093409468b6139cEric Laurent        final int device = getDeviceForStream(streamType);
1252fde16d5879ea88a971004c984093409468b6139cEric Laurent        int oldIndex;
1253fde16d5879ea88a971004c984093409468b6139cEric Laurent
1254c9d1d5f35091226e96fcfa91817480f589eb36e2Matthew Xie        // skip a2dp absolute volume control request when the device
1255c9d1d5f35091226e96fcfa91817480f589eb36e2Matthew Xie        // is not an a2dp device
1256c9d1d5f35091226e96fcfa91817480f589eb36e2Matthew Xie        if ((device & AudioSystem.DEVICE_OUT_ALL_A2DP) == 0 &&
1257c9d1d5f35091226e96fcfa91817480f589eb36e2Matthew Xie            (flags & AudioManager.FLAG_BLUETOOTH_ABS_VOLUME) != 0) {
1258c9d1d5f35091226e96fcfa91817480f589eb36e2Matthew Xie            return;
1259c9d1d5f35091226e96fcfa91817480f589eb36e2Matthew Xie        }
1260c9d1d5f35091226e96fcfa91817480f589eb36e2Matthew Xie
12610dac35af2c6aa42bcd181981b041747cfd1afa5fRoboErik        if (mAppOps.noteOp(STEAM_VOLUME_OPS[streamTypeAlias], uid, callingPackage)
12620dac35af2c6aa42bcd181981b041747cfd1afa5fRoboErik                != AppOpsManager.MODE_ALLOWED) {
1263ba50b97cff80e73620a0e3d13cae169e095974a7Dianne Hackborn            return;
1264ba50b97cff80e73620a0e3d13cae169e095974a7Dianne Hackborn        }
1265ba50b97cff80e73620a0e3d13cae169e095974a7Dianne Hackborn
1266fde16d5879ea88a971004c984093409468b6139cEric Laurent        synchronized (mSafeMediaVolumeState) {
1267fde16d5879ea88a971004c984093409468b6139cEric Laurent            // reset any pending volume command
1268fde16d5879ea88a971004c984093409468b6139cEric Laurent            mPendingVolumeCommand = null;
1269fde16d5879ea88a971004c984093409468b6139cEric Laurent
127042b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent            oldIndex = streamState.getIndex(device);
1271fde16d5879ea88a971004c984093409468b6139cEric Laurent
1272ba50b97cff80e73620a0e3d13cae169e095974a7Dianne Hackborn            index = rescaleIndex(index * 10, streamType, streamTypeAlias);
1273fde16d5879ea88a971004c984093409468b6139cEric Laurent
1274c9d1d5f35091226e96fcfa91817480f589eb36e2Matthew Xie            if (streamTypeAlias == AudioSystem.STREAM_MUSIC &&
1275c9d1d5f35091226e96fcfa91817480f589eb36e2Matthew Xie                (device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0 &&
1276c9d1d5f35091226e96fcfa91817480f589eb36e2Matthew Xie                (flags & AudioManager.FLAG_BLUETOOTH_ABS_VOLUME) == 0) {
1277c9d1d5f35091226e96fcfa91817480f589eb36e2Matthew Xie                synchronized (mA2dpAvrcpLock) {
1278c9d1d5f35091226e96fcfa91817480f589eb36e2Matthew Xie                    if (mA2dp != null && mAvrcpAbsVolSupported) {
12792f4a2b139b4c1dde7be1d14333ad02553734c528Zhihai Xu                        mA2dp.setAvrcpAbsoluteVolume(index / 10);
1280c9d1d5f35091226e96fcfa91817480f589eb36e2Matthew Xie                    }
12815a0cf7a27f3953a1266af48543ccd9024f4cd89fJohn Du                }
12825a0cf7a27f3953a1266af48543ccd9024f4cd89fJohn Du            }
12835a0cf7a27f3953a1266af48543ccd9024f4cd89fJohn Du
1284336cdb488ff0e5ec6709c66f55072d3ad22b82edJinsuk Kim            if (streamTypeAlias == AudioSystem.STREAM_MUSIC) {
1285336cdb488ff0e5ec6709c66f55072d3ad22b82edJinsuk Kim                setSystemAudioVolume(oldIndex, index, getStreamMaxVolume(streamType), flags);
128641d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang            }
128741d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang
1288fde16d5879ea88a971004c984093409468b6139cEric Laurent            flags &= ~AudioManager.FLAG_FIXED_VOLUME;
1289ba50b97cff80e73620a0e3d13cae169e095974a7Dianne Hackborn            if ((streamTypeAlias == AudioSystem.STREAM_MUSIC) &&
1290fde16d5879ea88a971004c984093409468b6139cEric Laurent                    ((device & mFixedVolumeDevices) != 0)) {
1291fde16d5879ea88a971004c984093409468b6139cEric Laurent                flags |= AudioManager.FLAG_FIXED_VOLUME;
1292fde16d5879ea88a971004c984093409468b6139cEric Laurent
1293fde16d5879ea88a971004c984093409468b6139cEric Laurent                // volume is either 0 or max allowed for fixed volume devices
1294fde16d5879ea88a971004c984093409468b6139cEric Laurent                if (index != 0) {
1295fde16d5879ea88a971004c984093409468b6139cEric Laurent                    if (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_ACTIVE &&
1296fde16d5879ea88a971004c984093409468b6139cEric Laurent                            (device & mSafeMediaVolumeDevices) != 0) {
1297fde16d5879ea88a971004c984093409468b6139cEric Laurent                        index = mSafeMediaVolumeIndex;
1298fde16d5879ea88a971004c984093409468b6139cEric Laurent                    } else {
1299fde16d5879ea88a971004c984093409468b6139cEric Laurent                        index = streamState.getMaxIndex();
1300fde16d5879ea88a971004c984093409468b6139cEric Laurent                    }
1301fde16d5879ea88a971004c984093409468b6139cEric Laurent                }
1302fde16d5879ea88a971004c984093409468b6139cEric Laurent            }
1303fde16d5879ea88a971004c984093409468b6139cEric Laurent
1304ba50b97cff80e73620a0e3d13cae169e095974a7Dianne Hackborn            if (!checkSafeMediaVolume(streamTypeAlias, index, device)) {
13053346a802087f621c6441bc512dfcc17b07143fc6John Spurlock                mVolumeController.postDisplaySafeVolumeWarning(flags);
1306fde16d5879ea88a971004c984093409468b6139cEric Laurent                mPendingVolumeCommand = new StreamVolumeCommand(
1307fde16d5879ea88a971004c984093409468b6139cEric Laurent                                                    streamType, index, flags, device);
1308fde16d5879ea88a971004c984093409468b6139cEric Laurent            } else {
1309fde16d5879ea88a971004c984093409468b6139cEric Laurent                onSetStreamVolume(streamType, index, flags, device);
131042b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                index = mStreamStates[streamType].getIndex(device);
1311fde16d5879ea88a971004c984093409468b6139cEric Laurent            }
1312fde16d5879ea88a971004c984093409468b6139cEric Laurent        }
131325101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent        sendVolumeUpdate(streamType, oldIndex, index, flags);
13149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
13159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
131645c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent    /** @see AudioManager#forceVolumeControlStream(int) */
131745c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent    public void forceVolumeControlStream(int streamType, IBinder cb) {
131845c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent        synchronized(mForceControlStreamLock) {
131945c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent            mVolumeControlStream = streamType;
132045c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent            if (mVolumeControlStream == -1) {
132145c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent                if (mForceControlStreamClient != null) {
132245c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent                    mForceControlStreamClient.release();
132345c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent                    mForceControlStreamClient = null;
132445c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent                }
132545c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent            } else {
132645c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent                mForceControlStreamClient = new ForceControlStreamClient(cb);
132745c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent            }
132845c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent        }
132945c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent    }
133045c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent
133145c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent    private class ForceControlStreamClient implements IBinder.DeathRecipient {
133245c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent        private IBinder mCb; // To be notified of client's death
133345c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent
133445c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent        ForceControlStreamClient(IBinder cb) {
133545c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent            if (cb != null) {
133645c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent                try {
133745c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent                    cb.linkToDeath(this, 0);
133845c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent                } catch (RemoteException e) {
133945c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent                    // Client has died!
134045c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent                    Log.w(TAG, "ForceControlStreamClient() could not link to "+cb+" binder death");
134145c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent                    cb = null;
134245c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent                }
134345c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent            }
134445c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent            mCb = cb;
134545c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent        }
134645c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent
134745c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent        public void binderDied() {
134845c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent            synchronized(mForceControlStreamLock) {
134945c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent                Log.w(TAG, "SCO client died");
135045c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent                if (mForceControlStreamClient != this) {
135145c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent                    Log.w(TAG, "unregistered control stream client died");
135245c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent                } else {
135345c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent                    mForceControlStreamClient = null;
135445c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent                    mVolumeControlStream = -1;
135545c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent                }
135645c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent            }
135745c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent        }
135845c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent
135945c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent        public void release() {
136045c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent            if (mCb != null) {
136145c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent                mCb.unlinkToDeath(this, 0);
136245c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent                mCb = null;
136345c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent            }
136445c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent        }
136545c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent    }
136645c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent
13676c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang    private int findVolumeDelta(int direction, int volume) {
13686c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang        int delta = 0;
13696c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang        if (direction == AudioManager.ADJUST_RAISE) {
13706c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang            if (volume == MAX_MASTER_VOLUME) {
13716c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang                return 0;
13726c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang            }
13736c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang            // This is the default value if we make it to the end
13746c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang            delta = mMasterVolumeRamp[1];
13756c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang            // If we're raising the volume move down the ramp array until we
13766c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang            // find the volume we're above and use that groups delta.
13776c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang            for (int i = mMasterVolumeRamp.length - 1; i > 1; i -= 2) {
13786c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang                if (volume >= mMasterVolumeRamp[i - 1]) {
13796c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang                    delta = mMasterVolumeRamp[i];
13806c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang                    break;
13816c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang                }
13826c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang            }
13836c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang        } else if (direction == AudioManager.ADJUST_LOWER){
13846c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang            if (volume == 0) {
13856c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang                return 0;
13866c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang            }
13876c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang            int length = mMasterVolumeRamp.length;
13886c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang            // This is the default value if we make it to the end
13896c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang            delta = -mMasterVolumeRamp[length - 1];
13906c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang            // If we're lowering the volume move up the ramp array until we
13916c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang            // find the volume we're below and use the group below it's delta
13926c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang            for (int i = 2; i < length; i += 2) {
13936c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang                if (volume <= mMasterVolumeRamp[i]) {
13946c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang                    delta = -mMasterVolumeRamp[i - 1];
13956c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang                    break;
13966c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang                }
13976c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang            }
13986c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang        }
13996c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang        return delta;
14006c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang    }
14016c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang
14025ac72a29593ab9a20337a2225df52bdf4754be02Dianne Hackborn    private void sendBroadcastToAll(Intent intent) {
14035ac72a29593ab9a20337a2225df52bdf4754be02Dianne Hackborn        final long ident = Binder.clearCallingIdentity();
14045ac72a29593ab9a20337a2225df52bdf4754be02Dianne Hackborn        try {
14055ac72a29593ab9a20337a2225df52bdf4754be02Dianne Hackborn            mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
14065ac72a29593ab9a20337a2225df52bdf4754be02Dianne Hackborn        } finally {
14075ac72a29593ab9a20337a2225df52bdf4754be02Dianne Hackborn            Binder.restoreCallingIdentity(ident);
14085ac72a29593ab9a20337a2225df52bdf4754be02Dianne Hackborn        }
14095ac72a29593ab9a20337a2225df52bdf4754be02Dianne Hackborn    }
14105ac72a29593ab9a20337a2225df52bdf4754be02Dianne Hackborn
14115ac72a29593ab9a20337a2225df52bdf4754be02Dianne Hackborn    private void sendStickyBroadcastToAll(Intent intent) {
14125ac72a29593ab9a20337a2225df52bdf4754be02Dianne Hackborn        final long ident = Binder.clearCallingIdentity();
14135ac72a29593ab9a20337a2225df52bdf4754be02Dianne Hackborn        try {
14145ac72a29593ab9a20337a2225df52bdf4754be02Dianne Hackborn            mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
14155ac72a29593ab9a20337a2225df52bdf4754be02Dianne Hackborn        } finally {
14165ac72a29593ab9a20337a2225df52bdf4754be02Dianne Hackborn            Binder.restoreCallingIdentity(ident);
14175ac72a29593ab9a20337a2225df52bdf4754be02Dianne Hackborn        }
14185ac72a29593ab9a20337a2225df52bdf4754be02Dianne Hackborn    }
14195ac72a29593ab9a20337a2225df52bdf4754be02Dianne Hackborn
142025101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent    // UI update and Broadcast Intent
142125101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent    private void sendVolumeUpdate(int streamType, int oldIndex, int index, int flags) {
1422212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent        if (!isPlatformVoice() && (streamType == AudioSystem.STREAM_RING)) {
142325101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent            streamType = AudioSystem.STREAM_NOTIFICATION;
142425101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent        }
142525101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent
1426336cdb488ff0e5ec6709c66f55072d3ad22b82edJinsuk Kim        if (streamType == AudioSystem.STREAM_MUSIC) {
1427336cdb488ff0e5ec6709c66f55072d3ad22b82edJinsuk Kim            flags = updateFlagsForSystemAudio(flags);
14281a6be6ed3962735f12dbd5ce1bca758120c8fb8dJungshik Jang        }
14293346a802087f621c6441bc512dfcc17b07143fc6John Spurlock        mVolumeController.postVolumeChanged(streamType, flags);
143025101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent
14314bbcc6549738f3d69831b2bd9eb4accec3e9920eEric Laurent        if ((flags & AudioManager.FLAG_FIXED_VOLUME) == 0) {
14324bbcc6549738f3d69831b2bd9eb4accec3e9920eEric Laurent            oldIndex = (oldIndex + 5) / 10;
14334bbcc6549738f3d69831b2bd9eb4accec3e9920eEric Laurent            index = (index + 5) / 10;
14344bbcc6549738f3d69831b2bd9eb4accec3e9920eEric Laurent            Intent intent = new Intent(AudioManager.VOLUME_CHANGED_ACTION);
14354bbcc6549738f3d69831b2bd9eb4accec3e9920eEric Laurent            intent.putExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, streamType);
14364bbcc6549738f3d69831b2bd9eb4accec3e9920eEric Laurent            intent.putExtra(AudioManager.EXTRA_VOLUME_STREAM_VALUE, index);
14374bbcc6549738f3d69831b2bd9eb4accec3e9920eEric Laurent            intent.putExtra(AudioManager.EXTRA_PREV_VOLUME_STREAM_VALUE, oldIndex);
14384bbcc6549738f3d69831b2bd9eb4accec3e9920eEric Laurent            sendBroadcastToAll(intent);
14394bbcc6549738f3d69831b2bd9eb4accec3e9920eEric Laurent        }
14409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
14419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1442336cdb488ff0e5ec6709c66f55072d3ad22b82edJinsuk Kim    // If Hdmi-CEC system audio mode is on, we show volume bar only when TV
1443336cdb488ff0e5ec6709c66f55072d3ad22b82edJinsuk Kim    // receives volume notification from Audio Receiver.
1444336cdb488ff0e5ec6709c66f55072d3ad22b82edJinsuk Kim    private int updateFlagsForSystemAudio(int flags) {
1445336cdb488ff0e5ec6709c66f55072d3ad22b82edJinsuk Kim        if (mHdmiTvClient != null) {
1446336cdb488ff0e5ec6709c66f55072d3ad22b82edJinsuk Kim            synchronized (mHdmiTvClient) {
1447336cdb488ff0e5ec6709c66f55072d3ad22b82edJinsuk Kim                if (mHdmiSystemAudioSupported &&
1448336cdb488ff0e5ec6709c66f55072d3ad22b82edJinsuk Kim                        ((flags & AudioManager.FLAG_HDMI_SYSTEM_AUDIO_VOLUME) == 0)) {
1449336cdb488ff0e5ec6709c66f55072d3ad22b82edJinsuk Kim                    flags &= ~AudioManager.FLAG_SHOW_UI;
1450336cdb488ff0e5ec6709c66f55072d3ad22b82edJinsuk Kim                }
1451336cdb488ff0e5ec6709c66f55072d3ad22b82edJinsuk Kim            }
1452336cdb488ff0e5ec6709c66f55072d3ad22b82edJinsuk Kim        }
1453336cdb488ff0e5ec6709c66f55072d3ad22b82edJinsuk Kim        return flags;
1454336cdb488ff0e5ec6709c66f55072d3ad22b82edJinsuk Kim    }
1455336cdb488ff0e5ec6709c66f55072d3ad22b82edJinsuk Kim
14560dc37cce9d564ae43883c8dc8672b9266b881e63Mike Lockwood    // UI update and Broadcast Intent
14570dc37cce9d564ae43883c8dc8672b9266b881e63Mike Lockwood    private void sendMasterVolumeUpdate(int flags, int oldVolume, int newVolume) {
1458336cdb488ff0e5ec6709c66f55072d3ad22b82edJinsuk Kim        mVolumeController.postMasterVolumeChanged(updateFlagsForSystemAudio(flags));
14590dc37cce9d564ae43883c8dc8672b9266b881e63Mike Lockwood
14600dc37cce9d564ae43883c8dc8672b9266b881e63Mike Lockwood        Intent intent = new Intent(AudioManager.MASTER_VOLUME_CHANGED_ACTION);
14610dc37cce9d564ae43883c8dc8672b9266b881e63Mike Lockwood        intent.putExtra(AudioManager.EXTRA_PREV_MASTER_VOLUME_VALUE, oldVolume);
14620dc37cce9d564ae43883c8dc8672b9266b881e63Mike Lockwood        intent.putExtra(AudioManager.EXTRA_MASTER_VOLUME_VALUE, newVolume);
14635ac72a29593ab9a20337a2225df52bdf4754be02Dianne Hackborn        sendBroadcastToAll(intent);
14640dc37cce9d564ae43883c8dc8672b9266b881e63Mike Lockwood    }
14650dc37cce9d564ae43883c8dc8672b9266b881e63Mike Lockwood
14660dc37cce9d564ae43883c8dc8672b9266b881e63Mike Lockwood    // UI update and Broadcast Intent
14670dc37cce9d564ae43883c8dc8672b9266b881e63Mike Lockwood    private void sendMasterMuteUpdate(boolean muted, int flags) {
1468336cdb488ff0e5ec6709c66f55072d3ad22b82edJinsuk Kim        mVolumeController.postMasterMuteChanged(updateFlagsForSystemAudio(flags));
146957978ed86286a33d5b1a0fd000ca3406ba9d87b3Justin Koh        broadcastMasterMuteStatus(muted);
147057978ed86286a33d5b1a0fd000ca3406ba9d87b3Justin Koh    }
14710dc37cce9d564ae43883c8dc8672b9266b881e63Mike Lockwood
147257978ed86286a33d5b1a0fd000ca3406ba9d87b3Justin Koh    private void broadcastMasterMuteStatus(boolean muted) {
14730dc37cce9d564ae43883c8dc8672b9266b881e63Mike Lockwood        Intent intent = new Intent(AudioManager.MASTER_MUTE_CHANGED_ACTION);
14740dc37cce9d564ae43883c8dc8672b9266b881e63Mike Lockwood        intent.putExtra(AudioManager.EXTRA_MASTER_VOLUME_MUTED, muted);
147557978ed86286a33d5b1a0fd000ca3406ba9d87b3Justin Koh        intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT
147657978ed86286a33d5b1a0fd000ca3406ba9d87b3Justin Koh                | Intent.FLAG_RECEIVER_REPLACE_PENDING);
14775ac72a29593ab9a20337a2225df52bdf4754be02Dianne Hackborn        sendStickyBroadcastToAll(intent);
14780dc37cce9d564ae43883c8dc8672b9266b881e63Mike Lockwood    }
14790dc37cce9d564ae43883c8dc8672b9266b881e63Mike Lockwood
14809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
14819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Sets the stream state's index, and posts a message to set system volume.
14829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * This will not call out to the UI. Assumes a valid stream type.
14839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
14849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param streamType Type of the stream
14859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param index Desired volume index of the stream
14869bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent     * @param device the device whose volume must be changed
14879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param force If true, set the volume even if the desired volume is same
14889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * as the current volume.
14899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
14909bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent    private void setStreamVolumeInt(int streamType,
14919bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                                    int index,
14929bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                                    int device,
149342b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                                    boolean force) {
14949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        VolumeStreamState streamState = mStreamStates[streamType];
14955b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent
149642b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent        if (streamState.setIndex(index, device) || force) {
149742b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent            // Post message to set system volume (it in turn will post a message
149842b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent            // to persist).
149942b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent            sendMsg(mAudioHandler,
150042b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                    MSG_SET_DEVICE_VOLUME,
150142b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                    SENDMSG_QUEUE,
150242b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                    device,
150342b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                    0,
150442b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                    streamState,
150542b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                    0);
15069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
15079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
15089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
15099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** @see AudioManager#setStreamSolo(int, boolean) */
15109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void setStreamSolo(int streamType, boolean state, IBinder cb) {
151183a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent        if (mUseFixedVolume) {
151283a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent            return;
151383a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent        }
151483a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent
15159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        for (int stream = 0; stream < mStreamStates.length; stream++) {
15169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (!isStreamAffectedByMute(stream) || stream == streamType) continue;
15179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mStreamStates[stream].mute(cb, state);
15189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         }
15199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
15209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
15219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** @see AudioManager#setStreamMute(int, boolean) */
15229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void setStreamMute(int streamType, boolean state, IBinder cb) {
152383a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent        if (mUseFixedVolume) {
152483a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent            return;
152583a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent        }
15267c82ced4fc5b66c09a19eed9a5499039530142fbRoboErik        if (streamType == AudioManager.USE_DEFAULT_STREAM_TYPE) {
15277c82ced4fc5b66c09a19eed9a5499039530142fbRoboErik            streamType = getActiveStreamType(streamType);
15287c82ced4fc5b66c09a19eed9a5499039530142fbRoboErik        }
152983a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent
15309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (isStreamAffectedByMute(streamType)) {
1531336cdb488ff0e5ec6709c66f55072d3ad22b82edJinsuk Kim            if (streamType == AudioSystem.STREAM_MUSIC) {
1532336cdb488ff0e5ec6709c66f55072d3ad22b82edJinsuk Kim                setSystemAudioMute(state);
1533336cdb488ff0e5ec6709c66f55072d3ad22b82edJinsuk Kim            }
1534336cdb488ff0e5ec6709c66f55072d3ad22b82edJinsuk Kim            mStreamStates[streamType].mute(cb, state);
15357c82ced4fc5b66c09a19eed9a5499039530142fbRoboErik
15367c82ced4fc5b66c09a19eed9a5499039530142fbRoboErik            Intent intent = new Intent(AudioManager.STREAM_MUTE_CHANGED_ACTION);
15377c82ced4fc5b66c09a19eed9a5499039530142fbRoboErik            intent.putExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, streamType);
15387c82ced4fc5b66c09a19eed9a5499039530142fbRoboErik            intent.putExtra(AudioManager.EXTRA_STREAM_VOLUME_MUTED, state);
15397c82ced4fc5b66c09a19eed9a5499039530142fbRoboErik            sendBroadcastToAll(intent);
1540336cdb488ff0e5ec6709c66f55072d3ad22b82edJinsuk Kim        }
1541336cdb488ff0e5ec6709c66f55072d3ad22b82edJinsuk Kim    }
1542336cdb488ff0e5ec6709c66f55072d3ad22b82edJinsuk Kim
1543336cdb488ff0e5ec6709c66f55072d3ad22b82edJinsuk Kim    private void setSystemAudioMute(boolean state) {
1544336cdb488ff0e5ec6709c66f55072d3ad22b82edJinsuk Kim        if (mHdmiManager == null || mHdmiTvClient == null) return;
1545336cdb488ff0e5ec6709c66f55072d3ad22b82edJinsuk Kim        synchronized (mHdmiManager) {
154648cbf292ba9ad550af7e44d950a441b1812428e2Jinsuk Kim            if (!mHdmiSystemAudioSupported) return;
154748cbf292ba9ad550af7e44d950a441b1812428e2Jinsuk Kim            synchronized (mHdmiTvClient) {
154848cbf292ba9ad550af7e44d950a441b1812428e2Jinsuk Kim                final long token = Binder.clearCallingIdentity();
154948cbf292ba9ad550af7e44d950a441b1812428e2Jinsuk Kim                try {
155048cbf292ba9ad550af7e44d950a441b1812428e2Jinsuk Kim                    mHdmiTvClient.setSystemAudioMute(state);
155148cbf292ba9ad550af7e44d950a441b1812428e2Jinsuk Kim                } finally {
155248cbf292ba9ad550af7e44d950a441b1812428e2Jinsuk Kim                    Binder.restoreCallingIdentity(token);
155341d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang                }
155441d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang            }
15559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
15569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
15579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
155825101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent    /** get stream mute state. */
155925101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent    public boolean isStreamMute(int streamType) {
15607c82ced4fc5b66c09a19eed9a5499039530142fbRoboErik        if (streamType == AudioManager.USE_DEFAULT_STREAM_TYPE) {
15617c82ced4fc5b66c09a19eed9a5499039530142fbRoboErik            streamType = getActiveStreamType(streamType);
15627c82ced4fc5b66c09a19eed9a5499039530142fbRoboErik        }
15638fa4d6f585f40ff5cf5f9bed316d92c64a306f21Eric Laurent        synchronized (VolumeStreamState.class) {
15648fa4d6f585f40ff5cf5f9bed316d92c64a306f21Eric Laurent            return mStreamStates[streamType].isMuted_syncVSS();
15658fa4d6f585f40ff5cf5f9bed316d92c64a306f21Eric Laurent        }
156625101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent    }
156725101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent
1568ba5270b88798c66fefc17a1b25b27894e4fb7862Jean-Michel Trivi    private class RmtSbmxFullVolDeathHandler implements IBinder.DeathRecipient {
1569ba5270b88798c66fefc17a1b25b27894e4fb7862Jean-Michel Trivi        private IBinder mICallback; // To be notified of client's death
1570ba5270b88798c66fefc17a1b25b27894e4fb7862Jean-Michel Trivi
1571ba5270b88798c66fefc17a1b25b27894e4fb7862Jean-Michel Trivi        RmtSbmxFullVolDeathHandler(IBinder cb) {
1572ba5270b88798c66fefc17a1b25b27894e4fb7862Jean-Michel Trivi            mICallback = cb;
1573ba5270b88798c66fefc17a1b25b27894e4fb7862Jean-Michel Trivi            try {
1574ba5270b88798c66fefc17a1b25b27894e4fb7862Jean-Michel Trivi                cb.linkToDeath(this, 0/*flags*/);
1575ba5270b88798c66fefc17a1b25b27894e4fb7862Jean-Michel Trivi            } catch (RemoteException e) {
1576ba5270b88798c66fefc17a1b25b27894e4fb7862Jean-Michel Trivi                Log.e(TAG, "can't link to death", e);
1577ba5270b88798c66fefc17a1b25b27894e4fb7862Jean-Michel Trivi            }
1578ba5270b88798c66fefc17a1b25b27894e4fb7862Jean-Michel Trivi        }
1579ba5270b88798c66fefc17a1b25b27894e4fb7862Jean-Michel Trivi
1580ba5270b88798c66fefc17a1b25b27894e4fb7862Jean-Michel Trivi        boolean isHandlerFor(IBinder cb) {
1581ba5270b88798c66fefc17a1b25b27894e4fb7862Jean-Michel Trivi            return mICallback.equals(cb);
1582ba5270b88798c66fefc17a1b25b27894e4fb7862Jean-Michel Trivi        }
1583ba5270b88798c66fefc17a1b25b27894e4fb7862Jean-Michel Trivi
1584ba5270b88798c66fefc17a1b25b27894e4fb7862Jean-Michel Trivi        void forget() {
1585ba5270b88798c66fefc17a1b25b27894e4fb7862Jean-Michel Trivi            try {
1586ba5270b88798c66fefc17a1b25b27894e4fb7862Jean-Michel Trivi                mICallback.unlinkToDeath(this, 0/*flags*/);
1587ba5270b88798c66fefc17a1b25b27894e4fb7862Jean-Michel Trivi            } catch (NoSuchElementException e) {
1588ba5270b88798c66fefc17a1b25b27894e4fb7862Jean-Michel Trivi                Log.e(TAG, "error unlinking to death", e);
1589ba5270b88798c66fefc17a1b25b27894e4fb7862Jean-Michel Trivi            }
1590ba5270b88798c66fefc17a1b25b27894e4fb7862Jean-Michel Trivi        }
1591ba5270b88798c66fefc17a1b25b27894e4fb7862Jean-Michel Trivi
1592ba5270b88798c66fefc17a1b25b27894e4fb7862Jean-Michel Trivi        public void binderDied() {
1593ba5270b88798c66fefc17a1b25b27894e4fb7862Jean-Michel Trivi            Log.w(TAG, "Recorder with remote submix at full volume died " + mICallback);
1594ba5270b88798c66fefc17a1b25b27894e4fb7862Jean-Michel Trivi            forceRemoteSubmixFullVolume(false, mICallback);
1595ba5270b88798c66fefc17a1b25b27894e4fb7862Jean-Michel Trivi        }
1596ba5270b88798c66fefc17a1b25b27894e4fb7862Jean-Michel Trivi    }
1597ba5270b88798c66fefc17a1b25b27894e4fb7862Jean-Michel Trivi
1598ba5270b88798c66fefc17a1b25b27894e4fb7862Jean-Michel Trivi    /**
1599ba5270b88798c66fefc17a1b25b27894e4fb7862Jean-Michel Trivi     * call must be synchronized on mRmtSbmxFullVolDeathHandlers
1600ba5270b88798c66fefc17a1b25b27894e4fb7862Jean-Michel Trivi     * @return true if there is a registered death handler, false otherwise */
1601ba5270b88798c66fefc17a1b25b27894e4fb7862Jean-Michel Trivi    private boolean discardRmtSbmxFullVolDeathHandlerFor(IBinder cb) {
1602ba5270b88798c66fefc17a1b25b27894e4fb7862Jean-Michel Trivi        Iterator<RmtSbmxFullVolDeathHandler> it = mRmtSbmxFullVolDeathHandlers.iterator();
1603ba5270b88798c66fefc17a1b25b27894e4fb7862Jean-Michel Trivi        while (it.hasNext()) {
1604ba5270b88798c66fefc17a1b25b27894e4fb7862Jean-Michel Trivi            final RmtSbmxFullVolDeathHandler handler = it.next();
1605ba5270b88798c66fefc17a1b25b27894e4fb7862Jean-Michel Trivi            if (handler.isHandlerFor(cb)) {
1606ba5270b88798c66fefc17a1b25b27894e4fb7862Jean-Michel Trivi                handler.forget();
1607ba5270b88798c66fefc17a1b25b27894e4fb7862Jean-Michel Trivi                mRmtSbmxFullVolDeathHandlers.remove(handler);
1608ba5270b88798c66fefc17a1b25b27894e4fb7862Jean-Michel Trivi                return true;
1609ba5270b88798c66fefc17a1b25b27894e4fb7862Jean-Michel Trivi            }
1610ba5270b88798c66fefc17a1b25b27894e4fb7862Jean-Michel Trivi        }
1611ba5270b88798c66fefc17a1b25b27894e4fb7862Jean-Michel Trivi        return false;
1612ba5270b88798c66fefc17a1b25b27894e4fb7862Jean-Michel Trivi    }
1613ba5270b88798c66fefc17a1b25b27894e4fb7862Jean-Michel Trivi
1614ba5270b88798c66fefc17a1b25b27894e4fb7862Jean-Michel Trivi    /** call synchronized on mRmtSbmxFullVolDeathHandlers */
1615ba5270b88798c66fefc17a1b25b27894e4fb7862Jean-Michel Trivi    private boolean hasRmtSbmxFullVolDeathHandlerFor(IBinder cb) {
1616ba5270b88798c66fefc17a1b25b27894e4fb7862Jean-Michel Trivi        Iterator<RmtSbmxFullVolDeathHandler> it = mRmtSbmxFullVolDeathHandlers.iterator();
1617ba5270b88798c66fefc17a1b25b27894e4fb7862Jean-Michel Trivi        while (it.hasNext()) {
1618ba5270b88798c66fefc17a1b25b27894e4fb7862Jean-Michel Trivi            if (it.next().isHandlerFor(cb)) {
1619ba5270b88798c66fefc17a1b25b27894e4fb7862Jean-Michel Trivi                return true;
1620ba5270b88798c66fefc17a1b25b27894e4fb7862Jean-Michel Trivi            }
1621ba5270b88798c66fefc17a1b25b27894e4fb7862Jean-Michel Trivi        }
1622ba5270b88798c66fefc17a1b25b27894e4fb7862Jean-Michel Trivi        return false;
1623ba5270b88798c66fefc17a1b25b27894e4fb7862Jean-Michel Trivi    }
1624ba5270b88798c66fefc17a1b25b27894e4fb7862Jean-Michel Trivi
1625ba5270b88798c66fefc17a1b25b27894e4fb7862Jean-Michel Trivi    private int mRmtSbmxFullVolRefCount = 0;
1626ba5270b88798c66fefc17a1b25b27894e4fb7862Jean-Michel Trivi    private ArrayList<RmtSbmxFullVolDeathHandler> mRmtSbmxFullVolDeathHandlers =
1627ba5270b88798c66fefc17a1b25b27894e4fb7862Jean-Michel Trivi            new ArrayList<RmtSbmxFullVolDeathHandler>();
1628ba5270b88798c66fefc17a1b25b27894e4fb7862Jean-Michel Trivi
1629ba5270b88798c66fefc17a1b25b27894e4fb7862Jean-Michel Trivi    public void forceRemoteSubmixFullVolume(boolean startForcing, IBinder cb) {
1630ba5270b88798c66fefc17a1b25b27894e4fb7862Jean-Michel Trivi        if (cb == null) {
1631ba5270b88798c66fefc17a1b25b27894e4fb7862Jean-Michel Trivi            return;
1632ba5270b88798c66fefc17a1b25b27894e4fb7862Jean-Michel Trivi        }
1633ba5270b88798c66fefc17a1b25b27894e4fb7862Jean-Michel Trivi        if ((PackageManager.PERMISSION_GRANTED != mContext.checkCallingOrSelfPermission(
1634ba5270b88798c66fefc17a1b25b27894e4fb7862Jean-Michel Trivi                        android.Manifest.permission.CAPTURE_AUDIO_OUTPUT))) {
1635ba5270b88798c66fefc17a1b25b27894e4fb7862Jean-Michel Trivi            Log.w(TAG, "Trying to call forceRemoteSubmixFullVolume() without CAPTURE_AUDIO_OUTPUT");
1636ba5270b88798c66fefc17a1b25b27894e4fb7862Jean-Michel Trivi            return;
1637ba5270b88798c66fefc17a1b25b27894e4fb7862Jean-Michel Trivi        }
1638ba5270b88798c66fefc17a1b25b27894e4fb7862Jean-Michel Trivi        synchronized(mRmtSbmxFullVolDeathHandlers) {
1639ba5270b88798c66fefc17a1b25b27894e4fb7862Jean-Michel Trivi            boolean applyRequired = false;
1640ba5270b88798c66fefc17a1b25b27894e4fb7862Jean-Michel Trivi            if (startForcing) {
1641ba5270b88798c66fefc17a1b25b27894e4fb7862Jean-Michel Trivi                if (!hasRmtSbmxFullVolDeathHandlerFor(cb)) {
1642ba5270b88798c66fefc17a1b25b27894e4fb7862Jean-Michel Trivi                    mRmtSbmxFullVolDeathHandlers.add(new RmtSbmxFullVolDeathHandler(cb));
1643ba5270b88798c66fefc17a1b25b27894e4fb7862Jean-Michel Trivi                    if (mRmtSbmxFullVolRefCount == 0) {
1644ba5270b88798c66fefc17a1b25b27894e4fb7862Jean-Michel Trivi                        mFullVolumeDevices |= AudioSystem.DEVICE_OUT_REMOTE_SUBMIX;
1645ba5270b88798c66fefc17a1b25b27894e4fb7862Jean-Michel Trivi                        mFixedVolumeDevices |= AudioSystem.DEVICE_OUT_REMOTE_SUBMIX;
1646ba5270b88798c66fefc17a1b25b27894e4fb7862Jean-Michel Trivi                        applyRequired = true;
1647ba5270b88798c66fefc17a1b25b27894e4fb7862Jean-Michel Trivi                    }
1648ba5270b88798c66fefc17a1b25b27894e4fb7862Jean-Michel Trivi                    mRmtSbmxFullVolRefCount++;
1649ba5270b88798c66fefc17a1b25b27894e4fb7862Jean-Michel Trivi                }
1650ba5270b88798c66fefc17a1b25b27894e4fb7862Jean-Michel Trivi            } else {
1651ba5270b88798c66fefc17a1b25b27894e4fb7862Jean-Michel Trivi                if (discardRmtSbmxFullVolDeathHandlerFor(cb) && (mRmtSbmxFullVolRefCount > 0)) {
1652ba5270b88798c66fefc17a1b25b27894e4fb7862Jean-Michel Trivi                    mRmtSbmxFullVolRefCount--;
1653ba5270b88798c66fefc17a1b25b27894e4fb7862Jean-Michel Trivi                    if (mRmtSbmxFullVolRefCount == 0) {
1654ba5270b88798c66fefc17a1b25b27894e4fb7862Jean-Michel Trivi                        mFullVolumeDevices &= ~AudioSystem.DEVICE_OUT_REMOTE_SUBMIX;
1655ba5270b88798c66fefc17a1b25b27894e4fb7862Jean-Michel Trivi                        mFixedVolumeDevices &= ~AudioSystem.DEVICE_OUT_REMOTE_SUBMIX;
1656ba5270b88798c66fefc17a1b25b27894e4fb7862Jean-Michel Trivi                        applyRequired = true;
1657ba5270b88798c66fefc17a1b25b27894e4fb7862Jean-Michel Trivi                    }
1658ba5270b88798c66fefc17a1b25b27894e4fb7862Jean-Michel Trivi                }
1659ba5270b88798c66fefc17a1b25b27894e4fb7862Jean-Michel Trivi            }
1660ba5270b88798c66fefc17a1b25b27894e4fb7862Jean-Michel Trivi            if (applyRequired) {
1661ba5270b88798c66fefc17a1b25b27894e4fb7862Jean-Michel Trivi                // Assumes only STREAM_MUSIC going through DEVICE_OUT_REMOTE_SUBMIX
1662ba5270b88798c66fefc17a1b25b27894e4fb7862Jean-Michel Trivi                checkAllFixedVolumeDevices(AudioSystem.STREAM_MUSIC);
1663ba5270b88798c66fefc17a1b25b27894e4fb7862Jean-Michel Trivi                mStreamStates[AudioSystem.STREAM_MUSIC].applyAllVolumes();
1664ba5270b88798c66fefc17a1b25b27894e4fb7862Jean-Michel Trivi            }
1665ba5270b88798c66fefc17a1b25b27894e4fb7862Jean-Michel Trivi        }
1666ba5270b88798c66fefc17a1b25b27894e4fb7862Jean-Michel Trivi    }
1667ba5270b88798c66fefc17a1b25b27894e4fb7862Jean-Michel Trivi
1668961cae92540763226648813d111c5b5c3b0f1597Dianne Hackborn    /** @see AudioManager#setMasterMute(boolean, int) */
16694a21b25fad62e4f19d13ba814263841c931f56efJulia Reynolds    public void setMasterMute(boolean state, int flags, String callingPackage, IBinder cb) {
16707c82ced4fc5b66c09a19eed9a5499039530142fbRoboErik        setMasterMuteInternal(state, flags, callingPackage, cb, Binder.getCallingUid());
16717c82ced4fc5b66c09a19eed9a5499039530142fbRoboErik    }
16727c82ced4fc5b66c09a19eed9a5499039530142fbRoboErik
16737c82ced4fc5b66c09a19eed9a5499039530142fbRoboErik    private void setMasterMuteInternal(boolean state, int flags, String callingPackage, IBinder cb,
16747c82ced4fc5b66c09a19eed9a5499039530142fbRoboErik            int uid) {
167583a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent        if (mUseFixedVolume) {
167683a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent            return;
167783a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent        }
16787c82ced4fc5b66c09a19eed9a5499039530142fbRoboErik        if (mAppOps.noteOp(AppOpsManager.OP_AUDIO_MASTER_VOLUME, uid, callingPackage)
16797c82ced4fc5b66c09a19eed9a5499039530142fbRoboErik                != AppOpsManager.MODE_ALLOWED) {
16804a21b25fad62e4f19d13ba814263841c931f56efJulia Reynolds            return;
16814a21b25fad62e4f19d13ba814263841c931f56efJulia Reynolds        }
16821ce5b26d707e0086e09af3cd0428f1b441145261Jason Simmons        if (state != AudioSystem.getMasterMute()) {
1683336cdb488ff0e5ec6709c66f55072d3ad22b82edJinsuk Kim            setSystemAudioMute(state);
16841ce5b26d707e0086e09af3cd0428f1b441145261Jason Simmons            AudioSystem.setMasterMute(state);
168557978ed86286a33d5b1a0fd000ca3406ba9d87b3Justin Koh            // Post a persist master volume msg
168675cf9e19a575c28c200c02c0ab6f83bb79f5c50dJustin Koh            sendMsg(mAudioHandler, MSG_PERSIST_MASTER_VOLUME_MUTE, SENDMSG_REPLACE, state ? 1
1687b53453fae037d67e421011936c8fdffe7ba43922Julia Reynolds                    : 0, UserHandle.getCallingUserId(), null, PERSIST_DELAY);
16880273af55cf68d54d26d154b44d105d40fed79701Justin Koh            sendMasterMuteUpdate(state, flags);
16897c82ced4fc5b66c09a19eed9a5499039530142fbRoboErik
16907c82ced4fc5b66c09a19eed9a5499039530142fbRoboErik            Intent intent = new Intent(AudioManager.MASTER_MUTE_CHANGED_ACTION);
16917c82ced4fc5b66c09a19eed9a5499039530142fbRoboErik            intent.putExtra(AudioManager.EXTRA_MASTER_VOLUME_MUTED, state);
16927c82ced4fc5b66c09a19eed9a5499039530142fbRoboErik            sendBroadcastToAll(intent);
16931ce5b26d707e0086e09af3cd0428f1b441145261Jason Simmons        }
1694ce952c8e13c535bedde77bcdb94dfcc7508475aaMike Lockwood    }
1695ce952c8e13c535bedde77bcdb94dfcc7508475aaMike Lockwood
1696ce952c8e13c535bedde77bcdb94dfcc7508475aaMike Lockwood    /** get master mute state. */
1697ce952c8e13c535bedde77bcdb94dfcc7508475aaMike Lockwood    public boolean isMasterMute() {
16983194ea94348bce8e7ee9f803698d877f46f8279aMike Lockwood        return AudioSystem.getMasterMute();
1699ce952c8e13c535bedde77bcdb94dfcc7508475aaMike Lockwood    }
1700ce952c8e13c535bedde77bcdb94dfcc7508475aaMike Lockwood
1701fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    protected static int getMaxStreamVolume(int streamType) {
1702fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        return MAX_STREAM_VOLUME[streamType];
1703fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    }
1704fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi
170591377de6f23af2b0b08adae22810cae6fc35cb1aEric Laurent    public static int getDefaultStreamVolume(int streamType) {
170691377de6f23af2b0b08adae22810cae6fc35cb1aEric Laurent        return DEFAULT_STREAM_VOLUME[streamType];
170791377de6f23af2b0b08adae22810cae6fc35cb1aEric Laurent    }
170891377de6f23af2b0b08adae22810cae6fc35cb1aEric Laurent
17099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** @see AudioManager#getStreamVolume(int) */
17109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public int getStreamVolume(int streamType) {
17119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        ensureValidStreamType(streamType);
17129bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent        int device = getDeviceForStream(streamType);
17138fa4d6f585f40ff5cf5f9bed316d92c64a306f21Eric Laurent        synchronized (VolumeStreamState.class) {
17148fa4d6f585f40ff5cf5f9bed316d92c64a306f21Eric Laurent            int index = mStreamStates[streamType].getIndex(device);
17154bbcc6549738f3d69831b2bd9eb4accec3e9920eEric Laurent
17168fa4d6f585f40ff5cf5f9bed316d92c64a306f21Eric Laurent            // by convention getStreamVolume() returns 0 when a stream is muted.
17178fa4d6f585f40ff5cf5f9bed316d92c64a306f21Eric Laurent            if (mStreamStates[streamType].isMuted_syncVSS()) {
17188fa4d6f585f40ff5cf5f9bed316d92c64a306f21Eric Laurent                index = 0;
17198fa4d6f585f40ff5cf5f9bed316d92c64a306f21Eric Laurent            }
17208fa4d6f585f40ff5cf5f9bed316d92c64a306f21Eric Laurent            if (index != 0 && (mStreamVolumeAlias[streamType] == AudioSystem.STREAM_MUSIC) &&
17218fa4d6f585f40ff5cf5f9bed316d92c64a306f21Eric Laurent                    (device & mFixedVolumeDevices) != 0) {
17228fa4d6f585f40ff5cf5f9bed316d92c64a306f21Eric Laurent                index = mStreamStates[streamType].getMaxIndex();
17238fa4d6f585f40ff5cf5f9bed316d92c64a306f21Eric Laurent            }
17248fa4d6f585f40ff5cf5f9bed316d92c64a306f21Eric Laurent            return (index + 5) / 10;
17254bbcc6549738f3d69831b2bd9eb4accec3e9920eEric Laurent        }
17269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
17279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1728519c7744b522aa07e12bc3244ac3de14aa2a4ad0RoboErik    @Override
17294767690f09ea3447b8c5c32fb28d27650aa18e00Mike Lockwood    public int getMasterVolume() {
1730ce952c8e13c535bedde77bcdb94dfcc7508475aaMike Lockwood        if (isMasterMute()) return 0;
1731ce952c8e13c535bedde77bcdb94dfcc7508475aaMike Lockwood        return getLastAudibleMasterVolume();
17328dc1dabd254249b7ddb8743e88fdb96580ffc585Mike Lockwood    }
17338dc1dabd254249b7ddb8743e88fdb96580ffc585Mike Lockwood
1734519c7744b522aa07e12bc3244ac3de14aa2a4ad0RoboErik    @Override
1735ba50b97cff80e73620a0e3d13cae169e095974a7Dianne Hackborn    public void setMasterVolume(int volume, int flags, String callingPackage) {
1736519c7744b522aa07e12bc3244ac3de14aa2a4ad0RoboErik        setMasterVolume(volume, flags, callingPackage, Binder.getCallingUid());
1737519c7744b522aa07e12bc3244ac3de14aa2a4ad0RoboErik    }
1738519c7744b522aa07e12bc3244ac3de14aa2a4ad0RoboErik
1739519c7744b522aa07e12bc3244ac3de14aa2a4ad0RoboErik    public void setMasterVolume(int volume, int flags, String callingPackage, int uid) {
174083a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent        if (mUseFixedVolume) {
174183a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent            return;
174283a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent        }
174383a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent
1744519c7744b522aa07e12bc3244ac3de14aa2a4ad0RoboErik        if (mAppOps.noteOp(AppOpsManager.OP_AUDIO_MASTER_VOLUME, uid, callingPackage)
1745519c7744b522aa07e12bc3244ac3de14aa2a4ad0RoboErik                != AppOpsManager.MODE_ALLOWED) {
1746ba50b97cff80e73620a0e3d13cae169e095974a7Dianne Hackborn            return;
1747ba50b97cff80e73620a0e3d13cae169e095974a7Dianne Hackborn        }
1748ba50b97cff80e73620a0e3d13cae169e095974a7Dianne Hackborn
17499760647dd0ee67e7c20f3e9d661d2006b1df0b54Mike Lockwood        if (volume < 0) {
17509760647dd0ee67e7c20f3e9d661d2006b1df0b54Mike Lockwood            volume = 0;
17519760647dd0ee67e7c20f3e9d661d2006b1df0b54Mike Lockwood        } else if (volume > MAX_MASTER_VOLUME) {
17529760647dd0ee67e7c20f3e9d661d2006b1df0b54Mike Lockwood            volume = MAX_MASTER_VOLUME;
17539760647dd0ee67e7c20f3e9d661d2006b1df0b54Mike Lockwood        }
17545c55a051ad7d86a464fb91426f1ea3c0250e38b3Mike Lockwood        doSetMasterVolume((float)volume / MAX_MASTER_VOLUME, flags);
17555c55a051ad7d86a464fb91426f1ea3c0250e38b3Mike Lockwood    }
17565c55a051ad7d86a464fb91426f1ea3c0250e38b3Mike Lockwood
17575c55a051ad7d86a464fb91426f1ea3c0250e38b3Mike Lockwood    private void doSetMasterVolume(float volume, int flags) {
17585c55a051ad7d86a464fb91426f1ea3c0250e38b3Mike Lockwood        // don't allow changing master volume when muted
17595c55a051ad7d86a464fb91426f1ea3c0250e38b3Mike Lockwood        if (!AudioSystem.getMasterMute()) {
17605c55a051ad7d86a464fb91426f1ea3c0250e38b3Mike Lockwood            int oldVolume = getMasterVolume();
17615c55a051ad7d86a464fb91426f1ea3c0250e38b3Mike Lockwood            AudioSystem.setMasterVolume(volume);
17625c55a051ad7d86a464fb91426f1ea3c0250e38b3Mike Lockwood
17635c55a051ad7d86a464fb91426f1ea3c0250e38b3Mike Lockwood            int newVolume = getMasterVolume();
17645c55a051ad7d86a464fb91426f1ea3c0250e38b3Mike Lockwood            if (newVolume != oldVolume) {
17655c55a051ad7d86a464fb91426f1ea3c0250e38b3Mike Lockwood                // Post a persist master volume msg
17665c55a051ad7d86a464fb91426f1ea3c0250e38b3Mike Lockwood                sendMsg(mAudioHandler, MSG_PERSIST_MASTER_VOLUME, SENDMSG_REPLACE,
17675c55a051ad7d86a464fb91426f1ea3c0250e38b3Mike Lockwood                        Math.round(volume * (float)1000.0), 0, null, PERSIST_DELAY);
1768336cdb488ff0e5ec6709c66f55072d3ad22b82edJinsuk Kim                setSystemAudioVolume(oldVolume, newVolume, getMasterMaxVolume(), flags);
17695c55a051ad7d86a464fb91426f1ea3c0250e38b3Mike Lockwood            }
17703caba517253d1703fc29b50740c4567b932279fbJustin Koh            // Send the volume update regardless whether there was a change.
17713caba517253d1703fc29b50740c4567b932279fbJustin Koh            sendMasterVolumeUpdate(flags, oldVolume, newVolume);
17725c55a051ad7d86a464fb91426f1ea3c0250e38b3Mike Lockwood        }
17738dc1dabd254249b7ddb8743e88fdb96580ffc585Mike Lockwood    }
17748dc1dabd254249b7ddb8743e88fdb96580ffc585Mike Lockwood
17759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** @see AudioManager#getStreamMaxVolume(int) */
17769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public int getStreamMaxVolume(int streamType) {
17779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        ensureValidStreamType(streamType);
1778a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent        return (mStreamStates[streamType].getMaxIndex() + 5) / 10;
17799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
17809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
17814767690f09ea3447b8c5c32fb28d27650aa18e00Mike Lockwood    public int getMasterMaxVolume() {
17824767690f09ea3447b8c5c32fb28d27650aa18e00Mike Lockwood        return MAX_MASTER_VOLUME;
17834767690f09ea3447b8c5c32fb28d27650aa18e00Mike Lockwood    }
178425101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent
178525101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent    /** Get last audible volume before stream was muted. */
178625101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent    public int getLastAudibleStreamVolume(int streamType) {
178725101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent        ensureValidStreamType(streamType);
17889bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent        int device = getDeviceForStream(streamType);
178942b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent        return (mStreamStates[streamType].getIndex(device) + 5) / 10;
179025101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent    }
179125101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent
1792ce952c8e13c535bedde77bcdb94dfcc7508475aaMike Lockwood    /** Get last audible master volume before it was muted. */
1793ce952c8e13c535bedde77bcdb94dfcc7508475aaMike Lockwood    public int getLastAudibleMasterVolume() {
1794ce952c8e13c535bedde77bcdb94dfcc7508475aaMike Lockwood        return Math.round(AudioSystem.getMasterVolume() * MAX_MASTER_VOLUME);
1795ce952c8e13c535bedde77bcdb94dfcc7508475aaMike Lockwood    }
1796ce952c8e13c535bedde77bcdb94dfcc7508475aaMike Lockwood
1797961cae92540763226648813d111c5b5c3b0f1597Dianne Hackborn    /** @see AudioManager#getMasterStreamType()  */
17986d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent    public int getMasterStreamType() {
17994f0f120316cfcee5880191264885772677fff921John Spurlock        return mStreamVolumeAlias[AudioSystem.STREAM_SYSTEM];
18006d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent    }
18016d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent
180222c921a910d236abf3a1705a02541a49fdaf3a14Emily Bernier    /** @see AudioManager#setMicrophoneMute(boolean) */
180322c921a910d236abf3a1705a02541a49fdaf3a14Emily Bernier    public void setMicrophoneMute(boolean on, String callingPackage) {
180422c921a910d236abf3a1705a02541a49fdaf3a14Emily Bernier        if (mAppOps.noteOp(AppOpsManager.OP_MUTE_MICROPHONE, Binder.getCallingUid(),
180522c921a910d236abf3a1705a02541a49fdaf3a14Emily Bernier                callingPackage) != AppOpsManager.MODE_ALLOWED) {
180622c921a910d236abf3a1705a02541a49fdaf3a14Emily Bernier            return;
180722c921a910d236abf3a1705a02541a49fdaf3a14Emily Bernier        }
18084a4fea0752c8edd33d680765e97ee3b538d777a5Jean-Michel Trivi        if (!checkAudioSettingsPermission("setMicrophoneMute()")) {
18094a4fea0752c8edd33d680765e97ee3b538d777a5Jean-Michel Trivi            return;
18104a4fea0752c8edd33d680765e97ee3b538d777a5Jean-Michel Trivi        }
181122c921a910d236abf3a1705a02541a49fdaf3a14Emily Bernier
181222c921a910d236abf3a1705a02541a49fdaf3a14Emily Bernier        AudioSystem.muteMicrophone(on);
1813b53453fae037d67e421011936c8fdffe7ba43922Julia Reynolds        // Post a persist microphone msg.
1814b53453fae037d67e421011936c8fdffe7ba43922Julia Reynolds        sendMsg(mAudioHandler, MSG_PERSIST_MICROPHONE_MUTE, SENDMSG_REPLACE, on ? 1
1815b53453fae037d67e421011936c8fdffe7ba43922Julia Reynolds                : 0, UserHandle.getCallingUserId(), null, PERSIST_DELAY);
181622c921a910d236abf3a1705a02541a49fdaf3a14Emily Bernier    }
181722c921a910d236abf3a1705a02541a49fdaf3a14Emily Bernier
1818661f2cf45860d2e10924e6b69966a9afe255f28bJohn Spurlock    @Override
1819661f2cf45860d2e10924e6b69966a9afe255f28bJohn Spurlock    public int getRingerModeExternal() {
1820661f2cf45860d2e10924e6b69966a9afe255f28bJohn Spurlock        synchronized(mSettingsLock) {
1821661f2cf45860d2e10924e6b69966a9afe255f28bJohn Spurlock            return mRingerModeExternal;
1822661f2cf45860d2e10924e6b69966a9afe255f28bJohn Spurlock        }
1823661f2cf45860d2e10924e6b69966a9afe255f28bJohn Spurlock    }
1824661f2cf45860d2e10924e6b69966a9afe255f28bJohn Spurlock
1825661f2cf45860d2e10924e6b69966a9afe255f28bJohn Spurlock    @Override
1826661f2cf45860d2e10924e6b69966a9afe255f28bJohn Spurlock    public int getRingerModeInternal() {
1827ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten        synchronized(mSettingsLock) {
1828ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten            return mRingerMode;
1829ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten        }
1830ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten    }
1831ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten
1832ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten    private void ensureValidRingerMode(int ringerMode) {
18339755937ed90f06db45ff5fe4510950ae1516f8f9John Spurlock        if (!isValidRingerMode(ringerMode)) {
1834ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten            throw new IllegalArgumentException("Bad ringer mode " + ringerMode);
1835ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten        }
18369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
18379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
18389755937ed90f06db45ff5fe4510950ae1516f8f9John Spurlock    /** @see AudioManager#isValidRingerMode(int) */
18399755937ed90f06db45ff5fe4510950ae1516f8f9John Spurlock    public boolean isValidRingerMode(int ringerMode) {
18409755937ed90f06db45ff5fe4510950ae1516f8f9John Spurlock        return ringerMode >= 0 && ringerMode <= AudioManager.RINGER_MODE_MAX;
18419755937ed90f06db45ff5fe4510950ae1516f8f9John Spurlock    }
18429755937ed90f06db45ff5fe4510950ae1516f8f9John Spurlock
1843661f2cf45860d2e10924e6b69966a9afe255f28bJohn Spurlock    public void setRingerModeExternal(int ringerMode, String caller) {
1844af88a19165a1de77948d58b2692c9a7e13712a59John Spurlock        setRingerMode(ringerMode, caller, true /*external*/);
1845661f2cf45860d2e10924e6b69966a9afe255f28bJohn Spurlock    }
1846661f2cf45860d2e10924e6b69966a9afe255f28bJohn Spurlock
1847661f2cf45860d2e10924e6b69966a9afe255f28bJohn Spurlock    public void setRingerModeInternal(int ringerMode, String caller) {
1848661f2cf45860d2e10924e6b69966a9afe255f28bJohn Spurlock        enforceSelfOrSystemUI("setRingerModeInternal");
1849af88a19165a1de77948d58b2692c9a7e13712a59John Spurlock        setRingerMode(ringerMode, caller, false /*external*/);
1850661f2cf45860d2e10924e6b69966a9afe255f28bJohn Spurlock    }
1851661f2cf45860d2e10924e6b69966a9afe255f28bJohn Spurlock
1852661f2cf45860d2e10924e6b69966a9afe255f28bJohn Spurlock    private void setRingerMode(int ringerMode, String caller, boolean external) {
1853212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent        if (mUseFixedVolume || isPlatformTelevision()) {
185483a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent            return;
185583a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent        }
1856661f2cf45860d2e10924e6b69966a9afe255f28bJohn Spurlock        if (caller == null || caller.length() == 0) {
1857661f2cf45860d2e10924e6b69966a9afe255f28bJohn Spurlock            throw new IllegalArgumentException("Bad caller: " + caller);
1858661f2cf45860d2e10924e6b69966a9afe255f28bJohn Spurlock        }
18599755937ed90f06db45ff5fe4510950ae1516f8f9John Spurlock        ensureValidRingerMode(ringerMode);
1860244820185269991186d07068b92985624cede4a5Eric Laurent        if ((ringerMode == AudioManager.RINGER_MODE_VIBRATE) && !mHasVibrator) {
1861244820185269991186d07068b92985624cede4a5Eric Laurent            ringerMode = AudioManager.RINGER_MODE_SILENT;
1862244820185269991186d07068b92985624cede4a5Eric Laurent        }
1863af88a19165a1de77948d58b2692c9a7e13712a59John Spurlock        final long identity = Binder.clearCallingIdentity();
1864af88a19165a1de77948d58b2692c9a7e13712a59John Spurlock        try {
1865af88a19165a1de77948d58b2692c9a7e13712a59John Spurlock            synchronized (mSettingsLock) {
1866af88a19165a1de77948d58b2692c9a7e13712a59John Spurlock                final int ringerModeInternal = getRingerModeInternal();
1867af88a19165a1de77948d58b2692c9a7e13712a59John Spurlock                final int ringerModeExternal = getRingerModeExternal();
1868af88a19165a1de77948d58b2692c9a7e13712a59John Spurlock                if (external) {
1869af88a19165a1de77948d58b2692c9a7e13712a59John Spurlock                    setRingerModeExt(ringerMode);
1870af88a19165a1de77948d58b2692c9a7e13712a59John Spurlock                    if (mRingerModeDelegate != null) {
1871af88a19165a1de77948d58b2692c9a7e13712a59John Spurlock                        ringerMode = mRingerModeDelegate.onSetRingerModeExternal(ringerModeExternal,
1872af88a19165a1de77948d58b2692c9a7e13712a59John Spurlock                                ringerMode, caller, ringerModeInternal);
1873af88a19165a1de77948d58b2692c9a7e13712a59John Spurlock                    }
1874af88a19165a1de77948d58b2692c9a7e13712a59John Spurlock                    if (ringerMode != ringerModeInternal) {
1875af88a19165a1de77948d58b2692c9a7e13712a59John Spurlock                        setRingerModeInt(ringerMode, true /*persist*/);
1876af88a19165a1de77948d58b2692c9a7e13712a59John Spurlock                    }
1877af88a19165a1de77948d58b2692c9a7e13712a59John Spurlock                } else /*internal*/ {
1878af88a19165a1de77948d58b2692c9a7e13712a59John Spurlock                    if (ringerMode != ringerModeInternal) {
1879af88a19165a1de77948d58b2692c9a7e13712a59John Spurlock                        setRingerModeInt(ringerMode, true /*persist*/);
1880af88a19165a1de77948d58b2692c9a7e13712a59John Spurlock                    }
1881af88a19165a1de77948d58b2692c9a7e13712a59John Spurlock                    if (mRingerModeDelegate != null) {
1882af88a19165a1de77948d58b2692c9a7e13712a59John Spurlock                        ringerMode = mRingerModeDelegate.onSetRingerModeInternal(ringerModeInternal,
1883af88a19165a1de77948d58b2692c9a7e13712a59John Spurlock                                ringerMode, caller, ringerModeExternal);
1884af88a19165a1de77948d58b2692c9a7e13712a59John Spurlock                    }
1885af88a19165a1de77948d58b2692c9a7e13712a59John Spurlock                    setRingerModeExt(ringerMode);
188657627794b682235afd60adfb235fee46d32f54e2John Spurlock                }
1887661f2cf45860d2e10924e6b69966a9afe255f28bJohn Spurlock            }
1888af88a19165a1de77948d58b2692c9a7e13712a59John Spurlock        } finally {
1889af88a19165a1de77948d58b2692c9a7e13712a59John Spurlock            Binder.restoreCallingIdentity(identity);
1890b109615ebebd6f3b9ae789412279f576c3ace46bJason Parekh        }
1891b109615ebebd6f3b9ae789412279f576c3ace46bJason Parekh    }
18929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1893661f2cf45860d2e10924e6b69966a9afe255f28bJohn Spurlock    private void setRingerModeExt(int ringerMode) {
1894661f2cf45860d2e10924e6b69966a9afe255f28bJohn Spurlock        synchronized(mSettingsLock) {
1895661f2cf45860d2e10924e6b69966a9afe255f28bJohn Spurlock            if (ringerMode == mRingerModeExternal) return;
1896661f2cf45860d2e10924e6b69966a9afe255f28bJohn Spurlock            mRingerModeExternal = ringerMode;
1897e5b42d97f6fd3eb0220ea84f21e60d530d93fc46John Spurlock        }
1898661f2cf45860d2e10924e6b69966a9afe255f28bJohn Spurlock        // Send sticky broadcast
1899bcc1087af40a0e1bb35dbe8a39c830ecdea8280bJohn Spurlock        broadcastRingerMode(AudioManager.RINGER_MODE_CHANGED_ACTION, ringerMode);
1900e5b42d97f6fd3eb0220ea84f21e60d530d93fc46John Spurlock    }
1901e5b42d97f6fd3eb0220ea84f21e60d530d93fc46John Spurlock
19024050c93601b3c3609b21cc1e18a29b64747e7fa9Eric Laurent    private void setRingerModeInt(int ringerMode, boolean persist) {
1903bcc1087af40a0e1bb35dbe8a39c830ecdea8280bJohn Spurlock        final boolean change;
1904ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten        synchronized(mSettingsLock) {
1905bcc1087af40a0e1bb35dbe8a39c830ecdea8280bJohn Spurlock            change = mRingerMode != ringerMode;
1906ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten            mRingerMode = ringerMode;
1907ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten        }
1908b109615ebebd6f3b9ae789412279f576c3ace46bJason Parekh
19095b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent        // Mute stream if not previously muted by ringer mode and ringer mode
19105b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent        // is not RINGER_MODE_NORMAL and stream is affected by ringer mode.
19115b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent        // Unmute stream if previously muted by ringer mode and ringer mode
19125b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent        // is RINGER_MODE_NORMAL or stream is not affected by ringer mode.
1913b109615ebebd6f3b9ae789412279f576c3ace46bJason Parekh        int numStreamTypes = AudioSystem.getNumStreamTypes();
1914661f2cf45860d2e10924e6b69966a9afe255f28bJohn Spurlock        final boolean ringerModeMute = ringerMode == AudioManager.RINGER_MODE_VIBRATE
1915661f2cf45860d2e10924e6b69966a9afe255f28bJohn Spurlock                || ringerMode == AudioManager.RINGER_MODE_SILENT;
19165b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent        for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
1917661f2cf45860d2e10924e6b69966a9afe255f28bJohn Spurlock            final boolean isMuted = isStreamMutedByRingerMode(streamType);
1918661f2cf45860d2e10924e6b69966a9afe255f28bJohn Spurlock            final boolean shouldMute = ringerModeMute && isStreamAffectedByRingerMode(streamType);
1919661f2cf45860d2e10924e6b69966a9afe255f28bJohn Spurlock            if (isMuted == shouldMute) continue;
1920661f2cf45860d2e10924e6b69966a9afe255f28bJohn Spurlock            if (!shouldMute) {
1921661f2cf45860d2e10924e6b69966a9afe255f28bJohn Spurlock                // unmute
1922661f2cf45860d2e10924e6b69966a9afe255f28bJohn Spurlock                // ring and notifications volume should never be 0 when not silenced
1923661f2cf45860d2e10924e6b69966a9afe255f28bJohn Spurlock                // on voice capable devices or devices that support vibration
1924661f2cf45860d2e10924e6b69966a9afe255f28bJohn Spurlock                if ((isPlatformVoice() || mHasVibrator) &&
1925661f2cf45860d2e10924e6b69966a9afe255f28bJohn Spurlock                        mStreamVolumeAlias[streamType] == AudioSystem.STREAM_RING) {
1926661f2cf45860d2e10924e6b69966a9afe255f28bJohn Spurlock                    synchronized (VolumeStreamState.class) {
1927661f2cf45860d2e10924e6b69966a9afe255f28bJohn Spurlock                        Set set = mStreamStates[streamType].mIndex.entrySet();
1928661f2cf45860d2e10924e6b69966a9afe255f28bJohn Spurlock                        Iterator i = set.iterator();
1929661f2cf45860d2e10924e6b69966a9afe255f28bJohn Spurlock                        while (i.hasNext()) {
1930661f2cf45860d2e10924e6b69966a9afe255f28bJohn Spurlock                            Map.Entry entry = (Map.Entry)i.next();
1931661f2cf45860d2e10924e6b69966a9afe255f28bJohn Spurlock                            if ((Integer)entry.getValue() == 0) {
1932661f2cf45860d2e10924e6b69966a9afe255f28bJohn Spurlock                                entry.setValue(10);
19339bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                            }
19349bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                        }
1935b024c30a80684ac08daef3137b7ba0d347fe3ce5Eric Laurent                    }
19369bcf401d13d47416043a704430388abd59aef7cdEric Laurent                }
1937661f2cf45860d2e10924e6b69966a9afe255f28bJohn Spurlock                mStreamStates[streamType].mute(null, false);
1938661f2cf45860d2e10924e6b69966a9afe255f28bJohn Spurlock                mRingerModeMutedStreams &= ~(1 << streamType);
19395b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent            } else {
1940661f2cf45860d2e10924e6b69966a9afe255f28bJohn Spurlock                // mute
1941661f2cf45860d2e10924e6b69966a9afe255f28bJohn Spurlock                mStreamStates[streamType].mute(null, true);
1942661f2cf45860d2e10924e6b69966a9afe255f28bJohn Spurlock                mRingerModeMutedStreams |= (1 << streamType);
1943b109615ebebd6f3b9ae789412279f576c3ace46bJason Parekh            }
19449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1945a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent
1946b109615ebebd6f3b9ae789412279f576c3ace46bJason Parekh        // Post a persist ringer mode msg
19474050c93601b3c3609b21cc1e18a29b64747e7fa9Eric Laurent        if (persist) {
1948afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent            sendMsg(mAudioHandler, MSG_PERSIST_RINGER_MODE,
19494050c93601b3c3609b21cc1e18a29b64747e7fa9Eric Laurent                    SENDMSG_REPLACE, 0, 0, null, PERSIST_DELAY);
19504050c93601b3c3609b21cc1e18a29b64747e7fa9Eric Laurent        }
1951bcc1087af40a0e1bb35dbe8a39c830ecdea8280bJohn Spurlock        if (change) {
1952bcc1087af40a0e1bb35dbe8a39c830ecdea8280bJohn Spurlock            // Send sticky broadcast
1953bcc1087af40a0e1bb35dbe8a39c830ecdea8280bJohn Spurlock            broadcastRingerMode(AudioManager.INTERNAL_RINGER_MODE_CHANGED_ACTION, ringerMode);
1954bcc1087af40a0e1bb35dbe8a39c830ecdea8280bJohn Spurlock        }
19559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
19569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
19579063154a793b0ab38b3c5992cbaed046427b4a82Mike Lockwood    private void restoreMasterVolume() {
195883a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent        if (mUseFixedVolume) {
195983a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent            AudioSystem.setMasterVolume(1.0f);
196083a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent            return;
196183a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent        }
19629063154a793b0ab38b3c5992cbaed046427b4a82Mike Lockwood        if (mUseMasterVolume) {
1963bc0fab1fc2db832ef86d8a33466ec4d68b103ca0Eric Laurent            float volume = Settings.System.getFloatForUser(mContentResolver,
1964bc0fab1fc2db832ef86d8a33466ec4d68b103ca0Eric Laurent                    Settings.System.VOLUME_MASTER, -1.0f, UserHandle.USER_CURRENT);
19659063154a793b0ab38b3c5992cbaed046427b4a82Mike Lockwood            if (volume >= 0.0f) {
19669063154a793b0ab38b3c5992cbaed046427b4a82Mike Lockwood                AudioSystem.setMasterVolume(volume);
19679063154a793b0ab38b3c5992cbaed046427b4a82Mike Lockwood            }
19689063154a793b0ab38b3c5992cbaed046427b4a82Mike Lockwood        }
19699063154a793b0ab38b3c5992cbaed046427b4a82Mike Lockwood    }
19709063154a793b0ab38b3c5992cbaed046427b4a82Mike Lockwood
19719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** @see AudioManager#shouldVibrate(int) */
19729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public boolean shouldVibrate(int vibrateType) {
1973bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent        if (!mHasVibrator) return false;
19749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
19759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        switch (getVibrateSetting(vibrateType)) {
19769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
19779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            case AudioManager.VIBRATE_SETTING_ON:
197857627794b682235afd60adfb235fee46d32f54e2John Spurlock                return getRingerModeExternal() != AudioManager.RINGER_MODE_SILENT;
19799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
19809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            case AudioManager.VIBRATE_SETTING_ONLY_SILENT:
198157627794b682235afd60adfb235fee46d32f54e2John Spurlock                return getRingerModeExternal() == AudioManager.RINGER_MODE_VIBRATE;
19829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
19839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            case AudioManager.VIBRATE_SETTING_OFF:
1984bcac496076ef6f439147e7a2be71e8a2b76ddedeDaniel Sandler                // return false, even for incoming calls
1985bcac496076ef6f439147e7a2be71e8a2b76ddedeDaniel Sandler                return false;
19869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
19879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            default:
19889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return false;
19899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
19909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
19919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
19929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** @see AudioManager#getVibrateSetting(int) */
19939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public int getVibrateSetting(int vibrateType) {
1994bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent        if (!mHasVibrator) return AudioManager.VIBRATE_SETTING_OFF;
19959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return (mVibrateSetting >> (vibrateType * 2)) & 3;
19969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
19979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
19989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** @see AudioManager#setVibrateSetting(int, int) */
19999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void setVibrateSetting(int vibrateType, int vibrateSetting) {
20009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2001bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent        if (!mHasVibrator) return;
2002bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent
20039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mVibrateSetting = getValueForVibrateSetting(mVibrateSetting, vibrateType, vibrateSetting);
20049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
20059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // Broadcast change
20069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        broadcastVibrateSetting(vibrateType);
20079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
20089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
20099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
20109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
20119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @see #setVibrateSetting(int, int)
20129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
20139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static int getValueForVibrateSetting(int existingValue, int vibrateType,
20149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int vibrateSetting) {
20159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
20169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // First clear the existing setting. Each vibrate type has two bits in
20179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // the value. Note '3' is '11' in binary.
20189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        existingValue &= ~(3 << (vibrateType * 2));
20199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
20209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // Set into the old value
20219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        existingValue |= (vibrateSetting & 3) << (vibrateType * 2);
20229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
20239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return existingValue;
20249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
20259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
20269272b4b4a44fe1f33e3030810618194f817caaecEric Laurent    private class SetModeDeathHandler implements IBinder.DeathRecipient {
20279272b4b4a44fe1f33e3030810618194f817caaecEric Laurent        private IBinder mCb; // To be notified of client's death
2028f1ddd51f9cd2f92b922bc636c307210a8d587c25Marco Nelissen        private int mPid;
20299272b4b4a44fe1f33e3030810618194f817caaecEric Laurent        private int mMode = AudioSystem.MODE_NORMAL; // Current mode set by this client
20309272b4b4a44fe1f33e3030810618194f817caaecEric Laurent
20319f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent        SetModeDeathHandler(IBinder cb, int pid) {
20329272b4b4a44fe1f33e3030810618194f817caaecEric Laurent            mCb = cb;
20339f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent            mPid = pid;
20349272b4b4a44fe1f33e3030810618194f817caaecEric Laurent        }
20359272b4b4a44fe1f33e3030810618194f817caaecEric Laurent
20369272b4b4a44fe1f33e3030810618194f817caaecEric Laurent        public void binderDied() {
2037d7454be47f4111c0478a502353e11dea401378bdEric Laurent            int newModeOwnerPid = 0;
20389272b4b4a44fe1f33e3030810618194f817caaecEric Laurent            synchronized(mSetModeDeathHandlers) {
20399272b4b4a44fe1f33e3030810618194f817caaecEric Laurent                Log.w(TAG, "setMode() client died");
20409272b4b4a44fe1f33e3030810618194f817caaecEric Laurent                int index = mSetModeDeathHandlers.indexOf(this);
20419272b4b4a44fe1f33e3030810618194f817caaecEric Laurent                if (index < 0) {
20429272b4b4a44fe1f33e3030810618194f817caaecEric Laurent                    Log.w(TAG, "unregistered setMode() client died");
20439272b4b4a44fe1f33e3030810618194f817caaecEric Laurent                } else {
2044d7454be47f4111c0478a502353e11dea401378bdEric Laurent                    newModeOwnerPid = setModeInt(AudioSystem.MODE_NORMAL, mCb, mPid);
20459272b4b4a44fe1f33e3030810618194f817caaecEric Laurent                }
20469272b4b4a44fe1f33e3030810618194f817caaecEric Laurent            }
20479f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent            // when entering RINGTONE, IN_CALL or IN_COMMUNICATION mode, clear all
20489f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent            // SCO connections not started by the application changing the mode
2049d7454be47f4111c0478a502353e11dea401378bdEric Laurent            if (newModeOwnerPid != 0) {
20506b5e22d52c69cb6d80ff09bd32395b0034ada343Eric Laurent                final long ident = Binder.clearCallingIdentity();
20516b5e22d52c69cb6d80ff09bd32395b0034ada343Eric Laurent                disconnectBluetoothSco(newModeOwnerPid);
20526b5e22d52c69cb6d80ff09bd32395b0034ada343Eric Laurent                Binder.restoreCallingIdentity(ident);
20539f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent            }
20549272b4b4a44fe1f33e3030810618194f817caaecEric Laurent        }
20559272b4b4a44fe1f33e3030810618194f817caaecEric Laurent
2056f1ddd51f9cd2f92b922bc636c307210a8d587c25Marco Nelissen        public int getPid() {
2057f1ddd51f9cd2f92b922bc636c307210a8d587c25Marco Nelissen            return mPid;
2058f1ddd51f9cd2f92b922bc636c307210a8d587c25Marco Nelissen        }
2059f1ddd51f9cd2f92b922bc636c307210a8d587c25Marco Nelissen
20609272b4b4a44fe1f33e3030810618194f817caaecEric Laurent        public void setMode(int mode) {
20619272b4b4a44fe1f33e3030810618194f817caaecEric Laurent            mMode = mode;
20629272b4b4a44fe1f33e3030810618194f817caaecEric Laurent        }
20639272b4b4a44fe1f33e3030810618194f817caaecEric Laurent
20649272b4b4a44fe1f33e3030810618194f817caaecEric Laurent        public int getMode() {
20659272b4b4a44fe1f33e3030810618194f817caaecEric Laurent            return mMode;
20669272b4b4a44fe1f33e3030810618194f817caaecEric Laurent        }
20679272b4b4a44fe1f33e3030810618194f817caaecEric Laurent
20689272b4b4a44fe1f33e3030810618194f817caaecEric Laurent        public IBinder getBinder() {
20699272b4b4a44fe1f33e3030810618194f817caaecEric Laurent            return mCb;
20709272b4b4a44fe1f33e3030810618194f817caaecEric Laurent        }
20719272b4b4a44fe1f33e3030810618194f817caaecEric Laurent    }
20729272b4b4a44fe1f33e3030810618194f817caaecEric Laurent
20739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** @see AudioManager#setMode(int) */
20749272b4b4a44fe1f33e3030810618194f817caaecEric Laurent    public void setMode(int mode, IBinder cb) {
2075339567d5c91a8dc9228913ed1e5deb0ebb8a4a64Jean-Michel Trivi        if (DEBUG_MODE) { Log.v(TAG, "setMode(mode=" + mode + ")"); }
20769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (!checkAudioSettingsPermission("setMode()")) {
20779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return;
20789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
2079a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent
2080ccd654e9d4c38da0d652c442e7a2ca3f447e9abeJean-Michel Trivi        if ( (mode == AudioSystem.MODE_IN_CALL) &&
2081ccd654e9d4c38da0d652c442e7a2ca3f447e9abeJean-Michel Trivi                (mContext.checkCallingOrSelfPermission(
2082ccd654e9d4c38da0d652c442e7a2ca3f447e9abeJean-Michel Trivi                        android.Manifest.permission.MODIFY_PHONE_STATE)
2083ccd654e9d4c38da0d652c442e7a2ca3f447e9abeJean-Michel Trivi                            != PackageManager.PERMISSION_GRANTED)) {
2084ccd654e9d4c38da0d652c442e7a2ca3f447e9abeJean-Michel Trivi            Log.w(TAG, "MODIFY_PHONE_STATE Permission Denial: setMode(MODE_IN_CALL) from pid="
2085ccd654e9d4c38da0d652c442e7a2ca3f447e9abeJean-Michel Trivi                    + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid());
2086ccd654e9d4c38da0d652c442e7a2ca3f447e9abeJean-Michel Trivi            return;
2087ccd654e9d4c38da0d652c442e7a2ca3f447e9abeJean-Michel Trivi        }
2088ccd654e9d4c38da0d652c442e7a2ca3f447e9abeJean-Michel Trivi
20898f677d66d9c3ba34c97e69b2bb9e161f129af0eeJean-Michel Trivi        if (mode < AudioSystem.MODE_CURRENT || mode >= AudioSystem.NUM_MODES) {
2090a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent            return;
2091a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent        }
2092a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent
2093d7454be47f4111c0478a502353e11dea401378bdEric Laurent        int newModeOwnerPid = 0;
20949f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent        synchronized(mSetModeDeathHandlers) {
2095a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent            if (mode == AudioSystem.MODE_CURRENT) {
2096a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent                mode = mMode;
2097a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent            }
2098d7454be47f4111c0478a502353e11dea401378bdEric Laurent            newModeOwnerPid = setModeInt(mode, cb, Binder.getCallingPid());
20999f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent        }
21009f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent        // when entering RINGTONE, IN_CALL or IN_COMMUNICATION mode, clear all
21019f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent        // SCO connections not started by the application changing the mode
2102d7454be47f4111c0478a502353e11dea401378bdEric Laurent        if (newModeOwnerPid != 0) {
2103d7454be47f4111c0478a502353e11dea401378bdEric Laurent             disconnectBluetoothSco(newModeOwnerPid);
21049f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent        }
21059f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent    }
21062ade576148fe33c5ff6098d30ccfbcf28df70e8eJean-Michel Trivi
21079f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent    // must be called synchronized on mSetModeDeathHandlers
2108d7454be47f4111c0478a502353e11dea401378bdEric Laurent    // setModeInt() returns a valid PID if the audio mode was successfully set to
21099f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent    // any mode other than NORMAL.
2110ccd654e9d4c38da0d652c442e7a2ca3f447e9abeJean-Michel Trivi    private int setModeInt(int mode, IBinder cb, int pid) {
2111339567d5c91a8dc9228913ed1e5deb0ebb8a4a64Jean-Michel Trivi        if (DEBUG_MODE) { Log.v(TAG, "setModeInt(mode=" + mode + ", pid=" + pid + ")"); }
2112d7454be47f4111c0478a502353e11dea401378bdEric Laurent        int newModeOwnerPid = 0;
21139f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent        if (cb == null) {
21149f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent            Log.e(TAG, "setModeInt() called with null binder");
2115d7454be47f4111c0478a502353e11dea401378bdEric Laurent            return newModeOwnerPid;
21169f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent        }
21172ade576148fe33c5ff6098d30ccfbcf28df70e8eJean-Michel Trivi
21189f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent        SetModeDeathHandler hdlr = null;
21199f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent        Iterator iter = mSetModeDeathHandlers.iterator();
21209f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent        while (iter.hasNext()) {
21219f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent            SetModeDeathHandler h = (SetModeDeathHandler)iter.next();
21229f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent            if (h.getPid() == pid) {
21239f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                hdlr = h;
21249f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                // Remove from client list so that it is re-inserted at top of list
21259f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                iter.remove();
21269f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                hdlr.getBinder().unlinkToDeath(hdlr, 0);
21279f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                break;
21289f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent            }
21299f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent        }
21309f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent        int status = AudioSystem.AUDIO_STATUS_OK;
21319f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent        do {
21329f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent            if (mode == AudioSystem.MODE_NORMAL) {
21339f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                // get new mode from client at top the list if any
21349f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                if (!mSetModeDeathHandlers.isEmpty()) {
21359f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                    hdlr = mSetModeDeathHandlers.get(0);
21369f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                    cb = hdlr.getBinder();
21379f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                    mode = hdlr.getMode();
2138339567d5c91a8dc9228913ed1e5deb0ebb8a4a64Jean-Michel Trivi                    if (DEBUG_MODE) {
2139339567d5c91a8dc9228913ed1e5deb0ebb8a4a64Jean-Michel Trivi                        Log.w(TAG, " using mode=" + mode + " instead due to death hdlr at pid="
2140339567d5c91a8dc9228913ed1e5deb0ebb8a4a64Jean-Michel Trivi                                + hdlr.mPid);
2141339567d5c91a8dc9228913ed1e5deb0ebb8a4a64Jean-Michel Trivi                    }
21429f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                }
21439f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent            } else {
21449f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                if (hdlr == null) {
21459f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                    hdlr = new SetModeDeathHandler(cb, pid);
21469f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                }
21479f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                // Register for client death notification
21489f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                try {
21499f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                    cb.linkToDeath(hdlr, 0);
21509f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                } catch (RemoteException e) {
21519f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                    // Client has died!
21529f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                    Log.w(TAG, "setMode() could not link to "+cb+" binder death");
21539f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                }
21549272b4b4a44fe1f33e3030810618194f817caaecEric Laurent
21559f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                // Last client to call setMode() is always at top of client list
21569f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                // as required by SetModeDeathHandler.binderDied()
21579f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                mSetModeDeathHandlers.add(0, hdlr);
21589f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                hdlr.setMode(mode);
21599f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent            }
21603def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent
21619f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent            if (mode != mMode) {
21629f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                status = AudioSystem.setPhoneState(mode);
21639f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                if (status == AudioSystem.AUDIO_STATUS_OK) {
2164339567d5c91a8dc9228913ed1e5deb0ebb8a4a64Jean-Michel Trivi                    if (DEBUG_MODE) { Log.v(TAG, " mode successfully set to " + mode); }
21659f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                    mMode = mode;
21669f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                } else {
21679f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                    if (hdlr != null) {
21689f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                        mSetModeDeathHandlers.remove(hdlr);
21699f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                        cb.unlinkToDeath(hdlr, 0);
21703def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                    }
21719f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                    // force reading new top of mSetModeDeathHandlers stack
2172339567d5c91a8dc9228913ed1e5deb0ebb8a4a64Jean-Michel Trivi                    if (DEBUG_MODE) { Log.w(TAG, " mode set to MODE_NORMAL after phoneState pb"); }
21739f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                    mode = AudioSystem.MODE_NORMAL;
2174b9c9d260f21b321527c4622a123af9767630d94dEric Laurent                }
21759f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent            } else {
21769f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                status = AudioSystem.AUDIO_STATUS_OK;
21779f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent            }
21789f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent        } while (status != AudioSystem.AUDIO_STATUS_OK && !mSetModeDeathHandlers.isEmpty());
21799f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent
21809f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent        if (status == AudioSystem.AUDIO_STATUS_OK) {
21819f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent            if (mode != AudioSystem.MODE_NORMAL) {
2182d7454be47f4111c0478a502353e11dea401378bdEric Laurent                if (mSetModeDeathHandlers.isEmpty()) {
2183d7454be47f4111c0478a502353e11dea401378bdEric Laurent                    Log.e(TAG, "setMode() different from MODE_NORMAL with empty mode client stack");
2184d7454be47f4111c0478a502353e11dea401378bdEric Laurent                } else {
2185d7454be47f4111c0478a502353e11dea401378bdEric Laurent                    newModeOwnerPid = mSetModeDeathHandlers.get(0).getPid();
2186d7454be47f4111c0478a502353e11dea401378bdEric Laurent                }
21879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
21889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int streamType = getActiveStreamType(AudioManager.USE_DEFAULT_STREAM_TYPE);
21899bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent            int device = getDeviceForStream(streamType);
219042b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent            int index = mStreamStates[mStreamVolumeAlias[streamType]].getIndex(device);
219142b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent            setStreamVolumeInt(mStreamVolumeAlias[streamType], index, device, true);
21926d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent
21936d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent            updateStreamVolumeAlias(true /*updateVolumes*/);
21949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
2195d7454be47f4111c0478a502353e11dea401378bdEric Laurent        return newModeOwnerPid;
21969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
21979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
21989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** @see AudioManager#getMode() */
21999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public int getMode() {
22009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return mMode;
22019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
22029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2203e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent    //==========================================================================================
2204e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent    // Sound Effects
2205e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent    //==========================================================================================
2206e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent
2207e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent    private static final String TAG_AUDIO_ASSETS = "audio_assets";
2208e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent    private static final String ATTR_VERSION = "version";
2209e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent    private static final String TAG_GROUP = "group";
2210e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent    private static final String ATTR_GROUP_NAME = "name";
2211e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent    private static final String TAG_ASSET = "asset";
2212e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent    private static final String ATTR_ASSET_ID = "id";
2213e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent    private static final String ATTR_ASSET_FILE = "file";
2214e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent
2215e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent    private static final String ASSET_FILE_VERSION = "1.0";
2216e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent    private static final String GROUP_TOUCH_SOUNDS = "touch_sounds";
2217e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent
2218167d1a27713ab64cd3c0aa70de96434083ef0400Glenn Kasten    private static final int SOUND_EFFECTS_LOAD_TIMEOUT_MS = 5000;
22195d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent
22205d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent    class LoadSoundEffectReply {
22215d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent        public int mStatus = 1;
22225d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent    };
22235d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent
2224e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent    private void loadTouchSoundAssetDefaults() {
2225e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent        SOUND_EFFECT_FILES.add("Effect_Tick.ogg");
2226e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent        for (int i = 0; i < AudioManager.NUM_SOUND_EFFECTS; i++) {
2227e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent            SOUND_EFFECT_FILES_MAP[i][0] = 0;
2228e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent            SOUND_EFFECT_FILES_MAP[i][1] = -1;
2229e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent        }
2230e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent    }
2231e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent
2232e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent    private void loadTouchSoundAssets() {
2233e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent        XmlResourceParser parser = null;
2234e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent
22355d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent        // only load assets once.
22365d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent        if (!SOUND_EFFECT_FILES.isEmpty()) {
22375d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent            return;
22385d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent        }
22395d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent
2240e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent        loadTouchSoundAssetDefaults();
2241e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent
2242e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent        try {
2243e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent            parser = mContext.getResources().getXml(com.android.internal.R.xml.audio_assets);
2244e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent
2245e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent            XmlUtils.beginDocument(parser, TAG_AUDIO_ASSETS);
2246e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent            String version = parser.getAttributeValue(null, ATTR_VERSION);
2247e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent            boolean inTouchSoundsGroup = false;
2248e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent
2249e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent            if (ASSET_FILE_VERSION.equals(version)) {
2250e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent                while (true) {
2251e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent                    XmlUtils.nextElement(parser);
2252e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent                    String element = parser.getName();
2253e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent                    if (element == null) {
2254e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent                        break;
2255e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent                    }
2256e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent                    if (element.equals(TAG_GROUP)) {
2257e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent                        String name = parser.getAttributeValue(null, ATTR_GROUP_NAME);
2258e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent                        if (GROUP_TOUCH_SOUNDS.equals(name)) {
2259e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent                            inTouchSoundsGroup = true;
2260e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent                            break;
2261e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent                        }
2262e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent                    }
2263e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent                }
2264e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent                while (inTouchSoundsGroup) {
2265e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent                    XmlUtils.nextElement(parser);
2266e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent                    String element = parser.getName();
2267e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent                    if (element == null) {
2268e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent                        break;
2269e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent                    }
2270e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent                    if (element.equals(TAG_ASSET)) {
2271e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent                        String id = parser.getAttributeValue(null, ATTR_ASSET_ID);
2272e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent                        String file = parser.getAttributeValue(null, ATTR_ASSET_FILE);
2273e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent                        int fx;
2274e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent
2275e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent                        try {
2276e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent                            Field field = AudioManager.class.getField(id);
2277e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent                            fx = field.getInt(null);
2278e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent                        } catch (Exception e) {
2279e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent                            Log.w(TAG, "Invalid touch sound ID: "+id);
2280e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent                            continue;
2281e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent                        }
2282e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent
2283e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent                        int i = SOUND_EFFECT_FILES.indexOf(file);
2284e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent                        if (i == -1) {
2285e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent                            i = SOUND_EFFECT_FILES.size();
2286e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent                            SOUND_EFFECT_FILES.add(file);
2287e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent                        }
2288e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent                        SOUND_EFFECT_FILES_MAP[fx][0] = i;
2289e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent                    } else {
2290e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent                        break;
2291e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent                    }
2292e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent                }
2293e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent            }
2294e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent        } catch (Resources.NotFoundException e) {
2295e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent            Log.w(TAG, "audio assets file not found", e);
2296e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent        } catch (XmlPullParserException e) {
2297e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent            Log.w(TAG, "XML parser exception reading touch sound assets", e);
2298e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent        } catch (IOException e) {
2299e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent            Log.w(TAG, "I/O exception reading touch sound assets", e);
2300e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent        } finally {
2301e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent            if (parser != null) {
2302e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent                parser.close();
2303e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent            }
2304e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent        }
2305e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent    }
2306e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent
23079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** @see AudioManager#playSoundEffect(int) */
23089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void playSoundEffect(int effectType) {
23095d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent        playSoundEffectVolume(effectType, -1.0f);
23109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
23119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
23129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** @see AudioManager#playSoundEffect(int, float) */
23139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void playSoundEffectVolume(int effectType, float volume) {
2314559c76dbc37ff25b204ed1f060d3ec2fa43d718cNatalie Silvanovich        if (effectType >= AudioManager.NUM_SOUND_EFFECTS || effectType < 0) {
2315559c76dbc37ff25b204ed1f060d3ec2fa43d718cNatalie Silvanovich            Log.w(TAG, "AudioService effectType value " + effectType + " out of range");
2316559c76dbc37ff25b204ed1f060d3ec2fa43d718cNatalie Silvanovich            return;
2317559c76dbc37ff25b204ed1f060d3ec2fa43d718cNatalie Silvanovich        }
2318559c76dbc37ff25b204ed1f060d3ec2fa43d718cNatalie Silvanovich
23195d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent        sendMsg(mAudioHandler, MSG_PLAY_SOUND_EFFECT, SENDMSG_QUEUE,
23209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                effectType, (int) (volume * 1000), null, 0);
23219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
23229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
23239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
23249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Loads samples into the soundpool.
23255c17a820f9e46e0756c11795b3e6f89105f2f539Glenn Kasten     * This method must be called at first when sound effects are enabled
23269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
23279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public boolean loadSoundEffects() {
23285d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent        int attempts = 3;
23295d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent        LoadSoundEffectReply reply = new LoadSoundEffectReply();
2330117b7bb5b5a4457711f59bde3dcc83d8f111c524Eric Laurent
23315d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent        synchronized (reply) {
23325d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent            sendMsg(mAudioHandler, MSG_LOAD_SOUND_EFFECTS, SENDMSG_QUEUE, 0, 0, reply, 0);
23335d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent            while ((reply.mStatus == 1) && (attempts-- > 0)) {
2334117b7bb5b5a4457711f59bde3dcc83d8f111c524Eric Laurent                try {
2335167d1a27713ab64cd3c0aa70de96434083ef0400Glenn Kasten                    reply.wait(SOUND_EFFECTS_LOAD_TIMEOUT_MS);
23365d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                } catch (InterruptedException e) {
23375d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    Log.w(TAG, "loadSoundEffects Interrupted while waiting sound pool loaded.");
2338117b7bb5b5a4457711f59bde3dcc83d8f111c524Eric Laurent                }
2339a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent            }
23409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
23415d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent        return (reply.mStatus == 0);
23429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
23439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
23449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
23459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *  Unloads samples from the sound pool.
23469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *  This method can be called to free some memory when
23479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *  sound effects are disabled.
23489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
23499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void unloadSoundEffects() {
23505d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent        sendMsg(mAudioHandler, MSG_UNLOAD_SOUND_EFFECTS, SENDMSG_QUEUE, 0, 0, null, 0);
23519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
23529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2353a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent    class SoundPoolListenerThread extends Thread {
2354a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent        public SoundPoolListenerThread() {
2355a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent            super("SoundPoolListenerThread");
2356a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent        }
2357a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent
2358a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent        @Override
2359a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent        public void run() {
2360a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent
2361a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent            Looper.prepare();
2362a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent            mSoundPoolLooper = Looper.myLooper();
2363a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent
2364a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent            synchronized (mSoundEffectsLock) {
2365a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent                if (mSoundPool != null) {
2366a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent                    mSoundPoolCallBack = new SoundPoolCallback();
2367a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent                    mSoundPool.setOnLoadCompleteListener(mSoundPoolCallBack);
2368a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent                }
2369a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent                mSoundEffectsLock.notify();
2370a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent            }
2371a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent            Looper.loop();
2372a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent        }
2373a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent    }
2374a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent
2375a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent    private final class SoundPoolCallback implements
2376a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent            android.media.SoundPool.OnLoadCompleteListener {
2377a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent
23785d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent        int mStatus = 1; // 1 means neither error nor last sample loaded yet
23795d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent        List<Integer> mSamples = new ArrayList<Integer>();
2380a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent
2381a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent        public int status() {
2382a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent            return mStatus;
2383a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent        }
2384a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent
23855d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent        public void setSamples(int[] samples) {
23865d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent            for (int i = 0; i < samples.length; i++) {
23875d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                // do not wait ack for samples rejected upfront by SoundPool
23885d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                if (samples[i] > 0) {
23895d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    mSamples.add(samples[i]);
23905d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                }
23915d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent            }
2392a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent        }
2393a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent
2394a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent        public void onLoadComplete(SoundPool soundPool, int sampleId, int status) {
2395a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent            synchronized (mSoundEffectsLock) {
23965d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                int i = mSamples.indexOf(sampleId);
23975d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                if (i >= 0) {
23985d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    mSamples.remove(i);
2399a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent                }
24005d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                if ((status != 0) || mSamples. isEmpty()) {
24015d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    mStatus = status;
2402a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent                    mSoundEffectsLock.notify();
2403a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent                }
2404a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent            }
2405a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent        }
2406a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent    }
2407a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent
24084050c93601b3c3609b21cc1e18a29b64747e7fa9Eric Laurent    /** @see AudioManager#reloadAudioSettings() */
24094050c93601b3c3609b21cc1e18a29b64747e7fa9Eric Laurent    public void reloadAudioSettings() {
2410bc0fab1fc2db832ef86d8a33466ec4d68b103ca0Eric Laurent        readAudioSettings(false /*userSwitch*/);
2411bc0fab1fc2db832ef86d8a33466ec4d68b103ca0Eric Laurent    }
2412bc0fab1fc2db832ef86d8a33466ec4d68b103ca0Eric Laurent
2413bc0fab1fc2db832ef86d8a33466ec4d68b103ca0Eric Laurent    private void readAudioSettings(boolean userSwitch) {
24144050c93601b3c3609b21cc1e18a29b64747e7fa9Eric Laurent        // restore ringer mode, ringer mode affected streams, mute affected streams and vibrate settings
24154050c93601b3c3609b21cc1e18a29b64747e7fa9Eric Laurent        readPersistedSettings();
24164050c93601b3c3609b21cc1e18a29b64747e7fa9Eric Laurent
24174050c93601b3c3609b21cc1e18a29b64747e7fa9Eric Laurent        // restore volume settings
24184050c93601b3c3609b21cc1e18a29b64747e7fa9Eric Laurent        int numStreamTypes = AudioSystem.getNumStreamTypes();
24194050c93601b3c3609b21cc1e18a29b64747e7fa9Eric Laurent        for (int streamType = 0; streamType < numStreamTypes; streamType++) {
24204050c93601b3c3609b21cc1e18a29b64747e7fa9Eric Laurent            VolumeStreamState streamState = mStreamStates[streamType];
24214050c93601b3c3609b21cc1e18a29b64747e7fa9Eric Laurent
2422bc0fab1fc2db832ef86d8a33466ec4d68b103ca0Eric Laurent            if (userSwitch && mStreamVolumeAlias[streamType] == AudioSystem.STREAM_MUSIC) {
2423bc0fab1fc2db832ef86d8a33466ec4d68b103ca0Eric Laurent                continue;
2424bc0fab1fc2db832ef86d8a33466ec4d68b103ca0Eric Laurent            }
2425bc0fab1fc2db832ef86d8a33466ec4d68b103ca0Eric Laurent
24268fa4d6f585f40ff5cf5f9bed316d92c64a306f21Eric Laurent            streamState.readSettings();
24278fa4d6f585f40ff5cf5f9bed316d92c64a306f21Eric Laurent            synchronized (VolumeStreamState.class) {
24283172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                // unmute stream that was muted but is not affect by mute anymore
24298fa4d6f585f40ff5cf5f9bed316d92c64a306f21Eric Laurent                if (streamState.isMuted_syncVSS() && ((!isStreamAffectedByMute(streamType) &&
243083a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent                        !isStreamMutedByRingerMode(streamType)) || mUseFixedVolume)) {
24313172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                    int size = streamState.mDeathHandlers.size();
24323172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                    for (int i = 0; i < size; i++) {
24333172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                        streamState.mDeathHandlers.get(i).mMuteCount = 1;
24348fa4d6f585f40ff5cf5f9bed316d92c64a306f21Eric Laurent                        streamState.mDeathHandlers.get(i).mute_syncVSS(false);
24353172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                    }
24363172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                }
24374050c93601b3c3609b21cc1e18a29b64747e7fa9Eric Laurent            }
24384050c93601b3c3609b21cc1e18a29b64747e7fa9Eric Laurent        }
24394050c93601b3c3609b21cc1e18a29b64747e7fa9Eric Laurent
244033902db75011d863009585682bd08560c5b89a75Eric Laurent        // apply new ringer mode before checking volume for alias streams so that streams
244133902db75011d863009585682bd08560c5b89a75Eric Laurent        // muted by ringer mode have the correct volume
2442661f2cf45860d2e10924e6b69966a9afe255f28bJohn Spurlock        setRingerModeInt(getRingerModeInternal(), false);
244333902db75011d863009585682bd08560c5b89a75Eric Laurent
2444212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent        checkAllFixedVolumeDevices();
2445244820185269991186d07068b92985624cede4a5Eric Laurent        checkAllAliasStreamVolumes();
2446244820185269991186d07068b92985624cede4a5Eric Laurent
2447d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent        synchronized (mSafeMediaVolumeState) {
2448aa5ee4d65f8788e2a0afcd198367450853fd72acJohn Spurlock            mMusicActiveMs = MathUtils.constrain(Settings.Secure.getIntForUser(mContentResolver,
2449aa5ee4d65f8788e2a0afcd198367450853fd72acJohn Spurlock                    Settings.Secure.UNSAFE_VOLUME_MUSIC_ACTIVE_MS, 0, UserHandle.USER_CURRENT),
2450aa5ee4d65f8788e2a0afcd198367450853fd72acJohn Spurlock                    0, UNSAFE_VOLUME_MUSIC_ACTIVE_MS_MAX);
2451d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent            if (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_ACTIVE) {
2452f1a457d06c53a901ea08d2d3fb6e766bc06c4d4fEric Laurent                enforceSafeMediaVolume();
2453f1a457d06c53a901ea08d2d3fb6e766bc06c4d4fEric Laurent            }
2454c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent        }
24554050c93601b3c3609b21cc1e18a29b64747e7fa9Eric Laurent    }
24564050c93601b3c3609b21cc1e18a29b64747e7fa9Eric Laurent
2457961cae92540763226648813d111c5b5c3b0f1597Dianne Hackborn    /** @see AudioManager#setSpeakerphoneOn(boolean) */
2458c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent    public void setSpeakerphoneOn(boolean on){
2459dc1d17a1dbfc2ae01c20012133a836b62f5b6930Eric Laurent        if (!checkAudioSettingsPermission("setSpeakerphoneOn()")) {
2460dc1d17a1dbfc2ae01c20012133a836b62f5b6930Eric Laurent            return;
2461dc1d17a1dbfc2ae01c20012133a836b62f5b6930Eric Laurent        }
24627337bee7839238f244fad31112a45389f6ef907cJohan Gustavsson
24637337bee7839238f244fad31112a45389f6ef907cJohan Gustavsson        if (on) {
24647337bee7839238f244fad31112a45389f6ef907cJohan Gustavsson            if (mForcedUseForComm == AudioSystem.FORCE_BT_SCO) {
24657337bee7839238f244fad31112a45389f6ef907cJohan Gustavsson                    sendMsg(mAudioHandler, MSG_SET_FORCE_USE, SENDMSG_QUEUE,
24667337bee7839238f244fad31112a45389f6ef907cJohan Gustavsson                            AudioSystem.FOR_RECORD, AudioSystem.FORCE_NONE, null, 0);
24677337bee7839238f244fad31112a45389f6ef907cJohan Gustavsson            }
24687337bee7839238f244fad31112a45389f6ef907cJohan Gustavsson            mForcedUseForComm = AudioSystem.FORCE_SPEAKER;
24697337bee7839238f244fad31112a45389f6ef907cJohan Gustavsson        } else if (mForcedUseForComm == AudioSystem.FORCE_SPEAKER){
24707337bee7839238f244fad31112a45389f6ef907cJohan Gustavsson            mForcedUseForComm = AudioSystem.FORCE_NONE;
24717337bee7839238f244fad31112a45389f6ef907cJohan Gustavsson        }
2472fa640154f1f42121d81242b2f1a10f03e52f0014Eric Laurent
2473afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent        sendMsg(mAudioHandler, MSG_SET_FORCE_USE, SENDMSG_QUEUE,
2474fa640154f1f42121d81242b2f1a10f03e52f0014Eric Laurent                AudioSystem.FOR_COMMUNICATION, mForcedUseForComm, null, 0);
2475c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent    }
2476c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent
2477c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent    /** @see AudioManager#isSpeakerphoneOn() */
2478c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent    public boolean isSpeakerphoneOn() {
2479fa640154f1f42121d81242b2f1a10f03e52f0014Eric Laurent        return (mForcedUseForComm == AudioSystem.FORCE_SPEAKER);
2480c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent    }
2481c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent
2482961cae92540763226648813d111c5b5c3b0f1597Dianne Hackborn    /** @see AudioManager#setBluetoothScoOn(boolean) */
2483c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent    public void setBluetoothScoOn(boolean on){
2484dc1d17a1dbfc2ae01c20012133a836b62f5b6930Eric Laurent        if (!checkAudioSettingsPermission("setBluetoothScoOn()")) {
2485dc1d17a1dbfc2ae01c20012133a836b62f5b6930Eric Laurent            return;
2486dc1d17a1dbfc2ae01c20012133a836b62f5b6930Eric Laurent        }
24877337bee7839238f244fad31112a45389f6ef907cJohan Gustavsson
24887337bee7839238f244fad31112a45389f6ef907cJohan Gustavsson        if (on) {
24897337bee7839238f244fad31112a45389f6ef907cJohan Gustavsson            mForcedUseForComm = AudioSystem.FORCE_BT_SCO;
24907337bee7839238f244fad31112a45389f6ef907cJohan Gustavsson        } else if (mForcedUseForComm == AudioSystem.FORCE_BT_SCO) {
24917337bee7839238f244fad31112a45389f6ef907cJohan Gustavsson            mForcedUseForComm = AudioSystem.FORCE_NONE;
24927337bee7839238f244fad31112a45389f6ef907cJohan Gustavsson        }
2493fa640154f1f42121d81242b2f1a10f03e52f0014Eric Laurent
2494afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent        sendMsg(mAudioHandler, MSG_SET_FORCE_USE, SENDMSG_QUEUE,
2495fa640154f1f42121d81242b2f1a10f03e52f0014Eric Laurent                AudioSystem.FOR_COMMUNICATION, mForcedUseForComm, null, 0);
2496afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent        sendMsg(mAudioHandler, MSG_SET_FORCE_USE, SENDMSG_QUEUE,
2497fa640154f1f42121d81242b2f1a10f03e52f0014Eric Laurent                AudioSystem.FOR_RECORD, mForcedUseForComm, null, 0);
2498c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent    }
2499c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent
2500c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent    /** @see AudioManager#isBluetoothScoOn() */
2501c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent    public boolean isBluetoothScoOn() {
2502fa640154f1f42121d81242b2f1a10f03e52f0014Eric Laurent        return (mForcedUseForComm == AudioSystem.FORCE_BT_SCO);
2503c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent    }
2504c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent
2505961cae92540763226648813d111c5b5c3b0f1597Dianne Hackborn    /** @see AudioManager#setBluetoothA2dpOn(boolean) */
25067847211fb4699bf6018e29d214a918ed6657319bEric Laurent    public void setBluetoothA2dpOn(boolean on) {
2507c390bed06b4a572e273ead1254da9a932e04dce3Eric Laurent        synchronized (mBluetoothA2dpEnabledLock) {
2508c390bed06b4a572e273ead1254da9a932e04dce3Eric Laurent            mBluetoothA2dpEnabled = on;
2509c390bed06b4a572e273ead1254da9a932e04dce3Eric Laurent            sendMsg(mAudioHandler, MSG_SET_FORCE_BT_A2DP_USE, SENDMSG_QUEUE,
2510c390bed06b4a572e273ead1254da9a932e04dce3Eric Laurent                    AudioSystem.FOR_MEDIA,
2511c390bed06b4a572e273ead1254da9a932e04dce3Eric Laurent                    mBluetoothA2dpEnabled ? AudioSystem.FORCE_NONE : AudioSystem.FORCE_NO_BT_A2DP,
2512c390bed06b4a572e273ead1254da9a932e04dce3Eric Laurent                    null, 0);
2513c390bed06b4a572e273ead1254da9a932e04dce3Eric Laurent        }
25147847211fb4699bf6018e29d214a918ed6657319bEric Laurent    }
25157847211fb4699bf6018e29d214a918ed6657319bEric Laurent
25167847211fb4699bf6018e29d214a918ed6657319bEric Laurent    /** @see AudioManager#isBluetoothA2dpOn() */
25177847211fb4699bf6018e29d214a918ed6657319bEric Laurent    public boolean isBluetoothA2dpOn() {
25187847211fb4699bf6018e29d214a918ed6657319bEric Laurent        synchronized (mBluetoothA2dpEnabledLock) {
25197847211fb4699bf6018e29d214a918ed6657319bEric Laurent            return mBluetoothA2dpEnabled;
25207847211fb4699bf6018e29d214a918ed6657319bEric Laurent        }
25217847211fb4699bf6018e29d214a918ed6657319bEric Laurent    }
25227847211fb4699bf6018e29d214a918ed6657319bEric Laurent
25233def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent    /** @see AudioManager#startBluetoothSco() */
252483900754f357616b9e56eaf7fc85f49b8906e987Eric Laurent    public void startBluetoothSco(IBinder cb, int targetSdkVersion) {
252583900754f357616b9e56eaf7fc85f49b8906e987Eric Laurent        int scoAudioMode =
252683900754f357616b9e56eaf7fc85f49b8906e987Eric Laurent                (targetSdkVersion < Build.VERSION_CODES.JELLY_BEAN_MR2) ?
2527f4e51d82d2e34e6832903f01eaecc15ded6c3241Liejun Tao                        SCO_MODE_VIRTUAL_CALL : SCO_MODE_UNDEFINED;
252883900754f357616b9e56eaf7fc85f49b8906e987Eric Laurent        startBluetoothScoInt(cb, scoAudioMode);
252983900754f357616b9e56eaf7fc85f49b8906e987Eric Laurent    }
253083900754f357616b9e56eaf7fc85f49b8906e987Eric Laurent
253183900754f357616b9e56eaf7fc85f49b8906e987Eric Laurent    /** @see AudioManager#startBluetoothScoVirtualCall() */
253283900754f357616b9e56eaf7fc85f49b8906e987Eric Laurent    public void startBluetoothScoVirtualCall(IBinder cb) {
253383900754f357616b9e56eaf7fc85f49b8906e987Eric Laurent        startBluetoothScoInt(cb, SCO_MODE_VIRTUAL_CALL);
253483900754f357616b9e56eaf7fc85f49b8906e987Eric Laurent    }
253583900754f357616b9e56eaf7fc85f49b8906e987Eric Laurent
253683900754f357616b9e56eaf7fc85f49b8906e987Eric Laurent    void startBluetoothScoInt(IBinder cb, int scoAudioMode){
2537dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent        if (!checkAudioSettingsPermission("startBluetoothSco()") ||
25384a5eeb9c727d77bb57fef87a70c8c9cc23dbfee3Eric Laurent                !mSystemReady) {
25393def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent            return;
25403def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent        }
2541854938a72d968c1bc0de4e2b0ea87777cfebc045Eric Laurent        ScoClient client = getScoClient(cb, true);
2542f5a1fc3c0fd733acd21e1437f153ba27220be8ceEric Laurent        // The calling identity must be cleared before calling ScoClient.incCount().
2543f5a1fc3c0fd733acd21e1437f153ba27220be8ceEric Laurent        // inCount() calls requestScoState() which in turn can call BluetoothHeadset APIs
2544f5a1fc3c0fd733acd21e1437f153ba27220be8ceEric Laurent        // and this must be done on behalf of system server to make sure permissions are granted.
2545f5a1fc3c0fd733acd21e1437f153ba27220be8ceEric Laurent        // The caller identity must be cleared after getScoClient() because it is needed if a new
2546f5a1fc3c0fd733acd21e1437f153ba27220be8ceEric Laurent        // client is created.
2547f5a1fc3c0fd733acd21e1437f153ba27220be8ceEric Laurent        final long ident = Binder.clearCallingIdentity();
254883900754f357616b9e56eaf7fc85f49b8906e987Eric Laurent        client.incCount(scoAudioMode);
25492a57ca931fefe817b6110101289721acaacfc808Eric Laurent        Binder.restoreCallingIdentity(ident);
25503def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent    }
25513def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent
25523def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent    /** @see AudioManager#stopBluetoothSco() */
25533def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent    public void stopBluetoothSco(IBinder cb){
2554dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent        if (!checkAudioSettingsPermission("stopBluetoothSco()") ||
25554a5eeb9c727d77bb57fef87a70c8c9cc23dbfee3Eric Laurent                !mSystemReady) {
25563def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent            return;
25573def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent        }
2558854938a72d968c1bc0de4e2b0ea87777cfebc045Eric Laurent        ScoClient client = getScoClient(cb, false);
2559f5a1fc3c0fd733acd21e1437f153ba27220be8ceEric Laurent        // The calling identity must be cleared before calling ScoClient.decCount().
2560f5a1fc3c0fd733acd21e1437f153ba27220be8ceEric Laurent        // decCount() calls requestScoState() which in turn can call BluetoothHeadset APIs
2561f5a1fc3c0fd733acd21e1437f153ba27220be8ceEric Laurent        // and this must be done on behalf of system server to make sure permissions are granted.
2562f5a1fc3c0fd733acd21e1437f153ba27220be8ceEric Laurent        final long ident = Binder.clearCallingIdentity();
2563854938a72d968c1bc0de4e2b0ea87777cfebc045Eric Laurent        if (client != null) {
2564854938a72d968c1bc0de4e2b0ea87777cfebc045Eric Laurent            client.decCount();
2565854938a72d968c1bc0de4e2b0ea87777cfebc045Eric Laurent        }
25662a57ca931fefe817b6110101289721acaacfc808Eric Laurent        Binder.restoreCallingIdentity(ident);
25673def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent    }
25683def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent
25697847211fb4699bf6018e29d214a918ed6657319bEric Laurent
25703def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent    private class ScoClient implements IBinder.DeathRecipient {
25713def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent        private IBinder mCb; // To be notified of client's death
2572f1ddd51f9cd2f92b922bc636c307210a8d587c25Marco Nelissen        private int mCreatorPid;
25733def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent        private int mStartcount; // number of SCO connections started by this client
25743def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent
25753def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent        ScoClient(IBinder cb) {
25763def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent            mCb = cb;
2577f1ddd51f9cd2f92b922bc636c307210a8d587c25Marco Nelissen            mCreatorPid = Binder.getCallingPid();
25783def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent            mStartcount = 0;
25793def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent        }
25803def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent
25813def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent        public void binderDied() {
25823def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent            synchronized(mScoClients) {
25833def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                Log.w(TAG, "SCO client died");
25843def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                int index = mScoClients.indexOf(this);
25853def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                if (index < 0) {
25863def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                    Log.w(TAG, "unregistered SCO client died");
25873def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                } else {
25883def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                    clearCount(true);
25893def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                    mScoClients.remove(this);
25903def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                }
25913def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent            }
25923def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent        }
25933def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent
259483900754f357616b9e56eaf7fc85f49b8906e987Eric Laurent        public void incCount(int scoAudioMode) {
25953def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent            synchronized(mScoClients) {
259683900754f357616b9e56eaf7fc85f49b8906e987Eric Laurent                requestScoState(BluetoothHeadset.STATE_AUDIO_CONNECTED, scoAudioMode);
25973def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                if (mStartcount == 0) {
25983def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                    try {
25993def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                        mCb.linkToDeath(this, 0);
26003def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                    } catch (RemoteException e) {
26013def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                        // client has already died!
26023def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                        Log.w(TAG, "ScoClient  incCount() could not link to "+mCb+" binder death");
26033def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                    }
26043def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                }
26053def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                mStartcount++;
26063def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent            }
26073def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent        }
26083def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent
26093def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent        public void decCount() {
26103def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent            synchronized(mScoClients) {
26113def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                if (mStartcount == 0) {
26123def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                    Log.w(TAG, "ScoClient.decCount() already 0");
26133def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                } else {
26143def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                    mStartcount--;
26153def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                    if (mStartcount == 0) {
2616e2dd8c4592762414c2c27e4589be7edc91a5ecaeEric Laurent                        try {
2617e2dd8c4592762414c2c27e4589be7edc91a5ecaeEric Laurent                            mCb.unlinkToDeath(this, 0);
2618e2dd8c4592762414c2c27e4589be7edc91a5ecaeEric Laurent                        } catch (NoSuchElementException e) {
2619e2dd8c4592762414c2c27e4589be7edc91a5ecaeEric Laurent                            Log.w(TAG, "decCount() going to 0 but not registered to binder");
2620e2dd8c4592762414c2c27e4589be7edc91a5ecaeEric Laurent                        }
26213def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                    }
2622c18c9138cee0f0859bcab636a004ce92ca4a9ab5Eric Laurent                    requestScoState(BluetoothHeadset.STATE_AUDIO_DISCONNECTED, 0);
26233def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                }
26243def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent            }
26253def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent        }
26263def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent
26273def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent        public void clearCount(boolean stopSco) {
26283def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent            synchronized(mScoClients) {
2629e2dd8c4592762414c2c27e4589be7edc91a5ecaeEric Laurent                if (mStartcount != 0) {
2630e2dd8c4592762414c2c27e4589be7edc91a5ecaeEric Laurent                    try {
2631e2dd8c4592762414c2c27e4589be7edc91a5ecaeEric Laurent                        mCb.unlinkToDeath(this, 0);
2632e2dd8c4592762414c2c27e4589be7edc91a5ecaeEric Laurent                    } catch (NoSuchElementException e) {
2633e2dd8c4592762414c2c27e4589be7edc91a5ecaeEric Laurent                        Log.w(TAG, "clearCount() mStartcount: "+mStartcount+" != 0 but not registered to binder");
2634e2dd8c4592762414c2c27e4589be7edc91a5ecaeEric Laurent                    }
2635e2dd8c4592762414c2c27e4589be7edc91a5ecaeEric Laurent                }
26363def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                mStartcount = 0;
26373def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                if (stopSco) {
2638c18c9138cee0f0859bcab636a004ce92ca4a9ab5Eric Laurent                    requestScoState(BluetoothHeadset.STATE_AUDIO_DISCONNECTED, 0);
26393def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                }
26403def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent            }
26413def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent        }
26423def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent
26433def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent        public int getCount() {
26443def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent            return mStartcount;
26453def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent        }
26463def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent
26473def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent        public IBinder getBinder() {
26483def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent            return mCb;
26493def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent        }
26503def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent
2651d7454be47f4111c0478a502353e11dea401378bdEric Laurent        public int getPid() {
2652d7454be47f4111c0478a502353e11dea401378bdEric Laurent            return mCreatorPid;
2653d7454be47f4111c0478a502353e11dea401378bdEric Laurent        }
2654d7454be47f4111c0478a502353e11dea401378bdEric Laurent
26553def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent        public int totalCount() {
26563def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent            synchronized(mScoClients) {
26573def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                int count = 0;
26583def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                int size = mScoClients.size();
26593def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                for (int i = 0; i < size; i++) {
26603def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                    count += mScoClients.get(i).getCount();
26613def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                }
26623def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                return count;
26633def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent            }
26643def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent        }
26653def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent
266683900754f357616b9e56eaf7fc85f49b8906e987Eric Laurent        private void requestScoState(int state, int scoAudioMode) {
266762ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent            checkScoAudioState();
2668dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent            if (totalCount() == 0) {
2669dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                if (state == BluetoothHeadset.STATE_AUDIO_CONNECTED) {
2670dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                    // Make sure that the state transitions to CONNECTING even if we cannot initiate
2671dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                    // the connection.
2672dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                    broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_CONNECTING);
2673dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                    // Accept SCO audio activation only in NORMAL audio mode or if the mode is
2674f1ddd51f9cd2f92b922bc636c307210a8d587c25Marco Nelissen                    // currently controlled by the same client process.
26759f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                    synchronized(mSetModeDeathHandlers) {
26769f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                        if ((mSetModeDeathHandlers.isEmpty() ||
26779f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                                mSetModeDeathHandlers.get(0).getPid() == mCreatorPid) &&
26789f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                                (mScoAudioState == SCO_STATE_INACTIVE ||
26799f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                                 mScoAudioState == SCO_STATE_DEACTIVATE_REQ)) {
26809f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                            if (mScoAudioState == SCO_STATE_INACTIVE) {
268183900754f357616b9e56eaf7fc85f49b8906e987Eric Laurent                                mScoAudioMode = scoAudioMode;
2682f4e51d82d2e34e6832903f01eaecc15ded6c3241Liejun Tao                                if (scoAudioMode == SCO_MODE_UNDEFINED) {
2683570cc5302a2e076f2b6ce810f9ac6f3c53bcd125Andre Eisenbach                                    if (mBluetoothHeadsetDevice != null) {
2684570cc5302a2e076f2b6ce810f9ac6f3c53bcd125Andre Eisenbach                                        mScoAudioMode = new Integer(Settings.Global.getInt(
2685570cc5302a2e076f2b6ce810f9ac6f3c53bcd125Andre Eisenbach                                                                mContentResolver,
2686570cc5302a2e076f2b6ce810f9ac6f3c53bcd125Andre Eisenbach                                                                "bluetooth_sco_channel_"+
2687570cc5302a2e076f2b6ce810f9ac6f3c53bcd125Andre Eisenbach                                                                mBluetoothHeadsetDevice.getAddress(),
2688570cc5302a2e076f2b6ce810f9ac6f3c53bcd125Andre Eisenbach                                                                SCO_MODE_VIRTUAL_CALL));
2689570cc5302a2e076f2b6ce810f9ac6f3c53bcd125Andre Eisenbach                                        if (mScoAudioMode > SCO_MODE_MAX || mScoAudioMode < 0) {
2690570cc5302a2e076f2b6ce810f9ac6f3c53bcd125Andre Eisenbach                                            mScoAudioMode = SCO_MODE_VIRTUAL_CALL;
2691570cc5302a2e076f2b6ce810f9ac6f3c53bcd125Andre Eisenbach                                        }
2692570cc5302a2e076f2b6ce810f9ac6f3c53bcd125Andre Eisenbach                                    } else {
2693570cc5302a2e076f2b6ce810f9ac6f3c53bcd125Andre Eisenbach                                        mScoAudioMode = SCO_MODE_RAW;
2694f4e51d82d2e34e6832903f01eaecc15ded6c3241Liejun Tao                                    }
2695f4e51d82d2e34e6832903f01eaecc15ded6c3241Liejun Tao                                }
26969f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                                if (mBluetoothHeadset != null && mBluetoothHeadsetDevice != null) {
2697f4e51d82d2e34e6832903f01eaecc15ded6c3241Liejun Tao                                    boolean status = false;
2698c18c9138cee0f0859bcab636a004ce92ca4a9ab5Eric Laurent                                    if (mScoAudioMode == SCO_MODE_RAW) {
2699c18c9138cee0f0859bcab636a004ce92ca4a9ab5Eric Laurent                                        status = mBluetoothHeadset.connectAudio();
2700f4e51d82d2e34e6832903f01eaecc15ded6c3241Liejun Tao                                    } else if (mScoAudioMode == SCO_MODE_VIRTUAL_CALL) {
2701c18c9138cee0f0859bcab636a004ce92ca4a9ab5Eric Laurent                                        status = mBluetoothHeadset.startScoUsingVirtualVoiceCall(
2702c18c9138cee0f0859bcab636a004ce92ca4a9ab5Eric Laurent                                                                            mBluetoothHeadsetDevice);
2703f4e51d82d2e34e6832903f01eaecc15ded6c3241Liejun Tao                                    } else if (mScoAudioMode == SCO_MODE_VR) {
2704f4e51d82d2e34e6832903f01eaecc15ded6c3241Liejun Tao                                        status = mBluetoothHeadset.startVoiceRecognition(
2705f4e51d82d2e34e6832903f01eaecc15ded6c3241Liejun Tao                                                                           mBluetoothHeadsetDevice);
2706c18c9138cee0f0859bcab636a004ce92ca4a9ab5Eric Laurent                                    }
2707f4e51d82d2e34e6832903f01eaecc15ded6c3241Liejun Tao
2708c18c9138cee0f0859bcab636a004ce92ca4a9ab5Eric Laurent                                    if (status) {
27099f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                                        mScoAudioState = SCO_STATE_ACTIVE_INTERNAL;
27109f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                                    } else {
27119f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                                        broadcastScoConnectionState(
27129f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                                                AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
27139f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                                    }
27149f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                                } else if (getBluetoothHeadset()) {
27159f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                                    mScoAudioState = SCO_STATE_ACTIVATE_REQ;
2716dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                                }
27179f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                            } else {
27189f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                                mScoAudioState = SCO_STATE_ACTIVE_INTERNAL;
27199f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                                broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_CONNECTED);
2720dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                            }
2721dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                        } else {
27229f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                            broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
2723dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                        }
2724dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                    }
272562ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent                } else if (state == BluetoothHeadset.STATE_AUDIO_DISCONNECTED &&
2726dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                              (mScoAudioState == SCO_STATE_ACTIVE_INTERNAL ||
2727dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                               mScoAudioState == SCO_STATE_ACTIVATE_REQ)) {
2728dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                    if (mScoAudioState == SCO_STATE_ACTIVE_INTERNAL) {
2729671db6f3ba1fdb3c907e0735fe6d0d284f5c34deMarco Nelissen                        if (mBluetoothHeadset != null && mBluetoothHeadsetDevice != null) {
2730f4e51d82d2e34e6832903f01eaecc15ded6c3241Liejun Tao                            boolean status = false;
2731c18c9138cee0f0859bcab636a004ce92ca4a9ab5Eric Laurent                            if (mScoAudioMode == SCO_MODE_RAW) {
2732c18c9138cee0f0859bcab636a004ce92ca4a9ab5Eric Laurent                                status = mBluetoothHeadset.disconnectAudio();
2733f4e51d82d2e34e6832903f01eaecc15ded6c3241Liejun Tao                            } else if (mScoAudioMode == SCO_MODE_VIRTUAL_CALL) {
2734c18c9138cee0f0859bcab636a004ce92ca4a9ab5Eric Laurent                                status = mBluetoothHeadset.stopScoUsingVirtualVoiceCall(
2735c18c9138cee0f0859bcab636a004ce92ca4a9ab5Eric Laurent                                                                        mBluetoothHeadsetDevice);
2736f4e51d82d2e34e6832903f01eaecc15ded6c3241Liejun Tao                            } else if (mScoAudioMode == SCO_MODE_VR) {
2737f4e51d82d2e34e6832903f01eaecc15ded6c3241Liejun Tao                                        status = mBluetoothHeadset.stopVoiceRecognition(
2738f4e51d82d2e34e6832903f01eaecc15ded6c3241Liejun Tao                                                                      mBluetoothHeadsetDevice);
2739c18c9138cee0f0859bcab636a004ce92ca4a9ab5Eric Laurent                            }
2740f4e51d82d2e34e6832903f01eaecc15ded6c3241Liejun Tao
2741c18c9138cee0f0859bcab636a004ce92ca4a9ab5Eric Laurent                            if (!status) {
2742dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                                mScoAudioState = SCO_STATE_INACTIVE;
2743dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                                broadcastScoConnectionState(
2744dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                                        AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
2745dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                            }
2746dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                        } else if (getBluetoothHeadset()) {
2747dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                            mScoAudioState = SCO_STATE_DEACTIVATE_REQ;
2748dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                        }
2749dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                    } else {
2750dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                        mScoAudioState = SCO_STATE_INACTIVE;
2751dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                        broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
2752dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                    }
27533def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                }
27543def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent            }
27553def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent        }
27563def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent    }
27573def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent
275862ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent    private void checkScoAudioState() {
275962ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent        if (mBluetoothHeadset != null && mBluetoothHeadsetDevice != null &&
2760dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                mScoAudioState == SCO_STATE_INACTIVE &&
276162ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent                mBluetoothHeadset.getAudioState(mBluetoothHeadsetDevice)
276262ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent                != BluetoothHeadset.STATE_AUDIO_DISCONNECTED) {
276362ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent            mScoAudioState = SCO_STATE_ACTIVE_EXTERNAL;
276462ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent        }
276562ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent    }
276662ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent
2767854938a72d968c1bc0de4e2b0ea87777cfebc045Eric Laurent    private ScoClient getScoClient(IBinder cb, boolean create) {
27683def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent        synchronized(mScoClients) {
2769854938a72d968c1bc0de4e2b0ea87777cfebc045Eric Laurent            ScoClient client = null;
27703def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent            int size = mScoClients.size();
27713def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent            for (int i = 0; i < size; i++) {
27723def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                client = mScoClients.get(i);
27733def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                if (client.getBinder() == cb)
27743def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                    return client;
27753def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent            }
2776854938a72d968c1bc0de4e2b0ea87777cfebc045Eric Laurent            if (create) {
2777854938a72d968c1bc0de4e2b0ea87777cfebc045Eric Laurent                client = new ScoClient(cb);
2778854938a72d968c1bc0de4e2b0ea87777cfebc045Eric Laurent                mScoClients.add(client);
2779854938a72d968c1bc0de4e2b0ea87777cfebc045Eric Laurent            }
27803def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent            return client;
27813def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent        }
27823def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent    }
27833def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent
2784d7454be47f4111c0478a502353e11dea401378bdEric Laurent    public void clearAllScoClients(int exceptPid, boolean stopSco) {
27853def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent        synchronized(mScoClients) {
2786854938a72d968c1bc0de4e2b0ea87777cfebc045Eric Laurent            ScoClient savedClient = null;
27873def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent            int size = mScoClients.size();
27883def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent            for (int i = 0; i < size; i++) {
2789854938a72d968c1bc0de4e2b0ea87777cfebc045Eric Laurent                ScoClient cl = mScoClients.get(i);
2790d7454be47f4111c0478a502353e11dea401378bdEric Laurent                if (cl.getPid() != exceptPid) {
2791854938a72d968c1bc0de4e2b0ea87777cfebc045Eric Laurent                    cl.clearCount(stopSco);
2792854938a72d968c1bc0de4e2b0ea87777cfebc045Eric Laurent                } else {
2793854938a72d968c1bc0de4e2b0ea87777cfebc045Eric Laurent                    savedClient = cl;
2794854938a72d968c1bc0de4e2b0ea87777cfebc045Eric Laurent                }
2795854938a72d968c1bc0de4e2b0ea87777cfebc045Eric Laurent            }
2796854938a72d968c1bc0de4e2b0ea87777cfebc045Eric Laurent            mScoClients.clear();
2797854938a72d968c1bc0de4e2b0ea87777cfebc045Eric Laurent            if (savedClient != null) {
2798854938a72d968c1bc0de4e2b0ea87777cfebc045Eric Laurent                mScoClients.add(savedClient);
27993def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent            }
28003def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent        }
28013def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent    }
28023def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent
2803dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent    private boolean getBluetoothHeadset() {
2804dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent        boolean result = false;
2805dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent        BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
2806dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent        if (adapter != null) {
2807dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent            result = adapter.getProfileProxy(mContext, mBluetoothProfileServiceListener,
2808dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                                    BluetoothProfile.HEADSET);
2809dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent        }
2810dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent        // If we could not get a bluetooth headset proxy, send a failure message
2811dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent        // without delay to reset the SCO audio state and clear SCO clients.
2812dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent        // If we could get a proxy, send a delayed failure message that will reset our state
2813dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent        // in case we don't receive onServiceConnected().
2814afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent        sendMsg(mAudioHandler, MSG_BT_HEADSET_CNCT_FAILED,
2815dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                SENDMSG_REPLACE, 0, 0, null, result ? BT_HEADSET_CNCT_TIMEOUT_MS : 0);
2816dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent        return result;
2817dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent    }
2818dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent
2819d7454be47f4111c0478a502353e11dea401378bdEric Laurent    private void disconnectBluetoothSco(int exceptPid) {
2820dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent        synchronized(mScoClients) {
2821dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent            checkScoAudioState();
2822dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent            if (mScoAudioState == SCO_STATE_ACTIVE_EXTERNAL ||
2823dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                    mScoAudioState == SCO_STATE_DEACTIVATE_EXT_REQ) {
2824dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                if (mBluetoothHeadsetDevice != null) {
2825dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                    if (mBluetoothHeadset != null) {
2826dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                        if (!mBluetoothHeadset.stopVoiceRecognition(
2827b06ac839dd2d0437fc8314f6deb7233af5af521eEric Laurent                                mBluetoothHeadsetDevice)) {
2828afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent                            sendMsg(mAudioHandler, MSG_BT_HEADSET_CNCT_FAILED,
2829dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                                    SENDMSG_REPLACE, 0, 0, null, 0);
2830dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                        }
2831dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                    } else if (mScoAudioState == SCO_STATE_ACTIVE_EXTERNAL &&
2832dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                            getBluetoothHeadset()) {
2833dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                        mScoAudioState = SCO_STATE_DEACTIVATE_EXT_REQ;
2834dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                    }
2835dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                }
2836dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent            } else {
2837d7454be47f4111c0478a502353e11dea401378bdEric Laurent                clearAllScoClients(exceptPid, true);
2838dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent            }
2839dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent        }
2840dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent    }
2841dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent
2842dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent    private void resetBluetoothSco() {
2843dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent        synchronized(mScoClients) {
2844d7454be47f4111c0478a502353e11dea401378bdEric Laurent            clearAllScoClients(0, false);
2845dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent            mScoAudioState = SCO_STATE_INACTIVE;
2846dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent            broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
2847dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent        }
2848dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent    }
2849dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent
2850dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent    private void broadcastScoConnectionState(int state) {
28512a57ca931fefe817b6110101289721acaacfc808Eric Laurent        sendMsg(mAudioHandler, MSG_BROADCAST_BT_CONNECTION_STATE,
28522a57ca931fefe817b6110101289721acaacfc808Eric Laurent                SENDMSG_QUEUE, state, 0, null, 0);
28532a57ca931fefe817b6110101289721acaacfc808Eric Laurent    }
28542a57ca931fefe817b6110101289721acaacfc808Eric Laurent
28552a57ca931fefe817b6110101289721acaacfc808Eric Laurent    private void onBroadcastScoConnectionState(int state) {
2856dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent        if (state != mScoConnectionState) {
2857dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent            Intent newIntent = new Intent(AudioManager.ACTION_SCO_AUDIO_STATE_UPDATED);
2858dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent            newIntent.putExtra(AudioManager.EXTRA_SCO_AUDIO_STATE, state);
2859dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent            newIntent.putExtra(AudioManager.EXTRA_SCO_AUDIO_PREVIOUS_STATE,
2860dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                    mScoConnectionState);
28615ac72a29593ab9a20337a2225df52bdf4754be02Dianne Hackborn            sendStickyBroadcastToAll(newIntent);
2862dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent            mScoConnectionState = state;
2863dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent        }
2864dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent    }
2865dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent
286682aa7f017daaaeb96c13e6e3491d5037ab471085Jaikumar Ganesh    private BluetoothProfile.ServiceListener mBluetoothProfileServiceListener =
286782aa7f017daaaeb96c13e6e3491d5037ab471085Jaikumar Ganesh        new BluetoothProfile.ServiceListener() {
286882aa7f017daaaeb96c13e6e3491d5037ab471085Jaikumar Ganesh        public void onServiceConnected(int profile, BluetoothProfile proxy) {
28696bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent            BluetoothDevice btDevice;
28706bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent            List<BluetoothDevice> deviceList;
28716bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent            switch(profile) {
28726bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent            case BluetoothProfile.A2DP:
28735a0cf7a27f3953a1266af48543ccd9024f4cd89fJohn Du                synchronized (mA2dpAvrcpLock) {
28745a0cf7a27f3953a1266af48543ccd9024f4cd89fJohn Du                    mA2dp = (BluetoothA2dp) proxy;
28755a0cf7a27f3953a1266af48543ccd9024f4cd89fJohn Du                    deviceList = mA2dp.getConnectedDevices();
28765a0cf7a27f3953a1266af48543ccd9024f4cd89fJohn Du                    if (deviceList.size() > 0) {
28775a0cf7a27f3953a1266af48543ccd9024f4cd89fJohn Du                        btDevice = deviceList.get(0);
28785a0cf7a27f3953a1266af48543ccd9024f4cd89fJohn Du                        synchronized (mConnectedDevices) {
28795a0cf7a27f3953a1266af48543ccd9024f4cd89fJohn Du                            int state = mA2dp.getConnectionState(btDevice);
28805a0cf7a27f3953a1266af48543ccd9024f4cd89fJohn Du                            int delay = checkSendBecomingNoisyIntent(
28810a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood                                                AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
28820a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood                                                (state == BluetoothA2dp.STATE_CONNECTED) ? 1 : 0);
28835a0cf7a27f3953a1266af48543ccd9024f4cd89fJohn Du                            queueMsgUnderWakeLock(mAudioHandler,
28840a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood                                    MSG_SET_A2DP_SINK_CONNECTION_STATE,
28855a0cf7a27f3953a1266af48543ccd9024f4cd89fJohn Du                                    state,
28865a0cf7a27f3953a1266af48543ccd9024f4cd89fJohn Du                                    0,
28875a0cf7a27f3953a1266af48543ccd9024f4cd89fJohn Du                                    btDevice,
28885a0cf7a27f3953a1266af48543ccd9024f4cd89fJohn Du                                    delay);
28895a0cf7a27f3953a1266af48543ccd9024f4cd89fJohn Du                        }
2890b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent                    }
28916bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                }
28926bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                break;
28936bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent
28940a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood            case BluetoothProfile.A2DP_SINK:
28950a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood                deviceList = proxy.getConnectedDevices();
28960a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood                if (deviceList.size() > 0) {
28970a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood                    btDevice = deviceList.get(0);
28980a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood                    synchronized (mConnectedDevices) {
28990a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood                        int state = proxy.getConnectionState(btDevice);
29000a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood                        queueMsgUnderWakeLock(mAudioHandler,
29010a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood                                MSG_SET_A2DP_SRC_CONNECTION_STATE,
29020a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood                                state,
29030a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood                                0,
29040a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood                                btDevice,
29050a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood                                0 /* delay */);
29060a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood                    }
29070a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood                }
29080a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood                break;
29090a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood
29106bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent            case BluetoothProfile.HEADSET:
29116bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                synchronized (mScoClients) {
29126bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                    // Discard timeout message
29136bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                    mAudioHandler.removeMessages(MSG_BT_HEADSET_CNCT_FAILED);
29146bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                    mBluetoothHeadset = (BluetoothHeadset) proxy;
29156bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                    deviceList = mBluetoothHeadset.getConnectedDevices();
29166bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                    if (deviceList.size() > 0) {
29176bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                        mBluetoothHeadsetDevice = deviceList.get(0);
29186bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                    } else {
29196bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                        mBluetoothHeadsetDevice = null;
2920dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                    }
29216bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                    // Refresh SCO audio state
29226bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                    checkScoAudioState();
29236bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                    // Continue pending action if any
29246bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                    if (mScoAudioState == SCO_STATE_ACTIVATE_REQ ||
29256bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                            mScoAudioState == SCO_STATE_DEACTIVATE_REQ ||
29266bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                            mScoAudioState == SCO_STATE_DEACTIVATE_EXT_REQ) {
29276bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                        boolean status = false;
29286bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                        if (mBluetoothHeadsetDevice != null) {
29296bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                            switch (mScoAudioState) {
29306bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                            case SCO_STATE_ACTIVATE_REQ:
29316bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                                mScoAudioState = SCO_STATE_ACTIVE_INTERNAL;
2932c18c9138cee0f0859bcab636a004ce92ca4a9ab5Eric Laurent                                if (mScoAudioMode == SCO_MODE_RAW) {
2933c18c9138cee0f0859bcab636a004ce92ca4a9ab5Eric Laurent                                    status = mBluetoothHeadset.connectAudio();
2934f4e51d82d2e34e6832903f01eaecc15ded6c3241Liejun Tao                                } else if (mScoAudioMode == SCO_MODE_VIRTUAL_CALL) {
2935c18c9138cee0f0859bcab636a004ce92ca4a9ab5Eric Laurent                                    status = mBluetoothHeadset.startScoUsingVirtualVoiceCall(
2936c18c9138cee0f0859bcab636a004ce92ca4a9ab5Eric Laurent                                                                        mBluetoothHeadsetDevice);
2937f4e51d82d2e34e6832903f01eaecc15ded6c3241Liejun Tao                                } else if (mScoAudioMode == SCO_MODE_VR) {
2938f4e51d82d2e34e6832903f01eaecc15ded6c3241Liejun Tao                                    status = mBluetoothHeadset.startVoiceRecognition(
2939f4e51d82d2e34e6832903f01eaecc15ded6c3241Liejun Tao                                                                      mBluetoothHeadsetDevice);
2940c18c9138cee0f0859bcab636a004ce92ca4a9ab5Eric Laurent                                }
29416bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                                break;
29426bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                            case SCO_STATE_DEACTIVATE_REQ:
2943c18c9138cee0f0859bcab636a004ce92ca4a9ab5Eric Laurent                                if (mScoAudioMode == SCO_MODE_RAW) {
2944c18c9138cee0f0859bcab636a004ce92ca4a9ab5Eric Laurent                                    status = mBluetoothHeadset.disconnectAudio();
2945f4e51d82d2e34e6832903f01eaecc15ded6c3241Liejun Tao                                } else if (mScoAudioMode == SCO_MODE_VIRTUAL_CALL) {
2946c18c9138cee0f0859bcab636a004ce92ca4a9ab5Eric Laurent                                    status = mBluetoothHeadset.stopScoUsingVirtualVoiceCall(
2947c18c9138cee0f0859bcab636a004ce92ca4a9ab5Eric Laurent                                                                        mBluetoothHeadsetDevice);
2948f4e51d82d2e34e6832903f01eaecc15ded6c3241Liejun Tao                                } else if (mScoAudioMode == SCO_MODE_VR) {
2949f4e51d82d2e34e6832903f01eaecc15ded6c3241Liejun Tao                                    status = mBluetoothHeadset.stopVoiceRecognition(
2950f4e51d82d2e34e6832903f01eaecc15ded6c3241Liejun Tao                                                                      mBluetoothHeadsetDevice);
2951c18c9138cee0f0859bcab636a004ce92ca4a9ab5Eric Laurent                                }
29526bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                                break;
29536bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                            case SCO_STATE_DEACTIVATE_EXT_REQ:
29546bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                                status = mBluetoothHeadset.stopVoiceRecognition(
29556bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                                        mBluetoothHeadsetDevice);
29566bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                            }
29576bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                        }
29586bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                        if (!status) {
2959afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent                            sendMsg(mAudioHandler, MSG_BT_HEADSET_CNCT_FAILED,
29606bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                                    SENDMSG_REPLACE, 0, 0, null, 0);
29616bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                        }
2962dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                    }
2963dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                }
29646bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                break;
29656bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent
29666bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent            default:
29676bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                break;
29683def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent            }
29693def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent        }
297082aa7f017daaaeb96c13e6e3491d5037ab471085Jaikumar Ganesh        public void onServiceDisconnected(int profile) {
29716bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent            switch(profile) {
29726bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent            case BluetoothProfile.A2DP:
29735a0cf7a27f3953a1266af48543ccd9024f4cd89fJohn Du                synchronized (mA2dpAvrcpLock) {
29745a0cf7a27f3953a1266af48543ccd9024f4cd89fJohn Du                    mA2dp = null;
29755a0cf7a27f3953a1266af48543ccd9024f4cd89fJohn Du                    synchronized (mConnectedDevices) {
29765a0cf7a27f3953a1266af48543ccd9024f4cd89fJohn Du                        if (mConnectedDevices.containsKey(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP)) {
29775a0cf7a27f3953a1266af48543ccd9024f4cd89fJohn Du                            makeA2dpDeviceUnavailableNow(
29785a0cf7a27f3953a1266af48543ccd9024f4cd89fJohn Du                                    mConnectedDevices.get(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP));
29795a0cf7a27f3953a1266af48543ccd9024f4cd89fJohn Du                        }
29806bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                    }
29816bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                }
29826bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                break;
29836bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent
29840a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood            case BluetoothProfile.A2DP_SINK:
29850a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood                synchronized (mConnectedDevices) {
29860a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood                    if (mConnectedDevices.containsKey(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP)) {
29870a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood                        makeA2dpSrcUnavailable(
29880a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood                                mConnectedDevices.get(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP));
29890a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood                    }
29900a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood                }
29910a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood                break;
29920a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood
29936bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent            case BluetoothProfile.HEADSET:
29946bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                synchronized (mScoClients) {
29956bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                    mBluetoothHeadset = null;
29966bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                }
29976bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                break;
29986bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent
29996bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent            default:
30006bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                break;
30013def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent            }
30023def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent        }
30033def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent    };
3004d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi
3005c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent    private void onCheckMusicActive() {
3006d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent        synchronized (mSafeMediaVolumeState) {
3007d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent            if (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_INACTIVE) {
3008c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent                int device = getDeviceForStream(AudioSystem.STREAM_MUSIC);
3009c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent
3010c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent                if ((device & mSafeMediaVolumeDevices) != 0) {
3011c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent                    sendMsg(mAudioHandler,
3012c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent                            MSG_CHECK_MUSIC_ACTIVE,
3013c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent                            SENDMSG_REPLACE,
3014f1a457d06c53a901ea08d2d3fb6e766bc06c4d4fEric Laurent                            0,
3015c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent                            0,
3016c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent                            null,
3017c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent                            MUSIC_ACTIVE_POLL_PERIOD_MS);
301842b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                    int index = mStreamStates[AudioSystem.STREAM_MUSIC].getIndex(device);
3019f1a457d06c53a901ea08d2d3fb6e766bc06c4d4fEric Laurent                    if (AudioSystem.isStreamActive(AudioSystem.STREAM_MUSIC, 0) &&
3020f1a457d06c53a901ea08d2d3fb6e766bc06c4d4fEric Laurent                            (index > mSafeMediaVolumeIndex)) {
3021c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent                        // Approximate cumulative active music time
3022c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent                        mMusicActiveMs += MUSIC_ACTIVE_POLL_PERIOD_MS;
3023c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent                        if (mMusicActiveMs > UNSAFE_VOLUME_MUSIC_ACTIVE_MS_MAX) {
3024c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent                            setSafeMediaVolumeEnabled(true);
3025c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent                            mMusicActiveMs = 0;
3026c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent                        }
3027aa5ee4d65f8788e2a0afcd198367450853fd72acJohn Spurlock                        saveMusicActiveMs();
3028c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent                    }
3029c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent                }
3030c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent            }
3031c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent        }
3032c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent    }
3033c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent
3034aa5ee4d65f8788e2a0afcd198367450853fd72acJohn Spurlock    private void saveMusicActiveMs() {
3035aa5ee4d65f8788e2a0afcd198367450853fd72acJohn Spurlock        mAudioHandler.obtainMessage(MSG_PERSIST_MUSIC_ACTIVE_MS, mMusicActiveMs, 0).sendToTarget();
3036aa5ee4d65f8788e2a0afcd198367450853fd72acJohn Spurlock    }
3037aa5ee4d65f8788e2a0afcd198367450853fd72acJohn Spurlock
3038d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent    private void onConfigureSafeVolume(boolean force) {
3039d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent        synchronized (mSafeMediaVolumeState) {
3040d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent            int mcc = mContext.getResources().getConfiguration().mcc;
3041d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent            if ((mMcc != mcc) || ((mMcc == 0) && force)) {
3042d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent                mSafeMediaVolumeIndex = mContext.getResources().getInteger(
3043d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent                        com.android.internal.R.integer.config_safe_media_volume_index) * 10;
3044351346092acdfbfcc1d9ebf98d539d2a1196c5e8John Spurlock                boolean safeMediaVolumeEnabled =
3045351346092acdfbfcc1d9ebf98d539d2a1196c5e8John Spurlock                        SystemProperties.getBoolean("audio.safemedia.force", false)
3046351346092acdfbfcc1d9ebf98d539d2a1196c5e8John Spurlock                        || mContext.getResources().getBoolean(
3047351346092acdfbfcc1d9ebf98d539d2a1196c5e8John Spurlock                                com.android.internal.R.bool.config_safe_media_volume_enabled);
304805274f348e12983eb8613cc6eb9ae561e8197e28Eric Laurent
304905274f348e12983eb8613cc6eb9ae561e8197e28Eric Laurent                // The persisted state is either "disabled" or "active": this is the state applied
305005274f348e12983eb8613cc6eb9ae561e8197e28Eric Laurent                // next time we boot and cannot be "inactive"
305105274f348e12983eb8613cc6eb9ae561e8197e28Eric Laurent                int persistedState;
3052d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent                if (safeMediaVolumeEnabled) {
305305274f348e12983eb8613cc6eb9ae561e8197e28Eric Laurent                    persistedState = SAFE_MEDIA_VOLUME_ACTIVE;
305405274f348e12983eb8613cc6eb9ae561e8197e28Eric Laurent                    // The state can already be "inactive" here if the user has forced it before
305505274f348e12983eb8613cc6eb9ae561e8197e28Eric Laurent                    // the 30 seconds timeout for forced configuration. In this case we don't reset
305605274f348e12983eb8613cc6eb9ae561e8197e28Eric Laurent                    // it to "active".
305705274f348e12983eb8613cc6eb9ae561e8197e28Eric Laurent                    if (mSafeMediaVolumeState != SAFE_MEDIA_VOLUME_INACTIVE) {
3058aa5ee4d65f8788e2a0afcd198367450853fd72acJohn Spurlock                        if (mMusicActiveMs == 0) {
3059aa5ee4d65f8788e2a0afcd198367450853fd72acJohn Spurlock                            mSafeMediaVolumeState = SAFE_MEDIA_VOLUME_ACTIVE;
3060aa5ee4d65f8788e2a0afcd198367450853fd72acJohn Spurlock                            enforceSafeMediaVolume();
3061aa5ee4d65f8788e2a0afcd198367450853fd72acJohn Spurlock                        } else {
3062aa5ee4d65f8788e2a0afcd198367450853fd72acJohn Spurlock                            // We have existing playback time recorded, already confirmed.
3063aa5ee4d65f8788e2a0afcd198367450853fd72acJohn Spurlock                            mSafeMediaVolumeState = SAFE_MEDIA_VOLUME_INACTIVE;
3064aa5ee4d65f8788e2a0afcd198367450853fd72acJohn Spurlock                        }
306505274f348e12983eb8613cc6eb9ae561e8197e28Eric Laurent                    }
3066d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent                } else {
306705274f348e12983eb8613cc6eb9ae561e8197e28Eric Laurent                    persistedState = SAFE_MEDIA_VOLUME_DISABLED;
3068d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent                    mSafeMediaVolumeState = SAFE_MEDIA_VOLUME_DISABLED;
3069d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent                }
3070d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent                mMcc = mcc;
307105274f348e12983eb8613cc6eb9ae561e8197e28Eric Laurent                sendMsg(mAudioHandler,
307205274f348e12983eb8613cc6eb9ae561e8197e28Eric Laurent                        MSG_PERSIST_SAFE_VOLUME_STATE,
307305274f348e12983eb8613cc6eb9ae561e8197e28Eric Laurent                        SENDMSG_QUEUE,
307405274f348e12983eb8613cc6eb9ae561e8197e28Eric Laurent                        persistedState,
307505274f348e12983eb8613cc6eb9ae561e8197e28Eric Laurent                        0,
307605274f348e12983eb8613cc6eb9ae561e8197e28Eric Laurent                        null,
307705274f348e12983eb8613cc6eb9ae561e8197e28Eric Laurent                        0);
3078d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent            }
3079d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent        }
3080d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent    }
3081d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent
30829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    ///////////////////////////////////////////////////////////////////////////
30839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // Internal methods
30849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    ///////////////////////////////////////////////////////////////////////////
30859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
30869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
30879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Checks if the adjustment should change ringer mode instead of just
30889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * adjusting volume. If so, this will set the proper ringer mode and volume
30899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * indices on the stream states.
30909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
3091a11b4affcad3d255aa723a89b768ea222506f2e8John Spurlock    private int checkForRingerModeChange(int oldIndex, int direction,  int step) {
3092a11b4affcad3d255aa723a89b768ea222506f2e8John Spurlock        int result = FLAG_ADJUST_VOLUME;
3093661f2cf45860d2e10924e6b69966a9afe255f28bJohn Spurlock        int ringerMode = getRingerModeInternal();
3094bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent
3095bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent        switch (ringerMode) {
3096bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent        case RINGER_MODE_NORMAL:
3097bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent            if (direction == AudioManager.ADJUST_LOWER) {
3098bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent                if (mHasVibrator) {
3099244820185269991186d07068b92985624cede4a5Eric Laurent                    // "step" is the delta in internal index units corresponding to a
3100244820185269991186d07068b92985624cede4a5Eric Laurent                    // change of 1 in UI index units.
3101244820185269991186d07068b92985624cede4a5Eric Laurent                    // Because of rounding when rescaling from one stream index range to its alias
3102244820185269991186d07068b92985624cede4a5Eric Laurent                    // index range, we cannot simply test oldIndex == step:
3103244820185269991186d07068b92985624cede4a5Eric Laurent                    //   (step <= oldIndex < 2 * step) is equivalent to: (old UI index == 1)
3104244820185269991186d07068b92985624cede4a5Eric Laurent                    if (step <= oldIndex && oldIndex < 2 * step) {
3105bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent                        ringerMode = RINGER_MODE_VIBRATE;
3106bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent                    }
3107bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent                } else {
3108244820185269991186d07068b92985624cede4a5Eric Laurent                    // (oldIndex < step) is equivalent to (old UI index == 0)
31098600534df66c2ff5846ed230b50c56229322d48aJohn Spurlock                    if ((oldIndex < step)
31108600534df66c2ff5846ed230b50c56229322d48aJohn Spurlock                            && VOLUME_SETS_RINGER_MODE_SILENT
31118600534df66c2ff5846ed230b50c56229322d48aJohn Spurlock                            && mPrevVolDirection != AudioManager.ADJUST_LOWER) {
3112bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent                        ringerMode = RINGER_MODE_SILENT;
3113bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent                    }
31143d4c06f90726a85e89dab13c41ddc15b9c912a3fEric Laurent                }
31156329bf7b1e2217c6c9477bd57349a1edade18417Daniel Sandler            }
3116bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent            break;
3117bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent        case RINGER_MODE_VIBRATE:
3118bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent            if (!mHasVibrator) {
3119bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent                Log.e(TAG, "checkForRingerModeChange() current ringer mode is vibrate" +
3120bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent                        "but no vibrator is present");
3121bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent                break;
3122bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent            }
3123c696a53d1fe4d61373c5dc64dd057d322da90c8fAmith Yamasani            if ((direction == AudioManager.ADJUST_LOWER)) {
3124795a51469701b4339eed4d97b6b06560f2d16d3fJohn Spurlock                if (mPrevVolDirection != AudioManager.ADJUST_LOWER) {
3125795a51469701b4339eed4d97b6b06560f2d16d3fJohn Spurlock                    if (VOLUME_SETS_RINGER_MODE_SILENT) {
3126795a51469701b4339eed4d97b6b06560f2d16d3fJohn Spurlock                        ringerMode = RINGER_MODE_SILENT;
3127795a51469701b4339eed4d97b6b06560f2d16d3fJohn Spurlock                    } else {
3128795a51469701b4339eed4d97b6b06560f2d16d3fJohn Spurlock                        result |= AudioManager.FLAG_SHOW_VIBRATE_HINT;
3129795a51469701b4339eed4d97b6b06560f2d16d3fJohn Spurlock                    }
3130c696a53d1fe4d61373c5dc64dd057d322da90c8fAmith Yamasani                }
3131c696a53d1fe4d61373c5dc64dd057d322da90c8fAmith Yamasani            } else if (direction == AudioManager.ADJUST_RAISE) {
3132bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent                ringerMode = RINGER_MODE_NORMAL;
3133c696a53d1fe4d61373c5dc64dd057d322da90c8fAmith Yamasani            }
3134a11b4affcad3d255aa723a89b768ea222506f2e8John Spurlock            result &= ~FLAG_ADJUST_VOLUME;
3135bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent            break;
3136bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent        case RINGER_MODE_SILENT:
31379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (direction == AudioManager.ADJUST_RAISE) {
3138a11b4affcad3d255aa723a89b768ea222506f2e8John Spurlock                if (PREVENT_VOLUME_ADJUSTMENT_IF_SILENT) {
3139a11b4affcad3d255aa723a89b768ea222506f2e8John Spurlock                    result |= AudioManager.FLAG_SHOW_SILENT_HINT;
3140bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent                } else {
3141a11b4affcad3d255aa723a89b768ea222506f2e8John Spurlock                  if (mHasVibrator) {
3142a11b4affcad3d255aa723a89b768ea222506f2e8John Spurlock                      ringerMode = RINGER_MODE_VIBRATE;
3143a11b4affcad3d255aa723a89b768ea222506f2e8John Spurlock                  } else {
3144a11b4affcad3d255aa723a89b768ea222506f2e8John Spurlock                      ringerMode = RINGER_MODE_NORMAL;
3145a11b4affcad3d255aa723a89b768ea222506f2e8John Spurlock                  }
3146bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent                }
31479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
3148a11b4affcad3d255aa723a89b768ea222506f2e8John Spurlock            result &= ~FLAG_ADJUST_VOLUME;
3149bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent            break;
3150bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent        default:
3151bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent            Log.e(TAG, "checkForRingerModeChange() wrong ringer mode: "+ringerMode);
3152bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent            break;
31539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
31549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3155661f2cf45860d2e10924e6b69966a9afe255f28bJohn Spurlock        setRingerMode(ringerMode, TAG + ".checkForRingerModeChange", false /*external*/);
31569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
315725101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent        mPrevVolDirection = direction;
315825101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent
3159a11b4affcad3d255aa723a89b768ea222506f2e8John Spurlock        return result;
31609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
31619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
31623346a802087f621c6441bc512dfcc17b07143fc6John Spurlock    @Override
31639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public boolean isStreamAffectedByRingerMode(int streamType) {
31649bcf401d13d47416043a704430388abd59aef7cdEric Laurent        return (mRingerModeAffectedStreams & (1 << streamType)) != 0;
31659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
31669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
31675b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent    private boolean isStreamMutedByRingerMode(int streamType) {
31685b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent        return (mRingerModeMutedStreams & (1 << streamType)) != 0;
31695b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent    }
31705b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent
317124e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent    boolean updateRingerModeAffectedStreams() {
317224e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent        int ringerModeAffectedStreams;
317324e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent        // make sure settings for ringer mode are consistent with device type: non voice capable
317424e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent        // devices (tablets) include media stream in silent mode whereas phones don't.
317524e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent        ringerModeAffectedStreams = Settings.System.getIntForUser(mContentResolver,
317624e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent                Settings.System.MODE_RINGER_STREAMS_AFFECTED,
317724e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent                ((1 << AudioSystem.STREAM_RING)|(1 << AudioSystem.STREAM_NOTIFICATION)|
317824e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent                 (1 << AudioSystem.STREAM_SYSTEM)|(1 << AudioSystem.STREAM_SYSTEM_ENFORCED)),
317924e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent                 UserHandle.USER_CURRENT);
318024e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent
318124e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent        // ringtone, notification and system streams are always affected by ringer mode
318224e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent        ringerModeAffectedStreams |= (1 << AudioSystem.STREAM_RING)|
318324e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent                                        (1 << AudioSystem.STREAM_NOTIFICATION)|
318424e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent                                        (1 << AudioSystem.STREAM_SYSTEM);
318524e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent
3186212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent        switch (mPlatformType) {
3187212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent            case PLATFORM_TELEVISION:
3188212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent                ringerModeAffectedStreams = 0;
3189212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent                break;
3190212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent            default:
319177e54d905f8c0c9925f21a8339a893391179d9d7John Spurlock                ringerModeAffectedStreams &= ~(1 << AudioSystem.STREAM_MUSIC);
3192212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent                break;
319324e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent        }
3194212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent
319524e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent        synchronized (mCameraSoundForced) {
319624e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent            if (mCameraSoundForced) {
319724e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent                ringerModeAffectedStreams &= ~(1 << AudioSystem.STREAM_SYSTEM_ENFORCED);
319824e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent            } else {
319924e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent                ringerModeAffectedStreams |= (1 << AudioSystem.STREAM_SYSTEM_ENFORCED);
320024e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent            }
320124e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent        }
320224e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent        if (mStreamVolumeAlias[AudioSystem.STREAM_DTMF] == AudioSystem.STREAM_RING) {
320324e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent            ringerModeAffectedStreams |= (1 << AudioSystem.STREAM_DTMF);
320424e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent        } else {
320524e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent            ringerModeAffectedStreams &= ~(1 << AudioSystem.STREAM_DTMF);
320624e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent        }
320724e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent
320824e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent        if (ringerModeAffectedStreams != mRingerModeAffectedStreams) {
320924e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent            Settings.System.putIntForUser(mContentResolver,
321024e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent                    Settings.System.MODE_RINGER_STREAMS_AFFECTED,
321124e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent                    ringerModeAffectedStreams,
321224e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent                    UserHandle.USER_CURRENT);
321324e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent            mRingerModeAffectedStreams = ringerModeAffectedStreams;
321424e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent            return true;
321524e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent        }
321624e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent        return false;
321724e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent    }
321824e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent
32199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public boolean isStreamAffectedByMute(int streamType) {
32209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return (mMuteAffectedStreams & (1 << streamType)) != 0;
32219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
32229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
32239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private void ensureValidDirection(int direction) {
32249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (direction < AudioManager.ADJUST_LOWER || direction > AudioManager.ADJUST_RAISE) {
32259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            throw new IllegalArgumentException("Bad direction " + direction);
32269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
32279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
32289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
32296c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang    private void ensureValidSteps(int steps) {
32306c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang        if (Math.abs(steps) > MAX_BATCH_VOLUME_ADJUST_STEPS) {
32316c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang            throw new IllegalArgumentException("Bad volume adjust steps " + steps);
32326c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang        }
32336c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang    }
32346c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang
32359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private void ensureValidStreamType(int streamType) {
32369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (streamType < 0 || streamType >= mStreamStates.length) {
32379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            throw new IllegalArgumentException("Bad stream type " + streamType);
32389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
32399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
32409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
32416d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent    private boolean isInCommunication() {
32420eb1e402c7e612887e38dc5516f11506b11fd835Nancy Chen        boolean IsInCall = false;
324325101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent
3244ef9f6f957d897ea0ed82114185b8fa3fefd4917bTyler Gunn        TelecomManager telecomManager =
3245ef9f6f957d897ea0ed82114185b8fa3fefd4917bTyler Gunn                (TelecomManager) mContext.getSystemService(Context.TELECOM_SERVICE);
324638edfda9bdd282228db08e3cc449b554b8744625Eric Laurent
324738edfda9bdd282228db08e3cc449b554b8744625Eric Laurent        final long ident = Binder.clearCallingIdentity();
3248ef9f6f957d897ea0ed82114185b8fa3fefd4917bTyler Gunn        IsInCall = telecomManager.isInCall();
324938edfda9bdd282228db08e3cc449b554b8744625Eric Laurent        Binder.restoreCallingIdentity(ident);
32509eb45934c582a0bf5060125690de8bce4f10ca76Santos Cordon
32510eb1e402c7e612887e38dc5516f11506b11fd835Nancy Chen        return (IsInCall || getMode() == AudioManager.MODE_IN_COMMUNICATION);
32526d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent    }
325325101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent
3254fca1e603236b8d1681f784e77e3719d1d59c1428Jean-Michel Trivi    /**
3255fca1e603236b8d1681f784e77e3719d1d59c1428Jean-Michel Trivi     * For code clarity for getActiveStreamType(int)
3256fca1e603236b8d1681f784e77e3719d1d59c1428Jean-Michel Trivi     * @param delay_ms max time since last STREAM_MUSIC activity to consider
3257fca1e603236b8d1681f784e77e3719d1d59c1428Jean-Michel Trivi     * @return true if STREAM_MUSIC is active in streams handled by AudioFlinger now or
3258fca1e603236b8d1681f784e77e3719d1d59c1428Jean-Michel Trivi     *     in the last "delay_ms" ms.
3259fca1e603236b8d1681f784e77e3719d1d59c1428Jean-Michel Trivi     */
3260fca1e603236b8d1681f784e77e3719d1d59c1428Jean-Michel Trivi    private boolean isAfMusicActiveRecently(int delay_ms) {
3261fca1e603236b8d1681f784e77e3719d1d59c1428Jean-Michel Trivi        return AudioSystem.isStreamActive(AudioSystem.STREAM_MUSIC, delay_ms)
3262fca1e603236b8d1681f784e77e3719d1d59c1428Jean-Michel Trivi                || AudioSystem.isStreamActiveRemotely(AudioSystem.STREAM_MUSIC, delay_ms);
3263fca1e603236b8d1681f784e77e3719d1d59c1428Jean-Michel Trivi    }
3264fca1e603236b8d1681f784e77e3719d1d59c1428Jean-Michel Trivi
32656d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent    private int getActiveStreamType(int suggestedStreamType) {
3266212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent        switch (mPlatformType) {
3267212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent        case PLATFORM_VOICE:
32686d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent            if (isInCommunication()) {
326925101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent                if (AudioSystem.getForceUse(AudioSystem.FOR_COMMUNICATION)
327025101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent                        == AudioSystem.FORCE_BT_SCO) {
327125101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent                    // Log.v(TAG, "getActiveStreamType: Forcing STREAM_BLUETOOTH_SCO...");
327225101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent                    return AudioSystem.STREAM_BLUETOOTH_SCO;
327325101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent                } else {
327425101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent                    // Log.v(TAG, "getActiveStreamType: Forcing STREAM_VOICE_CALL...");
327525101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent                    return AudioSystem.STREAM_VOICE_CALL;
327625101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent                }
32773114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi            } else if (suggestedStreamType == AudioManager.USE_DEFAULT_STREAM_TYPE) {
3278873cc45da2463a11182fe94a2565364d7e1709bbJean-Michel Trivi                if (isAfMusicActiveRecently(StreamOverride.sDelayMs)) {
32793114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                    if (DEBUG_VOL)
32803114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                        Log.v(TAG, "getActiveStreamType: Forcing STREAM_MUSIC stream active");
32813114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                    return AudioSystem.STREAM_MUSIC;
3282fca1e603236b8d1681f784e77e3719d1d59c1428Jean-Michel Trivi                    } else {
3283fca1e603236b8d1681f784e77e3719d1d59c1428Jean-Michel Trivi                        if (DEBUG_VOL)
3284fca1e603236b8d1681f784e77e3719d1d59c1428Jean-Michel Trivi                            Log.v(TAG, "getActiveStreamType: Forcing STREAM_RING b/c default");
3285fca1e603236b8d1681f784e77e3719d1d59c1428Jean-Michel Trivi                        return AudioSystem.STREAM_RING;
32863114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                }
3287fca1e603236b8d1681f784e77e3719d1d59c1428Jean-Michel Trivi            } else if (isAfMusicActiveRecently(0)) {
32883114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                if (DEBUG_VOL)
32893114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                    Log.v(TAG, "getActiveStreamType: Forcing STREAM_MUSIC stream active");
329025101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent                return AudioSystem.STREAM_MUSIC;
329125101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent            }
3292212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent            break;
3293212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent        case PLATFORM_TELEVISION:
3294212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent            if (suggestedStreamType == AudioManager.USE_DEFAULT_STREAM_TYPE) {
32952811dd337262934ea82477f9598f3e49092edb5eRoboErik                    // TV always defaults to STREAM_MUSIC
3296212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent                    return AudioSystem.STREAM_MUSIC;
3297212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent            }
3298212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent            break;
3299212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent        default:
33006d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent            if (isInCommunication()) {
330125101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent                if (AudioSystem.getForceUse(AudioSystem.FOR_COMMUNICATION)
330225101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent                        == AudioSystem.FORCE_BT_SCO) {
33033114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                    if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: Forcing STREAM_BLUETOOTH_SCO");
330425101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent                    return AudioSystem.STREAM_BLUETOOTH_SCO;
330525101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent                } else {
33063114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                    if (DEBUG_VOL)  Log.v(TAG, "getActiveStreamType: Forcing STREAM_VOICE_CALL");
330725101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent                    return AudioSystem.STREAM_VOICE_CALL;
330825101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent                }
330925101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent            } else if (AudioSystem.isStreamActive(AudioSystem.STREAM_NOTIFICATION,
3310873cc45da2463a11182fe94a2565364d7e1709bbJean-Michel Trivi                    StreamOverride.sDelayMs) ||
33113114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                    AudioSystem.isStreamActive(AudioSystem.STREAM_RING,
3312873cc45da2463a11182fe94a2565364d7e1709bbJean-Michel Trivi                            StreamOverride.sDelayMs)) {
33133114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: Forcing STREAM_NOTIFICATION");
331425101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent                return AudioSystem.STREAM_NOTIFICATION;
33153114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi            } else if (suggestedStreamType == AudioManager.USE_DEFAULT_STREAM_TYPE) {
3316873cc45da2463a11182fe94a2565364d7e1709bbJean-Michel Trivi                if (isAfMusicActiveRecently(StreamOverride.sDelayMs)) {
3317fca1e603236b8d1681f784e77e3719d1d59c1428Jean-Michel Trivi                    if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: forcing STREAM_MUSIC");
3318fca1e603236b8d1681f784e77e3719d1d59c1428Jean-Michel Trivi                    return AudioSystem.STREAM_MUSIC;
33193114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                } else {
3320eb1d88ddf9a0888455c82b83f19da124e5ca6f16John Spurlock                    if (DEBUG_VOL) Log.v(TAG,
3321eb1d88ddf9a0888455c82b83f19da124e5ca6f16John Spurlock                            "getActiveStreamType: using STREAM_NOTIFICATION as default");
3322eb1d88ddf9a0888455c82b83f19da124e5ca6f16John Spurlock                    return AudioSystem.STREAM_NOTIFICATION;
33233114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                }
3324c7fcba4b7bd3d78e7cfe975a3f8e4dde2f6738b7Joe Onorato            }
3325212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent            break;
33269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
3327212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent        if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: Returning suggested type "
3328212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent                + suggestedStreamType);
3329212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent        return suggestedStreamType;
33309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
33319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3332bcc1087af40a0e1bb35dbe8a39c830ecdea8280bJohn Spurlock    private void broadcastRingerMode(String action, int ringerMode) {
33339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // Send sticky broadcast
3334bcc1087af40a0e1bb35dbe8a39c830ecdea8280bJohn Spurlock        Intent broadcast = new Intent(action);
3335ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten        broadcast.putExtra(AudioManager.EXTRA_RINGER_MODE, ringerMode);
33361c633fc89bae9bf0af6fe643ac7ad2e744f27bedDianne Hackborn        broadcast.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT
33371c633fc89bae9bf0af6fe643ac7ad2e744f27bedDianne Hackborn                | Intent.FLAG_RECEIVER_REPLACE_PENDING);
33385ac72a29593ab9a20337a2225df52bdf4754be02Dianne Hackborn        sendStickyBroadcastToAll(broadcast);
33399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
33409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
33419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private void broadcastVibrateSetting(int vibrateType) {
33429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // Send broadcast
33439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (ActivityManagerNative.isSystemReady()) {
33449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            Intent broadcast = new Intent(AudioManager.VIBRATE_SETTING_CHANGED_ACTION);
33459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            broadcast.putExtra(AudioManager.EXTRA_VIBRATE_TYPE, vibrateType);
33469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            broadcast.putExtra(AudioManager.EXTRA_VIBRATE_SETTING, getVibrateSetting(vibrateType));
33475ac72a29593ab9a20337a2225df52bdf4754be02Dianne Hackborn            sendBroadcastToAll(broadcast);
33489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
33499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
33509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
33519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // Message helper methods
33522d8dab5a549b25b6f36df4614d7c0166d4d099e2Jean-Michel Trivi    /**
33532d8dab5a549b25b6f36df4614d7c0166d4d099e2Jean-Michel Trivi     * Queue a message on the given handler's message queue, after acquiring the service wake lock.
33542d8dab5a549b25b6f36df4614d7c0166d4d099e2Jean-Michel Trivi     * Note that the wake lock needs to be released after the message has been handled.
33552d8dab5a549b25b6f36df4614d7c0166d4d099e2Jean-Michel Trivi     */
33562d8dab5a549b25b6f36df4614d7c0166d4d099e2Jean-Michel Trivi    private void queueMsgUnderWakeLock(Handler handler, int msg,
33572d8dab5a549b25b6f36df4614d7c0166d4d099e2Jean-Michel Trivi            int arg1, int arg2, Object obj, int delay) {
3358a4dfbdc54d8898491d3a7d1d9d818c7db3fd773dEric Laurent        final long ident = Binder.clearCallingIdentity();
3359a4dfbdc54d8898491d3a7d1d9d818c7db3fd773dEric Laurent        // Always acquire the wake lock as AudioService because it is released by the
3360a4dfbdc54d8898491d3a7d1d9d818c7db3fd773dEric Laurent        // message handler.
3361fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        mAudioEventWakeLock.acquire();
3362a4dfbdc54d8898491d3a7d1d9d818c7db3fd773dEric Laurent        Binder.restoreCallingIdentity(ident);
33632d8dab5a549b25b6f36df4614d7c0166d4d099e2Jean-Michel Trivi        sendMsg(handler, msg, SENDMSG_QUEUE, arg1, arg2, obj, delay);
33642d8dab5a549b25b6f36df4614d7c0166d4d099e2Jean-Michel Trivi    }
33659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3366afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent    private static void sendMsg(Handler handler, int msg,
33679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int existingMsgPolicy, int arg1, int arg2, Object obj, int delay) {
33689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
33699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (existingMsgPolicy == SENDMSG_REPLACE) {
33709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            handler.removeMessages(msg);
33719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else if (existingMsgPolicy == SENDMSG_NOOP && handler.hasMessages(msg)) {
33729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return;
33739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
3374adbe8bf85f3c8230d16ae5cb3f5d9736e09ed84aEric Laurent        synchronized (mLastDeviceConnectMsgTime) {
3375adbe8bf85f3c8230d16ae5cb3f5d9736e09ed84aEric Laurent            long time = SystemClock.uptimeMillis() + delay;
3376adbe8bf85f3c8230d16ae5cb3f5d9736e09ed84aEric Laurent            handler.sendMessageAtTime(handler.obtainMessage(msg, arg1, arg2, obj), time);
3377adbe8bf85f3c8230d16ae5cb3f5d9736e09ed84aEric Laurent            if (msg == MSG_SET_WIRED_DEVICE_CONNECTION_STATE ||
3378adbe8bf85f3c8230d16ae5cb3f5d9736e09ed84aEric Laurent                    msg == MSG_SET_A2DP_SRC_CONNECTION_STATE ||
3379adbe8bf85f3c8230d16ae5cb3f5d9736e09ed84aEric Laurent                    msg == MSG_SET_A2DP_SINK_CONNECTION_STATE) {
3380adbe8bf85f3c8230d16ae5cb3f5d9736e09ed84aEric Laurent                mLastDeviceConnectMsgTime = time;
3381adbe8bf85f3c8230d16ae5cb3f5d9736e09ed84aEric Laurent            }
3382adbe8bf85f3c8230d16ae5cb3f5d9736e09ed84aEric Laurent        }
33839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
33849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
33859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    boolean checkAudioSettingsPermission(String method) {
3386ccd654e9d4c38da0d652c442e7a2ca3f447e9abeJean-Michel Trivi        if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.MODIFY_AUDIO_SETTINGS)
33879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                == PackageManager.PERMISSION_GRANTED) {
33889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return true;
33899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
33909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        String msg = "Audio Settings Permission Denial: " + method + " from pid="
33919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                + Binder.getCallingPid()
33929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                + ", uid=" + Binder.getCallingUid();
33939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        Log.w(TAG, msg);
33949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return false;
33959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
33969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
33979bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent    private int getDeviceForStream(int stream) {
33989bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent        int device = AudioSystem.getDevicesForStream(stream);
33999bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent        if ((device & (device - 1)) != 0) {
34009bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent            // Multiple device selection is either:
34019bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent            //  - speaker + one other device: give priority to speaker in this case.
34029bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent            //  - one A2DP device + another device: happens with duplicated output. In this case
34039bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent            // retain the device on the A2DP output as the other must not correspond to an active
34049bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent            // selection if not the speaker.
3405c9ff968787d4744194f9985ebaf8ce7efdd12256Jungshik Jang            //  - HDMI-CEC system audio mode only output: give priority to available item in order.
34069bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent            if ((device & AudioSystem.DEVICE_OUT_SPEAKER) != 0) {
34079bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                device = AudioSystem.DEVICE_OUT_SPEAKER;
3408c9ff968787d4744194f9985ebaf8ce7efdd12256Jungshik Jang            } else if ((device & AudioSystem.DEVICE_OUT_HDMI_ARC) != 0) {
3409c9ff968787d4744194f9985ebaf8ce7efdd12256Jungshik Jang                device = AudioSystem.DEVICE_OUT_HDMI_ARC;
3410c9ff968787d4744194f9985ebaf8ce7efdd12256Jungshik Jang            } else if ((device & AudioSystem.DEVICE_OUT_SPDIF) != 0) {
3411c9ff968787d4744194f9985ebaf8ce7efdd12256Jungshik Jang                device = AudioSystem.DEVICE_OUT_SPDIF;
3412c9ff968787d4744194f9985ebaf8ce7efdd12256Jungshik Jang            } else if ((device & AudioSystem.DEVICE_OUT_AUX_LINE) != 0) {
3413c9ff968787d4744194f9985ebaf8ce7efdd12256Jungshik Jang                device = AudioSystem.DEVICE_OUT_AUX_LINE;
34149bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent            } else {
34159bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                device &= AudioSystem.DEVICE_OUT_ALL_A2DP;
34169bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent            }
34179bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent        }
34189bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent        return device;
34199bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent    }
34209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3421b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent    public void setWiredDeviceConnectionState(int device, int state, String name) {
3422b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent        synchronized (mConnectedDevices) {
3423b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent            int delay = checkSendBecomingNoisyIntent(device, state);
34242d8dab5a549b25b6f36df4614d7c0166d4d099e2Jean-Michel Trivi            queueMsgUnderWakeLock(mAudioHandler,
3425b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent                    MSG_SET_WIRED_DEVICE_CONNECTION_STATE,
3426b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent                    device,
3427b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent                    state,
3428b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent                    name,
3429b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent                    delay);
3430b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent        }
3431b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent    }
3432b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent
34330a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood    public int setBluetoothA2dpDeviceConnectionState(BluetoothDevice device, int state, int profile)
3434b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent    {
3435b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent        int delay;
34360a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood        if (profile != BluetoothProfile.A2DP && profile != BluetoothProfile.A2DP_SINK) {
34370a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood            throw new IllegalArgumentException("invalid profile " + profile);
34380a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood        }
3439b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent        synchronized (mConnectedDevices) {
34400a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood            if (profile == BluetoothProfile.A2DP) {
34410a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood                delay = checkSendBecomingNoisyIntent(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
34420a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood                                                (state == BluetoothA2dp.STATE_CONNECTED) ? 1 : 0);
34430a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood            } else {
34440a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood                delay = 0;
34450a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood            }
34462d8dab5a549b25b6f36df4614d7c0166d4d099e2Jean-Michel Trivi            queueMsgUnderWakeLock(mAudioHandler,
34470a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood                    (profile == BluetoothProfile.A2DP ?
34480a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood                        MSG_SET_A2DP_SINK_CONNECTION_STATE : MSG_SET_A2DP_SRC_CONNECTION_STATE),
3449b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent                    state,
3450b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent                    0,
3451b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent                    device,
3452b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent                    delay);
3453b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent        }
3454b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent        return delay;
3455b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent    }
3456b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent
34579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    ///////////////////////////////////////////////////////////////////////////
34589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // Inner classes
34599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    ///////////////////////////////////////////////////////////////////////////
34609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
34618fa4d6f585f40ff5cf5f9bed316d92c64a306f21Eric Laurent    // NOTE: Locking order for synchronized objects related to volume or ringer mode management:
34628fa4d6f585f40ff5cf5f9bed316d92c64a306f21Eric Laurent    //  1 mScoclient OR mSafeMediaVolumeState
34638fa4d6f585f40ff5cf5f9bed316d92c64a306f21Eric Laurent    //  2   mSetModeDeathHandlers
34648fa4d6f585f40ff5cf5f9bed316d92c64a306f21Eric Laurent    //  3     mSettingsLock
34658fa4d6f585f40ff5cf5f9bed316d92c64a306f21Eric Laurent    //  4       VolumeStreamState.class
34668fa4d6f585f40ff5cf5f9bed316d92c64a306f21Eric Laurent    //  5         mCameraSoundForced
34679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public class VolumeStreamState {
34689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        private final int mStreamType;
34699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
347011a74a75653197a3d31fe91590cd8312f5270c44Jean-Michel Trivi        private String mVolumeIndexSettingName;
3471a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent        private int mIndexMax;
34723172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent        private final ConcurrentHashMap<Integer, Integer> mIndex =
34733172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                                            new ConcurrentHashMap<Integer, Integer>(8, 0.75f, 4);
34749bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent        private ArrayList<VolumeDeathHandler> mDeathHandlers; //handles mute/solo clients death
34759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3476a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent        private VolumeStreamState(String settingName, int streamType) {
34779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
34789bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent            mVolumeIndexSettingName = settingName;
34799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
34809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mStreamType = streamType;
34815982013cfc8274ff0bafaba83c676b3a8890cba9Jared Suttles            mIndexMax = MAX_STREAM_VOLUME[streamType];
3482a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent            AudioSystem.initStreamVolume(streamType, 0, mIndexMax);
3483a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent            mIndexMax *= 10;
34849bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent
348533902db75011d863009585682bd08560c5b89a75Eric Laurent            // mDeathHandlers must be created before calling readSettings()
34869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mDeathHandlers = new ArrayList<VolumeDeathHandler>();
348733902db75011d863009585682bd08560c5b89a75Eric Laurent
348833902db75011d863009585682bd08560c5b89a75Eric Laurent            readSettings();
34899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
34909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
349142b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent        public String getSettingNameForDevice(int device) {
349242b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent            String name = mVolumeIndexSettingName;
3493948d32748caaac5be06c991ebf00f74265a7849fEric Laurent            String suffix = AudioSystem.getOutputDeviceName(device);
34949bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent            if (suffix.isEmpty()) {
34959bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                return name;
34969bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent            }
34979bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent            return name + "_" + suffix;
34989bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent        }
34999bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent
3500fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent        public void readSettings() {
3501fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent            synchronized (VolumeStreamState.class) {
3502da39290460b30e5080769f039d6dff352b3c7808Wally Yau                // force maximum volume on all streams if fixed volume property
3503da39290460b30e5080769f039d6dff352b3c7808Wally Yau                // or master volume property is set
3504da39290460b30e5080769f039d6dff352b3c7808Wally Yau                if (mUseFixedVolume || mUseMasterVolume) {
3505fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                    mIndex.put(AudioSystem.DEVICE_OUT_DEFAULT, mIndexMax);
3506fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                    return;
3507fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                }
3508fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                // do not read system stream volume from settings: this stream is always aliased
3509fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                // to another stream type and its volume is never persisted. Values in settings can
3510fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                // only be stale values
3511fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                if ((mStreamType == AudioSystem.STREAM_SYSTEM) ||
3512fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                        (mStreamType == AudioSystem.STREAM_SYSTEM_ENFORCED)) {
351391377de6f23af2b0b08adae22810cae6fc35cb1aEric Laurent                    int index = 10 * DEFAULT_STREAM_VOLUME[mStreamType];
3514fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                    synchronized (mCameraSoundForced) {
3515fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                        if (mCameraSoundForced) {
3516fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                            index = mIndexMax;
3517fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                        }
3518dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent                    }
3519fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                    mIndex.put(AudioSystem.DEVICE_OUT_DEFAULT, index);
3520fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                    return;
3521dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent                }
3522002e9d382d2daa7ed41636463ecdbddbd4897abaEric Laurent
3523fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                int remainingDevices = AudioSystem.DEVICE_OUT_ALL;
352483a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent
3525fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                for (int i = 0; remainingDevices != 0; i++) {
3526fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                    int device = (1 << i);
3527fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                    if ((device & remainingDevices) == 0) {
3528fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                        continue;
3529fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                    }
3530fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                    remainingDevices &= ~device;
3531fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent
3532fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                    // retrieve current volume for device
3533fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                    String name = getSettingNameForDevice(device);
3534fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                    // if no volume stored for current stream and device, use default volume if default
3535fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                    // device, continue otherwise
3536fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                    int defaultIndex = (device == AudioSystem.DEVICE_OUT_DEFAULT) ?
353791377de6f23af2b0b08adae22810cae6fc35cb1aEric Laurent                                            DEFAULT_STREAM_VOLUME[mStreamType] : -1;
3538fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                    int index = Settings.System.getIntForUser(
3539fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                            mContentResolver, name, defaultIndex, UserHandle.USER_CURRENT);
3540fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                    if (index == -1) {
3541fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                        continue;
3542fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                    }
35439bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent
3544212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent                    mIndex.put(device, getValidIndex(10 * index));
3545dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent                }
35469bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent            }
35479bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent        }
35489bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent
35498fa4d6f585f40ff5cf5f9bed316d92c64a306f21Eric Laurent        // must be called while synchronized VolumeStreamState.class
35508fa4d6f585f40ff5cf5f9bed316d92c64a306f21Eric Laurent        public void applyDeviceVolume_syncVSS(int device) {
355142b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent            int index;
35528fa4d6f585f40ff5cf5f9bed316d92c64a306f21Eric Laurent            if (isMuted_syncVSS()) {
355342b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                index = 0;
3554ba5270b88798c66fefc17a1b25b27894e4fb7862Jean-Michel Trivi            } else if (((device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0 && mAvrcpAbsVolSupported)
3555ba5270b88798c66fefc17a1b25b27894e4fb7862Jean-Michel Trivi                    || ((device & mFullVolumeDevices) != 0)) {
3556c9d1d5f35091226e96fcfa91817480f589eb36e2Matthew Xie                index = (mIndexMax + 5)/10;
3557cd772d04345850e160a45613fcf6b86da0dce4cfEric Laurent            } else {
355842b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                index = (getIndex(device) + 5)/10;
355942b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent            }
356042b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent            AudioSystem.setStreamVolumeIndex(mStreamType, index, device);
35619bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent        }
35629bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent
3563fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent        public void applyAllVolumes() {
3564fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent            synchronized (VolumeStreamState.class) {
3565fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                // apply default volume first: by convention this will reset all
3566fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                // devices volumes in audio policy manager to the supplied value
3567fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                int index;
35688fa4d6f585f40ff5cf5f9bed316d92c64a306f21Eric Laurent                if (isMuted_syncVSS()) {
3569fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                    index = 0;
3570fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                } else {
3571fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                    index = (getIndex(AudioSystem.DEVICE_OUT_DEFAULT) + 5)/10;
3572fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                }
3573fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                AudioSystem.setStreamVolumeIndex(mStreamType, index, AudioSystem.DEVICE_OUT_DEFAULT);
3574fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                // then apply device specific volumes
3575fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                Set set = mIndex.entrySet();
3576fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                Iterator i = set.iterator();
3577fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                while (i.hasNext()) {
3578fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                    Map.Entry entry = (Map.Entry)i.next();
3579fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                    int device = ((Integer)entry.getKey()).intValue();
3580fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                    if (device != AudioSystem.DEVICE_OUT_DEFAULT) {
35818fa4d6f585f40ff5cf5f9bed316d92c64a306f21Eric Laurent                        if (isMuted_syncVSS()) {
3582fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                            index = 0;
3583ba5270b88798c66fefc17a1b25b27894e4fb7862Jean-Michel Trivi                        } else if (((device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0 &&
3584ba5270b88798c66fefc17a1b25b27894e4fb7862Jean-Michel Trivi                                mAvrcpAbsVolSupported)
3585ba5270b88798c66fefc17a1b25b27894e4fb7862Jean-Michel Trivi                                    || ((device & mFullVolumeDevices) != 0))
3586ba5270b88798c66fefc17a1b25b27894e4fb7862Jean-Michel Trivi                        {
3587fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                            index = (mIndexMax + 5)/10;
3588fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                        } else {
3589fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                            index = ((Integer)entry.getValue() + 5)/10;
3590fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                        }
3591fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                        AudioSystem.setStreamVolumeIndex(mStreamType, index, device);
359242b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                    }
35939bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                }
35949bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent            }
359511a74a75653197a3d31fe91590cd8312f5270c44Jean-Michel Trivi        }
359611a74a75653197a3d31fe91590cd8312f5270c44Jean-Michel Trivi
35979bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent        public boolean adjustIndex(int deltaIndex, int device) {
359842b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent            return setIndex(getIndex(device) + deltaIndex,
359942b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                            device);
36009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
36019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3602fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent        public boolean setIndex(int index, int device) {
3603fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent            synchronized (VolumeStreamState.class) {
3604fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                int oldIndex = getIndex(device);
3605fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                index = getValidIndex(index);
3606fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                synchronized (mCameraSoundForced) {
3607fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                    if ((mStreamType == AudioSystem.STREAM_SYSTEM_ENFORCED) && mCameraSoundForced) {
3608fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                        index = mIndexMax;
3609fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                    }
3610dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent                }
3611fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                mIndex.put(device, index);
3612fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent
3613fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                if (oldIndex != index) {
3614fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                    // Apply change to all streams using this one as alias
3615fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                    // if changing volume of current device, also change volume of current
3616fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                    // device on aliased stream
3617fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                    boolean currentDevice = (device == getDeviceForStream(mStreamType));
3618fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                    int numStreamTypes = AudioSystem.getNumStreamTypes();
3619fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                    for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
3620fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                        if (streamType != mStreamType &&
3621fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                                mStreamVolumeAlias[streamType] == mStreamType) {
3622fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                            int scaledIndex = rescaleIndex(index, mStreamType, streamType);
3623bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent                            mStreamStates[streamType].setIndex(scaledIndex,
3624fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                                                               device);
3625fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                            if (currentDevice) {
3626fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                                mStreamStates[streamType].setIndex(scaledIndex,
3627fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                                                                   getDeviceForStream(streamType));
3628fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                            }
3629bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent                        }
3630a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent                    }
3631fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                    return true;
3632fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                } else {
3633fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                    return false;
3634a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent                }
36359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
36369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
36379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3638fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent        public int getIndex(int device) {
3639fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent            synchronized (VolumeStreamState.class) {
3640fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                Integer index = mIndex.get(device);
3641fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                if (index == null) {
3642fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                    // there is always an entry for AudioSystem.DEVICE_OUT_DEFAULT
3643fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                    index = mIndex.get(AudioSystem.DEVICE_OUT_DEFAULT);
3644fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                }
3645fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                return index.intValue();
36469bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent            }
36479bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent        }
36489bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent
36499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public int getMaxIndex() {
3650a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent            return mIndexMax;
36519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
36529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3653fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent        public void setAllIndexes(VolumeStreamState srcStream) {
3654fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent            synchronized (VolumeStreamState.class) {
3655fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                int srcStreamType = srcStream.getStreamType();
3656fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                // apply default device volume from source stream to all devices first in case
3657fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                // some devices are present in this stream state but not in source stream state
3658fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                int index = srcStream.getIndex(AudioSystem.DEVICE_OUT_DEFAULT);
365924e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent                index = rescaleIndex(index, srcStreamType, mStreamType);
3660fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                Set set = mIndex.entrySet();
3661fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                Iterator i = set.iterator();
3662fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                while (i.hasNext()) {
3663fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                    Map.Entry entry = (Map.Entry)i.next();
3664fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                    entry.setValue(index);
3665fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                }
3666fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                // Now apply actual volume for devices in source stream state
3667fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                set = srcStream.mIndex.entrySet();
3668fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                i = set.iterator();
3669fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                while (i.hasNext()) {
3670fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                    Map.Entry entry = (Map.Entry)i.next();
3671fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                    int device = ((Integer)entry.getKey()).intValue();
3672fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                    index = ((Integer)entry.getValue()).intValue();
3673fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                    index = rescaleIndex(index, srcStreamType, mStreamType);
3674fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent
3675fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                    setIndex(index, device);
3676fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                }
36776d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent            }
36786d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent        }
36796d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent
3680fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent        public void setAllIndexesToMax() {
3681fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent            synchronized (VolumeStreamState.class) {
3682fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                Set set = mIndex.entrySet();
3683fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                Iterator i = set.iterator();
3684fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                while (i.hasNext()) {
3685fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                    Map.Entry entry = (Map.Entry)i.next();
3686fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                    entry.setValue(mIndexMax);
3687fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                }
3688dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent            }
3689dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent        }
3690dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent
3691fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent        public void mute(IBinder cb, boolean state) {
3692fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent            synchronized (VolumeStreamState.class) {
36938fa4d6f585f40ff5cf5f9bed316d92c64a306f21Eric Laurent                VolumeDeathHandler handler = getDeathHandler_syncVSS(cb, state);
3694fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                if (handler == null) {
3695fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                    Log.e(TAG, "Could not get client death handler for stream: "+mStreamType);
3696fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                    return;
3697fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                }
36988fa4d6f585f40ff5cf5f9bed316d92c64a306f21Eric Laurent                handler.mute_syncVSS(state);
36999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
37009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
37019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
37026d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent        public int getStreamType() {
37036d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent            return mStreamType;
37046d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent        }
37056d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent
3706212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent        public void checkFixedVolumeDevices() {
3707212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent            synchronized (VolumeStreamState.class) {
3708212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent                // ignore settings for fixed volume devices: volume should always be at max or 0
3709212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent                if (mStreamVolumeAlias[mStreamType] == AudioSystem.STREAM_MUSIC) {
3710212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent                    Set set = mIndex.entrySet();
3711212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent                    Iterator i = set.iterator();
3712212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent                    while (i.hasNext()) {
3713212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent                        Map.Entry entry = (Map.Entry)i.next();
3714212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent                        int device = ((Integer)entry.getKey()).intValue();
3715212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent                        int index = ((Integer)entry.getValue()).intValue();
3716ba5270b88798c66fefc17a1b25b27894e4fb7862Jean-Michel Trivi                        if (((device & mFullVolumeDevices) != 0)
3717ba5270b88798c66fefc17a1b25b27894e4fb7862Jean-Michel Trivi                                || (((device & mFixedVolumeDevices) != 0) && index != 0)) {
3718212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent                            entry.setValue(mIndexMax);
3719212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent                        }
37208fa4d6f585f40ff5cf5f9bed316d92c64a306f21Eric Laurent                        applyDeviceVolume_syncVSS(device);
3721212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent                    }
3722212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent                }
3723212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent            }
3724212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent        }
3725212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent
37269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        private int getValidIndex(int index) {
37279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (index < 0) {
37289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return 0;
3729da39290460b30e5080769f039d6dff352b3c7808Wally Yau            } else if (mUseFixedVolume || mUseMasterVolume || index > mIndexMax) {
3730a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent                return mIndexMax;
37319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
37329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
37339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return index;
37349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
37359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
37369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        private class VolumeDeathHandler implements IBinder.DeathRecipient {
37379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            private IBinder mICallback; // To be notified of client's death
37389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            private int mMuteCount; // Number of active mutes for this client
37399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
37409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            VolumeDeathHandler(IBinder cb) {
37419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mICallback = cb;
37429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
37439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
37448fa4d6f585f40ff5cf5f9bed316d92c64a306f21Eric Laurent            // must be called while synchronized VolumeStreamState.class
37458fa4d6f585f40ff5cf5f9bed316d92c64a306f21Eric Laurent            public void mute_syncVSS(boolean state) {
374642b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                boolean updateVolume = false;
37473172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                if (state) {
37483172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                    if (mMuteCount == 0) {
37493172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                        // Register for client death notification
37503172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                        try {
37513172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                            // mICallback can be 0 if muted by AudioService
37523172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                            if (mICallback != null) {
37533172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                                mICallback.linkToDeath(this, 0);
37543172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                            }
375542b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                            VolumeStreamState.this.mDeathHandlers.add(this);
37563172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                            // If the stream is not yet muted by any client, set level to 0
37578fa4d6f585f40ff5cf5f9bed316d92c64a306f21Eric Laurent                            if (!VolumeStreamState.this.isMuted_syncVSS()) {
375842b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                                updateVolume = true;
37593172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                            }
37603172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                        } catch (RemoteException e) {
37613172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                            // Client has died!
37623172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                            binderDied();
37633172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                            return;
37643172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                        }
37653172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                    } else {
37663172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                        Log.w(TAG, "stream: "+mStreamType+" was already muted by this client");
37673172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                    }
37683172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                    mMuteCount++;
37693172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                } else {
37703172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                    if (mMuteCount == 0) {
37713172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                        Log.e(TAG, "unexpected unmute for stream: "+mStreamType);
37723172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                    } else {
37733172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                        mMuteCount--;
37743172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                        if (mMuteCount == 0) {
37753172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                            // Unregister from client death notification
377642b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                            VolumeStreamState.this.mDeathHandlers.remove(this);
37773172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                            // mICallback can be 0 if muted by AudioService
37783172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                            if (mICallback != null) {
37793172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                                mICallback.unlinkToDeath(this, 0);
37803172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                            }
37818fa4d6f585f40ff5cf5f9bed316d92c64a306f21Eric Laurent                            if (!VolumeStreamState.this.isMuted_syncVSS()) {
378242b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                                updateVolume = true;
37839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            }
37849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        }
37859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    }
37869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
378742b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                if (updateVolume) {
378842b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                    sendMsg(mAudioHandler,
378942b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                            MSG_SET_ALL_VOLUMES,
379042b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                            SENDMSG_QUEUE,
379142b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                            0,
379242b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                            0,
379342b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                            VolumeStreamState.this, 0);
379442b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                }
37959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
37969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
37979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            public void binderDied() {
37989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                Log.w(TAG, "Volume service client died for stream: "+mStreamType);
37998fa4d6f585f40ff5cf5f9bed316d92c64a306f21Eric Laurent                synchronized (VolumeStreamState.class) {
38008fa4d6f585f40ff5cf5f9bed316d92c64a306f21Eric Laurent                    if (mMuteCount != 0) {
38018fa4d6f585f40ff5cf5f9bed316d92c64a306f21Eric Laurent                        // Reset all active mute requests from this client.
38028fa4d6f585f40ff5cf5f9bed316d92c64a306f21Eric Laurent                        mMuteCount = 1;
38038fa4d6f585f40ff5cf5f9bed316d92c64a306f21Eric Laurent                        mute_syncVSS(false);
38048fa4d6f585f40ff5cf5f9bed316d92c64a306f21Eric Laurent                    }
38059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
38069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
38079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
38089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
38098fa4d6f585f40ff5cf5f9bed316d92c64a306f21Eric Laurent        private int muteCount() {
38109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int count = 0;
38119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int size = mDeathHandlers.size();
38129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            for (int i = 0; i < size; i++) {
38139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                count += mDeathHandlers.get(i).mMuteCount;
38149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
38159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return count;
38169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
38179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
38188fa4d6f585f40ff5cf5f9bed316d92c64a306f21Eric Laurent        // must be called while synchronized VolumeStreamState.class
38198fa4d6f585f40ff5cf5f9bed316d92c64a306f21Eric Laurent        private boolean isMuted_syncVSS() {
382042b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent            return muteCount() != 0;
382142b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent        }
382242b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent
38238fa4d6f585f40ff5cf5f9bed316d92c64a306f21Eric Laurent        // must be called while synchronized VolumeStreamState.class
38248fa4d6f585f40ff5cf5f9bed316d92c64a306f21Eric Laurent        private VolumeDeathHandler getDeathHandler_syncVSS(IBinder cb, boolean state) {
38253172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent            VolumeDeathHandler handler;
38263172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent            int size = mDeathHandlers.size();
38273172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent            for (int i = 0; i < size; i++) {
38283172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                handler = mDeathHandlers.get(i);
38293172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                if (cb == handler.mICallback) {
38303172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                    return handler;
3831ce952c8e13c535bedde77bcdb94dfcc7508475aaMike Lockwood                }
3832ce952c8e13c535bedde77bcdb94dfcc7508475aaMike Lockwood            }
38333172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent            // If this is the first mute request for this client, create a new
38343172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent            // client death handler. Otherwise, it is an out of sequence unmute request.
38353172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent            if (state) {
38363172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                handler = new VolumeDeathHandler(cb);
38373172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent            } else {
38383172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                Log.w(TAG, "stream was not muted by this client");
38393172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                handler = null;
38403172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent            }
38413172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent            return handler;
3842ce952c8e13c535bedde77bcdb94dfcc7508475aaMike Lockwood        }
3843bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent
3844bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent        private void dump(PrintWriter pw) {
3845dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent            pw.print("   Mute count: ");
3846dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent            pw.println(muteCount());
38472b29bc4c1cef64abdf3a68b60bdcf7207193e980John Spurlock            pw.print("   Max: ");
38482b29bc4c1cef64abdf3a68b60bdcf7207193e980John Spurlock            pw.println((mIndexMax + 5) / 10);
3849bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent            pw.print("   Current: ");
3850bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent            Set set = mIndex.entrySet();
3851bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent            Iterator i = set.iterator();
3852bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent            while (i.hasNext()) {
3853bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent                Map.Entry entry = (Map.Entry)i.next();
38542b29bc4c1cef64abdf3a68b60bdcf7207193e980John Spurlock                final int device = (Integer) entry.getKey();
38552b29bc4c1cef64abdf3a68b60bdcf7207193e980John Spurlock                pw.print(Integer.toHexString(device));
38562b29bc4c1cef64abdf3a68b60bdcf7207193e980John Spurlock                final String deviceName = device == AudioSystem.DEVICE_OUT_DEFAULT ? "default"
38572b29bc4c1cef64abdf3a68b60bdcf7207193e980John Spurlock                        : AudioSystem.getOutputDeviceName(device);
38582b29bc4c1cef64abdf3a68b60bdcf7207193e980John Spurlock                if (!deviceName.isEmpty()) {
38592b29bc4c1cef64abdf3a68b60bdcf7207193e980John Spurlock                    pw.print(" (");
38602b29bc4c1cef64abdf3a68b60bdcf7207193e980John Spurlock                    pw.print(deviceName);
38612b29bc4c1cef64abdf3a68b60bdcf7207193e980John Spurlock                    pw.print(")");
38622b29bc4c1cef64abdf3a68b60bdcf7207193e980John Spurlock                }
38632b29bc4c1cef64abdf3a68b60bdcf7207193e980John Spurlock                pw.print(": ");
38642b29bc4c1cef64abdf3a68b60bdcf7207193e980John Spurlock                final int index = (((Integer) entry.getValue()) + 5) / 10;
38652b29bc4c1cef64abdf3a68b60bdcf7207193e980John Spurlock                pw.print(index);
38662b29bc4c1cef64abdf3a68b60bdcf7207193e980John Spurlock                if (i.hasNext()) {
38672b29bc4c1cef64abdf3a68b60bdcf7207193e980John Spurlock                    pw.print(", ");
38682b29bc4c1cef64abdf3a68b60bdcf7207193e980John Spurlock                }
3869bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent            }
3870bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent        }
3871ce952c8e13c535bedde77bcdb94dfcc7508475aaMike Lockwood    }
3872ce952c8e13c535bedde77bcdb94dfcc7508475aaMike Lockwood
38739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** Thread that handles native AudioSystem control. */
38749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private class AudioSystemThread extends Thread {
38759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        AudioSystemThread() {
38769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            super("AudioService");
38779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
38789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
38799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        @Override
38809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public void run() {
38819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // Set this thread up so the handler will work on it
38829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            Looper.prepare();
38839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
38849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            synchronized(AudioService.this) {
38859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mAudioHandler = new AudioHandler();
38869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
38879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // Notify that the handler has been created
38889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                AudioService.this.notify();
38899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
38909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
38919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // Listen for volume change requests that are set by VolumePanel
38929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            Looper.loop();
38939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
38949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
38959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
38969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** Handles internal volume messages in separate volume thread. */
38979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private class AudioHandler extends Handler {
38989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
38999bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent        private void setDeviceVolume(VolumeStreamState streamState, int device) {
39009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
39018fa4d6f585f40ff5cf5f9bed316d92c64a306f21Eric Laurent            synchronized (VolumeStreamState.class) {
39028fa4d6f585f40ff5cf5f9bed316d92c64a306f21Eric Laurent                // Apply volume
39038fa4d6f585f40ff5cf5f9bed316d92c64a306f21Eric Laurent                streamState.applyDeviceVolume_syncVSS(device);
39048fa4d6f585f40ff5cf5f9bed316d92c64a306f21Eric Laurent
39058fa4d6f585f40ff5cf5f9bed316d92c64a306f21Eric Laurent                // Apply change to all streams using this one as alias
39068fa4d6f585f40ff5cf5f9bed316d92c64a306f21Eric Laurent                int numStreamTypes = AudioSystem.getNumStreamTypes();
39078fa4d6f585f40ff5cf5f9bed316d92c64a306f21Eric Laurent                for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
39088fa4d6f585f40ff5cf5f9bed316d92c64a306f21Eric Laurent                    if (streamType != streamState.mStreamType &&
39098fa4d6f585f40ff5cf5f9bed316d92c64a306f21Eric Laurent                            mStreamVolumeAlias[streamType] == streamState.mStreamType) {
39108fa4d6f585f40ff5cf5f9bed316d92c64a306f21Eric Laurent                        // Make sure volume is also maxed out on A2DP device for aliased stream
39118fa4d6f585f40ff5cf5f9bed316d92c64a306f21Eric Laurent                        // that may have a different device selected
39128fa4d6f585f40ff5cf5f9bed316d92c64a306f21Eric Laurent                        int streamDevice = getDeviceForStream(streamType);
39138fa4d6f585f40ff5cf5f9bed316d92c64a306f21Eric Laurent                        if ((device != streamDevice) && mAvrcpAbsVolSupported &&
39148fa4d6f585f40ff5cf5f9bed316d92c64a306f21Eric Laurent                                ((device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0)) {
39158fa4d6f585f40ff5cf5f9bed316d92c64a306f21Eric Laurent                            mStreamStates[streamType].applyDeviceVolume_syncVSS(device);
39168fa4d6f585f40ff5cf5f9bed316d92c64a306f21Eric Laurent                        }
39178fa4d6f585f40ff5cf5f9bed316d92c64a306f21Eric Laurent                        mStreamStates[streamType].applyDeviceVolume_syncVSS(streamDevice);
3918cd772d04345850e160a45613fcf6b86da0dce4cfEric Laurent                    }
3919a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent                }
3920a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent            }
39219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // Post a persist volume msg
3922afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent            sendMsg(mAudioHandler,
3923afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent                    MSG_PERSIST_VOLUME,
392498ad9b9d6fd34aad487933170f50b5519313df61Eric Laurent                    SENDMSG_QUEUE,
39259bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                    device,
392642b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                    0,
3927afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent                    streamState,
3928afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent                    PERSIST_DELAY);
3929afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent
39309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
39319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
39329bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent        private void setAllVolumes(VolumeStreamState streamState) {
39339bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent
39349bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent            // Apply volume
39359bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent            streamState.applyAllVolumes();
39369bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent
39379bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent            // Apply change to all streams using this one as alias
39389bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent            int numStreamTypes = AudioSystem.getNumStreamTypes();
39399bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent            for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
39409bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                if (streamType != streamState.mStreamType &&
39416d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent                        mStreamVolumeAlias[streamType] == streamState.mStreamType) {
39429bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                    mStreamStates[streamType].applyAllVolumes();
39439bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                }
39449bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent            }
39459bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent        }
39469bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent
394742b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent        private void persistVolume(VolumeStreamState streamState, int device) {
394883a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent            if (mUseFixedVolume) {
394983a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent                return;
395083a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent            }
3951212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent            if (isPlatformTelevision() && (streamState.mStreamType != AudioSystem.STREAM_MUSIC)) {
3952212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent                return;
3953212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent            }
395442b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent            System.putIntForUser(mContentResolver,
395542b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                      streamState.getSettingNameForDevice(device),
395642b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                      (streamState.getIndex(device) + 5)/ 10,
395742b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                      UserHandle.USER_CURRENT);
39589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
39599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3960ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten        private void persistRingerMode(int ringerMode) {
396183a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent            if (mUseFixedVolume) {
396283a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent                return;
396383a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent            }
39648d9a1f66d9d3dbbd45a56d441a746ec11dba7645Jeff Sharkey            Settings.Global.putInt(mContentResolver, Settings.Global.MODE_RINGER, ringerMode);
39659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
39669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
39675d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent        private boolean onLoadSoundEffects() {
39685d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent            int status;
39695d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent
39705d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent            synchronized (mSoundEffectsLock) {
39714a5eeb9c727d77bb57fef87a70c8c9cc23dbfee3Eric Laurent                if (!mSystemReady) {
39725d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    Log.w(TAG, "onLoadSoundEffects() called before boot complete");
39735d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    return false;
39745d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                }
39755d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent
39765d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                if (mSoundPool != null) {
39775d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    return true;
39785d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                }
39795d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent
39805d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                loadTouchSoundAssets();
39815d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent
398255a30c41b6c47d3afe6b13c25c64e8eec9f45e7cJean-Michel Trivi                mSoundPool = new SoundPool.Builder()
398355a30c41b6c47d3afe6b13c25c64e8eec9f45e7cJean-Michel Trivi                        .setMaxStreams(NUM_SOUNDPOOL_CHANNELS)
398455a30c41b6c47d3afe6b13c25c64e8eec9f45e7cJean-Michel Trivi                        .setAudioAttributes(new AudioAttributes.Builder()
398555a30c41b6c47d3afe6b13c25c64e8eec9f45e7cJean-Michel Trivi                            .setUsage(AudioAttributes.USAGE_ASSISTANCE_SONIFICATION)
398655a30c41b6c47d3afe6b13c25c64e8eec9f45e7cJean-Michel Trivi                            .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
398755a30c41b6c47d3afe6b13c25c64e8eec9f45e7cJean-Michel Trivi                            .build())
398855a30c41b6c47d3afe6b13c25c64e8eec9f45e7cJean-Michel Trivi                        .build();
39895d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                mSoundPoolCallBack = null;
39905d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                mSoundPoolListenerThread = new SoundPoolListenerThread();
39915d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                mSoundPoolListenerThread.start();
39925d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                int attempts = 3;
39935d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                while ((mSoundPoolCallBack == null) && (attempts-- > 0)) {
39945d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    try {
39955d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                        // Wait for mSoundPoolCallBack to be set by the other thread
3996167d1a27713ab64cd3c0aa70de96434083ef0400Glenn Kasten                        mSoundEffectsLock.wait(SOUND_EFFECTS_LOAD_TIMEOUT_MS);
39975d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    } catch (InterruptedException e) {
39985d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                        Log.w(TAG, "Interrupted while waiting sound pool listener thread.");
39995d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    }
40005d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                }
40015d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent
40025d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                if (mSoundPoolCallBack == null) {
40035d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    Log.w(TAG, "onLoadSoundEffects() SoundPool listener or thread creation error");
40045d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    if (mSoundPoolLooper != null) {
40055d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                        mSoundPoolLooper.quit();
40065d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                        mSoundPoolLooper = null;
40075d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    }
40085d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    mSoundPoolListenerThread = null;
40095d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    mSoundPool.release();
40105d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    mSoundPool = null;
40115d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    return false;
40125d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                }
40135d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                /*
40145d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                 * poolId table: The value -1 in this table indicates that corresponding
40155d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                 * file (same index in SOUND_EFFECT_FILES[] has not been loaded.
40165d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                 * Once loaded, the value in poolId is the sample ID and the same
40175d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                 * sample can be reused for another effect using the same file.
40185d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                 */
40195d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                int[] poolId = new int[SOUND_EFFECT_FILES.size()];
40205d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                for (int fileIdx = 0; fileIdx < SOUND_EFFECT_FILES.size(); fileIdx++) {
40215d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    poolId[fileIdx] = -1;
40225d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                }
40235d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                /*
40245d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                 * Effects whose value in SOUND_EFFECT_FILES_MAP[effect][1] is -1 must be loaded.
40255d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                 * If load succeeds, value in SOUND_EFFECT_FILES_MAP[effect][1] is > 0:
40265d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                 * this indicates we have a valid sample loaded for this effect.
40275d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                 */
40285d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent
40295d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                int numSamples = 0;
40305d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                for (int effect = 0; effect < AudioManager.NUM_SOUND_EFFECTS; effect++) {
40315d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    // Do not load sample if this effect uses the MediaPlayer
40325d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    if (SOUND_EFFECT_FILES_MAP[effect][1] == 0) {
40335d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                        continue;
40345d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    }
40355d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    if (poolId[SOUND_EFFECT_FILES_MAP[effect][0]] == -1) {
40365d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                        String filePath = Environment.getRootDirectory()
40375d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                                + SOUND_EFFECTS_PATH
40385d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                                + SOUND_EFFECT_FILES.get(SOUND_EFFECT_FILES_MAP[effect][0]);
40395d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                        int sampleId = mSoundPool.load(filePath, 0);
40405d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                        if (sampleId <= 0) {
40415d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                            Log.w(TAG, "Soundpool could not load file: "+filePath);
40425d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                        } else {
40435d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                            SOUND_EFFECT_FILES_MAP[effect][1] = sampleId;
40445d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                            poolId[SOUND_EFFECT_FILES_MAP[effect][0]] = sampleId;
40455d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                            numSamples++;
40465d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                        }
40475d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    } else {
40485d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                        SOUND_EFFECT_FILES_MAP[effect][1] =
40495d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                                poolId[SOUND_EFFECT_FILES_MAP[effect][0]];
40505d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    }
40515d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                }
40525d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                // wait for all samples to be loaded
40535d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                if (numSamples > 0) {
40545d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    mSoundPoolCallBack.setSamples(poolId);
40555d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent
40565d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    attempts = 3;
40575d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    status = 1;
40585d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    while ((status == 1) && (attempts-- > 0)) {
40595d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                        try {
4060167d1a27713ab64cd3c0aa70de96434083ef0400Glenn Kasten                            mSoundEffectsLock.wait(SOUND_EFFECTS_LOAD_TIMEOUT_MS);
40615d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                            status = mSoundPoolCallBack.status();
40625d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                        } catch (InterruptedException e) {
40635d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                            Log.w(TAG, "Interrupted while waiting sound pool callback.");
40645d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                        }
40655d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    }
40665d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                } else {
40675d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    status = -1;
40685d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                }
40695d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent
40705d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                if (mSoundPoolLooper != null) {
40715d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    mSoundPoolLooper.quit();
40725d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    mSoundPoolLooper = null;
40735d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                }
40745d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                mSoundPoolListenerThread = null;
40755d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                if (status != 0) {
40765d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    Log.w(TAG,
40775d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                            "onLoadSoundEffects(), Error "+status+ " while loading samples");
40785d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    for (int effect = 0; effect < AudioManager.NUM_SOUND_EFFECTS; effect++) {
40795d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                        if (SOUND_EFFECT_FILES_MAP[effect][1] > 0) {
40805d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                            SOUND_EFFECT_FILES_MAP[effect][1] = -1;
40815d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                        }
40825d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    }
40835d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent
40845d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    mSoundPool.release();
40855d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    mSoundPool = null;
40865d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                }
40875d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent            }
40885d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent            return (status == 0);
40895d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent        }
40905d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent
40915d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent        /**
40925d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent         *  Unloads samples from the sound pool.
40935d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent         *  This method can be called to free some memory when
40945d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent         *  sound effects are disabled.
40955d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent         */
40965d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent        private void onUnloadSoundEffects() {
40975d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent            synchronized (mSoundEffectsLock) {
40985d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                if (mSoundPool == null) {
40995d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    return;
41005d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                }
41015d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent
41025d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                int[] poolId = new int[SOUND_EFFECT_FILES.size()];
41035d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                for (int fileIdx = 0; fileIdx < SOUND_EFFECT_FILES.size(); fileIdx++) {
41045d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    poolId[fileIdx] = 0;
41055d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                }
41065d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent
41075d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                for (int effect = 0; effect < AudioManager.NUM_SOUND_EFFECTS; effect++) {
41085d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    if (SOUND_EFFECT_FILES_MAP[effect][1] <= 0) {
41095d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                        continue;
41105d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    }
41115d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    if (poolId[SOUND_EFFECT_FILES_MAP[effect][0]] == 0) {
41125d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                        mSoundPool.unload(SOUND_EFFECT_FILES_MAP[effect][1]);
41135d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                        SOUND_EFFECT_FILES_MAP[effect][1] = -1;
41145d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                        poolId[SOUND_EFFECT_FILES_MAP[effect][0]] = -1;
41155d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    }
41165d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                }
41175d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                mSoundPool.release();
41185d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                mSoundPool = null;
41195d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent            }
41205d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent        }
41215d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent
41225d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent        private void onPlaySoundEffect(int effectType, int volume) {
41239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            synchronized (mSoundEffectsLock) {
41245d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent
41255d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                onLoadSoundEffects();
41265d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent
41279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (mSoundPool == null) {
41289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    return;
41299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
4130a2ef57dba9ac77d8eccacd646b2b8a8d99fe9d8bEric Laurent                float volFloat;
413125101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent                // use default if volume is not specified by caller
4132a2ef57dba9ac77d8eccacd646b2b8a8d99fe9d8bEric Laurent                if (volume < 0) {
4133f2b0c11f4e797e183131261724d8de310dac5431Jean-Michel Trivi                    volFloat = (float)Math.pow(10, (float)sSoundEffectVolumeDb/20);
4134a2ef57dba9ac77d8eccacd646b2b8a8d99fe9d8bEric Laurent                } else {
41358a2cfc309ab9126e90022916967c65a793c034f0RoboErik                    volFloat = volume / 1000.0f;
4136a2ef57dba9ac77d8eccacd646b2b8a8d99fe9d8bEric Laurent                }
41379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
41389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (SOUND_EFFECT_FILES_MAP[effectType][1] > 0) {
41395d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    mSoundPool.play(SOUND_EFFECT_FILES_MAP[effectType][1],
41405d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                                        volFloat, volFloat, 0, 0, 1.0f);
41419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                } else {
41429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    MediaPlayer mediaPlayer = new MediaPlayer();
414362b9aec7a0a4e1cf8cfec7e39ea3103ab510d72eGlenn Kasten                    try {
4144e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent                        String filePath = Environment.getRootDirectory() + SOUND_EFFECTS_PATH +
4145e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent                                    SOUND_EFFECT_FILES.get(SOUND_EFFECT_FILES_MAP[effectType][0]);
414662b9aec7a0a4e1cf8cfec7e39ea3103ab510d72eGlenn Kasten                        mediaPlayer.setDataSource(filePath);
414762b9aec7a0a4e1cf8cfec7e39ea3103ab510d72eGlenn Kasten                        mediaPlayer.setAudioStreamType(AudioSystem.STREAM_SYSTEM);
414862b9aec7a0a4e1cf8cfec7e39ea3103ab510d72eGlenn Kasten                        mediaPlayer.prepare();
4149068225de0197df07a0247b2877666ea91c22c992Glenn Kasten                        mediaPlayer.setVolume(volFloat);
415062b9aec7a0a4e1cf8cfec7e39ea3103ab510d72eGlenn Kasten                        mediaPlayer.setOnCompletionListener(new OnCompletionListener() {
415162b9aec7a0a4e1cf8cfec7e39ea3103ab510d72eGlenn Kasten                            public void onCompletion(MediaPlayer mp) {
415262b9aec7a0a4e1cf8cfec7e39ea3103ab510d72eGlenn Kasten                                cleanupPlayer(mp);
415362b9aec7a0a4e1cf8cfec7e39ea3103ab510d72eGlenn Kasten                            }
415462b9aec7a0a4e1cf8cfec7e39ea3103ab510d72eGlenn Kasten                        });
415562b9aec7a0a4e1cf8cfec7e39ea3103ab510d72eGlenn Kasten                        mediaPlayer.setOnErrorListener(new OnErrorListener() {
415662b9aec7a0a4e1cf8cfec7e39ea3103ab510d72eGlenn Kasten                            public boolean onError(MediaPlayer mp, int what, int extra) {
415762b9aec7a0a4e1cf8cfec7e39ea3103ab510d72eGlenn Kasten                                cleanupPlayer(mp);
415862b9aec7a0a4e1cf8cfec7e39ea3103ab510d72eGlenn Kasten                                return true;
415962b9aec7a0a4e1cf8cfec7e39ea3103ab510d72eGlenn Kasten                            }
416062b9aec7a0a4e1cf8cfec7e39ea3103ab510d72eGlenn Kasten                        });
416162b9aec7a0a4e1cf8cfec7e39ea3103ab510d72eGlenn Kasten                        mediaPlayer.start();
416262b9aec7a0a4e1cf8cfec7e39ea3103ab510d72eGlenn Kasten                    } catch (IOException ex) {
416362b9aec7a0a4e1cf8cfec7e39ea3103ab510d72eGlenn Kasten                        Log.w(TAG, "MediaPlayer IOException: "+ex);
416462b9aec7a0a4e1cf8cfec7e39ea3103ab510d72eGlenn Kasten                    } catch (IllegalArgumentException ex) {
416562b9aec7a0a4e1cf8cfec7e39ea3103ab510d72eGlenn Kasten                        Log.w(TAG, "MediaPlayer IllegalArgumentException: "+ex);
416662b9aec7a0a4e1cf8cfec7e39ea3103ab510d72eGlenn Kasten                    } catch (IllegalStateException ex) {
416762b9aec7a0a4e1cf8cfec7e39ea3103ab510d72eGlenn Kasten                        Log.w(TAG, "MediaPlayer IllegalStateException: "+ex);
41689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    }
41699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
41709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
41719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
41729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
41739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        private void cleanupPlayer(MediaPlayer mp) {
41749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (mp != null) {
41759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                try {
41769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    mp.stop();
41779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    mp.release();
41789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                } catch (IllegalStateException ex) {
41799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    Log.w(TAG, "MediaPlayer IllegalStateException: "+ex);
41809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
41819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
41829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
41839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4184fa640154f1f42121d81242b2f1a10f03e52f0014Eric Laurent        private void setForceUse(int usage, int config) {
4185fa640154f1f42121d81242b2f1a10f03e52f0014Eric Laurent            AudioSystem.setForceUse(usage, config);
4186fa640154f1f42121d81242b2f1a10f03e52f0014Eric Laurent        }
4187fa640154f1f42121d81242b2f1a10f03e52f0014Eric Laurent
418805274f348e12983eb8613cc6eb9ae561e8197e28Eric Laurent        private void onPersistSafeVolumeState(int state) {
418905274f348e12983eb8613cc6eb9ae561e8197e28Eric Laurent            Settings.Global.putInt(mContentResolver,
419005274f348e12983eb8613cc6eb9ae561e8197e28Eric Laurent                    Settings.Global.AUDIO_SAFE_VOLUME_STATE,
419105274f348e12983eb8613cc6eb9ae561e8197e28Eric Laurent                    state);
419205274f348e12983eb8613cc6eb9ae561e8197e28Eric Laurent        }
419305274f348e12983eb8613cc6eb9ae561e8197e28Eric Laurent
41949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        @Override
41959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public void handleMessage(Message msg) {
4196afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent            switch (msg.what) {
41979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
41989bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                case MSG_SET_DEVICE_VOLUME:
41999bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                    setDeviceVolume((VolumeStreamState) msg.obj, msg.arg1);
42009bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                    break;
42019bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent
42029bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                case MSG_SET_ALL_VOLUMES:
42039bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                    setAllVolumes((VolumeStreamState) msg.obj);
42049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    break;
42059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
42069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                case MSG_PERSIST_VOLUME:
420742b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                    persistVolume((VolumeStreamState) msg.obj, msg.arg1);
42089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    break;
42099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
42105c55a051ad7d86a464fb91426f1ea3c0250e38b3Mike Lockwood                case MSG_PERSIST_MASTER_VOLUME:
421183a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent                    if (mUseFixedVolume) {
421283a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent                        return;
421383a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent                    }
4214bc0fab1fc2db832ef86d8a33466ec4d68b103ca0Eric Laurent                    Settings.System.putFloatForUser(mContentResolver,
4215bc0fab1fc2db832ef86d8a33466ec4d68b103ca0Eric Laurent                                                    Settings.System.VOLUME_MASTER,
42168a2cfc309ab9126e90022916967c65a793c034f0RoboErik                                                    msg.arg1 / (float)1000.0,
4217bc0fab1fc2db832ef86d8a33466ec4d68b103ca0Eric Laurent                                                    UserHandle.USER_CURRENT);
42185c55a051ad7d86a464fb91426f1ea3c0250e38b3Mike Lockwood                    break;
42195c55a051ad7d86a464fb91426f1ea3c0250e38b3Mike Lockwood
422057978ed86286a33d5b1a0fd000ca3406ba9d87b3Justin Koh                case MSG_PERSIST_MASTER_VOLUME_MUTE:
422183a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent                    if (mUseFixedVolume) {
422283a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent                        return;
422383a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent                    }
4224bc0fab1fc2db832ef86d8a33466ec4d68b103ca0Eric Laurent                    Settings.System.putIntForUser(mContentResolver,
4225bc0fab1fc2db832ef86d8a33466ec4d68b103ca0Eric Laurent                                                 Settings.System.VOLUME_MASTER_MUTE,
4226bc0fab1fc2db832ef86d8a33466ec4d68b103ca0Eric Laurent                                                 msg.arg1,
4227b53453fae037d67e421011936c8fdffe7ba43922Julia Reynolds                                                 msg.arg2);
422857978ed86286a33d5b1a0fd000ca3406ba9d87b3Justin Koh                    break;
422957978ed86286a33d5b1a0fd000ca3406ba9d87b3Justin Koh
42309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                case MSG_PERSIST_RINGER_MODE:
4231ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten                    // note that the value persisted is the current ringer mode, not the
4232ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten                    // value of ringer mode as of the time the request was made to persist
4233661f2cf45860d2e10924e6b69966a9afe255f28bJohn Spurlock                    persistRingerMode(getRingerModeInternal());
42349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    break;
42359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
42369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                case MSG_MEDIA_SERVER_DIED:
4237eb4b8a27e3219726691a868793d2247dc9d2a317Eric Laurent                    if (!mSystemReady ||
4238eb4b8a27e3219726691a868793d2247dc9d2a317Eric Laurent                            (AudioSystem.checkAudioFlinger() != AudioSystem.AUDIO_STATUS_OK)) {
423989e74ba1419732dd5c7f939e48d4aa7989fd3a51Eric Laurent                        Log.e(TAG, "Media server died.");
4240afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent                        sendMsg(mAudioHandler, MSG_MEDIA_SERVER_DIED, SENDMSG_NOOP, 0, 0,
424189e74ba1419732dd5c7f939e48d4aa7989fd3a51Eric Laurent                                null, 500);
4242dfb881f96af7898151940a4bbc52e45e6043d38bEric Laurent                        break;
424389e74ba1419732dd5c7f939e48d4aa7989fd3a51Eric Laurent                    }
42449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    Log.e(TAG, "Media server started.");
4245dfb881f96af7898151940a4bbc52e45e6043d38bEric Laurent
42463c652ca5a546e7227a5f4bdbf0f81552b2c91383Eric Laurent                    // indicate to audio HAL that we start the reconfiguration phase after a media
42473c652ca5a546e7227a5f4bdbf0f81552b2c91383Eric Laurent                    // server crash
4248dfb881f96af7898151940a4bbc52e45e6043d38bEric Laurent                    // Note that we only execute this when the media server
42493c652ca5a546e7227a5f4bdbf0f81552b2c91383Eric Laurent                    // process restarts after a crash, not the first time it is started.
42503c652ca5a546e7227a5f4bdbf0f81552b2c91383Eric Laurent                    AudioSystem.setParameters("restarting=true");
42513c652ca5a546e7227a5f4bdbf0f81552b2c91383Eric Laurent
4252fd116ad1ab02f6060a0b2201f018317fa32e28b4Glenn Kasten                    readAndSetLowRamDevice();
4253fd116ad1ab02f6060a0b2201f018317fa32e28b4Glenn Kasten
4254c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent                    // Restore device connection states
42556bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                    synchronized (mConnectedDevices) {
42566bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                        Set set = mConnectedDevices.entrySet();
42576bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                        Iterator i = set.iterator();
42589bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                        while (i.hasNext()) {
42596bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                            Map.Entry device = (Map.Entry)i.next();
42606bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                            AudioSystem.setDeviceConnectionState(
42616bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                                                            ((Integer)device.getKey()).intValue(),
42626bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                                                            AudioSystem.DEVICE_STATE_AVAILABLE,
42636bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                                                            (String)device.getValue());
42646bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                        }
4265c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent                    }
4266c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent                    // Restore call state
4267c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent                    AudioSystem.setPhoneState(mMode);
4268c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent
4269d5603c126acdd94d9f7400bb1d04188020a425b4Eric Laurent                    // Restore forced usage for communcations and record
4270c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent                    AudioSystem.setForceUse(AudioSystem.FOR_COMMUNICATION, mForcedUseForComm);
4271d5603c126acdd94d9f7400bb1d04188020a425b4Eric Laurent                    AudioSystem.setForceUse(AudioSystem.FOR_RECORD, mForcedUseForComm);
4272dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent                    AudioSystem.setForceUse(AudioSystem.FOR_SYSTEM, mCameraSoundForced ?
4273dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent                                    AudioSystem.FORCE_SYSTEM_ENFORCED : AudioSystem.FORCE_NONE);
4274c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent
4275a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent                    // Restore stream volumes
42769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    int numStreamTypes = AudioSystem.getNumStreamTypes();
42779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
42789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        VolumeStreamState streamState = mStreamStates[streamType];
4279c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent                        AudioSystem.initStreamVolume(streamType, 0, (streamState.mIndexMax + 5) / 10);
42809bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent
42819bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                        streamState.applyAllVolumes();
42829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    }
4283c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent
4284c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent                    // Restore ringer mode
4285661f2cf45860d2e10924e6b69966a9afe255f28bJohn Spurlock                    setRingerModeInt(getRingerModeInternal(), false);
42863c652ca5a546e7227a5f4bdbf0f81552b2c91383Eric Laurent
42879063154a793b0ab38b3c5992cbaed046427b4a82Mike Lockwood                    // Restore master volume
42889063154a793b0ab38b3c5992cbaed046427b4a82Mike Lockwood                    restoreMasterVolume();
42899063154a793b0ab38b3c5992cbaed046427b4a82Mike Lockwood
4290f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi                    // Reset device orientation (if monitored for this device)
4291d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent                    if (mMonitorOrientation) {
4292f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi                        setOrientationForAudioSystem();
4293f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi                    }
4294bb6f8711a7f804d39c45218db2d6339940cc5d35Jean-Michel Trivi                    if (mMonitorRotation) {
4295bb6f8711a7f804d39c45218db2d6339940cc5d35Jean-Michel Trivi                        setRotationForAudioSystem();
4296bb6f8711a7f804d39c45218db2d6339940cc5d35Jean-Michel Trivi                    }
4297f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi
42987847211fb4699bf6018e29d214a918ed6657319bEric Laurent                    synchronized (mBluetoothA2dpEnabledLock) {
42997847211fb4699bf6018e29d214a918ed6657319bEric Laurent                        AudioSystem.setForceUse(AudioSystem.FOR_MEDIA,
43007847211fb4699bf6018e29d214a918ed6657319bEric Laurent                                mBluetoothA2dpEnabled ?
43017847211fb4699bf6018e29d214a918ed6657319bEric Laurent                                        AudioSystem.FORCE_NONE : AudioSystem.FORCE_NO_BT_A2DP);
43027847211fb4699bf6018e29d214a918ed6657319bEric Laurent                    }
4303bff5ca576ef55bfdd51a0d2ff39f4bac614fa728Eric Laurent
4304bff5ca576ef55bfdd51a0d2ff39f4bac614fa728Eric Laurent                    synchronized (mSettingsLock) {
4305bff5ca576ef55bfdd51a0d2ff39f4bac614fa728Eric Laurent                        AudioSystem.setForceUse(AudioSystem.FOR_DOCK,
4306bff5ca576ef55bfdd51a0d2ff39f4bac614fa728Eric Laurent                                mDockAudioMediaEnabled ?
4307bff5ca576ef55bfdd51a0d2ff39f4bac614fa728Eric Laurent                                        AudioSystem.FORCE_ANALOG_DOCK : AudioSystem.FORCE_NONE);
4308bff5ca576ef55bfdd51a0d2ff39f4bac614fa728Eric Laurent                    }
4309212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent                    if (mHdmiManager != null) {
4310212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent                        synchronized (mHdmiManager) {
4311212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent                            if (mHdmiTvClient != null) {
4312212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent                                setHdmiSystemAudioSupported(mHdmiSystemAudioSupported);
4313212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent                            }
4314212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent                        }
43156f34f5ab8ab1b1db7887e5405d8b0031e105ab05Jungshik Jang                    }
43167f5eb9fe3c10d8d83ff0e2b0fc60a05c2e6d5b02Eric Laurent
43177f5eb9fe3c10d8d83ff0e2b0fc60a05c2e6d5b02Eric Laurent                    synchronized (mAudioPolicies) {
43187f5eb9fe3c10d8d83ff0e2b0fc60a05c2e6d5b02Eric Laurent                        for(AudioPolicyProxy policy : mAudioPolicies.values()) {
43197f5eb9fe3c10d8d83ff0e2b0fc60a05c2e6d5b02Eric Laurent                            policy.connectMixes();
43207f5eb9fe3c10d8d83ff0e2b0fc60a05c2e6d5b02Eric Laurent                        }
43217f5eb9fe3c10d8d83ff0e2b0fc60a05c2e6d5b02Eric Laurent                    }
43227f5eb9fe3c10d8d83ff0e2b0fc60a05c2e6d5b02Eric Laurent
43233c652ca5a546e7227a5f4bdbf0f81552b2c91383Eric Laurent                    // indicate the end of reconfiguration phase to audio HAL
43243c652ca5a546e7227a5f4bdbf0f81552b2c91383Eric Laurent                    AudioSystem.setParameters("restarting=false");
43259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    break;
43269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
43275d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                case MSG_UNLOAD_SOUND_EFFECTS:
43285d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    onUnloadSoundEffects();
43295d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    break;
43305d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent
4331117b7bb5b5a4457711f59bde3dcc83d8f111c524Eric Laurent                case MSG_LOAD_SOUND_EFFECTS:
43325d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    //FIXME: onLoadSoundEffects() should be executed in a separate thread as it
43335d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    // can take several dozens of milliseconds to complete
43345d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    boolean loaded = onLoadSoundEffects();
43355d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    if (msg.obj != null) {
43365d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                        LoadSoundEffectReply reply = (LoadSoundEffectReply)msg.obj;
43375d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                        synchronized (reply) {
43385d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                            reply.mStatus = loaded ? 0 : -1;
43395d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                            reply.notify();
43405d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                        }
43415d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    }
4342117b7bb5b5a4457711f59bde3dcc83d8f111c524Eric Laurent                    break;
4343117b7bb5b5a4457711f59bde3dcc83d8f111c524Eric Laurent
43449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                case MSG_PLAY_SOUND_EFFECT:
43455d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    onPlaySoundEffect(msg.arg1, msg.arg2);
43469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    break;
43474c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi
43484c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi                case MSG_BTA2DP_DOCK_TIMEOUT:
43494c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi                    // msg.obj  == address of BTA2DP device
43506bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                    synchronized (mConnectedDevices) {
43516bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                        makeA2dpDeviceUnavailableNow( (String) msg.obj );
43526bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                    }
43534c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi                    break;
4354fa640154f1f42121d81242b2f1a10f03e52f0014Eric Laurent
4355fa640154f1f42121d81242b2f1a10f03e52f0014Eric Laurent                case MSG_SET_FORCE_USE:
4356c390bed06b4a572e273ead1254da9a932e04dce3Eric Laurent                case MSG_SET_FORCE_BT_A2DP_USE:
4357fa640154f1f42121d81242b2f1a10f03e52f0014Eric Laurent                    setForceUse(msg.arg1, msg.arg2);
4358fa640154f1f42121d81242b2f1a10f03e52f0014Eric Laurent                    break;
4359d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi
4360dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                case MSG_BT_HEADSET_CNCT_FAILED:
4361dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                    resetBluetoothSco();
4362dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                    break;
4363b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent
4364b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent                case MSG_SET_WIRED_DEVICE_CONNECTION_STATE:
4365b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent                    onSetWiredDeviceConnectionState(msg.arg1, msg.arg2, (String)msg.obj);
4366fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                    mAudioEventWakeLock.release();
4367b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent                    break;
4368b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent
43690a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood                case MSG_SET_A2DP_SRC_CONNECTION_STATE:
43700a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood                    onSetA2dpSourceConnectionState((BluetoothDevice)msg.obj, msg.arg1);
43710a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood                    mAudioEventWakeLock.release();
43720a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood                    break;
43730a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood
43740a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood                case MSG_SET_A2DP_SINK_CONNECTION_STATE:
43750a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood                    onSetA2dpSinkConnectionState((BluetoothDevice)msg.obj, msg.arg1);
4376fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                    mAudioEventWakeLock.release();
4377b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent                    break;
4378632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn
4379632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                case MSG_REPORT_NEW_ROUTES: {
4380632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                    int N = mRoutesObservers.beginBroadcast();
4381632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                    if (N > 0) {
4382632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                        AudioRoutesInfo routes;
4383632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                        synchronized (mCurAudioRoutes) {
4384632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                            routes = new AudioRoutesInfo(mCurAudioRoutes);
4385632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                        }
4386632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                        while (N > 0) {
4387632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                            N--;
4388632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                            IAudioRoutesObserver obs = mRoutesObservers.getBroadcastItem(N);
4389632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                            try {
4390632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                                obs.dispatchAudioRoutesChanged(routes);
4391632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                            } catch (RemoteException e) {
4392632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                            }
4393632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                        }
4394632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                    }
4395632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                    mRoutesObservers.finishBroadcast();
4396632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                    break;
4397632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                }
43983114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi
4399c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent                case MSG_CHECK_MUSIC_ACTIVE:
4400c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent                    onCheckMusicActive();
4401c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent                    break;
44025bfaeaef3fc348d66f48b86be08655e91dff910aEric Laurent
44035bfaeaef3fc348d66f48b86be08655e91dff910aEric Laurent                case MSG_BROADCAST_AUDIO_BECOMING_NOISY:
44045bfaeaef3fc348d66f48b86be08655e91dff910aEric Laurent                    onSendBecomingNoisyIntent();
44055bfaeaef3fc348d66f48b86be08655e91dff910aEric Laurent                    break;
4406d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent
4407d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent                case MSG_CONFIGURE_SAFE_MEDIA_VOLUME_FORCED:
4408d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent                case MSG_CONFIGURE_SAFE_MEDIA_VOLUME:
4409d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent                    onConfigureSafeVolume((msg.what == MSG_CONFIGURE_SAFE_MEDIA_VOLUME_FORCED));
4410d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent                    break;
441105274f348e12983eb8613cc6eb9ae561e8197e28Eric Laurent                case MSG_PERSIST_SAFE_VOLUME_STATE:
441205274f348e12983eb8613cc6eb9ae561e8197e28Eric Laurent                    onPersistSafeVolumeState(msg.arg1);
441305274f348e12983eb8613cc6eb9ae561e8197e28Eric Laurent                    break;
4414a578c48e6c8677bcb54340aadb9470f8a275e56cJean-Michel Trivi
44152a57ca931fefe817b6110101289721acaacfc808Eric Laurent                case MSG_BROADCAST_BT_CONNECTION_STATE:
44162a57ca931fefe817b6110101289721acaacfc808Eric Laurent                    onBroadcastScoConnectionState(msg.arg1);
44172a57ca931fefe817b6110101289721acaacfc808Eric Laurent                    break;
44184a5eeb9c727d77bb57fef87a70c8c9cc23dbfee3Eric Laurent
44194a5eeb9c727d77bb57fef87a70c8c9cc23dbfee3Eric Laurent                case MSG_SYSTEM_READY:
44204a5eeb9c727d77bb57fef87a70c8c9cc23dbfee3Eric Laurent                    onSystemReady();
44214a5eeb9c727d77bb57fef87a70c8c9cc23dbfee3Eric Laurent                    break;
4422aa5ee4d65f8788e2a0afcd198367450853fd72acJohn Spurlock
4423aa5ee4d65f8788e2a0afcd198367450853fd72acJohn Spurlock                case MSG_PERSIST_MUSIC_ACTIVE_MS:
4424aa5ee4d65f8788e2a0afcd198367450853fd72acJohn Spurlock                    final int musicActiveMs = msg.arg1;
4425aa5ee4d65f8788e2a0afcd198367450853fd72acJohn Spurlock                    Settings.Secure.putIntForUser(mContentResolver,
4426aa5ee4d65f8788e2a0afcd198367450853fd72acJohn Spurlock                            Settings.Secure.UNSAFE_VOLUME_MUSIC_ACTIVE_MS, musicActiveMs,
4427aa5ee4d65f8788e2a0afcd198367450853fd72acJohn Spurlock                            UserHandle.USER_CURRENT);
4428aa5ee4d65f8788e2a0afcd198367450853fd72acJohn Spurlock                    break;
4429b53453fae037d67e421011936c8fdffe7ba43922Julia Reynolds                case MSG_PERSIST_MICROPHONE_MUTE:
4430b53453fae037d67e421011936c8fdffe7ba43922Julia Reynolds                    Settings.System.putIntForUser(mContentResolver,
4431b53453fae037d67e421011936c8fdffe7ba43922Julia Reynolds                                                 Settings.System.MICROPHONE_MUTE,
4432b53453fae037d67e421011936c8fdffe7ba43922Julia Reynolds                                                 msg.arg1,
4433b53453fae037d67e421011936c8fdffe7ba43922Julia Reynolds                                                 msg.arg2);
4434b53453fae037d67e421011936c8fdffe7ba43922Julia Reynolds                    break;
44359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
44369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
44379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
44389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4439b109615ebebd6f3b9ae789412279f576c3ace46bJason Parekh    private class SettingsObserver extends ContentObserver {
4440a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent
4441b109615ebebd6f3b9ae789412279f576c3ace46bJason Parekh        SettingsObserver() {
4442b109615ebebd6f3b9ae789412279f576c3ace46bJason Parekh            super(new Handler());
4443b109615ebebd6f3b9ae789412279f576c3ace46bJason Parekh            mContentResolver.registerContentObserver(Settings.System.getUriFor(
4444b109615ebebd6f3b9ae789412279f576c3ace46bJason Parekh                Settings.System.MODE_RINGER_STREAMS_AFFECTED), false, this);
44457ee1e4ff7346a278a6722108fbc1869240b3e866Eric Laurent            mContentResolver.registerContentObserver(Settings.Global.getUriFor(
44467ee1e4ff7346a278a6722108fbc1869240b3e866Eric Laurent                Settings.Global.DOCK_AUDIO_MEDIA_ENABLED), false, this);
4447b109615ebebd6f3b9ae789412279f576c3ace46bJason Parekh        }
4448b109615ebebd6f3b9ae789412279f576c3ace46bJason Parekh
4449b109615ebebd6f3b9ae789412279f576c3ace46bJason Parekh        @Override
4450b109615ebebd6f3b9ae789412279f576c3ace46bJason Parekh        public void onChange(boolean selfChange) {
4451b109615ebebd6f3b9ae789412279f576c3ace46bJason Parekh            super.onChange(selfChange);
4452ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten            // FIXME This synchronized is not necessary if mSettingsLock only protects mRingerMode.
4453ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten            //       However there appear to be some missing locks around mRingerModeMutedStreams
4454ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten            //       and mRingerModeAffectedStreams, so will leave this synchronized for now.
4455ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten            //       mRingerModeMutedStreams and mMuteAffectedStreams are safe (only accessed once).
4456a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent            synchronized (mSettingsLock) {
445724e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent                if (updateRingerModeAffectedStreams()) {
4458a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent                    /*
4459a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent                     * Ensure all stream types that should be affected by ringer mode
4460a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent                     * are in the proper state.
4461a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent                     */
4462661f2cf45860d2e10924e6b69966a9afe255f28bJohn Spurlock                    setRingerModeInt(getRingerModeInternal(), false);
4463a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent                }
44647ee1e4ff7346a278a6722108fbc1869240b3e866Eric Laurent                readDockAudioSettings(mContentResolver);
4465a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent            }
4466b109615ebebd6f3b9ae789412279f576c3ace46bJason Parekh        }
4467b109615ebebd6f3b9ae789412279f576c3ace46bJason Parekh    }
4468a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent
44696bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent    // must be called synchronized on mConnectedDevices
44704c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi    private void makeA2dpDeviceAvailable(String address) {
44717847211fb4699bf6018e29d214a918ed6657319bEric Laurent        // enable A2DP before notifying A2DP connection to avoid unecessary processing in
44727847211fb4699bf6018e29d214a918ed6657319bEric Laurent        // audio policy manager
4473c9d1d5f35091226e96fcfa91817480f589eb36e2Matthew Xie        VolumeStreamState streamState = mStreamStates[AudioSystem.STREAM_MUSIC];
4474c9d1d5f35091226e96fcfa91817480f589eb36e2Matthew Xie        sendMsg(mAudioHandler, MSG_SET_DEVICE_VOLUME, SENDMSG_QUEUE,
4475c9d1d5f35091226e96fcfa91817480f589eb36e2Matthew Xie                AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, 0, streamState, 0);
44767847211fb4699bf6018e29d214a918ed6657319bEric Laurent        setBluetoothA2dpOnInt(true);
44774c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi        AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
44784c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi                AudioSystem.DEVICE_STATE_AVAILABLE,
44794c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi                address);
44804c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi        // Reset A2DP suspend state each time a new sink is connected
44814c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi        AudioSystem.setParameters("A2dpSuspended=false");
44824c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi        mConnectedDevices.put( new Integer(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP),
44834c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi                address);
44844c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi    }
44854c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi
44865bfaeaef3fc348d66f48b86be08655e91dff910aEric Laurent    private void onSendBecomingNoisyIntent() {
44875ac72a29593ab9a20337a2225df52bdf4754be02Dianne Hackborn        sendBroadcastToAll(new Intent(AudioManager.ACTION_AUDIO_BECOMING_NOISY));
44889841818b9a0280abf59343c9e00a2976dbc084faMike Lockwood    }
44899841818b9a0280abf59343c9e00a2976dbc084faMike Lockwood
44906bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent    // must be called synchronized on mConnectedDevices
44914c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi    private void makeA2dpDeviceUnavailableNow(String address) {
4492c9d1d5f35091226e96fcfa91817480f589eb36e2Matthew Xie        synchronized (mA2dpAvrcpLock) {
4493c9d1d5f35091226e96fcfa91817480f589eb36e2Matthew Xie            mAvrcpAbsVolSupported = false;
4494c9d1d5f35091226e96fcfa91817480f589eb36e2Matthew Xie        }
44954c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi        AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
44964c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi                AudioSystem.DEVICE_STATE_UNAVAILABLE,
44974c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi                address);
44984c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi        mConnectedDevices.remove(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP);
44995535ea8ef876be25121a6336ffab5a0bf8dbd031RoboErik        synchronized (mCurAudioRoutes) {
45005535ea8ef876be25121a6336ffab5a0bf8dbd031RoboErik            // Remove A2DP routes as well
45015535ea8ef876be25121a6336ffab5a0bf8dbd031RoboErik            if (mCurAudioRoutes.mBluetoothName != null) {
45025535ea8ef876be25121a6336ffab5a0bf8dbd031RoboErik                mCurAudioRoutes.mBluetoothName = null;
45035535ea8ef876be25121a6336ffab5a0bf8dbd031RoboErik                sendMsg(mAudioHandler, MSG_REPORT_NEW_ROUTES,
45045535ea8ef876be25121a6336ffab5a0bf8dbd031RoboErik                        SENDMSG_NOOP, 0, 0, null, 0);
45055535ea8ef876be25121a6336ffab5a0bf8dbd031RoboErik            }
45065535ea8ef876be25121a6336ffab5a0bf8dbd031RoboErik        }
45074c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi    }
45084c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi
45096bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent    // must be called synchronized on mConnectedDevices
45104c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi    private void makeA2dpDeviceUnavailableLater(String address) {
45113b5912602bec6ccbe8eef8a576730b1565f0067cEric Laurent        // prevent any activity on the A2DP audio output to avoid unwanted
45123b5912602bec6ccbe8eef8a576730b1565f0067cEric Laurent        // reconnection of the sink.
45133b5912602bec6ccbe8eef8a576730b1565f0067cEric Laurent        AudioSystem.setParameters("A2dpSuspended=true");
45144c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi        // the device will be made unavailable later, so consider it disconnected right away
45154c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi        mConnectedDevices.remove(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP);
45164c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi        // send the delayed message to make the device unavailable later
45174c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi        Message msg = mAudioHandler.obtainMessage(MSG_BTA2DP_DOCK_TIMEOUT, address);
45184c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi        mAudioHandler.sendMessageDelayed(msg, BTA2DP_DOCK_TIMEOUT_MILLIS);
45194c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi
45204c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi    }
45214c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi
45226bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent    // must be called synchronized on mConnectedDevices
45230a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood    private void makeA2dpSrcAvailable(String address) {
45240a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood        AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP,
45250a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood                AudioSystem.DEVICE_STATE_AVAILABLE,
45260a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood                address);
45270a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood        mConnectedDevices.put( new Integer(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP),
45280a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood                address);
45290a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood    }
45300a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood
45310a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood    // must be called synchronized on mConnectedDevices
45320a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood    private void makeA2dpSrcUnavailable(String address) {
45330a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood        AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP,
45340a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood                AudioSystem.DEVICE_STATE_UNAVAILABLE,
45350a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood                address);
45360a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood        mConnectedDevices.remove(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP);
45370a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood    }
45380a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood
45390a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood    // must be called synchronized on mConnectedDevices
4540a847ba4080675d395de725cfac5dfd9d5a993d4eJean-Michel Trivi    private void cancelA2dpDeviceTimeout() {
45414c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi        mAudioHandler.removeMessages(MSG_BTA2DP_DOCK_TIMEOUT);
45424c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi    }
45434c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi
45446bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent    // must be called synchronized on mConnectedDevices
4545a847ba4080675d395de725cfac5dfd9d5a993d4eJean-Michel Trivi    private boolean hasScheduledA2dpDockTimeout() {
4546a847ba4080675d395de725cfac5dfd9d5a993d4eJean-Michel Trivi        return mAudioHandler.hasMessages(MSG_BTA2DP_DOCK_TIMEOUT);
4547a847ba4080675d395de725cfac5dfd9d5a993d4eJean-Michel Trivi    }
4548a847ba4080675d395de725cfac5dfd9d5a993d4eJean-Michel Trivi
45490a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood    private void onSetA2dpSinkConnectionState(BluetoothDevice btDevice, int state)
45506bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent    {
45510a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood        if (DEBUG_VOL) {
45520a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood            Log.d(TAG, "onSetA2dpSinkConnectionState btDevice="+btDevice+"state="+state);
45530a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood        }
45546bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent        if (btDevice == null) {
45556bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent            return;
45566bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent        }
45576bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent        String address = btDevice.getAddress();
45586bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent        if (!BluetoothAdapter.checkBluetoothAddress(address)) {
45596bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent            address = "";
45606bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent        }
45615a0cf7a27f3953a1266af48543ccd9024f4cd89fJohn Du
45626bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent        synchronized (mConnectedDevices) {
45636bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent            boolean isConnected =
45646bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                (mConnectedDevices.containsKey(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP) &&
45656bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                 mConnectedDevices.get(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP).equals(address));
45666bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent
45676bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent            if (isConnected && state != BluetoothProfile.STATE_CONNECTED) {
45686bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                if (btDevice.isBluetoothDock()) {
45696bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                    if (state == BluetoothProfile.STATE_DISCONNECTED) {
45706bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                        // introduction of a delay for transient disconnections of docks when
45716bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                        // power is rapidly turned off/on, this message will be canceled if
45726bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                        // we reconnect the dock under a preset delay
45736bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                        makeA2dpDeviceUnavailableLater(address);
45746bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                        // the next time isConnected is evaluated, it will be false for the dock
45756bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                    }
45766bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                } else {
45776bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                    makeA2dpDeviceUnavailableNow(address);
45786bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                }
4579632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                synchronized (mCurAudioRoutes) {
4580632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                    if (mCurAudioRoutes.mBluetoothName != null) {
4581632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                        mCurAudioRoutes.mBluetoothName = null;
4582632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                        sendMsg(mAudioHandler, MSG_REPORT_NEW_ROUTES,
4583632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                                SENDMSG_NOOP, 0, 0, null, 0);
4584632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                    }
4585632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                }
45866bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent            } else if (!isConnected && state == BluetoothProfile.STATE_CONNECTED) {
45876bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                if (btDevice.isBluetoothDock()) {
45886bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                    // this could be a reconnection after a transient disconnection
45896bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                    cancelA2dpDeviceTimeout();
45906bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                    mDockAddress = address;
45916bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                } else {
45926bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                    // this could be a connection of another A2DP device before the timeout of
45936bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                    // a dock: cancel the dock timeout, and make the dock unavailable now
45946bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                    if(hasScheduledA2dpDockTimeout()) {
45956bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                        cancelA2dpDeviceTimeout();
45966bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                        makeA2dpDeviceUnavailableNow(mDockAddress);
45976bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                    }
45986bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                }
45996bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                makeA2dpDeviceAvailable(address);
4600632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                synchronized (mCurAudioRoutes) {
4601632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                    String name = btDevice.getAliasName();
4602632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                    if (!TextUtils.equals(mCurAudioRoutes.mBluetoothName, name)) {
4603632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                        mCurAudioRoutes.mBluetoothName = name;
4604632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                        sendMsg(mAudioHandler, MSG_REPORT_NEW_ROUTES,
4605632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                                SENDMSG_NOOP, 0, 0, null, 0);
4606632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                    }
4607632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                }
46086bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent            }
46096bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent        }
46106bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent    }
46116bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent
46120a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood    private void onSetA2dpSourceConnectionState(BluetoothDevice btDevice, int state)
46130a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood    {
46140a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood        if (DEBUG_VOL) {
46150a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood            Log.d(TAG, "onSetA2dpSourceConnectionState btDevice="+btDevice+" state="+state);
46160a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood        }
46170a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood        if (btDevice == null) {
46180a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood            return;
46190a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood        }
46200a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood        String address = btDevice.getAddress();
46210a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood        if (!BluetoothAdapter.checkBluetoothAddress(address)) {
46220a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood            address = "";
46230a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood        }
46240a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood
46250a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood        synchronized (mConnectedDevices) {
46260a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood                boolean isConnected =
46270a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood                (mConnectedDevices.containsKey(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP) &&
46280a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood                 mConnectedDevices.get(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP).equals(address));
46290a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood
46300a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood            if (isConnected && state != BluetoothProfile.STATE_CONNECTED) {
46310a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood                makeA2dpSrcUnavailable(address);
46320a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood            } else if (!isConnected && state == BluetoothProfile.STATE_CONNECTED) {
46330a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood                makeA2dpSrcAvailable(address);
46340a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood            }
46350a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood        }
46360a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood    }
46370a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood
46385a0cf7a27f3953a1266af48543ccd9024f4cd89fJohn Du    public void avrcpSupportsAbsoluteVolume(String address, boolean support) {
46395a0cf7a27f3953a1266af48543ccd9024f4cd89fJohn Du        // address is not used for now, but may be used when multiple a2dp devices are supported
46405a0cf7a27f3953a1266af48543ccd9024f4cd89fJohn Du        synchronized (mA2dpAvrcpLock) {
46415a0cf7a27f3953a1266af48543ccd9024f4cd89fJohn Du            mAvrcpAbsVolSupported = support;
4642c9d1d5f35091226e96fcfa91817480f589eb36e2Matthew Xie            sendMsg(mAudioHandler, MSG_SET_DEVICE_VOLUME, SENDMSG_QUEUE,
4643cd772d04345850e160a45613fcf6b86da0dce4cfEric Laurent                    AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, 0,
4644cd772d04345850e160a45613fcf6b86da0dce4cfEric Laurent                    mStreamStates[AudioSystem.STREAM_MUSIC], 0);
4645cd772d04345850e160a45613fcf6b86da0dce4cfEric Laurent            sendMsg(mAudioHandler, MSG_SET_DEVICE_VOLUME, SENDMSG_QUEUE,
4646cd772d04345850e160a45613fcf6b86da0dce4cfEric Laurent                    AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, 0,
4647cd772d04345850e160a45613fcf6b86da0dce4cfEric Laurent                    mStreamStates[AudioSystem.STREAM_RING], 0);
46485a0cf7a27f3953a1266af48543ccd9024f4cd89fJohn Du        }
46495a0cf7a27f3953a1266af48543ccd9024f4cd89fJohn Du    }
46505a0cf7a27f3953a1266af48543ccd9024f4cd89fJohn Du
465159f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent    private boolean handleDeviceConnection(boolean connected, int device, String params) {
465259f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent        synchronized (mConnectedDevices) {
465359f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent            boolean isConnected = (mConnectedDevices.containsKey(device) &&
46549841818b9a0280abf59343c9e00a2976dbc084faMike Lockwood                    (params.isEmpty() || mConnectedDevices.get(device).equals(params)));
465559f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent
465659f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent            if (isConnected && !connected) {
465759f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent                AudioSystem.setDeviceConnectionState(device,
465859f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent                                              AudioSystem.DEVICE_STATE_UNAVAILABLE,
46599841818b9a0280abf59343c9e00a2976dbc084faMike Lockwood                                              mConnectedDevices.get(device));
466059f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent                 mConnectedDevices.remove(device);
466159f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent                 return true;
466259f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent            } else if (!isConnected && connected) {
466359f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent                 AudioSystem.setDeviceConnectionState(device,
466459f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent                                                      AudioSystem.DEVICE_STATE_AVAILABLE,
466559f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent                                                      params);
466659f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent                 mConnectedDevices.put(new Integer(device), params);
466759f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent                 return true;
466859f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent            }
466959f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent        }
467059f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent        return false;
467159f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent    }
467259f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent
4673b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent    // Devices which removal triggers intent ACTION_AUDIO_BECOMING_NOISY. The intent is only
4674b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent    // sent if none of these devices is connected.
4675b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent    int mBecomingNoisyIntentDevices =
4676b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent            AudioSystem.DEVICE_OUT_WIRED_HEADSET | AudioSystem.DEVICE_OUT_WIRED_HEADPHONE |
4677948d32748caaac5be06c991ebf00f74265a7849fEric Laurent            AudioSystem.DEVICE_OUT_ALL_A2DP | AudioSystem.DEVICE_OUT_HDMI |
4678794da7a0543cbecffefb73794aa68d1a93e41adfEric Laurent            AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET | AudioSystem.DEVICE_OUT_DGTL_DOCK_HEADSET |
467943cc8bbbbd5e6418cdfa0fa4b26c9f5c3a28c029Jon Eklund            AudioSystem.DEVICE_OUT_ALL_USB | AudioSystem.DEVICE_OUT_LINE;
4680b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent
4681b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent    // must be called before removing the device from mConnectedDevices
4682b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent    private int checkSendBecomingNoisyIntent(int device, int state) {
4683b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent        int delay = 0;
4684b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent        if ((state == 0) && ((device & mBecomingNoisyIntentDevices) != 0)) {
4685b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent            int devices = 0;
4686b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent            for (int dev : mConnectedDevices.keySet()) {
468727c30e4426302581a266c89d0ef880b340d7b061Eric Laurent                if (((dev & AudioSystem.DEVICE_BIT_IN) == 0) &&
468827c30e4426302581a266c89d0ef880b340d7b061Eric Laurent                        ((dev & mBecomingNoisyIntentDevices) != 0)) {
4689b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent                   devices |= dev;
4690b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent                }
4691b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent            }
4692b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent            if (devices == device) {
46935bfaeaef3fc348d66f48b86be08655e91dff910aEric Laurent                sendMsg(mAudioHandler,
46945bfaeaef3fc348d66f48b86be08655e91dff910aEric Laurent                        MSG_BROADCAST_AUDIO_BECOMING_NOISY,
46955bfaeaef3fc348d66f48b86be08655e91dff910aEric Laurent                        SENDMSG_REPLACE,
46965bfaeaef3fc348d66f48b86be08655e91dff910aEric Laurent                        0,
46975bfaeaef3fc348d66f48b86be08655e91dff910aEric Laurent                        0,
46985bfaeaef3fc348d66f48b86be08655e91dff910aEric Laurent                        null,
46995bfaeaef3fc348d66f48b86be08655e91dff910aEric Laurent                        0);
4700b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent                delay = 1000;
4701b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent            }
4702b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent        }
4703b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent
47040a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood        if (mAudioHandler.hasMessages(MSG_SET_A2DP_SRC_CONNECTION_STATE) ||
47050a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood                mAudioHandler.hasMessages(MSG_SET_A2DP_SINK_CONNECTION_STATE) ||
4706b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent                mAudioHandler.hasMessages(MSG_SET_WIRED_DEVICE_CONNECTION_STATE)) {
4707adbe8bf85f3c8230d16ae5cb3f5d9736e09ed84aEric Laurent            synchronized (mLastDeviceConnectMsgTime) {
4708adbe8bf85f3c8230d16ae5cb3f5d9736e09ed84aEric Laurent                long time = SystemClock.uptimeMillis();
4709adbe8bf85f3c8230d16ae5cb3f5d9736e09ed84aEric Laurent                if (mLastDeviceConnectMsgTime > time) {
4710adbe8bf85f3c8230d16ae5cb3f5d9736e09ed84aEric Laurent                    delay = (int)(mLastDeviceConnectMsgTime - time);
4711adbe8bf85f3c8230d16ae5cb3f5d9736e09ed84aEric Laurent                }
4712adbe8bf85f3c8230d16ae5cb3f5d9736e09ed84aEric Laurent            }
4713b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent        }
4714b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent        return delay;
4715b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent    }
4716b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent
4717b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent    private void sendDeviceConnectionIntent(int device, int state, String name)
4718b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent    {
4719b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent        Intent intent = new Intent();
4720b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent
4721b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent        intent.putExtra("state", state);
4722b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent        intent.putExtra("name", name);
4723b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent        intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
4724b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent
4725632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn        int connType = 0;
4726632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn
4727b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent        if (device == AudioSystem.DEVICE_OUT_WIRED_HEADSET) {
4728632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn            connType = AudioRoutesInfo.MAIN_HEADSET;
4729b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent            intent.setAction(Intent.ACTION_HEADSET_PLUG);
4730b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent            intent.putExtra("microphone", 1);
473143cc8bbbbd5e6418cdfa0fa4b26c9f5c3a28c029Jon Eklund        } else if (device == AudioSystem.DEVICE_OUT_WIRED_HEADPHONE ||
473243cc8bbbbd5e6418cdfa0fa4b26c9f5c3a28c029Jon Eklund                   device == AudioSystem.DEVICE_OUT_LINE) {
473343cc8bbbbd5e6418cdfa0fa4b26c9f5c3a28c029Jon Eklund            /*do apps care about line-out vs headphones?*/
4734632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn            connType = AudioRoutesInfo.MAIN_HEADPHONES;
4735b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent            intent.setAction(Intent.ACTION_HEADSET_PLUG);
4736b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent            intent.putExtra("microphone", 0);
4737b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent        } else if (device == AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET) {
4738632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn            connType = AudioRoutesInfo.MAIN_DOCK_SPEAKERS;
4739c5258433dd353769ccfa2e5e769a7379378a3a0bJean-Michel Trivi            intent.setAction(AudioManager.ACTION_ANALOG_AUDIO_DOCK_PLUG);
4740b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent        } else if (device == AudioSystem.DEVICE_OUT_DGTL_DOCK_HEADSET) {
4741632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn            connType = AudioRoutesInfo.MAIN_DOCK_SPEAKERS;
4742c5258433dd353769ccfa2e5e769a7379378a3a0bJean-Michel Trivi            intent.setAction(AudioManager.ACTION_DIGITAL_AUDIO_DOCK_PLUG);
47436fa4245589c93025d91aab7dc6681babdd91ee41Eric Laurent        } else if (device == AudioSystem.DEVICE_OUT_HDMI ||
47446fa4245589c93025d91aab7dc6681babdd91ee41Eric Laurent                device == AudioSystem.DEVICE_OUT_HDMI_ARC) {
4745632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn            connType = AudioRoutesInfo.MAIN_HDMI;
474637d7804627eecaf04e170793c2f5703d5d6d44e8Jean-Michel Trivi            configureHdmiPlugIntent(intent, state);
4747b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent        }
4748b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent
4749632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn        synchronized (mCurAudioRoutes) {
4750632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn            if (connType != 0) {
4751632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                int newConn = mCurAudioRoutes.mMainType;
4752632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                if (state != 0) {
4753632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                    newConn |= connType;
4754632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                } else {
4755632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                    newConn &= ~connType;
4756632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                }
4757632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                if (newConn != mCurAudioRoutes.mMainType) {
4758632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                    mCurAudioRoutes.mMainType = newConn;
4759632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                    sendMsg(mAudioHandler, MSG_REPORT_NEW_ROUTES,
4760632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                            SENDMSG_NOOP, 0, 0, null, 0);
4761632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                }
4762632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn            }
4763632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn        }
4764632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn
47655ac72a29593ab9a20337a2225df52bdf4754be02Dianne Hackborn        final long ident = Binder.clearCallingIdentity();
47665ac72a29593ab9a20337a2225df52bdf4754be02Dianne Hackborn        try {
47675ac72a29593ab9a20337a2225df52bdf4754be02Dianne Hackborn            ActivityManagerNative.broadcastStickyIntent(intent, null, UserHandle.USER_ALL);
47685ac72a29593ab9a20337a2225df52bdf4754be02Dianne Hackborn        } finally {
47695ac72a29593ab9a20337a2225df52bdf4754be02Dianne Hackborn            Binder.restoreCallingIdentity(ident);
47705ac72a29593ab9a20337a2225df52bdf4754be02Dianne Hackborn        }
4771b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent    }
4772b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent
4773b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent    private void onSetWiredDeviceConnectionState(int device, int state, String name)
4774b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent    {
4775b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent        synchronized (mConnectedDevices) {
4776b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent            if ((state == 0) && ((device == AudioSystem.DEVICE_OUT_WIRED_HEADSET) ||
477743cc8bbbbd5e6418cdfa0fa4b26c9f5c3a28c029Jon Eklund                    (device == AudioSystem.DEVICE_OUT_WIRED_HEADPHONE) ||
477843cc8bbbbd5e6418cdfa0fa4b26c9f5c3a28c029Jon Eklund                    (device == AudioSystem.DEVICE_OUT_LINE))) {
4779b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent                setBluetoothA2dpOnInt(true);
4780b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent            }
4781ae4506e9b5fc3e0c6d9862fbc05b9af7d6742a6eEric Laurent            boolean isUsb = ((device & ~AudioSystem.DEVICE_OUT_ALL_USB) == 0) ||
4782ae4506e9b5fc3e0c6d9862fbc05b9af7d6742a6eEric Laurent                            (((device & AudioSystem.DEVICE_BIT_IN) != 0) &&
4783ae4506e9b5fc3e0c6d9862fbc05b9af7d6742a6eEric Laurent                             ((device & ~AudioSystem.DEVICE_IN_ALL_USB) == 0));
4784db45484e4b5858d14da93d3a06311b93bf0cf320Mike Lockwood            handleDeviceConnection((state == 1), device, (isUsb ? name : ""));
4785f1a457d06c53a901ea08d2d3fb6e766bc06c4d4fEric Laurent            if (state != 0) {
4786f1a457d06c53a901ea08d2d3fb6e766bc06c4d4fEric Laurent                if ((device == AudioSystem.DEVICE_OUT_WIRED_HEADSET) ||
478743cc8bbbbd5e6418cdfa0fa4b26c9f5c3a28c029Jon Eklund                    (device == AudioSystem.DEVICE_OUT_WIRED_HEADPHONE) ||
478843cc8bbbbd5e6418cdfa0fa4b26c9f5c3a28c029Jon Eklund                    (device == AudioSystem.DEVICE_OUT_LINE)) {
4789f1a457d06c53a901ea08d2d3fb6e766bc06c4d4fEric Laurent                    setBluetoothA2dpOnInt(false);
4790f1a457d06c53a901ea08d2d3fb6e766bc06c4d4fEric Laurent                }
4791f1a457d06c53a901ea08d2d3fb6e766bc06c4d4fEric Laurent                if ((device & mSafeMediaVolumeDevices) != 0) {
4792f1a457d06c53a901ea08d2d3fb6e766bc06c4d4fEric Laurent                    sendMsg(mAudioHandler,
4793f1a457d06c53a901ea08d2d3fb6e766bc06c4d4fEric Laurent                            MSG_CHECK_MUSIC_ACTIVE,
4794f1a457d06c53a901ea08d2d3fb6e766bc06c4d4fEric Laurent                            SENDMSG_REPLACE,
4795f1a457d06c53a901ea08d2d3fb6e766bc06c4d4fEric Laurent                            0,
4796f1a457d06c53a901ea08d2d3fb6e766bc06c4d4fEric Laurent                            0,
4797f1a457d06c53a901ea08d2d3fb6e766bc06c4d4fEric Laurent                            null,
4798f1a457d06c53a901ea08d2d3fb6e766bc06c4d4fEric Laurent                            MUSIC_ACTIVE_POLL_PERIOD_MS);
4799f1a457d06c53a901ea08d2d3fb6e766bc06c4d4fEric Laurent                }
4800212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent                // Television devices without CEC service apply software volume on HDMI output
4801212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent                if (isPlatformTelevision() && ((device & AudioSystem.DEVICE_OUT_HDMI) != 0)) {
4802212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent                    mFixedVolumeDevices |= AudioSystem.DEVICE_OUT_HDMI;
4803212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent                    checkAllFixedVolumeDevices();
4804212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent                    if (mHdmiManager != null) {
4805212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent                        synchronized (mHdmiManager) {
4806212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent                            if (mHdmiPlaybackClient != null) {
4807212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent                                mHdmiCecSink = false;
4808212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent                                mHdmiPlaybackClient.queryDisplayStatus(mHdmiDisplayStatusCallback);
4809212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent                            }
4810212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent                        }
4811212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent                    }
4812212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent                }
4813212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent            } else {
4814212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent                if (isPlatformTelevision() && ((device & AudioSystem.DEVICE_OUT_HDMI) != 0)) {
4815212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent                    if (mHdmiManager != null) {
4816212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent                        synchronized (mHdmiManager) {
4817212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent                            mHdmiCecSink = false;
4818212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent                        }
4819212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent                    }
4820212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent                }
4821b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent            }
4822ae4506e9b5fc3e0c6d9862fbc05b9af7d6742a6eEric Laurent            if (!isUsb && (device != AudioSystem.DEVICE_IN_WIRED_HEADSET)) {
4823db45484e4b5858d14da93d3a06311b93bf0cf320Mike Lockwood                sendDeviceConnectionIntent(device, state, name);
4824db45484e4b5858d14da93d3a06311b93bf0cf320Mike Lockwood            }
4825b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent        }
4826b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent    }
4827b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent
482837d7804627eecaf04e170793c2f5703d5d6d44e8Jean-Michel Trivi    private void configureHdmiPlugIntent(Intent intent, int state) {
4829c5258433dd353769ccfa2e5e769a7379378a3a0bJean-Michel Trivi        intent.setAction(AudioManager.ACTION_HDMI_AUDIO_PLUG);
4830c5258433dd353769ccfa2e5e769a7379378a3a0bJean-Michel Trivi        intent.putExtra(AudioManager.EXTRA_AUDIO_PLUG_STATE, state);
483137d7804627eecaf04e170793c2f5703d5d6d44e8Jean-Michel Trivi        if (state == 1) {
483237d7804627eecaf04e170793c2f5703d5d6d44e8Jean-Michel Trivi            ArrayList<AudioPort> ports = new ArrayList<AudioPort>();
483337d7804627eecaf04e170793c2f5703d5d6d44e8Jean-Michel Trivi            int[] portGeneration = new int[1];
483437d7804627eecaf04e170793c2f5703d5d6d44e8Jean-Michel Trivi            int status = AudioSystem.listAudioPorts(ports, portGeneration);
483537d7804627eecaf04e170793c2f5703d5d6d44e8Jean-Michel Trivi            if (status == AudioManager.SUCCESS) {
483637d7804627eecaf04e170793c2f5703d5d6d44e8Jean-Michel Trivi                for (AudioPort port : ports) {
483737d7804627eecaf04e170793c2f5703d5d6d44e8Jean-Michel Trivi                    if (port instanceof AudioDevicePort) {
483837d7804627eecaf04e170793c2f5703d5d6d44e8Jean-Michel Trivi                        final AudioDevicePort devicePort = (AudioDevicePort) port;
48396fa4245589c93025d91aab7dc6681babdd91ee41Eric Laurent                        if (devicePort.type() == AudioManager.DEVICE_OUT_HDMI ||
48406fa4245589c93025d91aab7dc6681babdd91ee41Eric Laurent                                devicePort.type() == AudioManager.DEVICE_OUT_HDMI_ARC) {
484137d7804627eecaf04e170793c2f5703d5d6d44e8Jean-Michel Trivi                            // format the list of supported encodings
484237d7804627eecaf04e170793c2f5703d5d6d44e8Jean-Michel Trivi                            int[] formats = devicePort.formats();
484337d7804627eecaf04e170793c2f5703d5d6d44e8Jean-Michel Trivi                            if (formats.length > 0) {
484437d7804627eecaf04e170793c2f5703d5d6d44e8Jean-Michel Trivi                                ArrayList<Integer> encodingList = new ArrayList(1);
484537d7804627eecaf04e170793c2f5703d5d6d44e8Jean-Michel Trivi                                for (int format : formats) {
484637d7804627eecaf04e170793c2f5703d5d6d44e8Jean-Michel Trivi                                    // a format in the list can be 0, skip it
484737d7804627eecaf04e170793c2f5703d5d6d44e8Jean-Michel Trivi                                    if (format != AudioFormat.ENCODING_INVALID) {
484837d7804627eecaf04e170793c2f5703d5d6d44e8Jean-Michel Trivi                                        encodingList.add(format);
484937d7804627eecaf04e170793c2f5703d5d6d44e8Jean-Michel Trivi                                    }
485037d7804627eecaf04e170793c2f5703d5d6d44e8Jean-Michel Trivi                                }
485137d7804627eecaf04e170793c2f5703d5d6d44e8Jean-Michel Trivi                                int[] encodingArray = new int[encodingList.size()];
485237d7804627eecaf04e170793c2f5703d5d6d44e8Jean-Michel Trivi                                for (int i = 0 ; i < encodingArray.length ; i++) {
485337d7804627eecaf04e170793c2f5703d5d6d44e8Jean-Michel Trivi                                    encodingArray[i] = encodingList.get(i);
485437d7804627eecaf04e170793c2f5703d5d6d44e8Jean-Michel Trivi                                }
4855c5258433dd353769ccfa2e5e769a7379378a3a0bJean-Michel Trivi                                intent.putExtra(AudioManager.EXTRA_ENCODINGS, encodingArray);
485637d7804627eecaf04e170793c2f5703d5d6d44e8Jean-Michel Trivi                            }
485737d7804627eecaf04e170793c2f5703d5d6d44e8Jean-Michel Trivi                            // find the maximum supported number of channels
485837d7804627eecaf04e170793c2f5703d5d6d44e8Jean-Michel Trivi                            int maxChannels = 0;
485937d7804627eecaf04e170793c2f5703d5d6d44e8Jean-Michel Trivi                            for (int mask : devicePort.channelMasks()) {
486037d7804627eecaf04e170793c2f5703d5d6d44e8Jean-Michel Trivi                                int channelCount = AudioFormat.channelCountFromOutChannelMask(mask);
486137d7804627eecaf04e170793c2f5703d5d6d44e8Jean-Michel Trivi                                if (channelCount > maxChannels) {
486237d7804627eecaf04e170793c2f5703d5d6d44e8Jean-Michel Trivi                                    maxChannels = channelCount;
486337d7804627eecaf04e170793c2f5703d5d6d44e8Jean-Michel Trivi                                }
486437d7804627eecaf04e170793c2f5703d5d6d44e8Jean-Michel Trivi                            }
4865c5258433dd353769ccfa2e5e769a7379378a3a0bJean-Michel Trivi                            intent.putExtra(AudioManager.EXTRA_MAX_CHANNEL_COUNT, maxChannels);
486637d7804627eecaf04e170793c2f5703d5d6d44e8Jean-Michel Trivi                        }
486737d7804627eecaf04e170793c2f5703d5d6d44e8Jean-Michel Trivi                    }
486837d7804627eecaf04e170793c2f5703d5d6d44e8Jean-Michel Trivi                }
486937d7804627eecaf04e170793c2f5703d5d6d44e8Jean-Michel Trivi            }
487037d7804627eecaf04e170793c2f5703d5d6d44e8Jean-Michel Trivi        }
487137d7804627eecaf04e170793c2f5703d5d6d44e8Jean-Michel Trivi    }
487237d7804627eecaf04e170793c2f5703d5d6d44e8Jean-Michel Trivi
4873a847ba4080675d395de725cfac5dfd9d5a993d4eJean-Michel Trivi    /* cache of the address of the last dock the device was connected to */
4874a847ba4080675d395de725cfac5dfd9d5a993d4eJean-Michel Trivi    private String mDockAddress;
4875a847ba4080675d395de725cfac5dfd9d5a993d4eJean-Michel Trivi
4876a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent    /**
4877a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent     * Receiver for misc intent broadcasts the Phone app cares about.
4878a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent     */
4879a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent    private class AudioServiceBroadcastReceiver extends BroadcastReceiver {
4880a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent        @Override
4881a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent        public void onReceive(Context context, Intent intent) {
4882a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent            String action = intent.getAction();
4883ae4506e9b5fc3e0c6d9862fbc05b9af7d6742a6eEric Laurent            int outDevice;
4884ae4506e9b5fc3e0c6d9862fbc05b9af7d6742a6eEric Laurent            int inDevice;
488559f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent            int state;
4886a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent
4887758559e6b7e310cf46cc269437f44decd58d68d6Jean-Michel Trivi            if (action.equals(Intent.ACTION_DOCK_EVENT)) {
4888758559e6b7e310cf46cc269437f44decd58d68d6Jean-Michel Trivi                int dockState = intent.getIntExtra(Intent.EXTRA_DOCK_STATE,
4889758559e6b7e310cf46cc269437f44decd58d68d6Jean-Michel Trivi                        Intent.EXTRA_DOCK_STATE_UNDOCKED);
4890758559e6b7e310cf46cc269437f44decd58d68d6Jean-Michel Trivi                int config;
4891758559e6b7e310cf46cc269437f44decd58d68d6Jean-Michel Trivi                switch (dockState) {
4892758559e6b7e310cf46cc269437f44decd58d68d6Jean-Michel Trivi                    case Intent.EXTRA_DOCK_STATE_DESK:
4893758559e6b7e310cf46cc269437f44decd58d68d6Jean-Michel Trivi                        config = AudioSystem.FORCE_BT_DESK_DOCK;
4894758559e6b7e310cf46cc269437f44decd58d68d6Jean-Michel Trivi                        break;
4895758559e6b7e310cf46cc269437f44decd58d68d6Jean-Michel Trivi                    case Intent.EXTRA_DOCK_STATE_CAR:
4896758559e6b7e310cf46cc269437f44decd58d68d6Jean-Michel Trivi                        config = AudioSystem.FORCE_BT_CAR_DOCK;
4897758559e6b7e310cf46cc269437f44decd58d68d6Jean-Michel Trivi                        break;
489821e941bf43362ddc6639a9f2d0828053360f53d7Praveen Bharathi                    case Intent.EXTRA_DOCK_STATE_LE_DESK:
489908ed1b9d2099ec8231b21353b33b901492ea9885Eric Laurent                        config = AudioSystem.FORCE_ANALOG_DOCK;
490021e941bf43362ddc6639a9f2d0828053360f53d7Praveen Bharathi                        break;
490121e941bf43362ddc6639a9f2d0828053360f53d7Praveen Bharathi                    case Intent.EXTRA_DOCK_STATE_HE_DESK:
490221e941bf43362ddc6639a9f2d0828053360f53d7Praveen Bharathi                        config = AudioSystem.FORCE_DIGITAL_DOCK;
490321e941bf43362ddc6639a9f2d0828053360f53d7Praveen Bharathi                        break;
4904758559e6b7e310cf46cc269437f44decd58d68d6Jean-Michel Trivi                    case Intent.EXTRA_DOCK_STATE_UNDOCKED:
4905758559e6b7e310cf46cc269437f44decd58d68d6Jean-Michel Trivi                    default:
4906758559e6b7e310cf46cc269437f44decd58d68d6Jean-Michel Trivi                        config = AudioSystem.FORCE_NONE;
4907758559e6b7e310cf46cc269437f44decd58d68d6Jean-Michel Trivi                }
490808ed1b9d2099ec8231b21353b33b901492ea9885Eric Laurent                // Low end docks have a menu to enable or disable audio
490908ed1b9d2099ec8231b21353b33b901492ea9885Eric Laurent                // (see mDockAudioMediaEnabled)
491008ed1b9d2099ec8231b21353b33b901492ea9885Eric Laurent                if (!((dockState == Intent.EXTRA_DOCK_STATE_LE_DESK) ||
491108ed1b9d2099ec8231b21353b33b901492ea9885Eric Laurent                      ((dockState == Intent.EXTRA_DOCK_STATE_UNDOCKED) &&
491208ed1b9d2099ec8231b21353b33b901492ea9885Eric Laurent                       (mDockState == Intent.EXTRA_DOCK_STATE_LE_DESK)))) {
491308ed1b9d2099ec8231b21353b33b901492ea9885Eric Laurent                    AudioSystem.setForceUse(AudioSystem.FOR_DOCK, config);
491408ed1b9d2099ec8231b21353b33b901492ea9885Eric Laurent                }
491508ed1b9d2099ec8231b21353b33b901492ea9885Eric Laurent                mDockState = dockState;
491682aa7f017daaaeb96c13e6e3491d5037ab471085Jaikumar Ganesh            } else if (action.equals(BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED)) {
491759f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent                state = intent.getIntExtra(BluetoothProfile.EXTRA_STATE,
491882aa7f017daaaeb96c13e6e3491d5037ab471085Jaikumar Ganesh                                               BluetoothProfile.STATE_DISCONNECTED);
4919ae4506e9b5fc3e0c6d9862fbc05b9af7d6742a6eEric Laurent                outDevice = AudioSystem.DEVICE_OUT_BLUETOOTH_SCO;
4920ae4506e9b5fc3e0c6d9862fbc05b9af7d6742a6eEric Laurent                inDevice = AudioSystem.DEVICE_IN_BLUETOOTH_SCO_HEADSET;
4921a56d1c72190462aa9e377906583eceb58e0efcddNick Pelly                String address = null;
4922dca56b9432e2cc851d1a58920071fed2e1e3d142Eric Laurent
4923dca56b9432e2cc851d1a58920071fed2e1e3d142Eric Laurent                BluetoothDevice btDevice = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
4924dca56b9432e2cc851d1a58920071fed2e1e3d142Eric Laurent                if (btDevice == null) {
4925dca56b9432e2cc851d1a58920071fed2e1e3d142Eric Laurent                    return;
4926dca56b9432e2cc851d1a58920071fed2e1e3d142Eric Laurent                }
4927dca56b9432e2cc851d1a58920071fed2e1e3d142Eric Laurent
4928dca56b9432e2cc851d1a58920071fed2e1e3d142Eric Laurent                address = btDevice.getAddress();
4929dca56b9432e2cc851d1a58920071fed2e1e3d142Eric Laurent                BluetoothClass btClass = btDevice.getBluetoothClass();
4930dca56b9432e2cc851d1a58920071fed2e1e3d142Eric Laurent                if (btClass != null) {
4931dca56b9432e2cc851d1a58920071fed2e1e3d142Eric Laurent                    switch (btClass.getDeviceClass()) {
4932dca56b9432e2cc851d1a58920071fed2e1e3d142Eric Laurent                    case BluetoothClass.Device.AUDIO_VIDEO_WEARABLE_HEADSET:
4933dca56b9432e2cc851d1a58920071fed2e1e3d142Eric Laurent                    case BluetoothClass.Device.AUDIO_VIDEO_HANDSFREE:
4934ae4506e9b5fc3e0c6d9862fbc05b9af7d6742a6eEric Laurent                        outDevice = AudioSystem.DEVICE_OUT_BLUETOOTH_SCO_HEADSET;
4935dca56b9432e2cc851d1a58920071fed2e1e3d142Eric Laurent                        break;
4936dca56b9432e2cc851d1a58920071fed2e1e3d142Eric Laurent                    case BluetoothClass.Device.AUDIO_VIDEO_CAR_AUDIO:
4937ae4506e9b5fc3e0c6d9862fbc05b9af7d6742a6eEric Laurent                        outDevice = AudioSystem.DEVICE_OUT_BLUETOOTH_SCO_CARKIT;
4938dca56b9432e2cc851d1a58920071fed2e1e3d142Eric Laurent                        break;
4939d5603c126acdd94d9f7400bb1d04188020a425b4Eric Laurent                    }
4940d5603c126acdd94d9f7400bb1d04188020a425b4Eric Laurent                }
4941d5603c126acdd94d9f7400bb1d04188020a425b4Eric Laurent
4942dca56b9432e2cc851d1a58920071fed2e1e3d142Eric Laurent                if (!BluetoothAdapter.checkBluetoothAddress(address)) {
4943dca56b9432e2cc851d1a58920071fed2e1e3d142Eric Laurent                    address = "";
4944dca56b9432e2cc851d1a58920071fed2e1e3d142Eric Laurent                }
4945d5603c126acdd94d9f7400bb1d04188020a425b4Eric Laurent
494659f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent                boolean connected = (state == BluetoothProfile.STATE_CONNECTED);
4947ae4506e9b5fc3e0c6d9862fbc05b9af7d6742a6eEric Laurent                boolean success = handleDeviceConnection(connected, outDevice, address) &&
4948ae4506e9b5fc3e0c6d9862fbc05b9af7d6742a6eEric Laurent                                      handleDeviceConnection(connected, inDevice, address);
4949ae4506e9b5fc3e0c6d9862fbc05b9af7d6742a6eEric Laurent                if (success) {
49506bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                    synchronized (mScoClients) {
495159f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent                        if (connected) {
495259f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent                            mBluetoothHeadsetDevice = btDevice;
495359f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent                        } else {
49546bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                            mBluetoothHeadsetDevice = null;
49556bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                            resetBluetoothSco();
49566bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                        }
495762ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent                    }
4958a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent                }
4959c5258433dd353769ccfa2e5e769a7379378a3a0bJean-Michel Trivi            } else if (action.equals(AudioManager.ACTION_USB_AUDIO_ACCESSORY_PLUG)) {
4960df3614693dd4fe52a116dcd28bd74eae80818a4fPaul McLean                state = intent.getIntExtra("state", 0);
4961df3614693dd4fe52a116dcd28bd74eae80818a4fPaul McLean
4962df3614693dd4fe52a116dcd28bd74eae80818a4fPaul McLean                int alsaCard = intent.getIntExtra("card", -1);
4963df3614693dd4fe52a116dcd28bd74eae80818a4fPaul McLean                int alsaDevice = intent.getIntExtra("device", -1);
4964df3614693dd4fe52a116dcd28bd74eae80818a4fPaul McLean
4965df3614693dd4fe52a116dcd28bd74eae80818a4fPaul McLean                String params = (alsaCard == -1 && alsaDevice == -1 ? ""
4966df3614693dd4fe52a116dcd28bd74eae80818a4fPaul McLean                                    : "card=" + alsaCard + ";device=" + alsaDevice);
4967df3614693dd4fe52a116dcd28bd74eae80818a4fPaul McLean
4968df3614693dd4fe52a116dcd28bd74eae80818a4fPaul McLean                // Playback Device
4969ae4506e9b5fc3e0c6d9862fbc05b9af7d6742a6eEric Laurent                outDevice = AudioSystem.DEVICE_OUT_USB_ACCESSORY;
4970ae4506e9b5fc3e0c6d9862fbc05b9af7d6742a6eEric Laurent                setWiredDeviceConnectionState(outDevice, state, params);
4971c5258433dd353769ccfa2e5e769a7379378a3a0bJean-Michel Trivi            } else if (action.equals(AudioManager.ACTION_USB_AUDIO_DEVICE_PLUG)) {
49725f5163548424ed3a4d7ea259848f82fb74aaf75dGlenn Kasten                // FIXME Does not yet handle the case where the setting is changed
49735f5163548424ed3a4d7ea259848f82fb74aaf75dGlenn Kasten                // after device connection.  Ideally we should handle the settings change
49745f5163548424ed3a4d7ea259848f82fb74aaf75dGlenn Kasten                // in SettingsObserver. Here we should log that a USB device is connected
49755f5163548424ed3a4d7ea259848f82fb74aaf75dGlenn Kasten                // and disconnected with its address (card , device) and force the
49765f5163548424ed3a4d7ea259848f82fb74aaf75dGlenn Kasten                // connection or disconnection when the setting changes.
497734cc4db180c20569e62db5860c0b206be65b5117Glenn Kasten                int isDisabled = Settings.Secure.getInt(mContentResolver,
497834cc4db180c20569e62db5860c0b206be65b5117Glenn Kasten                        Settings.Secure.USB_AUDIO_AUTOMATIC_ROUTING_DISABLED, 0);
49795f5163548424ed3a4d7ea259848f82fb74aaf75dGlenn Kasten                if (isDisabled != 0) {
49805f5163548424ed3a4d7ea259848f82fb74aaf75dGlenn Kasten                    return;
49815f5163548424ed3a4d7ea259848f82fb74aaf75dGlenn Kasten                }
49825f5163548424ed3a4d7ea259848f82fb74aaf75dGlenn Kasten
498359f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent                state = intent.getIntExtra("state", 0);
4984c837a451946b64d70ed7c642fbde03c182c28b6fPaul McLean
498559f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent                int alsaCard = intent.getIntExtra("card", -1);
498659f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent                int alsaDevice = intent.getIntExtra("device", -1);
4987c837a451946b64d70ed7c642fbde03c182c28b6fPaul McLean                boolean hasPlayback = intent.getBooleanExtra("hasPlayback", false);
4988c837a451946b64d70ed7c642fbde03c182c28b6fPaul McLean                boolean hasCapture = intent.getBooleanExtra("hasCapture", false);
4989c837a451946b64d70ed7c642fbde03c182c28b6fPaul McLean                boolean hasMIDI = intent.getBooleanExtra("hasMIDI", false);
4990c837a451946b64d70ed7c642fbde03c182c28b6fPaul McLean
49919841818b9a0280abf59343c9e00a2976dbc084faMike Lockwood                String params = (alsaCard == -1 && alsaDevice == -1 ? ""
49929841818b9a0280abf59343c9e00a2976dbc084faMike Lockwood                                    : "card=" + alsaCard + ";device=" + alsaDevice);
4993c837a451946b64d70ed7c642fbde03c182c28b6fPaul McLean
4994c837a451946b64d70ed7c642fbde03c182c28b6fPaul McLean                // Playback Device
4995df3614693dd4fe52a116dcd28bd74eae80818a4fPaul McLean                if (hasPlayback) {
4996ae4506e9b5fc3e0c6d9862fbc05b9af7d6742a6eEric Laurent                    outDevice = AudioSystem.DEVICE_OUT_USB_DEVICE;
4997ae4506e9b5fc3e0c6d9862fbc05b9af7d6742a6eEric Laurent                    setWiredDeviceConnectionState(outDevice, state, params);
4998df3614693dd4fe52a116dcd28bd74eae80818a4fPaul McLean                }
4999c837a451946b64d70ed7c642fbde03c182c28b6fPaul McLean
5000c837a451946b64d70ed7c642fbde03c182c28b6fPaul McLean                // Capture Device
5001df3614693dd4fe52a116dcd28bd74eae80818a4fPaul McLean                if (hasCapture) {
5002ae4506e9b5fc3e0c6d9862fbc05b9af7d6742a6eEric Laurent                    inDevice = AudioSystem.DEVICE_IN_USB_DEVICE;
5003ae4506e9b5fc3e0c6d9862fbc05b9af7d6742a6eEric Laurent                    setWiredDeviceConnectionState(inDevice, state, params);
5004df3614693dd4fe52a116dcd28bd74eae80818a4fPaul McLean                }
5005df3614693dd4fe52a116dcd28bd74eae80818a4fPaul McLean            } else if (action.equals(BluetoothHeadset.ACTION_AUDIO_STATE_CHANGED)) {
500662ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent                boolean broadcast = false;
500759f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent                int scoAudioState = AudioManager.SCO_AUDIO_STATE_ERROR;
50083def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                synchronized (mScoClients) {
500962ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent                    int btState = intent.getIntExtra(BluetoothProfile.EXTRA_STATE, -1);
5010dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                    // broadcast intent if the connection was initated by AudioService
5011dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                    if (!mScoClients.isEmpty() &&
5012dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                            (mScoAudioState == SCO_STATE_ACTIVE_INTERNAL ||
5013dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                             mScoAudioState == SCO_STATE_ACTIVATE_REQ ||
5014dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                             mScoAudioState == SCO_STATE_DEACTIVATE_REQ)) {
501562ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent                        broadcast = true;
501662ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent                    }
501762ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent                    switch (btState) {
501862ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent                    case BluetoothHeadset.STATE_AUDIO_CONNECTED:
501959f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent                        scoAudioState = AudioManager.SCO_AUDIO_STATE_CONNECTED;
5020dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                        if (mScoAudioState != SCO_STATE_ACTIVE_INTERNAL &&
5021dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                            mScoAudioState != SCO_STATE_DEACTIVATE_REQ &&
5022dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                            mScoAudioState != SCO_STATE_DEACTIVATE_EXT_REQ) {
502362ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent                            mScoAudioState = SCO_STATE_ACTIVE_EXTERNAL;
50243def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                        }
502562ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent                        break;
502662ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent                    case BluetoothHeadset.STATE_AUDIO_DISCONNECTED:
502759f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent                        scoAudioState = AudioManager.SCO_AUDIO_STATE_DISCONNECTED;
502862ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent                        mScoAudioState = SCO_STATE_INACTIVE;
5029d7454be47f4111c0478a502353e11dea401378bdEric Laurent                        clearAllScoClients(0, false);
503062ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent                        break;
503162ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent                    case BluetoothHeadset.STATE_AUDIO_CONNECTING:
5032dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                        if (mScoAudioState != SCO_STATE_ACTIVE_INTERNAL &&
5033dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                            mScoAudioState != SCO_STATE_DEACTIVATE_REQ &&
5034dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                            mScoAudioState != SCO_STATE_DEACTIVATE_EXT_REQ) {
503562ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent                            mScoAudioState = SCO_STATE_ACTIVE_EXTERNAL;
50363def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                        }
503762ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent                    default:
503862ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent                        // do not broadcast CONNECTING or invalid state
503962ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent                        broadcast = false;
504062ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent                        break;
50413def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                    }
50423def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                }
504362ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent                if (broadcast) {
504459f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent                    broadcastScoConnectionState(scoAudioState);
5045dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                    //FIXME: this is to maintain compatibility with deprecated intent
5046dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                    // AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED. Remove when appropriate.
504762ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent                    Intent newIntent = new Intent(AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED);
504859f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent                    newIntent.putExtra(AudioManager.EXTRA_SCO_AUDIO_STATE, scoAudioState);
50495ac72a29593ab9a20337a2225df52bdf4754be02Dianne Hackborn                    sendStickyBroadcastToAll(newIntent);
505062ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent                }
5051950e8cb40a6d826af4cc2eef9d3908c1b70486e6Eric Laurent            } else if (action.equals(Intent.ACTION_SCREEN_ON)) {
5052318f0fe43bdc4b2f6764edd91d6b78d9875ffdebJon Eklund                if (mMonitorRotation) {
5053318f0fe43bdc4b2f6764edd91d6b78d9875ffdebJon Eklund                    mOrientationListener.onOrientationChanged(0); //argument is ignored anyway
5054318f0fe43bdc4b2f6764edd91d6b78d9875ffdebJon Eklund                    mOrientationListener.enable();
5055318f0fe43bdc4b2f6764edd91d6b78d9875ffdebJon Eklund                }
5056950e8cb40a6d826af4cc2eef9d3908c1b70486e6Eric Laurent                AudioSystem.setParameters("screen_state=on");
5057950e8cb40a6d826af4cc2eef9d3908c1b70486e6Eric Laurent            } else if (action.equals(Intent.ACTION_SCREEN_OFF)) {
5058318f0fe43bdc4b2f6764edd91d6b78d9875ffdebJon Eklund                if (mMonitorRotation) {
5059318f0fe43bdc4b2f6764edd91d6b78d9875ffdebJon Eklund                    //reduce wakeups (save current) by only listening when display is on
5060318f0fe43bdc4b2f6764edd91d6b78d9875ffdebJon Eklund                    mOrientationListener.disable();
5061318f0fe43bdc4b2f6764edd91d6b78d9875ffdebJon Eklund                }
5062950e8cb40a6d826af4cc2eef9d3908c1b70486e6Eric Laurent                AudioSystem.setParameters("screen_state=off");
5063961cae92540763226648813d111c5b5c3b0f1597Dianne Hackborn            } else if (action.equals(Intent.ACTION_CONFIGURATION_CHANGED)) {
5064f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi                handleConfigurationChanged(context);
5065bc0fab1fc2db832ef86d8a33466ec4d68b103ca0Eric Laurent            } else if (action.equals(Intent.ACTION_USER_SWITCHED)) {
5066f4a8eb22112c534f436357b50f231778c5c15c25Jean-Michel Trivi                // attempt to stop music playback for background user
50675bfaeaef3fc348d66f48b86be08655e91dff910aEric Laurent                sendMsg(mAudioHandler,
50685bfaeaef3fc348d66f48b86be08655e91dff910aEric Laurent                        MSG_BROADCAST_AUDIO_BECOMING_NOISY,
50695bfaeaef3fc348d66f48b86be08655e91dff910aEric Laurent                        SENDMSG_REPLACE,
50705bfaeaef3fc348d66f48b86be08655e91dff910aEric Laurent                        0,
50715bfaeaef3fc348d66f48b86be08655e91dff910aEric Laurent                        0,
50725bfaeaef3fc348d66f48b86be08655e91dff910aEric Laurent                        null,
50735bfaeaef3fc348d66f48b86be08655e91dff910aEric Laurent                        0);
5074f4a8eb22112c534f436357b50f231778c5c15c25Jean-Michel Trivi                // the current audio focus owner is no longer valid
5075fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                mMediaFocusControl.discardAudioFocusOwner();
5076f4a8eb22112c534f436357b50f231778c5c15c25Jean-Michel Trivi
50775bfaeaef3fc348d66f48b86be08655e91dff910aEric Laurent                // load volume settings for new user
5078bc0fab1fc2db832ef86d8a33466ec4d68b103ca0Eric Laurent                readAudioSettings(true /*userSwitch*/);
5079bc0fab1fc2db832ef86d8a33466ec4d68b103ca0Eric Laurent                // preserve STREAM_MUSIC volume from one user to the next.
5080bc0fab1fc2db832ef86d8a33466ec4d68b103ca0Eric Laurent                sendMsg(mAudioHandler,
5081bc0fab1fc2db832ef86d8a33466ec4d68b103ca0Eric Laurent                        MSG_SET_ALL_VOLUMES,
5082bc0fab1fc2db832ef86d8a33466ec4d68b103ca0Eric Laurent                        SENDMSG_QUEUE,
5083bc0fab1fc2db832ef86d8a33466ec4d68b103ca0Eric Laurent                        0,
5084bc0fab1fc2db832ef86d8a33466ec4d68b103ca0Eric Laurent                        0,
5085bc0fab1fc2db832ef86d8a33466ec4d68b103ca0Eric Laurent                        mStreamStates[AudioSystem.STREAM_MUSIC], 0);
5086a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent            }
5087a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent        }
5088c837a451946b64d70ed7c642fbde03c182c28b6fPaul McLean    } // end class AudioServiceBroadcastReceiver
5089d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi
5090d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi    //==========================================================================================
5091fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    // RemoteControlDisplay / RemoteControlClient / Remote info
5092d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi    //==========================================================================================
5093f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi    public boolean registerRemoteController(IRemoteControlDisplay rcd, int w, int h,
5094f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi            ComponentName listenerComp) {
5095f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi        return mMediaFocusControl.registerRemoteController(rcd, w, h, listenerComp);
5096f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi    }
5097f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi
50987ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi    public boolean registerRemoteControlDisplay(IRemoteControlDisplay rcd, int w, int h) {
5099f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi        return mMediaFocusControl.registerRemoteControlDisplay(rcd, w, h);
5100e5e1e870fdb35f5291790e6d178bde7126f6fe35Jean-Michel Trivi    }
5101e5e1e870fdb35f5291790e6d178bde7126f6fe35Jean-Michel Trivi
5102fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    public void unregisterRemoteControlDisplay(IRemoteControlDisplay rcd) {
5103fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        mMediaFocusControl.unregisterRemoteControlDisplay(rcd);
5104d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi    }
5105d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi
5106fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    public void remoteControlDisplayUsesBitmapSize(IRemoteControlDisplay rcd, int w, int h) {
5107fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        mMediaFocusControl.remoteControlDisplayUsesBitmapSize(rcd, w, h);
5108d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi    }
5109d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi
5110fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    public void remoteControlDisplayWantsPlaybackPositionSync(IRemoteControlDisplay rcd,
5111fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            boolean wantsSync) {
5112fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        mMediaFocusControl.remoteControlDisplayWantsPlaybackPositionSync(rcd, wantsSync);
5113d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi    }
5114d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi
51153346a802087f621c6441bc512dfcc17b07143fc6John Spurlock    @Override
5116fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    public void setRemoteStreamVolume(int index) {
51173346a802087f621c6441bc512dfcc17b07143fc6John Spurlock        enforceSelfOrSystemUI("set the remote stream volume");
5118fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        mMediaFocusControl.setRemoteStreamVolume(index);
5119d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi    }
5120d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi
5121fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    //==========================================================================================
5122fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    // Audio Focus
5123fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    //==========================================================================================
5124fd6ad747e6c268753d0edf7a5a59b6815b190854Jean-Michel Trivi    public int requestAudioFocus(AudioAttributes aa, int durationHint, IBinder cb,
5125958876fe55ea0fdeb73c72240a2f2bab32833443Jean-Michel Trivi            IAudioFocusDispatcher fd, String clientId, String callingPackageName, int flags,
51260212be5150fb9fb3c340f3c7e51f6126372cc6f9Jean-Michel Trivi            IAudioPolicyCallback pcb) {
5127958876fe55ea0fdeb73c72240a2f2bab32833443Jean-Michel Trivi        // permission checks
5128958876fe55ea0fdeb73c72240a2f2bab32833443Jean-Michel Trivi        if ((flags & AudioManager.AUDIOFOCUS_FLAG_LOCK) == AudioManager.AUDIOFOCUS_FLAG_LOCK) {
5129958876fe55ea0fdeb73c72240a2f2bab32833443Jean-Michel Trivi            if (mMediaFocusControl.IN_VOICE_COMM_FOCUS_ID.equals(clientId)) {
5130958876fe55ea0fdeb73c72240a2f2bab32833443Jean-Michel Trivi                if (PackageManager.PERMISSION_GRANTED != mContext.checkCallingOrSelfPermission(
5131958876fe55ea0fdeb73c72240a2f2bab32833443Jean-Michel Trivi                            android.Manifest.permission.MODIFY_PHONE_STATE)) {
5132958876fe55ea0fdeb73c72240a2f2bab32833443Jean-Michel Trivi                    Log.e(TAG, "Invalid permission to (un)lock audio focus", new Exception());
5133958876fe55ea0fdeb73c72240a2f2bab32833443Jean-Michel Trivi                    return AudioManager.AUDIOFOCUS_REQUEST_FAILED;
5134958876fe55ea0fdeb73c72240a2f2bab32833443Jean-Michel Trivi                }
5135958876fe55ea0fdeb73c72240a2f2bab32833443Jean-Michel Trivi            } else {
5136958876fe55ea0fdeb73c72240a2f2bab32833443Jean-Michel Trivi                // only a registered audio policy can be used to lock focus
5137958876fe55ea0fdeb73c72240a2f2bab32833443Jean-Michel Trivi                synchronized (mAudioPolicies) {
51380212be5150fb9fb3c340f3c7e51f6126372cc6f9Jean-Michel Trivi                    if (!mAudioPolicies.containsKey(pcb.asBinder())) {
51390212be5150fb9fb3c340f3c7e51f6126372cc6f9Jean-Michel Trivi                        Log.e(TAG, "Invalid unregistered AudioPolicy to (un)lock audio focus");
5140958876fe55ea0fdeb73c72240a2f2bab32833443Jean-Michel Trivi                        return AudioManager.AUDIOFOCUS_REQUEST_FAILED;
5141958876fe55ea0fdeb73c72240a2f2bab32833443Jean-Michel Trivi                    }
5142958876fe55ea0fdeb73c72240a2f2bab32833443Jean-Michel Trivi                }
5143958876fe55ea0fdeb73c72240a2f2bab32833443Jean-Michel Trivi            }
5144958876fe55ea0fdeb73c72240a2f2bab32833443Jean-Michel Trivi        }
5145958876fe55ea0fdeb73c72240a2f2bab32833443Jean-Michel Trivi
5146fd6ad747e6c268753d0edf7a5a59b6815b190854Jean-Michel Trivi        return mMediaFocusControl.requestAudioFocus(aa, durationHint, cb, fd,
5147fd6ad747e6c268753d0edf7a5a59b6815b190854Jean-Michel Trivi                clientId, callingPackageName, flags);
51484294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi    }
51494294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi
5150958876fe55ea0fdeb73c72240a2f2bab32833443Jean-Michel Trivi    public int abandonAudioFocus(IAudioFocusDispatcher fd, String clientId, AudioAttributes aa) {
5151958876fe55ea0fdeb73c72240a2f2bab32833443Jean-Michel Trivi        return mMediaFocusControl.abandonAudioFocus(fd, clientId, aa);
5152c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi    }
5153c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi
5154fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    public void unregisterAudioFocusClient(String clientId) {
5155fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        mMediaFocusControl.unregisterAudioFocusClient(clientId);
51563114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    }
51573114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi
51582380566debfc57eb1cc07db1306ccee23b84ddd4Jean-Michel Trivi    public int getCurrentAudioFocus() {
51592380566debfc57eb1cc07db1306ccee23b84ddd4Jean-Michel Trivi        return mMediaFocusControl.getCurrentAudioFocus();
51602380566debfc57eb1cc07db1306ccee23b84ddd4Jean-Michel Trivi    }
51612380566debfc57eb1cc07db1306ccee23b84ddd4Jean-Michel Trivi
5162f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi    //==========================================================================================
5163f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi    // Device orientation
5164f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi    //==========================================================================================
5165f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi    /**
5166bb6f8711a7f804d39c45218db2d6339940cc5d35Jean-Michel Trivi     * Handles device configuration changes that may map to a change in the orientation
5167bb6f8711a7f804d39c45218db2d6339940cc5d35Jean-Michel Trivi     * or orientation.
5168bb6f8711a7f804d39c45218db2d6339940cc5d35Jean-Michel Trivi     * Monitoring orientation and rotation is optional, and is defined by the definition and value
5169bb6f8711a7f804d39c45218db2d6339940cc5d35Jean-Michel Trivi     * of the "ro.audio.monitorOrientation" and "ro.audio.monitorRotation" system properties.
5170f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi     */
5171f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi    private void handleConfigurationChanged(Context context) {
5172f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi        try {
5173f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi            // reading new orientation "safely" (i.e. under try catch) in case anything
5174f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi            // goes wrong when obtaining resources and configuration
5175d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent            Configuration config = context.getResources().getConfiguration();
5176bb6f8711a7f804d39c45218db2d6339940cc5d35Jean-Michel Trivi            // TODO merge rotation and orientation
5177d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent            if (mMonitorOrientation) {
5178d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent                int newOrientation = config.orientation;
5179d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent                if (newOrientation != mDeviceOrientation) {
5180d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent                    mDeviceOrientation = newOrientation;
5181d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent                    setOrientationForAudioSystem();
5182d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent                }
5183f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi            }
5184d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent            sendMsg(mAudioHandler,
5185d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent                    MSG_CONFIGURE_SAFE_MEDIA_VOLUME,
5186d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent                    SENDMSG_REPLACE,
5187d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent                    0,
5188d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent                    0,
5189d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent                    null,
5190d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent                    0);
5191dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent
5192dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent            boolean cameraSoundForced = mContext.getResources().getBoolean(
5193dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent                    com.android.internal.R.bool.config_camera_sound_forced);
5194dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent            synchronized (mSettingsLock) {
51958fa4d6f585f40ff5cf5f9bed316d92c64a306f21Eric Laurent                boolean cameraSoundForcedChanged = false;
5196dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent                synchronized (mCameraSoundForced) {
5197dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent                    if (cameraSoundForced != mCameraSoundForced) {
5198dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent                        mCameraSoundForced = cameraSoundForced;
51998fa4d6f585f40ff5cf5f9bed316d92c64a306f21Eric Laurent                        cameraSoundForcedChanged = true;
52008fa4d6f585f40ff5cf5f9bed316d92c64a306f21Eric Laurent                    }
52018fa4d6f585f40ff5cf5f9bed316d92c64a306f21Eric Laurent                }
52028fa4d6f585f40ff5cf5f9bed316d92c64a306f21Eric Laurent                if (cameraSoundForcedChanged) {
52038fa4d6f585f40ff5cf5f9bed316d92c64a306f21Eric Laurent                    if (!isPlatformTelevision()) {
52048fa4d6f585f40ff5cf5f9bed316d92c64a306f21Eric Laurent                        VolumeStreamState s = mStreamStates[AudioSystem.STREAM_SYSTEM_ENFORCED];
52058fa4d6f585f40ff5cf5f9bed316d92c64a306f21Eric Laurent                        if (cameraSoundForced) {
52068fa4d6f585f40ff5cf5f9bed316d92c64a306f21Eric Laurent                            s.setAllIndexesToMax();
52078fa4d6f585f40ff5cf5f9bed316d92c64a306f21Eric Laurent                            mRingerModeAffectedStreams &=
52088fa4d6f585f40ff5cf5f9bed316d92c64a306f21Eric Laurent                                    ~(1 << AudioSystem.STREAM_SYSTEM_ENFORCED);
52098fa4d6f585f40ff5cf5f9bed316d92c64a306f21Eric Laurent                        } else {
52108fa4d6f585f40ff5cf5f9bed316d92c64a306f21Eric Laurent                            s.setAllIndexes(mStreamStates[AudioSystem.STREAM_SYSTEM]);
52118fa4d6f585f40ff5cf5f9bed316d92c64a306f21Eric Laurent                            mRingerModeAffectedStreams |=
52128fa4d6f585f40ff5cf5f9bed316d92c64a306f21Eric Laurent                                    (1 << AudioSystem.STREAM_SYSTEM_ENFORCED);
5213dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent                        }
52148fa4d6f585f40ff5cf5f9bed316d92c64a306f21Eric Laurent                        // take new state into account for streams muted by ringer mode
5215661f2cf45860d2e10924e6b69966a9afe255f28bJohn Spurlock                        setRingerModeInt(getRingerModeInternal(), false);
5216dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent                    }
52178fa4d6f585f40ff5cf5f9bed316d92c64a306f21Eric Laurent
52188fa4d6f585f40ff5cf5f9bed316d92c64a306f21Eric Laurent                    sendMsg(mAudioHandler,
52198fa4d6f585f40ff5cf5f9bed316d92c64a306f21Eric Laurent                            MSG_SET_FORCE_USE,
52208fa4d6f585f40ff5cf5f9bed316d92c64a306f21Eric Laurent                            SENDMSG_QUEUE,
52218fa4d6f585f40ff5cf5f9bed316d92c64a306f21Eric Laurent                            AudioSystem.FOR_SYSTEM,
52228fa4d6f585f40ff5cf5f9bed316d92c64a306f21Eric Laurent                            cameraSoundForced ?
52238fa4d6f585f40ff5cf5f9bed316d92c64a306f21Eric Laurent                                    AudioSystem.FORCE_SYSTEM_ENFORCED : AudioSystem.FORCE_NONE,
52248fa4d6f585f40ff5cf5f9bed316d92c64a306f21Eric Laurent                            null,
52258fa4d6f585f40ff5cf5f9bed316d92c64a306f21Eric Laurent                            0);
52268fa4d6f585f40ff5cf5f9bed316d92c64a306f21Eric Laurent
52278fa4d6f585f40ff5cf5f9bed316d92c64a306f21Eric Laurent                    sendMsg(mAudioHandler,
52288fa4d6f585f40ff5cf5f9bed316d92c64a306f21Eric Laurent                            MSG_SET_ALL_VOLUMES,
52298fa4d6f585f40ff5cf5f9bed316d92c64a306f21Eric Laurent                            SENDMSG_QUEUE,
52308fa4d6f585f40ff5cf5f9bed316d92c64a306f21Eric Laurent                            0,
52318fa4d6f585f40ff5cf5f9bed316d92c64a306f21Eric Laurent                            0,
52328fa4d6f585f40ff5cf5f9bed316d92c64a306f21Eric Laurent                            mStreamStates[AudioSystem.STREAM_SYSTEM_ENFORCED], 0);
5233dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent                }
5234dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent            }
52353346a802087f621c6441bc512dfcc17b07143fc6John Spurlock            mVolumeController.setLayoutDirection(config.getLayoutDirection());
5236f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi        } catch (Exception e) {
5237bb6f8711a7f804d39c45218db2d6339940cc5d35Jean-Michel Trivi            Log.e(TAG, "Error handling configuration change: ", e);
5238f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi        }
5239f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi    }
5240f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi
5241f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi    private void setOrientationForAudioSystem() {
5242f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi        switch (mDeviceOrientation) {
5243f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi            case Configuration.ORIENTATION_LANDSCAPE:
5244f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi                //Log.i(TAG, "orientation is landscape");
5245f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi                AudioSystem.setParameters("orientation=landscape");
5246f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi                break;
5247f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi            case Configuration.ORIENTATION_PORTRAIT:
5248f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi                //Log.i(TAG, "orientation is portrait");
5249f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi                AudioSystem.setParameters("orientation=portrait");
5250f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi                break;
5251f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi            case Configuration.ORIENTATION_SQUARE:
5252f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi                //Log.i(TAG, "orientation is square");
5253f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi                AudioSystem.setParameters("orientation=square");
5254f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi                break;
5255f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi            case Configuration.ORIENTATION_UNDEFINED:
5256f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi                //Log.i(TAG, "orientation is undefined");
5257f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi                AudioSystem.setParameters("orientation=undefined");
5258f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi                break;
5259f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi            default:
5260f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi                Log.e(TAG, "Unknown orientation");
5261f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi        }
5262f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi    }
5263f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi
5264bb6f8711a7f804d39c45218db2d6339940cc5d35Jean-Michel Trivi    private void setRotationForAudioSystem() {
5265bb6f8711a7f804d39c45218db2d6339940cc5d35Jean-Michel Trivi        switch (mDeviceRotation) {
5266bb6f8711a7f804d39c45218db2d6339940cc5d35Jean-Michel Trivi            case Surface.ROTATION_0:
5267bb6f8711a7f804d39c45218db2d6339940cc5d35Jean-Michel Trivi                AudioSystem.setParameters("rotation=0");
5268bb6f8711a7f804d39c45218db2d6339940cc5d35Jean-Michel Trivi                break;
5269bb6f8711a7f804d39c45218db2d6339940cc5d35Jean-Michel Trivi            case Surface.ROTATION_90:
5270bb6f8711a7f804d39c45218db2d6339940cc5d35Jean-Michel Trivi                AudioSystem.setParameters("rotation=90");
5271bb6f8711a7f804d39c45218db2d6339940cc5d35Jean-Michel Trivi                break;
5272bb6f8711a7f804d39c45218db2d6339940cc5d35Jean-Michel Trivi            case Surface.ROTATION_180:
5273bb6f8711a7f804d39c45218db2d6339940cc5d35Jean-Michel Trivi                AudioSystem.setParameters("rotation=180");
5274bb6f8711a7f804d39c45218db2d6339940cc5d35Jean-Michel Trivi                break;
5275bb6f8711a7f804d39c45218db2d6339940cc5d35Jean-Michel Trivi            case Surface.ROTATION_270:
5276bb6f8711a7f804d39c45218db2d6339940cc5d35Jean-Michel Trivi                AudioSystem.setParameters("rotation=270");
5277bb6f8711a7f804d39c45218db2d6339940cc5d35Jean-Michel Trivi                break;
5278bb6f8711a7f804d39c45218db2d6339940cc5d35Jean-Michel Trivi            default:
5279bb6f8711a7f804d39c45218db2d6339940cc5d35Jean-Michel Trivi                Log.e(TAG, "Unknown device rotation");
5280bb6f8711a7f804d39c45218db2d6339940cc5d35Jean-Michel Trivi        }
5281bb6f8711a7f804d39c45218db2d6339940cc5d35Jean-Michel Trivi    }
5282bb6f8711a7f804d39c45218db2d6339940cc5d35Jean-Michel Trivi
5283f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi
52847847211fb4699bf6018e29d214a918ed6657319bEric Laurent    // Handles request to override default use of A2DP for media.
52857847211fb4699bf6018e29d214a918ed6657319bEric Laurent    public void setBluetoothA2dpOnInt(boolean on) {
52867847211fb4699bf6018e29d214a918ed6657319bEric Laurent        synchronized (mBluetoothA2dpEnabledLock) {
52877847211fb4699bf6018e29d214a918ed6657319bEric Laurent            mBluetoothA2dpEnabled = on;
5288c390bed06b4a572e273ead1254da9a932e04dce3Eric Laurent            mAudioHandler.removeMessages(MSG_SET_FORCE_BT_A2DP_USE);
5289c390bed06b4a572e273ead1254da9a932e04dce3Eric Laurent            AudioSystem.setForceUse(AudioSystem.FOR_MEDIA,
5290c390bed06b4a572e273ead1254da9a932e04dce3Eric Laurent                    mBluetoothA2dpEnabled ? AudioSystem.FORCE_NONE : AudioSystem.FORCE_NO_BT_A2DP);
52917847211fb4699bf6018e29d214a918ed6657319bEric Laurent        }
52927847211fb4699bf6018e29d214a918ed6657319bEric Laurent    }
52937847211fb4699bf6018e29d214a918ed6657319bEric Laurent
5294d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi    @Override
5295098d580cc2bb6c0891c756a4e5230c6c6b0d2376Jeff Sharkey    public void setRingtonePlayer(IRingtonePlayer player) {
5296098d580cc2bb6c0891c756a4e5230c6c6b0d2376Jeff Sharkey        mContext.enforceCallingOrSelfPermission(REMOTE_AUDIO_PLAYBACK, null);
5297098d580cc2bb6c0891c756a4e5230c6c6b0d2376Jeff Sharkey        mRingtonePlayer = player;
5298098d580cc2bb6c0891c756a4e5230c6c6b0d2376Jeff Sharkey    }
5299098d580cc2bb6c0891c756a4e5230c6c6b0d2376Jeff Sharkey
5300098d580cc2bb6c0891c756a4e5230c6c6b0d2376Jeff Sharkey    @Override
5301098d580cc2bb6c0891c756a4e5230c6c6b0d2376Jeff Sharkey    public IRingtonePlayer getRingtonePlayer() {
5302098d580cc2bb6c0891c756a4e5230c6c6b0d2376Jeff Sharkey        return mRingtonePlayer;
5303098d580cc2bb6c0891c756a4e5230c6c6b0d2376Jeff Sharkey    }
5304098d580cc2bb6c0891c756a4e5230c6c6b0d2376Jeff Sharkey
5305098d580cc2bb6c0891c756a4e5230c6c6b0d2376Jeff Sharkey    @Override
5306632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn    public AudioRoutesInfo startWatchingRoutes(IAudioRoutesObserver observer) {
5307632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn        synchronized (mCurAudioRoutes) {
5308632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn            AudioRoutesInfo routes = new AudioRoutesInfo(mCurAudioRoutes);
5309632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn            mRoutesObservers.register(observer);
5310632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn            return routes;
5311632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn        }
5312632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn    }
5313632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn
5314c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent
5315c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent    //==========================================================================================
5316c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent    // Safe media volume management.
5317c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent    // MUSIC stream volume level is limited when headphones are connected according to safety
5318c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent    // regulation. When the user attempts to raise the volume above the limit, a warning is
5319c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent    // displayed and the user has to acknowlegde before the volume is actually changed.
5320c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent    // The volume index corresponding to the limit is stored in config_safe_media_volume_index
5321c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent    // property. Platforms with a different limit must set this property accordingly in their
5322c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent    // overlay.
5323c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent    //==========================================================================================
5324c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent
5325d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent    // mSafeMediaVolumeState indicates whether the media volume is limited over headphones.
5326d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent    // It is SAFE_MEDIA_VOLUME_NOT_CONFIGURED at boot time until a network service is connected
5327d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent    // or the configure time is elapsed. It is then set to SAFE_MEDIA_VOLUME_ACTIVE or
5328d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent    // SAFE_MEDIA_VOLUME_DISABLED according to country option. If not SAFE_MEDIA_VOLUME_DISABLED, it
5329d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent    // can be set to SAFE_MEDIA_VOLUME_INACTIVE by calling AudioService.disableSafeMediaVolume()
5330d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent    // (when user opts out).
5331351346092acdfbfcc1d9ebf98d539d2a1196c5e8John Spurlock    private static final int SAFE_MEDIA_VOLUME_NOT_CONFIGURED = 0;
5332351346092acdfbfcc1d9ebf98d539d2a1196c5e8John Spurlock    private static final int SAFE_MEDIA_VOLUME_DISABLED = 1;
5333351346092acdfbfcc1d9ebf98d539d2a1196c5e8John Spurlock    private static final int SAFE_MEDIA_VOLUME_INACTIVE = 2;  // confirmed
5334351346092acdfbfcc1d9ebf98d539d2a1196c5e8John Spurlock    private static final int SAFE_MEDIA_VOLUME_ACTIVE = 3;  // unconfirmed
5335d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent    private Integer mSafeMediaVolumeState;
5336d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent
5337d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent    private int mMcc = 0;
5338c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent    // mSafeMediaVolumeIndex is the cached value of config_safe_media_volume_index property
5339d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent    private int mSafeMediaVolumeIndex;
5340c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent    // mSafeMediaVolumeDevices lists the devices for which safe media volume is enforced,
5341c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent    private final int mSafeMediaVolumeDevices = AudioSystem.DEVICE_OUT_WIRED_HEADSET |
5342c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent                                                AudioSystem.DEVICE_OUT_WIRED_HEADPHONE;
5343c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent    // mMusicActiveMs is the cumulative time of music activity since safe volume was disabled.
5344c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent    // When this time reaches UNSAFE_VOLUME_MUSIC_ACTIVE_MS_MAX, the safe media volume is re-enabled
5345c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent    // automatically. mMusicActiveMs is rounded to a multiple of MUSIC_ACTIVE_POLL_PERIOD_MS.
5346c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent    private int mMusicActiveMs;
5347c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent    private static final int UNSAFE_VOLUME_MUSIC_ACTIVE_MS_MAX = (20 * 3600 * 1000); // 20 hours
5348c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent    private static final int MUSIC_ACTIVE_POLL_PERIOD_MS = 60000;  // 1 minute polling interval
5349d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent    private static final int SAFE_VOLUME_CONFIGURE_TIMEOUT_MS = 30000;  // 30s after boot completed
5350c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent
5351c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent    private void setSafeMediaVolumeEnabled(boolean on) {
5352d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent        synchronized (mSafeMediaVolumeState) {
5353d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent            if ((mSafeMediaVolumeState != SAFE_MEDIA_VOLUME_NOT_CONFIGURED) &&
5354d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent                    (mSafeMediaVolumeState != SAFE_MEDIA_VOLUME_DISABLED)) {
5355d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent                if (on && (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_INACTIVE)) {
5356d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent                    mSafeMediaVolumeState = SAFE_MEDIA_VOLUME_ACTIVE;
5357d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent                    enforceSafeMediaVolume();
5358d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent                } else if (!on && (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_ACTIVE)) {
5359d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent                    mSafeMediaVolumeState = SAFE_MEDIA_VOLUME_INACTIVE;
5360aa5ee4d65f8788e2a0afcd198367450853fd72acJohn Spurlock                    mMusicActiveMs = 1;  // nonzero = confirmed
5361aa5ee4d65f8788e2a0afcd198367450853fd72acJohn Spurlock                    saveMusicActiveMs();
5362d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent                    sendMsg(mAudioHandler,
5363d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent                            MSG_CHECK_MUSIC_ACTIVE,
5364d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent                            SENDMSG_REPLACE,
5365d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent                            0,
5366d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent                            0,
5367d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent                            null,
5368d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent                            MUSIC_ACTIVE_POLL_PERIOD_MS);
5369d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent                }
5370c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent            }
5371c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent        }
5372c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent    }
5373c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent
5374c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent    private void enforceSafeMediaVolume() {
5375c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent        VolumeStreamState streamState = mStreamStates[AudioSystem.STREAM_MUSIC];
5376c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent        int devices = mSafeMediaVolumeDevices;
5377c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent        int i = 0;
5378c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent
5379c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent        while (devices != 0) {
5380c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent            int device = 1 << i++;
5381c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent            if ((device & devices) == 0) {
5382c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent                continue;
5383c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent            }
538442b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent            int index = streamState.getIndex(device);
5385c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent            if (index > mSafeMediaVolumeIndex) {
538642b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                streamState.setIndex(mSafeMediaVolumeIndex, device);
538742b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                sendMsg(mAudioHandler,
538842b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                        MSG_SET_DEVICE_VOLUME,
538942b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                        SENDMSG_QUEUE,
539042b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                        device,
539142b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                        0,
539242b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                        streamState,
539342b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                        0);
5394c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent            }
5395c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent            devices &= ~device;
5396c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent        }
5397c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent    }
5398c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent
5399c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent    private boolean checkSafeMediaVolume(int streamType, int index, int device) {
5400d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent        synchronized (mSafeMediaVolumeState) {
5401d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent            if ((mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_ACTIVE) &&
5402c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent                    (mStreamVolumeAlias[streamType] == AudioSystem.STREAM_MUSIC) &&
5403c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent                    ((device & mSafeMediaVolumeDevices) != 0) &&
5404c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent                    (index > mSafeMediaVolumeIndex)) {
5405c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent                return false;
5406c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent            }
5407c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent            return true;
5408c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent        }
5409c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent    }
5410c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent
54113346a802087f621c6441bc512dfcc17b07143fc6John Spurlock    @Override
5412c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent    public void disableSafeMediaVolume() {
54133346a802087f621c6441bc512dfcc17b07143fc6John Spurlock        enforceSelfOrSystemUI("disable the safe media volume");
5414d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent        synchronized (mSafeMediaVolumeState) {
5415c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent            setSafeMediaVolumeEnabled(false);
5416fde16d5879ea88a971004c984093409468b6139cEric Laurent            if (mPendingVolumeCommand != null) {
5417fde16d5879ea88a971004c984093409468b6139cEric Laurent                onSetStreamVolume(mPendingVolumeCommand.mStreamType,
5418fde16d5879ea88a971004c984093409468b6139cEric Laurent                                  mPendingVolumeCommand.mIndex,
5419fde16d5879ea88a971004c984093409468b6139cEric Laurent                                  mPendingVolumeCommand.mFlags,
5420fde16d5879ea88a971004c984093409468b6139cEric Laurent                                  mPendingVolumeCommand.mDevice);
5421fde16d5879ea88a971004c984093409468b6139cEric Laurent                mPendingVolumeCommand = null;
5422fde16d5879ea88a971004c984093409468b6139cEric Laurent            }
5423c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent        }
5424c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent    }
5425c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent
542641d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang    //==========================================================================================
542741d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang    // Hdmi Cec system audio mode.
542841d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang    // If Hdmi Cec's system audio mode is on, audio service should notify volume change
542941d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang    // to HdmiControlService so that audio recevier can handle volume change.
543041d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang    //==========================================================================================
543141d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang
5432212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent    private class MyDisplayStatusCallback implements HdmiPlaybackClient.DisplayStatusCallback {
5433212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent        public void onComplete(int status) {
5434212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent            if (mHdmiManager != null) {
5435212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent                synchronized (mHdmiManager) {
5436212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent                    mHdmiCecSink = (status != HdmiControlManager.POWER_STATUS_UNKNOWN);
5437212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent                    // Television devices without CEC service apply software volume on HDMI output
5438212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent                    if (isPlatformTelevision() && !mHdmiCecSink) {
5439212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent                        mFixedVolumeDevices &= ~AudioSystem.DEVICE_OUT_HDMI;
5440212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent                    }
5441212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent                    checkAllFixedVolumeDevices();
5442212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent                }
5443212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent            }
5444212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent        }
5445212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent    };
5446212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent
544741d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang    // If HDMI-CEC system audio is supported
544841d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang    private boolean mHdmiSystemAudioSupported = false;
544941d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang    // Set only when device is tv.
545041d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang    private HdmiTvClient mHdmiTvClient;
54510b03f9909be438f45b32ce2a6a2c2c5208a82cc9Eric Laurent    // true if the device has system feature PackageManager.FEATURE_LEANBACK.
5452212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent    // cached HdmiControlManager interface
5453212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent    private HdmiControlManager mHdmiManager;
5454212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent    // Set only when device is a set-top box.
5455212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent    private HdmiPlaybackClient mHdmiPlaybackClient;
5456212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent    // true if we are a set-top box, an HDMI sink is connected and it supports CEC.
5457212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent    private boolean mHdmiCecSink;
5458212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent
5459212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent    private MyDisplayStatusCallback mHdmiDisplayStatusCallback = new MyDisplayStatusCallback();
546041d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang
546141d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang    @Override
546212307ca810e8100981b2b60e3f2c6a7e451b9774Jungshik Jang    public int setHdmiSystemAudioSupported(boolean on) {
5463212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent        int device = AudioSystem.DEVICE_NONE;
5464212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent        if (mHdmiManager != null) {
5465212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent            synchronized (mHdmiManager) {
5466212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent                if (mHdmiTvClient == null) {
5467212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent                    Log.w(TAG, "Only Hdmi-Cec enabled TV device supports system audio mode.");
5468212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent                    return device;
5469212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent                }
547041d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang
5471212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent                synchronized (mHdmiTvClient) {
5472212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent                    if (mHdmiSystemAudioSupported != on) {
5473212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent                        mHdmiSystemAudioSupported = on;
5474212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent                        AudioSystem.setForceUse(AudioSystem.FOR_HDMI_SYSTEM_AUDIO,
5475212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent                                on ? AudioSystem.FORCE_HDMI_SYSTEM_AUDIO_ENFORCED :
5476212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent                                     AudioSystem.FORCE_NONE);
5477212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent                    }
5478212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent                    device = AudioSystem.getDevicesForStream(AudioSystem.STREAM_MUSIC);
5479212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent                }
54806f34f5ab8ab1b1db7887e5405d8b0031e105ab05Jungshik Jang            }
54816f34f5ab8ab1b1db7887e5405d8b0031e105ab05Jungshik Jang        }
5482212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent        return device;
54836f34f5ab8ab1b1db7887e5405d8b0031e105ab05Jungshik Jang    }
54846f34f5ab8ab1b1db7887e5405d8b0031e105ab05Jungshik Jang
5485e7d6d97f0d95b9e8982b0d4d9f5e8ce688291940Terry Heo    @Override
5486e7d6d97f0d95b9e8982b0d4d9f5e8ce688291940Terry Heo    public boolean isHdmiSystemAudioSupported() {
5487e7d6d97f0d95b9e8982b0d4d9f5e8ce688291940Terry Heo        return mHdmiSystemAudioSupported;
5488e7d6d97f0d95b9e8982b0d4d9f5e8ce688291940Terry Heo    }
5489e7d6d97f0d95b9e8982b0d4d9f5e8ce688291940Terry Heo
5490dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent    //==========================================================================================
5491873cc45da2463a11182fe94a2565364d7e1709bbJean-Michel Trivi    // Accessibility: taking touch exploration into account for selecting the default
5492873cc45da2463a11182fe94a2565364d7e1709bbJean-Michel Trivi    //   stream override timeout when adjusting volume
5493873cc45da2463a11182fe94a2565364d7e1709bbJean-Michel Trivi    //==========================================================================================
5494873cc45da2463a11182fe94a2565364d7e1709bbJean-Michel Trivi    private static class StreamOverride
5495873cc45da2463a11182fe94a2565364d7e1709bbJean-Michel Trivi            implements AccessibilityManager.TouchExplorationStateChangeListener {
5496873cc45da2463a11182fe94a2565364d7e1709bbJean-Michel Trivi
5497873cc45da2463a11182fe94a2565364d7e1709bbJean-Michel Trivi        // AudioService.getActiveStreamType() will return:
5498873cc45da2463a11182fe94a2565364d7e1709bbJean-Michel Trivi        // - STREAM_NOTIFICATION on tablets during this period after a notification stopped
5499873cc45da2463a11182fe94a2565364d7e1709bbJean-Michel Trivi        // - STREAM_MUSIC on phones during this period after music or talkback/voice search prompt
5500873cc45da2463a11182fe94a2565364d7e1709bbJean-Michel Trivi        // stopped
5501873cc45da2463a11182fe94a2565364d7e1709bbJean-Michel Trivi        private static final int DEFAULT_STREAM_TYPE_OVERRIDE_DELAY_MS = 5000;
5502873cc45da2463a11182fe94a2565364d7e1709bbJean-Michel Trivi        private static final int TOUCH_EXPLORE_STREAM_TYPE_OVERRIDE_DELAY_MS = 1000;
5503873cc45da2463a11182fe94a2565364d7e1709bbJean-Michel Trivi
5504873cc45da2463a11182fe94a2565364d7e1709bbJean-Michel Trivi        static int sDelayMs;
5505873cc45da2463a11182fe94a2565364d7e1709bbJean-Michel Trivi
5506873cc45da2463a11182fe94a2565364d7e1709bbJean-Michel Trivi        static void init(Context ctxt) {
5507873cc45da2463a11182fe94a2565364d7e1709bbJean-Michel Trivi            AccessibilityManager accessibilityManager =
5508873cc45da2463a11182fe94a2565364d7e1709bbJean-Michel Trivi                    (AccessibilityManager) ctxt.getSystemService(Context.ACCESSIBILITY_SERVICE);
5509873cc45da2463a11182fe94a2565364d7e1709bbJean-Michel Trivi            updateDefaultStreamOverrideDelay(
5510873cc45da2463a11182fe94a2565364d7e1709bbJean-Michel Trivi                    accessibilityManager.isTouchExplorationEnabled());
5511873cc45da2463a11182fe94a2565364d7e1709bbJean-Michel Trivi            accessibilityManager.addTouchExplorationStateChangeListener(
5512873cc45da2463a11182fe94a2565364d7e1709bbJean-Michel Trivi                    new StreamOverride());
5513873cc45da2463a11182fe94a2565364d7e1709bbJean-Michel Trivi        }
5514873cc45da2463a11182fe94a2565364d7e1709bbJean-Michel Trivi
5515873cc45da2463a11182fe94a2565364d7e1709bbJean-Michel Trivi        @Override
5516873cc45da2463a11182fe94a2565364d7e1709bbJean-Michel Trivi        public void onTouchExplorationStateChanged(boolean enabled) {
5517873cc45da2463a11182fe94a2565364d7e1709bbJean-Michel Trivi            updateDefaultStreamOverrideDelay(enabled);
5518873cc45da2463a11182fe94a2565364d7e1709bbJean-Michel Trivi        }
5519873cc45da2463a11182fe94a2565364d7e1709bbJean-Michel Trivi
5520873cc45da2463a11182fe94a2565364d7e1709bbJean-Michel Trivi        private static void updateDefaultStreamOverrideDelay(boolean touchExploreEnabled) {
5521873cc45da2463a11182fe94a2565364d7e1709bbJean-Michel Trivi            if (touchExploreEnabled) {
5522873cc45da2463a11182fe94a2565364d7e1709bbJean-Michel Trivi                sDelayMs = TOUCH_EXPLORE_STREAM_TYPE_OVERRIDE_DELAY_MS;
5523873cc45da2463a11182fe94a2565364d7e1709bbJean-Michel Trivi            } else {
5524873cc45da2463a11182fe94a2565364d7e1709bbJean-Michel Trivi                sDelayMs = DEFAULT_STREAM_TYPE_OVERRIDE_DELAY_MS;
5525873cc45da2463a11182fe94a2565364d7e1709bbJean-Michel Trivi            }
5526873cc45da2463a11182fe94a2565364d7e1709bbJean-Michel Trivi            if (DEBUG_VOL) Log.d(TAG, "Touch exploration enabled=" + touchExploreEnabled
5527873cc45da2463a11182fe94a2565364d7e1709bbJean-Michel Trivi                    + " stream override delay is now " + sDelayMs + " ms");
5528873cc45da2463a11182fe94a2565364d7e1709bbJean-Michel Trivi        }
5529873cc45da2463a11182fe94a2565364d7e1709bbJean-Michel Trivi    }
5530873cc45da2463a11182fe94a2565364d7e1709bbJean-Michel Trivi
5531873cc45da2463a11182fe94a2565364d7e1709bbJean-Michel Trivi    //==========================================================================================
5532dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent    // Camera shutter sound policy.
5533dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent    // config_camera_sound_forced configuration option in config.xml defines if the camera shutter
5534dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent    // sound is forced (sound even if the device is in silent mode) or not. This option is false by
5535dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent    // default and can be overridden by country specific overlay in values-mccXXX/config.xml.
5536dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent    //==========================================================================================
5537dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent
5538dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent    // cached value of com.android.internal.R.bool.config_camera_sound_forced
5539dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent    private Boolean mCameraSoundForced;
5540dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent
5541dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent    // called by android.hardware.Camera to populate CameraInfo.canDisableShutterSound
5542dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent    public boolean isCameraSoundForced() {
5543dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent        synchronized (mCameraSoundForced) {
5544dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent            return mCameraSoundForced;
5545dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent        }
5546dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent    }
5547dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent
5548dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent    private static final String[] RINGER_MODE_NAMES = new String[] {
5549dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent            "SILENT",
5550dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent            "VIBRATE",
5551dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent            "NORMAL"
5552dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent    };
5553dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent
5554dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent    private void dumpRingerMode(PrintWriter pw) {
5555dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent        pw.println("\nRinger mode: ");
5556661f2cf45860d2e10924e6b69966a9afe255f28bJohn Spurlock        pw.println("- mode (internal) = " + RINGER_MODE_NAMES[mRingerMode]);
5557661f2cf45860d2e10924e6b69966a9afe255f28bJohn Spurlock        pw.println("- mode (external) = " + RINGER_MODE_NAMES[mRingerModeExternal]);
5558dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent        pw.print("- ringer mode affected streams = 0x");
5559dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent        pw.println(Integer.toHexString(mRingerModeAffectedStreams));
5560dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent        pw.print("- ringer mode muted streams = 0x");
5561dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent        pw.println(Integer.toHexString(mRingerModeMutedStreams));
5562661f2cf45860d2e10924e6b69966a9afe255f28bJohn Spurlock        pw.print("- delegate = "); pw.println(mRingerModeDelegate);
5563dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent    }
5564dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent
5565632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn    @Override
5566d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi    protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
5567eb4cc492c93ab9635dde78b958a834120412e72aJeff Sharkey        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DUMP, TAG);
5568eb4cc492c93ab9635dde78b958a834120412e72aJeff Sharkey
5569fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        mMediaFocusControl.dump(pw);
5570bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent        dumpStreamStates(pw);
5571dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent        dumpRingerMode(pw);
5572632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn        pw.println("\nAudio routes:");
5573632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn        pw.print("  mMainType=0x"); pw.println(Integer.toHexString(mCurAudioRoutes.mMainType));
5574632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn        pw.print("  mBluetoothName="); pw.println(mCurAudioRoutes.mBluetoothName);
5575351346092acdfbfcc1d9ebf98d539d2a1196c5e8John Spurlock
5576351346092acdfbfcc1d9ebf98d539d2a1196c5e8John Spurlock        pw.println("\nOther state:");
55773346a802087f621c6441bc512dfcc17b07143fc6John Spurlock        pw.print("  mVolumeController="); pw.println(mVolumeController);
5578351346092acdfbfcc1d9ebf98d539d2a1196c5e8John Spurlock        pw.print("  mSafeMediaVolumeState=");
5579351346092acdfbfcc1d9ebf98d539d2a1196c5e8John Spurlock        pw.println(safeMediaVolumeStateToString(mSafeMediaVolumeState));
5580351346092acdfbfcc1d9ebf98d539d2a1196c5e8John Spurlock        pw.print("  mSafeMediaVolumeIndex="); pw.println(mSafeMediaVolumeIndex);
5581351346092acdfbfcc1d9ebf98d539d2a1196c5e8John Spurlock        pw.print("  mPendingVolumeCommand="); pw.println(mPendingVolumeCommand);
5582351346092acdfbfcc1d9ebf98d539d2a1196c5e8John Spurlock        pw.print("  mMusicActiveMs="); pw.println(mMusicActiveMs);
5583aa5ee4d65f8788e2a0afcd198367450853fd72acJohn Spurlock        pw.print("  mMcc="); pw.println(mMcc);
5584661f2cf45860d2e10924e6b69966a9afe255f28bJohn Spurlock        pw.print("  mHasVibrator="); pw.println(mHasVibrator);
55851b3541d5eedb332ea01066b4a78a2d06d5304044Jean-Michel Trivi
55861b3541d5eedb332ea01066b4a78a2d06d5304044Jean-Michel Trivi        dumpAudioPolicies(pw);
5587351346092acdfbfcc1d9ebf98d539d2a1196c5e8John Spurlock    }
5588351346092acdfbfcc1d9ebf98d539d2a1196c5e8John Spurlock
5589351346092acdfbfcc1d9ebf98d539d2a1196c5e8John Spurlock    private static String safeMediaVolumeStateToString(Integer state) {
5590351346092acdfbfcc1d9ebf98d539d2a1196c5e8John Spurlock        switch(state) {
5591351346092acdfbfcc1d9ebf98d539d2a1196c5e8John Spurlock            case SAFE_MEDIA_VOLUME_NOT_CONFIGURED: return "SAFE_MEDIA_VOLUME_NOT_CONFIGURED";
5592351346092acdfbfcc1d9ebf98d539d2a1196c5e8John Spurlock            case SAFE_MEDIA_VOLUME_DISABLED: return "SAFE_MEDIA_VOLUME_DISABLED";
5593351346092acdfbfcc1d9ebf98d539d2a1196c5e8John Spurlock            case SAFE_MEDIA_VOLUME_INACTIVE: return "SAFE_MEDIA_VOLUME_INACTIVE";
5594351346092acdfbfcc1d9ebf98d539d2a1196c5e8John Spurlock            case SAFE_MEDIA_VOLUME_ACTIVE: return "SAFE_MEDIA_VOLUME_ACTIVE";
5595351346092acdfbfcc1d9ebf98d539d2a1196c5e8John Spurlock        }
5596351346092acdfbfcc1d9ebf98d539d2a1196c5e8John Spurlock        return null;
5597d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi    }
5598fd116ad1ab02f6060a0b2201f018317fa32e28b4Glenn Kasten
5599fd116ad1ab02f6060a0b2201f018317fa32e28b4Glenn Kasten    // Inform AudioFlinger of our device's low RAM attribute
5600fd116ad1ab02f6060a0b2201f018317fa32e28b4Glenn Kasten    private static void readAndSetLowRamDevice()
5601fd116ad1ab02f6060a0b2201f018317fa32e28b4Glenn Kasten    {
5602fd116ad1ab02f6060a0b2201f018317fa32e28b4Glenn Kasten        int status = AudioSystem.setLowRamDevice(ActivityManager.isLowRamDeviceStatic());
5603fd116ad1ab02f6060a0b2201f018317fa32e28b4Glenn Kasten        if (status != 0) {
5604fd116ad1ab02f6060a0b2201f018317fa32e28b4Glenn Kasten            Log.w(TAG, "AudioFlinger informed of device's low RAM attribute; status " + status);
5605fd116ad1ab02f6060a0b2201f018317fa32e28b4Glenn Kasten        }
5606fd116ad1ab02f6060a0b2201f018317fa32e28b4Glenn Kasten    }
56073346a802087f621c6441bc512dfcc17b07143fc6John Spurlock
56083346a802087f621c6441bc512dfcc17b07143fc6John Spurlock    private void enforceSelfOrSystemUI(String action) {
56093346a802087f621c6441bc512dfcc17b07143fc6John Spurlock        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.STATUS_BAR_SERVICE,
56103346a802087f621c6441bc512dfcc17b07143fc6John Spurlock                "Only SystemUI can " + action);
56113346a802087f621c6441bc512dfcc17b07143fc6John Spurlock    }
56123346a802087f621c6441bc512dfcc17b07143fc6John Spurlock
56133346a802087f621c6441bc512dfcc17b07143fc6John Spurlock    @Override
56143346a802087f621c6441bc512dfcc17b07143fc6John Spurlock    public void setVolumeController(final IVolumeController controller) {
56153346a802087f621c6441bc512dfcc17b07143fc6John Spurlock        enforceSelfOrSystemUI("set the volume controller");
56163346a802087f621c6441bc512dfcc17b07143fc6John Spurlock
56173346a802087f621c6441bc512dfcc17b07143fc6John Spurlock        // return early if things are not actually changing
56183346a802087f621c6441bc512dfcc17b07143fc6John Spurlock        if (mVolumeController.isSameBinder(controller)) {
56193346a802087f621c6441bc512dfcc17b07143fc6John Spurlock            return;
56203346a802087f621c6441bc512dfcc17b07143fc6John Spurlock        }
56213346a802087f621c6441bc512dfcc17b07143fc6John Spurlock
56223346a802087f621c6441bc512dfcc17b07143fc6John Spurlock        // dismiss the old volume controller
56233346a802087f621c6441bc512dfcc17b07143fc6John Spurlock        mVolumeController.postDismiss();
56243346a802087f621c6441bc512dfcc17b07143fc6John Spurlock        if (controller != null) {
56253346a802087f621c6441bc512dfcc17b07143fc6John Spurlock            // we are about to register a new controller, listen for its death
56263346a802087f621c6441bc512dfcc17b07143fc6John Spurlock            try {
56273346a802087f621c6441bc512dfcc17b07143fc6John Spurlock                controller.asBinder().linkToDeath(new DeathRecipient() {
56283346a802087f621c6441bc512dfcc17b07143fc6John Spurlock                    @Override
56293346a802087f621c6441bc512dfcc17b07143fc6John Spurlock                    public void binderDied() {
56303346a802087f621c6441bc512dfcc17b07143fc6John Spurlock                        if (mVolumeController.isSameBinder(controller)) {
56313346a802087f621c6441bc512dfcc17b07143fc6John Spurlock                            Log.w(TAG, "Current remote volume controller died, unregistering");
56323346a802087f621c6441bc512dfcc17b07143fc6John Spurlock                            setVolumeController(null);
56333346a802087f621c6441bc512dfcc17b07143fc6John Spurlock                        }
56343346a802087f621c6441bc512dfcc17b07143fc6John Spurlock                    }
56353346a802087f621c6441bc512dfcc17b07143fc6John Spurlock                }, 0);
56363346a802087f621c6441bc512dfcc17b07143fc6John Spurlock            } catch (RemoteException e) {
56373346a802087f621c6441bc512dfcc17b07143fc6John Spurlock                // noop
56383346a802087f621c6441bc512dfcc17b07143fc6John Spurlock            }
56393346a802087f621c6441bc512dfcc17b07143fc6John Spurlock        }
56403346a802087f621c6441bc512dfcc17b07143fc6John Spurlock        mVolumeController.setController(controller);
564133f4e04e32fac42f158733d6a731e50490fa9951John Spurlock        if (DEBUG_VOL) Log.d(TAG, "Volume controller: " + mVolumeController);
564233f4e04e32fac42f158733d6a731e50490fa9951John Spurlock    }
564333f4e04e32fac42f158733d6a731e50490fa9951John Spurlock
564433f4e04e32fac42f158733d6a731e50490fa9951John Spurlock    @Override
564533f4e04e32fac42f158733d6a731e50490fa9951John Spurlock    public void notifyVolumeControllerVisible(final IVolumeController controller, boolean visible) {
564633f4e04e32fac42f158733d6a731e50490fa9951John Spurlock        enforceSelfOrSystemUI("notify about volume controller visibility");
564733f4e04e32fac42f158733d6a731e50490fa9951John Spurlock
564833f4e04e32fac42f158733d6a731e50490fa9951John Spurlock        // return early if the controller is not current
564933f4e04e32fac42f158733d6a731e50490fa9951John Spurlock        if (!mVolumeController.isSameBinder(controller)) {
565033f4e04e32fac42f158733d6a731e50490fa9951John Spurlock            return;
565133f4e04e32fac42f158733d6a731e50490fa9951John Spurlock        }
565233f4e04e32fac42f158733d6a731e50490fa9951John Spurlock
565333f4e04e32fac42f158733d6a731e50490fa9951John Spurlock        mVolumeController.setVisible(visible);
565433f4e04e32fac42f158733d6a731e50490fa9951John Spurlock        if (DEBUG_VOL) Log.d(TAG, "Volume controller visible: " + visible);
56553346a802087f621c6441bc512dfcc17b07143fc6John Spurlock    }
5656d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik
5657d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik    public static class VolumeController {
5658d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik        private static final String TAG = "VolumeController";
5659d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik
5660d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik        private IVolumeController mController;
566133f4e04e32fac42f158733d6a731e50490fa9951John Spurlock        private boolean mVisible;
566233f4e04e32fac42f158733d6a731e50490fa9951John Spurlock        private long mNextLongPress;
566333f4e04e32fac42f158733d6a731e50490fa9951John Spurlock        private int mLongPressTimeout;
5664d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik
5665d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik        public void setController(IVolumeController controller) {
5666d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik            mController = controller;
566733f4e04e32fac42f158733d6a731e50490fa9951John Spurlock            mVisible = false;
566833f4e04e32fac42f158733d6a731e50490fa9951John Spurlock        }
566933f4e04e32fac42f158733d6a731e50490fa9951John Spurlock
567033f4e04e32fac42f158733d6a731e50490fa9951John Spurlock        public void loadSettings(ContentResolver cr) {
567133f4e04e32fac42f158733d6a731e50490fa9951John Spurlock            mLongPressTimeout = Settings.Secure.getIntForUser(cr,
567233f4e04e32fac42f158733d6a731e50490fa9951John Spurlock                    Settings.Secure.LONG_PRESS_TIMEOUT, 500, UserHandle.USER_CURRENT);
567333f4e04e32fac42f158733d6a731e50490fa9951John Spurlock        }
567433f4e04e32fac42f158733d6a731e50490fa9951John Spurlock
567533f4e04e32fac42f158733d6a731e50490fa9951John Spurlock        public boolean suppressAdjustment(int resolvedStream, int flags) {
567633f4e04e32fac42f158733d6a731e50490fa9951John Spurlock            boolean suppress = false;
567733f4e04e32fac42f158733d6a731e50490fa9951John Spurlock            if (resolvedStream == AudioSystem.STREAM_RING && mController != null) {
567833f4e04e32fac42f158733d6a731e50490fa9951John Spurlock                final long now = SystemClock.uptimeMillis();
567933f4e04e32fac42f158733d6a731e50490fa9951John Spurlock                if ((flags & AudioManager.FLAG_SHOW_UI) != 0 && !mVisible) {
568033f4e04e32fac42f158733d6a731e50490fa9951John Spurlock                    // ui will become visible
568133f4e04e32fac42f158733d6a731e50490fa9951John Spurlock                    if (mNextLongPress < now) {
568233f4e04e32fac42f158733d6a731e50490fa9951John Spurlock                        mNextLongPress = now + mLongPressTimeout;
568333f4e04e32fac42f158733d6a731e50490fa9951John Spurlock                    }
568433f4e04e32fac42f158733d6a731e50490fa9951John Spurlock                    suppress = true;
568533f4e04e32fac42f158733d6a731e50490fa9951John Spurlock                } else if (mNextLongPress > 0) {  // in a long-press
568633f4e04e32fac42f158733d6a731e50490fa9951John Spurlock                    if (now > mNextLongPress) {
568733f4e04e32fac42f158733d6a731e50490fa9951John Spurlock                        // long press triggered, no more suppression
568833f4e04e32fac42f158733d6a731e50490fa9951John Spurlock                        mNextLongPress = 0;
568933f4e04e32fac42f158733d6a731e50490fa9951John Spurlock                    } else {
569033f4e04e32fac42f158733d6a731e50490fa9951John Spurlock                        // keep suppressing until the long press triggers
569133f4e04e32fac42f158733d6a731e50490fa9951John Spurlock                        suppress = true;
569233f4e04e32fac42f158733d6a731e50490fa9951John Spurlock                    }
569333f4e04e32fac42f158733d6a731e50490fa9951John Spurlock                }
569433f4e04e32fac42f158733d6a731e50490fa9951John Spurlock            }
569533f4e04e32fac42f158733d6a731e50490fa9951John Spurlock            return suppress;
569633f4e04e32fac42f158733d6a731e50490fa9951John Spurlock        }
569733f4e04e32fac42f158733d6a731e50490fa9951John Spurlock
569833f4e04e32fac42f158733d6a731e50490fa9951John Spurlock        public void setVisible(boolean visible) {
569933f4e04e32fac42f158733d6a731e50490fa9951John Spurlock            mVisible = visible;
5700d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik        }
5701d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik
5702d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik        public boolean isSameBinder(IVolumeController controller) {
5703d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik            return Objects.equals(asBinder(), binder(controller));
5704d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik        }
5705d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik
5706d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik        public IBinder asBinder() {
5707d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik            return binder(mController);
5708d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik        }
5709d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik
5710d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik        private static IBinder binder(IVolumeController controller) {
5711d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik            return controller == null ? null : controller.asBinder();
5712d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik        }
5713d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik
5714d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik        @Override
5715d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik        public String toString() {
571633f4e04e32fac42f158733d6a731e50490fa9951John Spurlock            return "VolumeController(" + asBinder() + ",mVisible=" + mVisible + ")";
5717d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik        }
5718d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik
5719d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik        public void postDisplaySafeVolumeWarning(int flags) {
5720d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik            if (mController == null)
5721d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik                return;
5722d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik            try {
5723d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik                mController.displaySafeVolumeWarning(flags);
5724d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik            } catch (RemoteException e) {
5725d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik                Log.w(TAG, "Error calling displaySafeVolumeWarning", e);
5726d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik            }
5727d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik        }
5728d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik
5729d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik        public void postVolumeChanged(int streamType, int flags) {
5730d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik            if (mController == null)
5731d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik                return;
5732d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik            try {
5733d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik                mController.volumeChanged(streamType, flags);
5734d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik            } catch (RemoteException e) {
5735d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik                Log.w(TAG, "Error calling volumeChanged", e);
5736d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik            }
5737d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik        }
5738d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik
5739d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik        public void postMasterVolumeChanged(int flags) {
5740d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik            if (mController == null)
5741d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik                return;
5742d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik            try {
5743d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik                mController.masterVolumeChanged(flags);
5744d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik            } catch (RemoteException e) {
5745d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik                Log.w(TAG, "Error calling masterVolumeChanged", e);
5746d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik            }
5747d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik        }
5748d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik
5749d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik        public void postMasterMuteChanged(int flags) {
5750d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik            if (mController == null)
5751d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik                return;
5752d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik            try {
5753d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik                mController.masterMuteChanged(flags);
5754d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik            } catch (RemoteException e) {
5755d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik                Log.w(TAG, "Error calling masterMuteChanged", e);
5756d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik            }
5757d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik        }
5758d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik
5759d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik        public void setLayoutDirection(int layoutDirection) {
5760d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik            if (mController == null)
5761d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik                return;
5762d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik            try {
5763d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik                mController.setLayoutDirection(layoutDirection);
5764d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik            } catch (RemoteException e) {
5765d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik                Log.w(TAG, "Error calling setLayoutDirection", e);
5766d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik            }
5767d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik        }
5768d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik
5769d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik        public void postDismiss() {
5770d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik            if (mController == null)
5771d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik                return;
5772d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik            try {
5773d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik                mController.dismiss();
5774d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik            } catch (RemoteException e) {
5775d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik                Log.w(TAG, "Error calling dismiss", e);
5776d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik            }
5777661f2cf45860d2e10924e6b69966a9afe255f28bJohn Spurlock        }
5778d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik    }
5779a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi
57800dac35af2c6aa42bcd181981b041747cfd1afa5fRoboErik    /**
57810dac35af2c6aa42bcd181981b041747cfd1afa5fRoboErik     * Interface for system components to get some extra functionality through
57820dac35af2c6aa42bcd181981b041747cfd1afa5fRoboErik     * LocalServices.
57830dac35af2c6aa42bcd181981b041747cfd1afa5fRoboErik     */
57840dac35af2c6aa42bcd181981b041747cfd1afa5fRoboErik    final class AudioServiceInternal extends AudioManagerInternal {
5785661f2cf45860d2e10924e6b69966a9afe255f28bJohn Spurlock        @Override
5786661f2cf45860d2e10924e6b69966a9afe255f28bJohn Spurlock        public void setRingerModeDelegate(RingerModeDelegate delegate) {
5787661f2cf45860d2e10924e6b69966a9afe255f28bJohn Spurlock            mRingerModeDelegate = delegate;
5788661f2cf45860d2e10924e6b69966a9afe255f28bJohn Spurlock            if (mRingerModeDelegate != null) {
5789661f2cf45860d2e10924e6b69966a9afe255f28bJohn Spurlock                setRingerModeInternal(getRingerModeInternal(), TAG + ".setRingerModeDelegate");
5790661f2cf45860d2e10924e6b69966a9afe255f28bJohn Spurlock            }
5791661f2cf45860d2e10924e6b69966a9afe255f28bJohn Spurlock        }
5792272e161c1a200900cb10b5b0cdab8ae1f123cabdRoboErik
5793272e161c1a200900cb10b5b0cdab8ae1f123cabdRoboErik        @Override
5794272e161c1a200900cb10b5b0cdab8ae1f123cabdRoboErik        public void adjustSuggestedStreamVolumeForUid(int streamType, int direction, int flags,
5795272e161c1a200900cb10b5b0cdab8ae1f123cabdRoboErik                String callingPackage, int uid) {
5796272e161c1a200900cb10b5b0cdab8ae1f123cabdRoboErik            // direction and stream type swap here because the public
5797272e161c1a200900cb10b5b0cdab8ae1f123cabdRoboErik            // adjustSuggested has a different order than the other methods.
5798272e161c1a200900cb10b5b0cdab8ae1f123cabdRoboErik            adjustSuggestedStreamVolume(direction, streamType, flags, callingPackage, uid);
5799272e161c1a200900cb10b5b0cdab8ae1f123cabdRoboErik        }
5800272e161c1a200900cb10b5b0cdab8ae1f123cabdRoboErik
58010dac35af2c6aa42bcd181981b041747cfd1afa5fRoboErik        @Override
58020dac35af2c6aa42bcd181981b041747cfd1afa5fRoboErik        public void adjustStreamVolumeForUid(int streamType, int direction, int flags,
58030dac35af2c6aa42bcd181981b041747cfd1afa5fRoboErik                String callingPackage, int uid) {
58040dac35af2c6aa42bcd181981b041747cfd1afa5fRoboErik            adjustStreamVolume(streamType, direction, flags, callingPackage, uid);
58050dac35af2c6aa42bcd181981b041747cfd1afa5fRoboErik        }
58060dac35af2c6aa42bcd181981b041747cfd1afa5fRoboErik
58070dac35af2c6aa42bcd181981b041747cfd1afa5fRoboErik        @Override
58080dac35af2c6aa42bcd181981b041747cfd1afa5fRoboErik        public void setStreamVolumeForUid(int streamType, int direction, int flags,
58090dac35af2c6aa42bcd181981b041747cfd1afa5fRoboErik                String callingPackage, int uid) {
58100dac35af2c6aa42bcd181981b041747cfd1afa5fRoboErik            setStreamVolume(streamType, direction, flags, callingPackage, uid);
58110dac35af2c6aa42bcd181981b041747cfd1afa5fRoboErik        }
5812519c7744b522aa07e12bc3244ac3de14aa2a4ad0RoboErik
5813519c7744b522aa07e12bc3244ac3de14aa2a4ad0RoboErik        @Override
5814519c7744b522aa07e12bc3244ac3de14aa2a4ad0RoboErik        public void adjustMasterVolumeForUid(int steps, int flags, String callingPackage,
5815519c7744b522aa07e12bc3244ac3de14aa2a4ad0RoboErik                int uid) {
5816519c7744b522aa07e12bc3244ac3de14aa2a4ad0RoboErik            adjustMasterVolume(steps, flags, callingPackage, uid);
5817519c7744b522aa07e12bc3244ac3de14aa2a4ad0RoboErik        }
5818661f2cf45860d2e10924e6b69966a9afe255f28bJohn Spurlock
5819661f2cf45860d2e10924e6b69966a9afe255f28bJohn Spurlock        @Override
5820661f2cf45860d2e10924e6b69966a9afe255f28bJohn Spurlock        public int getRingerModeInternal() {
5821661f2cf45860d2e10924e6b69966a9afe255f28bJohn Spurlock            return AudioService.this.getRingerModeInternal();
5822661f2cf45860d2e10924e6b69966a9afe255f28bJohn Spurlock        }
5823661f2cf45860d2e10924e6b69966a9afe255f28bJohn Spurlock
5824661f2cf45860d2e10924e6b69966a9afe255f28bJohn Spurlock        @Override
5825661f2cf45860d2e10924e6b69966a9afe255f28bJohn Spurlock        public void setRingerModeInternal(int ringerMode, String caller) {
5826661f2cf45860d2e10924e6b69966a9afe255f28bJohn Spurlock            AudioService.this.setRingerModeInternal(ringerMode, caller);
5827661f2cf45860d2e10924e6b69966a9afe255f28bJohn Spurlock        }
58287c82ced4fc5b66c09a19eed9a5499039530142fbRoboErik
58297c82ced4fc5b66c09a19eed9a5499039530142fbRoboErik        @Override
58307c82ced4fc5b66c09a19eed9a5499039530142fbRoboErik        public void setMasterMuteForUid(boolean state, int flags, String callingPackage, IBinder cb,
58317c82ced4fc5b66c09a19eed9a5499039530142fbRoboErik                int uid) {
58327c82ced4fc5b66c09a19eed9a5499039530142fbRoboErik            setMasterMuteInternal(state, flags, callingPackage, cb, uid);
58337c82ced4fc5b66c09a19eed9a5499039530142fbRoboErik        }
58340dac35af2c6aa42bcd181981b041747cfd1afa5fRoboErik    }
58350dac35af2c6aa42bcd181981b041747cfd1afa5fRoboErik
5836a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi    //==========================================================================================
5837a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi    // Audio policy management
5838a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi    //==========================================================================================
58390212be5150fb9fb3c340f3c7e51f6126372cc6f9Jean-Michel Trivi    public String registerAudioPolicy(AudioPolicyConfig policyConfig, IAudioPolicyCallback pcb,
58400212be5150fb9fb3c340f3c7e51f6126372cc6f9Jean-Michel Trivi            boolean hasFocusListener) {
58410212be5150fb9fb3c340f3c7e51f6126372cc6f9Jean-Michel Trivi        if (DEBUG_AP) Log.d(TAG, "registerAudioPolicy for " + pcb.asBinder()
58420212be5150fb9fb3c340f3c7e51f6126372cc6f9Jean-Michel Trivi                + " with config:" + policyConfig);
58438fdb0d4defb6ee2ca8057d3442ead36b408b6c17Jean-Michel Trivi        String regId = null;
58440212be5150fb9fb3c340f3c7e51f6126372cc6f9Jean-Michel Trivi        // error handling
5845a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi        boolean hasPermissionForPolicy =
58460212be5150fb9fb3c340f3c7e51f6126372cc6f9Jean-Michel Trivi                (PackageManager.PERMISSION_GRANTED == mContext.checkCallingPermission(
5847a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi                        android.Manifest.permission.MODIFY_AUDIO_ROUTING));
5848a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi        if (!hasPermissionForPolicy) {
5849a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi            Slog.w(TAG, "Can't register audio policy for pid " + Binder.getCallingPid() + " / uid "
5850a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi                    + Binder.getCallingUid() + ", need MODIFY_AUDIO_ROUTING");
58518fdb0d4defb6ee2ca8057d3442ead36b408b6c17Jean-Michel Trivi            return null;
5852a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi        }
58530212be5150fb9fb3c340f3c7e51f6126372cc6f9Jean-Michel Trivi
5854a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi        synchronized (mAudioPolicies) {
5855a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi            try {
58560212be5150fb9fb3c340f3c7e51f6126372cc6f9Jean-Michel Trivi                if (mAudioPolicies.containsKey(pcb.asBinder())) {
58571b3541d5eedb332ea01066b4a78a2d06d5304044Jean-Michel Trivi                    Slog.e(TAG, "Cannot re-register policy");
58581b3541d5eedb332ea01066b4a78a2d06d5304044Jean-Michel Trivi                    return null;
58591b3541d5eedb332ea01066b4a78a2d06d5304044Jean-Michel Trivi                }
58600212be5150fb9fb3c340f3c7e51f6126372cc6f9Jean-Michel Trivi                AudioPolicyProxy app = new AudioPolicyProxy(policyConfig, pcb, hasFocusListener);
58610212be5150fb9fb3c340f3c7e51f6126372cc6f9Jean-Michel Trivi                pcb.asBinder().linkToDeath(app, 0/*flags*/);
58620212be5150fb9fb3c340f3c7e51f6126372cc6f9Jean-Michel Trivi                regId = app.getRegistrationId();
58630212be5150fb9fb3c340f3c7e51f6126372cc6f9Jean-Michel Trivi                mAudioPolicies.put(pcb.asBinder(), app);
5864a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi            } catch (RemoteException e) {
5865a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi                // audio policy owner has already died!
58660212be5150fb9fb3c340f3c7e51f6126372cc6f9Jean-Michel Trivi                Slog.w(TAG, "Audio policy registration failed, could not link to " + pcb +
5867a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi                        " binder death", e);
58688fdb0d4defb6ee2ca8057d3442ead36b408b6c17Jean-Michel Trivi                return null;
5869a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi            }
5870a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi        }
58718fdb0d4defb6ee2ca8057d3442ead36b408b6c17Jean-Michel Trivi        return regId;
5872a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi    }
58738fdb0d4defb6ee2ca8057d3442ead36b408b6c17Jean-Michel Trivi
58740212be5150fb9fb3c340f3c7e51f6126372cc6f9Jean-Michel Trivi    public void unregisterAudioPolicyAsync(IAudioPolicyCallback pcb) {
58750212be5150fb9fb3c340f3c7e51f6126372cc6f9Jean-Michel Trivi        if (DEBUG_AP) Log.d(TAG, "unregisterAudioPolicyAsync for " + pcb.asBinder());
5876a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi        synchronized (mAudioPolicies) {
58770212be5150fb9fb3c340f3c7e51f6126372cc6f9Jean-Michel Trivi            AudioPolicyProxy app = mAudioPolicies.remove(pcb.asBinder());
5878a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi            if (app == null) {
5879a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi                Slog.w(TAG, "Trying to unregister unknown audio policy for pid "
5880a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi                        + Binder.getCallingPid() + " / uid " + Binder.getCallingUid());
58811b3541d5eedb332ea01066b4a78a2d06d5304044Jean-Michel Trivi                return;
5882a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi            } else {
58830212be5150fb9fb3c340f3c7e51f6126372cc6f9Jean-Michel Trivi                pcb.asBinder().unlinkToDeath(app, 0/*flags*/);
5884a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi            }
58850212be5150fb9fb3c340f3c7e51f6126372cc6f9Jean-Michel Trivi            app.release();
5886a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi        }
58878fdb0d4defb6ee2ca8057d3442ead36b408b6c17Jean-Michel Trivi        // TODO implement clearing mix attribute matching info in native audio policy
5888a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi    }
5889a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi
58900212be5150fb9fb3c340f3c7e51f6126372cc6f9Jean-Michel Trivi    public int setFocusPropertiesForPolicy(int duckingBehavior, IAudioPolicyCallback pcb) {
58910212be5150fb9fb3c340f3c7e51f6126372cc6f9Jean-Michel Trivi        if (DEBUG_AP) Log.d(TAG, "setFocusPropertiesForPolicy() duck behavior=" + duckingBehavior
58920212be5150fb9fb3c340f3c7e51f6126372cc6f9Jean-Michel Trivi                + " policy " +  pcb.asBinder());
58930212be5150fb9fb3c340f3c7e51f6126372cc6f9Jean-Michel Trivi        // error handling
58940212be5150fb9fb3c340f3c7e51f6126372cc6f9Jean-Michel Trivi        boolean hasPermissionForPolicy =
58950212be5150fb9fb3c340f3c7e51f6126372cc6f9Jean-Michel Trivi                (PackageManager.PERMISSION_GRANTED == mContext.checkCallingPermission(
58960212be5150fb9fb3c340f3c7e51f6126372cc6f9Jean-Michel Trivi                        android.Manifest.permission.MODIFY_AUDIO_ROUTING));
58970212be5150fb9fb3c340f3c7e51f6126372cc6f9Jean-Michel Trivi        if (!hasPermissionForPolicy) {
58980212be5150fb9fb3c340f3c7e51f6126372cc6f9Jean-Michel Trivi            Slog.w(TAG, "Cannot change audio policy ducking handling for pid " +
58990212be5150fb9fb3c340f3c7e51f6126372cc6f9Jean-Michel Trivi                    + Binder.getCallingPid() + " / uid "
59000212be5150fb9fb3c340f3c7e51f6126372cc6f9Jean-Michel Trivi                    + Binder.getCallingUid() + ", need MODIFY_AUDIO_ROUTING");
59010212be5150fb9fb3c340f3c7e51f6126372cc6f9Jean-Michel Trivi            return AudioManager.ERROR;
59020212be5150fb9fb3c340f3c7e51f6126372cc6f9Jean-Michel Trivi        }
59030212be5150fb9fb3c340f3c7e51f6126372cc6f9Jean-Michel Trivi
59040212be5150fb9fb3c340f3c7e51f6126372cc6f9Jean-Michel Trivi        synchronized (mAudioPolicies) {
59050212be5150fb9fb3c340f3c7e51f6126372cc6f9Jean-Michel Trivi            if (!mAudioPolicies.containsKey(pcb.asBinder())) {
59060212be5150fb9fb3c340f3c7e51f6126372cc6f9Jean-Michel Trivi                Slog.e(TAG, "Cannot change audio policy focus properties, unregistered policy");
59070212be5150fb9fb3c340f3c7e51f6126372cc6f9Jean-Michel Trivi                return AudioManager.ERROR;
59080212be5150fb9fb3c340f3c7e51f6126372cc6f9Jean-Michel Trivi            }
59090212be5150fb9fb3c340f3c7e51f6126372cc6f9Jean-Michel Trivi            final AudioPolicyProxy app = mAudioPolicies.get(pcb.asBinder());
59100212be5150fb9fb3c340f3c7e51f6126372cc6f9Jean-Michel Trivi            if (duckingBehavior == AudioPolicy.FOCUS_POLICY_DUCKING_IN_POLICY) {
59110212be5150fb9fb3c340f3c7e51f6126372cc6f9Jean-Michel Trivi                // is there already one policy managing ducking?
59120212be5150fb9fb3c340f3c7e51f6126372cc6f9Jean-Michel Trivi                for(AudioPolicyProxy policy : mAudioPolicies.values()) {
59130212be5150fb9fb3c340f3c7e51f6126372cc6f9Jean-Michel Trivi                    if (policy.mFocusDuckBehavior == AudioPolicy.FOCUS_POLICY_DUCKING_IN_POLICY) {
59140212be5150fb9fb3c340f3c7e51f6126372cc6f9Jean-Michel Trivi                        Slog.e(TAG, "Cannot change audio policy ducking behavior, already handled");
59150212be5150fb9fb3c340f3c7e51f6126372cc6f9Jean-Michel Trivi                        return AudioManager.ERROR;
59160212be5150fb9fb3c340f3c7e51f6126372cc6f9Jean-Michel Trivi                    }
59170212be5150fb9fb3c340f3c7e51f6126372cc6f9Jean-Michel Trivi                }
59180212be5150fb9fb3c340f3c7e51f6126372cc6f9Jean-Michel Trivi            }
59190212be5150fb9fb3c340f3c7e51f6126372cc6f9Jean-Michel Trivi            app.mFocusDuckBehavior = duckingBehavior;
59200212be5150fb9fb3c340f3c7e51f6126372cc6f9Jean-Michel Trivi            mMediaFocusControl.setDuckingInExtPolicyAvailable(
59210212be5150fb9fb3c340f3c7e51f6126372cc6f9Jean-Michel Trivi                    duckingBehavior == AudioPolicy.FOCUS_POLICY_DUCKING_IN_POLICY);
59220212be5150fb9fb3c340f3c7e51f6126372cc6f9Jean-Michel Trivi        }
59230212be5150fb9fb3c340f3c7e51f6126372cc6f9Jean-Michel Trivi        return AudioManager.SUCCESS;
59240212be5150fb9fb3c340f3c7e51f6126372cc6f9Jean-Michel Trivi    }
59250212be5150fb9fb3c340f3c7e51f6126372cc6f9Jean-Michel Trivi
59261b3541d5eedb332ea01066b4a78a2d06d5304044Jean-Michel Trivi    private void dumpAudioPolicies(PrintWriter pw) {
59271b3541d5eedb332ea01066b4a78a2d06d5304044Jean-Michel Trivi        pw.println("\nAudio policies:");
59281b3541d5eedb332ea01066b4a78a2d06d5304044Jean-Michel Trivi        synchronized (mAudioPolicies) {
59291b3541d5eedb332ea01066b4a78a2d06d5304044Jean-Michel Trivi            for(AudioPolicyProxy policy : mAudioPolicies.values()) {
59301b3541d5eedb332ea01066b4a78a2d06d5304044Jean-Michel Trivi                pw.println(policy.toLogFriendlyString());
59311b3541d5eedb332ea01066b4a78a2d06d5304044Jean-Michel Trivi            }
59321b3541d5eedb332ea01066b4a78a2d06d5304044Jean-Michel Trivi        }
59331b3541d5eedb332ea01066b4a78a2d06d5304044Jean-Michel Trivi    }
59341b3541d5eedb332ea01066b4a78a2d06d5304044Jean-Michel Trivi
5935958876fe55ea0fdeb73c72240a2f2bab32833443Jean-Michel Trivi    //======================
5936958876fe55ea0fdeb73c72240a2f2bab32833443Jean-Michel Trivi    // Audio policy proxy
5937958876fe55ea0fdeb73c72240a2f2bab32833443Jean-Michel Trivi    //======================
59388fdb0d4defb6ee2ca8057d3442ead36b408b6c17Jean-Michel Trivi    /**
59391b3541d5eedb332ea01066b4a78a2d06d5304044Jean-Michel Trivi     * This internal class inherits from AudioPolicyConfig, each instance contains all the
59401b3541d5eedb332ea01066b4a78a2d06d5304044Jean-Michel Trivi     * mixes of an AudioPolicy and their configurations.
59418fdb0d4defb6ee2ca8057d3442ead36b408b6c17Jean-Michel Trivi     */
59428fdb0d4defb6ee2ca8057d3442ead36b408b6c17Jean-Michel Trivi    public class AudioPolicyProxy extends AudioPolicyConfig implements IBinder.DeathRecipient {
5943a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi        private static final String TAG = "AudioPolicyProxy";
5944a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi        AudioPolicyConfig mConfig;
59450212be5150fb9fb3c340f3c7e51f6126372cc6f9Jean-Michel Trivi        IAudioPolicyCallback mPolicyToken;
59460212be5150fb9fb3c340f3c7e51f6126372cc6f9Jean-Michel Trivi        boolean mHasFocusListener;
59470212be5150fb9fb3c340f3c7e51f6126372cc6f9Jean-Michel Trivi        /**
59480212be5150fb9fb3c340f3c7e51f6126372cc6f9Jean-Michel Trivi         * Audio focus ducking behavior for an audio policy.
59490212be5150fb9fb3c340f3c7e51f6126372cc6f9Jean-Michel Trivi         * This variable reflects the value that was successfully set in
59500212be5150fb9fb3c340f3c7e51f6126372cc6f9Jean-Michel Trivi         * {@link AudioService#setFocusPropertiesForPolicy(int, IAudioPolicyCallback)}. This
59510212be5150fb9fb3c340f3c7e51f6126372cc6f9Jean-Michel Trivi         * implies that a value of FOCUS_POLICY_DUCKING_IN_POLICY means the corresponding policy
59520212be5150fb9fb3c340f3c7e51f6126372cc6f9Jean-Michel Trivi         * is handling ducking for audio focus.
59530212be5150fb9fb3c340f3c7e51f6126372cc6f9Jean-Michel Trivi         */
59540212be5150fb9fb3c340f3c7e51f6126372cc6f9Jean-Michel Trivi        int mFocusDuckBehavior = AudioPolicy.FOCUS_POLICY_DUCKING_DEFAULT;
59550212be5150fb9fb3c340f3c7e51f6126372cc6f9Jean-Michel Trivi
59560212be5150fb9fb3c340f3c7e51f6126372cc6f9Jean-Michel Trivi        AudioPolicyProxy(AudioPolicyConfig config, IAudioPolicyCallback token,
59570212be5150fb9fb3c340f3c7e51f6126372cc6f9Jean-Michel Trivi                boolean hasFocusListener) {
59588fdb0d4defb6ee2ca8057d3442ead36b408b6c17Jean-Michel Trivi            super(config);
59591b3541d5eedb332ea01066b4a78a2d06d5304044Jean-Michel Trivi            setRegistration(new String(config.hashCode() + ":ap:" + mAudioPolicyCounter++));
59600212be5150fb9fb3c340f3c7e51f6126372cc6f9Jean-Michel Trivi            mPolicyToken = token;
59610212be5150fb9fb3c340f3c7e51f6126372cc6f9Jean-Michel Trivi            mHasFocusListener = hasFocusListener;
59620212be5150fb9fb3c340f3c7e51f6126372cc6f9Jean-Michel Trivi            if (mHasFocusListener) {
59630212be5150fb9fb3c340f3c7e51f6126372cc6f9Jean-Michel Trivi                mMediaFocusControl.addFocusFollower(mPolicyToken);
59640212be5150fb9fb3c340f3c7e51f6126372cc6f9Jean-Michel Trivi            }
59657f5eb9fe3c10d8d83ff0e2b0fc60a05c2e6d5b02Eric Laurent            connectMixes();
5966a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi        }
5967a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi
5968a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi        public void binderDied() {
5969a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi            synchronized (mAudioPolicies) {
59700212be5150fb9fb3c340f3c7e51f6126372cc6f9Jean-Michel Trivi                Log.i(TAG, "audio policy " + mPolicyToken + " died");
59710212be5150fb9fb3c340f3c7e51f6126372cc6f9Jean-Michel Trivi                release();
59720212be5150fb9fb3c340f3c7e51f6126372cc6f9Jean-Michel Trivi                mAudioPolicies.remove(mPolicyToken.asBinder());
59738fdb0d4defb6ee2ca8057d3442ead36b408b6c17Jean-Michel Trivi            }
59748fdb0d4defb6ee2ca8057d3442ead36b408b6c17Jean-Michel Trivi        }
59758fdb0d4defb6ee2ca8057d3442ead36b408b6c17Jean-Michel Trivi
59760212be5150fb9fb3c340f3c7e51f6126372cc6f9Jean-Michel Trivi        String getRegistrationId() {
59771b3541d5eedb332ea01066b4a78a2d06d5304044Jean-Michel Trivi            return getRegistration();
59788fdb0d4defb6ee2ca8057d3442ead36b408b6c17Jean-Michel Trivi        }
59798fdb0d4defb6ee2ca8057d3442ead36b408b6c17Jean-Michel Trivi
59800212be5150fb9fb3c340f3c7e51f6126372cc6f9Jean-Michel Trivi        void release() {
59810212be5150fb9fb3c340f3c7e51f6126372cc6f9Jean-Michel Trivi            if (mFocusDuckBehavior == AudioPolicy.FOCUS_POLICY_DUCKING_IN_POLICY) {
59820212be5150fb9fb3c340f3c7e51f6126372cc6f9Jean-Michel Trivi                mMediaFocusControl.setDuckingInExtPolicyAvailable(false);
59830212be5150fb9fb3c340f3c7e51f6126372cc6f9Jean-Michel Trivi            }
59840212be5150fb9fb3c340f3c7e51f6126372cc6f9Jean-Michel Trivi            if (mHasFocusListener) {
59850212be5150fb9fb3c340f3c7e51f6126372cc6f9Jean-Michel Trivi                mMediaFocusControl.removeFocusFollower(mPolicyToken);
59860212be5150fb9fb3c340f3c7e51f6126372cc6f9Jean-Michel Trivi            }
59877f5eb9fe3c10d8d83ff0e2b0fc60a05c2e6d5b02Eric Laurent            AudioSystem.registerPolicyMixes(mMixes, false);
59888fdb0d4defb6ee2ca8057d3442ead36b408b6c17Jean-Michel Trivi        }
59898fdb0d4defb6ee2ca8057d3442ead36b408b6c17Jean-Michel Trivi
59907f5eb9fe3c10d8d83ff0e2b0fc60a05c2e6d5b02Eric Laurent        void connectMixes() {
59917f5eb9fe3c10d8d83ff0e2b0fc60a05c2e6d5b02Eric Laurent            AudioSystem.registerPolicyMixes(mMixes, true);
5992a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi        }
5993a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi    };
5994a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi
5995a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi    private HashMap<IBinder, AudioPolicyProxy> mAudioPolicies =
5996a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi            new HashMap<IBinder, AudioPolicyProxy>();
59978fdb0d4defb6ee2ca8057d3442ead36b408b6c17Jean-Michel Trivi    private int mAudioPolicyCounter = 0; // always accessed synchronized on mAudioPolicies
59989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
5999