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) {
1403267603f3bbf7a6a707aaf055297ae0c3afae51d8Christopher Tate        intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
14045ac72a29593ab9a20337a2225df52bdf4754be02Dianne Hackborn        final long ident = Binder.clearCallingIdentity();
14055ac72a29593ab9a20337a2225df52bdf4754be02Dianne Hackborn        try {
14065ac72a29593ab9a20337a2225df52bdf4754be02Dianne Hackborn            mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
14075ac72a29593ab9a20337a2225df52bdf4754be02Dianne Hackborn        } finally {
14085ac72a29593ab9a20337a2225df52bdf4754be02Dianne Hackborn            Binder.restoreCallingIdentity(ident);
14095ac72a29593ab9a20337a2225df52bdf4754be02Dianne Hackborn        }
14105ac72a29593ab9a20337a2225df52bdf4754be02Dianne Hackborn    }
14115ac72a29593ab9a20337a2225df52bdf4754be02Dianne Hackborn
14125ac72a29593ab9a20337a2225df52bdf4754be02Dianne Hackborn    private void sendStickyBroadcastToAll(Intent intent) {
14135ac72a29593ab9a20337a2225df52bdf4754be02Dianne Hackborn        final long ident = Binder.clearCallingIdentity();
14145ac72a29593ab9a20337a2225df52bdf4754be02Dianne Hackborn        try {
14155ac72a29593ab9a20337a2225df52bdf4754be02Dianne Hackborn            mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
14165ac72a29593ab9a20337a2225df52bdf4754be02Dianne Hackborn        } finally {
14175ac72a29593ab9a20337a2225df52bdf4754be02Dianne Hackborn            Binder.restoreCallingIdentity(ident);
14185ac72a29593ab9a20337a2225df52bdf4754be02Dianne Hackborn        }
14195ac72a29593ab9a20337a2225df52bdf4754be02Dianne Hackborn    }
14205ac72a29593ab9a20337a2225df52bdf4754be02Dianne Hackborn
142125101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent    // UI update and Broadcast Intent
142225101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent    private void sendVolumeUpdate(int streamType, int oldIndex, int index, int flags) {
1423212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent        if (!isPlatformVoice() && (streamType == AudioSystem.STREAM_RING)) {
142425101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent            streamType = AudioSystem.STREAM_NOTIFICATION;
142525101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent        }
142625101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent
1427336cdb488ff0e5ec6709c66f55072d3ad22b82edJinsuk Kim        if (streamType == AudioSystem.STREAM_MUSIC) {
1428336cdb488ff0e5ec6709c66f55072d3ad22b82edJinsuk Kim            flags = updateFlagsForSystemAudio(flags);
14291a6be6ed3962735f12dbd5ce1bca758120c8fb8dJungshik Jang        }
14303346a802087f621c6441bc512dfcc17b07143fc6John Spurlock        mVolumeController.postVolumeChanged(streamType, flags);
143125101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent
14324bbcc6549738f3d69831b2bd9eb4accec3e9920eEric Laurent        if ((flags & AudioManager.FLAG_FIXED_VOLUME) == 0) {
14334bbcc6549738f3d69831b2bd9eb4accec3e9920eEric Laurent            oldIndex = (oldIndex + 5) / 10;
14344bbcc6549738f3d69831b2bd9eb4accec3e9920eEric Laurent            index = (index + 5) / 10;
14354bbcc6549738f3d69831b2bd9eb4accec3e9920eEric Laurent            Intent intent = new Intent(AudioManager.VOLUME_CHANGED_ACTION);
14364bbcc6549738f3d69831b2bd9eb4accec3e9920eEric Laurent            intent.putExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, streamType);
14374bbcc6549738f3d69831b2bd9eb4accec3e9920eEric Laurent            intent.putExtra(AudioManager.EXTRA_VOLUME_STREAM_VALUE, index);
14384bbcc6549738f3d69831b2bd9eb4accec3e9920eEric Laurent            intent.putExtra(AudioManager.EXTRA_PREV_VOLUME_STREAM_VALUE, oldIndex);
14394bbcc6549738f3d69831b2bd9eb4accec3e9920eEric Laurent            sendBroadcastToAll(intent);
14404bbcc6549738f3d69831b2bd9eb4accec3e9920eEric Laurent        }
14419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
14429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1443336cdb488ff0e5ec6709c66f55072d3ad22b82edJinsuk Kim    // If Hdmi-CEC system audio mode is on, we show volume bar only when TV
1444336cdb488ff0e5ec6709c66f55072d3ad22b82edJinsuk Kim    // receives volume notification from Audio Receiver.
1445336cdb488ff0e5ec6709c66f55072d3ad22b82edJinsuk Kim    private int updateFlagsForSystemAudio(int flags) {
1446336cdb488ff0e5ec6709c66f55072d3ad22b82edJinsuk Kim        if (mHdmiTvClient != null) {
1447336cdb488ff0e5ec6709c66f55072d3ad22b82edJinsuk Kim            synchronized (mHdmiTvClient) {
1448336cdb488ff0e5ec6709c66f55072d3ad22b82edJinsuk Kim                if (mHdmiSystemAudioSupported &&
1449336cdb488ff0e5ec6709c66f55072d3ad22b82edJinsuk Kim                        ((flags & AudioManager.FLAG_HDMI_SYSTEM_AUDIO_VOLUME) == 0)) {
1450336cdb488ff0e5ec6709c66f55072d3ad22b82edJinsuk Kim                    flags &= ~AudioManager.FLAG_SHOW_UI;
1451336cdb488ff0e5ec6709c66f55072d3ad22b82edJinsuk Kim                }
1452336cdb488ff0e5ec6709c66f55072d3ad22b82edJinsuk Kim            }
1453336cdb488ff0e5ec6709c66f55072d3ad22b82edJinsuk Kim        }
1454336cdb488ff0e5ec6709c66f55072d3ad22b82edJinsuk Kim        return flags;
1455336cdb488ff0e5ec6709c66f55072d3ad22b82edJinsuk Kim    }
1456336cdb488ff0e5ec6709c66f55072d3ad22b82edJinsuk Kim
14570dc37cce9d564ae43883c8dc8672b9266b881e63Mike Lockwood    // UI update and Broadcast Intent
14580dc37cce9d564ae43883c8dc8672b9266b881e63Mike Lockwood    private void sendMasterVolumeUpdate(int flags, int oldVolume, int newVolume) {
1459336cdb488ff0e5ec6709c66f55072d3ad22b82edJinsuk Kim        mVolumeController.postMasterVolumeChanged(updateFlagsForSystemAudio(flags));
14600dc37cce9d564ae43883c8dc8672b9266b881e63Mike Lockwood
14610dc37cce9d564ae43883c8dc8672b9266b881e63Mike Lockwood        Intent intent = new Intent(AudioManager.MASTER_VOLUME_CHANGED_ACTION);
14620dc37cce9d564ae43883c8dc8672b9266b881e63Mike Lockwood        intent.putExtra(AudioManager.EXTRA_PREV_MASTER_VOLUME_VALUE, oldVolume);
14630dc37cce9d564ae43883c8dc8672b9266b881e63Mike Lockwood        intent.putExtra(AudioManager.EXTRA_MASTER_VOLUME_VALUE, newVolume);
14645ac72a29593ab9a20337a2225df52bdf4754be02Dianne Hackborn        sendBroadcastToAll(intent);
14650dc37cce9d564ae43883c8dc8672b9266b881e63Mike Lockwood    }
14660dc37cce9d564ae43883c8dc8672b9266b881e63Mike Lockwood
14670dc37cce9d564ae43883c8dc8672b9266b881e63Mike Lockwood    // UI update and Broadcast Intent
14680dc37cce9d564ae43883c8dc8672b9266b881e63Mike Lockwood    private void sendMasterMuteUpdate(boolean muted, int flags) {
1469336cdb488ff0e5ec6709c66f55072d3ad22b82edJinsuk Kim        mVolumeController.postMasterMuteChanged(updateFlagsForSystemAudio(flags));
147057978ed86286a33d5b1a0fd000ca3406ba9d87b3Justin Koh        broadcastMasterMuteStatus(muted);
147157978ed86286a33d5b1a0fd000ca3406ba9d87b3Justin Koh    }
14720dc37cce9d564ae43883c8dc8672b9266b881e63Mike Lockwood
147357978ed86286a33d5b1a0fd000ca3406ba9d87b3Justin Koh    private void broadcastMasterMuteStatus(boolean muted) {
14740dc37cce9d564ae43883c8dc8672b9266b881e63Mike Lockwood        Intent intent = new Intent(AudioManager.MASTER_MUTE_CHANGED_ACTION);
14750dc37cce9d564ae43883c8dc8672b9266b881e63Mike Lockwood        intent.putExtra(AudioManager.EXTRA_MASTER_VOLUME_MUTED, muted);
147657978ed86286a33d5b1a0fd000ca3406ba9d87b3Justin Koh        intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT
147757978ed86286a33d5b1a0fd000ca3406ba9d87b3Justin Koh                | Intent.FLAG_RECEIVER_REPLACE_PENDING);
14785ac72a29593ab9a20337a2225df52bdf4754be02Dianne Hackborn        sendStickyBroadcastToAll(intent);
14790dc37cce9d564ae43883c8dc8672b9266b881e63Mike Lockwood    }
14800dc37cce9d564ae43883c8dc8672b9266b881e63Mike Lockwood
14819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
14829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Sets the stream state's index, and posts a message to set system volume.
14839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * This will not call out to the UI. Assumes a valid stream type.
14849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
14859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param streamType Type of the stream
14869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param index Desired volume index of the stream
14879bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent     * @param device the device whose volume must be changed
14889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param force If true, set the volume even if the desired volume is same
14899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * as the current volume.
14909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
14919bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent    private void setStreamVolumeInt(int streamType,
14929bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                                    int index,
14939bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                                    int device,
149442b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                                    boolean force) {
14959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        VolumeStreamState streamState = mStreamStates[streamType];
14965b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent
149742b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent        if (streamState.setIndex(index, device) || force) {
149842b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent            // Post message to set system volume (it in turn will post a message
149942b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent            // to persist).
150042b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent            sendMsg(mAudioHandler,
150142b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                    MSG_SET_DEVICE_VOLUME,
150242b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                    SENDMSG_QUEUE,
150342b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                    device,
150442b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                    0,
150542b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                    streamState,
150642b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                    0);
15079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
15089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
15099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
15109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** @see AudioManager#setStreamSolo(int, boolean) */
15119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void setStreamSolo(int streamType, boolean state, IBinder cb) {
151283a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent        if (mUseFixedVolume) {
151383a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent            return;
151483a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent        }
15154fb3b602156d093c1082be88f2f016f3a791a978Eric Laurent        int streamAlias = mStreamVolumeAlias[streamType];
15169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        for (int stream = 0; stream < mStreamStates.length; stream++) {
15174fb3b602156d093c1082be88f2f016f3a791a978Eric Laurent            if (!isStreamAffectedByMute(streamAlias) || streamAlias == mStreamVolumeAlias[stream]) {
15184fb3b602156d093c1082be88f2f016f3a791a978Eric Laurent                continue;
15194fb3b602156d093c1082be88f2f016f3a791a978Eric Laurent            }
15209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mStreamStates[stream].mute(cb, state);
15219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         }
15229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
15239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
15249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** @see AudioManager#setStreamMute(int, boolean) */
15259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void setStreamMute(int streamType, boolean state, IBinder cb) {
152683a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent        if (mUseFixedVolume) {
152783a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent            return;
152883a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent        }
15297c82ced4fc5b66c09a19eed9a5499039530142fbRoboErik        if (streamType == AudioManager.USE_DEFAULT_STREAM_TYPE) {
15307c82ced4fc5b66c09a19eed9a5499039530142fbRoboErik            streamType = getActiveStreamType(streamType);
15317c82ced4fc5b66c09a19eed9a5499039530142fbRoboErik        }
15324fb3b602156d093c1082be88f2f016f3a791a978Eric Laurent        int streamAlias = mStreamVolumeAlias[streamType];
15334fb3b602156d093c1082be88f2f016f3a791a978Eric Laurent        if (isStreamAffectedByMute(streamAlias)) {
15344fb3b602156d093c1082be88f2f016f3a791a978Eric Laurent            if (streamAlias == AudioSystem.STREAM_MUSIC) {
1535336cdb488ff0e5ec6709c66f55072d3ad22b82edJinsuk Kim                setSystemAudioMute(state);
1536336cdb488ff0e5ec6709c66f55072d3ad22b82edJinsuk Kim            }
15374fb3b602156d093c1082be88f2f016f3a791a978Eric Laurent            for (int stream = 0; stream < mStreamStates.length; stream++) {
15384fb3b602156d093c1082be88f2f016f3a791a978Eric Laurent                if (streamAlias == mStreamVolumeAlias[stream]) {
15394fb3b602156d093c1082be88f2f016f3a791a978Eric Laurent                    mStreamStates[stream].mute(cb, state);
15404fb3b602156d093c1082be88f2f016f3a791a978Eric Laurent
15414fb3b602156d093c1082be88f2f016f3a791a978Eric Laurent                    Intent intent = new Intent(AudioManager.STREAM_MUTE_CHANGED_ACTION);
15424fb3b602156d093c1082be88f2f016f3a791a978Eric Laurent                    intent.putExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, stream);
15434fb3b602156d093c1082be88f2f016f3a791a978Eric Laurent                    intent.putExtra(AudioManager.EXTRA_STREAM_VOLUME_MUTED, state);
15444fb3b602156d093c1082be88f2f016f3a791a978Eric Laurent                    sendBroadcastToAll(intent);
15454fb3b602156d093c1082be88f2f016f3a791a978Eric Laurent                }
15464fb3b602156d093c1082be88f2f016f3a791a978Eric Laurent            }
1547336cdb488ff0e5ec6709c66f55072d3ad22b82edJinsuk Kim        }
1548336cdb488ff0e5ec6709c66f55072d3ad22b82edJinsuk Kim    }
1549336cdb488ff0e5ec6709c66f55072d3ad22b82edJinsuk Kim
1550336cdb488ff0e5ec6709c66f55072d3ad22b82edJinsuk Kim    private void setSystemAudioMute(boolean state) {
1551336cdb488ff0e5ec6709c66f55072d3ad22b82edJinsuk Kim        if (mHdmiManager == null || mHdmiTvClient == null) return;
1552336cdb488ff0e5ec6709c66f55072d3ad22b82edJinsuk Kim        synchronized (mHdmiManager) {
155348cbf292ba9ad550af7e44d950a441b1812428e2Jinsuk Kim            if (!mHdmiSystemAudioSupported) return;
155448cbf292ba9ad550af7e44d950a441b1812428e2Jinsuk Kim            synchronized (mHdmiTvClient) {
155548cbf292ba9ad550af7e44d950a441b1812428e2Jinsuk Kim                final long token = Binder.clearCallingIdentity();
155648cbf292ba9ad550af7e44d950a441b1812428e2Jinsuk Kim                try {
155748cbf292ba9ad550af7e44d950a441b1812428e2Jinsuk Kim                    mHdmiTvClient.setSystemAudioMute(state);
155848cbf292ba9ad550af7e44d950a441b1812428e2Jinsuk Kim                } finally {
155948cbf292ba9ad550af7e44d950a441b1812428e2Jinsuk Kim                    Binder.restoreCallingIdentity(token);
156041d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang                }
156141d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang            }
15629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
15639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
15649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
156525101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent    /** get stream mute state. */
156625101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent    public boolean isStreamMute(int streamType) {
15677c82ced4fc5b66c09a19eed9a5499039530142fbRoboErik        if (streamType == AudioManager.USE_DEFAULT_STREAM_TYPE) {
15687c82ced4fc5b66c09a19eed9a5499039530142fbRoboErik            streamType = getActiveStreamType(streamType);
15697c82ced4fc5b66c09a19eed9a5499039530142fbRoboErik        }
15708fa4d6f585f40ff5cf5f9bed316d92c64a306f21Eric Laurent        synchronized (VolumeStreamState.class) {
15718fa4d6f585f40ff5cf5f9bed316d92c64a306f21Eric Laurent            return mStreamStates[streamType].isMuted_syncVSS();
15728fa4d6f585f40ff5cf5f9bed316d92c64a306f21Eric Laurent        }
157325101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent    }
157425101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent
1575ba5270b88798c66fefc17a1b25b27894e4fb7862Jean-Michel Trivi    private class RmtSbmxFullVolDeathHandler implements IBinder.DeathRecipient {
1576ba5270b88798c66fefc17a1b25b27894e4fb7862Jean-Michel Trivi        private IBinder mICallback; // To be notified of client's death
1577ba5270b88798c66fefc17a1b25b27894e4fb7862Jean-Michel Trivi
1578ba5270b88798c66fefc17a1b25b27894e4fb7862Jean-Michel Trivi        RmtSbmxFullVolDeathHandler(IBinder cb) {
1579ba5270b88798c66fefc17a1b25b27894e4fb7862Jean-Michel Trivi            mICallback = cb;
1580ba5270b88798c66fefc17a1b25b27894e4fb7862Jean-Michel Trivi            try {
1581ba5270b88798c66fefc17a1b25b27894e4fb7862Jean-Michel Trivi                cb.linkToDeath(this, 0/*flags*/);
1582ba5270b88798c66fefc17a1b25b27894e4fb7862Jean-Michel Trivi            } catch (RemoteException e) {
1583ba5270b88798c66fefc17a1b25b27894e4fb7862Jean-Michel Trivi                Log.e(TAG, "can't link to death", e);
1584ba5270b88798c66fefc17a1b25b27894e4fb7862Jean-Michel Trivi            }
1585ba5270b88798c66fefc17a1b25b27894e4fb7862Jean-Michel Trivi        }
1586ba5270b88798c66fefc17a1b25b27894e4fb7862Jean-Michel Trivi
1587ba5270b88798c66fefc17a1b25b27894e4fb7862Jean-Michel Trivi        boolean isHandlerFor(IBinder cb) {
1588ba5270b88798c66fefc17a1b25b27894e4fb7862Jean-Michel Trivi            return mICallback.equals(cb);
1589ba5270b88798c66fefc17a1b25b27894e4fb7862Jean-Michel Trivi        }
1590ba5270b88798c66fefc17a1b25b27894e4fb7862Jean-Michel Trivi
1591ba5270b88798c66fefc17a1b25b27894e4fb7862Jean-Michel Trivi        void forget() {
1592ba5270b88798c66fefc17a1b25b27894e4fb7862Jean-Michel Trivi            try {
1593ba5270b88798c66fefc17a1b25b27894e4fb7862Jean-Michel Trivi                mICallback.unlinkToDeath(this, 0/*flags*/);
1594ba5270b88798c66fefc17a1b25b27894e4fb7862Jean-Michel Trivi            } catch (NoSuchElementException e) {
1595ba5270b88798c66fefc17a1b25b27894e4fb7862Jean-Michel Trivi                Log.e(TAG, "error unlinking to death", e);
1596ba5270b88798c66fefc17a1b25b27894e4fb7862Jean-Michel Trivi            }
1597ba5270b88798c66fefc17a1b25b27894e4fb7862Jean-Michel Trivi        }
1598ba5270b88798c66fefc17a1b25b27894e4fb7862Jean-Michel Trivi
1599ba5270b88798c66fefc17a1b25b27894e4fb7862Jean-Michel Trivi        public void binderDied() {
1600ba5270b88798c66fefc17a1b25b27894e4fb7862Jean-Michel Trivi            Log.w(TAG, "Recorder with remote submix at full volume died " + mICallback);
1601ba5270b88798c66fefc17a1b25b27894e4fb7862Jean-Michel Trivi            forceRemoteSubmixFullVolume(false, mICallback);
1602ba5270b88798c66fefc17a1b25b27894e4fb7862Jean-Michel Trivi        }
1603ba5270b88798c66fefc17a1b25b27894e4fb7862Jean-Michel Trivi    }
1604ba5270b88798c66fefc17a1b25b27894e4fb7862Jean-Michel Trivi
1605ba5270b88798c66fefc17a1b25b27894e4fb7862Jean-Michel Trivi    /**
1606ba5270b88798c66fefc17a1b25b27894e4fb7862Jean-Michel Trivi     * call must be synchronized on mRmtSbmxFullVolDeathHandlers
1607ba5270b88798c66fefc17a1b25b27894e4fb7862Jean-Michel Trivi     * @return true if there is a registered death handler, false otherwise */
1608ba5270b88798c66fefc17a1b25b27894e4fb7862Jean-Michel Trivi    private boolean discardRmtSbmxFullVolDeathHandlerFor(IBinder cb) {
1609ba5270b88798c66fefc17a1b25b27894e4fb7862Jean-Michel Trivi        Iterator<RmtSbmxFullVolDeathHandler> it = mRmtSbmxFullVolDeathHandlers.iterator();
1610ba5270b88798c66fefc17a1b25b27894e4fb7862Jean-Michel Trivi        while (it.hasNext()) {
1611ba5270b88798c66fefc17a1b25b27894e4fb7862Jean-Michel Trivi            final RmtSbmxFullVolDeathHandler handler = it.next();
1612ba5270b88798c66fefc17a1b25b27894e4fb7862Jean-Michel Trivi            if (handler.isHandlerFor(cb)) {
1613ba5270b88798c66fefc17a1b25b27894e4fb7862Jean-Michel Trivi                handler.forget();
1614ba5270b88798c66fefc17a1b25b27894e4fb7862Jean-Michel Trivi                mRmtSbmxFullVolDeathHandlers.remove(handler);
1615ba5270b88798c66fefc17a1b25b27894e4fb7862Jean-Michel Trivi                return true;
1616ba5270b88798c66fefc17a1b25b27894e4fb7862Jean-Michel Trivi            }
1617ba5270b88798c66fefc17a1b25b27894e4fb7862Jean-Michel Trivi        }
1618ba5270b88798c66fefc17a1b25b27894e4fb7862Jean-Michel Trivi        return false;
1619ba5270b88798c66fefc17a1b25b27894e4fb7862Jean-Michel Trivi    }
1620ba5270b88798c66fefc17a1b25b27894e4fb7862Jean-Michel Trivi
1621ba5270b88798c66fefc17a1b25b27894e4fb7862Jean-Michel Trivi    /** call synchronized on mRmtSbmxFullVolDeathHandlers */
1622ba5270b88798c66fefc17a1b25b27894e4fb7862Jean-Michel Trivi    private boolean hasRmtSbmxFullVolDeathHandlerFor(IBinder cb) {
1623ba5270b88798c66fefc17a1b25b27894e4fb7862Jean-Michel Trivi        Iterator<RmtSbmxFullVolDeathHandler> it = mRmtSbmxFullVolDeathHandlers.iterator();
1624ba5270b88798c66fefc17a1b25b27894e4fb7862Jean-Michel Trivi        while (it.hasNext()) {
1625ba5270b88798c66fefc17a1b25b27894e4fb7862Jean-Michel Trivi            if (it.next().isHandlerFor(cb)) {
1626ba5270b88798c66fefc17a1b25b27894e4fb7862Jean-Michel Trivi                return true;
1627ba5270b88798c66fefc17a1b25b27894e4fb7862Jean-Michel Trivi            }
1628ba5270b88798c66fefc17a1b25b27894e4fb7862Jean-Michel Trivi        }
1629ba5270b88798c66fefc17a1b25b27894e4fb7862Jean-Michel Trivi        return false;
1630ba5270b88798c66fefc17a1b25b27894e4fb7862Jean-Michel Trivi    }
1631ba5270b88798c66fefc17a1b25b27894e4fb7862Jean-Michel Trivi
1632ba5270b88798c66fefc17a1b25b27894e4fb7862Jean-Michel Trivi    private int mRmtSbmxFullVolRefCount = 0;
1633ba5270b88798c66fefc17a1b25b27894e4fb7862Jean-Michel Trivi    private ArrayList<RmtSbmxFullVolDeathHandler> mRmtSbmxFullVolDeathHandlers =
1634ba5270b88798c66fefc17a1b25b27894e4fb7862Jean-Michel Trivi            new ArrayList<RmtSbmxFullVolDeathHandler>();
1635ba5270b88798c66fefc17a1b25b27894e4fb7862Jean-Michel Trivi
1636ba5270b88798c66fefc17a1b25b27894e4fb7862Jean-Michel Trivi    public void forceRemoteSubmixFullVolume(boolean startForcing, IBinder cb) {
1637ba5270b88798c66fefc17a1b25b27894e4fb7862Jean-Michel Trivi        if (cb == null) {
1638ba5270b88798c66fefc17a1b25b27894e4fb7862Jean-Michel Trivi            return;
1639ba5270b88798c66fefc17a1b25b27894e4fb7862Jean-Michel Trivi        }
1640ba5270b88798c66fefc17a1b25b27894e4fb7862Jean-Michel Trivi        if ((PackageManager.PERMISSION_GRANTED != mContext.checkCallingOrSelfPermission(
1641ba5270b88798c66fefc17a1b25b27894e4fb7862Jean-Michel Trivi                        android.Manifest.permission.CAPTURE_AUDIO_OUTPUT))) {
1642ba5270b88798c66fefc17a1b25b27894e4fb7862Jean-Michel Trivi            Log.w(TAG, "Trying to call forceRemoteSubmixFullVolume() without CAPTURE_AUDIO_OUTPUT");
1643ba5270b88798c66fefc17a1b25b27894e4fb7862Jean-Michel Trivi            return;
1644ba5270b88798c66fefc17a1b25b27894e4fb7862Jean-Michel Trivi        }
1645ba5270b88798c66fefc17a1b25b27894e4fb7862Jean-Michel Trivi        synchronized(mRmtSbmxFullVolDeathHandlers) {
1646ba5270b88798c66fefc17a1b25b27894e4fb7862Jean-Michel Trivi            boolean applyRequired = false;
1647ba5270b88798c66fefc17a1b25b27894e4fb7862Jean-Michel Trivi            if (startForcing) {
1648ba5270b88798c66fefc17a1b25b27894e4fb7862Jean-Michel Trivi                if (!hasRmtSbmxFullVolDeathHandlerFor(cb)) {
1649ba5270b88798c66fefc17a1b25b27894e4fb7862Jean-Michel Trivi                    mRmtSbmxFullVolDeathHandlers.add(new RmtSbmxFullVolDeathHandler(cb));
1650ba5270b88798c66fefc17a1b25b27894e4fb7862Jean-Michel Trivi                    if (mRmtSbmxFullVolRefCount == 0) {
1651ba5270b88798c66fefc17a1b25b27894e4fb7862Jean-Michel Trivi                        mFullVolumeDevices |= AudioSystem.DEVICE_OUT_REMOTE_SUBMIX;
1652ba5270b88798c66fefc17a1b25b27894e4fb7862Jean-Michel Trivi                        mFixedVolumeDevices |= AudioSystem.DEVICE_OUT_REMOTE_SUBMIX;
1653ba5270b88798c66fefc17a1b25b27894e4fb7862Jean-Michel Trivi                        applyRequired = true;
1654ba5270b88798c66fefc17a1b25b27894e4fb7862Jean-Michel Trivi                    }
1655ba5270b88798c66fefc17a1b25b27894e4fb7862Jean-Michel Trivi                    mRmtSbmxFullVolRefCount++;
1656ba5270b88798c66fefc17a1b25b27894e4fb7862Jean-Michel Trivi                }
1657ba5270b88798c66fefc17a1b25b27894e4fb7862Jean-Michel Trivi            } else {
1658ba5270b88798c66fefc17a1b25b27894e4fb7862Jean-Michel Trivi                if (discardRmtSbmxFullVolDeathHandlerFor(cb) && (mRmtSbmxFullVolRefCount > 0)) {
1659ba5270b88798c66fefc17a1b25b27894e4fb7862Jean-Michel Trivi                    mRmtSbmxFullVolRefCount--;
1660ba5270b88798c66fefc17a1b25b27894e4fb7862Jean-Michel Trivi                    if (mRmtSbmxFullVolRefCount == 0) {
1661ba5270b88798c66fefc17a1b25b27894e4fb7862Jean-Michel Trivi                        mFullVolumeDevices &= ~AudioSystem.DEVICE_OUT_REMOTE_SUBMIX;
1662ba5270b88798c66fefc17a1b25b27894e4fb7862Jean-Michel Trivi                        mFixedVolumeDevices &= ~AudioSystem.DEVICE_OUT_REMOTE_SUBMIX;
1663ba5270b88798c66fefc17a1b25b27894e4fb7862Jean-Michel Trivi                        applyRequired = true;
1664ba5270b88798c66fefc17a1b25b27894e4fb7862Jean-Michel Trivi                    }
1665ba5270b88798c66fefc17a1b25b27894e4fb7862Jean-Michel Trivi                }
1666ba5270b88798c66fefc17a1b25b27894e4fb7862Jean-Michel Trivi            }
1667ba5270b88798c66fefc17a1b25b27894e4fb7862Jean-Michel Trivi            if (applyRequired) {
1668ba5270b88798c66fefc17a1b25b27894e4fb7862Jean-Michel Trivi                // Assumes only STREAM_MUSIC going through DEVICE_OUT_REMOTE_SUBMIX
1669ba5270b88798c66fefc17a1b25b27894e4fb7862Jean-Michel Trivi                checkAllFixedVolumeDevices(AudioSystem.STREAM_MUSIC);
1670ba5270b88798c66fefc17a1b25b27894e4fb7862Jean-Michel Trivi                mStreamStates[AudioSystem.STREAM_MUSIC].applyAllVolumes();
1671ba5270b88798c66fefc17a1b25b27894e4fb7862Jean-Michel Trivi            }
1672ba5270b88798c66fefc17a1b25b27894e4fb7862Jean-Michel Trivi        }
1673ba5270b88798c66fefc17a1b25b27894e4fb7862Jean-Michel Trivi    }
1674ba5270b88798c66fefc17a1b25b27894e4fb7862Jean-Michel Trivi
1675961cae92540763226648813d111c5b5c3b0f1597Dianne Hackborn    /** @see AudioManager#setMasterMute(boolean, int) */
16764a21b25fad62e4f19d13ba814263841c931f56efJulia Reynolds    public void setMasterMute(boolean state, int flags, String callingPackage, IBinder cb) {
16777c82ced4fc5b66c09a19eed9a5499039530142fbRoboErik        setMasterMuteInternal(state, flags, callingPackage, cb, Binder.getCallingUid());
16787c82ced4fc5b66c09a19eed9a5499039530142fbRoboErik    }
16797c82ced4fc5b66c09a19eed9a5499039530142fbRoboErik
16807c82ced4fc5b66c09a19eed9a5499039530142fbRoboErik    private void setMasterMuteInternal(boolean state, int flags, String callingPackage, IBinder cb,
16817c82ced4fc5b66c09a19eed9a5499039530142fbRoboErik            int uid) {
168283a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent        if (mUseFixedVolume) {
168383a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent            return;
168483a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent        }
16857c82ced4fc5b66c09a19eed9a5499039530142fbRoboErik        if (mAppOps.noteOp(AppOpsManager.OP_AUDIO_MASTER_VOLUME, uid, callingPackage)
16867c82ced4fc5b66c09a19eed9a5499039530142fbRoboErik                != AppOpsManager.MODE_ALLOWED) {
16874a21b25fad62e4f19d13ba814263841c931f56efJulia Reynolds            return;
16884a21b25fad62e4f19d13ba814263841c931f56efJulia Reynolds        }
16891ce5b26d707e0086e09af3cd0428f1b441145261Jason Simmons        if (state != AudioSystem.getMasterMute()) {
1690336cdb488ff0e5ec6709c66f55072d3ad22b82edJinsuk Kim            setSystemAudioMute(state);
16911ce5b26d707e0086e09af3cd0428f1b441145261Jason Simmons            AudioSystem.setMasterMute(state);
169257978ed86286a33d5b1a0fd000ca3406ba9d87b3Justin Koh            // Post a persist master volume msg
169375cf9e19a575c28c200c02c0ab6f83bb79f5c50dJustin Koh            sendMsg(mAudioHandler, MSG_PERSIST_MASTER_VOLUME_MUTE, SENDMSG_REPLACE, state ? 1
1694b53453fae037d67e421011936c8fdffe7ba43922Julia Reynolds                    : 0, UserHandle.getCallingUserId(), null, PERSIST_DELAY);
16950273af55cf68d54d26d154b44d105d40fed79701Justin Koh            sendMasterMuteUpdate(state, flags);
16967c82ced4fc5b66c09a19eed9a5499039530142fbRoboErik
16977c82ced4fc5b66c09a19eed9a5499039530142fbRoboErik            Intent intent = new Intent(AudioManager.MASTER_MUTE_CHANGED_ACTION);
16987c82ced4fc5b66c09a19eed9a5499039530142fbRoboErik            intent.putExtra(AudioManager.EXTRA_MASTER_VOLUME_MUTED, state);
16997c82ced4fc5b66c09a19eed9a5499039530142fbRoboErik            sendBroadcastToAll(intent);
17001ce5b26d707e0086e09af3cd0428f1b441145261Jason Simmons        }
1701ce952c8e13c535bedde77bcdb94dfcc7508475aaMike Lockwood    }
1702ce952c8e13c535bedde77bcdb94dfcc7508475aaMike Lockwood
1703ce952c8e13c535bedde77bcdb94dfcc7508475aaMike Lockwood    /** get master mute state. */
1704ce952c8e13c535bedde77bcdb94dfcc7508475aaMike Lockwood    public boolean isMasterMute() {
17053194ea94348bce8e7ee9f803698d877f46f8279aMike Lockwood        return AudioSystem.getMasterMute();
1706ce952c8e13c535bedde77bcdb94dfcc7508475aaMike Lockwood    }
1707ce952c8e13c535bedde77bcdb94dfcc7508475aaMike Lockwood
1708fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    protected static int getMaxStreamVolume(int streamType) {
1709fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        return MAX_STREAM_VOLUME[streamType];
1710fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    }
1711fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi
171291377de6f23af2b0b08adae22810cae6fc35cb1aEric Laurent    public static int getDefaultStreamVolume(int streamType) {
171391377de6f23af2b0b08adae22810cae6fc35cb1aEric Laurent        return DEFAULT_STREAM_VOLUME[streamType];
171491377de6f23af2b0b08adae22810cae6fc35cb1aEric Laurent    }
171591377de6f23af2b0b08adae22810cae6fc35cb1aEric Laurent
17169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** @see AudioManager#getStreamVolume(int) */
17179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public int getStreamVolume(int streamType) {
17189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        ensureValidStreamType(streamType);
17199bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent        int device = getDeviceForStream(streamType);
17208fa4d6f585f40ff5cf5f9bed316d92c64a306f21Eric Laurent        synchronized (VolumeStreamState.class) {
17218fa4d6f585f40ff5cf5f9bed316d92c64a306f21Eric Laurent            int index = mStreamStates[streamType].getIndex(device);
17224bbcc6549738f3d69831b2bd9eb4accec3e9920eEric Laurent
17238fa4d6f585f40ff5cf5f9bed316d92c64a306f21Eric Laurent            // by convention getStreamVolume() returns 0 when a stream is muted.
17248fa4d6f585f40ff5cf5f9bed316d92c64a306f21Eric Laurent            if (mStreamStates[streamType].isMuted_syncVSS()) {
17258fa4d6f585f40ff5cf5f9bed316d92c64a306f21Eric Laurent                index = 0;
17268fa4d6f585f40ff5cf5f9bed316d92c64a306f21Eric Laurent            }
17278fa4d6f585f40ff5cf5f9bed316d92c64a306f21Eric Laurent            if (index != 0 && (mStreamVolumeAlias[streamType] == AudioSystem.STREAM_MUSIC) &&
17288fa4d6f585f40ff5cf5f9bed316d92c64a306f21Eric Laurent                    (device & mFixedVolumeDevices) != 0) {
17298fa4d6f585f40ff5cf5f9bed316d92c64a306f21Eric Laurent                index = mStreamStates[streamType].getMaxIndex();
17308fa4d6f585f40ff5cf5f9bed316d92c64a306f21Eric Laurent            }
17318fa4d6f585f40ff5cf5f9bed316d92c64a306f21Eric Laurent            return (index + 5) / 10;
17324bbcc6549738f3d69831b2bd9eb4accec3e9920eEric Laurent        }
17339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
17349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1735519c7744b522aa07e12bc3244ac3de14aa2a4ad0RoboErik    @Override
17364767690f09ea3447b8c5c32fb28d27650aa18e00Mike Lockwood    public int getMasterVolume() {
1737ce952c8e13c535bedde77bcdb94dfcc7508475aaMike Lockwood        if (isMasterMute()) return 0;
1738ce952c8e13c535bedde77bcdb94dfcc7508475aaMike Lockwood        return getLastAudibleMasterVolume();
17398dc1dabd254249b7ddb8743e88fdb96580ffc585Mike Lockwood    }
17408dc1dabd254249b7ddb8743e88fdb96580ffc585Mike Lockwood
1741519c7744b522aa07e12bc3244ac3de14aa2a4ad0RoboErik    @Override
1742ba50b97cff80e73620a0e3d13cae169e095974a7Dianne Hackborn    public void setMasterVolume(int volume, int flags, String callingPackage) {
1743519c7744b522aa07e12bc3244ac3de14aa2a4ad0RoboErik        setMasterVolume(volume, flags, callingPackage, Binder.getCallingUid());
1744519c7744b522aa07e12bc3244ac3de14aa2a4ad0RoboErik    }
1745519c7744b522aa07e12bc3244ac3de14aa2a4ad0RoboErik
1746519c7744b522aa07e12bc3244ac3de14aa2a4ad0RoboErik    public void setMasterVolume(int volume, int flags, String callingPackage, int uid) {
174783a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent        if (mUseFixedVolume) {
174883a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent            return;
174983a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent        }
175083a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent
1751519c7744b522aa07e12bc3244ac3de14aa2a4ad0RoboErik        if (mAppOps.noteOp(AppOpsManager.OP_AUDIO_MASTER_VOLUME, uid, callingPackage)
1752519c7744b522aa07e12bc3244ac3de14aa2a4ad0RoboErik                != AppOpsManager.MODE_ALLOWED) {
1753ba50b97cff80e73620a0e3d13cae169e095974a7Dianne Hackborn            return;
1754ba50b97cff80e73620a0e3d13cae169e095974a7Dianne Hackborn        }
1755ba50b97cff80e73620a0e3d13cae169e095974a7Dianne Hackborn
17569760647dd0ee67e7c20f3e9d661d2006b1df0b54Mike Lockwood        if (volume < 0) {
17579760647dd0ee67e7c20f3e9d661d2006b1df0b54Mike Lockwood            volume = 0;
17589760647dd0ee67e7c20f3e9d661d2006b1df0b54Mike Lockwood        } else if (volume > MAX_MASTER_VOLUME) {
17599760647dd0ee67e7c20f3e9d661d2006b1df0b54Mike Lockwood            volume = MAX_MASTER_VOLUME;
17609760647dd0ee67e7c20f3e9d661d2006b1df0b54Mike Lockwood        }
17615c55a051ad7d86a464fb91426f1ea3c0250e38b3Mike Lockwood        doSetMasterVolume((float)volume / MAX_MASTER_VOLUME, flags);
17625c55a051ad7d86a464fb91426f1ea3c0250e38b3Mike Lockwood    }
17635c55a051ad7d86a464fb91426f1ea3c0250e38b3Mike Lockwood
17645c55a051ad7d86a464fb91426f1ea3c0250e38b3Mike Lockwood    private void doSetMasterVolume(float volume, int flags) {
17655c55a051ad7d86a464fb91426f1ea3c0250e38b3Mike Lockwood        // don't allow changing master volume when muted
17665c55a051ad7d86a464fb91426f1ea3c0250e38b3Mike Lockwood        if (!AudioSystem.getMasterMute()) {
17675c55a051ad7d86a464fb91426f1ea3c0250e38b3Mike Lockwood            int oldVolume = getMasterVolume();
17685c55a051ad7d86a464fb91426f1ea3c0250e38b3Mike Lockwood            AudioSystem.setMasterVolume(volume);
17695c55a051ad7d86a464fb91426f1ea3c0250e38b3Mike Lockwood
17705c55a051ad7d86a464fb91426f1ea3c0250e38b3Mike Lockwood            int newVolume = getMasterVolume();
17715c55a051ad7d86a464fb91426f1ea3c0250e38b3Mike Lockwood            if (newVolume != oldVolume) {
17725c55a051ad7d86a464fb91426f1ea3c0250e38b3Mike Lockwood                // Post a persist master volume msg
17735c55a051ad7d86a464fb91426f1ea3c0250e38b3Mike Lockwood                sendMsg(mAudioHandler, MSG_PERSIST_MASTER_VOLUME, SENDMSG_REPLACE,
17745c55a051ad7d86a464fb91426f1ea3c0250e38b3Mike Lockwood                        Math.round(volume * (float)1000.0), 0, null, PERSIST_DELAY);
1775336cdb488ff0e5ec6709c66f55072d3ad22b82edJinsuk Kim                setSystemAudioVolume(oldVolume, newVolume, getMasterMaxVolume(), flags);
17765c55a051ad7d86a464fb91426f1ea3c0250e38b3Mike Lockwood            }
17773caba517253d1703fc29b50740c4567b932279fbJustin Koh            // Send the volume update regardless whether there was a change.
17783caba517253d1703fc29b50740c4567b932279fbJustin Koh            sendMasterVolumeUpdate(flags, oldVolume, newVolume);
17795c55a051ad7d86a464fb91426f1ea3c0250e38b3Mike Lockwood        }
17808dc1dabd254249b7ddb8743e88fdb96580ffc585Mike Lockwood    }
17818dc1dabd254249b7ddb8743e88fdb96580ffc585Mike Lockwood
17829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** @see AudioManager#getStreamMaxVolume(int) */
17839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public int getStreamMaxVolume(int streamType) {
17849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        ensureValidStreamType(streamType);
1785a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent        return (mStreamStates[streamType].getMaxIndex() + 5) / 10;
17869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
17879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
17884767690f09ea3447b8c5c32fb28d27650aa18e00Mike Lockwood    public int getMasterMaxVolume() {
17894767690f09ea3447b8c5c32fb28d27650aa18e00Mike Lockwood        return MAX_MASTER_VOLUME;
17904767690f09ea3447b8c5c32fb28d27650aa18e00Mike Lockwood    }
179125101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent
179225101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent    /** Get last audible volume before stream was muted. */
179325101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent    public int getLastAudibleStreamVolume(int streamType) {
179425101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent        ensureValidStreamType(streamType);
17959bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent        int device = getDeviceForStream(streamType);
179642b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent        return (mStreamStates[streamType].getIndex(device) + 5) / 10;
179725101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent    }
179825101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent
1799ce952c8e13c535bedde77bcdb94dfcc7508475aaMike Lockwood    /** Get last audible master volume before it was muted. */
1800ce952c8e13c535bedde77bcdb94dfcc7508475aaMike Lockwood    public int getLastAudibleMasterVolume() {
1801ce952c8e13c535bedde77bcdb94dfcc7508475aaMike Lockwood        return Math.round(AudioSystem.getMasterVolume() * MAX_MASTER_VOLUME);
1802ce952c8e13c535bedde77bcdb94dfcc7508475aaMike Lockwood    }
1803ce952c8e13c535bedde77bcdb94dfcc7508475aaMike Lockwood
1804961cae92540763226648813d111c5b5c3b0f1597Dianne Hackborn    /** @see AudioManager#getMasterStreamType()  */
18056d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent    public int getMasterStreamType() {
18064f0f120316cfcee5880191264885772677fff921John Spurlock        return mStreamVolumeAlias[AudioSystem.STREAM_SYSTEM];
18076d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent    }
18086d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent
180922c921a910d236abf3a1705a02541a49fdaf3a14Emily Bernier    /** @see AudioManager#setMicrophoneMute(boolean) */
181022c921a910d236abf3a1705a02541a49fdaf3a14Emily Bernier    public void setMicrophoneMute(boolean on, String callingPackage) {
181122c921a910d236abf3a1705a02541a49fdaf3a14Emily Bernier        if (mAppOps.noteOp(AppOpsManager.OP_MUTE_MICROPHONE, Binder.getCallingUid(),
181222c921a910d236abf3a1705a02541a49fdaf3a14Emily Bernier                callingPackage) != AppOpsManager.MODE_ALLOWED) {
181322c921a910d236abf3a1705a02541a49fdaf3a14Emily Bernier            return;
181422c921a910d236abf3a1705a02541a49fdaf3a14Emily Bernier        }
18154a4fea0752c8edd33d680765e97ee3b538d777a5Jean-Michel Trivi        if (!checkAudioSettingsPermission("setMicrophoneMute()")) {
18164a4fea0752c8edd33d680765e97ee3b538d777a5Jean-Michel Trivi            return;
18174a4fea0752c8edd33d680765e97ee3b538d777a5Jean-Michel Trivi        }
181822c921a910d236abf3a1705a02541a49fdaf3a14Emily Bernier
181922c921a910d236abf3a1705a02541a49fdaf3a14Emily Bernier        AudioSystem.muteMicrophone(on);
1820b53453fae037d67e421011936c8fdffe7ba43922Julia Reynolds        // Post a persist microphone msg.
1821b53453fae037d67e421011936c8fdffe7ba43922Julia Reynolds        sendMsg(mAudioHandler, MSG_PERSIST_MICROPHONE_MUTE, SENDMSG_REPLACE, on ? 1
1822b53453fae037d67e421011936c8fdffe7ba43922Julia Reynolds                : 0, UserHandle.getCallingUserId(), null, PERSIST_DELAY);
182322c921a910d236abf3a1705a02541a49fdaf3a14Emily Bernier    }
182422c921a910d236abf3a1705a02541a49fdaf3a14Emily Bernier
1825661f2cf45860d2e10924e6b69966a9afe255f28bJohn Spurlock    @Override
1826661f2cf45860d2e10924e6b69966a9afe255f28bJohn Spurlock    public int getRingerModeExternal() {
1827661f2cf45860d2e10924e6b69966a9afe255f28bJohn Spurlock        synchronized(mSettingsLock) {
1828661f2cf45860d2e10924e6b69966a9afe255f28bJohn Spurlock            return mRingerModeExternal;
1829661f2cf45860d2e10924e6b69966a9afe255f28bJohn Spurlock        }
1830661f2cf45860d2e10924e6b69966a9afe255f28bJohn Spurlock    }
1831661f2cf45860d2e10924e6b69966a9afe255f28bJohn Spurlock
1832661f2cf45860d2e10924e6b69966a9afe255f28bJohn Spurlock    @Override
1833661f2cf45860d2e10924e6b69966a9afe255f28bJohn Spurlock    public int getRingerModeInternal() {
1834ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten        synchronized(mSettingsLock) {
1835ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten            return mRingerMode;
1836ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten        }
1837ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten    }
1838ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten
1839ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten    private void ensureValidRingerMode(int ringerMode) {
18409755937ed90f06db45ff5fe4510950ae1516f8f9John Spurlock        if (!isValidRingerMode(ringerMode)) {
1841ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten            throw new IllegalArgumentException("Bad ringer mode " + ringerMode);
1842ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten        }
18439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
18449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
18459755937ed90f06db45ff5fe4510950ae1516f8f9John Spurlock    /** @see AudioManager#isValidRingerMode(int) */
18469755937ed90f06db45ff5fe4510950ae1516f8f9John Spurlock    public boolean isValidRingerMode(int ringerMode) {
18479755937ed90f06db45ff5fe4510950ae1516f8f9John Spurlock        return ringerMode >= 0 && ringerMode <= AudioManager.RINGER_MODE_MAX;
18489755937ed90f06db45ff5fe4510950ae1516f8f9John Spurlock    }
18499755937ed90f06db45ff5fe4510950ae1516f8f9John Spurlock
1850661f2cf45860d2e10924e6b69966a9afe255f28bJohn Spurlock    public void setRingerModeExternal(int ringerMode, String caller) {
1851af88a19165a1de77948d58b2692c9a7e13712a59John Spurlock        setRingerMode(ringerMode, caller, true /*external*/);
1852661f2cf45860d2e10924e6b69966a9afe255f28bJohn Spurlock    }
1853661f2cf45860d2e10924e6b69966a9afe255f28bJohn Spurlock
1854661f2cf45860d2e10924e6b69966a9afe255f28bJohn Spurlock    public void setRingerModeInternal(int ringerMode, String caller) {
1855661f2cf45860d2e10924e6b69966a9afe255f28bJohn Spurlock        enforceSelfOrSystemUI("setRingerModeInternal");
1856af88a19165a1de77948d58b2692c9a7e13712a59John Spurlock        setRingerMode(ringerMode, caller, false /*external*/);
1857661f2cf45860d2e10924e6b69966a9afe255f28bJohn Spurlock    }
1858661f2cf45860d2e10924e6b69966a9afe255f28bJohn Spurlock
1859661f2cf45860d2e10924e6b69966a9afe255f28bJohn Spurlock    private void setRingerMode(int ringerMode, String caller, boolean external) {
1860212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent        if (mUseFixedVolume || isPlatformTelevision()) {
186183a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent            return;
186283a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent        }
1863661f2cf45860d2e10924e6b69966a9afe255f28bJohn Spurlock        if (caller == null || caller.length() == 0) {
1864661f2cf45860d2e10924e6b69966a9afe255f28bJohn Spurlock            throw new IllegalArgumentException("Bad caller: " + caller);
1865661f2cf45860d2e10924e6b69966a9afe255f28bJohn Spurlock        }
18669755937ed90f06db45ff5fe4510950ae1516f8f9John Spurlock        ensureValidRingerMode(ringerMode);
1867244820185269991186d07068b92985624cede4a5Eric Laurent        if ((ringerMode == AudioManager.RINGER_MODE_VIBRATE) && !mHasVibrator) {
1868244820185269991186d07068b92985624cede4a5Eric Laurent            ringerMode = AudioManager.RINGER_MODE_SILENT;
1869244820185269991186d07068b92985624cede4a5Eric Laurent        }
1870af88a19165a1de77948d58b2692c9a7e13712a59John Spurlock        final long identity = Binder.clearCallingIdentity();
1871af88a19165a1de77948d58b2692c9a7e13712a59John Spurlock        try {
1872af88a19165a1de77948d58b2692c9a7e13712a59John Spurlock            synchronized (mSettingsLock) {
1873af88a19165a1de77948d58b2692c9a7e13712a59John Spurlock                final int ringerModeInternal = getRingerModeInternal();
1874af88a19165a1de77948d58b2692c9a7e13712a59John Spurlock                final int ringerModeExternal = getRingerModeExternal();
1875af88a19165a1de77948d58b2692c9a7e13712a59John Spurlock                if (external) {
1876af88a19165a1de77948d58b2692c9a7e13712a59John Spurlock                    setRingerModeExt(ringerMode);
1877af88a19165a1de77948d58b2692c9a7e13712a59John Spurlock                    if (mRingerModeDelegate != null) {
1878af88a19165a1de77948d58b2692c9a7e13712a59John Spurlock                        ringerMode = mRingerModeDelegate.onSetRingerModeExternal(ringerModeExternal,
1879af88a19165a1de77948d58b2692c9a7e13712a59John Spurlock                                ringerMode, caller, ringerModeInternal);
1880af88a19165a1de77948d58b2692c9a7e13712a59John Spurlock                    }
1881af88a19165a1de77948d58b2692c9a7e13712a59John Spurlock                    if (ringerMode != ringerModeInternal) {
1882af88a19165a1de77948d58b2692c9a7e13712a59John Spurlock                        setRingerModeInt(ringerMode, true /*persist*/);
1883af88a19165a1de77948d58b2692c9a7e13712a59John Spurlock                    }
1884af88a19165a1de77948d58b2692c9a7e13712a59John Spurlock                } else /*internal*/ {
1885af88a19165a1de77948d58b2692c9a7e13712a59John Spurlock                    if (ringerMode != ringerModeInternal) {
1886af88a19165a1de77948d58b2692c9a7e13712a59John Spurlock                        setRingerModeInt(ringerMode, true /*persist*/);
1887af88a19165a1de77948d58b2692c9a7e13712a59John Spurlock                    }
1888af88a19165a1de77948d58b2692c9a7e13712a59John Spurlock                    if (mRingerModeDelegate != null) {
1889af88a19165a1de77948d58b2692c9a7e13712a59John Spurlock                        ringerMode = mRingerModeDelegate.onSetRingerModeInternal(ringerModeInternal,
1890af88a19165a1de77948d58b2692c9a7e13712a59John Spurlock                                ringerMode, caller, ringerModeExternal);
1891af88a19165a1de77948d58b2692c9a7e13712a59John Spurlock                    }
1892af88a19165a1de77948d58b2692c9a7e13712a59John Spurlock                    setRingerModeExt(ringerMode);
189357627794b682235afd60adfb235fee46d32f54e2John Spurlock                }
1894661f2cf45860d2e10924e6b69966a9afe255f28bJohn Spurlock            }
1895af88a19165a1de77948d58b2692c9a7e13712a59John Spurlock        } finally {
1896af88a19165a1de77948d58b2692c9a7e13712a59John Spurlock            Binder.restoreCallingIdentity(identity);
1897b109615ebebd6f3b9ae789412279f576c3ace46bJason Parekh        }
1898b109615ebebd6f3b9ae789412279f576c3ace46bJason Parekh    }
18999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1900661f2cf45860d2e10924e6b69966a9afe255f28bJohn Spurlock    private void setRingerModeExt(int ringerMode) {
1901661f2cf45860d2e10924e6b69966a9afe255f28bJohn Spurlock        synchronized(mSettingsLock) {
1902661f2cf45860d2e10924e6b69966a9afe255f28bJohn Spurlock            if (ringerMode == mRingerModeExternal) return;
1903661f2cf45860d2e10924e6b69966a9afe255f28bJohn Spurlock            mRingerModeExternal = ringerMode;
1904e5b42d97f6fd3eb0220ea84f21e60d530d93fc46John Spurlock        }
1905661f2cf45860d2e10924e6b69966a9afe255f28bJohn Spurlock        // Send sticky broadcast
1906bcc1087af40a0e1bb35dbe8a39c830ecdea8280bJohn Spurlock        broadcastRingerMode(AudioManager.RINGER_MODE_CHANGED_ACTION, ringerMode);
1907e5b42d97f6fd3eb0220ea84f21e60d530d93fc46John Spurlock    }
1908e5b42d97f6fd3eb0220ea84f21e60d530d93fc46John Spurlock
19094050c93601b3c3609b21cc1e18a29b64747e7fa9Eric Laurent    private void setRingerModeInt(int ringerMode, boolean persist) {
1910bcc1087af40a0e1bb35dbe8a39c830ecdea8280bJohn Spurlock        final boolean change;
1911ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten        synchronized(mSettingsLock) {
1912bcc1087af40a0e1bb35dbe8a39c830ecdea8280bJohn Spurlock            change = mRingerMode != ringerMode;
1913ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten            mRingerMode = ringerMode;
1914ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten        }
1915b109615ebebd6f3b9ae789412279f576c3ace46bJason Parekh
19165b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent        // Mute stream if not previously muted by ringer mode and ringer mode
19175b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent        // is not RINGER_MODE_NORMAL and stream is affected by ringer mode.
19185b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent        // Unmute stream if previously muted by ringer mode and ringer mode
19195b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent        // is RINGER_MODE_NORMAL or stream is not affected by ringer mode.
1920b109615ebebd6f3b9ae789412279f576c3ace46bJason Parekh        int numStreamTypes = AudioSystem.getNumStreamTypes();
1921661f2cf45860d2e10924e6b69966a9afe255f28bJohn Spurlock        final boolean ringerModeMute = ringerMode == AudioManager.RINGER_MODE_VIBRATE
1922661f2cf45860d2e10924e6b69966a9afe255f28bJohn Spurlock                || ringerMode == AudioManager.RINGER_MODE_SILENT;
19235b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent        for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
1924661f2cf45860d2e10924e6b69966a9afe255f28bJohn Spurlock            final boolean isMuted = isStreamMutedByRingerMode(streamType);
1925661f2cf45860d2e10924e6b69966a9afe255f28bJohn Spurlock            final boolean shouldMute = ringerModeMute && isStreamAffectedByRingerMode(streamType);
1926661f2cf45860d2e10924e6b69966a9afe255f28bJohn Spurlock            if (isMuted == shouldMute) continue;
1927661f2cf45860d2e10924e6b69966a9afe255f28bJohn Spurlock            if (!shouldMute) {
1928661f2cf45860d2e10924e6b69966a9afe255f28bJohn Spurlock                // unmute
1929661f2cf45860d2e10924e6b69966a9afe255f28bJohn Spurlock                // ring and notifications volume should never be 0 when not silenced
1930661f2cf45860d2e10924e6b69966a9afe255f28bJohn Spurlock                // on voice capable devices or devices that support vibration
1931661f2cf45860d2e10924e6b69966a9afe255f28bJohn Spurlock                if ((isPlatformVoice() || mHasVibrator) &&
1932661f2cf45860d2e10924e6b69966a9afe255f28bJohn Spurlock                        mStreamVolumeAlias[streamType] == AudioSystem.STREAM_RING) {
1933661f2cf45860d2e10924e6b69966a9afe255f28bJohn Spurlock                    synchronized (VolumeStreamState.class) {
1934661f2cf45860d2e10924e6b69966a9afe255f28bJohn Spurlock                        Set set = mStreamStates[streamType].mIndex.entrySet();
1935661f2cf45860d2e10924e6b69966a9afe255f28bJohn Spurlock                        Iterator i = set.iterator();
1936661f2cf45860d2e10924e6b69966a9afe255f28bJohn Spurlock                        while (i.hasNext()) {
1937661f2cf45860d2e10924e6b69966a9afe255f28bJohn Spurlock                            Map.Entry entry = (Map.Entry)i.next();
1938661f2cf45860d2e10924e6b69966a9afe255f28bJohn Spurlock                            if ((Integer)entry.getValue() == 0) {
1939661f2cf45860d2e10924e6b69966a9afe255f28bJohn Spurlock                                entry.setValue(10);
19409bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                            }
19419bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                        }
1942b024c30a80684ac08daef3137b7ba0d347fe3ce5Eric Laurent                    }
19439bcf401d13d47416043a704430388abd59aef7cdEric Laurent                }
1944661f2cf45860d2e10924e6b69966a9afe255f28bJohn Spurlock                mStreamStates[streamType].mute(null, false);
1945661f2cf45860d2e10924e6b69966a9afe255f28bJohn Spurlock                mRingerModeMutedStreams &= ~(1 << streamType);
19465b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent            } else {
1947661f2cf45860d2e10924e6b69966a9afe255f28bJohn Spurlock                // mute
1948661f2cf45860d2e10924e6b69966a9afe255f28bJohn Spurlock                mStreamStates[streamType].mute(null, true);
1949661f2cf45860d2e10924e6b69966a9afe255f28bJohn Spurlock                mRingerModeMutedStreams |= (1 << streamType);
1950b109615ebebd6f3b9ae789412279f576c3ace46bJason Parekh            }
19519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1952a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent
1953b109615ebebd6f3b9ae789412279f576c3ace46bJason Parekh        // Post a persist ringer mode msg
19544050c93601b3c3609b21cc1e18a29b64747e7fa9Eric Laurent        if (persist) {
1955afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent            sendMsg(mAudioHandler, MSG_PERSIST_RINGER_MODE,
19564050c93601b3c3609b21cc1e18a29b64747e7fa9Eric Laurent                    SENDMSG_REPLACE, 0, 0, null, PERSIST_DELAY);
19574050c93601b3c3609b21cc1e18a29b64747e7fa9Eric Laurent        }
1958bcc1087af40a0e1bb35dbe8a39c830ecdea8280bJohn Spurlock        if (change) {
1959bcc1087af40a0e1bb35dbe8a39c830ecdea8280bJohn Spurlock            // Send sticky broadcast
1960bcc1087af40a0e1bb35dbe8a39c830ecdea8280bJohn Spurlock            broadcastRingerMode(AudioManager.INTERNAL_RINGER_MODE_CHANGED_ACTION, ringerMode);
1961bcc1087af40a0e1bb35dbe8a39c830ecdea8280bJohn Spurlock        }
19629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
19639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
19649063154a793b0ab38b3c5992cbaed046427b4a82Mike Lockwood    private void restoreMasterVolume() {
196583a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent        if (mUseFixedVolume) {
196683a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent            AudioSystem.setMasterVolume(1.0f);
196783a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent            return;
196883a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent        }
19699063154a793b0ab38b3c5992cbaed046427b4a82Mike Lockwood        if (mUseMasterVolume) {
1970bc0fab1fc2db832ef86d8a33466ec4d68b103ca0Eric Laurent            float volume = Settings.System.getFloatForUser(mContentResolver,
1971bc0fab1fc2db832ef86d8a33466ec4d68b103ca0Eric Laurent                    Settings.System.VOLUME_MASTER, -1.0f, UserHandle.USER_CURRENT);
19729063154a793b0ab38b3c5992cbaed046427b4a82Mike Lockwood            if (volume >= 0.0f) {
19739063154a793b0ab38b3c5992cbaed046427b4a82Mike Lockwood                AudioSystem.setMasterVolume(volume);
19749063154a793b0ab38b3c5992cbaed046427b4a82Mike Lockwood            }
19759063154a793b0ab38b3c5992cbaed046427b4a82Mike Lockwood        }
19769063154a793b0ab38b3c5992cbaed046427b4a82Mike Lockwood    }
19779063154a793b0ab38b3c5992cbaed046427b4a82Mike Lockwood
19789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** @see AudioManager#shouldVibrate(int) */
19799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public boolean shouldVibrate(int vibrateType) {
1980bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent        if (!mHasVibrator) return false;
19819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
19829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        switch (getVibrateSetting(vibrateType)) {
19839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
19849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            case AudioManager.VIBRATE_SETTING_ON:
198557627794b682235afd60adfb235fee46d32f54e2John Spurlock                return getRingerModeExternal() != AudioManager.RINGER_MODE_SILENT;
19869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
19879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            case AudioManager.VIBRATE_SETTING_ONLY_SILENT:
198857627794b682235afd60adfb235fee46d32f54e2John Spurlock                return getRingerModeExternal() == AudioManager.RINGER_MODE_VIBRATE;
19899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
19909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            case AudioManager.VIBRATE_SETTING_OFF:
1991bcac496076ef6f439147e7a2be71e8a2b76ddedeDaniel Sandler                // return false, even for incoming calls
1992bcac496076ef6f439147e7a2be71e8a2b76ddedeDaniel Sandler                return false;
19939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
19949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            default:
19959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return false;
19969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
19979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
19989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
19999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** @see AudioManager#getVibrateSetting(int) */
20009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public int getVibrateSetting(int vibrateType) {
2001bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent        if (!mHasVibrator) return AudioManager.VIBRATE_SETTING_OFF;
20029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return (mVibrateSetting >> (vibrateType * 2)) & 3;
20039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
20049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
20059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** @see AudioManager#setVibrateSetting(int, int) */
20069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void setVibrateSetting(int vibrateType, int vibrateSetting) {
20079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2008bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent        if (!mHasVibrator) return;
2009bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent
20109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mVibrateSetting = getValueForVibrateSetting(mVibrateSetting, vibrateType, vibrateSetting);
20119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
20129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // Broadcast change
20139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        broadcastVibrateSetting(vibrateType);
20149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
20159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
20169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
20179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
20189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @see #setVibrateSetting(int, int)
20199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
20209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static int getValueForVibrateSetting(int existingValue, int vibrateType,
20219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int vibrateSetting) {
20229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
20239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // First clear the existing setting. Each vibrate type has two bits in
20249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // the value. Note '3' is '11' in binary.
20259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        existingValue &= ~(3 << (vibrateType * 2));
20269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
20279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // Set into the old value
20289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        existingValue |= (vibrateSetting & 3) << (vibrateType * 2);
20299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
20309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return existingValue;
20319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
20329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
20339272b4b4a44fe1f33e3030810618194f817caaecEric Laurent    private class SetModeDeathHandler implements IBinder.DeathRecipient {
20349272b4b4a44fe1f33e3030810618194f817caaecEric Laurent        private IBinder mCb; // To be notified of client's death
2035f1ddd51f9cd2f92b922bc636c307210a8d587c25Marco Nelissen        private int mPid;
20369272b4b4a44fe1f33e3030810618194f817caaecEric Laurent        private int mMode = AudioSystem.MODE_NORMAL; // Current mode set by this client
20379272b4b4a44fe1f33e3030810618194f817caaecEric Laurent
20389f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent        SetModeDeathHandler(IBinder cb, int pid) {
20399272b4b4a44fe1f33e3030810618194f817caaecEric Laurent            mCb = cb;
20409f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent            mPid = pid;
20419272b4b4a44fe1f33e3030810618194f817caaecEric Laurent        }
20429272b4b4a44fe1f33e3030810618194f817caaecEric Laurent
20439272b4b4a44fe1f33e3030810618194f817caaecEric Laurent        public void binderDied() {
2044d7454be47f4111c0478a502353e11dea401378bdEric Laurent            int newModeOwnerPid = 0;
20459272b4b4a44fe1f33e3030810618194f817caaecEric Laurent            synchronized(mSetModeDeathHandlers) {
20469272b4b4a44fe1f33e3030810618194f817caaecEric Laurent                Log.w(TAG, "setMode() client died");
20479272b4b4a44fe1f33e3030810618194f817caaecEric Laurent                int index = mSetModeDeathHandlers.indexOf(this);
20489272b4b4a44fe1f33e3030810618194f817caaecEric Laurent                if (index < 0) {
20499272b4b4a44fe1f33e3030810618194f817caaecEric Laurent                    Log.w(TAG, "unregistered setMode() client died");
20509272b4b4a44fe1f33e3030810618194f817caaecEric Laurent                } else {
2051d7454be47f4111c0478a502353e11dea401378bdEric Laurent                    newModeOwnerPid = setModeInt(AudioSystem.MODE_NORMAL, mCb, mPid);
20529272b4b4a44fe1f33e3030810618194f817caaecEric Laurent                }
20539272b4b4a44fe1f33e3030810618194f817caaecEric Laurent            }
20549f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent            // when entering RINGTONE, IN_CALL or IN_COMMUNICATION mode, clear all
20559f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent            // SCO connections not started by the application changing the mode
2056d7454be47f4111c0478a502353e11dea401378bdEric Laurent            if (newModeOwnerPid != 0) {
20576b5e22d52c69cb6d80ff09bd32395b0034ada343Eric Laurent                final long ident = Binder.clearCallingIdentity();
20586b5e22d52c69cb6d80ff09bd32395b0034ada343Eric Laurent                disconnectBluetoothSco(newModeOwnerPid);
20596b5e22d52c69cb6d80ff09bd32395b0034ada343Eric Laurent                Binder.restoreCallingIdentity(ident);
20609f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent            }
20619272b4b4a44fe1f33e3030810618194f817caaecEric Laurent        }
20629272b4b4a44fe1f33e3030810618194f817caaecEric Laurent
2063f1ddd51f9cd2f92b922bc636c307210a8d587c25Marco Nelissen        public int getPid() {
2064f1ddd51f9cd2f92b922bc636c307210a8d587c25Marco Nelissen            return mPid;
2065f1ddd51f9cd2f92b922bc636c307210a8d587c25Marco Nelissen        }
2066f1ddd51f9cd2f92b922bc636c307210a8d587c25Marco Nelissen
20679272b4b4a44fe1f33e3030810618194f817caaecEric Laurent        public void setMode(int mode) {
20689272b4b4a44fe1f33e3030810618194f817caaecEric Laurent            mMode = mode;
20699272b4b4a44fe1f33e3030810618194f817caaecEric Laurent        }
20709272b4b4a44fe1f33e3030810618194f817caaecEric Laurent
20719272b4b4a44fe1f33e3030810618194f817caaecEric Laurent        public int getMode() {
20729272b4b4a44fe1f33e3030810618194f817caaecEric Laurent            return mMode;
20739272b4b4a44fe1f33e3030810618194f817caaecEric Laurent        }
20749272b4b4a44fe1f33e3030810618194f817caaecEric Laurent
20759272b4b4a44fe1f33e3030810618194f817caaecEric Laurent        public IBinder getBinder() {
20769272b4b4a44fe1f33e3030810618194f817caaecEric Laurent            return mCb;
20779272b4b4a44fe1f33e3030810618194f817caaecEric Laurent        }
20789272b4b4a44fe1f33e3030810618194f817caaecEric Laurent    }
20799272b4b4a44fe1f33e3030810618194f817caaecEric Laurent
20809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** @see AudioManager#setMode(int) */
20819272b4b4a44fe1f33e3030810618194f817caaecEric Laurent    public void setMode(int mode, IBinder cb) {
2082339567d5c91a8dc9228913ed1e5deb0ebb8a4a64Jean-Michel Trivi        if (DEBUG_MODE) { Log.v(TAG, "setMode(mode=" + mode + ")"); }
20839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (!checkAudioSettingsPermission("setMode()")) {
20849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return;
20859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
2086a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent
2087ccd654e9d4c38da0d652c442e7a2ca3f447e9abeJean-Michel Trivi        if ( (mode == AudioSystem.MODE_IN_CALL) &&
2088ccd654e9d4c38da0d652c442e7a2ca3f447e9abeJean-Michel Trivi                (mContext.checkCallingOrSelfPermission(
2089ccd654e9d4c38da0d652c442e7a2ca3f447e9abeJean-Michel Trivi                        android.Manifest.permission.MODIFY_PHONE_STATE)
2090ccd654e9d4c38da0d652c442e7a2ca3f447e9abeJean-Michel Trivi                            != PackageManager.PERMISSION_GRANTED)) {
2091ccd654e9d4c38da0d652c442e7a2ca3f447e9abeJean-Michel Trivi            Log.w(TAG, "MODIFY_PHONE_STATE Permission Denial: setMode(MODE_IN_CALL) from pid="
2092ccd654e9d4c38da0d652c442e7a2ca3f447e9abeJean-Michel Trivi                    + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid());
2093ccd654e9d4c38da0d652c442e7a2ca3f447e9abeJean-Michel Trivi            return;
2094ccd654e9d4c38da0d652c442e7a2ca3f447e9abeJean-Michel Trivi        }
2095ccd654e9d4c38da0d652c442e7a2ca3f447e9abeJean-Michel Trivi
20968f677d66d9c3ba34c97e69b2bb9e161f129af0eeJean-Michel Trivi        if (mode < AudioSystem.MODE_CURRENT || mode >= AudioSystem.NUM_MODES) {
2097a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent            return;
2098a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent        }
2099a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent
2100d7454be47f4111c0478a502353e11dea401378bdEric Laurent        int newModeOwnerPid = 0;
21019f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent        synchronized(mSetModeDeathHandlers) {
2102a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent            if (mode == AudioSystem.MODE_CURRENT) {
2103a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent                mode = mMode;
2104a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent            }
2105d7454be47f4111c0478a502353e11dea401378bdEric Laurent            newModeOwnerPid = setModeInt(mode, cb, Binder.getCallingPid());
21069f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent        }
21079f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent        // when entering RINGTONE, IN_CALL or IN_COMMUNICATION mode, clear all
21089f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent        // SCO connections not started by the application changing the mode
2109d7454be47f4111c0478a502353e11dea401378bdEric Laurent        if (newModeOwnerPid != 0) {
2110d7454be47f4111c0478a502353e11dea401378bdEric Laurent             disconnectBluetoothSco(newModeOwnerPid);
21119f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent        }
21129f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent    }
21132ade576148fe33c5ff6098d30ccfbcf28df70e8eJean-Michel Trivi
21149f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent    // must be called synchronized on mSetModeDeathHandlers
2115d7454be47f4111c0478a502353e11dea401378bdEric Laurent    // setModeInt() returns a valid PID if the audio mode was successfully set to
21169f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent    // any mode other than NORMAL.
2117ccd654e9d4c38da0d652c442e7a2ca3f447e9abeJean-Michel Trivi    private int setModeInt(int mode, IBinder cb, int pid) {
2118339567d5c91a8dc9228913ed1e5deb0ebb8a4a64Jean-Michel Trivi        if (DEBUG_MODE) { Log.v(TAG, "setModeInt(mode=" + mode + ", pid=" + pid + ")"); }
2119d7454be47f4111c0478a502353e11dea401378bdEric Laurent        int newModeOwnerPid = 0;
21209f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent        if (cb == null) {
21219f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent            Log.e(TAG, "setModeInt() called with null binder");
2122d7454be47f4111c0478a502353e11dea401378bdEric Laurent            return newModeOwnerPid;
21239f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent        }
21242ade576148fe33c5ff6098d30ccfbcf28df70e8eJean-Michel Trivi
21259f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent        SetModeDeathHandler hdlr = null;
21269f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent        Iterator iter = mSetModeDeathHandlers.iterator();
21279f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent        while (iter.hasNext()) {
21289f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent            SetModeDeathHandler h = (SetModeDeathHandler)iter.next();
21299f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent            if (h.getPid() == pid) {
21309f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                hdlr = h;
21319f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                // Remove from client list so that it is re-inserted at top of list
21329f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                iter.remove();
21339f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                hdlr.getBinder().unlinkToDeath(hdlr, 0);
21349f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                break;
21359f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent            }
21369f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent        }
21379f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent        int status = AudioSystem.AUDIO_STATUS_OK;
21389f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent        do {
21399f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent            if (mode == AudioSystem.MODE_NORMAL) {
21409f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                // get new mode from client at top the list if any
21419f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                if (!mSetModeDeathHandlers.isEmpty()) {
21429f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                    hdlr = mSetModeDeathHandlers.get(0);
21439f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                    cb = hdlr.getBinder();
21449f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                    mode = hdlr.getMode();
2145339567d5c91a8dc9228913ed1e5deb0ebb8a4a64Jean-Michel Trivi                    if (DEBUG_MODE) {
2146339567d5c91a8dc9228913ed1e5deb0ebb8a4a64Jean-Michel Trivi                        Log.w(TAG, " using mode=" + mode + " instead due to death hdlr at pid="
2147339567d5c91a8dc9228913ed1e5deb0ebb8a4a64Jean-Michel Trivi                                + hdlr.mPid);
2148339567d5c91a8dc9228913ed1e5deb0ebb8a4a64Jean-Michel Trivi                    }
21499f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                }
21509f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent            } else {
21519f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                if (hdlr == null) {
21529f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                    hdlr = new SetModeDeathHandler(cb, pid);
21539f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                }
21549f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                // Register for client death notification
21559f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                try {
21569f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                    cb.linkToDeath(hdlr, 0);
21579f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                } catch (RemoteException e) {
21589f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                    // Client has died!
21599f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                    Log.w(TAG, "setMode() could not link to "+cb+" binder death");
21609f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                }
21619272b4b4a44fe1f33e3030810618194f817caaecEric Laurent
21629f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                // Last client to call setMode() is always at top of client list
21639f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                // as required by SetModeDeathHandler.binderDied()
21649f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                mSetModeDeathHandlers.add(0, hdlr);
21659f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                hdlr.setMode(mode);
21669f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent            }
21673def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent
21689f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent            if (mode != mMode) {
21699f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                status = AudioSystem.setPhoneState(mode);
21709f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                if (status == AudioSystem.AUDIO_STATUS_OK) {
2171339567d5c91a8dc9228913ed1e5deb0ebb8a4a64Jean-Michel Trivi                    if (DEBUG_MODE) { Log.v(TAG, " mode successfully set to " + mode); }
21729f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                    mMode = mode;
21739f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                } else {
21749f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                    if (hdlr != null) {
21759f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                        mSetModeDeathHandlers.remove(hdlr);
21769f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                        cb.unlinkToDeath(hdlr, 0);
21773def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                    }
21789f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                    // force reading new top of mSetModeDeathHandlers stack
2179339567d5c91a8dc9228913ed1e5deb0ebb8a4a64Jean-Michel Trivi                    if (DEBUG_MODE) { Log.w(TAG, " mode set to MODE_NORMAL after phoneState pb"); }
21809f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                    mode = AudioSystem.MODE_NORMAL;
2181b9c9d260f21b321527c4622a123af9767630d94dEric Laurent                }
21829f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent            } else {
21839f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                status = AudioSystem.AUDIO_STATUS_OK;
21849f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent            }
21859f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent        } while (status != AudioSystem.AUDIO_STATUS_OK && !mSetModeDeathHandlers.isEmpty());
21869f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent
21879f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent        if (status == AudioSystem.AUDIO_STATUS_OK) {
21889f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent            if (mode != AudioSystem.MODE_NORMAL) {
2189d7454be47f4111c0478a502353e11dea401378bdEric Laurent                if (mSetModeDeathHandlers.isEmpty()) {
2190d7454be47f4111c0478a502353e11dea401378bdEric Laurent                    Log.e(TAG, "setMode() different from MODE_NORMAL with empty mode client stack");
2191d7454be47f4111c0478a502353e11dea401378bdEric Laurent                } else {
2192d7454be47f4111c0478a502353e11dea401378bdEric Laurent                    newModeOwnerPid = mSetModeDeathHandlers.get(0).getPid();
2193d7454be47f4111c0478a502353e11dea401378bdEric Laurent                }
21949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
21959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int streamType = getActiveStreamType(AudioManager.USE_DEFAULT_STREAM_TYPE);
21969bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent            int device = getDeviceForStream(streamType);
219742b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent            int index = mStreamStates[mStreamVolumeAlias[streamType]].getIndex(device);
219842b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent            setStreamVolumeInt(mStreamVolumeAlias[streamType], index, device, true);
21996d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent
22006d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent            updateStreamVolumeAlias(true /*updateVolumes*/);
22019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
2202d7454be47f4111c0478a502353e11dea401378bdEric Laurent        return newModeOwnerPid;
22039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
22049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
22059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** @see AudioManager#getMode() */
22069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public int getMode() {
22079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return mMode;
22089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
22099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2210e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent    //==========================================================================================
2211e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent    // Sound Effects
2212e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent    //==========================================================================================
2213e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent
2214e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent    private static final String TAG_AUDIO_ASSETS = "audio_assets";
2215e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent    private static final String ATTR_VERSION = "version";
2216e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent    private static final String TAG_GROUP = "group";
2217e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent    private static final String ATTR_GROUP_NAME = "name";
2218e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent    private static final String TAG_ASSET = "asset";
2219e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent    private static final String ATTR_ASSET_ID = "id";
2220e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent    private static final String ATTR_ASSET_FILE = "file";
2221e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent
2222e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent    private static final String ASSET_FILE_VERSION = "1.0";
2223e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent    private static final String GROUP_TOUCH_SOUNDS = "touch_sounds";
2224e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent
2225167d1a27713ab64cd3c0aa70de96434083ef0400Glenn Kasten    private static final int SOUND_EFFECTS_LOAD_TIMEOUT_MS = 5000;
22265d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent
22275d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent    class LoadSoundEffectReply {
22285d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent        public int mStatus = 1;
22295d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent    };
22305d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent
2231e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent    private void loadTouchSoundAssetDefaults() {
2232e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent        SOUND_EFFECT_FILES.add("Effect_Tick.ogg");
2233e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent        for (int i = 0; i < AudioManager.NUM_SOUND_EFFECTS; i++) {
2234e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent            SOUND_EFFECT_FILES_MAP[i][0] = 0;
2235e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent            SOUND_EFFECT_FILES_MAP[i][1] = -1;
2236e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent        }
2237e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent    }
2238e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent
2239e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent    private void loadTouchSoundAssets() {
2240e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent        XmlResourceParser parser = null;
2241e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent
22425d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent        // only load assets once.
22435d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent        if (!SOUND_EFFECT_FILES.isEmpty()) {
22445d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent            return;
22455d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent        }
22465d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent
2247e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent        loadTouchSoundAssetDefaults();
2248e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent
2249e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent        try {
2250e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent            parser = mContext.getResources().getXml(com.android.internal.R.xml.audio_assets);
2251e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent
2252e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent            XmlUtils.beginDocument(parser, TAG_AUDIO_ASSETS);
2253e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent            String version = parser.getAttributeValue(null, ATTR_VERSION);
2254e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent            boolean inTouchSoundsGroup = false;
2255e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent
2256e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent            if (ASSET_FILE_VERSION.equals(version)) {
2257e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent                while (true) {
2258e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent                    XmlUtils.nextElement(parser);
2259e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent                    String element = parser.getName();
2260e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent                    if (element == null) {
2261e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent                        break;
2262e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent                    }
2263e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent                    if (element.equals(TAG_GROUP)) {
2264e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent                        String name = parser.getAttributeValue(null, ATTR_GROUP_NAME);
2265e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent                        if (GROUP_TOUCH_SOUNDS.equals(name)) {
2266e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent                            inTouchSoundsGroup = true;
2267e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent                            break;
2268e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent                        }
2269e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent                    }
2270e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent                }
2271e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent                while (inTouchSoundsGroup) {
2272e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent                    XmlUtils.nextElement(parser);
2273e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent                    String element = parser.getName();
2274e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent                    if (element == null) {
2275e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent                        break;
2276e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent                    }
2277e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent                    if (element.equals(TAG_ASSET)) {
2278e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent                        String id = parser.getAttributeValue(null, ATTR_ASSET_ID);
2279e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent                        String file = parser.getAttributeValue(null, ATTR_ASSET_FILE);
2280e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent                        int fx;
2281e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent
2282e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent                        try {
2283e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent                            Field field = AudioManager.class.getField(id);
2284e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent                            fx = field.getInt(null);
2285e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent                        } catch (Exception e) {
2286e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent                            Log.w(TAG, "Invalid touch sound ID: "+id);
2287e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent                            continue;
2288e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent                        }
2289e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent
2290e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent                        int i = SOUND_EFFECT_FILES.indexOf(file);
2291e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent                        if (i == -1) {
2292e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent                            i = SOUND_EFFECT_FILES.size();
2293e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent                            SOUND_EFFECT_FILES.add(file);
2294e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent                        }
2295e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent                        SOUND_EFFECT_FILES_MAP[fx][0] = i;
2296e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent                    } else {
2297e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent                        break;
2298e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent                    }
2299e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent                }
2300e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent            }
2301e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent        } catch (Resources.NotFoundException e) {
2302e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent            Log.w(TAG, "audio assets file not found", e);
2303e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent        } catch (XmlPullParserException e) {
2304e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent            Log.w(TAG, "XML parser exception reading touch sound assets", e);
2305e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent        } catch (IOException e) {
2306e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent            Log.w(TAG, "I/O exception reading touch sound assets", e);
2307e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent        } finally {
2308e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent            if (parser != null) {
2309e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent                parser.close();
2310e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent            }
2311e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent        }
2312e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent    }
2313e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent
23149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** @see AudioManager#playSoundEffect(int) */
23159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void playSoundEffect(int effectType) {
23165d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent        playSoundEffectVolume(effectType, -1.0f);
23179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
23189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
23199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** @see AudioManager#playSoundEffect(int, float) */
23209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void playSoundEffectVolume(int effectType, float volume) {
2321559c76dbc37ff25b204ed1f060d3ec2fa43d718cNatalie Silvanovich        if (effectType >= AudioManager.NUM_SOUND_EFFECTS || effectType < 0) {
2322559c76dbc37ff25b204ed1f060d3ec2fa43d718cNatalie Silvanovich            Log.w(TAG, "AudioService effectType value " + effectType + " out of range");
2323559c76dbc37ff25b204ed1f060d3ec2fa43d718cNatalie Silvanovich            return;
2324559c76dbc37ff25b204ed1f060d3ec2fa43d718cNatalie Silvanovich        }
2325559c76dbc37ff25b204ed1f060d3ec2fa43d718cNatalie Silvanovich
23265d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent        sendMsg(mAudioHandler, MSG_PLAY_SOUND_EFFECT, SENDMSG_QUEUE,
23279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                effectType, (int) (volume * 1000), null, 0);
23289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
23299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
23309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
23319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Loads samples into the soundpool.
23325c17a820f9e46e0756c11795b3e6f89105f2f539Glenn Kasten     * This method must be called at first when sound effects are enabled
23339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
23349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public boolean loadSoundEffects() {
23355d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent        int attempts = 3;
23365d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent        LoadSoundEffectReply reply = new LoadSoundEffectReply();
2337117b7bb5b5a4457711f59bde3dcc83d8f111c524Eric Laurent
23385d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent        synchronized (reply) {
23395d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent            sendMsg(mAudioHandler, MSG_LOAD_SOUND_EFFECTS, SENDMSG_QUEUE, 0, 0, reply, 0);
23405d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent            while ((reply.mStatus == 1) && (attempts-- > 0)) {
2341117b7bb5b5a4457711f59bde3dcc83d8f111c524Eric Laurent                try {
2342167d1a27713ab64cd3c0aa70de96434083ef0400Glenn Kasten                    reply.wait(SOUND_EFFECTS_LOAD_TIMEOUT_MS);
23435d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                } catch (InterruptedException e) {
23445d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    Log.w(TAG, "loadSoundEffects Interrupted while waiting sound pool loaded.");
2345117b7bb5b5a4457711f59bde3dcc83d8f111c524Eric Laurent                }
2346a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent            }
23479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
23485d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent        return (reply.mStatus == 0);
23499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
23509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
23519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
23529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *  Unloads samples from the sound pool.
23539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *  This method can be called to free some memory when
23549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *  sound effects are disabled.
23559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
23569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void unloadSoundEffects() {
23575d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent        sendMsg(mAudioHandler, MSG_UNLOAD_SOUND_EFFECTS, SENDMSG_QUEUE, 0, 0, null, 0);
23589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
23599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2360a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent    class SoundPoolListenerThread extends Thread {
2361a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent        public SoundPoolListenerThread() {
2362a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent            super("SoundPoolListenerThread");
2363a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent        }
2364a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent
2365a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent        @Override
2366a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent        public void run() {
2367a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent
2368a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent            Looper.prepare();
2369a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent            mSoundPoolLooper = Looper.myLooper();
2370a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent
2371a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent            synchronized (mSoundEffectsLock) {
2372a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent                if (mSoundPool != null) {
2373a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent                    mSoundPoolCallBack = new SoundPoolCallback();
2374a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent                    mSoundPool.setOnLoadCompleteListener(mSoundPoolCallBack);
2375a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent                }
2376a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent                mSoundEffectsLock.notify();
2377a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent            }
2378a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent            Looper.loop();
2379a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent        }
2380a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent    }
2381a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent
2382a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent    private final class SoundPoolCallback implements
2383a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent            android.media.SoundPool.OnLoadCompleteListener {
2384a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent
23855d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent        int mStatus = 1; // 1 means neither error nor last sample loaded yet
23865d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent        List<Integer> mSamples = new ArrayList<Integer>();
2387a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent
2388a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent        public int status() {
2389a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent            return mStatus;
2390a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent        }
2391a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent
23925d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent        public void setSamples(int[] samples) {
23935d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent            for (int i = 0; i < samples.length; i++) {
23945d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                // do not wait ack for samples rejected upfront by SoundPool
23955d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                if (samples[i] > 0) {
23965d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    mSamples.add(samples[i]);
23975d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                }
23985d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent            }
2399a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent        }
2400a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent
2401a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent        public void onLoadComplete(SoundPool soundPool, int sampleId, int status) {
2402a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent            synchronized (mSoundEffectsLock) {
24035d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                int i = mSamples.indexOf(sampleId);
24045d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                if (i >= 0) {
24055d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    mSamples.remove(i);
2406a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent                }
24075d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                if ((status != 0) || mSamples. isEmpty()) {
24085d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    mStatus = status;
2409a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent                    mSoundEffectsLock.notify();
2410a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent                }
2411a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent            }
2412a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent        }
2413a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent    }
2414a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent
24154050c93601b3c3609b21cc1e18a29b64747e7fa9Eric Laurent    /** @see AudioManager#reloadAudioSettings() */
24164050c93601b3c3609b21cc1e18a29b64747e7fa9Eric Laurent    public void reloadAudioSettings() {
2417bc0fab1fc2db832ef86d8a33466ec4d68b103ca0Eric Laurent        readAudioSettings(false /*userSwitch*/);
2418bc0fab1fc2db832ef86d8a33466ec4d68b103ca0Eric Laurent    }
2419bc0fab1fc2db832ef86d8a33466ec4d68b103ca0Eric Laurent
2420bc0fab1fc2db832ef86d8a33466ec4d68b103ca0Eric Laurent    private void readAudioSettings(boolean userSwitch) {
24214050c93601b3c3609b21cc1e18a29b64747e7fa9Eric Laurent        // restore ringer mode, ringer mode affected streams, mute affected streams and vibrate settings
24224050c93601b3c3609b21cc1e18a29b64747e7fa9Eric Laurent        readPersistedSettings();
24234050c93601b3c3609b21cc1e18a29b64747e7fa9Eric Laurent
24244050c93601b3c3609b21cc1e18a29b64747e7fa9Eric Laurent        // restore volume settings
24254050c93601b3c3609b21cc1e18a29b64747e7fa9Eric Laurent        int numStreamTypes = AudioSystem.getNumStreamTypes();
24264050c93601b3c3609b21cc1e18a29b64747e7fa9Eric Laurent        for (int streamType = 0; streamType < numStreamTypes; streamType++) {
24274050c93601b3c3609b21cc1e18a29b64747e7fa9Eric Laurent            VolumeStreamState streamState = mStreamStates[streamType];
24284050c93601b3c3609b21cc1e18a29b64747e7fa9Eric Laurent
2429bc0fab1fc2db832ef86d8a33466ec4d68b103ca0Eric Laurent            if (userSwitch && mStreamVolumeAlias[streamType] == AudioSystem.STREAM_MUSIC) {
2430bc0fab1fc2db832ef86d8a33466ec4d68b103ca0Eric Laurent                continue;
2431bc0fab1fc2db832ef86d8a33466ec4d68b103ca0Eric Laurent            }
2432bc0fab1fc2db832ef86d8a33466ec4d68b103ca0Eric Laurent
24338fa4d6f585f40ff5cf5f9bed316d92c64a306f21Eric Laurent            streamState.readSettings();
24348fa4d6f585f40ff5cf5f9bed316d92c64a306f21Eric Laurent            synchronized (VolumeStreamState.class) {
24353172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                // unmute stream that was muted but is not affect by mute anymore
24368fa4d6f585f40ff5cf5f9bed316d92c64a306f21Eric Laurent                if (streamState.isMuted_syncVSS() && ((!isStreamAffectedByMute(streamType) &&
243783a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent                        !isStreamMutedByRingerMode(streamType)) || mUseFixedVolume)) {
24383172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                    int size = streamState.mDeathHandlers.size();
24393172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                    for (int i = 0; i < size; i++) {
24403172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                        streamState.mDeathHandlers.get(i).mMuteCount = 1;
24418fa4d6f585f40ff5cf5f9bed316d92c64a306f21Eric Laurent                        streamState.mDeathHandlers.get(i).mute_syncVSS(false);
24423172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                    }
24433172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                }
24444050c93601b3c3609b21cc1e18a29b64747e7fa9Eric Laurent            }
24454050c93601b3c3609b21cc1e18a29b64747e7fa9Eric Laurent        }
24464050c93601b3c3609b21cc1e18a29b64747e7fa9Eric Laurent
244733902db75011d863009585682bd08560c5b89a75Eric Laurent        // apply new ringer mode before checking volume for alias streams so that streams
244833902db75011d863009585682bd08560c5b89a75Eric Laurent        // muted by ringer mode have the correct volume
2449661f2cf45860d2e10924e6b69966a9afe255f28bJohn Spurlock        setRingerModeInt(getRingerModeInternal(), false);
245033902db75011d863009585682bd08560c5b89a75Eric Laurent
2451212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent        checkAllFixedVolumeDevices();
2452244820185269991186d07068b92985624cede4a5Eric Laurent        checkAllAliasStreamVolumes();
2453244820185269991186d07068b92985624cede4a5Eric Laurent
2454d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent        synchronized (mSafeMediaVolumeState) {
2455aa5ee4d65f8788e2a0afcd198367450853fd72acJohn Spurlock            mMusicActiveMs = MathUtils.constrain(Settings.Secure.getIntForUser(mContentResolver,
2456aa5ee4d65f8788e2a0afcd198367450853fd72acJohn Spurlock                    Settings.Secure.UNSAFE_VOLUME_MUSIC_ACTIVE_MS, 0, UserHandle.USER_CURRENT),
2457aa5ee4d65f8788e2a0afcd198367450853fd72acJohn Spurlock                    0, UNSAFE_VOLUME_MUSIC_ACTIVE_MS_MAX);
2458d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent            if (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_ACTIVE) {
2459f1a457d06c53a901ea08d2d3fb6e766bc06c4d4fEric Laurent                enforceSafeMediaVolume();
2460f1a457d06c53a901ea08d2d3fb6e766bc06c4d4fEric Laurent            }
2461c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent        }
24624050c93601b3c3609b21cc1e18a29b64747e7fa9Eric Laurent    }
24634050c93601b3c3609b21cc1e18a29b64747e7fa9Eric Laurent
2464961cae92540763226648813d111c5b5c3b0f1597Dianne Hackborn    /** @see AudioManager#setSpeakerphoneOn(boolean) */
2465c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent    public void setSpeakerphoneOn(boolean on){
2466dc1d17a1dbfc2ae01c20012133a836b62f5b6930Eric Laurent        if (!checkAudioSettingsPermission("setSpeakerphoneOn()")) {
2467dc1d17a1dbfc2ae01c20012133a836b62f5b6930Eric Laurent            return;
2468dc1d17a1dbfc2ae01c20012133a836b62f5b6930Eric Laurent        }
24697337bee7839238f244fad31112a45389f6ef907cJohan Gustavsson
24707337bee7839238f244fad31112a45389f6ef907cJohan Gustavsson        if (on) {
24717337bee7839238f244fad31112a45389f6ef907cJohan Gustavsson            if (mForcedUseForComm == AudioSystem.FORCE_BT_SCO) {
24727337bee7839238f244fad31112a45389f6ef907cJohan Gustavsson                    sendMsg(mAudioHandler, MSG_SET_FORCE_USE, SENDMSG_QUEUE,
24737337bee7839238f244fad31112a45389f6ef907cJohan Gustavsson                            AudioSystem.FOR_RECORD, AudioSystem.FORCE_NONE, null, 0);
24747337bee7839238f244fad31112a45389f6ef907cJohan Gustavsson            }
24757337bee7839238f244fad31112a45389f6ef907cJohan Gustavsson            mForcedUseForComm = AudioSystem.FORCE_SPEAKER;
24767337bee7839238f244fad31112a45389f6ef907cJohan Gustavsson        } else if (mForcedUseForComm == AudioSystem.FORCE_SPEAKER){
24777337bee7839238f244fad31112a45389f6ef907cJohan Gustavsson            mForcedUseForComm = AudioSystem.FORCE_NONE;
24787337bee7839238f244fad31112a45389f6ef907cJohan Gustavsson        }
2479fa640154f1f42121d81242b2f1a10f03e52f0014Eric Laurent
2480afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent        sendMsg(mAudioHandler, MSG_SET_FORCE_USE, SENDMSG_QUEUE,
2481fa640154f1f42121d81242b2f1a10f03e52f0014Eric Laurent                AudioSystem.FOR_COMMUNICATION, mForcedUseForComm, null, 0);
2482c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent    }
2483c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent
2484c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent    /** @see AudioManager#isSpeakerphoneOn() */
2485c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent    public boolean isSpeakerphoneOn() {
2486fa640154f1f42121d81242b2f1a10f03e52f0014Eric Laurent        return (mForcedUseForComm == AudioSystem.FORCE_SPEAKER);
2487c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent    }
2488c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent
2489961cae92540763226648813d111c5b5c3b0f1597Dianne Hackborn    /** @see AudioManager#setBluetoothScoOn(boolean) */
2490c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent    public void setBluetoothScoOn(boolean on){
2491dc1d17a1dbfc2ae01c20012133a836b62f5b6930Eric Laurent        if (!checkAudioSettingsPermission("setBluetoothScoOn()")) {
2492dc1d17a1dbfc2ae01c20012133a836b62f5b6930Eric Laurent            return;
2493dc1d17a1dbfc2ae01c20012133a836b62f5b6930Eric Laurent        }
24947337bee7839238f244fad31112a45389f6ef907cJohan Gustavsson
24957337bee7839238f244fad31112a45389f6ef907cJohan Gustavsson        if (on) {
24967337bee7839238f244fad31112a45389f6ef907cJohan Gustavsson            mForcedUseForComm = AudioSystem.FORCE_BT_SCO;
24977337bee7839238f244fad31112a45389f6ef907cJohan Gustavsson        } else if (mForcedUseForComm == AudioSystem.FORCE_BT_SCO) {
24987337bee7839238f244fad31112a45389f6ef907cJohan Gustavsson            mForcedUseForComm = AudioSystem.FORCE_NONE;
24997337bee7839238f244fad31112a45389f6ef907cJohan Gustavsson        }
2500fa640154f1f42121d81242b2f1a10f03e52f0014Eric Laurent
2501afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent        sendMsg(mAudioHandler, MSG_SET_FORCE_USE, SENDMSG_QUEUE,
2502fa640154f1f42121d81242b2f1a10f03e52f0014Eric Laurent                AudioSystem.FOR_COMMUNICATION, mForcedUseForComm, null, 0);
2503afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent        sendMsg(mAudioHandler, MSG_SET_FORCE_USE, SENDMSG_QUEUE,
2504fa640154f1f42121d81242b2f1a10f03e52f0014Eric Laurent                AudioSystem.FOR_RECORD, mForcedUseForComm, null, 0);
2505c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent    }
2506c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent
2507c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent    /** @see AudioManager#isBluetoothScoOn() */
2508c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent    public boolean isBluetoothScoOn() {
2509fa640154f1f42121d81242b2f1a10f03e52f0014Eric Laurent        return (mForcedUseForComm == AudioSystem.FORCE_BT_SCO);
2510c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent    }
2511c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent
2512961cae92540763226648813d111c5b5c3b0f1597Dianne Hackborn    /** @see AudioManager#setBluetoothA2dpOn(boolean) */
25137847211fb4699bf6018e29d214a918ed6657319bEric Laurent    public void setBluetoothA2dpOn(boolean on) {
2514c390bed06b4a572e273ead1254da9a932e04dce3Eric Laurent        synchronized (mBluetoothA2dpEnabledLock) {
2515c390bed06b4a572e273ead1254da9a932e04dce3Eric Laurent            mBluetoothA2dpEnabled = on;
2516c390bed06b4a572e273ead1254da9a932e04dce3Eric Laurent            sendMsg(mAudioHandler, MSG_SET_FORCE_BT_A2DP_USE, SENDMSG_QUEUE,
2517c390bed06b4a572e273ead1254da9a932e04dce3Eric Laurent                    AudioSystem.FOR_MEDIA,
2518c390bed06b4a572e273ead1254da9a932e04dce3Eric Laurent                    mBluetoothA2dpEnabled ? AudioSystem.FORCE_NONE : AudioSystem.FORCE_NO_BT_A2DP,
2519c390bed06b4a572e273ead1254da9a932e04dce3Eric Laurent                    null, 0);
2520c390bed06b4a572e273ead1254da9a932e04dce3Eric Laurent        }
25217847211fb4699bf6018e29d214a918ed6657319bEric Laurent    }
25227847211fb4699bf6018e29d214a918ed6657319bEric Laurent
25237847211fb4699bf6018e29d214a918ed6657319bEric Laurent    /** @see AudioManager#isBluetoothA2dpOn() */
25247847211fb4699bf6018e29d214a918ed6657319bEric Laurent    public boolean isBluetoothA2dpOn() {
25257847211fb4699bf6018e29d214a918ed6657319bEric Laurent        synchronized (mBluetoothA2dpEnabledLock) {
25267847211fb4699bf6018e29d214a918ed6657319bEric Laurent            return mBluetoothA2dpEnabled;
25277847211fb4699bf6018e29d214a918ed6657319bEric Laurent        }
25287847211fb4699bf6018e29d214a918ed6657319bEric Laurent    }
25297847211fb4699bf6018e29d214a918ed6657319bEric Laurent
25303def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent    /** @see AudioManager#startBluetoothSco() */
253183900754f357616b9e56eaf7fc85f49b8906e987Eric Laurent    public void startBluetoothSco(IBinder cb, int targetSdkVersion) {
253283900754f357616b9e56eaf7fc85f49b8906e987Eric Laurent        int scoAudioMode =
253383900754f357616b9e56eaf7fc85f49b8906e987Eric Laurent                (targetSdkVersion < Build.VERSION_CODES.JELLY_BEAN_MR2) ?
2534f4e51d82d2e34e6832903f01eaecc15ded6c3241Liejun Tao                        SCO_MODE_VIRTUAL_CALL : SCO_MODE_UNDEFINED;
253583900754f357616b9e56eaf7fc85f49b8906e987Eric Laurent        startBluetoothScoInt(cb, scoAudioMode);
253683900754f357616b9e56eaf7fc85f49b8906e987Eric Laurent    }
253783900754f357616b9e56eaf7fc85f49b8906e987Eric Laurent
253883900754f357616b9e56eaf7fc85f49b8906e987Eric Laurent    /** @see AudioManager#startBluetoothScoVirtualCall() */
253983900754f357616b9e56eaf7fc85f49b8906e987Eric Laurent    public void startBluetoothScoVirtualCall(IBinder cb) {
254083900754f357616b9e56eaf7fc85f49b8906e987Eric Laurent        startBluetoothScoInt(cb, SCO_MODE_VIRTUAL_CALL);
254183900754f357616b9e56eaf7fc85f49b8906e987Eric Laurent    }
254283900754f357616b9e56eaf7fc85f49b8906e987Eric Laurent
254383900754f357616b9e56eaf7fc85f49b8906e987Eric Laurent    void startBluetoothScoInt(IBinder cb, int scoAudioMode){
2544dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent        if (!checkAudioSettingsPermission("startBluetoothSco()") ||
25454a5eeb9c727d77bb57fef87a70c8c9cc23dbfee3Eric Laurent                !mSystemReady) {
25463def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent            return;
25473def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent        }
2548854938a72d968c1bc0de4e2b0ea87777cfebc045Eric Laurent        ScoClient client = getScoClient(cb, true);
2549f5a1fc3c0fd733acd21e1437f153ba27220be8ceEric Laurent        // The calling identity must be cleared before calling ScoClient.incCount().
2550f5a1fc3c0fd733acd21e1437f153ba27220be8ceEric Laurent        // inCount() calls requestScoState() which in turn can call BluetoothHeadset APIs
2551f5a1fc3c0fd733acd21e1437f153ba27220be8ceEric Laurent        // and this must be done on behalf of system server to make sure permissions are granted.
2552f5a1fc3c0fd733acd21e1437f153ba27220be8ceEric Laurent        // The caller identity must be cleared after getScoClient() because it is needed if a new
2553f5a1fc3c0fd733acd21e1437f153ba27220be8ceEric Laurent        // client is created.
2554f5a1fc3c0fd733acd21e1437f153ba27220be8ceEric Laurent        final long ident = Binder.clearCallingIdentity();
255583900754f357616b9e56eaf7fc85f49b8906e987Eric Laurent        client.incCount(scoAudioMode);
25562a57ca931fefe817b6110101289721acaacfc808Eric Laurent        Binder.restoreCallingIdentity(ident);
25573def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent    }
25583def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent
25593def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent    /** @see AudioManager#stopBluetoothSco() */
25603def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent    public void stopBluetoothSco(IBinder cb){
2561dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent        if (!checkAudioSettingsPermission("stopBluetoothSco()") ||
25624a5eeb9c727d77bb57fef87a70c8c9cc23dbfee3Eric Laurent                !mSystemReady) {
25633def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent            return;
25643def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent        }
2565854938a72d968c1bc0de4e2b0ea87777cfebc045Eric Laurent        ScoClient client = getScoClient(cb, false);
2566f5a1fc3c0fd733acd21e1437f153ba27220be8ceEric Laurent        // The calling identity must be cleared before calling ScoClient.decCount().
2567f5a1fc3c0fd733acd21e1437f153ba27220be8ceEric Laurent        // decCount() calls requestScoState() which in turn can call BluetoothHeadset APIs
2568f5a1fc3c0fd733acd21e1437f153ba27220be8ceEric Laurent        // and this must be done on behalf of system server to make sure permissions are granted.
2569f5a1fc3c0fd733acd21e1437f153ba27220be8ceEric Laurent        final long ident = Binder.clearCallingIdentity();
2570854938a72d968c1bc0de4e2b0ea87777cfebc045Eric Laurent        if (client != null) {
2571854938a72d968c1bc0de4e2b0ea87777cfebc045Eric Laurent            client.decCount();
2572854938a72d968c1bc0de4e2b0ea87777cfebc045Eric Laurent        }
25732a57ca931fefe817b6110101289721acaacfc808Eric Laurent        Binder.restoreCallingIdentity(ident);
25743def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent    }
25753def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent
25767847211fb4699bf6018e29d214a918ed6657319bEric Laurent
25773def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent    private class ScoClient implements IBinder.DeathRecipient {
25783def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent        private IBinder mCb; // To be notified of client's death
2579f1ddd51f9cd2f92b922bc636c307210a8d587c25Marco Nelissen        private int mCreatorPid;
25803def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent        private int mStartcount; // number of SCO connections started by this client
25813def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent
25823def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent        ScoClient(IBinder cb) {
25833def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent            mCb = cb;
2584f1ddd51f9cd2f92b922bc636c307210a8d587c25Marco Nelissen            mCreatorPid = Binder.getCallingPid();
25853def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent            mStartcount = 0;
25863def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent        }
25873def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent
25883def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent        public void binderDied() {
25893def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent            synchronized(mScoClients) {
25903def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                Log.w(TAG, "SCO client died");
25913def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                int index = mScoClients.indexOf(this);
25923def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                if (index < 0) {
25933def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                    Log.w(TAG, "unregistered SCO client died");
25943def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                } else {
25953def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                    clearCount(true);
25963def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                    mScoClients.remove(this);
25973def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                }
25983def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent            }
25993def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent        }
26003def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent
260183900754f357616b9e56eaf7fc85f49b8906e987Eric Laurent        public void incCount(int scoAudioMode) {
26023def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent            synchronized(mScoClients) {
260383900754f357616b9e56eaf7fc85f49b8906e987Eric Laurent                requestScoState(BluetoothHeadset.STATE_AUDIO_CONNECTED, scoAudioMode);
26043def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                if (mStartcount == 0) {
26053def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                    try {
26063def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                        mCb.linkToDeath(this, 0);
26073def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                    } catch (RemoteException e) {
26083def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                        // client has already died!
26093def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                        Log.w(TAG, "ScoClient  incCount() could not link to "+mCb+" binder death");
26103def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                    }
26113def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                }
26123def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                mStartcount++;
26133def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent            }
26143def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent        }
26153def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent
26163def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent        public void decCount() {
26173def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent            synchronized(mScoClients) {
26183def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                if (mStartcount == 0) {
26193def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                    Log.w(TAG, "ScoClient.decCount() already 0");
26203def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                } else {
26213def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                    mStartcount--;
26223def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                    if (mStartcount == 0) {
2623e2dd8c4592762414c2c27e4589be7edc91a5ecaeEric Laurent                        try {
2624e2dd8c4592762414c2c27e4589be7edc91a5ecaeEric Laurent                            mCb.unlinkToDeath(this, 0);
2625e2dd8c4592762414c2c27e4589be7edc91a5ecaeEric Laurent                        } catch (NoSuchElementException e) {
2626e2dd8c4592762414c2c27e4589be7edc91a5ecaeEric Laurent                            Log.w(TAG, "decCount() going to 0 but not registered to binder");
2627e2dd8c4592762414c2c27e4589be7edc91a5ecaeEric Laurent                        }
26283def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                    }
2629c18c9138cee0f0859bcab636a004ce92ca4a9ab5Eric Laurent                    requestScoState(BluetoothHeadset.STATE_AUDIO_DISCONNECTED, 0);
26303def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                }
26313def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent            }
26323def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent        }
26333def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent
26343def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent        public void clearCount(boolean stopSco) {
26353def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent            synchronized(mScoClients) {
2636e2dd8c4592762414c2c27e4589be7edc91a5ecaeEric Laurent                if (mStartcount != 0) {
2637e2dd8c4592762414c2c27e4589be7edc91a5ecaeEric Laurent                    try {
2638e2dd8c4592762414c2c27e4589be7edc91a5ecaeEric Laurent                        mCb.unlinkToDeath(this, 0);
2639e2dd8c4592762414c2c27e4589be7edc91a5ecaeEric Laurent                    } catch (NoSuchElementException e) {
2640e2dd8c4592762414c2c27e4589be7edc91a5ecaeEric Laurent                        Log.w(TAG, "clearCount() mStartcount: "+mStartcount+" != 0 but not registered to binder");
2641e2dd8c4592762414c2c27e4589be7edc91a5ecaeEric Laurent                    }
2642e2dd8c4592762414c2c27e4589be7edc91a5ecaeEric Laurent                }
26433def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                mStartcount = 0;
26443def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                if (stopSco) {
2645c18c9138cee0f0859bcab636a004ce92ca4a9ab5Eric Laurent                    requestScoState(BluetoothHeadset.STATE_AUDIO_DISCONNECTED, 0);
26463def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                }
26473def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent            }
26483def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent        }
26493def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent
26503def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent        public int getCount() {
26513def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent            return mStartcount;
26523def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent        }
26533def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent
26543def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent        public IBinder getBinder() {
26553def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent            return mCb;
26563def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent        }
26573def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent
2658d7454be47f4111c0478a502353e11dea401378bdEric Laurent        public int getPid() {
2659d7454be47f4111c0478a502353e11dea401378bdEric Laurent            return mCreatorPid;
2660d7454be47f4111c0478a502353e11dea401378bdEric Laurent        }
2661d7454be47f4111c0478a502353e11dea401378bdEric Laurent
26623def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent        public int totalCount() {
26633def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent            synchronized(mScoClients) {
26643def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                int count = 0;
26653def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                int size = mScoClients.size();
26663def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                for (int i = 0; i < size; i++) {
26673def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                    count += mScoClients.get(i).getCount();
26683def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                }
26693def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                return count;
26703def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent            }
26713def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent        }
26723def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent
267383900754f357616b9e56eaf7fc85f49b8906e987Eric Laurent        private void requestScoState(int state, int scoAudioMode) {
267462ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent            checkScoAudioState();
2675dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent            if (totalCount() == 0) {
2676dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                if (state == BluetoothHeadset.STATE_AUDIO_CONNECTED) {
2677dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                    // Make sure that the state transitions to CONNECTING even if we cannot initiate
2678dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                    // the connection.
2679dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                    broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_CONNECTING);
2680dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                    // Accept SCO audio activation only in NORMAL audio mode or if the mode is
2681f1ddd51f9cd2f92b922bc636c307210a8d587c25Marco Nelissen                    // currently controlled by the same client process.
26829f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                    synchronized(mSetModeDeathHandlers) {
26839f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                        if ((mSetModeDeathHandlers.isEmpty() ||
26849f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                                mSetModeDeathHandlers.get(0).getPid() == mCreatorPid) &&
26859f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                                (mScoAudioState == SCO_STATE_INACTIVE ||
26869f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                                 mScoAudioState == SCO_STATE_DEACTIVATE_REQ)) {
26879f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                            if (mScoAudioState == SCO_STATE_INACTIVE) {
268883900754f357616b9e56eaf7fc85f49b8906e987Eric Laurent                                mScoAudioMode = scoAudioMode;
2689f4e51d82d2e34e6832903f01eaecc15ded6c3241Liejun Tao                                if (scoAudioMode == SCO_MODE_UNDEFINED) {
2690570cc5302a2e076f2b6ce810f9ac6f3c53bcd125Andre Eisenbach                                    if (mBluetoothHeadsetDevice != null) {
2691570cc5302a2e076f2b6ce810f9ac6f3c53bcd125Andre Eisenbach                                        mScoAudioMode = new Integer(Settings.Global.getInt(
2692570cc5302a2e076f2b6ce810f9ac6f3c53bcd125Andre Eisenbach                                                                mContentResolver,
2693570cc5302a2e076f2b6ce810f9ac6f3c53bcd125Andre Eisenbach                                                                "bluetooth_sco_channel_"+
2694570cc5302a2e076f2b6ce810f9ac6f3c53bcd125Andre Eisenbach                                                                mBluetoothHeadsetDevice.getAddress(),
2695570cc5302a2e076f2b6ce810f9ac6f3c53bcd125Andre Eisenbach                                                                SCO_MODE_VIRTUAL_CALL));
2696570cc5302a2e076f2b6ce810f9ac6f3c53bcd125Andre Eisenbach                                        if (mScoAudioMode > SCO_MODE_MAX || mScoAudioMode < 0) {
2697570cc5302a2e076f2b6ce810f9ac6f3c53bcd125Andre Eisenbach                                            mScoAudioMode = SCO_MODE_VIRTUAL_CALL;
2698570cc5302a2e076f2b6ce810f9ac6f3c53bcd125Andre Eisenbach                                        }
2699570cc5302a2e076f2b6ce810f9ac6f3c53bcd125Andre Eisenbach                                    } else {
2700570cc5302a2e076f2b6ce810f9ac6f3c53bcd125Andre Eisenbach                                        mScoAudioMode = SCO_MODE_RAW;
2701f4e51d82d2e34e6832903f01eaecc15ded6c3241Liejun Tao                                    }
2702f4e51d82d2e34e6832903f01eaecc15ded6c3241Liejun Tao                                }
27039f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                                if (mBluetoothHeadset != null && mBluetoothHeadsetDevice != null) {
2704f4e51d82d2e34e6832903f01eaecc15ded6c3241Liejun Tao                                    boolean status = false;
2705c18c9138cee0f0859bcab636a004ce92ca4a9ab5Eric Laurent                                    if (mScoAudioMode == SCO_MODE_RAW) {
2706c18c9138cee0f0859bcab636a004ce92ca4a9ab5Eric Laurent                                        status = mBluetoothHeadset.connectAudio();
2707f4e51d82d2e34e6832903f01eaecc15ded6c3241Liejun Tao                                    } else if (mScoAudioMode == SCO_MODE_VIRTUAL_CALL) {
2708c18c9138cee0f0859bcab636a004ce92ca4a9ab5Eric Laurent                                        status = mBluetoothHeadset.startScoUsingVirtualVoiceCall(
2709c18c9138cee0f0859bcab636a004ce92ca4a9ab5Eric Laurent                                                                            mBluetoothHeadsetDevice);
2710f4e51d82d2e34e6832903f01eaecc15ded6c3241Liejun Tao                                    } else if (mScoAudioMode == SCO_MODE_VR) {
2711f4e51d82d2e34e6832903f01eaecc15ded6c3241Liejun Tao                                        status = mBluetoothHeadset.startVoiceRecognition(
2712f4e51d82d2e34e6832903f01eaecc15ded6c3241Liejun Tao                                                                           mBluetoothHeadsetDevice);
2713c18c9138cee0f0859bcab636a004ce92ca4a9ab5Eric Laurent                                    }
2714f4e51d82d2e34e6832903f01eaecc15ded6c3241Liejun Tao
2715c18c9138cee0f0859bcab636a004ce92ca4a9ab5Eric Laurent                                    if (status) {
27169f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                                        mScoAudioState = SCO_STATE_ACTIVE_INTERNAL;
27179f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                                    } else {
27189f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                                        broadcastScoConnectionState(
27199f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                                                AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
27209f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                                    }
27219f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                                } else if (getBluetoothHeadset()) {
27229f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                                    mScoAudioState = SCO_STATE_ACTIVATE_REQ;
2723dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                                }
27249f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                            } else {
27259f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                                mScoAudioState = SCO_STATE_ACTIVE_INTERNAL;
27269f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                                broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_CONNECTED);
2727dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                            }
2728dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                        } else {
27299f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                            broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
2730dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                        }
2731dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                    }
273262ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent                } else if (state == BluetoothHeadset.STATE_AUDIO_DISCONNECTED &&
2733dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                              (mScoAudioState == SCO_STATE_ACTIVE_INTERNAL ||
2734dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                               mScoAudioState == SCO_STATE_ACTIVATE_REQ)) {
2735dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                    if (mScoAudioState == SCO_STATE_ACTIVE_INTERNAL) {
2736671db6f3ba1fdb3c907e0735fe6d0d284f5c34deMarco Nelissen                        if (mBluetoothHeadset != null && mBluetoothHeadsetDevice != null) {
2737f4e51d82d2e34e6832903f01eaecc15ded6c3241Liejun Tao                            boolean status = false;
2738c18c9138cee0f0859bcab636a004ce92ca4a9ab5Eric Laurent                            if (mScoAudioMode == SCO_MODE_RAW) {
2739c18c9138cee0f0859bcab636a004ce92ca4a9ab5Eric Laurent                                status = mBluetoothHeadset.disconnectAudio();
2740f4e51d82d2e34e6832903f01eaecc15ded6c3241Liejun Tao                            } else if (mScoAudioMode == SCO_MODE_VIRTUAL_CALL) {
2741c18c9138cee0f0859bcab636a004ce92ca4a9ab5Eric Laurent                                status = mBluetoothHeadset.stopScoUsingVirtualVoiceCall(
2742c18c9138cee0f0859bcab636a004ce92ca4a9ab5Eric Laurent                                                                        mBluetoothHeadsetDevice);
2743f4e51d82d2e34e6832903f01eaecc15ded6c3241Liejun Tao                            } else if (mScoAudioMode == SCO_MODE_VR) {
2744f4e51d82d2e34e6832903f01eaecc15ded6c3241Liejun Tao                                        status = mBluetoothHeadset.stopVoiceRecognition(
2745f4e51d82d2e34e6832903f01eaecc15ded6c3241Liejun Tao                                                                      mBluetoothHeadsetDevice);
2746c18c9138cee0f0859bcab636a004ce92ca4a9ab5Eric Laurent                            }
2747f4e51d82d2e34e6832903f01eaecc15ded6c3241Liejun Tao
2748c18c9138cee0f0859bcab636a004ce92ca4a9ab5Eric Laurent                            if (!status) {
2749dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                                mScoAudioState = SCO_STATE_INACTIVE;
2750dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                                broadcastScoConnectionState(
2751dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                                        AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
2752dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                            }
2753dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                        } else if (getBluetoothHeadset()) {
2754dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                            mScoAudioState = SCO_STATE_DEACTIVATE_REQ;
2755dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                        }
2756dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                    } else {
2757dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                        mScoAudioState = SCO_STATE_INACTIVE;
2758dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                        broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
2759dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                    }
27603def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                }
27613def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent            }
27623def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent        }
27633def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent    }
27643def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent
276562ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent    private void checkScoAudioState() {
276662ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent        if (mBluetoothHeadset != null && mBluetoothHeadsetDevice != null &&
2767dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                mScoAudioState == SCO_STATE_INACTIVE &&
276862ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent                mBluetoothHeadset.getAudioState(mBluetoothHeadsetDevice)
276962ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent                != BluetoothHeadset.STATE_AUDIO_DISCONNECTED) {
277062ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent            mScoAudioState = SCO_STATE_ACTIVE_EXTERNAL;
277162ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent        }
277262ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent    }
277362ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent
2774854938a72d968c1bc0de4e2b0ea87777cfebc045Eric Laurent    private ScoClient getScoClient(IBinder cb, boolean create) {
27753def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent        synchronized(mScoClients) {
2776854938a72d968c1bc0de4e2b0ea87777cfebc045Eric Laurent            ScoClient client = null;
27773def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent            int size = mScoClients.size();
27783def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent            for (int i = 0; i < size; i++) {
27793def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                client = mScoClients.get(i);
27803def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                if (client.getBinder() == cb)
27813def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                    return client;
27823def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent            }
2783854938a72d968c1bc0de4e2b0ea87777cfebc045Eric Laurent            if (create) {
2784854938a72d968c1bc0de4e2b0ea87777cfebc045Eric Laurent                client = new ScoClient(cb);
2785854938a72d968c1bc0de4e2b0ea87777cfebc045Eric Laurent                mScoClients.add(client);
2786854938a72d968c1bc0de4e2b0ea87777cfebc045Eric Laurent            }
27873def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent            return client;
27883def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent        }
27893def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent    }
27903def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent
2791d7454be47f4111c0478a502353e11dea401378bdEric Laurent    public void clearAllScoClients(int exceptPid, boolean stopSco) {
27923def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent        synchronized(mScoClients) {
2793854938a72d968c1bc0de4e2b0ea87777cfebc045Eric Laurent            ScoClient savedClient = null;
27943def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent            int size = mScoClients.size();
27953def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent            for (int i = 0; i < size; i++) {
2796854938a72d968c1bc0de4e2b0ea87777cfebc045Eric Laurent                ScoClient cl = mScoClients.get(i);
2797d7454be47f4111c0478a502353e11dea401378bdEric Laurent                if (cl.getPid() != exceptPid) {
2798854938a72d968c1bc0de4e2b0ea87777cfebc045Eric Laurent                    cl.clearCount(stopSco);
2799854938a72d968c1bc0de4e2b0ea87777cfebc045Eric Laurent                } else {
2800854938a72d968c1bc0de4e2b0ea87777cfebc045Eric Laurent                    savedClient = cl;
2801854938a72d968c1bc0de4e2b0ea87777cfebc045Eric Laurent                }
2802854938a72d968c1bc0de4e2b0ea87777cfebc045Eric Laurent            }
2803854938a72d968c1bc0de4e2b0ea87777cfebc045Eric Laurent            mScoClients.clear();
2804854938a72d968c1bc0de4e2b0ea87777cfebc045Eric Laurent            if (savedClient != null) {
2805854938a72d968c1bc0de4e2b0ea87777cfebc045Eric Laurent                mScoClients.add(savedClient);
28063def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent            }
28073def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent        }
28083def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent    }
28093def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent
2810dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent    private boolean getBluetoothHeadset() {
2811dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent        boolean result = false;
2812dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent        BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
2813dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent        if (adapter != null) {
2814dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent            result = adapter.getProfileProxy(mContext, mBluetoothProfileServiceListener,
2815dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                                    BluetoothProfile.HEADSET);
2816dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent        }
2817dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent        // If we could not get a bluetooth headset proxy, send a failure message
2818dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent        // without delay to reset the SCO audio state and clear SCO clients.
2819dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent        // If we could get a proxy, send a delayed failure message that will reset our state
2820dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent        // in case we don't receive onServiceConnected().
2821afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent        sendMsg(mAudioHandler, MSG_BT_HEADSET_CNCT_FAILED,
2822dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                SENDMSG_REPLACE, 0, 0, null, result ? BT_HEADSET_CNCT_TIMEOUT_MS : 0);
2823dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent        return result;
2824dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent    }
2825dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent
2826d7454be47f4111c0478a502353e11dea401378bdEric Laurent    private void disconnectBluetoothSco(int exceptPid) {
2827dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent        synchronized(mScoClients) {
2828dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent            checkScoAudioState();
2829dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent            if (mScoAudioState == SCO_STATE_ACTIVE_EXTERNAL ||
2830dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                    mScoAudioState == SCO_STATE_DEACTIVATE_EXT_REQ) {
2831dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                if (mBluetoothHeadsetDevice != null) {
2832dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                    if (mBluetoothHeadset != null) {
2833dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                        if (!mBluetoothHeadset.stopVoiceRecognition(
2834b06ac839dd2d0437fc8314f6deb7233af5af521eEric Laurent                                mBluetoothHeadsetDevice)) {
2835afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent                            sendMsg(mAudioHandler, MSG_BT_HEADSET_CNCT_FAILED,
2836dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                                    SENDMSG_REPLACE, 0, 0, null, 0);
2837dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                        }
2838dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                    } else if (mScoAudioState == SCO_STATE_ACTIVE_EXTERNAL &&
2839dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                            getBluetoothHeadset()) {
2840dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                        mScoAudioState = SCO_STATE_DEACTIVATE_EXT_REQ;
2841dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                    }
2842dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                }
2843dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent            } else {
2844d7454be47f4111c0478a502353e11dea401378bdEric Laurent                clearAllScoClients(exceptPid, true);
2845dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent            }
2846dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent        }
2847dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent    }
2848dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent
2849dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent    private void resetBluetoothSco() {
2850dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent        synchronized(mScoClients) {
2851d7454be47f4111c0478a502353e11dea401378bdEric Laurent            clearAllScoClients(0, false);
2852dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent            mScoAudioState = SCO_STATE_INACTIVE;
2853dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent            broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
2854dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent        }
2855dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent    }
2856dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent
2857dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent    private void broadcastScoConnectionState(int state) {
28582a57ca931fefe817b6110101289721acaacfc808Eric Laurent        sendMsg(mAudioHandler, MSG_BROADCAST_BT_CONNECTION_STATE,
28592a57ca931fefe817b6110101289721acaacfc808Eric Laurent                SENDMSG_QUEUE, state, 0, null, 0);
28602a57ca931fefe817b6110101289721acaacfc808Eric Laurent    }
28612a57ca931fefe817b6110101289721acaacfc808Eric Laurent
28622a57ca931fefe817b6110101289721acaacfc808Eric Laurent    private void onBroadcastScoConnectionState(int state) {
2863dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent        if (state != mScoConnectionState) {
2864dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent            Intent newIntent = new Intent(AudioManager.ACTION_SCO_AUDIO_STATE_UPDATED);
2865dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent            newIntent.putExtra(AudioManager.EXTRA_SCO_AUDIO_STATE, state);
2866dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent            newIntent.putExtra(AudioManager.EXTRA_SCO_AUDIO_PREVIOUS_STATE,
2867dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                    mScoConnectionState);
28685ac72a29593ab9a20337a2225df52bdf4754be02Dianne Hackborn            sendStickyBroadcastToAll(newIntent);
2869dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent            mScoConnectionState = state;
2870dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent        }
2871dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent    }
2872dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent
287382aa7f017daaaeb96c13e6e3491d5037ab471085Jaikumar Ganesh    private BluetoothProfile.ServiceListener mBluetoothProfileServiceListener =
287482aa7f017daaaeb96c13e6e3491d5037ab471085Jaikumar Ganesh        new BluetoothProfile.ServiceListener() {
287582aa7f017daaaeb96c13e6e3491d5037ab471085Jaikumar Ganesh        public void onServiceConnected(int profile, BluetoothProfile proxy) {
28766bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent            BluetoothDevice btDevice;
28776bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent            List<BluetoothDevice> deviceList;
28786bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent            switch(profile) {
28796bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent            case BluetoothProfile.A2DP:
28805a0cf7a27f3953a1266af48543ccd9024f4cd89fJohn Du                synchronized (mA2dpAvrcpLock) {
28815a0cf7a27f3953a1266af48543ccd9024f4cd89fJohn Du                    mA2dp = (BluetoothA2dp) proxy;
28825a0cf7a27f3953a1266af48543ccd9024f4cd89fJohn Du                    deviceList = mA2dp.getConnectedDevices();
28835a0cf7a27f3953a1266af48543ccd9024f4cd89fJohn Du                    if (deviceList.size() > 0) {
28845a0cf7a27f3953a1266af48543ccd9024f4cd89fJohn Du                        btDevice = deviceList.get(0);
28855a0cf7a27f3953a1266af48543ccd9024f4cd89fJohn Du                        synchronized (mConnectedDevices) {
28865a0cf7a27f3953a1266af48543ccd9024f4cd89fJohn Du                            int state = mA2dp.getConnectionState(btDevice);
28875a0cf7a27f3953a1266af48543ccd9024f4cd89fJohn Du                            int delay = checkSendBecomingNoisyIntent(
28880a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood                                                AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
28890a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood                                                (state == BluetoothA2dp.STATE_CONNECTED) ? 1 : 0);
28905a0cf7a27f3953a1266af48543ccd9024f4cd89fJohn Du                            queueMsgUnderWakeLock(mAudioHandler,
28910a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood                                    MSG_SET_A2DP_SINK_CONNECTION_STATE,
28925a0cf7a27f3953a1266af48543ccd9024f4cd89fJohn Du                                    state,
28935a0cf7a27f3953a1266af48543ccd9024f4cd89fJohn Du                                    0,
28945a0cf7a27f3953a1266af48543ccd9024f4cd89fJohn Du                                    btDevice,
28955a0cf7a27f3953a1266af48543ccd9024f4cd89fJohn Du                                    delay);
28965a0cf7a27f3953a1266af48543ccd9024f4cd89fJohn Du                        }
2897b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent                    }
28986bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                }
28996bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                break;
29006bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent
29010a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood            case BluetoothProfile.A2DP_SINK:
29020a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood                deviceList = proxy.getConnectedDevices();
29030a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood                if (deviceList.size() > 0) {
29040a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood                    btDevice = deviceList.get(0);
29050a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood                    synchronized (mConnectedDevices) {
29060a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood                        int state = proxy.getConnectionState(btDevice);
29070a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood                        queueMsgUnderWakeLock(mAudioHandler,
29080a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood                                MSG_SET_A2DP_SRC_CONNECTION_STATE,
29090a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood                                state,
29100a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood                                0,
29110a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood                                btDevice,
29120a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood                                0 /* delay */);
29130a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood                    }
29140a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood                }
29150a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood                break;
29160a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood
29176bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent            case BluetoothProfile.HEADSET:
29186bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                synchronized (mScoClients) {
29196bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                    // Discard timeout message
29206bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                    mAudioHandler.removeMessages(MSG_BT_HEADSET_CNCT_FAILED);
29216bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                    mBluetoothHeadset = (BluetoothHeadset) proxy;
29226bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                    deviceList = mBluetoothHeadset.getConnectedDevices();
29236bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                    if (deviceList.size() > 0) {
29246bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                        mBluetoothHeadsetDevice = deviceList.get(0);
29256bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                    } else {
29266bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                        mBluetoothHeadsetDevice = null;
2927dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                    }
29286bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                    // Refresh SCO audio state
29296bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                    checkScoAudioState();
29306bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                    // Continue pending action if any
29316bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                    if (mScoAudioState == SCO_STATE_ACTIVATE_REQ ||
29326bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                            mScoAudioState == SCO_STATE_DEACTIVATE_REQ ||
29336bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                            mScoAudioState == SCO_STATE_DEACTIVATE_EXT_REQ) {
29346bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                        boolean status = false;
29356bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                        if (mBluetoothHeadsetDevice != null) {
29366bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                            switch (mScoAudioState) {
29376bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                            case SCO_STATE_ACTIVATE_REQ:
29386bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                                mScoAudioState = SCO_STATE_ACTIVE_INTERNAL;
2939c18c9138cee0f0859bcab636a004ce92ca4a9ab5Eric Laurent                                if (mScoAudioMode == SCO_MODE_RAW) {
2940c18c9138cee0f0859bcab636a004ce92ca4a9ab5Eric Laurent                                    status = mBluetoothHeadset.connectAudio();
2941f4e51d82d2e34e6832903f01eaecc15ded6c3241Liejun Tao                                } else if (mScoAudioMode == SCO_MODE_VIRTUAL_CALL) {
2942c18c9138cee0f0859bcab636a004ce92ca4a9ab5Eric Laurent                                    status = mBluetoothHeadset.startScoUsingVirtualVoiceCall(
2943c18c9138cee0f0859bcab636a004ce92ca4a9ab5Eric Laurent                                                                        mBluetoothHeadsetDevice);
2944f4e51d82d2e34e6832903f01eaecc15ded6c3241Liejun Tao                                } else if (mScoAudioMode == SCO_MODE_VR) {
2945f4e51d82d2e34e6832903f01eaecc15ded6c3241Liejun Tao                                    status = mBluetoothHeadset.startVoiceRecognition(
2946f4e51d82d2e34e6832903f01eaecc15ded6c3241Liejun Tao                                                                      mBluetoothHeadsetDevice);
2947c18c9138cee0f0859bcab636a004ce92ca4a9ab5Eric Laurent                                }
29486bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                                break;
29496bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                            case SCO_STATE_DEACTIVATE_REQ:
2950c18c9138cee0f0859bcab636a004ce92ca4a9ab5Eric Laurent                                if (mScoAudioMode == SCO_MODE_RAW) {
2951c18c9138cee0f0859bcab636a004ce92ca4a9ab5Eric Laurent                                    status = mBluetoothHeadset.disconnectAudio();
2952f4e51d82d2e34e6832903f01eaecc15ded6c3241Liejun Tao                                } else if (mScoAudioMode == SCO_MODE_VIRTUAL_CALL) {
2953c18c9138cee0f0859bcab636a004ce92ca4a9ab5Eric Laurent                                    status = mBluetoothHeadset.stopScoUsingVirtualVoiceCall(
2954c18c9138cee0f0859bcab636a004ce92ca4a9ab5Eric Laurent                                                                        mBluetoothHeadsetDevice);
2955f4e51d82d2e34e6832903f01eaecc15ded6c3241Liejun Tao                                } else if (mScoAudioMode == SCO_MODE_VR) {
2956f4e51d82d2e34e6832903f01eaecc15ded6c3241Liejun Tao                                    status = mBluetoothHeadset.stopVoiceRecognition(
2957f4e51d82d2e34e6832903f01eaecc15ded6c3241Liejun Tao                                                                      mBluetoothHeadsetDevice);
2958c18c9138cee0f0859bcab636a004ce92ca4a9ab5Eric Laurent                                }
29596bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                                break;
29606bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                            case SCO_STATE_DEACTIVATE_EXT_REQ:
29616bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                                status = mBluetoothHeadset.stopVoiceRecognition(
29626bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                                        mBluetoothHeadsetDevice);
29636bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                            }
29646bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                        }
29656bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                        if (!status) {
2966afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent                            sendMsg(mAudioHandler, MSG_BT_HEADSET_CNCT_FAILED,
29676bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                                    SENDMSG_REPLACE, 0, 0, null, 0);
29686bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                        }
2969dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                    }
2970dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                }
29716bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                break;
29726bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent
29736bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent            default:
29746bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                break;
29753def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent            }
29763def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent        }
297782aa7f017daaaeb96c13e6e3491d5037ab471085Jaikumar Ganesh        public void onServiceDisconnected(int profile) {
29786bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent            switch(profile) {
29796bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent            case BluetoothProfile.A2DP:
29805a0cf7a27f3953a1266af48543ccd9024f4cd89fJohn Du                synchronized (mA2dpAvrcpLock) {
29815a0cf7a27f3953a1266af48543ccd9024f4cd89fJohn Du                    mA2dp = null;
29825a0cf7a27f3953a1266af48543ccd9024f4cd89fJohn Du                    synchronized (mConnectedDevices) {
29835a0cf7a27f3953a1266af48543ccd9024f4cd89fJohn Du                        if (mConnectedDevices.containsKey(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP)) {
29845a0cf7a27f3953a1266af48543ccd9024f4cd89fJohn Du                            makeA2dpDeviceUnavailableNow(
29855a0cf7a27f3953a1266af48543ccd9024f4cd89fJohn Du                                    mConnectedDevices.get(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP));
29865a0cf7a27f3953a1266af48543ccd9024f4cd89fJohn Du                        }
29876bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                    }
29886bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                }
29896bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                break;
29906bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent
29910a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood            case BluetoothProfile.A2DP_SINK:
29920a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood                synchronized (mConnectedDevices) {
29930a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood                    if (mConnectedDevices.containsKey(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP)) {
29940a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood                        makeA2dpSrcUnavailable(
29950a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood                                mConnectedDevices.get(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP));
29960a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood                    }
29970a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood                }
29980a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood                break;
29990a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood
30006bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent            case BluetoothProfile.HEADSET:
30016bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                synchronized (mScoClients) {
30026bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                    mBluetoothHeadset = null;
30036bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                }
30046bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                break;
30056bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent
30066bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent            default:
30076bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                break;
30083def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent            }
30093def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent        }
30103def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent    };
3011d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi
3012c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent    private void onCheckMusicActive() {
3013d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent        synchronized (mSafeMediaVolumeState) {
3014d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent            if (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_INACTIVE) {
3015c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent                int device = getDeviceForStream(AudioSystem.STREAM_MUSIC);
3016c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent
3017c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent                if ((device & mSafeMediaVolumeDevices) != 0) {
3018c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent                    sendMsg(mAudioHandler,
3019c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent                            MSG_CHECK_MUSIC_ACTIVE,
3020c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent                            SENDMSG_REPLACE,
3021f1a457d06c53a901ea08d2d3fb6e766bc06c4d4fEric Laurent                            0,
3022c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent                            0,
3023c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent                            null,
3024c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent                            MUSIC_ACTIVE_POLL_PERIOD_MS);
302542b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                    int index = mStreamStates[AudioSystem.STREAM_MUSIC].getIndex(device);
3026f1a457d06c53a901ea08d2d3fb6e766bc06c4d4fEric Laurent                    if (AudioSystem.isStreamActive(AudioSystem.STREAM_MUSIC, 0) &&
3027f1a457d06c53a901ea08d2d3fb6e766bc06c4d4fEric Laurent                            (index > mSafeMediaVolumeIndex)) {
3028c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent                        // Approximate cumulative active music time
3029c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent                        mMusicActiveMs += MUSIC_ACTIVE_POLL_PERIOD_MS;
3030c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent                        if (mMusicActiveMs > UNSAFE_VOLUME_MUSIC_ACTIVE_MS_MAX) {
3031c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent                            setSafeMediaVolumeEnabled(true);
3032c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent                            mMusicActiveMs = 0;
3033c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent                        }
3034aa5ee4d65f8788e2a0afcd198367450853fd72acJohn Spurlock                        saveMusicActiveMs();
3035c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent                    }
3036c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent                }
3037c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent            }
3038c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent        }
3039c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent    }
3040c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent
3041aa5ee4d65f8788e2a0afcd198367450853fd72acJohn Spurlock    private void saveMusicActiveMs() {
3042aa5ee4d65f8788e2a0afcd198367450853fd72acJohn Spurlock        mAudioHandler.obtainMessage(MSG_PERSIST_MUSIC_ACTIVE_MS, mMusicActiveMs, 0).sendToTarget();
3043aa5ee4d65f8788e2a0afcd198367450853fd72acJohn Spurlock    }
3044aa5ee4d65f8788e2a0afcd198367450853fd72acJohn Spurlock
3045d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent    private void onConfigureSafeVolume(boolean force) {
3046d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent        synchronized (mSafeMediaVolumeState) {
3047d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent            int mcc = mContext.getResources().getConfiguration().mcc;
3048d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent            if ((mMcc != mcc) || ((mMcc == 0) && force)) {
3049d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent                mSafeMediaVolumeIndex = mContext.getResources().getInteger(
3050d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent                        com.android.internal.R.integer.config_safe_media_volume_index) * 10;
3051351346092acdfbfcc1d9ebf98d539d2a1196c5e8John Spurlock                boolean safeMediaVolumeEnabled =
3052351346092acdfbfcc1d9ebf98d539d2a1196c5e8John Spurlock                        SystemProperties.getBoolean("audio.safemedia.force", false)
3053351346092acdfbfcc1d9ebf98d539d2a1196c5e8John Spurlock                        || mContext.getResources().getBoolean(
3054351346092acdfbfcc1d9ebf98d539d2a1196c5e8John Spurlock                                com.android.internal.R.bool.config_safe_media_volume_enabled);
305505274f348e12983eb8613cc6eb9ae561e8197e28Eric Laurent
305605274f348e12983eb8613cc6eb9ae561e8197e28Eric Laurent                // The persisted state is either "disabled" or "active": this is the state applied
305705274f348e12983eb8613cc6eb9ae561e8197e28Eric Laurent                // next time we boot and cannot be "inactive"
305805274f348e12983eb8613cc6eb9ae561e8197e28Eric Laurent                int persistedState;
3059d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent                if (safeMediaVolumeEnabled) {
306005274f348e12983eb8613cc6eb9ae561e8197e28Eric Laurent                    persistedState = SAFE_MEDIA_VOLUME_ACTIVE;
306105274f348e12983eb8613cc6eb9ae561e8197e28Eric Laurent                    // The state can already be "inactive" here if the user has forced it before
306205274f348e12983eb8613cc6eb9ae561e8197e28Eric Laurent                    // the 30 seconds timeout for forced configuration. In this case we don't reset
306305274f348e12983eb8613cc6eb9ae561e8197e28Eric Laurent                    // it to "active".
306405274f348e12983eb8613cc6eb9ae561e8197e28Eric Laurent                    if (mSafeMediaVolumeState != SAFE_MEDIA_VOLUME_INACTIVE) {
3065aa5ee4d65f8788e2a0afcd198367450853fd72acJohn Spurlock                        if (mMusicActiveMs == 0) {
3066aa5ee4d65f8788e2a0afcd198367450853fd72acJohn Spurlock                            mSafeMediaVolumeState = SAFE_MEDIA_VOLUME_ACTIVE;
3067aa5ee4d65f8788e2a0afcd198367450853fd72acJohn Spurlock                            enforceSafeMediaVolume();
3068aa5ee4d65f8788e2a0afcd198367450853fd72acJohn Spurlock                        } else {
3069aa5ee4d65f8788e2a0afcd198367450853fd72acJohn Spurlock                            // We have existing playback time recorded, already confirmed.
3070aa5ee4d65f8788e2a0afcd198367450853fd72acJohn Spurlock                            mSafeMediaVolumeState = SAFE_MEDIA_VOLUME_INACTIVE;
3071aa5ee4d65f8788e2a0afcd198367450853fd72acJohn Spurlock                        }
307205274f348e12983eb8613cc6eb9ae561e8197e28Eric Laurent                    }
3073d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent                } else {
307405274f348e12983eb8613cc6eb9ae561e8197e28Eric Laurent                    persistedState = SAFE_MEDIA_VOLUME_DISABLED;
3075d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent                    mSafeMediaVolumeState = SAFE_MEDIA_VOLUME_DISABLED;
3076d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent                }
3077d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent                mMcc = mcc;
307805274f348e12983eb8613cc6eb9ae561e8197e28Eric Laurent                sendMsg(mAudioHandler,
307905274f348e12983eb8613cc6eb9ae561e8197e28Eric Laurent                        MSG_PERSIST_SAFE_VOLUME_STATE,
308005274f348e12983eb8613cc6eb9ae561e8197e28Eric Laurent                        SENDMSG_QUEUE,
308105274f348e12983eb8613cc6eb9ae561e8197e28Eric Laurent                        persistedState,
308205274f348e12983eb8613cc6eb9ae561e8197e28Eric Laurent                        0,
308305274f348e12983eb8613cc6eb9ae561e8197e28Eric Laurent                        null,
308405274f348e12983eb8613cc6eb9ae561e8197e28Eric Laurent                        0);
3085d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent            }
3086d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent        }
3087d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent    }
3088d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent
30899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    ///////////////////////////////////////////////////////////////////////////
30909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // Internal methods
30919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    ///////////////////////////////////////////////////////////////////////////
30929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
30939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
30949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Checks if the adjustment should change ringer mode instead of just
30959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * adjusting volume. If so, this will set the proper ringer mode and volume
30969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * indices on the stream states.
30979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
3098a11b4affcad3d255aa723a89b768ea222506f2e8John Spurlock    private int checkForRingerModeChange(int oldIndex, int direction,  int step) {
3099a11b4affcad3d255aa723a89b768ea222506f2e8John Spurlock        int result = FLAG_ADJUST_VOLUME;
3100661f2cf45860d2e10924e6b69966a9afe255f28bJohn Spurlock        int ringerMode = getRingerModeInternal();
3101bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent
3102bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent        switch (ringerMode) {
3103bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent        case RINGER_MODE_NORMAL:
3104bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent            if (direction == AudioManager.ADJUST_LOWER) {
3105bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent                if (mHasVibrator) {
3106244820185269991186d07068b92985624cede4a5Eric Laurent                    // "step" is the delta in internal index units corresponding to a
3107244820185269991186d07068b92985624cede4a5Eric Laurent                    // change of 1 in UI index units.
3108244820185269991186d07068b92985624cede4a5Eric Laurent                    // Because of rounding when rescaling from one stream index range to its alias
3109244820185269991186d07068b92985624cede4a5Eric Laurent                    // index range, we cannot simply test oldIndex == step:
3110244820185269991186d07068b92985624cede4a5Eric Laurent                    //   (step <= oldIndex < 2 * step) is equivalent to: (old UI index == 1)
3111244820185269991186d07068b92985624cede4a5Eric Laurent                    if (step <= oldIndex && oldIndex < 2 * step) {
3112bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent                        ringerMode = RINGER_MODE_VIBRATE;
3113bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent                    }
3114bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent                } else {
3115244820185269991186d07068b92985624cede4a5Eric Laurent                    // (oldIndex < step) is equivalent to (old UI index == 0)
31168600534df66c2ff5846ed230b50c56229322d48aJohn Spurlock                    if ((oldIndex < step)
31178600534df66c2ff5846ed230b50c56229322d48aJohn Spurlock                            && VOLUME_SETS_RINGER_MODE_SILENT
31188600534df66c2ff5846ed230b50c56229322d48aJohn Spurlock                            && mPrevVolDirection != AudioManager.ADJUST_LOWER) {
3119bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent                        ringerMode = RINGER_MODE_SILENT;
3120bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent                    }
31213d4c06f90726a85e89dab13c41ddc15b9c912a3fEric Laurent                }
31226329bf7b1e2217c6c9477bd57349a1edade18417Daniel Sandler            }
3123bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent            break;
3124bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent        case RINGER_MODE_VIBRATE:
3125bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent            if (!mHasVibrator) {
3126bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent                Log.e(TAG, "checkForRingerModeChange() current ringer mode is vibrate" +
3127bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent                        "but no vibrator is present");
3128bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent                break;
3129bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent            }
3130c696a53d1fe4d61373c5dc64dd057d322da90c8fAmith Yamasani            if ((direction == AudioManager.ADJUST_LOWER)) {
3131795a51469701b4339eed4d97b6b06560f2d16d3fJohn Spurlock                if (mPrevVolDirection != AudioManager.ADJUST_LOWER) {
3132795a51469701b4339eed4d97b6b06560f2d16d3fJohn Spurlock                    if (VOLUME_SETS_RINGER_MODE_SILENT) {
3133795a51469701b4339eed4d97b6b06560f2d16d3fJohn Spurlock                        ringerMode = RINGER_MODE_SILENT;
3134795a51469701b4339eed4d97b6b06560f2d16d3fJohn Spurlock                    } else {
3135795a51469701b4339eed4d97b6b06560f2d16d3fJohn Spurlock                        result |= AudioManager.FLAG_SHOW_VIBRATE_HINT;
3136795a51469701b4339eed4d97b6b06560f2d16d3fJohn Spurlock                    }
3137c696a53d1fe4d61373c5dc64dd057d322da90c8fAmith Yamasani                }
3138c696a53d1fe4d61373c5dc64dd057d322da90c8fAmith Yamasani            } else if (direction == AudioManager.ADJUST_RAISE) {
3139bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent                ringerMode = RINGER_MODE_NORMAL;
3140c696a53d1fe4d61373c5dc64dd057d322da90c8fAmith Yamasani            }
3141a11b4affcad3d255aa723a89b768ea222506f2e8John Spurlock            result &= ~FLAG_ADJUST_VOLUME;
3142bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent            break;
3143bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent        case RINGER_MODE_SILENT:
31449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (direction == AudioManager.ADJUST_RAISE) {
3145a11b4affcad3d255aa723a89b768ea222506f2e8John Spurlock                if (PREVENT_VOLUME_ADJUSTMENT_IF_SILENT) {
3146a11b4affcad3d255aa723a89b768ea222506f2e8John Spurlock                    result |= AudioManager.FLAG_SHOW_SILENT_HINT;
3147bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent                } else {
3148a11b4affcad3d255aa723a89b768ea222506f2e8John Spurlock                  if (mHasVibrator) {
3149a11b4affcad3d255aa723a89b768ea222506f2e8John Spurlock                      ringerMode = RINGER_MODE_VIBRATE;
3150a11b4affcad3d255aa723a89b768ea222506f2e8John Spurlock                  } else {
3151a11b4affcad3d255aa723a89b768ea222506f2e8John Spurlock                      ringerMode = RINGER_MODE_NORMAL;
3152a11b4affcad3d255aa723a89b768ea222506f2e8John Spurlock                  }
3153bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent                }
31549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
3155a11b4affcad3d255aa723a89b768ea222506f2e8John Spurlock            result &= ~FLAG_ADJUST_VOLUME;
3156bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent            break;
3157bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent        default:
3158bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent            Log.e(TAG, "checkForRingerModeChange() wrong ringer mode: "+ringerMode);
3159bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent            break;
31609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
31619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3162661f2cf45860d2e10924e6b69966a9afe255f28bJohn Spurlock        setRingerMode(ringerMode, TAG + ".checkForRingerModeChange", false /*external*/);
31639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
316425101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent        mPrevVolDirection = direction;
316525101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent
3166a11b4affcad3d255aa723a89b768ea222506f2e8John Spurlock        return result;
31679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
31689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
31693346a802087f621c6441bc512dfcc17b07143fc6John Spurlock    @Override
31709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public boolean isStreamAffectedByRingerMode(int streamType) {
31719bcf401d13d47416043a704430388abd59aef7cdEric Laurent        return (mRingerModeAffectedStreams & (1 << streamType)) != 0;
31729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
31739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
31745b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent    private boolean isStreamMutedByRingerMode(int streamType) {
31755b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent        return (mRingerModeMutedStreams & (1 << streamType)) != 0;
31765b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent    }
31775b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent
317824e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent    boolean updateRingerModeAffectedStreams() {
317924e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent        int ringerModeAffectedStreams;
318024e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent        // make sure settings for ringer mode are consistent with device type: non voice capable
318124e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent        // devices (tablets) include media stream in silent mode whereas phones don't.
318224e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent        ringerModeAffectedStreams = Settings.System.getIntForUser(mContentResolver,
318324e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent                Settings.System.MODE_RINGER_STREAMS_AFFECTED,
318424e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent                ((1 << AudioSystem.STREAM_RING)|(1 << AudioSystem.STREAM_NOTIFICATION)|
318524e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent                 (1 << AudioSystem.STREAM_SYSTEM)|(1 << AudioSystem.STREAM_SYSTEM_ENFORCED)),
318624e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent                 UserHandle.USER_CURRENT);
318724e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent
318824e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent        // ringtone, notification and system streams are always affected by ringer mode
318924e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent        ringerModeAffectedStreams |= (1 << AudioSystem.STREAM_RING)|
319024e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent                                        (1 << AudioSystem.STREAM_NOTIFICATION)|
319124e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent                                        (1 << AudioSystem.STREAM_SYSTEM);
319224e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent
3193212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent        switch (mPlatformType) {
3194212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent            case PLATFORM_TELEVISION:
3195212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent                ringerModeAffectedStreams = 0;
3196212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent                break;
3197212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent            default:
319877e54d905f8c0c9925f21a8339a893391179d9d7John Spurlock                ringerModeAffectedStreams &= ~(1 << AudioSystem.STREAM_MUSIC);
3199212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent                break;
320024e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent        }
3201212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent
320224e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent        synchronized (mCameraSoundForced) {
320324e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent            if (mCameraSoundForced) {
320424e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent                ringerModeAffectedStreams &= ~(1 << AudioSystem.STREAM_SYSTEM_ENFORCED);
320524e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent            } else {
320624e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent                ringerModeAffectedStreams |= (1 << AudioSystem.STREAM_SYSTEM_ENFORCED);
320724e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent            }
320824e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent        }
320924e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent        if (mStreamVolumeAlias[AudioSystem.STREAM_DTMF] == AudioSystem.STREAM_RING) {
321024e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent            ringerModeAffectedStreams |= (1 << AudioSystem.STREAM_DTMF);
321124e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent        } else {
321224e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent            ringerModeAffectedStreams &= ~(1 << AudioSystem.STREAM_DTMF);
321324e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent        }
321424e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent
321524e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent        if (ringerModeAffectedStreams != mRingerModeAffectedStreams) {
321624e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent            Settings.System.putIntForUser(mContentResolver,
321724e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent                    Settings.System.MODE_RINGER_STREAMS_AFFECTED,
321824e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent                    ringerModeAffectedStreams,
321924e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent                    UserHandle.USER_CURRENT);
322024e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent            mRingerModeAffectedStreams = ringerModeAffectedStreams;
322124e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent            return true;
322224e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent        }
322324e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent        return false;
322424e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent    }
322524e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent
32269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public boolean isStreamAffectedByMute(int streamType) {
32279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return (mMuteAffectedStreams & (1 << streamType)) != 0;
32289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
32299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
32309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private void ensureValidDirection(int direction) {
32319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (direction < AudioManager.ADJUST_LOWER || direction > AudioManager.ADJUST_RAISE) {
32329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            throw new IllegalArgumentException("Bad direction " + direction);
32339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
32349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
32359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
32366c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang    private void ensureValidSteps(int steps) {
32376c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang        if (Math.abs(steps) > MAX_BATCH_VOLUME_ADJUST_STEPS) {
32386c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang            throw new IllegalArgumentException("Bad volume adjust steps " + steps);
32396c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang        }
32406c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang    }
32416c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang
32429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private void ensureValidStreamType(int streamType) {
32439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (streamType < 0 || streamType >= mStreamStates.length) {
32449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            throw new IllegalArgumentException("Bad stream type " + streamType);
32459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
32469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
32479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
32486d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent    private boolean isInCommunication() {
32490eb1e402c7e612887e38dc5516f11506b11fd835Nancy Chen        boolean IsInCall = false;
325025101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent
3251ef9f6f957d897ea0ed82114185b8fa3fefd4917bTyler Gunn        TelecomManager telecomManager =
3252ef9f6f957d897ea0ed82114185b8fa3fefd4917bTyler Gunn                (TelecomManager) mContext.getSystemService(Context.TELECOM_SERVICE);
325338edfda9bdd282228db08e3cc449b554b8744625Eric Laurent
325438edfda9bdd282228db08e3cc449b554b8744625Eric Laurent        final long ident = Binder.clearCallingIdentity();
3255ef9f6f957d897ea0ed82114185b8fa3fefd4917bTyler Gunn        IsInCall = telecomManager.isInCall();
325638edfda9bdd282228db08e3cc449b554b8744625Eric Laurent        Binder.restoreCallingIdentity(ident);
32579eb45934c582a0bf5060125690de8bce4f10ca76Santos Cordon
32580eb1e402c7e612887e38dc5516f11506b11fd835Nancy Chen        return (IsInCall || getMode() == AudioManager.MODE_IN_COMMUNICATION);
32596d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent    }
326025101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent
3261fca1e603236b8d1681f784e77e3719d1d59c1428Jean-Michel Trivi    /**
3262fca1e603236b8d1681f784e77e3719d1d59c1428Jean-Michel Trivi     * For code clarity for getActiveStreamType(int)
3263fca1e603236b8d1681f784e77e3719d1d59c1428Jean-Michel Trivi     * @param delay_ms max time since last STREAM_MUSIC activity to consider
3264fca1e603236b8d1681f784e77e3719d1d59c1428Jean-Michel Trivi     * @return true if STREAM_MUSIC is active in streams handled by AudioFlinger now or
3265fca1e603236b8d1681f784e77e3719d1d59c1428Jean-Michel Trivi     *     in the last "delay_ms" ms.
3266fca1e603236b8d1681f784e77e3719d1d59c1428Jean-Michel Trivi     */
3267fca1e603236b8d1681f784e77e3719d1d59c1428Jean-Michel Trivi    private boolean isAfMusicActiveRecently(int delay_ms) {
3268fca1e603236b8d1681f784e77e3719d1d59c1428Jean-Michel Trivi        return AudioSystem.isStreamActive(AudioSystem.STREAM_MUSIC, delay_ms)
3269fca1e603236b8d1681f784e77e3719d1d59c1428Jean-Michel Trivi                || AudioSystem.isStreamActiveRemotely(AudioSystem.STREAM_MUSIC, delay_ms);
3270fca1e603236b8d1681f784e77e3719d1d59c1428Jean-Michel Trivi    }
3271fca1e603236b8d1681f784e77e3719d1d59c1428Jean-Michel Trivi
32726d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent    private int getActiveStreamType(int suggestedStreamType) {
3273212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent        switch (mPlatformType) {
3274212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent        case PLATFORM_VOICE:
32756d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent            if (isInCommunication()) {
327625101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent                if (AudioSystem.getForceUse(AudioSystem.FOR_COMMUNICATION)
327725101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent                        == AudioSystem.FORCE_BT_SCO) {
327825101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent                    // Log.v(TAG, "getActiveStreamType: Forcing STREAM_BLUETOOTH_SCO...");
327925101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent                    return AudioSystem.STREAM_BLUETOOTH_SCO;
328025101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent                } else {
328125101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent                    // Log.v(TAG, "getActiveStreamType: Forcing STREAM_VOICE_CALL...");
328225101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent                    return AudioSystem.STREAM_VOICE_CALL;
328325101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent                }
32843114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi            } else if (suggestedStreamType == AudioManager.USE_DEFAULT_STREAM_TYPE) {
3285873cc45da2463a11182fe94a2565364d7e1709bbJean-Michel Trivi                if (isAfMusicActiveRecently(StreamOverride.sDelayMs)) {
32863114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                    if (DEBUG_VOL)
32873114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                        Log.v(TAG, "getActiveStreamType: Forcing STREAM_MUSIC stream active");
32883114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                    return AudioSystem.STREAM_MUSIC;
3289fca1e603236b8d1681f784e77e3719d1d59c1428Jean-Michel Trivi                    } else {
3290fca1e603236b8d1681f784e77e3719d1d59c1428Jean-Michel Trivi                        if (DEBUG_VOL)
3291fca1e603236b8d1681f784e77e3719d1d59c1428Jean-Michel Trivi                            Log.v(TAG, "getActiveStreamType: Forcing STREAM_RING b/c default");
3292fca1e603236b8d1681f784e77e3719d1d59c1428Jean-Michel Trivi                        return AudioSystem.STREAM_RING;
32933114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                }
3294fca1e603236b8d1681f784e77e3719d1d59c1428Jean-Michel Trivi            } else if (isAfMusicActiveRecently(0)) {
32953114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                if (DEBUG_VOL)
32963114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                    Log.v(TAG, "getActiveStreamType: Forcing STREAM_MUSIC stream active");
329725101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent                return AudioSystem.STREAM_MUSIC;
329825101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent            }
3299212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent            break;
3300212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent        case PLATFORM_TELEVISION:
3301212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent            if (suggestedStreamType == AudioManager.USE_DEFAULT_STREAM_TYPE) {
33022811dd337262934ea82477f9598f3e49092edb5eRoboErik                    // TV always defaults to STREAM_MUSIC
3303212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent                    return AudioSystem.STREAM_MUSIC;
3304212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent            }
3305212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent            break;
3306212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent        default:
33076d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent            if (isInCommunication()) {
330825101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent                if (AudioSystem.getForceUse(AudioSystem.FOR_COMMUNICATION)
330925101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent                        == AudioSystem.FORCE_BT_SCO) {
33103114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                    if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: Forcing STREAM_BLUETOOTH_SCO");
331125101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent                    return AudioSystem.STREAM_BLUETOOTH_SCO;
331225101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent                } else {
33133114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                    if (DEBUG_VOL)  Log.v(TAG, "getActiveStreamType: Forcing STREAM_VOICE_CALL");
331425101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent                    return AudioSystem.STREAM_VOICE_CALL;
331525101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent                }
331625101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent            } else if (AudioSystem.isStreamActive(AudioSystem.STREAM_NOTIFICATION,
3317873cc45da2463a11182fe94a2565364d7e1709bbJean-Michel Trivi                    StreamOverride.sDelayMs) ||
33183114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                    AudioSystem.isStreamActive(AudioSystem.STREAM_RING,
3319873cc45da2463a11182fe94a2565364d7e1709bbJean-Michel Trivi                            StreamOverride.sDelayMs)) {
33203114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: Forcing STREAM_NOTIFICATION");
332125101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent                return AudioSystem.STREAM_NOTIFICATION;
33223114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi            } else if (suggestedStreamType == AudioManager.USE_DEFAULT_STREAM_TYPE) {
3323873cc45da2463a11182fe94a2565364d7e1709bbJean-Michel Trivi                if (isAfMusicActiveRecently(StreamOverride.sDelayMs)) {
3324fca1e603236b8d1681f784e77e3719d1d59c1428Jean-Michel Trivi                    if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: forcing STREAM_MUSIC");
3325fca1e603236b8d1681f784e77e3719d1d59c1428Jean-Michel Trivi                    return AudioSystem.STREAM_MUSIC;
33263114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                } else {
3327eb1d88ddf9a0888455c82b83f19da124e5ca6f16John Spurlock                    if (DEBUG_VOL) Log.v(TAG,
3328eb1d88ddf9a0888455c82b83f19da124e5ca6f16John Spurlock                            "getActiveStreamType: using STREAM_NOTIFICATION as default");
3329eb1d88ddf9a0888455c82b83f19da124e5ca6f16John Spurlock                    return AudioSystem.STREAM_NOTIFICATION;
33303114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                }
3331c7fcba4b7bd3d78e7cfe975a3f8e4dde2f6738b7Joe Onorato            }
3332212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent            break;
33339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
3334212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent        if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: Returning suggested type "
3335212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent                + suggestedStreamType);
3336212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent        return suggestedStreamType;
33379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
33389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3339bcc1087af40a0e1bb35dbe8a39c830ecdea8280bJohn Spurlock    private void broadcastRingerMode(String action, int ringerMode) {
33409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // Send sticky broadcast
3341bcc1087af40a0e1bb35dbe8a39c830ecdea8280bJohn Spurlock        Intent broadcast = new Intent(action);
3342ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten        broadcast.putExtra(AudioManager.EXTRA_RINGER_MODE, ringerMode);
33431c633fc89bae9bf0af6fe643ac7ad2e744f27bedDianne Hackborn        broadcast.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT
33441c633fc89bae9bf0af6fe643ac7ad2e744f27bedDianne Hackborn                | Intent.FLAG_RECEIVER_REPLACE_PENDING);
33455ac72a29593ab9a20337a2225df52bdf4754be02Dianne Hackborn        sendStickyBroadcastToAll(broadcast);
33469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
33479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
33489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private void broadcastVibrateSetting(int vibrateType) {
33499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // Send broadcast
33509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (ActivityManagerNative.isSystemReady()) {
33519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            Intent broadcast = new Intent(AudioManager.VIBRATE_SETTING_CHANGED_ACTION);
33529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            broadcast.putExtra(AudioManager.EXTRA_VIBRATE_TYPE, vibrateType);
33539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            broadcast.putExtra(AudioManager.EXTRA_VIBRATE_SETTING, getVibrateSetting(vibrateType));
33545ac72a29593ab9a20337a2225df52bdf4754be02Dianne Hackborn            sendBroadcastToAll(broadcast);
33559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
33569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
33579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
33589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // Message helper methods
33592d8dab5a549b25b6f36df4614d7c0166d4d099e2Jean-Michel Trivi    /**
33602d8dab5a549b25b6f36df4614d7c0166d4d099e2Jean-Michel Trivi     * Queue a message on the given handler's message queue, after acquiring the service wake lock.
33612d8dab5a549b25b6f36df4614d7c0166d4d099e2Jean-Michel Trivi     * Note that the wake lock needs to be released after the message has been handled.
33622d8dab5a549b25b6f36df4614d7c0166d4d099e2Jean-Michel Trivi     */
33632d8dab5a549b25b6f36df4614d7c0166d4d099e2Jean-Michel Trivi    private void queueMsgUnderWakeLock(Handler handler, int msg,
33642d8dab5a549b25b6f36df4614d7c0166d4d099e2Jean-Michel Trivi            int arg1, int arg2, Object obj, int delay) {
3365a4dfbdc54d8898491d3a7d1d9d818c7db3fd773dEric Laurent        final long ident = Binder.clearCallingIdentity();
3366a4dfbdc54d8898491d3a7d1d9d818c7db3fd773dEric Laurent        // Always acquire the wake lock as AudioService because it is released by the
3367a4dfbdc54d8898491d3a7d1d9d818c7db3fd773dEric Laurent        // message handler.
3368fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        mAudioEventWakeLock.acquire();
3369a4dfbdc54d8898491d3a7d1d9d818c7db3fd773dEric Laurent        Binder.restoreCallingIdentity(ident);
33702d8dab5a549b25b6f36df4614d7c0166d4d099e2Jean-Michel Trivi        sendMsg(handler, msg, SENDMSG_QUEUE, arg1, arg2, obj, delay);
33712d8dab5a549b25b6f36df4614d7c0166d4d099e2Jean-Michel Trivi    }
33729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3373afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent    private static void sendMsg(Handler handler, int msg,
33749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int existingMsgPolicy, int arg1, int arg2, Object obj, int delay) {
33759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
33769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (existingMsgPolicy == SENDMSG_REPLACE) {
33779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            handler.removeMessages(msg);
33789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else if (existingMsgPolicy == SENDMSG_NOOP && handler.hasMessages(msg)) {
33799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return;
33809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
3381adbe8bf85f3c8230d16ae5cb3f5d9736e09ed84aEric Laurent        synchronized (mLastDeviceConnectMsgTime) {
3382adbe8bf85f3c8230d16ae5cb3f5d9736e09ed84aEric Laurent            long time = SystemClock.uptimeMillis() + delay;
3383adbe8bf85f3c8230d16ae5cb3f5d9736e09ed84aEric Laurent            handler.sendMessageAtTime(handler.obtainMessage(msg, arg1, arg2, obj), time);
3384adbe8bf85f3c8230d16ae5cb3f5d9736e09ed84aEric Laurent            if (msg == MSG_SET_WIRED_DEVICE_CONNECTION_STATE ||
3385adbe8bf85f3c8230d16ae5cb3f5d9736e09ed84aEric Laurent                    msg == MSG_SET_A2DP_SRC_CONNECTION_STATE ||
3386adbe8bf85f3c8230d16ae5cb3f5d9736e09ed84aEric Laurent                    msg == MSG_SET_A2DP_SINK_CONNECTION_STATE) {
3387adbe8bf85f3c8230d16ae5cb3f5d9736e09ed84aEric Laurent                mLastDeviceConnectMsgTime = time;
3388adbe8bf85f3c8230d16ae5cb3f5d9736e09ed84aEric Laurent            }
3389adbe8bf85f3c8230d16ae5cb3f5d9736e09ed84aEric Laurent        }
33909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
33919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
33929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    boolean checkAudioSettingsPermission(String method) {
3393ccd654e9d4c38da0d652c442e7a2ca3f447e9abeJean-Michel Trivi        if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.MODIFY_AUDIO_SETTINGS)
33949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                == PackageManager.PERMISSION_GRANTED) {
33959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return true;
33969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
33979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        String msg = "Audio Settings Permission Denial: " + method + " from pid="
33989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                + Binder.getCallingPid()
33999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                + ", uid=" + Binder.getCallingUid();
34009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        Log.w(TAG, msg);
34019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return false;
34029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
34039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
34049bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent    private int getDeviceForStream(int stream) {
34059bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent        int device = AudioSystem.getDevicesForStream(stream);
34069bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent        if ((device & (device - 1)) != 0) {
34079bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent            // Multiple device selection is either:
34089bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent            //  - speaker + one other device: give priority to speaker in this case.
34099bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent            //  - one A2DP device + another device: happens with duplicated output. In this case
34109bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent            // retain the device on the A2DP output as the other must not correspond to an active
34119bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent            // selection if not the speaker.
3412c9ff968787d4744194f9985ebaf8ce7efdd12256Jungshik Jang            //  - HDMI-CEC system audio mode only output: give priority to available item in order.
34139bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent            if ((device & AudioSystem.DEVICE_OUT_SPEAKER) != 0) {
34149bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                device = AudioSystem.DEVICE_OUT_SPEAKER;
3415c9ff968787d4744194f9985ebaf8ce7efdd12256Jungshik Jang            } else if ((device & AudioSystem.DEVICE_OUT_HDMI_ARC) != 0) {
3416c9ff968787d4744194f9985ebaf8ce7efdd12256Jungshik Jang                device = AudioSystem.DEVICE_OUT_HDMI_ARC;
3417c9ff968787d4744194f9985ebaf8ce7efdd12256Jungshik Jang            } else if ((device & AudioSystem.DEVICE_OUT_SPDIF) != 0) {
3418c9ff968787d4744194f9985ebaf8ce7efdd12256Jungshik Jang                device = AudioSystem.DEVICE_OUT_SPDIF;
3419c9ff968787d4744194f9985ebaf8ce7efdd12256Jungshik Jang            } else if ((device & AudioSystem.DEVICE_OUT_AUX_LINE) != 0) {
3420c9ff968787d4744194f9985ebaf8ce7efdd12256Jungshik Jang                device = AudioSystem.DEVICE_OUT_AUX_LINE;
34219bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent            } else {
34229bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                device &= AudioSystem.DEVICE_OUT_ALL_A2DP;
34239bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent            }
34249bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent        }
34259bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent        return device;
34269bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent    }
34279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3428b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent    public void setWiredDeviceConnectionState(int device, int state, String name) {
3429b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent        synchronized (mConnectedDevices) {
3430b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent            int delay = checkSendBecomingNoisyIntent(device, state);
34312d8dab5a549b25b6f36df4614d7c0166d4d099e2Jean-Michel Trivi            queueMsgUnderWakeLock(mAudioHandler,
3432b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent                    MSG_SET_WIRED_DEVICE_CONNECTION_STATE,
3433b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent                    device,
3434b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent                    state,
3435b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent                    name,
3436b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent                    delay);
3437b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent        }
3438b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent    }
3439b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent
34400a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood    public int setBluetoothA2dpDeviceConnectionState(BluetoothDevice device, int state, int profile)
3441b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent    {
3442b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent        int delay;
34430a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood        if (profile != BluetoothProfile.A2DP && profile != BluetoothProfile.A2DP_SINK) {
34440a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood            throw new IllegalArgumentException("invalid profile " + profile);
34450a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood        }
3446b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent        synchronized (mConnectedDevices) {
34470a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood            if (profile == BluetoothProfile.A2DP) {
34480a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood                delay = checkSendBecomingNoisyIntent(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
34490a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood                                                (state == BluetoothA2dp.STATE_CONNECTED) ? 1 : 0);
34500a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood            } else {
34510a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood                delay = 0;
34520a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood            }
34532d8dab5a549b25b6f36df4614d7c0166d4d099e2Jean-Michel Trivi            queueMsgUnderWakeLock(mAudioHandler,
34540a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood                    (profile == BluetoothProfile.A2DP ?
34550a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood                        MSG_SET_A2DP_SINK_CONNECTION_STATE : MSG_SET_A2DP_SRC_CONNECTION_STATE),
3456b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent                    state,
3457b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent                    0,
3458b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent                    device,
3459b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent                    delay);
3460b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent        }
3461b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent        return delay;
3462b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent    }
3463b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent
34649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    ///////////////////////////////////////////////////////////////////////////
34659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // Inner classes
34669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    ///////////////////////////////////////////////////////////////////////////
34679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
34688fa4d6f585f40ff5cf5f9bed316d92c64a306f21Eric Laurent    // NOTE: Locking order for synchronized objects related to volume or ringer mode management:
34698fa4d6f585f40ff5cf5f9bed316d92c64a306f21Eric Laurent    //  1 mScoclient OR mSafeMediaVolumeState
34708fa4d6f585f40ff5cf5f9bed316d92c64a306f21Eric Laurent    //  2   mSetModeDeathHandlers
34718fa4d6f585f40ff5cf5f9bed316d92c64a306f21Eric Laurent    //  3     mSettingsLock
34728fa4d6f585f40ff5cf5f9bed316d92c64a306f21Eric Laurent    //  4       VolumeStreamState.class
34738fa4d6f585f40ff5cf5f9bed316d92c64a306f21Eric Laurent    //  5         mCameraSoundForced
34749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public class VolumeStreamState {
34759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        private final int mStreamType;
34769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
347711a74a75653197a3d31fe91590cd8312f5270c44Jean-Michel Trivi        private String mVolumeIndexSettingName;
3478a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent        private int mIndexMax;
34793172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent        private final ConcurrentHashMap<Integer, Integer> mIndex =
34803172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                                            new ConcurrentHashMap<Integer, Integer>(8, 0.75f, 4);
34819bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent        private ArrayList<VolumeDeathHandler> mDeathHandlers; //handles mute/solo clients death
34829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3483a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent        private VolumeStreamState(String settingName, int streamType) {
34849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
34859bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent            mVolumeIndexSettingName = settingName;
34869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
34879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mStreamType = streamType;
34885982013cfc8274ff0bafaba83c676b3a8890cba9Jared Suttles            mIndexMax = MAX_STREAM_VOLUME[streamType];
3489a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent            AudioSystem.initStreamVolume(streamType, 0, mIndexMax);
3490a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent            mIndexMax *= 10;
34919bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent
349233902db75011d863009585682bd08560c5b89a75Eric Laurent            // mDeathHandlers must be created before calling readSettings()
34939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mDeathHandlers = new ArrayList<VolumeDeathHandler>();
349433902db75011d863009585682bd08560c5b89a75Eric Laurent
349533902db75011d863009585682bd08560c5b89a75Eric Laurent            readSettings();
34969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
34979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
349842b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent        public String getSettingNameForDevice(int device) {
349942b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent            String name = mVolumeIndexSettingName;
3500948d32748caaac5be06c991ebf00f74265a7849fEric Laurent            String suffix = AudioSystem.getOutputDeviceName(device);
35019bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent            if (suffix.isEmpty()) {
35029bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                return name;
35039bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent            }
35049bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent            return name + "_" + suffix;
35059bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent        }
35069bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent
3507fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent        public void readSettings() {
3508fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent            synchronized (VolumeStreamState.class) {
3509da39290460b30e5080769f039d6dff352b3c7808Wally Yau                // force maximum volume on all streams if fixed volume property
3510da39290460b30e5080769f039d6dff352b3c7808Wally Yau                // or master volume property is set
3511da39290460b30e5080769f039d6dff352b3c7808Wally Yau                if (mUseFixedVolume || mUseMasterVolume) {
3512fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                    mIndex.put(AudioSystem.DEVICE_OUT_DEFAULT, mIndexMax);
3513fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                    return;
3514fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                }
3515fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                // do not read system stream volume from settings: this stream is always aliased
3516fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                // to another stream type and its volume is never persisted. Values in settings can
3517fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                // only be stale values
3518fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                if ((mStreamType == AudioSystem.STREAM_SYSTEM) ||
3519fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                        (mStreamType == AudioSystem.STREAM_SYSTEM_ENFORCED)) {
352091377de6f23af2b0b08adae22810cae6fc35cb1aEric Laurent                    int index = 10 * DEFAULT_STREAM_VOLUME[mStreamType];
3521fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                    synchronized (mCameraSoundForced) {
3522fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                        if (mCameraSoundForced) {
3523fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                            index = mIndexMax;
3524fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                        }
3525dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent                    }
3526fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                    mIndex.put(AudioSystem.DEVICE_OUT_DEFAULT, index);
3527fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                    return;
3528dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent                }
3529002e9d382d2daa7ed41636463ecdbddbd4897abaEric Laurent
3530fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                int remainingDevices = AudioSystem.DEVICE_OUT_ALL;
353183a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent
3532fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                for (int i = 0; remainingDevices != 0; i++) {
3533fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                    int device = (1 << i);
3534fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                    if ((device & remainingDevices) == 0) {
3535fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                        continue;
3536fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                    }
3537fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                    remainingDevices &= ~device;
3538fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent
3539fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                    // retrieve current volume for device
3540fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                    String name = getSettingNameForDevice(device);
3541fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                    // if no volume stored for current stream and device, use default volume if default
3542fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                    // device, continue otherwise
3543fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                    int defaultIndex = (device == AudioSystem.DEVICE_OUT_DEFAULT) ?
354491377de6f23af2b0b08adae22810cae6fc35cb1aEric Laurent                                            DEFAULT_STREAM_VOLUME[mStreamType] : -1;
3545fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                    int index = Settings.System.getIntForUser(
3546fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                            mContentResolver, name, defaultIndex, UserHandle.USER_CURRENT);
3547fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                    if (index == -1) {
3548fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                        continue;
3549fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                    }
35509bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent
3551212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent                    mIndex.put(device, getValidIndex(10 * index));
3552dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent                }
35539bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent            }
35549bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent        }
35559bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent
35568fa4d6f585f40ff5cf5f9bed316d92c64a306f21Eric Laurent        // must be called while synchronized VolumeStreamState.class
35578fa4d6f585f40ff5cf5f9bed316d92c64a306f21Eric Laurent        public void applyDeviceVolume_syncVSS(int device) {
355842b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent            int index;
35598fa4d6f585f40ff5cf5f9bed316d92c64a306f21Eric Laurent            if (isMuted_syncVSS()) {
356042b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                index = 0;
3561ba5270b88798c66fefc17a1b25b27894e4fb7862Jean-Michel Trivi            } else if (((device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0 && mAvrcpAbsVolSupported)
3562ba5270b88798c66fefc17a1b25b27894e4fb7862Jean-Michel Trivi                    || ((device & mFullVolumeDevices) != 0)) {
3563c9d1d5f35091226e96fcfa91817480f589eb36e2Matthew Xie                index = (mIndexMax + 5)/10;
3564cd772d04345850e160a45613fcf6b86da0dce4cfEric Laurent            } else {
356542b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                index = (getIndex(device) + 5)/10;
356642b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent            }
356742b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent            AudioSystem.setStreamVolumeIndex(mStreamType, index, device);
35689bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent        }
35699bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent
3570fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent        public void applyAllVolumes() {
3571fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent            synchronized (VolumeStreamState.class) {
3572fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                // apply default volume first: by convention this will reset all
3573fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                // devices volumes in audio policy manager to the supplied value
3574fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                int index;
35758fa4d6f585f40ff5cf5f9bed316d92c64a306f21Eric Laurent                if (isMuted_syncVSS()) {
3576fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                    index = 0;
3577fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                } else {
3578fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                    index = (getIndex(AudioSystem.DEVICE_OUT_DEFAULT) + 5)/10;
3579fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                }
3580fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                AudioSystem.setStreamVolumeIndex(mStreamType, index, AudioSystem.DEVICE_OUT_DEFAULT);
3581fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                // then apply device specific volumes
3582fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                Set set = mIndex.entrySet();
3583fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                Iterator i = set.iterator();
3584fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                while (i.hasNext()) {
3585fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                    Map.Entry entry = (Map.Entry)i.next();
3586fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                    int device = ((Integer)entry.getKey()).intValue();
3587fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                    if (device != AudioSystem.DEVICE_OUT_DEFAULT) {
35888fa4d6f585f40ff5cf5f9bed316d92c64a306f21Eric Laurent                        if (isMuted_syncVSS()) {
3589fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                            index = 0;
3590ba5270b88798c66fefc17a1b25b27894e4fb7862Jean-Michel Trivi                        } else if (((device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0 &&
3591ba5270b88798c66fefc17a1b25b27894e4fb7862Jean-Michel Trivi                                mAvrcpAbsVolSupported)
3592ba5270b88798c66fefc17a1b25b27894e4fb7862Jean-Michel Trivi                                    || ((device & mFullVolumeDevices) != 0))
3593ba5270b88798c66fefc17a1b25b27894e4fb7862Jean-Michel Trivi                        {
3594fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                            index = (mIndexMax + 5)/10;
3595fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                        } else {
3596fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                            index = ((Integer)entry.getValue() + 5)/10;
3597fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                        }
3598fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                        AudioSystem.setStreamVolumeIndex(mStreamType, index, device);
359942b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                    }
36009bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                }
36019bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent            }
360211a74a75653197a3d31fe91590cd8312f5270c44Jean-Michel Trivi        }
360311a74a75653197a3d31fe91590cd8312f5270c44Jean-Michel Trivi
36049bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent        public boolean adjustIndex(int deltaIndex, int device) {
360542b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent            return setIndex(getIndex(device) + deltaIndex,
360642b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                            device);
36079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
36089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3609fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent        public boolean setIndex(int index, int device) {
3610fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent            synchronized (VolumeStreamState.class) {
3611fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                int oldIndex = getIndex(device);
3612fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                index = getValidIndex(index);
3613fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                synchronized (mCameraSoundForced) {
3614fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                    if ((mStreamType == AudioSystem.STREAM_SYSTEM_ENFORCED) && mCameraSoundForced) {
3615fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                        index = mIndexMax;
3616fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                    }
3617dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent                }
3618fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                mIndex.put(device, index);
3619fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent
3620fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                if (oldIndex != index) {
3621fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                    // Apply change to all streams using this one as alias
3622fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                    // if changing volume of current device, also change volume of current
3623fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                    // device on aliased stream
3624fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                    boolean currentDevice = (device == getDeviceForStream(mStreamType));
3625fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                    int numStreamTypes = AudioSystem.getNumStreamTypes();
3626fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                    for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
3627fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                        if (streamType != mStreamType &&
3628fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                                mStreamVolumeAlias[streamType] == mStreamType) {
3629fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                            int scaledIndex = rescaleIndex(index, mStreamType, streamType);
3630bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent                            mStreamStates[streamType].setIndex(scaledIndex,
3631fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                                                               device);
3632fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                            if (currentDevice) {
3633fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                                mStreamStates[streamType].setIndex(scaledIndex,
3634fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                                                                   getDeviceForStream(streamType));
3635fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                            }
3636bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent                        }
3637a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent                    }
3638fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                    return true;
3639fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                } else {
3640fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                    return false;
3641a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent                }
36429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
36439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
36449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3645fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent        public int getIndex(int device) {
3646fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent            synchronized (VolumeStreamState.class) {
3647fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                Integer index = mIndex.get(device);
3648fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                if (index == null) {
3649fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                    // there is always an entry for AudioSystem.DEVICE_OUT_DEFAULT
3650fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                    index = mIndex.get(AudioSystem.DEVICE_OUT_DEFAULT);
3651fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                }
3652fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                return index.intValue();
36539bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent            }
36549bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent        }
36559bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent
36569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public int getMaxIndex() {
3657a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent            return mIndexMax;
36589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
36599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3660fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent        public void setAllIndexes(VolumeStreamState srcStream) {
3661fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent            synchronized (VolumeStreamState.class) {
3662fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                int srcStreamType = srcStream.getStreamType();
3663fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                // apply default device volume from source stream to all devices first in case
3664fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                // some devices are present in this stream state but not in source stream state
3665fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                int index = srcStream.getIndex(AudioSystem.DEVICE_OUT_DEFAULT);
366624e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent                index = rescaleIndex(index, srcStreamType, mStreamType);
3667fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                Set set = mIndex.entrySet();
3668fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                Iterator i = set.iterator();
3669fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                while (i.hasNext()) {
3670fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                    Map.Entry entry = (Map.Entry)i.next();
3671fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                    entry.setValue(index);
3672fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                }
3673fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                // Now apply actual volume for devices in source stream state
3674fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                set = srcStream.mIndex.entrySet();
3675fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                i = set.iterator();
3676fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                while (i.hasNext()) {
3677fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                    Map.Entry entry = (Map.Entry)i.next();
3678fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                    int device = ((Integer)entry.getKey()).intValue();
3679fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                    index = ((Integer)entry.getValue()).intValue();
3680fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                    index = rescaleIndex(index, srcStreamType, mStreamType);
3681fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent
3682fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                    setIndex(index, device);
3683fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                }
36846d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent            }
36856d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent        }
36866d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent
3687fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent        public void setAllIndexesToMax() {
3688fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent            synchronized (VolumeStreamState.class) {
3689fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                Set set = mIndex.entrySet();
3690fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                Iterator i = set.iterator();
3691fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                while (i.hasNext()) {
3692fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                    Map.Entry entry = (Map.Entry)i.next();
3693fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                    entry.setValue(mIndexMax);
3694fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                }
3695dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent            }
3696dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent        }
3697dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent
3698fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent        public void mute(IBinder cb, boolean state) {
3699fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent            synchronized (VolumeStreamState.class) {
37008fa4d6f585f40ff5cf5f9bed316d92c64a306f21Eric Laurent                VolumeDeathHandler handler = getDeathHandler_syncVSS(cb, state);
3701fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                if (handler == null) {
3702fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                    Log.e(TAG, "Could not get client death handler for stream: "+mStreamType);
3703fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                    return;
3704fdbee869be504e399efce1127a68281bd9b158c5Eric Laurent                }
37058fa4d6f585f40ff5cf5f9bed316d92c64a306f21Eric Laurent                handler.mute_syncVSS(state);
37069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
37079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
37089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
37096d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent        public int getStreamType() {
37106d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent            return mStreamType;
37116d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent        }
37126d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent
3713212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent        public void checkFixedVolumeDevices() {
3714212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent            synchronized (VolumeStreamState.class) {
3715212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent                // ignore settings for fixed volume devices: volume should always be at max or 0
3716212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent                if (mStreamVolumeAlias[mStreamType] == AudioSystem.STREAM_MUSIC) {
3717212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent                    Set set = mIndex.entrySet();
3718212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent                    Iterator i = set.iterator();
3719212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent                    while (i.hasNext()) {
3720212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent                        Map.Entry entry = (Map.Entry)i.next();
3721212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent                        int device = ((Integer)entry.getKey()).intValue();
3722212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent                        int index = ((Integer)entry.getValue()).intValue();
3723ba5270b88798c66fefc17a1b25b27894e4fb7862Jean-Michel Trivi                        if (((device & mFullVolumeDevices) != 0)
3724ba5270b88798c66fefc17a1b25b27894e4fb7862Jean-Michel Trivi                                || (((device & mFixedVolumeDevices) != 0) && index != 0)) {
3725212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent                            entry.setValue(mIndexMax);
3726212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent                        }
37278fa4d6f585f40ff5cf5f9bed316d92c64a306f21Eric Laurent                        applyDeviceVolume_syncVSS(device);
3728212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent                    }
3729212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent                }
3730212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent            }
3731212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent        }
3732212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent
37339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        private int getValidIndex(int index) {
37349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (index < 0) {
37359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return 0;
3736da39290460b30e5080769f039d6dff352b3c7808Wally Yau            } else if (mUseFixedVolume || mUseMasterVolume || index > mIndexMax) {
3737a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent                return mIndexMax;
37389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
37399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
37409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return index;
37419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
37429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
37439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        private class VolumeDeathHandler implements IBinder.DeathRecipient {
37449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            private IBinder mICallback; // To be notified of client's death
37459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            private int mMuteCount; // Number of active mutes for this client
37469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
37479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            VolumeDeathHandler(IBinder cb) {
37489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mICallback = cb;
37499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
37509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
37518fa4d6f585f40ff5cf5f9bed316d92c64a306f21Eric Laurent            // must be called while synchronized VolumeStreamState.class
37528fa4d6f585f40ff5cf5f9bed316d92c64a306f21Eric Laurent            public void mute_syncVSS(boolean state) {
375342b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                boolean updateVolume = false;
37543172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                if (state) {
37553172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                    if (mMuteCount == 0) {
37563172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                        // Register for client death notification
37573172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                        try {
37583172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                            // mICallback can be 0 if muted by AudioService
37593172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                            if (mICallback != null) {
37603172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                                mICallback.linkToDeath(this, 0);
37613172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                            }
376242b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                            VolumeStreamState.this.mDeathHandlers.add(this);
37633172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                            // If the stream is not yet muted by any client, set level to 0
37648fa4d6f585f40ff5cf5f9bed316d92c64a306f21Eric Laurent                            if (!VolumeStreamState.this.isMuted_syncVSS()) {
376542b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                                updateVolume = true;
37663172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                            }
37673172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                        } catch (RemoteException e) {
37683172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                            // Client has died!
37693172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                            binderDied();
37703172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                            return;
37713172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                        }
37723172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                    } else {
37733172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                        Log.w(TAG, "stream: "+mStreamType+" was already muted by this client");
37743172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                    }
37753172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                    mMuteCount++;
37763172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                } else {
37773172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                    if (mMuteCount == 0) {
37783172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                        Log.e(TAG, "unexpected unmute for stream: "+mStreamType);
37793172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                    } else {
37803172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                        mMuteCount--;
37813172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                        if (mMuteCount == 0) {
37823172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                            // Unregister from client death notification
378342b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                            VolumeStreamState.this.mDeathHandlers.remove(this);
37843172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                            // mICallback can be 0 if muted by AudioService
37853172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                            if (mICallback != null) {
37863172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                                mICallback.unlinkToDeath(this, 0);
37873172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                            }
37888fa4d6f585f40ff5cf5f9bed316d92c64a306f21Eric Laurent                            if (!VolumeStreamState.this.isMuted_syncVSS()) {
378942b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                                updateVolume = true;
37909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            }
37919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        }
37929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    }
37939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
379442b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                if (updateVolume) {
379542b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                    sendMsg(mAudioHandler,
379642b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                            MSG_SET_ALL_VOLUMES,
379742b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                            SENDMSG_QUEUE,
379842b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                            0,
379942b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                            0,
380042b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                            VolumeStreamState.this, 0);
380142b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                }
38029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
38039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
38049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            public void binderDied() {
38059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                Log.w(TAG, "Volume service client died for stream: "+mStreamType);
38068fa4d6f585f40ff5cf5f9bed316d92c64a306f21Eric Laurent                synchronized (VolumeStreamState.class) {
38078fa4d6f585f40ff5cf5f9bed316d92c64a306f21Eric Laurent                    if (mMuteCount != 0) {
38088fa4d6f585f40ff5cf5f9bed316d92c64a306f21Eric Laurent                        // Reset all active mute requests from this client.
38098fa4d6f585f40ff5cf5f9bed316d92c64a306f21Eric Laurent                        mMuteCount = 1;
38108fa4d6f585f40ff5cf5f9bed316d92c64a306f21Eric Laurent                        mute_syncVSS(false);
38118fa4d6f585f40ff5cf5f9bed316d92c64a306f21Eric Laurent                    }
38129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
38139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
38149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
38159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
38168fa4d6f585f40ff5cf5f9bed316d92c64a306f21Eric Laurent        private int muteCount() {
38179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int count = 0;
38189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int size = mDeathHandlers.size();
38199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            for (int i = 0; i < size; i++) {
38209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                count += mDeathHandlers.get(i).mMuteCount;
38219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
38229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return count;
38239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
38249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
38258fa4d6f585f40ff5cf5f9bed316d92c64a306f21Eric Laurent        // must be called while synchronized VolumeStreamState.class
38268fa4d6f585f40ff5cf5f9bed316d92c64a306f21Eric Laurent        private boolean isMuted_syncVSS() {
382742b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent            return muteCount() != 0;
382842b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent        }
382942b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent
38308fa4d6f585f40ff5cf5f9bed316d92c64a306f21Eric Laurent        // must be called while synchronized VolumeStreamState.class
38318fa4d6f585f40ff5cf5f9bed316d92c64a306f21Eric Laurent        private VolumeDeathHandler getDeathHandler_syncVSS(IBinder cb, boolean state) {
38323172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent            VolumeDeathHandler handler;
38333172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent            int size = mDeathHandlers.size();
38343172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent            for (int i = 0; i < size; i++) {
38353172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                handler = mDeathHandlers.get(i);
38363172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                if (cb == handler.mICallback) {
38373172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                    return handler;
3838ce952c8e13c535bedde77bcdb94dfcc7508475aaMike Lockwood                }
3839ce952c8e13c535bedde77bcdb94dfcc7508475aaMike Lockwood            }
38403172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent            // If this is the first mute request for this client, create a new
38413172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent            // client death handler. Otherwise, it is an out of sequence unmute request.
38423172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent            if (state) {
38433172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                handler = new VolumeDeathHandler(cb);
38443172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent            } else {
38453172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                Log.w(TAG, "stream was not muted by this client");
38463172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                handler = null;
38473172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent            }
38483172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent            return handler;
3849ce952c8e13c535bedde77bcdb94dfcc7508475aaMike Lockwood        }
3850bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent
3851bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent        private void dump(PrintWriter pw) {
3852dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent            pw.print("   Mute count: ");
3853dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent            pw.println(muteCount());
38542b29bc4c1cef64abdf3a68b60bdcf7207193e980John Spurlock            pw.print("   Max: ");
38552b29bc4c1cef64abdf3a68b60bdcf7207193e980John Spurlock            pw.println((mIndexMax + 5) / 10);
3856bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent            pw.print("   Current: ");
3857bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent            Set set = mIndex.entrySet();
3858bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent            Iterator i = set.iterator();
3859bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent            while (i.hasNext()) {
3860bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent                Map.Entry entry = (Map.Entry)i.next();
38612b29bc4c1cef64abdf3a68b60bdcf7207193e980John Spurlock                final int device = (Integer) entry.getKey();
38622b29bc4c1cef64abdf3a68b60bdcf7207193e980John Spurlock                pw.print(Integer.toHexString(device));
38632b29bc4c1cef64abdf3a68b60bdcf7207193e980John Spurlock                final String deviceName = device == AudioSystem.DEVICE_OUT_DEFAULT ? "default"
38642b29bc4c1cef64abdf3a68b60bdcf7207193e980John Spurlock                        : AudioSystem.getOutputDeviceName(device);
38652b29bc4c1cef64abdf3a68b60bdcf7207193e980John Spurlock                if (!deviceName.isEmpty()) {
38662b29bc4c1cef64abdf3a68b60bdcf7207193e980John Spurlock                    pw.print(" (");
38672b29bc4c1cef64abdf3a68b60bdcf7207193e980John Spurlock                    pw.print(deviceName);
38682b29bc4c1cef64abdf3a68b60bdcf7207193e980John Spurlock                    pw.print(")");
38692b29bc4c1cef64abdf3a68b60bdcf7207193e980John Spurlock                }
38702b29bc4c1cef64abdf3a68b60bdcf7207193e980John Spurlock                pw.print(": ");
38712b29bc4c1cef64abdf3a68b60bdcf7207193e980John Spurlock                final int index = (((Integer) entry.getValue()) + 5) / 10;
38722b29bc4c1cef64abdf3a68b60bdcf7207193e980John Spurlock                pw.print(index);
38732b29bc4c1cef64abdf3a68b60bdcf7207193e980John Spurlock                if (i.hasNext()) {
38742b29bc4c1cef64abdf3a68b60bdcf7207193e980John Spurlock                    pw.print(", ");
38752b29bc4c1cef64abdf3a68b60bdcf7207193e980John Spurlock                }
3876bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent            }
3877bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent        }
3878ce952c8e13c535bedde77bcdb94dfcc7508475aaMike Lockwood    }
3879ce952c8e13c535bedde77bcdb94dfcc7508475aaMike Lockwood
38809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** Thread that handles native AudioSystem control. */
38819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private class AudioSystemThread extends Thread {
38829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        AudioSystemThread() {
38839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            super("AudioService");
38849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
38859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
38869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        @Override
38879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public void run() {
38889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // Set this thread up so the handler will work on it
38899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            Looper.prepare();
38909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
38919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            synchronized(AudioService.this) {
38929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mAudioHandler = new AudioHandler();
38939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
38949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // Notify that the handler has been created
38959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                AudioService.this.notify();
38969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
38979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
38989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // Listen for volume change requests that are set by VolumePanel
38999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            Looper.loop();
39009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
39019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
39029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
39039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** Handles internal volume messages in separate volume thread. */
39049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private class AudioHandler extends Handler {
39059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
39069bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent        private void setDeviceVolume(VolumeStreamState streamState, int device) {
39079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
39088fa4d6f585f40ff5cf5f9bed316d92c64a306f21Eric Laurent            synchronized (VolumeStreamState.class) {
39098fa4d6f585f40ff5cf5f9bed316d92c64a306f21Eric Laurent                // Apply volume
39108fa4d6f585f40ff5cf5f9bed316d92c64a306f21Eric Laurent                streamState.applyDeviceVolume_syncVSS(device);
39118fa4d6f585f40ff5cf5f9bed316d92c64a306f21Eric Laurent
39128fa4d6f585f40ff5cf5f9bed316d92c64a306f21Eric Laurent                // Apply change to all streams using this one as alias
39138fa4d6f585f40ff5cf5f9bed316d92c64a306f21Eric Laurent                int numStreamTypes = AudioSystem.getNumStreamTypes();
39148fa4d6f585f40ff5cf5f9bed316d92c64a306f21Eric Laurent                for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
39158fa4d6f585f40ff5cf5f9bed316d92c64a306f21Eric Laurent                    if (streamType != streamState.mStreamType &&
39168fa4d6f585f40ff5cf5f9bed316d92c64a306f21Eric Laurent                            mStreamVolumeAlias[streamType] == streamState.mStreamType) {
39178fa4d6f585f40ff5cf5f9bed316d92c64a306f21Eric Laurent                        // Make sure volume is also maxed out on A2DP device for aliased stream
39188fa4d6f585f40ff5cf5f9bed316d92c64a306f21Eric Laurent                        // that may have a different device selected
39198fa4d6f585f40ff5cf5f9bed316d92c64a306f21Eric Laurent                        int streamDevice = getDeviceForStream(streamType);
39208fa4d6f585f40ff5cf5f9bed316d92c64a306f21Eric Laurent                        if ((device != streamDevice) && mAvrcpAbsVolSupported &&
39218fa4d6f585f40ff5cf5f9bed316d92c64a306f21Eric Laurent                                ((device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0)) {
39228fa4d6f585f40ff5cf5f9bed316d92c64a306f21Eric Laurent                            mStreamStates[streamType].applyDeviceVolume_syncVSS(device);
39238fa4d6f585f40ff5cf5f9bed316d92c64a306f21Eric Laurent                        }
39248fa4d6f585f40ff5cf5f9bed316d92c64a306f21Eric Laurent                        mStreamStates[streamType].applyDeviceVolume_syncVSS(streamDevice);
3925cd772d04345850e160a45613fcf6b86da0dce4cfEric Laurent                    }
3926a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent                }
3927a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent            }
39289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // Post a persist volume msg
3929afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent            sendMsg(mAudioHandler,
3930afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent                    MSG_PERSIST_VOLUME,
393198ad9b9d6fd34aad487933170f50b5519313df61Eric Laurent                    SENDMSG_QUEUE,
39329bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                    device,
393342b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                    0,
3934afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent                    streamState,
3935afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent                    PERSIST_DELAY);
3936afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent
39379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
39389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
39399bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent        private void setAllVolumes(VolumeStreamState streamState) {
39409bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent
39419bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent            // Apply volume
39429bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent            streamState.applyAllVolumes();
39439bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent
39449bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent            // Apply change to all streams using this one as alias
39459bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent            int numStreamTypes = AudioSystem.getNumStreamTypes();
39469bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent            for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
39479bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                if (streamType != streamState.mStreamType &&
39486d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent                        mStreamVolumeAlias[streamType] == streamState.mStreamType) {
39499bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                    mStreamStates[streamType].applyAllVolumes();
39509bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                }
39519bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent            }
39529bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent        }
39539bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent
395442b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent        private void persistVolume(VolumeStreamState streamState, int device) {
395583a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent            if (mUseFixedVolume) {
395683a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent                return;
395783a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent            }
3958212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent            if (isPlatformTelevision() && (streamState.mStreamType != AudioSystem.STREAM_MUSIC)) {
3959212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent                return;
3960212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent            }
396142b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent            System.putIntForUser(mContentResolver,
396242b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                      streamState.getSettingNameForDevice(device),
396342b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                      (streamState.getIndex(device) + 5)/ 10,
396442b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                      UserHandle.USER_CURRENT);
39659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
39669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3967ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten        private void persistRingerMode(int ringerMode) {
396883a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent            if (mUseFixedVolume) {
396983a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent                return;
397083a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent            }
39718d9a1f66d9d3dbbd45a56d441a746ec11dba7645Jeff Sharkey            Settings.Global.putInt(mContentResolver, Settings.Global.MODE_RINGER, ringerMode);
39729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
39739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
39745d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent        private boolean onLoadSoundEffects() {
39755d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent            int status;
39765d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent
39775d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent            synchronized (mSoundEffectsLock) {
39784a5eeb9c727d77bb57fef87a70c8c9cc23dbfee3Eric Laurent                if (!mSystemReady) {
39795d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    Log.w(TAG, "onLoadSoundEffects() called before boot complete");
39805d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    return false;
39815d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                }
39825d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent
39835d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                if (mSoundPool != null) {
39845d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    return true;
39855d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                }
39865d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent
39875d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                loadTouchSoundAssets();
39885d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent
398955a30c41b6c47d3afe6b13c25c64e8eec9f45e7cJean-Michel Trivi                mSoundPool = new SoundPool.Builder()
399055a30c41b6c47d3afe6b13c25c64e8eec9f45e7cJean-Michel Trivi                        .setMaxStreams(NUM_SOUNDPOOL_CHANNELS)
399155a30c41b6c47d3afe6b13c25c64e8eec9f45e7cJean-Michel Trivi                        .setAudioAttributes(new AudioAttributes.Builder()
399255a30c41b6c47d3afe6b13c25c64e8eec9f45e7cJean-Michel Trivi                            .setUsage(AudioAttributes.USAGE_ASSISTANCE_SONIFICATION)
399355a30c41b6c47d3afe6b13c25c64e8eec9f45e7cJean-Michel Trivi                            .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
399455a30c41b6c47d3afe6b13c25c64e8eec9f45e7cJean-Michel Trivi                            .build())
399555a30c41b6c47d3afe6b13c25c64e8eec9f45e7cJean-Michel Trivi                        .build();
39965d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                mSoundPoolCallBack = null;
39975d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                mSoundPoolListenerThread = new SoundPoolListenerThread();
39985d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                mSoundPoolListenerThread.start();
39995d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                int attempts = 3;
40005d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                while ((mSoundPoolCallBack == null) && (attempts-- > 0)) {
40015d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    try {
40025d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                        // Wait for mSoundPoolCallBack to be set by the other thread
4003167d1a27713ab64cd3c0aa70de96434083ef0400Glenn Kasten                        mSoundEffectsLock.wait(SOUND_EFFECTS_LOAD_TIMEOUT_MS);
40045d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    } catch (InterruptedException e) {
40055d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                        Log.w(TAG, "Interrupted while waiting sound pool listener thread.");
40065d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    }
40075d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                }
40085d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent
40095d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                if (mSoundPoolCallBack == null) {
40105d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    Log.w(TAG, "onLoadSoundEffects() SoundPool listener or thread creation error");
40115d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    if (mSoundPoolLooper != null) {
40125d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                        mSoundPoolLooper.quit();
40135d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                        mSoundPoolLooper = null;
40145d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    }
40155d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    mSoundPoolListenerThread = null;
40165d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    mSoundPool.release();
40175d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    mSoundPool = null;
40185d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    return false;
40195d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                }
40205d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                /*
40215d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                 * poolId table: The value -1 in this table indicates that corresponding
40225d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                 * file (same index in SOUND_EFFECT_FILES[] has not been loaded.
40235d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                 * Once loaded, the value in poolId is the sample ID and the same
40245d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                 * sample can be reused for another effect using the same file.
40255d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                 */
40265d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                int[] poolId = new int[SOUND_EFFECT_FILES.size()];
40275d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                for (int fileIdx = 0; fileIdx < SOUND_EFFECT_FILES.size(); fileIdx++) {
40285d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    poolId[fileIdx] = -1;
40295d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                }
40305d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                /*
40315d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                 * Effects whose value in SOUND_EFFECT_FILES_MAP[effect][1] is -1 must be loaded.
40325d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                 * If load succeeds, value in SOUND_EFFECT_FILES_MAP[effect][1] is > 0:
40335d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                 * this indicates we have a valid sample loaded for this effect.
40345d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                 */
40355d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent
40365d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                int numSamples = 0;
40375d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                for (int effect = 0; effect < AudioManager.NUM_SOUND_EFFECTS; effect++) {
40385d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    // Do not load sample if this effect uses the MediaPlayer
40395d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    if (SOUND_EFFECT_FILES_MAP[effect][1] == 0) {
40405d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                        continue;
40415d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    }
40425d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    if (poolId[SOUND_EFFECT_FILES_MAP[effect][0]] == -1) {
40435d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                        String filePath = Environment.getRootDirectory()
40445d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                                + SOUND_EFFECTS_PATH
40455d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                                + SOUND_EFFECT_FILES.get(SOUND_EFFECT_FILES_MAP[effect][0]);
40465d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                        int sampleId = mSoundPool.load(filePath, 0);
40475d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                        if (sampleId <= 0) {
40485d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                            Log.w(TAG, "Soundpool could not load file: "+filePath);
40495d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                        } else {
40505d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                            SOUND_EFFECT_FILES_MAP[effect][1] = sampleId;
40515d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                            poolId[SOUND_EFFECT_FILES_MAP[effect][0]] = sampleId;
40525d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                            numSamples++;
40535d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                        }
40545d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    } else {
40555d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                        SOUND_EFFECT_FILES_MAP[effect][1] =
40565d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                                poolId[SOUND_EFFECT_FILES_MAP[effect][0]];
40575d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    }
40585d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                }
40595d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                // wait for all samples to be loaded
40605d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                if (numSamples > 0) {
40615d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    mSoundPoolCallBack.setSamples(poolId);
40625d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent
40635d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    attempts = 3;
40645d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    status = 1;
40655d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    while ((status == 1) && (attempts-- > 0)) {
40665d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                        try {
4067167d1a27713ab64cd3c0aa70de96434083ef0400Glenn Kasten                            mSoundEffectsLock.wait(SOUND_EFFECTS_LOAD_TIMEOUT_MS);
40685d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                            status = mSoundPoolCallBack.status();
40695d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                        } catch (InterruptedException e) {
40705d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                            Log.w(TAG, "Interrupted while waiting sound pool callback.");
40715d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                        }
40725d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    }
40735d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                } else {
40745d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    status = -1;
40755d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                }
40765d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent
40775d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                if (mSoundPoolLooper != null) {
40785d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    mSoundPoolLooper.quit();
40795d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    mSoundPoolLooper = null;
40805d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                }
40815d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                mSoundPoolListenerThread = null;
40825d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                if (status != 0) {
40835d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    Log.w(TAG,
40845d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                            "onLoadSoundEffects(), Error "+status+ " while loading samples");
40855d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    for (int effect = 0; effect < AudioManager.NUM_SOUND_EFFECTS; effect++) {
40865d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                        if (SOUND_EFFECT_FILES_MAP[effect][1] > 0) {
40875d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                            SOUND_EFFECT_FILES_MAP[effect][1] = -1;
40885d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                        }
40895d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    }
40905d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent
40915d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    mSoundPool.release();
40925d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    mSoundPool = null;
40935d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                }
40945d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent            }
40955d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent            return (status == 0);
40965d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent        }
40975d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent
40985d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent        /**
40995d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent         *  Unloads samples from the sound pool.
41005d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent         *  This method can be called to free some memory when
41015d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent         *  sound effects are disabled.
41025d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent         */
41035d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent        private void onUnloadSoundEffects() {
41045d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent            synchronized (mSoundEffectsLock) {
41055d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                if (mSoundPool == null) {
41065d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    return;
41075d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                }
41085d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent
41095d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                int[] poolId = new int[SOUND_EFFECT_FILES.size()];
41105d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                for (int fileIdx = 0; fileIdx < SOUND_EFFECT_FILES.size(); fileIdx++) {
41115d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    poolId[fileIdx] = 0;
41125d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                }
41135d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent
41145d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                for (int effect = 0; effect < AudioManager.NUM_SOUND_EFFECTS; effect++) {
41155d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    if (SOUND_EFFECT_FILES_MAP[effect][1] <= 0) {
41165d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                        continue;
41175d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    }
41185d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    if (poolId[SOUND_EFFECT_FILES_MAP[effect][0]] == 0) {
41195d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                        mSoundPool.unload(SOUND_EFFECT_FILES_MAP[effect][1]);
41205d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                        SOUND_EFFECT_FILES_MAP[effect][1] = -1;
41215d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                        poolId[SOUND_EFFECT_FILES_MAP[effect][0]] = -1;
41225d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    }
41235d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                }
41245d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                mSoundPool.release();
41255d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                mSoundPool = null;
41265d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent            }
41275d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent        }
41285d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent
41295d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent        private void onPlaySoundEffect(int effectType, int volume) {
41309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            synchronized (mSoundEffectsLock) {
41315d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent
41325d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                onLoadSoundEffects();
41335d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent
41349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (mSoundPool == null) {
41359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    return;
41369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
4137a2ef57dba9ac77d8eccacd646b2b8a8d99fe9d8bEric Laurent                float volFloat;
413825101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent                // use default if volume is not specified by caller
4139a2ef57dba9ac77d8eccacd646b2b8a8d99fe9d8bEric Laurent                if (volume < 0) {
4140f2b0c11f4e797e183131261724d8de310dac5431Jean-Michel Trivi                    volFloat = (float)Math.pow(10, (float)sSoundEffectVolumeDb/20);
4141a2ef57dba9ac77d8eccacd646b2b8a8d99fe9d8bEric Laurent                } else {
41428a2cfc309ab9126e90022916967c65a793c034f0RoboErik                    volFloat = volume / 1000.0f;
4143a2ef57dba9ac77d8eccacd646b2b8a8d99fe9d8bEric Laurent                }
41449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
41459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (SOUND_EFFECT_FILES_MAP[effectType][1] > 0) {
41465d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    mSoundPool.play(SOUND_EFFECT_FILES_MAP[effectType][1],
41475d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                                        volFloat, volFloat, 0, 0, 1.0f);
41489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                } else {
41499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    MediaPlayer mediaPlayer = new MediaPlayer();
415062b9aec7a0a4e1cf8cfec7e39ea3103ab510d72eGlenn Kasten                    try {
4151e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent                        String filePath = Environment.getRootDirectory() + SOUND_EFFECTS_PATH +
4152e78fced559d879b2e37b610d0d9a89daf08f0f2bEric Laurent                                    SOUND_EFFECT_FILES.get(SOUND_EFFECT_FILES_MAP[effectType][0]);
415362b9aec7a0a4e1cf8cfec7e39ea3103ab510d72eGlenn Kasten                        mediaPlayer.setDataSource(filePath);
415462b9aec7a0a4e1cf8cfec7e39ea3103ab510d72eGlenn Kasten                        mediaPlayer.setAudioStreamType(AudioSystem.STREAM_SYSTEM);
415562b9aec7a0a4e1cf8cfec7e39ea3103ab510d72eGlenn Kasten                        mediaPlayer.prepare();
4156068225de0197df07a0247b2877666ea91c22c992Glenn Kasten                        mediaPlayer.setVolume(volFloat);
415762b9aec7a0a4e1cf8cfec7e39ea3103ab510d72eGlenn Kasten                        mediaPlayer.setOnCompletionListener(new OnCompletionListener() {
415862b9aec7a0a4e1cf8cfec7e39ea3103ab510d72eGlenn Kasten                            public void onCompletion(MediaPlayer mp) {
415962b9aec7a0a4e1cf8cfec7e39ea3103ab510d72eGlenn Kasten                                cleanupPlayer(mp);
416062b9aec7a0a4e1cf8cfec7e39ea3103ab510d72eGlenn Kasten                            }
416162b9aec7a0a4e1cf8cfec7e39ea3103ab510d72eGlenn Kasten                        });
416262b9aec7a0a4e1cf8cfec7e39ea3103ab510d72eGlenn Kasten                        mediaPlayer.setOnErrorListener(new OnErrorListener() {
416362b9aec7a0a4e1cf8cfec7e39ea3103ab510d72eGlenn Kasten                            public boolean onError(MediaPlayer mp, int what, int extra) {
416462b9aec7a0a4e1cf8cfec7e39ea3103ab510d72eGlenn Kasten                                cleanupPlayer(mp);
416562b9aec7a0a4e1cf8cfec7e39ea3103ab510d72eGlenn Kasten                                return true;
416662b9aec7a0a4e1cf8cfec7e39ea3103ab510d72eGlenn Kasten                            }
416762b9aec7a0a4e1cf8cfec7e39ea3103ab510d72eGlenn Kasten                        });
416862b9aec7a0a4e1cf8cfec7e39ea3103ab510d72eGlenn Kasten                        mediaPlayer.start();
416962b9aec7a0a4e1cf8cfec7e39ea3103ab510d72eGlenn Kasten                    } catch (IOException ex) {
417062b9aec7a0a4e1cf8cfec7e39ea3103ab510d72eGlenn Kasten                        Log.w(TAG, "MediaPlayer IOException: "+ex);
417162b9aec7a0a4e1cf8cfec7e39ea3103ab510d72eGlenn Kasten                    } catch (IllegalArgumentException ex) {
417262b9aec7a0a4e1cf8cfec7e39ea3103ab510d72eGlenn Kasten                        Log.w(TAG, "MediaPlayer IllegalArgumentException: "+ex);
417362b9aec7a0a4e1cf8cfec7e39ea3103ab510d72eGlenn Kasten                    } catch (IllegalStateException ex) {
417462b9aec7a0a4e1cf8cfec7e39ea3103ab510d72eGlenn Kasten                        Log.w(TAG, "MediaPlayer IllegalStateException: "+ex);
41759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    }
41769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
41779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
41789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
41799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
41809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        private void cleanupPlayer(MediaPlayer mp) {
41819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (mp != null) {
41829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                try {
41839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    mp.stop();
41849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    mp.release();
41859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                } catch (IllegalStateException ex) {
41869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    Log.w(TAG, "MediaPlayer IllegalStateException: "+ex);
41879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
41889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
41899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
41909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4191fa640154f1f42121d81242b2f1a10f03e52f0014Eric Laurent        private void setForceUse(int usage, int config) {
4192fa640154f1f42121d81242b2f1a10f03e52f0014Eric Laurent            AudioSystem.setForceUse(usage, config);
4193fa640154f1f42121d81242b2f1a10f03e52f0014Eric Laurent        }
4194fa640154f1f42121d81242b2f1a10f03e52f0014Eric Laurent
419505274f348e12983eb8613cc6eb9ae561e8197e28Eric Laurent        private void onPersistSafeVolumeState(int state) {
419605274f348e12983eb8613cc6eb9ae561e8197e28Eric Laurent            Settings.Global.putInt(mContentResolver,
419705274f348e12983eb8613cc6eb9ae561e8197e28Eric Laurent                    Settings.Global.AUDIO_SAFE_VOLUME_STATE,
419805274f348e12983eb8613cc6eb9ae561e8197e28Eric Laurent                    state);
419905274f348e12983eb8613cc6eb9ae561e8197e28Eric Laurent        }
420005274f348e12983eb8613cc6eb9ae561e8197e28Eric Laurent
42019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        @Override
42029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public void handleMessage(Message msg) {
4203afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent            switch (msg.what) {
42049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
42059bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                case MSG_SET_DEVICE_VOLUME:
42069bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                    setDeviceVolume((VolumeStreamState) msg.obj, msg.arg1);
42079bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                    break;
42089bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent
42099bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                case MSG_SET_ALL_VOLUMES:
42109bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                    setAllVolumes((VolumeStreamState) msg.obj);
42119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    break;
42129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
42139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                case MSG_PERSIST_VOLUME:
421442b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                    persistVolume((VolumeStreamState) msg.obj, msg.arg1);
42159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    break;
42169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
42175c55a051ad7d86a464fb91426f1ea3c0250e38b3Mike Lockwood                case MSG_PERSIST_MASTER_VOLUME:
421883a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent                    if (mUseFixedVolume) {
421983a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent                        return;
422083a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent                    }
4221bc0fab1fc2db832ef86d8a33466ec4d68b103ca0Eric Laurent                    Settings.System.putFloatForUser(mContentResolver,
4222bc0fab1fc2db832ef86d8a33466ec4d68b103ca0Eric Laurent                                                    Settings.System.VOLUME_MASTER,
42238a2cfc309ab9126e90022916967c65a793c034f0RoboErik                                                    msg.arg1 / (float)1000.0,
4224bc0fab1fc2db832ef86d8a33466ec4d68b103ca0Eric Laurent                                                    UserHandle.USER_CURRENT);
42255c55a051ad7d86a464fb91426f1ea3c0250e38b3Mike Lockwood                    break;
42265c55a051ad7d86a464fb91426f1ea3c0250e38b3Mike Lockwood
422757978ed86286a33d5b1a0fd000ca3406ba9d87b3Justin Koh                case MSG_PERSIST_MASTER_VOLUME_MUTE:
422883a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent                    if (mUseFixedVolume) {
422983a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent                        return;
423083a017b6b7c099d1a0293e5839be6477325aef06Eric Laurent                    }
4231bc0fab1fc2db832ef86d8a33466ec4d68b103ca0Eric Laurent                    Settings.System.putIntForUser(mContentResolver,
4232bc0fab1fc2db832ef86d8a33466ec4d68b103ca0Eric Laurent                                                 Settings.System.VOLUME_MASTER_MUTE,
4233bc0fab1fc2db832ef86d8a33466ec4d68b103ca0Eric Laurent                                                 msg.arg1,
4234b53453fae037d67e421011936c8fdffe7ba43922Julia Reynolds                                                 msg.arg2);
423557978ed86286a33d5b1a0fd000ca3406ba9d87b3Justin Koh                    break;
423657978ed86286a33d5b1a0fd000ca3406ba9d87b3Justin Koh
42379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                case MSG_PERSIST_RINGER_MODE:
4238ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten                    // note that the value persisted is the current ringer mode, not the
4239ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten                    // value of ringer mode as of the time the request was made to persist
4240661f2cf45860d2e10924e6b69966a9afe255f28bJohn Spurlock                    persistRingerMode(getRingerModeInternal());
42419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    break;
42429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
42439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                case MSG_MEDIA_SERVER_DIED:
4244eb4b8a27e3219726691a868793d2247dc9d2a317Eric Laurent                    if (!mSystemReady ||
4245eb4b8a27e3219726691a868793d2247dc9d2a317Eric Laurent                            (AudioSystem.checkAudioFlinger() != AudioSystem.AUDIO_STATUS_OK)) {
424689e74ba1419732dd5c7f939e48d4aa7989fd3a51Eric Laurent                        Log.e(TAG, "Media server died.");
4247afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent                        sendMsg(mAudioHandler, MSG_MEDIA_SERVER_DIED, SENDMSG_NOOP, 0, 0,
424889e74ba1419732dd5c7f939e48d4aa7989fd3a51Eric Laurent                                null, 500);
4249dfb881f96af7898151940a4bbc52e45e6043d38bEric Laurent                        break;
425089e74ba1419732dd5c7f939e48d4aa7989fd3a51Eric Laurent                    }
42519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    Log.e(TAG, "Media server started.");
4252dfb881f96af7898151940a4bbc52e45e6043d38bEric Laurent
42533c652ca5a546e7227a5f4bdbf0f81552b2c91383Eric Laurent                    // indicate to audio HAL that we start the reconfiguration phase after a media
42543c652ca5a546e7227a5f4bdbf0f81552b2c91383Eric Laurent                    // server crash
4255dfb881f96af7898151940a4bbc52e45e6043d38bEric Laurent                    // Note that we only execute this when the media server
42563c652ca5a546e7227a5f4bdbf0f81552b2c91383Eric Laurent                    // process restarts after a crash, not the first time it is started.
42573c652ca5a546e7227a5f4bdbf0f81552b2c91383Eric Laurent                    AudioSystem.setParameters("restarting=true");
42583c652ca5a546e7227a5f4bdbf0f81552b2c91383Eric Laurent
4259fd116ad1ab02f6060a0b2201f018317fa32e28b4Glenn Kasten                    readAndSetLowRamDevice();
4260fd116ad1ab02f6060a0b2201f018317fa32e28b4Glenn Kasten
4261c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent                    // Restore device connection states
42626bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                    synchronized (mConnectedDevices) {
42636bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                        Set set = mConnectedDevices.entrySet();
42646bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                        Iterator i = set.iterator();
42659bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                        while (i.hasNext()) {
42666bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                            Map.Entry device = (Map.Entry)i.next();
42676bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                            AudioSystem.setDeviceConnectionState(
42686bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                                                            ((Integer)device.getKey()).intValue(),
42696bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                                                            AudioSystem.DEVICE_STATE_AVAILABLE,
42706bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                                                            (String)device.getValue());
42716bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                        }
4272c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent                    }
4273c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent                    // Restore call state
4274c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent                    AudioSystem.setPhoneState(mMode);
4275c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent
4276d5603c126acdd94d9f7400bb1d04188020a425b4Eric Laurent                    // Restore forced usage for communcations and record
4277c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent                    AudioSystem.setForceUse(AudioSystem.FOR_COMMUNICATION, mForcedUseForComm);
4278d5603c126acdd94d9f7400bb1d04188020a425b4Eric Laurent                    AudioSystem.setForceUse(AudioSystem.FOR_RECORD, mForcedUseForComm);
4279dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent                    AudioSystem.setForceUse(AudioSystem.FOR_SYSTEM, mCameraSoundForced ?
4280dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent                                    AudioSystem.FORCE_SYSTEM_ENFORCED : AudioSystem.FORCE_NONE);
4281c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent
4282a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent                    // Restore stream volumes
42839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    int numStreamTypes = AudioSystem.getNumStreamTypes();
42849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
42859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        VolumeStreamState streamState = mStreamStates[streamType];
4286c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent                        AudioSystem.initStreamVolume(streamType, 0, (streamState.mIndexMax + 5) / 10);
42879bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent
42889bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                        streamState.applyAllVolumes();
42899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    }
4290c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent
4291c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent                    // Restore ringer mode
4292661f2cf45860d2e10924e6b69966a9afe255f28bJohn Spurlock                    setRingerModeInt(getRingerModeInternal(), false);
42933c652ca5a546e7227a5f4bdbf0f81552b2c91383Eric Laurent
42949063154a793b0ab38b3c5992cbaed046427b4a82Mike Lockwood                    // Restore master volume
42959063154a793b0ab38b3c5992cbaed046427b4a82Mike Lockwood                    restoreMasterVolume();
42969063154a793b0ab38b3c5992cbaed046427b4a82Mike Lockwood
4297f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi                    // Reset device orientation (if monitored for this device)
4298d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent                    if (mMonitorOrientation) {
4299f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi                        setOrientationForAudioSystem();
4300f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi                    }
4301bb6f8711a7f804d39c45218db2d6339940cc5d35Jean-Michel Trivi                    if (mMonitorRotation) {
4302bb6f8711a7f804d39c45218db2d6339940cc5d35Jean-Michel Trivi                        setRotationForAudioSystem();
4303bb6f8711a7f804d39c45218db2d6339940cc5d35Jean-Michel Trivi                    }
4304f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi
43057847211fb4699bf6018e29d214a918ed6657319bEric Laurent                    synchronized (mBluetoothA2dpEnabledLock) {
43067847211fb4699bf6018e29d214a918ed6657319bEric Laurent                        AudioSystem.setForceUse(AudioSystem.FOR_MEDIA,
43077847211fb4699bf6018e29d214a918ed6657319bEric Laurent                                mBluetoothA2dpEnabled ?
43087847211fb4699bf6018e29d214a918ed6657319bEric Laurent                                        AudioSystem.FORCE_NONE : AudioSystem.FORCE_NO_BT_A2DP);
43097847211fb4699bf6018e29d214a918ed6657319bEric Laurent                    }
4310bff5ca576ef55bfdd51a0d2ff39f4bac614fa728Eric Laurent
4311bff5ca576ef55bfdd51a0d2ff39f4bac614fa728Eric Laurent                    synchronized (mSettingsLock) {
4312bff5ca576ef55bfdd51a0d2ff39f4bac614fa728Eric Laurent                        AudioSystem.setForceUse(AudioSystem.FOR_DOCK,
4313bff5ca576ef55bfdd51a0d2ff39f4bac614fa728Eric Laurent                                mDockAudioMediaEnabled ?
4314bff5ca576ef55bfdd51a0d2ff39f4bac614fa728Eric Laurent                                        AudioSystem.FORCE_ANALOG_DOCK : AudioSystem.FORCE_NONE);
4315bff5ca576ef55bfdd51a0d2ff39f4bac614fa728Eric Laurent                    }
4316212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent                    if (mHdmiManager != null) {
4317212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent                        synchronized (mHdmiManager) {
4318212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent                            if (mHdmiTvClient != null) {
4319212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent                                setHdmiSystemAudioSupported(mHdmiSystemAudioSupported);
4320212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent                            }
4321212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent                        }
43226f34f5ab8ab1b1db7887e5405d8b0031e105ab05Jungshik Jang                    }
43237f5eb9fe3c10d8d83ff0e2b0fc60a05c2e6d5b02Eric Laurent
43247f5eb9fe3c10d8d83ff0e2b0fc60a05c2e6d5b02Eric Laurent                    synchronized (mAudioPolicies) {
43257f5eb9fe3c10d8d83ff0e2b0fc60a05c2e6d5b02Eric Laurent                        for(AudioPolicyProxy policy : mAudioPolicies.values()) {
43267f5eb9fe3c10d8d83ff0e2b0fc60a05c2e6d5b02Eric Laurent                            policy.connectMixes();
43277f5eb9fe3c10d8d83ff0e2b0fc60a05c2e6d5b02Eric Laurent                        }
43287f5eb9fe3c10d8d83ff0e2b0fc60a05c2e6d5b02Eric Laurent                    }
43297f5eb9fe3c10d8d83ff0e2b0fc60a05c2e6d5b02Eric Laurent
43303c652ca5a546e7227a5f4bdbf0f81552b2c91383Eric Laurent                    // indicate the end of reconfiguration phase to audio HAL
43313c652ca5a546e7227a5f4bdbf0f81552b2c91383Eric Laurent                    AudioSystem.setParameters("restarting=false");
43329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    break;
43339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
43345d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                case MSG_UNLOAD_SOUND_EFFECTS:
43355d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    onUnloadSoundEffects();
43365d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    break;
43375d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent
4338117b7bb5b5a4457711f59bde3dcc83d8f111c524Eric Laurent                case MSG_LOAD_SOUND_EFFECTS:
43395d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    //FIXME: onLoadSoundEffects() should be executed in a separate thread as it
43405d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    // can take several dozens of milliseconds to complete
43415d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    boolean loaded = onLoadSoundEffects();
43425d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    if (msg.obj != null) {
43435d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                        LoadSoundEffectReply reply = (LoadSoundEffectReply)msg.obj;
43445d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                        synchronized (reply) {
43455d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                            reply.mStatus = loaded ? 0 : -1;
43465d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                            reply.notify();
43475d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                        }
43485d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    }
4349117b7bb5b5a4457711f59bde3dcc83d8f111c524Eric Laurent                    break;
4350117b7bb5b5a4457711f59bde3dcc83d8f111c524Eric Laurent
43519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                case MSG_PLAY_SOUND_EFFECT:
43525d3eb44a749ece55ce345f9d8ac608fc3715f9daEric Laurent                    onPlaySoundEffect(msg.arg1, msg.arg2);
43539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    break;
43544c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi
43554c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi                case MSG_BTA2DP_DOCK_TIMEOUT:
43564c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi                    // msg.obj  == address of BTA2DP device
43576bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                    synchronized (mConnectedDevices) {
43586bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                        makeA2dpDeviceUnavailableNow( (String) msg.obj );
43596bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                    }
43604c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi                    break;
4361fa640154f1f42121d81242b2f1a10f03e52f0014Eric Laurent
4362fa640154f1f42121d81242b2f1a10f03e52f0014Eric Laurent                case MSG_SET_FORCE_USE:
4363c390bed06b4a572e273ead1254da9a932e04dce3Eric Laurent                case MSG_SET_FORCE_BT_A2DP_USE:
4364fa640154f1f42121d81242b2f1a10f03e52f0014Eric Laurent                    setForceUse(msg.arg1, msg.arg2);
4365fa640154f1f42121d81242b2f1a10f03e52f0014Eric Laurent                    break;
4366d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi
4367dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                case MSG_BT_HEADSET_CNCT_FAILED:
4368dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                    resetBluetoothSco();
4369dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                    break;
4370b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent
4371b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent                case MSG_SET_WIRED_DEVICE_CONNECTION_STATE:
4372b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent                    onSetWiredDeviceConnectionState(msg.arg1, msg.arg2, (String)msg.obj);
4373fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                    mAudioEventWakeLock.release();
4374b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent                    break;
4375b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent
43760a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood                case MSG_SET_A2DP_SRC_CONNECTION_STATE:
43770a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood                    onSetA2dpSourceConnectionState((BluetoothDevice)msg.obj, msg.arg1);
43780a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood                    mAudioEventWakeLock.release();
43790a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood                    break;
43800a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood
43810a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood                case MSG_SET_A2DP_SINK_CONNECTION_STATE:
43820a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood                    onSetA2dpSinkConnectionState((BluetoothDevice)msg.obj, msg.arg1);
4383fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                    mAudioEventWakeLock.release();
4384b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent                    break;
4385632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn
4386632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                case MSG_REPORT_NEW_ROUTES: {
4387632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                    int N = mRoutesObservers.beginBroadcast();
4388632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                    if (N > 0) {
4389632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                        AudioRoutesInfo routes;
4390632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                        synchronized (mCurAudioRoutes) {
4391632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                            routes = new AudioRoutesInfo(mCurAudioRoutes);
4392632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                        }
4393632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                        while (N > 0) {
4394632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                            N--;
4395632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                            IAudioRoutesObserver obs = mRoutesObservers.getBroadcastItem(N);
4396632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                            try {
4397632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                                obs.dispatchAudioRoutesChanged(routes);
4398632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                            } catch (RemoteException e) {
4399632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                            }
4400632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                        }
4401632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                    }
4402632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                    mRoutesObservers.finishBroadcast();
4403632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                    break;
4404632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                }
44053114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi
4406c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent                case MSG_CHECK_MUSIC_ACTIVE:
4407c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent                    onCheckMusicActive();
4408c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent                    break;
44095bfaeaef3fc348d66f48b86be08655e91dff910aEric Laurent
44105bfaeaef3fc348d66f48b86be08655e91dff910aEric Laurent                case MSG_BROADCAST_AUDIO_BECOMING_NOISY:
44115bfaeaef3fc348d66f48b86be08655e91dff910aEric Laurent                    onSendBecomingNoisyIntent();
44125bfaeaef3fc348d66f48b86be08655e91dff910aEric Laurent                    break;
4413d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent
4414d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent                case MSG_CONFIGURE_SAFE_MEDIA_VOLUME_FORCED:
4415d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent                case MSG_CONFIGURE_SAFE_MEDIA_VOLUME:
4416d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent                    onConfigureSafeVolume((msg.what == MSG_CONFIGURE_SAFE_MEDIA_VOLUME_FORCED));
4417d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent                    break;
441805274f348e12983eb8613cc6eb9ae561e8197e28Eric Laurent                case MSG_PERSIST_SAFE_VOLUME_STATE:
441905274f348e12983eb8613cc6eb9ae561e8197e28Eric Laurent                    onPersistSafeVolumeState(msg.arg1);
442005274f348e12983eb8613cc6eb9ae561e8197e28Eric Laurent                    break;
4421a578c48e6c8677bcb54340aadb9470f8a275e56cJean-Michel Trivi
44222a57ca931fefe817b6110101289721acaacfc808Eric Laurent                case MSG_BROADCAST_BT_CONNECTION_STATE:
44232a57ca931fefe817b6110101289721acaacfc808Eric Laurent                    onBroadcastScoConnectionState(msg.arg1);
44242a57ca931fefe817b6110101289721acaacfc808Eric Laurent                    break;
44254a5eeb9c727d77bb57fef87a70c8c9cc23dbfee3Eric Laurent
44264a5eeb9c727d77bb57fef87a70c8c9cc23dbfee3Eric Laurent                case MSG_SYSTEM_READY:
44274a5eeb9c727d77bb57fef87a70c8c9cc23dbfee3Eric Laurent                    onSystemReady();
44284a5eeb9c727d77bb57fef87a70c8c9cc23dbfee3Eric Laurent                    break;
4429aa5ee4d65f8788e2a0afcd198367450853fd72acJohn Spurlock
4430aa5ee4d65f8788e2a0afcd198367450853fd72acJohn Spurlock                case MSG_PERSIST_MUSIC_ACTIVE_MS:
4431aa5ee4d65f8788e2a0afcd198367450853fd72acJohn Spurlock                    final int musicActiveMs = msg.arg1;
4432aa5ee4d65f8788e2a0afcd198367450853fd72acJohn Spurlock                    Settings.Secure.putIntForUser(mContentResolver,
4433aa5ee4d65f8788e2a0afcd198367450853fd72acJohn Spurlock                            Settings.Secure.UNSAFE_VOLUME_MUSIC_ACTIVE_MS, musicActiveMs,
4434aa5ee4d65f8788e2a0afcd198367450853fd72acJohn Spurlock                            UserHandle.USER_CURRENT);
4435aa5ee4d65f8788e2a0afcd198367450853fd72acJohn Spurlock                    break;
4436b53453fae037d67e421011936c8fdffe7ba43922Julia Reynolds                case MSG_PERSIST_MICROPHONE_MUTE:
4437b53453fae037d67e421011936c8fdffe7ba43922Julia Reynolds                    Settings.System.putIntForUser(mContentResolver,
4438b53453fae037d67e421011936c8fdffe7ba43922Julia Reynolds                                                 Settings.System.MICROPHONE_MUTE,
4439b53453fae037d67e421011936c8fdffe7ba43922Julia Reynolds                                                 msg.arg1,
4440b53453fae037d67e421011936c8fdffe7ba43922Julia Reynolds                                                 msg.arg2);
4441b53453fae037d67e421011936c8fdffe7ba43922Julia Reynolds                    break;
44429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
44439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
44449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
44459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4446b109615ebebd6f3b9ae789412279f576c3ace46bJason Parekh    private class SettingsObserver extends ContentObserver {
4447a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent
4448b109615ebebd6f3b9ae789412279f576c3ace46bJason Parekh        SettingsObserver() {
4449b109615ebebd6f3b9ae789412279f576c3ace46bJason Parekh            super(new Handler());
4450b109615ebebd6f3b9ae789412279f576c3ace46bJason Parekh            mContentResolver.registerContentObserver(Settings.System.getUriFor(
4451b109615ebebd6f3b9ae789412279f576c3ace46bJason Parekh                Settings.System.MODE_RINGER_STREAMS_AFFECTED), false, this);
44527ee1e4ff7346a278a6722108fbc1869240b3e866Eric Laurent            mContentResolver.registerContentObserver(Settings.Global.getUriFor(
44537ee1e4ff7346a278a6722108fbc1869240b3e866Eric Laurent                Settings.Global.DOCK_AUDIO_MEDIA_ENABLED), false, this);
4454b109615ebebd6f3b9ae789412279f576c3ace46bJason Parekh        }
4455b109615ebebd6f3b9ae789412279f576c3ace46bJason Parekh
4456b109615ebebd6f3b9ae789412279f576c3ace46bJason Parekh        @Override
4457b109615ebebd6f3b9ae789412279f576c3ace46bJason Parekh        public void onChange(boolean selfChange) {
4458b109615ebebd6f3b9ae789412279f576c3ace46bJason Parekh            super.onChange(selfChange);
4459ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten            // FIXME This synchronized is not necessary if mSettingsLock only protects mRingerMode.
4460ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten            //       However there appear to be some missing locks around mRingerModeMutedStreams
4461ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten            //       and mRingerModeAffectedStreams, so will leave this synchronized for now.
4462ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten            //       mRingerModeMutedStreams and mMuteAffectedStreams are safe (only accessed once).
4463a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent            synchronized (mSettingsLock) {
446424e0d9b6c40712a297e4c287435a3b0fdd30e9daEric Laurent                if (updateRingerModeAffectedStreams()) {
4465a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent                    /*
4466a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent                     * Ensure all stream types that should be affected by ringer mode
4467a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent                     * are in the proper state.
4468a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent                     */
4469661f2cf45860d2e10924e6b69966a9afe255f28bJohn Spurlock                    setRingerModeInt(getRingerModeInternal(), false);
4470a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent                }
44717ee1e4ff7346a278a6722108fbc1869240b3e866Eric Laurent                readDockAudioSettings(mContentResolver);
4472a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent            }
4473b109615ebebd6f3b9ae789412279f576c3ace46bJason Parekh        }
4474b109615ebebd6f3b9ae789412279f576c3ace46bJason Parekh    }
4475a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent
44766bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent    // must be called synchronized on mConnectedDevices
44774c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi    private void makeA2dpDeviceAvailable(String address) {
44787847211fb4699bf6018e29d214a918ed6657319bEric Laurent        // enable A2DP before notifying A2DP connection to avoid unecessary processing in
44797847211fb4699bf6018e29d214a918ed6657319bEric Laurent        // audio policy manager
4480c9d1d5f35091226e96fcfa91817480f589eb36e2Matthew Xie        VolumeStreamState streamState = mStreamStates[AudioSystem.STREAM_MUSIC];
4481c9d1d5f35091226e96fcfa91817480f589eb36e2Matthew Xie        sendMsg(mAudioHandler, MSG_SET_DEVICE_VOLUME, SENDMSG_QUEUE,
4482c9d1d5f35091226e96fcfa91817480f589eb36e2Matthew Xie                AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, 0, streamState, 0);
44837847211fb4699bf6018e29d214a918ed6657319bEric Laurent        setBluetoothA2dpOnInt(true);
44844c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi        AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
44854c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi                AudioSystem.DEVICE_STATE_AVAILABLE,
44864c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi                address);
44874c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi        // Reset A2DP suspend state each time a new sink is connected
44884c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi        AudioSystem.setParameters("A2dpSuspended=false");
44894c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi        mConnectedDevices.put( new Integer(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP),
44904c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi                address);
44914c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi    }
44924c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi
44935bfaeaef3fc348d66f48b86be08655e91dff910aEric Laurent    private void onSendBecomingNoisyIntent() {
44945ac72a29593ab9a20337a2225df52bdf4754be02Dianne Hackborn        sendBroadcastToAll(new Intent(AudioManager.ACTION_AUDIO_BECOMING_NOISY));
44959841818b9a0280abf59343c9e00a2976dbc084faMike Lockwood    }
44969841818b9a0280abf59343c9e00a2976dbc084faMike Lockwood
44976bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent    // must be called synchronized on mConnectedDevices
44984c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi    private void makeA2dpDeviceUnavailableNow(String address) {
4499c9d1d5f35091226e96fcfa91817480f589eb36e2Matthew Xie        synchronized (mA2dpAvrcpLock) {
4500c9d1d5f35091226e96fcfa91817480f589eb36e2Matthew Xie            mAvrcpAbsVolSupported = false;
4501c9d1d5f35091226e96fcfa91817480f589eb36e2Matthew Xie        }
45024c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi        AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
45034c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi                AudioSystem.DEVICE_STATE_UNAVAILABLE,
45044c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi                address);
45054c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi        mConnectedDevices.remove(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP);
45065535ea8ef876be25121a6336ffab5a0bf8dbd031RoboErik        synchronized (mCurAudioRoutes) {
45075535ea8ef876be25121a6336ffab5a0bf8dbd031RoboErik            // Remove A2DP routes as well
45085535ea8ef876be25121a6336ffab5a0bf8dbd031RoboErik            if (mCurAudioRoutes.mBluetoothName != null) {
45095535ea8ef876be25121a6336ffab5a0bf8dbd031RoboErik                mCurAudioRoutes.mBluetoothName = null;
45105535ea8ef876be25121a6336ffab5a0bf8dbd031RoboErik                sendMsg(mAudioHandler, MSG_REPORT_NEW_ROUTES,
45115535ea8ef876be25121a6336ffab5a0bf8dbd031RoboErik                        SENDMSG_NOOP, 0, 0, null, 0);
45125535ea8ef876be25121a6336ffab5a0bf8dbd031RoboErik            }
45135535ea8ef876be25121a6336ffab5a0bf8dbd031RoboErik        }
45144c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi    }
45154c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi
45166bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent    // must be called synchronized on mConnectedDevices
45174c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi    private void makeA2dpDeviceUnavailableLater(String address) {
45183b5912602bec6ccbe8eef8a576730b1565f0067cEric Laurent        // prevent any activity on the A2DP audio output to avoid unwanted
45193b5912602bec6ccbe8eef8a576730b1565f0067cEric Laurent        // reconnection of the sink.
45203b5912602bec6ccbe8eef8a576730b1565f0067cEric Laurent        AudioSystem.setParameters("A2dpSuspended=true");
45214c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi        // the device will be made unavailable later, so consider it disconnected right away
45224c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi        mConnectedDevices.remove(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP);
45234c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi        // send the delayed message to make the device unavailable later
45244c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi        Message msg = mAudioHandler.obtainMessage(MSG_BTA2DP_DOCK_TIMEOUT, address);
45254c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi        mAudioHandler.sendMessageDelayed(msg, BTA2DP_DOCK_TIMEOUT_MILLIS);
45264c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi
45274c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi    }
45284c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi
45296bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent    // must be called synchronized on mConnectedDevices
45300a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood    private void makeA2dpSrcAvailable(String address) {
45310a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood        AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP,
45320a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood                AudioSystem.DEVICE_STATE_AVAILABLE,
45330a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood                address);
45340a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood        mConnectedDevices.put( new Integer(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP),
45350a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood                address);
45360a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood    }
45370a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood
45380a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood    // must be called synchronized on mConnectedDevices
45390a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood    private void makeA2dpSrcUnavailable(String address) {
45400a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood        AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP,
45410a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood                AudioSystem.DEVICE_STATE_UNAVAILABLE,
45420a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood                address);
45430a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood        mConnectedDevices.remove(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP);
45440a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood    }
45450a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood
45460a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood    // must be called synchronized on mConnectedDevices
4547a847ba4080675d395de725cfac5dfd9d5a993d4eJean-Michel Trivi    private void cancelA2dpDeviceTimeout() {
45484c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi        mAudioHandler.removeMessages(MSG_BTA2DP_DOCK_TIMEOUT);
45494c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi    }
45504c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi
45516bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent    // must be called synchronized on mConnectedDevices
4552a847ba4080675d395de725cfac5dfd9d5a993d4eJean-Michel Trivi    private boolean hasScheduledA2dpDockTimeout() {
4553a847ba4080675d395de725cfac5dfd9d5a993d4eJean-Michel Trivi        return mAudioHandler.hasMessages(MSG_BTA2DP_DOCK_TIMEOUT);
4554a847ba4080675d395de725cfac5dfd9d5a993d4eJean-Michel Trivi    }
4555a847ba4080675d395de725cfac5dfd9d5a993d4eJean-Michel Trivi
45560a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood    private void onSetA2dpSinkConnectionState(BluetoothDevice btDevice, int state)
45576bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent    {
45580a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood        if (DEBUG_VOL) {
45590a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood            Log.d(TAG, "onSetA2dpSinkConnectionState btDevice="+btDevice+"state="+state);
45600a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood        }
45616bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent        if (btDevice == null) {
45626bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent            return;
45636bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent        }
45646bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent        String address = btDevice.getAddress();
45656bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent        if (!BluetoothAdapter.checkBluetoothAddress(address)) {
45666bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent            address = "";
45676bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent        }
45685a0cf7a27f3953a1266af48543ccd9024f4cd89fJohn Du
45696bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent        synchronized (mConnectedDevices) {
45706bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent            boolean isConnected =
45716bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                (mConnectedDevices.containsKey(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP) &&
45726bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                 mConnectedDevices.get(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP).equals(address));
45736bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent
45746bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent            if (isConnected && state != BluetoothProfile.STATE_CONNECTED) {
45756bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                if (btDevice.isBluetoothDock()) {
45766bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                    if (state == BluetoothProfile.STATE_DISCONNECTED) {
45776bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                        // introduction of a delay for transient disconnections of docks when
45786bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                        // power is rapidly turned off/on, this message will be canceled if
45796bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                        // we reconnect the dock under a preset delay
45806bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                        makeA2dpDeviceUnavailableLater(address);
45816bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                        // the next time isConnected is evaluated, it will be false for the dock
45826bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                    }
45836bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                } else {
45846bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                    makeA2dpDeviceUnavailableNow(address);
45856bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                }
4586632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                synchronized (mCurAudioRoutes) {
4587632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                    if (mCurAudioRoutes.mBluetoothName != null) {
4588632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                        mCurAudioRoutes.mBluetoothName = null;
4589632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                        sendMsg(mAudioHandler, MSG_REPORT_NEW_ROUTES,
4590632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                                SENDMSG_NOOP, 0, 0, null, 0);
4591632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                    }
4592632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                }
45936bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent            } else if (!isConnected && state == BluetoothProfile.STATE_CONNECTED) {
45946bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                if (btDevice.isBluetoothDock()) {
45956bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                    // this could be a reconnection after a transient disconnection
45966bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                    cancelA2dpDeviceTimeout();
45976bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                    mDockAddress = address;
45986bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                } else {
45996bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                    // this could be a connection of another A2DP device before the timeout of
46006bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                    // a dock: cancel the dock timeout, and make the dock unavailable now
46016bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                    if(hasScheduledA2dpDockTimeout()) {
46026bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                        cancelA2dpDeviceTimeout();
46036bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                        makeA2dpDeviceUnavailableNow(mDockAddress);
46046bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                    }
46056bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                }
46066bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                makeA2dpDeviceAvailable(address);
4607632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                synchronized (mCurAudioRoutes) {
4608632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                    String name = btDevice.getAliasName();
4609632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                    if (!TextUtils.equals(mCurAudioRoutes.mBluetoothName, name)) {
4610632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                        mCurAudioRoutes.mBluetoothName = name;
4611632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                        sendMsg(mAudioHandler, MSG_REPORT_NEW_ROUTES,
4612632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                                SENDMSG_NOOP, 0, 0, null, 0);
4613632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                    }
4614632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                }
46156bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent            }
46166bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent        }
46176bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent    }
46186bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent
46190a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood    private void onSetA2dpSourceConnectionState(BluetoothDevice btDevice, int state)
46200a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood    {
46210a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood        if (DEBUG_VOL) {
46220a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood            Log.d(TAG, "onSetA2dpSourceConnectionState btDevice="+btDevice+" state="+state);
46230a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood        }
46240a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood        if (btDevice == null) {
46250a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood            return;
46260a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood        }
46270a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood        String address = btDevice.getAddress();
46280a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood        if (!BluetoothAdapter.checkBluetoothAddress(address)) {
46290a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood            address = "";
46300a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood        }
46310a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood
46320a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood        synchronized (mConnectedDevices) {
46330a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood                boolean isConnected =
46340a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood                (mConnectedDevices.containsKey(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP) &&
46350a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood                 mConnectedDevices.get(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP).equals(address));
46360a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood
46370a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood            if (isConnected && state != BluetoothProfile.STATE_CONNECTED) {
46380a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood                makeA2dpSrcUnavailable(address);
46390a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood            } else if (!isConnected && state == BluetoothProfile.STATE_CONNECTED) {
46400a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood                makeA2dpSrcAvailable(address);
46410a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood            }
46420a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood        }
46430a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood    }
46440a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood
46455a0cf7a27f3953a1266af48543ccd9024f4cd89fJohn Du    public void avrcpSupportsAbsoluteVolume(String address, boolean support) {
46465a0cf7a27f3953a1266af48543ccd9024f4cd89fJohn Du        // address is not used for now, but may be used when multiple a2dp devices are supported
46475a0cf7a27f3953a1266af48543ccd9024f4cd89fJohn Du        synchronized (mA2dpAvrcpLock) {
46485a0cf7a27f3953a1266af48543ccd9024f4cd89fJohn Du            mAvrcpAbsVolSupported = support;
4649c9d1d5f35091226e96fcfa91817480f589eb36e2Matthew Xie            sendMsg(mAudioHandler, MSG_SET_DEVICE_VOLUME, SENDMSG_QUEUE,
4650cd772d04345850e160a45613fcf6b86da0dce4cfEric Laurent                    AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, 0,
4651cd772d04345850e160a45613fcf6b86da0dce4cfEric Laurent                    mStreamStates[AudioSystem.STREAM_MUSIC], 0);
4652cd772d04345850e160a45613fcf6b86da0dce4cfEric Laurent            sendMsg(mAudioHandler, MSG_SET_DEVICE_VOLUME, SENDMSG_QUEUE,
4653cd772d04345850e160a45613fcf6b86da0dce4cfEric Laurent                    AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, 0,
4654cd772d04345850e160a45613fcf6b86da0dce4cfEric Laurent                    mStreamStates[AudioSystem.STREAM_RING], 0);
46555a0cf7a27f3953a1266af48543ccd9024f4cd89fJohn Du        }
46565a0cf7a27f3953a1266af48543ccd9024f4cd89fJohn Du    }
46575a0cf7a27f3953a1266af48543ccd9024f4cd89fJohn Du
465859f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent    private boolean handleDeviceConnection(boolean connected, int device, String params) {
465959f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent        synchronized (mConnectedDevices) {
466059f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent            boolean isConnected = (mConnectedDevices.containsKey(device) &&
46619841818b9a0280abf59343c9e00a2976dbc084faMike Lockwood                    (params.isEmpty() || mConnectedDevices.get(device).equals(params)));
466259f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent
466359f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent            if (isConnected && !connected) {
466459f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent                AudioSystem.setDeviceConnectionState(device,
466559f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent                                              AudioSystem.DEVICE_STATE_UNAVAILABLE,
46669841818b9a0280abf59343c9e00a2976dbc084faMike Lockwood                                              mConnectedDevices.get(device));
466759f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent                 mConnectedDevices.remove(device);
466859f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent                 return true;
466959f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent            } else if (!isConnected && connected) {
467059f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent                 AudioSystem.setDeviceConnectionState(device,
467159f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent                                                      AudioSystem.DEVICE_STATE_AVAILABLE,
467259f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent                                                      params);
467359f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent                 mConnectedDevices.put(new Integer(device), params);
467459f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent                 return true;
467559f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent            }
467659f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent        }
467759f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent        return false;
467859f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent    }
467959f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent
4680b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent    // Devices which removal triggers intent ACTION_AUDIO_BECOMING_NOISY. The intent is only
4681b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent    // sent if none of these devices is connected.
4682b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent    int mBecomingNoisyIntentDevices =
4683b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent            AudioSystem.DEVICE_OUT_WIRED_HEADSET | AudioSystem.DEVICE_OUT_WIRED_HEADPHONE |
4684948d32748caaac5be06c991ebf00f74265a7849fEric Laurent            AudioSystem.DEVICE_OUT_ALL_A2DP | AudioSystem.DEVICE_OUT_HDMI |
4685794da7a0543cbecffefb73794aa68d1a93e41adfEric Laurent            AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET | AudioSystem.DEVICE_OUT_DGTL_DOCK_HEADSET |
468643cc8bbbbd5e6418cdfa0fa4b26c9f5c3a28c029Jon Eklund            AudioSystem.DEVICE_OUT_ALL_USB | AudioSystem.DEVICE_OUT_LINE;
4687b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent
4688b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent    // must be called before removing the device from mConnectedDevices
4689b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent    private int checkSendBecomingNoisyIntent(int device, int state) {
4690b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent        int delay = 0;
4691b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent        if ((state == 0) && ((device & mBecomingNoisyIntentDevices) != 0)) {
4692b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent            int devices = 0;
4693b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent            for (int dev : mConnectedDevices.keySet()) {
469427c30e4426302581a266c89d0ef880b340d7b061Eric Laurent                if (((dev & AudioSystem.DEVICE_BIT_IN) == 0) &&
469527c30e4426302581a266c89d0ef880b340d7b061Eric Laurent                        ((dev & mBecomingNoisyIntentDevices) != 0)) {
4696b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent                   devices |= dev;
4697b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent                }
4698b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent            }
4699b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent            if (devices == device) {
47005bfaeaef3fc348d66f48b86be08655e91dff910aEric Laurent                sendMsg(mAudioHandler,
47015bfaeaef3fc348d66f48b86be08655e91dff910aEric Laurent                        MSG_BROADCAST_AUDIO_BECOMING_NOISY,
47025bfaeaef3fc348d66f48b86be08655e91dff910aEric Laurent                        SENDMSG_REPLACE,
47035bfaeaef3fc348d66f48b86be08655e91dff910aEric Laurent                        0,
47045bfaeaef3fc348d66f48b86be08655e91dff910aEric Laurent                        0,
47055bfaeaef3fc348d66f48b86be08655e91dff910aEric Laurent                        null,
47065bfaeaef3fc348d66f48b86be08655e91dff910aEric Laurent                        0);
4707b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent                delay = 1000;
4708b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent            }
4709b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent        }
4710b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent
47110a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood        if (mAudioHandler.hasMessages(MSG_SET_A2DP_SRC_CONNECTION_STATE) ||
47120a40ec2192e4836b2fcb6ba51a7688aa6bd4ee98Mike Lockwood                mAudioHandler.hasMessages(MSG_SET_A2DP_SINK_CONNECTION_STATE) ||
4713b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent                mAudioHandler.hasMessages(MSG_SET_WIRED_DEVICE_CONNECTION_STATE)) {
4714adbe8bf85f3c8230d16ae5cb3f5d9736e09ed84aEric Laurent            synchronized (mLastDeviceConnectMsgTime) {
4715adbe8bf85f3c8230d16ae5cb3f5d9736e09ed84aEric Laurent                long time = SystemClock.uptimeMillis();
4716adbe8bf85f3c8230d16ae5cb3f5d9736e09ed84aEric Laurent                if (mLastDeviceConnectMsgTime > time) {
4717c525cf7a33430f44246f63d1c68c4cda4b92254eMatthew Xie                    delay = (int)(mLastDeviceConnectMsgTime - time) + 30;
4718adbe8bf85f3c8230d16ae5cb3f5d9736e09ed84aEric Laurent                }
4719adbe8bf85f3c8230d16ae5cb3f5d9736e09ed84aEric Laurent            }
4720b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent        }
4721b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent        return delay;
4722b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent    }
4723b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent
4724b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent    private void sendDeviceConnectionIntent(int device, int state, String name)
4725b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent    {
4726b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent        Intent intent = new Intent();
4727b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent
4728b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent        intent.putExtra("state", state);
4729b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent        intent.putExtra("name", name);
4730b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent        intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
4731b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent
4732632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn        int connType = 0;
4733632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn
4734b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent        if (device == AudioSystem.DEVICE_OUT_WIRED_HEADSET) {
4735632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn            connType = AudioRoutesInfo.MAIN_HEADSET;
4736b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent            intent.setAction(Intent.ACTION_HEADSET_PLUG);
4737b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent            intent.putExtra("microphone", 1);
473843cc8bbbbd5e6418cdfa0fa4b26c9f5c3a28c029Jon Eklund        } else if (device == AudioSystem.DEVICE_OUT_WIRED_HEADPHONE ||
473943cc8bbbbd5e6418cdfa0fa4b26c9f5c3a28c029Jon Eklund                   device == AudioSystem.DEVICE_OUT_LINE) {
474043cc8bbbbd5e6418cdfa0fa4b26c9f5c3a28c029Jon Eklund            /*do apps care about line-out vs headphones?*/
4741632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn            connType = AudioRoutesInfo.MAIN_HEADPHONES;
4742b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent            intent.setAction(Intent.ACTION_HEADSET_PLUG);
4743b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent            intent.putExtra("microphone", 0);
4744b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent        } else if (device == AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET) {
4745632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn            connType = AudioRoutesInfo.MAIN_DOCK_SPEAKERS;
4746c5258433dd353769ccfa2e5e769a7379378a3a0bJean-Michel Trivi            intent.setAction(AudioManager.ACTION_ANALOG_AUDIO_DOCK_PLUG);
4747b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent        } else if (device == AudioSystem.DEVICE_OUT_DGTL_DOCK_HEADSET) {
4748632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn            connType = AudioRoutesInfo.MAIN_DOCK_SPEAKERS;
4749c5258433dd353769ccfa2e5e769a7379378a3a0bJean-Michel Trivi            intent.setAction(AudioManager.ACTION_DIGITAL_AUDIO_DOCK_PLUG);
47506fa4245589c93025d91aab7dc6681babdd91ee41Eric Laurent        } else if (device == AudioSystem.DEVICE_OUT_HDMI ||
47516fa4245589c93025d91aab7dc6681babdd91ee41Eric Laurent                device == AudioSystem.DEVICE_OUT_HDMI_ARC) {
4752632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn            connType = AudioRoutesInfo.MAIN_HDMI;
475337d7804627eecaf04e170793c2f5703d5d6d44e8Jean-Michel Trivi            configureHdmiPlugIntent(intent, state);
4754b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent        }
4755b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent
4756632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn        synchronized (mCurAudioRoutes) {
4757632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn            if (connType != 0) {
4758632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                int newConn = mCurAudioRoutes.mMainType;
4759632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                if (state != 0) {
4760632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                    newConn |= connType;
4761632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                } else {
4762632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                    newConn &= ~connType;
4763632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                }
4764632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                if (newConn != mCurAudioRoutes.mMainType) {
4765632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                    mCurAudioRoutes.mMainType = newConn;
4766632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                    sendMsg(mAudioHandler, MSG_REPORT_NEW_ROUTES,
4767632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                            SENDMSG_NOOP, 0, 0, null, 0);
4768632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                }
4769632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn            }
4770632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn        }
4771632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn
47725ac72a29593ab9a20337a2225df52bdf4754be02Dianne Hackborn        final long ident = Binder.clearCallingIdentity();
47735ac72a29593ab9a20337a2225df52bdf4754be02Dianne Hackborn        try {
47745ac72a29593ab9a20337a2225df52bdf4754be02Dianne Hackborn            ActivityManagerNative.broadcastStickyIntent(intent, null, UserHandle.USER_ALL);
47755ac72a29593ab9a20337a2225df52bdf4754be02Dianne Hackborn        } finally {
47765ac72a29593ab9a20337a2225df52bdf4754be02Dianne Hackborn            Binder.restoreCallingIdentity(ident);
47775ac72a29593ab9a20337a2225df52bdf4754be02Dianne Hackborn        }
4778b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent    }
4779b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent
4780b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent    private void onSetWiredDeviceConnectionState(int device, int state, String name)
4781b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent    {
4782b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent        synchronized (mConnectedDevices) {
4783b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent            if ((state == 0) && ((device == AudioSystem.DEVICE_OUT_WIRED_HEADSET) ||
478443cc8bbbbd5e6418cdfa0fa4b26c9f5c3a28c029Jon Eklund                    (device == AudioSystem.DEVICE_OUT_WIRED_HEADPHONE) ||
478543cc8bbbbd5e6418cdfa0fa4b26c9f5c3a28c029Jon Eklund                    (device == AudioSystem.DEVICE_OUT_LINE))) {
4786b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent                setBluetoothA2dpOnInt(true);
4787b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent            }
4788ae4506e9b5fc3e0c6d9862fbc05b9af7d6742a6eEric Laurent            boolean isUsb = ((device & ~AudioSystem.DEVICE_OUT_ALL_USB) == 0) ||
4789ae4506e9b5fc3e0c6d9862fbc05b9af7d6742a6eEric Laurent                            (((device & AudioSystem.DEVICE_BIT_IN) != 0) &&
4790ae4506e9b5fc3e0c6d9862fbc05b9af7d6742a6eEric Laurent                             ((device & ~AudioSystem.DEVICE_IN_ALL_USB) == 0));
4791db45484e4b5858d14da93d3a06311b93bf0cf320Mike Lockwood            handleDeviceConnection((state == 1), device, (isUsb ? name : ""));
4792f1a457d06c53a901ea08d2d3fb6e766bc06c4d4fEric Laurent            if (state != 0) {
4793f1a457d06c53a901ea08d2d3fb6e766bc06c4d4fEric Laurent                if ((device == AudioSystem.DEVICE_OUT_WIRED_HEADSET) ||
479443cc8bbbbd5e6418cdfa0fa4b26c9f5c3a28c029Jon Eklund                    (device == AudioSystem.DEVICE_OUT_WIRED_HEADPHONE) ||
479543cc8bbbbd5e6418cdfa0fa4b26c9f5c3a28c029Jon Eklund                    (device == AudioSystem.DEVICE_OUT_LINE)) {
4796f1a457d06c53a901ea08d2d3fb6e766bc06c4d4fEric Laurent                    setBluetoothA2dpOnInt(false);
4797f1a457d06c53a901ea08d2d3fb6e766bc06c4d4fEric Laurent                }
4798f1a457d06c53a901ea08d2d3fb6e766bc06c4d4fEric Laurent                if ((device & mSafeMediaVolumeDevices) != 0) {
4799f1a457d06c53a901ea08d2d3fb6e766bc06c4d4fEric Laurent                    sendMsg(mAudioHandler,
4800f1a457d06c53a901ea08d2d3fb6e766bc06c4d4fEric Laurent                            MSG_CHECK_MUSIC_ACTIVE,
4801f1a457d06c53a901ea08d2d3fb6e766bc06c4d4fEric Laurent                            SENDMSG_REPLACE,
4802f1a457d06c53a901ea08d2d3fb6e766bc06c4d4fEric Laurent                            0,
4803f1a457d06c53a901ea08d2d3fb6e766bc06c4d4fEric Laurent                            0,
4804f1a457d06c53a901ea08d2d3fb6e766bc06c4d4fEric Laurent                            null,
4805f1a457d06c53a901ea08d2d3fb6e766bc06c4d4fEric Laurent                            MUSIC_ACTIVE_POLL_PERIOD_MS);
4806f1a457d06c53a901ea08d2d3fb6e766bc06c4d4fEric Laurent                }
4807212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent                // Television devices without CEC service apply software volume on HDMI output
4808212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent                if (isPlatformTelevision() && ((device & AudioSystem.DEVICE_OUT_HDMI) != 0)) {
4809212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent                    mFixedVolumeDevices |= AudioSystem.DEVICE_OUT_HDMI;
4810212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent                    checkAllFixedVolumeDevices();
4811212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent                    if (mHdmiManager != null) {
4812212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent                        synchronized (mHdmiManager) {
4813212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent                            if (mHdmiPlaybackClient != null) {
4814212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent                                mHdmiCecSink = false;
4815212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent                                mHdmiPlaybackClient.queryDisplayStatus(mHdmiDisplayStatusCallback);
4816212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent                            }
4817212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent                        }
4818212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent                    }
4819212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent                }
4820212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent            } else {
4821212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent                if (isPlatformTelevision() && ((device & AudioSystem.DEVICE_OUT_HDMI) != 0)) {
4822212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent                    if (mHdmiManager != null) {
4823212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent                        synchronized (mHdmiManager) {
4824212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent                            mHdmiCecSink = false;
4825212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent                        }
4826212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent                    }
4827212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent                }
4828b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent            }
4829ae4506e9b5fc3e0c6d9862fbc05b9af7d6742a6eEric Laurent            if (!isUsb && (device != AudioSystem.DEVICE_IN_WIRED_HEADSET)) {
4830db45484e4b5858d14da93d3a06311b93bf0cf320Mike Lockwood                sendDeviceConnectionIntent(device, state, name);
4831db45484e4b5858d14da93d3a06311b93bf0cf320Mike Lockwood            }
4832b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent        }
4833b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent    }
4834b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent
483537d7804627eecaf04e170793c2f5703d5d6d44e8Jean-Michel Trivi    private void configureHdmiPlugIntent(Intent intent, int state) {
4836c5258433dd353769ccfa2e5e769a7379378a3a0bJean-Michel Trivi        intent.setAction(AudioManager.ACTION_HDMI_AUDIO_PLUG);
4837c5258433dd353769ccfa2e5e769a7379378a3a0bJean-Michel Trivi        intent.putExtra(AudioManager.EXTRA_AUDIO_PLUG_STATE, state);
483837d7804627eecaf04e170793c2f5703d5d6d44e8Jean-Michel Trivi        if (state == 1) {
483937d7804627eecaf04e170793c2f5703d5d6d44e8Jean-Michel Trivi            ArrayList<AudioPort> ports = new ArrayList<AudioPort>();
484037d7804627eecaf04e170793c2f5703d5d6d44e8Jean-Michel Trivi            int[] portGeneration = new int[1];
484137d7804627eecaf04e170793c2f5703d5d6d44e8Jean-Michel Trivi            int status = AudioSystem.listAudioPorts(ports, portGeneration);
484237d7804627eecaf04e170793c2f5703d5d6d44e8Jean-Michel Trivi            if (status == AudioManager.SUCCESS) {
484337d7804627eecaf04e170793c2f5703d5d6d44e8Jean-Michel Trivi                for (AudioPort port : ports) {
484437d7804627eecaf04e170793c2f5703d5d6d44e8Jean-Michel Trivi                    if (port instanceof AudioDevicePort) {
484537d7804627eecaf04e170793c2f5703d5d6d44e8Jean-Michel Trivi                        final AudioDevicePort devicePort = (AudioDevicePort) port;
48466fa4245589c93025d91aab7dc6681babdd91ee41Eric Laurent                        if (devicePort.type() == AudioManager.DEVICE_OUT_HDMI ||
48476fa4245589c93025d91aab7dc6681babdd91ee41Eric Laurent                                devicePort.type() == AudioManager.DEVICE_OUT_HDMI_ARC) {
484837d7804627eecaf04e170793c2f5703d5d6d44e8Jean-Michel Trivi                            // format the list of supported encodings
484937d7804627eecaf04e170793c2f5703d5d6d44e8Jean-Michel Trivi                            int[] formats = devicePort.formats();
485037d7804627eecaf04e170793c2f5703d5d6d44e8Jean-Michel Trivi                            if (formats.length > 0) {
485137d7804627eecaf04e170793c2f5703d5d6d44e8Jean-Michel Trivi                                ArrayList<Integer> encodingList = new ArrayList(1);
485237d7804627eecaf04e170793c2f5703d5d6d44e8Jean-Michel Trivi                                for (int format : formats) {
485337d7804627eecaf04e170793c2f5703d5d6d44e8Jean-Michel Trivi                                    // a format in the list can be 0, skip it
485437d7804627eecaf04e170793c2f5703d5d6d44e8Jean-Michel Trivi                                    if (format != AudioFormat.ENCODING_INVALID) {
485537d7804627eecaf04e170793c2f5703d5d6d44e8Jean-Michel Trivi                                        encodingList.add(format);
485637d7804627eecaf04e170793c2f5703d5d6d44e8Jean-Michel Trivi                                    }
485737d7804627eecaf04e170793c2f5703d5d6d44e8Jean-Michel Trivi                                }
485837d7804627eecaf04e170793c2f5703d5d6d44e8Jean-Michel Trivi                                int[] encodingArray = new int[encodingList.size()];
485937d7804627eecaf04e170793c2f5703d5d6d44e8Jean-Michel Trivi                                for (int i = 0 ; i < encodingArray.length ; i++) {
486037d7804627eecaf04e170793c2f5703d5d6d44e8Jean-Michel Trivi                                    encodingArray[i] = encodingList.get(i);
486137d7804627eecaf04e170793c2f5703d5d6d44e8Jean-Michel Trivi                                }
4862c5258433dd353769ccfa2e5e769a7379378a3a0bJean-Michel Trivi                                intent.putExtra(AudioManager.EXTRA_ENCODINGS, encodingArray);
486337d7804627eecaf04e170793c2f5703d5d6d44e8Jean-Michel Trivi                            }
486437d7804627eecaf04e170793c2f5703d5d6d44e8Jean-Michel Trivi                            // find the maximum supported number of channels
486537d7804627eecaf04e170793c2f5703d5d6d44e8Jean-Michel Trivi                            int maxChannels = 0;
486637d7804627eecaf04e170793c2f5703d5d6d44e8Jean-Michel Trivi                            for (int mask : devicePort.channelMasks()) {
486737d7804627eecaf04e170793c2f5703d5d6d44e8Jean-Michel Trivi                                int channelCount = AudioFormat.channelCountFromOutChannelMask(mask);
486837d7804627eecaf04e170793c2f5703d5d6d44e8Jean-Michel Trivi                                if (channelCount > maxChannels) {
486937d7804627eecaf04e170793c2f5703d5d6d44e8Jean-Michel Trivi                                    maxChannels = channelCount;
487037d7804627eecaf04e170793c2f5703d5d6d44e8Jean-Michel Trivi                                }
487137d7804627eecaf04e170793c2f5703d5d6d44e8Jean-Michel Trivi                            }
4872c5258433dd353769ccfa2e5e769a7379378a3a0bJean-Michel Trivi                            intent.putExtra(AudioManager.EXTRA_MAX_CHANNEL_COUNT, maxChannels);
487337d7804627eecaf04e170793c2f5703d5d6d44e8Jean-Michel Trivi                        }
487437d7804627eecaf04e170793c2f5703d5d6d44e8Jean-Michel Trivi                    }
487537d7804627eecaf04e170793c2f5703d5d6d44e8Jean-Michel Trivi                }
487637d7804627eecaf04e170793c2f5703d5d6d44e8Jean-Michel Trivi            }
487737d7804627eecaf04e170793c2f5703d5d6d44e8Jean-Michel Trivi        }
487837d7804627eecaf04e170793c2f5703d5d6d44e8Jean-Michel Trivi    }
487937d7804627eecaf04e170793c2f5703d5d6d44e8Jean-Michel Trivi
4880a847ba4080675d395de725cfac5dfd9d5a993d4eJean-Michel Trivi    /* cache of the address of the last dock the device was connected to */
4881a847ba4080675d395de725cfac5dfd9d5a993d4eJean-Michel Trivi    private String mDockAddress;
4882a847ba4080675d395de725cfac5dfd9d5a993d4eJean-Michel Trivi
4883a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent    /**
4884a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent     * Receiver for misc intent broadcasts the Phone app cares about.
4885a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent     */
4886a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent    private class AudioServiceBroadcastReceiver extends BroadcastReceiver {
4887a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent        @Override
4888a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent        public void onReceive(Context context, Intent intent) {
4889a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent            String action = intent.getAction();
4890ae4506e9b5fc3e0c6d9862fbc05b9af7d6742a6eEric Laurent            int outDevice;
4891ae4506e9b5fc3e0c6d9862fbc05b9af7d6742a6eEric Laurent            int inDevice;
489259f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent            int state;
4893a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent
4894758559e6b7e310cf46cc269437f44decd58d68d6Jean-Michel Trivi            if (action.equals(Intent.ACTION_DOCK_EVENT)) {
4895758559e6b7e310cf46cc269437f44decd58d68d6Jean-Michel Trivi                int dockState = intent.getIntExtra(Intent.EXTRA_DOCK_STATE,
4896758559e6b7e310cf46cc269437f44decd58d68d6Jean-Michel Trivi                        Intent.EXTRA_DOCK_STATE_UNDOCKED);
4897758559e6b7e310cf46cc269437f44decd58d68d6Jean-Michel Trivi                int config;
4898758559e6b7e310cf46cc269437f44decd58d68d6Jean-Michel Trivi                switch (dockState) {
4899758559e6b7e310cf46cc269437f44decd58d68d6Jean-Michel Trivi                    case Intent.EXTRA_DOCK_STATE_DESK:
4900758559e6b7e310cf46cc269437f44decd58d68d6Jean-Michel Trivi                        config = AudioSystem.FORCE_BT_DESK_DOCK;
4901758559e6b7e310cf46cc269437f44decd58d68d6Jean-Michel Trivi                        break;
4902758559e6b7e310cf46cc269437f44decd58d68d6Jean-Michel Trivi                    case Intent.EXTRA_DOCK_STATE_CAR:
4903758559e6b7e310cf46cc269437f44decd58d68d6Jean-Michel Trivi                        config = AudioSystem.FORCE_BT_CAR_DOCK;
4904758559e6b7e310cf46cc269437f44decd58d68d6Jean-Michel Trivi                        break;
490521e941bf43362ddc6639a9f2d0828053360f53d7Praveen Bharathi                    case Intent.EXTRA_DOCK_STATE_LE_DESK:
490608ed1b9d2099ec8231b21353b33b901492ea9885Eric Laurent                        config = AudioSystem.FORCE_ANALOG_DOCK;
490721e941bf43362ddc6639a9f2d0828053360f53d7Praveen Bharathi                        break;
490821e941bf43362ddc6639a9f2d0828053360f53d7Praveen Bharathi                    case Intent.EXTRA_DOCK_STATE_HE_DESK:
490921e941bf43362ddc6639a9f2d0828053360f53d7Praveen Bharathi                        config = AudioSystem.FORCE_DIGITAL_DOCK;
491021e941bf43362ddc6639a9f2d0828053360f53d7Praveen Bharathi                        break;
4911758559e6b7e310cf46cc269437f44decd58d68d6Jean-Michel Trivi                    case Intent.EXTRA_DOCK_STATE_UNDOCKED:
4912758559e6b7e310cf46cc269437f44decd58d68d6Jean-Michel Trivi                    default:
4913758559e6b7e310cf46cc269437f44decd58d68d6Jean-Michel Trivi                        config = AudioSystem.FORCE_NONE;
4914758559e6b7e310cf46cc269437f44decd58d68d6Jean-Michel Trivi                }
491508ed1b9d2099ec8231b21353b33b901492ea9885Eric Laurent                // Low end docks have a menu to enable or disable audio
491608ed1b9d2099ec8231b21353b33b901492ea9885Eric Laurent                // (see mDockAudioMediaEnabled)
491708ed1b9d2099ec8231b21353b33b901492ea9885Eric Laurent                if (!((dockState == Intent.EXTRA_DOCK_STATE_LE_DESK) ||
491808ed1b9d2099ec8231b21353b33b901492ea9885Eric Laurent                      ((dockState == Intent.EXTRA_DOCK_STATE_UNDOCKED) &&
491908ed1b9d2099ec8231b21353b33b901492ea9885Eric Laurent                       (mDockState == Intent.EXTRA_DOCK_STATE_LE_DESK)))) {
492008ed1b9d2099ec8231b21353b33b901492ea9885Eric Laurent                    AudioSystem.setForceUse(AudioSystem.FOR_DOCK, config);
492108ed1b9d2099ec8231b21353b33b901492ea9885Eric Laurent                }
492208ed1b9d2099ec8231b21353b33b901492ea9885Eric Laurent                mDockState = dockState;
492382aa7f017daaaeb96c13e6e3491d5037ab471085Jaikumar Ganesh            } else if (action.equals(BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED)) {
492459f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent                state = intent.getIntExtra(BluetoothProfile.EXTRA_STATE,
492582aa7f017daaaeb96c13e6e3491d5037ab471085Jaikumar Ganesh                                               BluetoothProfile.STATE_DISCONNECTED);
4926ae4506e9b5fc3e0c6d9862fbc05b9af7d6742a6eEric Laurent                outDevice = AudioSystem.DEVICE_OUT_BLUETOOTH_SCO;
4927ae4506e9b5fc3e0c6d9862fbc05b9af7d6742a6eEric Laurent                inDevice = AudioSystem.DEVICE_IN_BLUETOOTH_SCO_HEADSET;
4928a56d1c72190462aa9e377906583eceb58e0efcddNick Pelly                String address = null;
4929dca56b9432e2cc851d1a58920071fed2e1e3d142Eric Laurent
4930dca56b9432e2cc851d1a58920071fed2e1e3d142Eric Laurent                BluetoothDevice btDevice = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
4931dca56b9432e2cc851d1a58920071fed2e1e3d142Eric Laurent                if (btDevice == null) {
4932dca56b9432e2cc851d1a58920071fed2e1e3d142Eric Laurent                    return;
4933dca56b9432e2cc851d1a58920071fed2e1e3d142Eric Laurent                }
4934dca56b9432e2cc851d1a58920071fed2e1e3d142Eric Laurent
4935dca56b9432e2cc851d1a58920071fed2e1e3d142Eric Laurent                address = btDevice.getAddress();
4936dca56b9432e2cc851d1a58920071fed2e1e3d142Eric Laurent                BluetoothClass btClass = btDevice.getBluetoothClass();
4937dca56b9432e2cc851d1a58920071fed2e1e3d142Eric Laurent                if (btClass != null) {
4938dca56b9432e2cc851d1a58920071fed2e1e3d142Eric Laurent                    switch (btClass.getDeviceClass()) {
4939dca56b9432e2cc851d1a58920071fed2e1e3d142Eric Laurent                    case BluetoothClass.Device.AUDIO_VIDEO_WEARABLE_HEADSET:
4940dca56b9432e2cc851d1a58920071fed2e1e3d142Eric Laurent                    case BluetoothClass.Device.AUDIO_VIDEO_HANDSFREE:
4941ae4506e9b5fc3e0c6d9862fbc05b9af7d6742a6eEric Laurent                        outDevice = AudioSystem.DEVICE_OUT_BLUETOOTH_SCO_HEADSET;
4942dca56b9432e2cc851d1a58920071fed2e1e3d142Eric Laurent                        break;
4943dca56b9432e2cc851d1a58920071fed2e1e3d142Eric Laurent                    case BluetoothClass.Device.AUDIO_VIDEO_CAR_AUDIO:
4944ae4506e9b5fc3e0c6d9862fbc05b9af7d6742a6eEric Laurent                        outDevice = AudioSystem.DEVICE_OUT_BLUETOOTH_SCO_CARKIT;
4945dca56b9432e2cc851d1a58920071fed2e1e3d142Eric Laurent                        break;
4946d5603c126acdd94d9f7400bb1d04188020a425b4Eric Laurent                    }
4947d5603c126acdd94d9f7400bb1d04188020a425b4Eric Laurent                }
4948d5603c126acdd94d9f7400bb1d04188020a425b4Eric Laurent
4949dca56b9432e2cc851d1a58920071fed2e1e3d142Eric Laurent                if (!BluetoothAdapter.checkBluetoothAddress(address)) {
4950dca56b9432e2cc851d1a58920071fed2e1e3d142Eric Laurent                    address = "";
4951dca56b9432e2cc851d1a58920071fed2e1e3d142Eric Laurent                }
4952d5603c126acdd94d9f7400bb1d04188020a425b4Eric Laurent
495359f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent                boolean connected = (state == BluetoothProfile.STATE_CONNECTED);
4954ae4506e9b5fc3e0c6d9862fbc05b9af7d6742a6eEric Laurent                boolean success = handleDeviceConnection(connected, outDevice, address) &&
4955ae4506e9b5fc3e0c6d9862fbc05b9af7d6742a6eEric Laurent                                      handleDeviceConnection(connected, inDevice, address);
4956ae4506e9b5fc3e0c6d9862fbc05b9af7d6742a6eEric Laurent                if (success) {
49576bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                    synchronized (mScoClients) {
495859f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent                        if (connected) {
495959f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent                            mBluetoothHeadsetDevice = btDevice;
496059f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent                        } else {
49616bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                            mBluetoothHeadsetDevice = null;
49626bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                            resetBluetoothSco();
49636bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                        }
496462ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent                    }
4965a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent                }
4966c5258433dd353769ccfa2e5e769a7379378a3a0bJean-Michel Trivi            } else if (action.equals(AudioManager.ACTION_USB_AUDIO_ACCESSORY_PLUG)) {
4967df3614693dd4fe52a116dcd28bd74eae80818a4fPaul McLean                state = intent.getIntExtra("state", 0);
4968df3614693dd4fe52a116dcd28bd74eae80818a4fPaul McLean
4969df3614693dd4fe52a116dcd28bd74eae80818a4fPaul McLean                int alsaCard = intent.getIntExtra("card", -1);
4970df3614693dd4fe52a116dcd28bd74eae80818a4fPaul McLean                int alsaDevice = intent.getIntExtra("device", -1);
4971df3614693dd4fe52a116dcd28bd74eae80818a4fPaul McLean
4972df3614693dd4fe52a116dcd28bd74eae80818a4fPaul McLean                String params = (alsaCard == -1 && alsaDevice == -1 ? ""
4973df3614693dd4fe52a116dcd28bd74eae80818a4fPaul McLean                                    : "card=" + alsaCard + ";device=" + alsaDevice);
4974df3614693dd4fe52a116dcd28bd74eae80818a4fPaul McLean
4975df3614693dd4fe52a116dcd28bd74eae80818a4fPaul McLean                // Playback Device
4976ae4506e9b5fc3e0c6d9862fbc05b9af7d6742a6eEric Laurent                outDevice = AudioSystem.DEVICE_OUT_USB_ACCESSORY;
4977ae4506e9b5fc3e0c6d9862fbc05b9af7d6742a6eEric Laurent                setWiredDeviceConnectionState(outDevice, state, params);
4978c5258433dd353769ccfa2e5e769a7379378a3a0bJean-Michel Trivi            } else if (action.equals(AudioManager.ACTION_USB_AUDIO_DEVICE_PLUG)) {
49795f5163548424ed3a4d7ea259848f82fb74aaf75dGlenn Kasten                // FIXME Does not yet handle the case where the setting is changed
49805f5163548424ed3a4d7ea259848f82fb74aaf75dGlenn Kasten                // after device connection.  Ideally we should handle the settings change
49815f5163548424ed3a4d7ea259848f82fb74aaf75dGlenn Kasten                // in SettingsObserver. Here we should log that a USB device is connected
49825f5163548424ed3a4d7ea259848f82fb74aaf75dGlenn Kasten                // and disconnected with its address (card , device) and force the
49835f5163548424ed3a4d7ea259848f82fb74aaf75dGlenn Kasten                // connection or disconnection when the setting changes.
498434cc4db180c20569e62db5860c0b206be65b5117Glenn Kasten                int isDisabled = Settings.Secure.getInt(mContentResolver,
498534cc4db180c20569e62db5860c0b206be65b5117Glenn Kasten                        Settings.Secure.USB_AUDIO_AUTOMATIC_ROUTING_DISABLED, 0);
49865f5163548424ed3a4d7ea259848f82fb74aaf75dGlenn Kasten                if (isDisabled != 0) {
49875f5163548424ed3a4d7ea259848f82fb74aaf75dGlenn Kasten                    return;
49885f5163548424ed3a4d7ea259848f82fb74aaf75dGlenn Kasten                }
49895f5163548424ed3a4d7ea259848f82fb74aaf75dGlenn Kasten
499059f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent                state = intent.getIntExtra("state", 0);
4991c837a451946b64d70ed7c642fbde03c182c28b6fPaul McLean
499259f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent                int alsaCard = intent.getIntExtra("card", -1);
499359f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent                int alsaDevice = intent.getIntExtra("device", -1);
4994c837a451946b64d70ed7c642fbde03c182c28b6fPaul McLean                boolean hasPlayback = intent.getBooleanExtra("hasPlayback", false);
4995c837a451946b64d70ed7c642fbde03c182c28b6fPaul McLean                boolean hasCapture = intent.getBooleanExtra("hasCapture", false);
4996c837a451946b64d70ed7c642fbde03c182c28b6fPaul McLean                boolean hasMIDI = intent.getBooleanExtra("hasMIDI", false);
4997c837a451946b64d70ed7c642fbde03c182c28b6fPaul McLean
49989841818b9a0280abf59343c9e00a2976dbc084faMike Lockwood                String params = (alsaCard == -1 && alsaDevice == -1 ? ""
49999841818b9a0280abf59343c9e00a2976dbc084faMike Lockwood                                    : "card=" + alsaCard + ";device=" + alsaDevice);
5000c837a451946b64d70ed7c642fbde03c182c28b6fPaul McLean
5001c837a451946b64d70ed7c642fbde03c182c28b6fPaul McLean                // Playback Device
5002df3614693dd4fe52a116dcd28bd74eae80818a4fPaul McLean                if (hasPlayback) {
5003ae4506e9b5fc3e0c6d9862fbc05b9af7d6742a6eEric Laurent                    outDevice = AudioSystem.DEVICE_OUT_USB_DEVICE;
5004ae4506e9b5fc3e0c6d9862fbc05b9af7d6742a6eEric Laurent                    setWiredDeviceConnectionState(outDevice, state, params);
5005df3614693dd4fe52a116dcd28bd74eae80818a4fPaul McLean                }
5006c837a451946b64d70ed7c642fbde03c182c28b6fPaul McLean
5007c837a451946b64d70ed7c642fbde03c182c28b6fPaul McLean                // Capture Device
5008df3614693dd4fe52a116dcd28bd74eae80818a4fPaul McLean                if (hasCapture) {
5009ae4506e9b5fc3e0c6d9862fbc05b9af7d6742a6eEric Laurent                    inDevice = AudioSystem.DEVICE_IN_USB_DEVICE;
5010ae4506e9b5fc3e0c6d9862fbc05b9af7d6742a6eEric Laurent                    setWiredDeviceConnectionState(inDevice, state, params);
5011df3614693dd4fe52a116dcd28bd74eae80818a4fPaul McLean                }
5012df3614693dd4fe52a116dcd28bd74eae80818a4fPaul McLean            } else if (action.equals(BluetoothHeadset.ACTION_AUDIO_STATE_CHANGED)) {
501362ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent                boolean broadcast = false;
501459f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent                int scoAudioState = AudioManager.SCO_AUDIO_STATE_ERROR;
50153def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                synchronized (mScoClients) {
501662ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent                    int btState = intent.getIntExtra(BluetoothProfile.EXTRA_STATE, -1);
5017dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                    // broadcast intent if the connection was initated by AudioService
5018dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                    if (!mScoClients.isEmpty() &&
5019dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                            (mScoAudioState == SCO_STATE_ACTIVE_INTERNAL ||
5020dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                             mScoAudioState == SCO_STATE_ACTIVATE_REQ ||
5021dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                             mScoAudioState == SCO_STATE_DEACTIVATE_REQ)) {
502262ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent                        broadcast = true;
502362ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent                    }
502462ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent                    switch (btState) {
502562ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent                    case BluetoothHeadset.STATE_AUDIO_CONNECTED:
502659f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent                        scoAudioState = AudioManager.SCO_AUDIO_STATE_CONNECTED;
5027dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                        if (mScoAudioState != SCO_STATE_ACTIVE_INTERNAL &&
5028dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                            mScoAudioState != SCO_STATE_DEACTIVATE_REQ &&
5029dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                            mScoAudioState != SCO_STATE_DEACTIVATE_EXT_REQ) {
503062ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent                            mScoAudioState = SCO_STATE_ACTIVE_EXTERNAL;
50313def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                        }
503262ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent                        break;
503362ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent                    case BluetoothHeadset.STATE_AUDIO_DISCONNECTED:
503459f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent                        scoAudioState = AudioManager.SCO_AUDIO_STATE_DISCONNECTED;
503562ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent                        mScoAudioState = SCO_STATE_INACTIVE;
5036d7454be47f4111c0478a502353e11dea401378bdEric Laurent                        clearAllScoClients(0, false);
503762ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent                        break;
503862ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent                    case BluetoothHeadset.STATE_AUDIO_CONNECTING:
5039dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                        if (mScoAudioState != SCO_STATE_ACTIVE_INTERNAL &&
5040dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                            mScoAudioState != SCO_STATE_DEACTIVATE_REQ &&
5041dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                            mScoAudioState != SCO_STATE_DEACTIVATE_EXT_REQ) {
504262ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent                            mScoAudioState = SCO_STATE_ACTIVE_EXTERNAL;
50433def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                        }
504462ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent                    default:
504562ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent                        // do not broadcast CONNECTING or invalid state
504662ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent                        broadcast = false;
504762ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent                        break;
50483def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                    }
50493def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                }
505062ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent                if (broadcast) {
505159f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent                    broadcastScoConnectionState(scoAudioState);
5052dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                    //FIXME: this is to maintain compatibility with deprecated intent
5053dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                    // AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED. Remove when appropriate.
505462ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent                    Intent newIntent = new Intent(AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED);
505559f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent                    newIntent.putExtra(AudioManager.EXTRA_SCO_AUDIO_STATE, scoAudioState);
50565ac72a29593ab9a20337a2225df52bdf4754be02Dianne Hackborn                    sendStickyBroadcastToAll(newIntent);
505762ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent                }
5058950e8cb40a6d826af4cc2eef9d3908c1b70486e6Eric Laurent            } else if (action.equals(Intent.ACTION_SCREEN_ON)) {
5059318f0fe43bdc4b2f6764edd91d6b78d9875ffdebJon Eklund                if (mMonitorRotation) {
5060318f0fe43bdc4b2f6764edd91d6b78d9875ffdebJon Eklund                    mOrientationListener.onOrientationChanged(0); //argument is ignored anyway
5061318f0fe43bdc4b2f6764edd91d6b78d9875ffdebJon Eklund                    mOrientationListener.enable();
5062318f0fe43bdc4b2f6764edd91d6b78d9875ffdebJon Eklund                }
5063950e8cb40a6d826af4cc2eef9d3908c1b70486e6Eric Laurent                AudioSystem.setParameters("screen_state=on");
5064950e8cb40a6d826af4cc2eef9d3908c1b70486e6Eric Laurent            } else if (action.equals(Intent.ACTION_SCREEN_OFF)) {
5065318f0fe43bdc4b2f6764edd91d6b78d9875ffdebJon Eklund                if (mMonitorRotation) {
5066318f0fe43bdc4b2f6764edd91d6b78d9875ffdebJon Eklund                    //reduce wakeups (save current) by only listening when display is on
5067318f0fe43bdc4b2f6764edd91d6b78d9875ffdebJon Eklund                    mOrientationListener.disable();
5068318f0fe43bdc4b2f6764edd91d6b78d9875ffdebJon Eklund                }
5069950e8cb40a6d826af4cc2eef9d3908c1b70486e6Eric Laurent                AudioSystem.setParameters("screen_state=off");
5070961cae92540763226648813d111c5b5c3b0f1597Dianne Hackborn            } else if (action.equals(Intent.ACTION_CONFIGURATION_CHANGED)) {
5071f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi                handleConfigurationChanged(context);
5072bc0fab1fc2db832ef86d8a33466ec4d68b103ca0Eric Laurent            } else if (action.equals(Intent.ACTION_USER_SWITCHED)) {
5073f4a8eb22112c534f436357b50f231778c5c15c25Jean-Michel Trivi                // attempt to stop music playback for background user
50745bfaeaef3fc348d66f48b86be08655e91dff910aEric Laurent                sendMsg(mAudioHandler,
50755bfaeaef3fc348d66f48b86be08655e91dff910aEric Laurent                        MSG_BROADCAST_AUDIO_BECOMING_NOISY,
50765bfaeaef3fc348d66f48b86be08655e91dff910aEric Laurent                        SENDMSG_REPLACE,
50775bfaeaef3fc348d66f48b86be08655e91dff910aEric Laurent                        0,
50785bfaeaef3fc348d66f48b86be08655e91dff910aEric Laurent                        0,
50795bfaeaef3fc348d66f48b86be08655e91dff910aEric Laurent                        null,
50805bfaeaef3fc348d66f48b86be08655e91dff910aEric Laurent                        0);
5081f4a8eb22112c534f436357b50f231778c5c15c25Jean-Michel Trivi                // the current audio focus owner is no longer valid
5082fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi                mMediaFocusControl.discardAudioFocusOwner();
5083f4a8eb22112c534f436357b50f231778c5c15c25Jean-Michel Trivi
50845bfaeaef3fc348d66f48b86be08655e91dff910aEric Laurent                // load volume settings for new user
5085bc0fab1fc2db832ef86d8a33466ec4d68b103ca0Eric Laurent                readAudioSettings(true /*userSwitch*/);
5086bc0fab1fc2db832ef86d8a33466ec4d68b103ca0Eric Laurent                // preserve STREAM_MUSIC volume from one user to the next.
5087bc0fab1fc2db832ef86d8a33466ec4d68b103ca0Eric Laurent                sendMsg(mAudioHandler,
5088bc0fab1fc2db832ef86d8a33466ec4d68b103ca0Eric Laurent                        MSG_SET_ALL_VOLUMES,
5089bc0fab1fc2db832ef86d8a33466ec4d68b103ca0Eric Laurent                        SENDMSG_QUEUE,
5090bc0fab1fc2db832ef86d8a33466ec4d68b103ca0Eric Laurent                        0,
5091bc0fab1fc2db832ef86d8a33466ec4d68b103ca0Eric Laurent                        0,
5092bc0fab1fc2db832ef86d8a33466ec4d68b103ca0Eric Laurent                        mStreamStates[AudioSystem.STREAM_MUSIC], 0);
5093a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent            }
5094a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent        }
5095c837a451946b64d70ed7c642fbde03c182c28b6fPaul McLean    } // end class AudioServiceBroadcastReceiver
5096d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi
5097d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi    //==========================================================================================
5098fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    // RemoteControlDisplay / RemoteControlClient / Remote info
5099d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi    //==========================================================================================
5100f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi    public boolean registerRemoteController(IRemoteControlDisplay rcd, int w, int h,
5101f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi            ComponentName listenerComp) {
5102f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi        return mMediaFocusControl.registerRemoteController(rcd, w, h, listenerComp);
5103f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi    }
5104f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi
51057ddd226e7c6e759feaf2747a90be1cc06acf37a3Jean-Michel Trivi    public boolean registerRemoteControlDisplay(IRemoteControlDisplay rcd, int w, int h) {
5106f108cdd9ee5efe354d87edd02a07b323298c116cJean-Michel Trivi        return mMediaFocusControl.registerRemoteControlDisplay(rcd, w, h);
5107e5e1e870fdb35f5291790e6d178bde7126f6fe35Jean-Michel Trivi    }
5108e5e1e870fdb35f5291790e6d178bde7126f6fe35Jean-Michel Trivi
5109fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    public void unregisterRemoteControlDisplay(IRemoteControlDisplay rcd) {
5110fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        mMediaFocusControl.unregisterRemoteControlDisplay(rcd);
5111d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi    }
5112d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi
5113fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    public void remoteControlDisplayUsesBitmapSize(IRemoteControlDisplay rcd, int w, int h) {
5114fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        mMediaFocusControl.remoteControlDisplayUsesBitmapSize(rcd, w, h);
5115d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi    }
5116d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi
5117fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    public void remoteControlDisplayWantsPlaybackPositionSync(IRemoteControlDisplay rcd,
5118fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi            boolean wantsSync) {
5119fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        mMediaFocusControl.remoteControlDisplayWantsPlaybackPositionSync(rcd, wantsSync);
5120d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi    }
5121d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi
51223346a802087f621c6441bc512dfcc17b07143fc6John Spurlock    @Override
5123fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    public void setRemoteStreamVolume(int index) {
51243346a802087f621c6441bc512dfcc17b07143fc6John Spurlock        enforceSelfOrSystemUI("set the remote stream volume");
5125fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        mMediaFocusControl.setRemoteStreamVolume(index);
5126d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi    }
5127d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi
5128fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    //==========================================================================================
5129fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    // Audio Focus
5130fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    //==========================================================================================
5131fd6ad747e6c268753d0edf7a5a59b6815b190854Jean-Michel Trivi    public int requestAudioFocus(AudioAttributes aa, int durationHint, IBinder cb,
5132958876fe55ea0fdeb73c72240a2f2bab32833443Jean-Michel Trivi            IAudioFocusDispatcher fd, String clientId, String callingPackageName, int flags,
51330212be5150fb9fb3c340f3c7e51f6126372cc6f9Jean-Michel Trivi            IAudioPolicyCallback pcb) {
5134958876fe55ea0fdeb73c72240a2f2bab32833443Jean-Michel Trivi        // permission checks
5135958876fe55ea0fdeb73c72240a2f2bab32833443Jean-Michel Trivi        if ((flags & AudioManager.AUDIOFOCUS_FLAG_LOCK) == AudioManager.AUDIOFOCUS_FLAG_LOCK) {
5136958876fe55ea0fdeb73c72240a2f2bab32833443Jean-Michel Trivi            if (mMediaFocusControl.IN_VOICE_COMM_FOCUS_ID.equals(clientId)) {
5137958876fe55ea0fdeb73c72240a2f2bab32833443Jean-Michel Trivi                if (PackageManager.PERMISSION_GRANTED != mContext.checkCallingOrSelfPermission(
5138958876fe55ea0fdeb73c72240a2f2bab32833443Jean-Michel Trivi                            android.Manifest.permission.MODIFY_PHONE_STATE)) {
5139958876fe55ea0fdeb73c72240a2f2bab32833443Jean-Michel Trivi                    Log.e(TAG, "Invalid permission to (un)lock audio focus", new Exception());
5140958876fe55ea0fdeb73c72240a2f2bab32833443Jean-Michel Trivi                    return AudioManager.AUDIOFOCUS_REQUEST_FAILED;
5141958876fe55ea0fdeb73c72240a2f2bab32833443Jean-Michel Trivi                }
5142958876fe55ea0fdeb73c72240a2f2bab32833443Jean-Michel Trivi            } else {
5143958876fe55ea0fdeb73c72240a2f2bab32833443Jean-Michel Trivi                // only a registered audio policy can be used to lock focus
5144958876fe55ea0fdeb73c72240a2f2bab32833443Jean-Michel Trivi                synchronized (mAudioPolicies) {
51450212be5150fb9fb3c340f3c7e51f6126372cc6f9Jean-Michel Trivi                    if (!mAudioPolicies.containsKey(pcb.asBinder())) {
51460212be5150fb9fb3c340f3c7e51f6126372cc6f9Jean-Michel Trivi                        Log.e(TAG, "Invalid unregistered AudioPolicy to (un)lock audio focus");
5147958876fe55ea0fdeb73c72240a2f2bab32833443Jean-Michel Trivi                        return AudioManager.AUDIOFOCUS_REQUEST_FAILED;
5148958876fe55ea0fdeb73c72240a2f2bab32833443Jean-Michel Trivi                    }
5149958876fe55ea0fdeb73c72240a2f2bab32833443Jean-Michel Trivi                }
5150958876fe55ea0fdeb73c72240a2f2bab32833443Jean-Michel Trivi            }
5151958876fe55ea0fdeb73c72240a2f2bab32833443Jean-Michel Trivi        }
5152958876fe55ea0fdeb73c72240a2f2bab32833443Jean-Michel Trivi
5153fd6ad747e6c268753d0edf7a5a59b6815b190854Jean-Michel Trivi        return mMediaFocusControl.requestAudioFocus(aa, durationHint, cb, fd,
5154fd6ad747e6c268753d0edf7a5a59b6815b190854Jean-Michel Trivi                clientId, callingPackageName, flags);
51554294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi    }
51564294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi
5157958876fe55ea0fdeb73c72240a2f2bab32833443Jean-Michel Trivi    public int abandonAudioFocus(IAudioFocusDispatcher fd, String clientId, AudioAttributes aa) {
5158958876fe55ea0fdeb73c72240a2f2bab32833443Jean-Michel Trivi        return mMediaFocusControl.abandonAudioFocus(fd, clientId, aa);
5159c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi    }
5160c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi
5161fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi    public void unregisterAudioFocusClient(String clientId) {
5162fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        mMediaFocusControl.unregisterAudioFocusClient(clientId);
51633114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    }
51643114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi
51652380566debfc57eb1cc07db1306ccee23b84ddd4Jean-Michel Trivi    public int getCurrentAudioFocus() {
51662380566debfc57eb1cc07db1306ccee23b84ddd4Jean-Michel Trivi        return mMediaFocusControl.getCurrentAudioFocus();
51672380566debfc57eb1cc07db1306ccee23b84ddd4Jean-Michel Trivi    }
51682380566debfc57eb1cc07db1306ccee23b84ddd4Jean-Michel Trivi
5169f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi    //==========================================================================================
5170f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi    // Device orientation
5171f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi    //==========================================================================================
5172f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi    /**
5173bb6f8711a7f804d39c45218db2d6339940cc5d35Jean-Michel Trivi     * Handles device configuration changes that may map to a change in the orientation
5174bb6f8711a7f804d39c45218db2d6339940cc5d35Jean-Michel Trivi     * or orientation.
5175bb6f8711a7f804d39c45218db2d6339940cc5d35Jean-Michel Trivi     * Monitoring orientation and rotation is optional, and is defined by the definition and value
5176bb6f8711a7f804d39c45218db2d6339940cc5d35Jean-Michel Trivi     * of the "ro.audio.monitorOrientation" and "ro.audio.monitorRotation" system properties.
5177f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi     */
5178f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi    private void handleConfigurationChanged(Context context) {
5179f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi        try {
5180f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi            // reading new orientation "safely" (i.e. under try catch) in case anything
5181f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi            // goes wrong when obtaining resources and configuration
5182d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent            Configuration config = context.getResources().getConfiguration();
5183bb6f8711a7f804d39c45218db2d6339940cc5d35Jean-Michel Trivi            // TODO merge rotation and orientation
5184d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent            if (mMonitorOrientation) {
5185d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent                int newOrientation = config.orientation;
5186d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent                if (newOrientation != mDeviceOrientation) {
5187d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent                    mDeviceOrientation = newOrientation;
5188d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent                    setOrientationForAudioSystem();
5189d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent                }
5190f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi            }
5191d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent            sendMsg(mAudioHandler,
5192d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent                    MSG_CONFIGURE_SAFE_MEDIA_VOLUME,
5193d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent                    SENDMSG_REPLACE,
5194d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent                    0,
5195d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent                    0,
5196d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent                    null,
5197d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent                    0);
5198dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent
5199dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent            boolean cameraSoundForced = mContext.getResources().getBoolean(
5200dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent                    com.android.internal.R.bool.config_camera_sound_forced);
5201dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent            synchronized (mSettingsLock) {
52028fa4d6f585f40ff5cf5f9bed316d92c64a306f21Eric Laurent                boolean cameraSoundForcedChanged = false;
5203dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent                synchronized (mCameraSoundForced) {
5204dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent                    if (cameraSoundForced != mCameraSoundForced) {
5205dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent                        mCameraSoundForced = cameraSoundForced;
52068fa4d6f585f40ff5cf5f9bed316d92c64a306f21Eric Laurent                        cameraSoundForcedChanged = true;
52078fa4d6f585f40ff5cf5f9bed316d92c64a306f21Eric Laurent                    }
52088fa4d6f585f40ff5cf5f9bed316d92c64a306f21Eric Laurent                }
52098fa4d6f585f40ff5cf5f9bed316d92c64a306f21Eric Laurent                if (cameraSoundForcedChanged) {
52108fa4d6f585f40ff5cf5f9bed316d92c64a306f21Eric Laurent                    if (!isPlatformTelevision()) {
52118fa4d6f585f40ff5cf5f9bed316d92c64a306f21Eric Laurent                        VolumeStreamState s = mStreamStates[AudioSystem.STREAM_SYSTEM_ENFORCED];
52128fa4d6f585f40ff5cf5f9bed316d92c64a306f21Eric Laurent                        if (cameraSoundForced) {
52138fa4d6f585f40ff5cf5f9bed316d92c64a306f21Eric Laurent                            s.setAllIndexesToMax();
52148fa4d6f585f40ff5cf5f9bed316d92c64a306f21Eric Laurent                            mRingerModeAffectedStreams &=
52158fa4d6f585f40ff5cf5f9bed316d92c64a306f21Eric Laurent                                    ~(1 << AudioSystem.STREAM_SYSTEM_ENFORCED);
52168fa4d6f585f40ff5cf5f9bed316d92c64a306f21Eric Laurent                        } else {
52178fa4d6f585f40ff5cf5f9bed316d92c64a306f21Eric Laurent                            s.setAllIndexes(mStreamStates[AudioSystem.STREAM_SYSTEM]);
52188fa4d6f585f40ff5cf5f9bed316d92c64a306f21Eric Laurent                            mRingerModeAffectedStreams |=
52198fa4d6f585f40ff5cf5f9bed316d92c64a306f21Eric Laurent                                    (1 << AudioSystem.STREAM_SYSTEM_ENFORCED);
5220dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent                        }
52218fa4d6f585f40ff5cf5f9bed316d92c64a306f21Eric Laurent                        // take new state into account for streams muted by ringer mode
5222661f2cf45860d2e10924e6b69966a9afe255f28bJohn Spurlock                        setRingerModeInt(getRingerModeInternal(), false);
5223dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent                    }
52248fa4d6f585f40ff5cf5f9bed316d92c64a306f21Eric Laurent
52258fa4d6f585f40ff5cf5f9bed316d92c64a306f21Eric Laurent                    sendMsg(mAudioHandler,
52268fa4d6f585f40ff5cf5f9bed316d92c64a306f21Eric Laurent                            MSG_SET_FORCE_USE,
52278fa4d6f585f40ff5cf5f9bed316d92c64a306f21Eric Laurent                            SENDMSG_QUEUE,
52288fa4d6f585f40ff5cf5f9bed316d92c64a306f21Eric Laurent                            AudioSystem.FOR_SYSTEM,
52298fa4d6f585f40ff5cf5f9bed316d92c64a306f21Eric Laurent                            cameraSoundForced ?
52308fa4d6f585f40ff5cf5f9bed316d92c64a306f21Eric Laurent                                    AudioSystem.FORCE_SYSTEM_ENFORCED : AudioSystem.FORCE_NONE,
52318fa4d6f585f40ff5cf5f9bed316d92c64a306f21Eric Laurent                            null,
52328fa4d6f585f40ff5cf5f9bed316d92c64a306f21Eric Laurent                            0);
52338fa4d6f585f40ff5cf5f9bed316d92c64a306f21Eric Laurent
52348fa4d6f585f40ff5cf5f9bed316d92c64a306f21Eric Laurent                    sendMsg(mAudioHandler,
52358fa4d6f585f40ff5cf5f9bed316d92c64a306f21Eric Laurent                            MSG_SET_ALL_VOLUMES,
52368fa4d6f585f40ff5cf5f9bed316d92c64a306f21Eric Laurent                            SENDMSG_QUEUE,
52378fa4d6f585f40ff5cf5f9bed316d92c64a306f21Eric Laurent                            0,
52388fa4d6f585f40ff5cf5f9bed316d92c64a306f21Eric Laurent                            0,
52398fa4d6f585f40ff5cf5f9bed316d92c64a306f21Eric Laurent                            mStreamStates[AudioSystem.STREAM_SYSTEM_ENFORCED], 0);
5240dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent                }
5241dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent            }
52423346a802087f621c6441bc512dfcc17b07143fc6John Spurlock            mVolumeController.setLayoutDirection(config.getLayoutDirection());
5243f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi        } catch (Exception e) {
5244bb6f8711a7f804d39c45218db2d6339940cc5d35Jean-Michel Trivi            Log.e(TAG, "Error handling configuration change: ", e);
5245f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi        }
5246f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi    }
5247f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi
5248f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi    private void setOrientationForAudioSystem() {
5249f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi        switch (mDeviceOrientation) {
5250f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi            case Configuration.ORIENTATION_LANDSCAPE:
5251f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi                //Log.i(TAG, "orientation is landscape");
5252f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi                AudioSystem.setParameters("orientation=landscape");
5253f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi                break;
5254f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi            case Configuration.ORIENTATION_PORTRAIT:
5255f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi                //Log.i(TAG, "orientation is portrait");
5256f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi                AudioSystem.setParameters("orientation=portrait");
5257f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi                break;
5258f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi            case Configuration.ORIENTATION_SQUARE:
5259f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi                //Log.i(TAG, "orientation is square");
5260f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi                AudioSystem.setParameters("orientation=square");
5261f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi                break;
5262f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi            case Configuration.ORIENTATION_UNDEFINED:
5263f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi                //Log.i(TAG, "orientation is undefined");
5264f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi                AudioSystem.setParameters("orientation=undefined");
5265f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi                break;
5266f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi            default:
5267f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi                Log.e(TAG, "Unknown orientation");
5268f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi        }
5269f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi    }
5270f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi
5271bb6f8711a7f804d39c45218db2d6339940cc5d35Jean-Michel Trivi    private void setRotationForAudioSystem() {
5272bb6f8711a7f804d39c45218db2d6339940cc5d35Jean-Michel Trivi        switch (mDeviceRotation) {
5273bb6f8711a7f804d39c45218db2d6339940cc5d35Jean-Michel Trivi            case Surface.ROTATION_0:
5274bb6f8711a7f804d39c45218db2d6339940cc5d35Jean-Michel Trivi                AudioSystem.setParameters("rotation=0");
5275bb6f8711a7f804d39c45218db2d6339940cc5d35Jean-Michel Trivi                break;
5276bb6f8711a7f804d39c45218db2d6339940cc5d35Jean-Michel Trivi            case Surface.ROTATION_90:
5277bb6f8711a7f804d39c45218db2d6339940cc5d35Jean-Michel Trivi                AudioSystem.setParameters("rotation=90");
5278bb6f8711a7f804d39c45218db2d6339940cc5d35Jean-Michel Trivi                break;
5279bb6f8711a7f804d39c45218db2d6339940cc5d35Jean-Michel Trivi            case Surface.ROTATION_180:
5280bb6f8711a7f804d39c45218db2d6339940cc5d35Jean-Michel Trivi                AudioSystem.setParameters("rotation=180");
5281bb6f8711a7f804d39c45218db2d6339940cc5d35Jean-Michel Trivi                break;
5282bb6f8711a7f804d39c45218db2d6339940cc5d35Jean-Michel Trivi            case Surface.ROTATION_270:
5283bb6f8711a7f804d39c45218db2d6339940cc5d35Jean-Michel Trivi                AudioSystem.setParameters("rotation=270");
5284bb6f8711a7f804d39c45218db2d6339940cc5d35Jean-Michel Trivi                break;
5285bb6f8711a7f804d39c45218db2d6339940cc5d35Jean-Michel Trivi            default:
5286bb6f8711a7f804d39c45218db2d6339940cc5d35Jean-Michel Trivi                Log.e(TAG, "Unknown device rotation");
5287bb6f8711a7f804d39c45218db2d6339940cc5d35Jean-Michel Trivi        }
5288bb6f8711a7f804d39c45218db2d6339940cc5d35Jean-Michel Trivi    }
5289bb6f8711a7f804d39c45218db2d6339940cc5d35Jean-Michel Trivi
5290f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi
52917847211fb4699bf6018e29d214a918ed6657319bEric Laurent    // Handles request to override default use of A2DP for media.
52927847211fb4699bf6018e29d214a918ed6657319bEric Laurent    public void setBluetoothA2dpOnInt(boolean on) {
52937847211fb4699bf6018e29d214a918ed6657319bEric Laurent        synchronized (mBluetoothA2dpEnabledLock) {
52947847211fb4699bf6018e29d214a918ed6657319bEric Laurent            mBluetoothA2dpEnabled = on;
5295c390bed06b4a572e273ead1254da9a932e04dce3Eric Laurent            mAudioHandler.removeMessages(MSG_SET_FORCE_BT_A2DP_USE);
5296c390bed06b4a572e273ead1254da9a932e04dce3Eric Laurent            AudioSystem.setForceUse(AudioSystem.FOR_MEDIA,
5297c390bed06b4a572e273ead1254da9a932e04dce3Eric Laurent                    mBluetoothA2dpEnabled ? AudioSystem.FORCE_NONE : AudioSystem.FORCE_NO_BT_A2DP);
52987847211fb4699bf6018e29d214a918ed6657319bEric Laurent        }
52997847211fb4699bf6018e29d214a918ed6657319bEric Laurent    }
53007847211fb4699bf6018e29d214a918ed6657319bEric Laurent
5301d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi    @Override
5302098d580cc2bb6c0891c756a4e5230c6c6b0d2376Jeff Sharkey    public void setRingtonePlayer(IRingtonePlayer player) {
5303098d580cc2bb6c0891c756a4e5230c6c6b0d2376Jeff Sharkey        mContext.enforceCallingOrSelfPermission(REMOTE_AUDIO_PLAYBACK, null);
5304098d580cc2bb6c0891c756a4e5230c6c6b0d2376Jeff Sharkey        mRingtonePlayer = player;
5305098d580cc2bb6c0891c756a4e5230c6c6b0d2376Jeff Sharkey    }
5306098d580cc2bb6c0891c756a4e5230c6c6b0d2376Jeff Sharkey
5307098d580cc2bb6c0891c756a4e5230c6c6b0d2376Jeff Sharkey    @Override
5308098d580cc2bb6c0891c756a4e5230c6c6b0d2376Jeff Sharkey    public IRingtonePlayer getRingtonePlayer() {
5309098d580cc2bb6c0891c756a4e5230c6c6b0d2376Jeff Sharkey        return mRingtonePlayer;
5310098d580cc2bb6c0891c756a4e5230c6c6b0d2376Jeff Sharkey    }
5311098d580cc2bb6c0891c756a4e5230c6c6b0d2376Jeff Sharkey
5312098d580cc2bb6c0891c756a4e5230c6c6b0d2376Jeff Sharkey    @Override
5313632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn    public AudioRoutesInfo startWatchingRoutes(IAudioRoutesObserver observer) {
5314632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn        synchronized (mCurAudioRoutes) {
5315632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn            AudioRoutesInfo routes = new AudioRoutesInfo(mCurAudioRoutes);
5316632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn            mRoutesObservers.register(observer);
5317632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn            return routes;
5318632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn        }
5319632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn    }
5320632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn
5321c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent
5322c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent    //==========================================================================================
5323c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent    // Safe media volume management.
5324c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent    // MUSIC stream volume level is limited when headphones are connected according to safety
5325c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent    // regulation. When the user attempts to raise the volume above the limit, a warning is
5326c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent    // displayed and the user has to acknowlegde before the volume is actually changed.
5327c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent    // The volume index corresponding to the limit is stored in config_safe_media_volume_index
5328c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent    // property. Platforms with a different limit must set this property accordingly in their
5329c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent    // overlay.
5330c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent    //==========================================================================================
5331c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent
5332d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent    // mSafeMediaVolumeState indicates whether the media volume is limited over headphones.
5333d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent    // It is SAFE_MEDIA_VOLUME_NOT_CONFIGURED at boot time until a network service is connected
5334d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent    // or the configure time is elapsed. It is then set to SAFE_MEDIA_VOLUME_ACTIVE or
5335d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent    // SAFE_MEDIA_VOLUME_DISABLED according to country option. If not SAFE_MEDIA_VOLUME_DISABLED, it
5336d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent    // can be set to SAFE_MEDIA_VOLUME_INACTIVE by calling AudioService.disableSafeMediaVolume()
5337d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent    // (when user opts out).
5338351346092acdfbfcc1d9ebf98d539d2a1196c5e8John Spurlock    private static final int SAFE_MEDIA_VOLUME_NOT_CONFIGURED = 0;
5339351346092acdfbfcc1d9ebf98d539d2a1196c5e8John Spurlock    private static final int SAFE_MEDIA_VOLUME_DISABLED = 1;
5340351346092acdfbfcc1d9ebf98d539d2a1196c5e8John Spurlock    private static final int SAFE_MEDIA_VOLUME_INACTIVE = 2;  // confirmed
5341351346092acdfbfcc1d9ebf98d539d2a1196c5e8John Spurlock    private static final int SAFE_MEDIA_VOLUME_ACTIVE = 3;  // unconfirmed
5342d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent    private Integer mSafeMediaVolumeState;
5343d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent
5344d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent    private int mMcc = 0;
5345c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent    // mSafeMediaVolumeIndex is the cached value of config_safe_media_volume_index property
5346d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent    private int mSafeMediaVolumeIndex;
5347c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent    // mSafeMediaVolumeDevices lists the devices for which safe media volume is enforced,
5348c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent    private final int mSafeMediaVolumeDevices = AudioSystem.DEVICE_OUT_WIRED_HEADSET |
5349c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent                                                AudioSystem.DEVICE_OUT_WIRED_HEADPHONE;
5350c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent    // mMusicActiveMs is the cumulative time of music activity since safe volume was disabled.
5351c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent    // When this time reaches UNSAFE_VOLUME_MUSIC_ACTIVE_MS_MAX, the safe media volume is re-enabled
5352c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent    // automatically. mMusicActiveMs is rounded to a multiple of MUSIC_ACTIVE_POLL_PERIOD_MS.
5353c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent    private int mMusicActiveMs;
5354c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent    private static final int UNSAFE_VOLUME_MUSIC_ACTIVE_MS_MAX = (20 * 3600 * 1000); // 20 hours
5355c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent    private static final int MUSIC_ACTIVE_POLL_PERIOD_MS = 60000;  // 1 minute polling interval
5356d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent    private static final int SAFE_VOLUME_CONFIGURE_TIMEOUT_MS = 30000;  // 30s after boot completed
5357c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent
5358c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent    private void setSafeMediaVolumeEnabled(boolean on) {
5359d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent        synchronized (mSafeMediaVolumeState) {
5360d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent            if ((mSafeMediaVolumeState != SAFE_MEDIA_VOLUME_NOT_CONFIGURED) &&
5361d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent                    (mSafeMediaVolumeState != SAFE_MEDIA_VOLUME_DISABLED)) {
5362d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent                if (on && (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_INACTIVE)) {
5363d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent                    mSafeMediaVolumeState = SAFE_MEDIA_VOLUME_ACTIVE;
5364d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent                    enforceSafeMediaVolume();
5365d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent                } else if (!on && (mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_ACTIVE)) {
5366d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent                    mSafeMediaVolumeState = SAFE_MEDIA_VOLUME_INACTIVE;
5367aa5ee4d65f8788e2a0afcd198367450853fd72acJohn Spurlock                    mMusicActiveMs = 1;  // nonzero = confirmed
5368aa5ee4d65f8788e2a0afcd198367450853fd72acJohn Spurlock                    saveMusicActiveMs();
5369d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent                    sendMsg(mAudioHandler,
5370d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent                            MSG_CHECK_MUSIC_ACTIVE,
5371d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent                            SENDMSG_REPLACE,
5372d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent                            0,
5373d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent                            0,
5374d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent                            null,
5375d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent                            MUSIC_ACTIVE_POLL_PERIOD_MS);
5376d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent                }
5377c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent            }
5378c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent        }
5379c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent    }
5380c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent
5381c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent    private void enforceSafeMediaVolume() {
5382c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent        VolumeStreamState streamState = mStreamStates[AudioSystem.STREAM_MUSIC];
5383c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent        int devices = mSafeMediaVolumeDevices;
5384c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent        int i = 0;
5385c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent
5386c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent        while (devices != 0) {
5387c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent            int device = 1 << i++;
5388c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent            if ((device & devices) == 0) {
5389c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent                continue;
5390c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent            }
539142b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent            int index = streamState.getIndex(device);
5392c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent            if (index > mSafeMediaVolumeIndex) {
539342b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                streamState.setIndex(mSafeMediaVolumeIndex, device);
539442b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                sendMsg(mAudioHandler,
539542b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                        MSG_SET_DEVICE_VOLUME,
539642b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                        SENDMSG_QUEUE,
539742b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                        device,
539842b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                        0,
539942b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                        streamState,
540042b041ed4f184e3af7f788eb07307f556a2a6616Eric Laurent                        0);
5401c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent            }
5402c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent            devices &= ~device;
5403c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent        }
5404c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent    }
5405c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent
5406c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent    private boolean checkSafeMediaVolume(int streamType, int index, int device) {
5407d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent        synchronized (mSafeMediaVolumeState) {
5408d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent            if ((mSafeMediaVolumeState == SAFE_MEDIA_VOLUME_ACTIVE) &&
5409c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent                    (mStreamVolumeAlias[streamType] == AudioSystem.STREAM_MUSIC) &&
5410c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent                    ((device & mSafeMediaVolumeDevices) != 0) &&
5411c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent                    (index > mSafeMediaVolumeIndex)) {
5412c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent                return false;
5413c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent            }
5414c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent            return true;
5415c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent        }
5416c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent    }
5417c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent
54183346a802087f621c6441bc512dfcc17b07143fc6John Spurlock    @Override
5419c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent    public void disableSafeMediaVolume() {
54203346a802087f621c6441bc512dfcc17b07143fc6John Spurlock        enforceSelfOrSystemUI("disable the safe media volume");
5421d640bd325c3be9a350058c835b880a7e0b40dc60Eric Laurent        synchronized (mSafeMediaVolumeState) {
5422c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent            setSafeMediaVolumeEnabled(false);
5423fde16d5879ea88a971004c984093409468b6139cEric Laurent            if (mPendingVolumeCommand != null) {
5424fde16d5879ea88a971004c984093409468b6139cEric Laurent                onSetStreamVolume(mPendingVolumeCommand.mStreamType,
5425fde16d5879ea88a971004c984093409468b6139cEric Laurent                                  mPendingVolumeCommand.mIndex,
5426fde16d5879ea88a971004c984093409468b6139cEric Laurent                                  mPendingVolumeCommand.mFlags,
5427fde16d5879ea88a971004c984093409468b6139cEric Laurent                                  mPendingVolumeCommand.mDevice);
5428fde16d5879ea88a971004c984093409468b6139cEric Laurent                mPendingVolumeCommand = null;
5429fde16d5879ea88a971004c984093409468b6139cEric Laurent            }
5430c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent        }
5431c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent    }
5432c34dcc1e1ebf152bb400abbb8bc25f7dc0c3ba97Eric Laurent
543341d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang    //==========================================================================================
543441d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang    // Hdmi Cec system audio mode.
543541d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang    // If Hdmi Cec's system audio mode is on, audio service should notify volume change
543641d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang    // to HdmiControlService so that audio recevier can handle volume change.
543741d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang    //==========================================================================================
543841d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang
5439212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent    private class MyDisplayStatusCallback implements HdmiPlaybackClient.DisplayStatusCallback {
5440212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent        public void onComplete(int status) {
5441212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent            if (mHdmiManager != null) {
5442212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent                synchronized (mHdmiManager) {
5443212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent                    mHdmiCecSink = (status != HdmiControlManager.POWER_STATUS_UNKNOWN);
5444212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent                    // Television devices without CEC service apply software volume on HDMI output
5445212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent                    if (isPlatformTelevision() && !mHdmiCecSink) {
5446212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent                        mFixedVolumeDevices &= ~AudioSystem.DEVICE_OUT_HDMI;
5447212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent                    }
5448212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent                    checkAllFixedVolumeDevices();
5449212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent                }
5450212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent            }
5451212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent        }
5452212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent    };
5453212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent
545441d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang    // If HDMI-CEC system audio is supported
545541d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang    private boolean mHdmiSystemAudioSupported = false;
545641d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang    // Set only when device is tv.
545741d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang    private HdmiTvClient mHdmiTvClient;
54580b03f9909be438f45b32ce2a6a2c2c5208a82cc9Eric Laurent    // true if the device has system feature PackageManager.FEATURE_LEANBACK.
5459212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent    // cached HdmiControlManager interface
5460212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent    private HdmiControlManager mHdmiManager;
5461212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent    // Set only when device is a set-top box.
5462212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent    private HdmiPlaybackClient mHdmiPlaybackClient;
5463212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent    // true if we are a set-top box, an HDMI sink is connected and it supports CEC.
5464212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent    private boolean mHdmiCecSink;
5465212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent
5466212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent    private MyDisplayStatusCallback mHdmiDisplayStatusCallback = new MyDisplayStatusCallback();
546741d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang
546841d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang    @Override
546912307ca810e8100981b2b60e3f2c6a7e451b9774Jungshik Jang    public int setHdmiSystemAudioSupported(boolean on) {
5470212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent        int device = AudioSystem.DEVICE_NONE;
5471212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent        if (mHdmiManager != null) {
5472212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent            synchronized (mHdmiManager) {
5473212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent                if (mHdmiTvClient == null) {
5474212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent                    Log.w(TAG, "Only Hdmi-Cec enabled TV device supports system audio mode.");
5475212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent                    return device;
5476212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent                }
547741d974631c5f525da49c88d34cecedd5a4cfeda8Jungshik Jang
5478212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent                synchronized (mHdmiTvClient) {
5479212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent                    if (mHdmiSystemAudioSupported != on) {
5480212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent                        mHdmiSystemAudioSupported = on;
5481212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent                        AudioSystem.setForceUse(AudioSystem.FOR_HDMI_SYSTEM_AUDIO,
5482212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent                                on ? AudioSystem.FORCE_HDMI_SYSTEM_AUDIO_ENFORCED :
5483212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent                                     AudioSystem.FORCE_NONE);
5484212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent                    }
5485212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent                    device = AudioSystem.getDevicesForStream(AudioSystem.STREAM_MUSIC);
5486212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent                }
54876f34f5ab8ab1b1db7887e5405d8b0031e105ab05Jungshik Jang            }
54886f34f5ab8ab1b1db7887e5405d8b0031e105ab05Jungshik Jang        }
5489212532b58e3b17d7e9d6e1361946d909d4e372c2Eric Laurent        return device;
54906f34f5ab8ab1b1db7887e5405d8b0031e105ab05Jungshik Jang    }
54916f34f5ab8ab1b1db7887e5405d8b0031e105ab05Jungshik Jang
5492e7d6d97f0d95b9e8982b0d4d9f5e8ce688291940Terry Heo    @Override
5493e7d6d97f0d95b9e8982b0d4d9f5e8ce688291940Terry Heo    public boolean isHdmiSystemAudioSupported() {
5494e7d6d97f0d95b9e8982b0d4d9f5e8ce688291940Terry Heo        return mHdmiSystemAudioSupported;
5495e7d6d97f0d95b9e8982b0d4d9f5e8ce688291940Terry Heo    }
5496e7d6d97f0d95b9e8982b0d4d9f5e8ce688291940Terry Heo
5497dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent    //==========================================================================================
5498873cc45da2463a11182fe94a2565364d7e1709bbJean-Michel Trivi    // Accessibility: taking touch exploration into account for selecting the default
5499873cc45da2463a11182fe94a2565364d7e1709bbJean-Michel Trivi    //   stream override timeout when adjusting volume
5500873cc45da2463a11182fe94a2565364d7e1709bbJean-Michel Trivi    //==========================================================================================
5501873cc45da2463a11182fe94a2565364d7e1709bbJean-Michel Trivi    private static class StreamOverride
5502873cc45da2463a11182fe94a2565364d7e1709bbJean-Michel Trivi            implements AccessibilityManager.TouchExplorationStateChangeListener {
5503873cc45da2463a11182fe94a2565364d7e1709bbJean-Michel Trivi
5504873cc45da2463a11182fe94a2565364d7e1709bbJean-Michel Trivi        // AudioService.getActiveStreamType() will return:
5505873cc45da2463a11182fe94a2565364d7e1709bbJean-Michel Trivi        // - STREAM_NOTIFICATION on tablets during this period after a notification stopped
5506873cc45da2463a11182fe94a2565364d7e1709bbJean-Michel Trivi        // - STREAM_MUSIC on phones during this period after music or talkback/voice search prompt
5507873cc45da2463a11182fe94a2565364d7e1709bbJean-Michel Trivi        // stopped
5508873cc45da2463a11182fe94a2565364d7e1709bbJean-Michel Trivi        private static final int DEFAULT_STREAM_TYPE_OVERRIDE_DELAY_MS = 5000;
5509873cc45da2463a11182fe94a2565364d7e1709bbJean-Michel Trivi        private static final int TOUCH_EXPLORE_STREAM_TYPE_OVERRIDE_DELAY_MS = 1000;
5510873cc45da2463a11182fe94a2565364d7e1709bbJean-Michel Trivi
5511873cc45da2463a11182fe94a2565364d7e1709bbJean-Michel Trivi        static int sDelayMs;
5512873cc45da2463a11182fe94a2565364d7e1709bbJean-Michel Trivi
5513873cc45da2463a11182fe94a2565364d7e1709bbJean-Michel Trivi        static void init(Context ctxt) {
5514873cc45da2463a11182fe94a2565364d7e1709bbJean-Michel Trivi            AccessibilityManager accessibilityManager =
5515873cc45da2463a11182fe94a2565364d7e1709bbJean-Michel Trivi                    (AccessibilityManager) ctxt.getSystemService(Context.ACCESSIBILITY_SERVICE);
5516873cc45da2463a11182fe94a2565364d7e1709bbJean-Michel Trivi            updateDefaultStreamOverrideDelay(
5517873cc45da2463a11182fe94a2565364d7e1709bbJean-Michel Trivi                    accessibilityManager.isTouchExplorationEnabled());
5518873cc45da2463a11182fe94a2565364d7e1709bbJean-Michel Trivi            accessibilityManager.addTouchExplorationStateChangeListener(
5519873cc45da2463a11182fe94a2565364d7e1709bbJean-Michel Trivi                    new StreamOverride());
5520873cc45da2463a11182fe94a2565364d7e1709bbJean-Michel Trivi        }
5521873cc45da2463a11182fe94a2565364d7e1709bbJean-Michel Trivi
5522873cc45da2463a11182fe94a2565364d7e1709bbJean-Michel Trivi        @Override
5523873cc45da2463a11182fe94a2565364d7e1709bbJean-Michel Trivi        public void onTouchExplorationStateChanged(boolean enabled) {
5524873cc45da2463a11182fe94a2565364d7e1709bbJean-Michel Trivi            updateDefaultStreamOverrideDelay(enabled);
5525873cc45da2463a11182fe94a2565364d7e1709bbJean-Michel Trivi        }
5526873cc45da2463a11182fe94a2565364d7e1709bbJean-Michel Trivi
5527873cc45da2463a11182fe94a2565364d7e1709bbJean-Michel Trivi        private static void updateDefaultStreamOverrideDelay(boolean touchExploreEnabled) {
5528873cc45da2463a11182fe94a2565364d7e1709bbJean-Michel Trivi            if (touchExploreEnabled) {
5529873cc45da2463a11182fe94a2565364d7e1709bbJean-Michel Trivi                sDelayMs = TOUCH_EXPLORE_STREAM_TYPE_OVERRIDE_DELAY_MS;
5530873cc45da2463a11182fe94a2565364d7e1709bbJean-Michel Trivi            } else {
5531873cc45da2463a11182fe94a2565364d7e1709bbJean-Michel Trivi                sDelayMs = DEFAULT_STREAM_TYPE_OVERRIDE_DELAY_MS;
5532873cc45da2463a11182fe94a2565364d7e1709bbJean-Michel Trivi            }
5533873cc45da2463a11182fe94a2565364d7e1709bbJean-Michel Trivi            if (DEBUG_VOL) Log.d(TAG, "Touch exploration enabled=" + touchExploreEnabled
5534873cc45da2463a11182fe94a2565364d7e1709bbJean-Michel Trivi                    + " stream override delay is now " + sDelayMs + " ms");
5535873cc45da2463a11182fe94a2565364d7e1709bbJean-Michel Trivi        }
5536873cc45da2463a11182fe94a2565364d7e1709bbJean-Michel Trivi    }
5537873cc45da2463a11182fe94a2565364d7e1709bbJean-Michel Trivi
5538873cc45da2463a11182fe94a2565364d7e1709bbJean-Michel Trivi    //==========================================================================================
5539dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent    // Camera shutter sound policy.
5540dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent    // config_camera_sound_forced configuration option in config.xml defines if the camera shutter
5541dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent    // sound is forced (sound even if the device is in silent mode) or not. This option is false by
5542dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent    // default and can be overridden by country specific overlay in values-mccXXX/config.xml.
5543dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent    //==========================================================================================
5544dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent
5545dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent    // cached value of com.android.internal.R.bool.config_camera_sound_forced
5546dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent    private Boolean mCameraSoundForced;
5547dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent
5548dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent    // called by android.hardware.Camera to populate CameraInfo.canDisableShutterSound
5549dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent    public boolean isCameraSoundForced() {
5550dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent        synchronized (mCameraSoundForced) {
5551dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent            return mCameraSoundForced;
5552dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent        }
5553dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent    }
5554dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent
5555dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent    private static final String[] RINGER_MODE_NAMES = new String[] {
5556dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent            "SILENT",
5557dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent            "VIBRATE",
5558dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent            "NORMAL"
5559dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent    };
5560dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent
5561dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent    private void dumpRingerMode(PrintWriter pw) {
5562dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent        pw.println("\nRinger mode: ");
5563661f2cf45860d2e10924e6b69966a9afe255f28bJohn Spurlock        pw.println("- mode (internal) = " + RINGER_MODE_NAMES[mRingerMode]);
5564661f2cf45860d2e10924e6b69966a9afe255f28bJohn Spurlock        pw.println("- mode (external) = " + RINGER_MODE_NAMES[mRingerModeExternal]);
5565dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent        pw.print("- ringer mode affected streams = 0x");
5566dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent        pw.println(Integer.toHexString(mRingerModeAffectedStreams));
5567dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent        pw.print("- ringer mode muted streams = 0x");
5568dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent        pw.println(Integer.toHexString(mRingerModeMutedStreams));
5569661f2cf45860d2e10924e6b69966a9afe255f28bJohn Spurlock        pw.print("- delegate = "); pw.println(mRingerModeDelegate);
5570dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent    }
5571dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent
5572632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn    @Override
5573d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi    protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
5574eb4cc492c93ab9635dde78b958a834120412e72aJeff Sharkey        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DUMP, TAG);
5575eb4cc492c93ab9635dde78b958a834120412e72aJeff Sharkey
5576fa9a69805b001034aa04c3b33989a7ac21522371Jean-Michel Trivi        mMediaFocusControl.dump(pw);
5577bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent        dumpStreamStates(pw);
5578dd45d01128423a82652a3c9d77fa393631d95229Eric Laurent        dumpRingerMode(pw);
5579632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn        pw.println("\nAudio routes:");
5580632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn        pw.print("  mMainType=0x"); pw.println(Integer.toHexString(mCurAudioRoutes.mMainType));
5581632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn        pw.print("  mBluetoothName="); pw.println(mCurAudioRoutes.mBluetoothName);
5582351346092acdfbfcc1d9ebf98d539d2a1196c5e8John Spurlock
5583351346092acdfbfcc1d9ebf98d539d2a1196c5e8John Spurlock        pw.println("\nOther state:");
55843346a802087f621c6441bc512dfcc17b07143fc6John Spurlock        pw.print("  mVolumeController="); pw.println(mVolumeController);
5585351346092acdfbfcc1d9ebf98d539d2a1196c5e8John Spurlock        pw.print("  mSafeMediaVolumeState=");
5586351346092acdfbfcc1d9ebf98d539d2a1196c5e8John Spurlock        pw.println(safeMediaVolumeStateToString(mSafeMediaVolumeState));
5587351346092acdfbfcc1d9ebf98d539d2a1196c5e8John Spurlock        pw.print("  mSafeMediaVolumeIndex="); pw.println(mSafeMediaVolumeIndex);
5588351346092acdfbfcc1d9ebf98d539d2a1196c5e8John Spurlock        pw.print("  mPendingVolumeCommand="); pw.println(mPendingVolumeCommand);
5589351346092acdfbfcc1d9ebf98d539d2a1196c5e8John Spurlock        pw.print("  mMusicActiveMs="); pw.println(mMusicActiveMs);
5590aa5ee4d65f8788e2a0afcd198367450853fd72acJohn Spurlock        pw.print("  mMcc="); pw.println(mMcc);
5591661f2cf45860d2e10924e6b69966a9afe255f28bJohn Spurlock        pw.print("  mHasVibrator="); pw.println(mHasVibrator);
55921b3541d5eedb332ea01066b4a78a2d06d5304044Jean-Michel Trivi
55931b3541d5eedb332ea01066b4a78a2d06d5304044Jean-Michel Trivi        dumpAudioPolicies(pw);
5594351346092acdfbfcc1d9ebf98d539d2a1196c5e8John Spurlock    }
5595351346092acdfbfcc1d9ebf98d539d2a1196c5e8John Spurlock
5596351346092acdfbfcc1d9ebf98d539d2a1196c5e8John Spurlock    private static String safeMediaVolumeStateToString(Integer state) {
5597351346092acdfbfcc1d9ebf98d539d2a1196c5e8John Spurlock        switch(state) {
5598351346092acdfbfcc1d9ebf98d539d2a1196c5e8John Spurlock            case SAFE_MEDIA_VOLUME_NOT_CONFIGURED: return "SAFE_MEDIA_VOLUME_NOT_CONFIGURED";
5599351346092acdfbfcc1d9ebf98d539d2a1196c5e8John Spurlock            case SAFE_MEDIA_VOLUME_DISABLED: return "SAFE_MEDIA_VOLUME_DISABLED";
5600351346092acdfbfcc1d9ebf98d539d2a1196c5e8John Spurlock            case SAFE_MEDIA_VOLUME_INACTIVE: return "SAFE_MEDIA_VOLUME_INACTIVE";
5601351346092acdfbfcc1d9ebf98d539d2a1196c5e8John Spurlock            case SAFE_MEDIA_VOLUME_ACTIVE: return "SAFE_MEDIA_VOLUME_ACTIVE";
5602351346092acdfbfcc1d9ebf98d539d2a1196c5e8John Spurlock        }
5603351346092acdfbfcc1d9ebf98d539d2a1196c5e8John Spurlock        return null;
5604d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi    }
5605fd116ad1ab02f6060a0b2201f018317fa32e28b4Glenn Kasten
5606fd116ad1ab02f6060a0b2201f018317fa32e28b4Glenn Kasten    // Inform AudioFlinger of our device's low RAM attribute
5607fd116ad1ab02f6060a0b2201f018317fa32e28b4Glenn Kasten    private static void readAndSetLowRamDevice()
5608fd116ad1ab02f6060a0b2201f018317fa32e28b4Glenn Kasten    {
5609fd116ad1ab02f6060a0b2201f018317fa32e28b4Glenn Kasten        int status = AudioSystem.setLowRamDevice(ActivityManager.isLowRamDeviceStatic());
5610fd116ad1ab02f6060a0b2201f018317fa32e28b4Glenn Kasten        if (status != 0) {
5611fd116ad1ab02f6060a0b2201f018317fa32e28b4Glenn Kasten            Log.w(TAG, "AudioFlinger informed of device's low RAM attribute; status " + status);
5612fd116ad1ab02f6060a0b2201f018317fa32e28b4Glenn Kasten        }
5613fd116ad1ab02f6060a0b2201f018317fa32e28b4Glenn Kasten    }
56143346a802087f621c6441bc512dfcc17b07143fc6John Spurlock
56153346a802087f621c6441bc512dfcc17b07143fc6John Spurlock    private void enforceSelfOrSystemUI(String action) {
56163346a802087f621c6441bc512dfcc17b07143fc6John Spurlock        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.STATUS_BAR_SERVICE,
56173346a802087f621c6441bc512dfcc17b07143fc6John Spurlock                "Only SystemUI can " + action);
56183346a802087f621c6441bc512dfcc17b07143fc6John Spurlock    }
56193346a802087f621c6441bc512dfcc17b07143fc6John Spurlock
56203346a802087f621c6441bc512dfcc17b07143fc6John Spurlock    @Override
56213346a802087f621c6441bc512dfcc17b07143fc6John Spurlock    public void setVolumeController(final IVolumeController controller) {
56223346a802087f621c6441bc512dfcc17b07143fc6John Spurlock        enforceSelfOrSystemUI("set the volume controller");
56233346a802087f621c6441bc512dfcc17b07143fc6John Spurlock
56243346a802087f621c6441bc512dfcc17b07143fc6John Spurlock        // return early if things are not actually changing
56253346a802087f621c6441bc512dfcc17b07143fc6John Spurlock        if (mVolumeController.isSameBinder(controller)) {
56263346a802087f621c6441bc512dfcc17b07143fc6John Spurlock            return;
56273346a802087f621c6441bc512dfcc17b07143fc6John Spurlock        }
56283346a802087f621c6441bc512dfcc17b07143fc6John Spurlock
56293346a802087f621c6441bc512dfcc17b07143fc6John Spurlock        // dismiss the old volume controller
56303346a802087f621c6441bc512dfcc17b07143fc6John Spurlock        mVolumeController.postDismiss();
56313346a802087f621c6441bc512dfcc17b07143fc6John Spurlock        if (controller != null) {
56323346a802087f621c6441bc512dfcc17b07143fc6John Spurlock            // we are about to register a new controller, listen for its death
56333346a802087f621c6441bc512dfcc17b07143fc6John Spurlock            try {
56343346a802087f621c6441bc512dfcc17b07143fc6John Spurlock                controller.asBinder().linkToDeath(new DeathRecipient() {
56353346a802087f621c6441bc512dfcc17b07143fc6John Spurlock                    @Override
56363346a802087f621c6441bc512dfcc17b07143fc6John Spurlock                    public void binderDied() {
56373346a802087f621c6441bc512dfcc17b07143fc6John Spurlock                        if (mVolumeController.isSameBinder(controller)) {
56383346a802087f621c6441bc512dfcc17b07143fc6John Spurlock                            Log.w(TAG, "Current remote volume controller died, unregistering");
56393346a802087f621c6441bc512dfcc17b07143fc6John Spurlock                            setVolumeController(null);
56403346a802087f621c6441bc512dfcc17b07143fc6John Spurlock                        }
56413346a802087f621c6441bc512dfcc17b07143fc6John Spurlock                    }
56423346a802087f621c6441bc512dfcc17b07143fc6John Spurlock                }, 0);
56433346a802087f621c6441bc512dfcc17b07143fc6John Spurlock            } catch (RemoteException e) {
56443346a802087f621c6441bc512dfcc17b07143fc6John Spurlock                // noop
56453346a802087f621c6441bc512dfcc17b07143fc6John Spurlock            }
56463346a802087f621c6441bc512dfcc17b07143fc6John Spurlock        }
56473346a802087f621c6441bc512dfcc17b07143fc6John Spurlock        mVolumeController.setController(controller);
564833f4e04e32fac42f158733d6a731e50490fa9951John Spurlock        if (DEBUG_VOL) Log.d(TAG, "Volume controller: " + mVolumeController);
564933f4e04e32fac42f158733d6a731e50490fa9951John Spurlock    }
565033f4e04e32fac42f158733d6a731e50490fa9951John Spurlock
565133f4e04e32fac42f158733d6a731e50490fa9951John Spurlock    @Override
565233f4e04e32fac42f158733d6a731e50490fa9951John Spurlock    public void notifyVolumeControllerVisible(final IVolumeController controller, boolean visible) {
565333f4e04e32fac42f158733d6a731e50490fa9951John Spurlock        enforceSelfOrSystemUI("notify about volume controller visibility");
565433f4e04e32fac42f158733d6a731e50490fa9951John Spurlock
565533f4e04e32fac42f158733d6a731e50490fa9951John Spurlock        // return early if the controller is not current
565633f4e04e32fac42f158733d6a731e50490fa9951John Spurlock        if (!mVolumeController.isSameBinder(controller)) {
565733f4e04e32fac42f158733d6a731e50490fa9951John Spurlock            return;
565833f4e04e32fac42f158733d6a731e50490fa9951John Spurlock        }
565933f4e04e32fac42f158733d6a731e50490fa9951John Spurlock
566033f4e04e32fac42f158733d6a731e50490fa9951John Spurlock        mVolumeController.setVisible(visible);
566133f4e04e32fac42f158733d6a731e50490fa9951John Spurlock        if (DEBUG_VOL) Log.d(TAG, "Volume controller visible: " + visible);
56623346a802087f621c6441bc512dfcc17b07143fc6John Spurlock    }
5663d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik
5664d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik    public static class VolumeController {
5665d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik        private static final String TAG = "VolumeController";
5666d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik
5667d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik        private IVolumeController mController;
566833f4e04e32fac42f158733d6a731e50490fa9951John Spurlock        private boolean mVisible;
566933f4e04e32fac42f158733d6a731e50490fa9951John Spurlock        private long mNextLongPress;
567033f4e04e32fac42f158733d6a731e50490fa9951John Spurlock        private int mLongPressTimeout;
5671d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik
5672d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik        public void setController(IVolumeController controller) {
5673d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik            mController = controller;
567433f4e04e32fac42f158733d6a731e50490fa9951John Spurlock            mVisible = false;
567533f4e04e32fac42f158733d6a731e50490fa9951John Spurlock        }
567633f4e04e32fac42f158733d6a731e50490fa9951John Spurlock
567733f4e04e32fac42f158733d6a731e50490fa9951John Spurlock        public void loadSettings(ContentResolver cr) {
567833f4e04e32fac42f158733d6a731e50490fa9951John Spurlock            mLongPressTimeout = Settings.Secure.getIntForUser(cr,
567933f4e04e32fac42f158733d6a731e50490fa9951John Spurlock                    Settings.Secure.LONG_PRESS_TIMEOUT, 500, UserHandle.USER_CURRENT);
568033f4e04e32fac42f158733d6a731e50490fa9951John Spurlock        }
568133f4e04e32fac42f158733d6a731e50490fa9951John Spurlock
568233f4e04e32fac42f158733d6a731e50490fa9951John Spurlock        public boolean suppressAdjustment(int resolvedStream, int flags) {
568333f4e04e32fac42f158733d6a731e50490fa9951John Spurlock            boolean suppress = false;
568433f4e04e32fac42f158733d6a731e50490fa9951John Spurlock            if (resolvedStream == AudioSystem.STREAM_RING && mController != null) {
568533f4e04e32fac42f158733d6a731e50490fa9951John Spurlock                final long now = SystemClock.uptimeMillis();
568633f4e04e32fac42f158733d6a731e50490fa9951John Spurlock                if ((flags & AudioManager.FLAG_SHOW_UI) != 0 && !mVisible) {
568733f4e04e32fac42f158733d6a731e50490fa9951John Spurlock                    // ui will become visible
568833f4e04e32fac42f158733d6a731e50490fa9951John Spurlock                    if (mNextLongPress < now) {
568933f4e04e32fac42f158733d6a731e50490fa9951John Spurlock                        mNextLongPress = now + mLongPressTimeout;
569033f4e04e32fac42f158733d6a731e50490fa9951John Spurlock                    }
569133f4e04e32fac42f158733d6a731e50490fa9951John Spurlock                    suppress = true;
569233f4e04e32fac42f158733d6a731e50490fa9951John Spurlock                } else if (mNextLongPress > 0) {  // in a long-press
569333f4e04e32fac42f158733d6a731e50490fa9951John Spurlock                    if (now > mNextLongPress) {
569433f4e04e32fac42f158733d6a731e50490fa9951John Spurlock                        // long press triggered, no more suppression
569533f4e04e32fac42f158733d6a731e50490fa9951John Spurlock                        mNextLongPress = 0;
569633f4e04e32fac42f158733d6a731e50490fa9951John Spurlock                    } else {
569733f4e04e32fac42f158733d6a731e50490fa9951John Spurlock                        // keep suppressing until the long press triggers
569833f4e04e32fac42f158733d6a731e50490fa9951John Spurlock                        suppress = true;
569933f4e04e32fac42f158733d6a731e50490fa9951John Spurlock                    }
570033f4e04e32fac42f158733d6a731e50490fa9951John Spurlock                }
570133f4e04e32fac42f158733d6a731e50490fa9951John Spurlock            }
570233f4e04e32fac42f158733d6a731e50490fa9951John Spurlock            return suppress;
570333f4e04e32fac42f158733d6a731e50490fa9951John Spurlock        }
570433f4e04e32fac42f158733d6a731e50490fa9951John Spurlock
570533f4e04e32fac42f158733d6a731e50490fa9951John Spurlock        public void setVisible(boolean visible) {
570633f4e04e32fac42f158733d6a731e50490fa9951John Spurlock            mVisible = visible;
5707d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik        }
5708d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik
5709d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik        public boolean isSameBinder(IVolumeController controller) {
5710d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik            return Objects.equals(asBinder(), binder(controller));
5711d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik        }
5712d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik
5713d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik        public IBinder asBinder() {
5714d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik            return binder(mController);
5715d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik        }
5716d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik
5717d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik        private static IBinder binder(IVolumeController controller) {
5718d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik            return controller == null ? null : controller.asBinder();
5719d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik        }
5720d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik
5721d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik        @Override
5722d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik        public String toString() {
572333f4e04e32fac42f158733d6a731e50490fa9951John Spurlock            return "VolumeController(" + asBinder() + ",mVisible=" + mVisible + ")";
5724d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik        }
5725d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik
5726d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik        public void postDisplaySafeVolumeWarning(int flags) {
5727d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik            if (mController == null)
5728d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik                return;
5729d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik            try {
5730d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik                mController.displaySafeVolumeWarning(flags);
5731d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik            } catch (RemoteException e) {
5732d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik                Log.w(TAG, "Error calling displaySafeVolumeWarning", e);
5733d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik            }
5734d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik        }
5735d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik
5736d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik        public void postVolumeChanged(int streamType, int flags) {
5737d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik            if (mController == null)
5738d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik                return;
5739d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik            try {
5740d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik                mController.volumeChanged(streamType, flags);
5741d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik            } catch (RemoteException e) {
5742d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik                Log.w(TAG, "Error calling volumeChanged", e);
5743d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik            }
5744d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik        }
5745d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik
5746d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik        public void postMasterVolumeChanged(int flags) {
5747d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik            if (mController == null)
5748d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik                return;
5749d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik            try {
5750d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik                mController.masterVolumeChanged(flags);
5751d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik            } catch (RemoteException e) {
5752d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik                Log.w(TAG, "Error calling masterVolumeChanged", e);
5753d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik            }
5754d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik        }
5755d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik
5756d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik        public void postMasterMuteChanged(int flags) {
5757d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik            if (mController == null)
5758d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik                return;
5759d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik            try {
5760d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik                mController.masterMuteChanged(flags);
5761d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik            } catch (RemoteException e) {
5762d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik                Log.w(TAG, "Error calling masterMuteChanged", e);
5763d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik            }
5764d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik        }
5765d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik
5766d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik        public void setLayoutDirection(int layoutDirection) {
5767d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik            if (mController == null)
5768d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik                return;
5769d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik            try {
5770d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik                mController.setLayoutDirection(layoutDirection);
5771d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik            } catch (RemoteException e) {
5772d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik                Log.w(TAG, "Error calling setLayoutDirection", e);
5773d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik            }
5774d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik        }
5775d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik
5776d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik        public void postDismiss() {
5777d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik            if (mController == null)
5778d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik                return;
5779d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik            try {
5780d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik                mController.dismiss();
5781d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik            } catch (RemoteException e) {
5782d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik                Log.w(TAG, "Error calling dismiss", e);
5783d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik            }
5784661f2cf45860d2e10924e6b69966a9afe255f28bJohn Spurlock        }
5785d09bd0c6eb8318e0122b14d7eb5324e481706e41RoboErik    }
5786a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi
57870dac35af2c6aa42bcd181981b041747cfd1afa5fRoboErik    /**
57880dac35af2c6aa42bcd181981b041747cfd1afa5fRoboErik     * Interface for system components to get some extra functionality through
57890dac35af2c6aa42bcd181981b041747cfd1afa5fRoboErik     * LocalServices.
57900dac35af2c6aa42bcd181981b041747cfd1afa5fRoboErik     */
57910dac35af2c6aa42bcd181981b041747cfd1afa5fRoboErik    final class AudioServiceInternal extends AudioManagerInternal {
5792661f2cf45860d2e10924e6b69966a9afe255f28bJohn Spurlock        @Override
5793661f2cf45860d2e10924e6b69966a9afe255f28bJohn Spurlock        public void setRingerModeDelegate(RingerModeDelegate delegate) {
5794661f2cf45860d2e10924e6b69966a9afe255f28bJohn Spurlock            mRingerModeDelegate = delegate;
5795661f2cf45860d2e10924e6b69966a9afe255f28bJohn Spurlock            if (mRingerModeDelegate != null) {
5796661f2cf45860d2e10924e6b69966a9afe255f28bJohn Spurlock                setRingerModeInternal(getRingerModeInternal(), TAG + ".setRingerModeDelegate");
5797661f2cf45860d2e10924e6b69966a9afe255f28bJohn Spurlock            }
5798661f2cf45860d2e10924e6b69966a9afe255f28bJohn Spurlock        }
5799272e161c1a200900cb10b5b0cdab8ae1f123cabdRoboErik
5800272e161c1a200900cb10b5b0cdab8ae1f123cabdRoboErik        @Override
5801272e161c1a200900cb10b5b0cdab8ae1f123cabdRoboErik        public void adjustSuggestedStreamVolumeForUid(int streamType, int direction, int flags,
5802272e161c1a200900cb10b5b0cdab8ae1f123cabdRoboErik                String callingPackage, int uid) {
5803272e161c1a200900cb10b5b0cdab8ae1f123cabdRoboErik            // direction and stream type swap here because the public
5804272e161c1a200900cb10b5b0cdab8ae1f123cabdRoboErik            // adjustSuggested has a different order than the other methods.
5805272e161c1a200900cb10b5b0cdab8ae1f123cabdRoboErik            adjustSuggestedStreamVolume(direction, streamType, flags, callingPackage, uid);
5806272e161c1a200900cb10b5b0cdab8ae1f123cabdRoboErik        }
5807272e161c1a200900cb10b5b0cdab8ae1f123cabdRoboErik
58080dac35af2c6aa42bcd181981b041747cfd1afa5fRoboErik        @Override
58090dac35af2c6aa42bcd181981b041747cfd1afa5fRoboErik        public void adjustStreamVolumeForUid(int streamType, int direction, int flags,
58100dac35af2c6aa42bcd181981b041747cfd1afa5fRoboErik                String callingPackage, int uid) {
58110dac35af2c6aa42bcd181981b041747cfd1afa5fRoboErik            adjustStreamVolume(streamType, direction, flags, callingPackage, uid);
58120dac35af2c6aa42bcd181981b041747cfd1afa5fRoboErik        }
58130dac35af2c6aa42bcd181981b041747cfd1afa5fRoboErik
58140dac35af2c6aa42bcd181981b041747cfd1afa5fRoboErik        @Override
58150dac35af2c6aa42bcd181981b041747cfd1afa5fRoboErik        public void setStreamVolumeForUid(int streamType, int direction, int flags,
58160dac35af2c6aa42bcd181981b041747cfd1afa5fRoboErik                String callingPackage, int uid) {
58170dac35af2c6aa42bcd181981b041747cfd1afa5fRoboErik            setStreamVolume(streamType, direction, flags, callingPackage, uid);
58180dac35af2c6aa42bcd181981b041747cfd1afa5fRoboErik        }
5819519c7744b522aa07e12bc3244ac3de14aa2a4ad0RoboErik
5820519c7744b522aa07e12bc3244ac3de14aa2a4ad0RoboErik        @Override
5821519c7744b522aa07e12bc3244ac3de14aa2a4ad0RoboErik        public void adjustMasterVolumeForUid(int steps, int flags, String callingPackage,
5822519c7744b522aa07e12bc3244ac3de14aa2a4ad0RoboErik                int uid) {
5823519c7744b522aa07e12bc3244ac3de14aa2a4ad0RoboErik            adjustMasterVolume(steps, flags, callingPackage, uid);
5824519c7744b522aa07e12bc3244ac3de14aa2a4ad0RoboErik        }
5825661f2cf45860d2e10924e6b69966a9afe255f28bJohn Spurlock
5826661f2cf45860d2e10924e6b69966a9afe255f28bJohn Spurlock        @Override
5827661f2cf45860d2e10924e6b69966a9afe255f28bJohn Spurlock        public int getRingerModeInternal() {
5828661f2cf45860d2e10924e6b69966a9afe255f28bJohn Spurlock            return AudioService.this.getRingerModeInternal();
5829661f2cf45860d2e10924e6b69966a9afe255f28bJohn Spurlock        }
5830661f2cf45860d2e10924e6b69966a9afe255f28bJohn Spurlock
5831661f2cf45860d2e10924e6b69966a9afe255f28bJohn Spurlock        @Override
5832661f2cf45860d2e10924e6b69966a9afe255f28bJohn Spurlock        public void setRingerModeInternal(int ringerMode, String caller) {
5833661f2cf45860d2e10924e6b69966a9afe255f28bJohn Spurlock            AudioService.this.setRingerModeInternal(ringerMode, caller);
5834661f2cf45860d2e10924e6b69966a9afe255f28bJohn Spurlock        }
58357c82ced4fc5b66c09a19eed9a5499039530142fbRoboErik
58367c82ced4fc5b66c09a19eed9a5499039530142fbRoboErik        @Override
58377c82ced4fc5b66c09a19eed9a5499039530142fbRoboErik        public void setMasterMuteForUid(boolean state, int flags, String callingPackage, IBinder cb,
58387c82ced4fc5b66c09a19eed9a5499039530142fbRoboErik                int uid) {
58397c82ced4fc5b66c09a19eed9a5499039530142fbRoboErik            setMasterMuteInternal(state, flags, callingPackage, cb, uid);
58407c82ced4fc5b66c09a19eed9a5499039530142fbRoboErik        }
58410dac35af2c6aa42bcd181981b041747cfd1afa5fRoboErik    }
58420dac35af2c6aa42bcd181981b041747cfd1afa5fRoboErik
5843a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi    //==========================================================================================
5844a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi    // Audio policy management
5845a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi    //==========================================================================================
58460212be5150fb9fb3c340f3c7e51f6126372cc6f9Jean-Michel Trivi    public String registerAudioPolicy(AudioPolicyConfig policyConfig, IAudioPolicyCallback pcb,
58470212be5150fb9fb3c340f3c7e51f6126372cc6f9Jean-Michel Trivi            boolean hasFocusListener) {
58480212be5150fb9fb3c340f3c7e51f6126372cc6f9Jean-Michel Trivi        if (DEBUG_AP) Log.d(TAG, "registerAudioPolicy for " + pcb.asBinder()
58490212be5150fb9fb3c340f3c7e51f6126372cc6f9Jean-Michel Trivi                + " with config:" + policyConfig);
58508fdb0d4defb6ee2ca8057d3442ead36b408b6c17Jean-Michel Trivi        String regId = null;
58510212be5150fb9fb3c340f3c7e51f6126372cc6f9Jean-Michel Trivi        // error handling
5852a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi        boolean hasPermissionForPolicy =
58530212be5150fb9fb3c340f3c7e51f6126372cc6f9Jean-Michel Trivi                (PackageManager.PERMISSION_GRANTED == mContext.checkCallingPermission(
5854a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi                        android.Manifest.permission.MODIFY_AUDIO_ROUTING));
5855a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi        if (!hasPermissionForPolicy) {
5856a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi            Slog.w(TAG, "Can't register audio policy for pid " + Binder.getCallingPid() + " / uid "
5857a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi                    + Binder.getCallingUid() + ", need MODIFY_AUDIO_ROUTING");
58588fdb0d4defb6ee2ca8057d3442ead36b408b6c17Jean-Michel Trivi            return null;
5859a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi        }
58600212be5150fb9fb3c340f3c7e51f6126372cc6f9Jean-Michel Trivi
5861a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi        synchronized (mAudioPolicies) {
5862a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi            try {
58630212be5150fb9fb3c340f3c7e51f6126372cc6f9Jean-Michel Trivi                if (mAudioPolicies.containsKey(pcb.asBinder())) {
58641b3541d5eedb332ea01066b4a78a2d06d5304044Jean-Michel Trivi                    Slog.e(TAG, "Cannot re-register policy");
58651b3541d5eedb332ea01066b4a78a2d06d5304044Jean-Michel Trivi                    return null;
58661b3541d5eedb332ea01066b4a78a2d06d5304044Jean-Michel Trivi                }
58670212be5150fb9fb3c340f3c7e51f6126372cc6f9Jean-Michel Trivi                AudioPolicyProxy app = new AudioPolicyProxy(policyConfig, pcb, hasFocusListener);
58680212be5150fb9fb3c340f3c7e51f6126372cc6f9Jean-Michel Trivi                pcb.asBinder().linkToDeath(app, 0/*flags*/);
58690212be5150fb9fb3c340f3c7e51f6126372cc6f9Jean-Michel Trivi                regId = app.getRegistrationId();
58700212be5150fb9fb3c340f3c7e51f6126372cc6f9Jean-Michel Trivi                mAudioPolicies.put(pcb.asBinder(), app);
5871a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi            } catch (RemoteException e) {
5872a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi                // audio policy owner has already died!
58730212be5150fb9fb3c340f3c7e51f6126372cc6f9Jean-Michel Trivi                Slog.w(TAG, "Audio policy registration failed, could not link to " + pcb +
5874a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi                        " binder death", e);
58758fdb0d4defb6ee2ca8057d3442ead36b408b6c17Jean-Michel Trivi                return null;
5876a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi            }
5877a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi        }
58788fdb0d4defb6ee2ca8057d3442ead36b408b6c17Jean-Michel Trivi        return regId;
5879a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi    }
58808fdb0d4defb6ee2ca8057d3442ead36b408b6c17Jean-Michel Trivi
58810212be5150fb9fb3c340f3c7e51f6126372cc6f9Jean-Michel Trivi    public void unregisterAudioPolicyAsync(IAudioPolicyCallback pcb) {
58820212be5150fb9fb3c340f3c7e51f6126372cc6f9Jean-Michel Trivi        if (DEBUG_AP) Log.d(TAG, "unregisterAudioPolicyAsync for " + pcb.asBinder());
5883a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi        synchronized (mAudioPolicies) {
58840212be5150fb9fb3c340f3c7e51f6126372cc6f9Jean-Michel Trivi            AudioPolicyProxy app = mAudioPolicies.remove(pcb.asBinder());
5885a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi            if (app == null) {
5886a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi                Slog.w(TAG, "Trying to unregister unknown audio policy for pid "
5887a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi                        + Binder.getCallingPid() + " / uid " + Binder.getCallingUid());
58881b3541d5eedb332ea01066b4a78a2d06d5304044Jean-Michel Trivi                return;
5889a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi            } else {
58900212be5150fb9fb3c340f3c7e51f6126372cc6f9Jean-Michel Trivi                pcb.asBinder().unlinkToDeath(app, 0/*flags*/);
5891a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi            }
58920212be5150fb9fb3c340f3c7e51f6126372cc6f9Jean-Michel Trivi            app.release();
5893a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi        }
58948fdb0d4defb6ee2ca8057d3442ead36b408b6c17Jean-Michel Trivi        // TODO implement clearing mix attribute matching info in native audio policy
5895a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi    }
5896a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi
58970212be5150fb9fb3c340f3c7e51f6126372cc6f9Jean-Michel Trivi    public int setFocusPropertiesForPolicy(int duckingBehavior, IAudioPolicyCallback pcb) {
58980212be5150fb9fb3c340f3c7e51f6126372cc6f9Jean-Michel Trivi        if (DEBUG_AP) Log.d(TAG, "setFocusPropertiesForPolicy() duck behavior=" + duckingBehavior
58990212be5150fb9fb3c340f3c7e51f6126372cc6f9Jean-Michel Trivi                + " policy " +  pcb.asBinder());
59000212be5150fb9fb3c340f3c7e51f6126372cc6f9Jean-Michel Trivi        // error handling
59010212be5150fb9fb3c340f3c7e51f6126372cc6f9Jean-Michel Trivi        boolean hasPermissionForPolicy =
59020212be5150fb9fb3c340f3c7e51f6126372cc6f9Jean-Michel Trivi                (PackageManager.PERMISSION_GRANTED == mContext.checkCallingPermission(
59030212be5150fb9fb3c340f3c7e51f6126372cc6f9Jean-Michel Trivi                        android.Manifest.permission.MODIFY_AUDIO_ROUTING));
59040212be5150fb9fb3c340f3c7e51f6126372cc6f9Jean-Michel Trivi        if (!hasPermissionForPolicy) {
59050212be5150fb9fb3c340f3c7e51f6126372cc6f9Jean-Michel Trivi            Slog.w(TAG, "Cannot change audio policy ducking handling for pid " +
59060212be5150fb9fb3c340f3c7e51f6126372cc6f9Jean-Michel Trivi                    + Binder.getCallingPid() + " / uid "
59070212be5150fb9fb3c340f3c7e51f6126372cc6f9Jean-Michel Trivi                    + Binder.getCallingUid() + ", need MODIFY_AUDIO_ROUTING");
59080212be5150fb9fb3c340f3c7e51f6126372cc6f9Jean-Michel Trivi            return AudioManager.ERROR;
59090212be5150fb9fb3c340f3c7e51f6126372cc6f9Jean-Michel Trivi        }
59100212be5150fb9fb3c340f3c7e51f6126372cc6f9Jean-Michel Trivi
59110212be5150fb9fb3c340f3c7e51f6126372cc6f9Jean-Michel Trivi        synchronized (mAudioPolicies) {
59120212be5150fb9fb3c340f3c7e51f6126372cc6f9Jean-Michel Trivi            if (!mAudioPolicies.containsKey(pcb.asBinder())) {
59130212be5150fb9fb3c340f3c7e51f6126372cc6f9Jean-Michel Trivi                Slog.e(TAG, "Cannot change audio policy focus properties, unregistered policy");
59140212be5150fb9fb3c340f3c7e51f6126372cc6f9Jean-Michel Trivi                return AudioManager.ERROR;
59150212be5150fb9fb3c340f3c7e51f6126372cc6f9Jean-Michel Trivi            }
59160212be5150fb9fb3c340f3c7e51f6126372cc6f9Jean-Michel Trivi            final AudioPolicyProxy app = mAudioPolicies.get(pcb.asBinder());
59170212be5150fb9fb3c340f3c7e51f6126372cc6f9Jean-Michel Trivi            if (duckingBehavior == AudioPolicy.FOCUS_POLICY_DUCKING_IN_POLICY) {
59180212be5150fb9fb3c340f3c7e51f6126372cc6f9Jean-Michel Trivi                // is there already one policy managing ducking?
59190212be5150fb9fb3c340f3c7e51f6126372cc6f9Jean-Michel Trivi                for(AudioPolicyProxy policy : mAudioPolicies.values()) {
59200212be5150fb9fb3c340f3c7e51f6126372cc6f9Jean-Michel Trivi                    if (policy.mFocusDuckBehavior == AudioPolicy.FOCUS_POLICY_DUCKING_IN_POLICY) {
59210212be5150fb9fb3c340f3c7e51f6126372cc6f9Jean-Michel Trivi                        Slog.e(TAG, "Cannot change audio policy ducking behavior, already handled");
59220212be5150fb9fb3c340f3c7e51f6126372cc6f9Jean-Michel Trivi                        return AudioManager.ERROR;
59230212be5150fb9fb3c340f3c7e51f6126372cc6f9Jean-Michel Trivi                    }
59240212be5150fb9fb3c340f3c7e51f6126372cc6f9Jean-Michel Trivi                }
59250212be5150fb9fb3c340f3c7e51f6126372cc6f9Jean-Michel Trivi            }
59260212be5150fb9fb3c340f3c7e51f6126372cc6f9Jean-Michel Trivi            app.mFocusDuckBehavior = duckingBehavior;
59270212be5150fb9fb3c340f3c7e51f6126372cc6f9Jean-Michel Trivi            mMediaFocusControl.setDuckingInExtPolicyAvailable(
59280212be5150fb9fb3c340f3c7e51f6126372cc6f9Jean-Michel Trivi                    duckingBehavior == AudioPolicy.FOCUS_POLICY_DUCKING_IN_POLICY);
59290212be5150fb9fb3c340f3c7e51f6126372cc6f9Jean-Michel Trivi        }
59300212be5150fb9fb3c340f3c7e51f6126372cc6f9Jean-Michel Trivi        return AudioManager.SUCCESS;
59310212be5150fb9fb3c340f3c7e51f6126372cc6f9Jean-Michel Trivi    }
59320212be5150fb9fb3c340f3c7e51f6126372cc6f9Jean-Michel Trivi
59331b3541d5eedb332ea01066b4a78a2d06d5304044Jean-Michel Trivi    private void dumpAudioPolicies(PrintWriter pw) {
59341b3541d5eedb332ea01066b4a78a2d06d5304044Jean-Michel Trivi        pw.println("\nAudio policies:");
59351b3541d5eedb332ea01066b4a78a2d06d5304044Jean-Michel Trivi        synchronized (mAudioPolicies) {
59361b3541d5eedb332ea01066b4a78a2d06d5304044Jean-Michel Trivi            for(AudioPolicyProxy policy : mAudioPolicies.values()) {
59371b3541d5eedb332ea01066b4a78a2d06d5304044Jean-Michel Trivi                pw.println(policy.toLogFriendlyString());
59381b3541d5eedb332ea01066b4a78a2d06d5304044Jean-Michel Trivi            }
59391b3541d5eedb332ea01066b4a78a2d06d5304044Jean-Michel Trivi        }
59401b3541d5eedb332ea01066b4a78a2d06d5304044Jean-Michel Trivi    }
59411b3541d5eedb332ea01066b4a78a2d06d5304044Jean-Michel Trivi
5942958876fe55ea0fdeb73c72240a2f2bab32833443Jean-Michel Trivi    //======================
5943958876fe55ea0fdeb73c72240a2f2bab32833443Jean-Michel Trivi    // Audio policy proxy
5944958876fe55ea0fdeb73c72240a2f2bab32833443Jean-Michel Trivi    //======================
59458fdb0d4defb6ee2ca8057d3442ead36b408b6c17Jean-Michel Trivi    /**
59461b3541d5eedb332ea01066b4a78a2d06d5304044Jean-Michel Trivi     * This internal class inherits from AudioPolicyConfig, each instance contains all the
59471b3541d5eedb332ea01066b4a78a2d06d5304044Jean-Michel Trivi     * mixes of an AudioPolicy and their configurations.
59488fdb0d4defb6ee2ca8057d3442ead36b408b6c17Jean-Michel Trivi     */
59498fdb0d4defb6ee2ca8057d3442ead36b408b6c17Jean-Michel Trivi    public class AudioPolicyProxy extends AudioPolicyConfig implements IBinder.DeathRecipient {
5950a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi        private static final String TAG = "AudioPolicyProxy";
5951a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi        AudioPolicyConfig mConfig;
59520212be5150fb9fb3c340f3c7e51f6126372cc6f9Jean-Michel Trivi        IAudioPolicyCallback mPolicyToken;
59530212be5150fb9fb3c340f3c7e51f6126372cc6f9Jean-Michel Trivi        boolean mHasFocusListener;
59540212be5150fb9fb3c340f3c7e51f6126372cc6f9Jean-Michel Trivi        /**
59550212be5150fb9fb3c340f3c7e51f6126372cc6f9Jean-Michel Trivi         * Audio focus ducking behavior for an audio policy.
59560212be5150fb9fb3c340f3c7e51f6126372cc6f9Jean-Michel Trivi         * This variable reflects the value that was successfully set in
59570212be5150fb9fb3c340f3c7e51f6126372cc6f9Jean-Michel Trivi         * {@link AudioService#setFocusPropertiesForPolicy(int, IAudioPolicyCallback)}. This
59580212be5150fb9fb3c340f3c7e51f6126372cc6f9Jean-Michel Trivi         * implies that a value of FOCUS_POLICY_DUCKING_IN_POLICY means the corresponding policy
59590212be5150fb9fb3c340f3c7e51f6126372cc6f9Jean-Michel Trivi         * is handling ducking for audio focus.
59600212be5150fb9fb3c340f3c7e51f6126372cc6f9Jean-Michel Trivi         */
59610212be5150fb9fb3c340f3c7e51f6126372cc6f9Jean-Michel Trivi        int mFocusDuckBehavior = AudioPolicy.FOCUS_POLICY_DUCKING_DEFAULT;
59620212be5150fb9fb3c340f3c7e51f6126372cc6f9Jean-Michel Trivi
59630212be5150fb9fb3c340f3c7e51f6126372cc6f9Jean-Michel Trivi        AudioPolicyProxy(AudioPolicyConfig config, IAudioPolicyCallback token,
59640212be5150fb9fb3c340f3c7e51f6126372cc6f9Jean-Michel Trivi                boolean hasFocusListener) {
59658fdb0d4defb6ee2ca8057d3442ead36b408b6c17Jean-Michel Trivi            super(config);
59661b3541d5eedb332ea01066b4a78a2d06d5304044Jean-Michel Trivi            setRegistration(new String(config.hashCode() + ":ap:" + mAudioPolicyCounter++));
59670212be5150fb9fb3c340f3c7e51f6126372cc6f9Jean-Michel Trivi            mPolicyToken = token;
59680212be5150fb9fb3c340f3c7e51f6126372cc6f9Jean-Michel Trivi            mHasFocusListener = hasFocusListener;
59690212be5150fb9fb3c340f3c7e51f6126372cc6f9Jean-Michel Trivi            if (mHasFocusListener) {
59700212be5150fb9fb3c340f3c7e51f6126372cc6f9Jean-Michel Trivi                mMediaFocusControl.addFocusFollower(mPolicyToken);
59710212be5150fb9fb3c340f3c7e51f6126372cc6f9Jean-Michel Trivi            }
59727f5eb9fe3c10d8d83ff0e2b0fc60a05c2e6d5b02Eric Laurent            connectMixes();
5973a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi        }
5974a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi
5975a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi        public void binderDied() {
5976a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi            synchronized (mAudioPolicies) {
59770212be5150fb9fb3c340f3c7e51f6126372cc6f9Jean-Michel Trivi                Log.i(TAG, "audio policy " + mPolicyToken + " died");
59780212be5150fb9fb3c340f3c7e51f6126372cc6f9Jean-Michel Trivi                release();
59790212be5150fb9fb3c340f3c7e51f6126372cc6f9Jean-Michel Trivi                mAudioPolicies.remove(mPolicyToken.asBinder());
59808fdb0d4defb6ee2ca8057d3442ead36b408b6c17Jean-Michel Trivi            }
59818fdb0d4defb6ee2ca8057d3442ead36b408b6c17Jean-Michel Trivi        }
59828fdb0d4defb6ee2ca8057d3442ead36b408b6c17Jean-Michel Trivi
59830212be5150fb9fb3c340f3c7e51f6126372cc6f9Jean-Michel Trivi        String getRegistrationId() {
59841b3541d5eedb332ea01066b4a78a2d06d5304044Jean-Michel Trivi            return getRegistration();
59858fdb0d4defb6ee2ca8057d3442ead36b408b6c17Jean-Michel Trivi        }
59868fdb0d4defb6ee2ca8057d3442ead36b408b6c17Jean-Michel Trivi
59870212be5150fb9fb3c340f3c7e51f6126372cc6f9Jean-Michel Trivi        void release() {
59880212be5150fb9fb3c340f3c7e51f6126372cc6f9Jean-Michel Trivi            if (mFocusDuckBehavior == AudioPolicy.FOCUS_POLICY_DUCKING_IN_POLICY) {
59890212be5150fb9fb3c340f3c7e51f6126372cc6f9Jean-Michel Trivi                mMediaFocusControl.setDuckingInExtPolicyAvailable(false);
59900212be5150fb9fb3c340f3c7e51f6126372cc6f9Jean-Michel Trivi            }
59910212be5150fb9fb3c340f3c7e51f6126372cc6f9Jean-Michel Trivi            if (mHasFocusListener) {
59920212be5150fb9fb3c340f3c7e51f6126372cc6f9Jean-Michel Trivi                mMediaFocusControl.removeFocusFollower(mPolicyToken);
59930212be5150fb9fb3c340f3c7e51f6126372cc6f9Jean-Michel Trivi            }
59947f5eb9fe3c10d8d83ff0e2b0fc60a05c2e6d5b02Eric Laurent            AudioSystem.registerPolicyMixes(mMixes, false);
59958fdb0d4defb6ee2ca8057d3442ead36b408b6c17Jean-Michel Trivi        }
59968fdb0d4defb6ee2ca8057d3442ead36b408b6c17Jean-Michel Trivi
59977f5eb9fe3c10d8d83ff0e2b0fc60a05c2e6d5b02Eric Laurent        void connectMixes() {
59987f5eb9fe3c10d8d83ff0e2b0fc60a05c2e6d5b02Eric Laurent            AudioSystem.registerPolicyMixes(mMixes, true);
5999a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi        }
6000a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi    };
6001a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi
6002a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi    private HashMap<IBinder, AudioPolicyProxy> mAudioPolicies =
6003a8b6bd88cfb010c9e9aa1339e504fd593919e1e0Jean-Michel Trivi            new HashMap<IBinder, AudioPolicyProxy>();
60048fdb0d4defb6ee2ca8057d3442ead36b408b6c17Jean-Michel Trivi    private int mAudioPolicyCounter = 0; // always accessed synchronized on mAudioPolicies
60059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
6006