AudioService.java revision f2b0c11f4e797e183131261724d8de310dac5431
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
24c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Triviimport android.app.Activity;
259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.app.ActivityManagerNative;
266243edd818b84adfbe712d5d233d6414b33653acAmith Yamasaniimport android.app.KeyguardManager;
27f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Triviimport android.app.PendingIntent;
28f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Triviimport android.app.PendingIntent.CanceledException;
29c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Triviimport android.app.PendingIntent.OnFinished;
3082aa7f017daaaeb96c13e6e3491d5037ab471085Jaikumar Ganeshimport android.bluetooth.BluetoothA2dp;
3182aa7f017daaaeb96c13e6e3491d5037ab471085Jaikumar Ganeshimport android.bluetooth.BluetoothAdapter;
3282aa7f017daaaeb96c13e6e3491d5037ab471085Jaikumar Ganeshimport android.bluetooth.BluetoothClass;
3382aa7f017daaaeb96c13e6e3491d5037ab471085Jaikumar Ganeshimport android.bluetooth.BluetoothDevice;
3482aa7f017daaaeb96c13e6e3491d5037ab471085Jaikumar Ganeshimport android.bluetooth.BluetoothHeadset;
3582aa7f017daaaeb96c13e6e3491d5037ab471085Jaikumar Ganeshimport android.bluetooth.BluetoothProfile;
364294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Triviimport android.content.ActivityNotFoundException;
37bd022f423a33f0794bb53e5b0720da2d67e4631cNick Pellyimport android.content.BroadcastReceiver;
38d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Triviimport android.content.ComponentName;
399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.ContentResolver;
409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.Context;
419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.Intent;
42a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurentimport android.content.IntentFilter;
439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.pm.PackageManager;
44f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Triviimport android.content.res.Configuration;
45b109615ebebd6f3b9ae789412279f576c3ace46bJason Parekhimport android.database.ContentObserver;
469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.media.MediaPlayer.OnCompletionListener;
479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.media.MediaPlayer.OnErrorListener;
489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.Binder;
49f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Triviimport android.os.Bundle;
509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.Environment;
519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.Handler;
529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.IBinder;
539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.Looper;
549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.Message;
55c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Triviimport android.os.PowerManager;
56632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackbornimport android.os.RemoteCallbackList;
579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.RemoteException;
589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.ServiceManager;
5982aa7f017daaaeb96c13e6e3491d5037ab471085Jaikumar Ganeshimport android.os.SystemProperties;
60bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurentimport android.os.Vibrator;
619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.provider.Settings;
629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.provider.Settings.System;
633c2711fc2853394324b044632b79ca67388df8f4Jean-Michel Triviimport android.speech.RecognizerIntent;
64b4bccb6d8df16a2c5235cead187156bc721cf074Jean-Michel Triviimport android.telephony.PhoneStateListener;
65b4bccb6d8df16a2c5235cead187156bc721cf074Jean-Michel Triviimport android.telephony.TelephonyManager;
66632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackbornimport android.text.TextUtils;
679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.util.Log;
68d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Triviimport android.view.KeyEvent;
699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.view.VolumePanel;
709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport com.android.internal.telephony.ITelephony;
729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
73d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Triviimport java.io.FileDescriptor;
749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.io.IOException;
75d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Triviimport java.io.PrintWriter;
769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.ArrayList;
773172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurentimport java.util.concurrent.ConcurrentHashMap;
78c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurentimport java.util.HashMap;
79c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurentimport java.util.Iterator;
805a1e4cf83f5be1b5d79e2643fa791aa269b6a4bcJaikumar Ganeshimport java.util.List;
81c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurentimport java.util.Map;
8282aa7f017daaaeb96c13e6e3491d5037ab471085Jaikumar Ganeshimport java.util.NoSuchElementException;
83c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurentimport java.util.Set;
84d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Triviimport java.util.Stack;
859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/**
879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * The implementation of the volume manager service.
889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * <p>
899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * This implementation focuses on delivering a responsive UI. Most methods are
909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * asynchronous to external calls. For example, the task of setting a volume
919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * will update our internal state, but in a separate thread will set the system
929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * volume and later persist to the database. Similarly, setting the ringer mode
939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * will update the state and broadcast a change and in a separate thread later
949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * persist the ringer mode.
959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @hide
979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */
98c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivipublic class AudioService extends IAudioService.Stub implements OnFinished {
999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final String TAG = "AudioService";
1019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10218e7bce52318f00b5023f33933a571c477f2b61cJean-Michel Trivi    /** Debug remote control client/display feature */
1037ff866e8cf43afc64111e98863dab549b57447b4Jean-Michel Trivi    protected static final boolean DEBUG_RC = false;
1043114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    /** Debug volumes */
1053114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    protected static final boolean DEBUG_VOL = false;
10618e7bce52318f00b5023f33933a571c477f2b61cJean-Michel Trivi
1079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** How long to delay before persisting a change in volume/ringer mode. */
10845edba1b8b0377dfe70a4f2b0afb0f04dd8e1ee9RoboErik    private static final int PERSIST_DELAY = 500;
1099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private Context mContext;
1119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private ContentResolver mContentResolver;
112c7fcba4b7bd3d78e7cfe975a3f8e4dde2f6738b7Joe Onorato    private boolean mVoiceCapable;
113d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi
1149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** The UI */
1159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private VolumePanel mVolumePanel;
1169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // sendMsg() flags
1189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** If the msg is already queued, replace it with this one. */
1199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final int SENDMSG_REPLACE = 0;
1209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** If the msg is already queued, ignore this one and leave the old. */
1219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final int SENDMSG_NOOP = 1;
1229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** If the msg is already queued, queue this one and leave the old. */
1239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final int SENDMSG_QUEUE = 2;
1249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1253114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    // AudioHandler messages
1269bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent    private static final int MSG_SET_DEVICE_VOLUME = 0;
1279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final int MSG_PERSIST_VOLUME = 1;
1285c55a051ad7d86a464fb91426f1ea3c0250e38b3Mike Lockwood    private static final int MSG_PERSIST_MASTER_VOLUME = 2;
1299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final int MSG_PERSIST_RINGER_MODE = 3;
130bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent    private static final int MSG_MEDIA_SERVER_DIED = 4;
131bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent    private static final int MSG_MEDIA_SERVER_STARTED = 5;
132bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent    private static final int MSG_PLAY_SOUND_EFFECT = 6;
133bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent    private static final int MSG_BTA2DP_DOCK_TIMEOUT = 7;
134bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent    private static final int MSG_LOAD_SOUND_EFFECTS = 8;
135bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent    private static final int MSG_SET_FORCE_USE = 9;
136bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent    private static final int MSG_PERSIST_MEDIABUTTONRECEIVER = 10;
137bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent    private static final int MSG_BT_HEADSET_CNCT_FAILED = 11;
138bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent    private static final int MSG_RCDISPLAY_CLEAR = 12;
139bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent    private static final int MSG_RCDISPLAY_UPDATE = 13;
140bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent    private static final int MSG_SET_ALL_VOLUMES = 14;
141bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent    private static final int MSG_PERSIST_MASTER_VOLUME_MUTE = 15;
142632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn    private static final int MSG_REPORT_NEW_ROUTES = 16;
1433114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    private static final int MSG_REEVALUATE_REMOTE = 17;
144f98de1e8dd6dcbd191921b4aa07a1d41b0b9db91Jean-Michel Trivi    private static final int MSG_RCC_NEW_PLAYBACK_INFO = 18;
145f98de1e8dd6dcbd191921b4aa07a1d41b0b9db91Jean-Michel Trivi    private static final int MSG_RCC_NEW_VOLUME_OBS = 19;
146c390bed06b4a572e273ead1254da9a932e04dce3Eric Laurent    private static final int MSG_SET_FORCE_BT_A2DP_USE = 20;
1473114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    // start of messages handled under wakelock
1483114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    //   these messages can only be queued, i.e. sent with queueMsgUnderWakeLock(),
149e12c39bb9cedb8b363658979872694eb55b1386eJean-Michel Trivi    //   and not with sendMsg(..., ..., SENDMSG_QUEUE, ...)
150c390bed06b4a572e273ead1254da9a932e04dce3Eric Laurent    private static final int MSG_SET_WIRED_DEVICE_CONNECTION_STATE = 21;
151c390bed06b4a572e273ead1254da9a932e04dce3Eric Laurent    private static final int MSG_SET_A2DP_CONNECTION_STATE = 22;
1523114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    // end of messages handled under wakelock
153afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent
154afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent    // flags for MSG_PERSIST_VOLUME indicating if current and/or last audible volume should be
155afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent    // persisted
156afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent    private static final int PERSIST_CURRENT = 0x1;
157afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent    private static final int PERSIST_LAST_AUDIBLE = 0x2;
158afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent
1594c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi    private static final int BTA2DP_DOCK_TIMEOUT_MILLIS = 8000;
160dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent    // Timeout for connection to bluetooth headset service
161dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent    private static final int BT_HEADSET_CNCT_TIMEOUT_MS = 3000;
162dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent
1639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** @see AudioSystemThread */
1649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private AudioSystemThread mAudioSystemThread;
1659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** @see AudioHandler */
1669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private AudioHandler mAudioHandler;
1679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** @see VolumeStreamState */
1689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private VolumeStreamState[] mStreamStates;
169b109615ebebd6f3b9ae789412279f576c3ace46bJason Parekh    private SettingsObserver mSettingsObserver;
170a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent
1719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private int mMode;
172ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten    // protects mRingerMode
173ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten    private final Object mSettingsLock = new Object();
17445c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent
1759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private boolean mMediaServerOk;
1769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private SoundPool mSoundPool;
17830c918ce7fbe171944b28fc91b3f22b3d631872dGlenn Kasten    private final Object mSoundEffectsLock = new Object();
1799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final int NUM_SOUNDPOOL_CHANNELS = 4;
1809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1814767690f09ea3447b8c5c32fb28d27650aa18e00Mike Lockwood    // Internally master volume is a float in the 0.0 - 1.0 range,
1824767690f09ea3447b8c5c32fb28d27650aa18e00Mike Lockwood    // but to support integer based AudioManager API we translate it to 0 - 100
1834767690f09ea3447b8c5c32fb28d27650aa18e00Mike Lockwood    private static final int MAX_MASTER_VOLUME = 100;
1844767690f09ea3447b8c5c32fb28d27650aa18e00Mike Lockwood
1856c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang    // Maximum volume adjust steps allowed in a single batch call.
1866c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang    private static final int MAX_BATCH_VOLUME_ADJUST_STEPS = 4;
1876c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang
1889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /* Sound effect file names  */
1899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final String SOUND_EFFECTS_PATH = "/media/audio/ui/";
1909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final String[] SOUND_EFFECT_FILES = new String[] {
1919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        "Effect_Tick.ogg",
1929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        "KeypressStandard.ogg",
1939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        "KeypressSpacebar.ogg",
1949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        "KeypressDelete.ogg",
1959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        "KeypressReturn.ogg"
1969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    };
1979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /* Sound effect file name mapping sound effect id (AudioManager.FX_xxx) to
1999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * file index in SOUND_EFFECT_FILES[] (first column) and indicating if effect
2009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * uses soundpool (second column) */
20130c918ce7fbe171944b28fc91b3f22b3d631872dGlenn Kasten    private final int[][] SOUND_EFFECT_FILES_MAP = new int[][] {
2029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        {0, -1},  // FX_KEY_CLICK
2039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        {0, -1},  // FX_FOCUS_NAVIGATION_UP
2049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        {0, -1},  // FX_FOCUS_NAVIGATION_DOWN
2059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        {0, -1},  // FX_FOCUS_NAVIGATION_LEFT
2069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        {0, -1},  // FX_FOCUS_NAVIGATION_RIGHT
2079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        {1, -1},  // FX_KEYPRESS_STANDARD
2089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        {2, -1},  // FX_KEYPRESS_SPACEBAR
2099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        {3, -1},  // FX_FOCUS_DELETE
2109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        {4, -1}   // FX_FOCUS_RETURN
2119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    };
2129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2135982013cfc8274ff0bafaba83c676b3a8890cba9Jared Suttles   /** @hide Maximum volume index values for audio streams */
21430c918ce7fbe171944b28fc91b3f22b3d631872dGlenn Kasten    private final int[] MAX_STREAM_VOLUME = new int[] {
2156ee9952bc20be72b9419cb653c9e2e833889a3d3Eric Laurent        5,  // STREAM_VOICE_CALL
2166ee9952bc20be72b9419cb653c9e2e833889a3d3Eric Laurent        7,  // STREAM_SYSTEM
2176ee9952bc20be72b9419cb653c9e2e833889a3d3Eric Laurent        7,  // STREAM_RING
2186ee9952bc20be72b9419cb653c9e2e833889a3d3Eric Laurent        15, // STREAM_MUSIC
2196ee9952bc20be72b9419cb653c9e2e833889a3d3Eric Laurent        7,  // STREAM_ALARM
2206ee9952bc20be72b9419cb653c9e2e833889a3d3Eric Laurent        7,  // STREAM_NOTIFICATION
2216ee9952bc20be72b9419cb653c9e2e833889a3d3Eric Laurent        15, // STREAM_BLUETOOTH_SCO
2226ee9952bc20be72b9419cb653c9e2e833889a3d3Eric Laurent        7,  // STREAM_SYSTEM_ENFORCED
2236ee9952bc20be72b9419cb653c9e2e833889a3d3Eric Laurent        15, // STREAM_DTMF
2246ee9952bc20be72b9419cb653c9e2e833889a3d3Eric Laurent        15  // STREAM_TTS
2255982013cfc8274ff0bafaba83c676b3a8890cba9Jared Suttles    };
2266d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent    /* mStreamVolumeAlias[] indicates for each stream if it uses the volume settings
227a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent     * of another stream: This avoids multiplying the volume settings for hidden
228a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent     * stream types that follow other stream behavior for volume settings
2296d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent     * NOTE: do not create loops in aliases!
2306d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent     * Some streams alias to different streams according to device category (phone or tablet) or
2316d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent     * use case (in call s off call...).See updateStreamVolumeAlias() for more details
2326d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent     *  mStreamVolumeAlias contains the default aliases for a voice capable device (phone) and
2336d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent     *  STREAM_VOLUME_ALIAS_NON_VOICE for a non voice capable device (tablet).*/
23430c918ce7fbe171944b28fc91b3f22b3d631872dGlenn Kasten    private final int[] STREAM_VOLUME_ALIAS = new int[] {
2356d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent        AudioSystem.STREAM_VOICE_CALL,      // STREAM_VOICE_CALL
2366d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent        AudioSystem.STREAM_RING,            // STREAM_SYSTEM
2376d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent        AudioSystem.STREAM_RING,            // STREAM_RING
2386d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent        AudioSystem.STREAM_MUSIC,           // STREAM_MUSIC
2396d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent        AudioSystem.STREAM_ALARM,           // STREAM_ALARM
2406d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent        AudioSystem.STREAM_RING,            // STREAM_NOTIFICATION
2416d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent        AudioSystem.STREAM_BLUETOOTH_SCO,   // STREAM_BLUETOOTH_SCO
2426d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent        AudioSystem.STREAM_RING,            // STREAM_SYSTEM_ENFORCED
2436d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent        AudioSystem.STREAM_RING,            // STREAM_DTMF
2446d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent        AudioSystem.STREAM_MUSIC            // STREAM_TTS
245a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent    };
2466d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent    private final int[] STREAM_VOLUME_ALIAS_NON_VOICE = new int[] {
2476d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent        AudioSystem.STREAM_VOICE_CALL,      // STREAM_VOICE_CALL
2486d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent        AudioSystem.STREAM_MUSIC,           // STREAM_SYSTEM
2496d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent        AudioSystem.STREAM_RING,            // STREAM_RING
2506d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent        AudioSystem.STREAM_MUSIC,           // STREAM_MUSIC
2516d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent        AudioSystem.STREAM_ALARM,           // STREAM_ALARM
2526d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent        AudioSystem.STREAM_RING,            // STREAM_NOTIFICATION
2536d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent        AudioSystem.STREAM_BLUETOOTH_SCO,   // STREAM_BLUETOOTH_SCO
2546d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent        AudioSystem.STREAM_MUSIC,           // STREAM_SYSTEM_ENFORCED
2556d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent        AudioSystem.STREAM_MUSIC,           // STREAM_DTMF
2566d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent        AudioSystem.STREAM_MUSIC            // STREAM_TTS
2576d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent    };
2586d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent    private int[] mStreamVolumeAlias;
259a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent
260bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent    // stream names used by dumpStreamStates()
261bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent    private final String[] STREAM_NAMES = new String[] {
262bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent            "STREAM_VOICE_CALL",
263bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent            "STREAM_SYSTEM",
264bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent            "STREAM_RING",
265bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent            "STREAM_MUSIC",
266bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent            "STREAM_ALARM",
267bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent            "STREAM_NOTIFICATION",
268bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent            "STREAM_BLUETOOTH_SCO",
269bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent            "STREAM_SYSTEM_ENFORCED",
270bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent            "STREAM_DTMF",
271bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent            "STREAM_TTS"
272bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent    };
273bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent
27430c918ce7fbe171944b28fc91b3f22b3d631872dGlenn Kasten    private final AudioSystem.ErrorCallback mAudioSystemCallback = new AudioSystem.ErrorCallback() {
2759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public void onError(int error) {
2769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            switch (error) {
2779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            case AudioSystem.AUDIO_STATUS_SERVER_DIED:
2789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (mMediaServerOk) {
279afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent                    sendMsg(mAudioHandler, MSG_MEDIA_SERVER_DIED, SENDMSG_NOOP, 0, 0,
2809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            null, 1500);
28189e74ba1419732dd5c7f939e48d4aa7989fd3a51Eric Laurent                    mMediaServerOk = false;
2829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
2839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                break;
2849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            case AudioSystem.AUDIO_STATUS_OK:
2859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (!mMediaServerOk) {
286afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent                    sendMsg(mAudioHandler, MSG_MEDIA_SERVER_STARTED, SENDMSG_NOOP, 0, 0,
2879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            null, 0);
28889e74ba1419732dd5c7f939e48d4aa7989fd3a51Eric Laurent                    mMediaServerOk = true;
2899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
2909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                break;
2919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            default:
2929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                break;
2939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
2949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project       }
2959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    };
2969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
2989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Current ringer mode from one of {@link AudioManager#RINGER_MODE_NORMAL},
2999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * {@link AudioManager#RINGER_MODE_SILENT}, or
3009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * {@link AudioManager#RINGER_MODE_VIBRATE}.
3019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
302ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten    // protected by mSettingsLock
3039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private int mRingerMode;
3049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3059bcf401d13d47416043a704430388abd59aef7cdEric Laurent    /** @see System#MODE_RINGER_STREAMS_AFFECTED */
3069bcf401d13d47416043a704430388abd59aef7cdEric Laurent    private int mRingerModeAffectedStreams;
3079bcf401d13d47416043a704430388abd59aef7cdEric Laurent
3085b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent    // Streams currently muted by ringer mode
3095b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent    private int mRingerModeMutedStreams;
3105b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent
3119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** @see System#MUTE_STREAMS_AFFECTED */
3129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private int mMuteAffectedStreams;
3139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
315bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent     * NOTE: setVibrateSetting(), getVibrateSetting(), shouldVibrate() are deprecated.
316bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent     * mVibrateSetting is just maintained during deprecation period but vibration policy is
317bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent     * now only controlled by mHasVibrator and mRingerMode
3189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
3199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private int mVibrateSetting;
3209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
321bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent    // Is there a vibrator
322bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent    private final boolean mHasVibrator;
323bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent
324a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent    // Broadcast receiver for device connections intent broadcasts
325a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent    private final BroadcastReceiver mReceiver = new AudioServiceBroadcastReceiver();
326a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent
327e73131a68408a0495ba96a4d5a60799ba293c176Jean-Michel Trivi    // Used to alter media button redirection when the phone is ringing.
328e73131a68408a0495ba96a4d5a60799ba293c176Jean-Michel Trivi    private boolean mIsRinging = false;
329e73131a68408a0495ba96a4d5a60799ba293c176Jean-Michel Trivi
330c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent    // Devices currently connected
33130c918ce7fbe171944b28fc91b3f22b3d631872dGlenn Kasten    private final HashMap <Integer, String> mConnectedDevices = new HashMap <Integer, String>();
332c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent
333c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent    // Forced device usage for communications
334c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent    private int mForcedUseForComm;
335c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent
3360dc37cce9d564ae43883c8dc8672b9266b881e63Mike Lockwood    // True if we have master volume support
3370dc37cce9d564ae43883c8dc8672b9266b881e63Mike Lockwood    private final boolean mUseMasterVolume;
3380dc37cce9d564ae43883c8dc8672b9266b881e63Mike Lockwood
3399760647dd0ee67e7c20f3e9d661d2006b1df0b54Mike Lockwood    private final int[] mMasterVolumeRamp;
3409760647dd0ee67e7c20f3e9d661d2006b1df0b54Mike Lockwood
3419272b4b4a44fe1f33e3030810618194f817caaecEric Laurent    // List of binder death handlers for setMode() client processes.
3429272b4b4a44fe1f33e3030810618194f817caaecEric Laurent    // The last process to have called setMode() is at the top of the list.
34330c918ce7fbe171944b28fc91b3f22b3d631872dGlenn Kasten    private final ArrayList <SetModeDeathHandler> mSetModeDeathHandlers = new ArrayList <SetModeDeathHandler>();
344eb14a783be073b5fd6e8c8c9bc87d2d1919f2c9eEric Laurent
3453def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent    // List of clients having issued a SCO start request
34630c918ce7fbe171944b28fc91b3f22b3d631872dGlenn Kasten    private final ArrayList <ScoClient> mScoClients = new ArrayList <ScoClient>();
3473def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent
3483def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent    // BluetoothHeadset API to control SCO connection
3493def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent    private BluetoothHeadset mBluetoothHeadset;
3503def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent
35182aa7f017daaaeb96c13e6e3491d5037ab471085Jaikumar Ganesh    // Bluetooth headset device
35282aa7f017daaaeb96c13e6e3491d5037ab471085Jaikumar Ganesh    private BluetoothDevice mBluetoothHeadsetDevice;
3533def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent
35462ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent    // Indicate if SCO audio connection is currently active and if the initiator is
35562ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent    // audio service (internal) or bluetooth headset (external)
35662ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent    private int mScoAudioState;
35762ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent    // SCO audio state is not active
35862ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent    private static final int SCO_STATE_INACTIVE = 0;
359dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent    // SCO audio activation request waiting for headset service to connect
360dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent    private static final int SCO_STATE_ACTIVATE_REQ = 1;
36162ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent    // SCO audio state is active or starting due to a local request to start a virtual call
362dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent    private static final int SCO_STATE_ACTIVE_INTERNAL = 3;
363dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent    // SCO audio deactivation request waiting for headset service to connect
364dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent    private static final int SCO_STATE_DEACTIVATE_REQ = 5;
365dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent
36662ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent    // SCO audio state is active due to an action in BT handsfree (either voice recognition or
36762ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent    // in call audio)
36862ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent    private static final int SCO_STATE_ACTIVE_EXTERNAL = 2;
369dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent    // Deactivation request for all SCO connections (initiated by audio mode change)
370dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent    // waiting for headset service to connect
371dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent    private static final int SCO_STATE_DEACTIVATE_EXT_REQ = 4;
372dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent
373dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent    // Current connection state indicated by bluetooth headset
374dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent    private int mScoConnectionState;
37562ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent
376a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent    // true if boot sequence has been completed
377a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent    private boolean mBootCompleted;
378a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent    // listener for SoundPool sample load completion indication
379a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent    private SoundPoolCallback mSoundPoolCallBack;
380a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent    // thread for SoundPool listener
381a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent    private SoundPoolListenerThread mSoundPoolListenerThread;
382a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent    // message looper for SoundPool listener
383a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent    private Looper mSoundPoolLooper = null;
384c55b393efd462490cd5e27fc373bceafdd25662eJean-Michel Trivi    // volume applied to sound played with playSoundEffect()
385f2b0c11f4e797e183131261724d8de310dac5431Jean-Michel Trivi    private static int sSoundEffectVolumeDb;
38625101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent    // getActiveStreamType() will return STREAM_NOTIFICATION during this period after a notification
38725101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent    // stopped
38825101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent    private static final int NOTIFICATION_VOLUME_DELAY_MS = 5000;
38925101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent    // previous volume adjustment direction received by checkForRingerModeChange()
39025101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent    private int mPrevVolDirection = AudioManager.ADJUST_SAME;
3916243edd818b84adfbe712d5d233d6414b33653acAmith Yamasani    // Keyguard manager proxy
3926243edd818b84adfbe712d5d233d6414b33653acAmith Yamasani    private KeyguardManager mKeyguardManager;
39345c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent    // mVolumeControlStream is set by VolumePanel to temporarily force the stream type which volume
39445c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent    // is controlled by Vol keys.
39545c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent    private int  mVolumeControlStream = -1;
39645c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent    private final Object mForceControlStreamLock = new Object();
39745c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent    // VolumePanel is currently the only client of forceVolumeControlStream() and runs in system
39845c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent    // server process so in theory it is not necessary to monitor the client death.
39945c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent    // However it is good to be ready for future evolutions.
40045c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent    private ForceControlStreamClient mForceControlStreamClient = null;
401098d580cc2bb6c0891c756a4e5230c6c6b0d2376Jeff Sharkey    // Used to play ringtones outside system_server
402098d580cc2bb6c0891c756a4e5230c6c6b0d2376Jeff Sharkey    private volatile IRingtonePlayer mRingtonePlayer;
4039bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent
404f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi    private int mDeviceOrientation = Configuration.ORIENTATION_UNDEFINED;
405f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi
4067847211fb4699bf6018e29d214a918ed6657319bEric Laurent    // Request to override default use of A2DP for media.
4077847211fb4699bf6018e29d214a918ed6657319bEric Laurent    private boolean mBluetoothA2dpEnabled;
4087847211fb4699bf6018e29d214a918ed6657319bEric Laurent    private final Object mBluetoothA2dpEnabledLock = new Object();
4097847211fb4699bf6018e29d214a918ed6657319bEric Laurent
410632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn    // Monitoring of audio routes.  Protected by mCurAudioRoutes.
411632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn    final AudioRoutesInfo mCurAudioRoutes = new AudioRoutesInfo();
412632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn    final RemoteCallbackList<IAudioRoutesObserver> mRoutesObservers
413632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn            = new RemoteCallbackList<IAudioRoutesObserver>();
414632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn
4153114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    /**
4163114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     * A fake stream type to match the notion of remote media playback
4173114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     */
4183114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    public final static int STREAM_REMOTE_MUSIC = -200;
4193114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi
4209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    ///////////////////////////////////////////////////////////////////////////
4219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // Construction
4229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    ///////////////////////////////////////////////////////////////////////////
4239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** @hide */
4259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public AudioService(Context context) {
4269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext = context;
4279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContentResolver = context.getContentResolver();
428c7fcba4b7bd3d78e7cfe975a3f8e4dde2f6738b7Joe Onorato        mVoiceCapable = mContext.getResources().getBoolean(
429c7fcba4b7bd3d78e7cfe975a3f8e4dde2f6738b7Joe Onorato                com.android.internal.R.bool.config_voice_capable);
4305982013cfc8274ff0bafaba83c676b3a8890cba9Jared Suttles
431c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi        PowerManager pm = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
4322d8dab5a549b25b6f36df4614d7c0166d4d099e2Jean-Michel Trivi        mMediaEventWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "handleMediaEvent");
433c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi
434bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent        Vibrator vibrator = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE);
435bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent        mHasVibrator = vibrator == null ? false : vibrator.hasVibrator();
436bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent
4375982013cfc8274ff0bafaba83c676b3a8890cba9Jared Suttles       // Intialized volume
4385982013cfc8274ff0bafaba83c676b3a8890cba9Jared Suttles        MAX_STREAM_VOLUME[AudioSystem.STREAM_VOICE_CALL] = SystemProperties.getInt(
4395982013cfc8274ff0bafaba83c676b3a8890cba9Jared Suttles            "ro.config.vc_call_vol_steps",
4405982013cfc8274ff0bafaba83c676b3a8890cba9Jared Suttles           MAX_STREAM_VOLUME[AudioSystem.STREAM_VOICE_CALL]);
4415982013cfc8274ff0bafaba83c676b3a8890cba9Jared Suttles
442f2b0c11f4e797e183131261724d8de310dac5431Jean-Michel Trivi        sSoundEffectVolumeDb = context.getResources().getInteger(
443c55b393efd462490cd5e27fc373bceafdd25662eJean-Michel Trivi                com.android.internal.R.integer.config_soundEffectVolumeDb);
44425101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent
4459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mVolumePanel = new VolumePanel(context, this);
4466d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent        mMode = AudioSystem.MODE_NORMAL;
447c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent        mForcedUseForComm = AudioSystem.FORCE_NONE;
4489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        createAudioSystemThread();
4499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        readPersistedSettings();
450c1d4166289ce016965d1147f7e8d37862ee347ecEric Laurent        mSettingsObserver = new SettingsObserver();
4516d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent        updateStreamVolumeAlias(false /*updateVolumes*/);
452a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent        createStreamStates();
4539f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent
4549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mMediaServerOk = true;
4553891c4cc918e8062abb97c542a8625d556dccc59Eric Laurent
4563891c4cc918e8062abb97c542a8625d556dccc59Eric Laurent        // Call setRingerModeInt() to apply correct mute
4573891c4cc918e8062abb97c542a8625d556dccc59Eric Laurent        // state on streams affected by ringer mode.
4583891c4cc918e8062abb97c542a8625d556dccc59Eric Laurent        mRingerModeMutedStreams = 0;
4593891c4cc918e8062abb97c542a8625d556dccc59Eric Laurent        setRingerModeInt(getRingerMode(), false);
4603891c4cc918e8062abb97c542a8625d556dccc59Eric Laurent
4619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        AudioSystem.setErrorCallback(mAudioSystemCallback);
462a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent
463a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent        // Register for device connection intent broadcasts.
464a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent        IntentFilter intentFilter =
465b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent                new IntentFilter(BluetoothHeadset.ACTION_AUDIO_STATE_CHANGED);
46682aa7f017daaaeb96c13e6e3491d5037ab471085Jaikumar Ganesh        intentFilter.addAction(BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED);
46782aa7f017daaaeb96c13e6e3491d5037ab471085Jaikumar Ganesh        intentFilter.addAction(Intent.ACTION_DOCK_EVENT);
46859f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent        intentFilter.addAction(Intent.ACTION_USB_AUDIO_ACCESSORY_PLUG);
46959f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent        intentFilter.addAction(Intent.ACTION_USB_AUDIO_DEVICE_PLUG);
47062ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent        intentFilter.addAction(Intent.ACTION_BOOT_COMPLETED);
471950e8cb40a6d826af4cc2eef9d3908c1b70486e6Eric Laurent        intentFilter.addAction(Intent.ACTION_SCREEN_ON);
472950e8cb40a6d826af4cc2eef9d3908c1b70486e6Eric Laurent        intentFilter.addAction(Intent.ACTION_SCREEN_OFF);
473f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi
474f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi        // Register a configuration change listener only if requested by system properties
475f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi        // to monitor orientation changes (off by default)
476f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi        if (SystemProperties.getBoolean("ro.audio.monitorOrientation", false)) {
477f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi            Log.v(TAG, "monitoring device orientation");
478f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi            intentFilter.addAction(Intent.ACTION_CONFIGURATION_CHANGED);
479f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi            // initialize orientation in AudioSystem
480f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi            setOrientationForAudioSystem();
481f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi        }
482f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi
483a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent        context.registerReceiver(mReceiver, intentFilter);
4845982013cfc8274ff0bafaba83c676b3a8890cba9Jared Suttles
485d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi        // Register for package removal intent broadcasts for media button receiver persistence
486d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi        IntentFilter pkgFilter = new IntentFilter();
487d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi        pkgFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
488d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi        pkgFilter.addDataScheme("package");
489d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi        context.registerReceiver(mReceiver, pkgFilter);
490d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi
491b4bccb6d8df16a2c5235cead187156bc721cf074Jean-Michel Trivi        // Register for phone state monitoring
492b4bccb6d8df16a2c5235cead187156bc721cf074Jean-Michel Trivi        TelephonyManager tmgr = (TelephonyManager)
493b4bccb6d8df16a2c5235cead187156bc721cf074Jean-Michel Trivi                context.getSystemService(Context.TELEPHONY_SERVICE);
494b4bccb6d8df16a2c5235cead187156bc721cf074Jean-Michel Trivi        tmgr.listen(mPhoneStateListener, PhoneStateListener.LISTEN_CALL_STATE);
4958517e46f3d3c2ce11de09aa849a8533ffc1a2026Mike Lockwood
4960dc37cce9d564ae43883c8dc8672b9266b881e63Mike Lockwood        mUseMasterVolume = context.getResources().getBoolean(
4970dc37cce9d564ae43883c8dc8672b9266b881e63Mike Lockwood                com.android.internal.R.bool.config_useMasterVolume);
4989063154a793b0ab38b3c5992cbaed046427b4a82Mike Lockwood        restoreMasterVolume();
4999760647dd0ee67e7c20f3e9d661d2006b1df0b54Mike Lockwood
5009760647dd0ee67e7c20f3e9d661d2006b1df0b54Mike Lockwood        mMasterVolumeRamp = context.getResources().getIntArray(
5019760647dd0ee67e7c20f3e9d661d2006b1df0b54Mike Lockwood                com.android.internal.R.array.config_masterVolumeRamp);
5027847211fb4699bf6018e29d214a918ed6657319bEric Laurent
5033114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        mMainRemote = new RemotePlaybackState(-1, MAX_STREAM_VOLUME[AudioManager.STREAM_MUSIC],
5043114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                MAX_STREAM_VOLUME[AudioManager.STREAM_MUSIC]);
5053114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        mHasRemotePlayback = false;
5063114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        mMainRemoteIsActive = false;
5073114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        postReevaluateRemote();
5089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
5099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private void createAudioSystemThread() {
5119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mAudioSystemThread = new AudioSystemThread();
5129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mAudioSystemThread.start();
5139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        waitForAudioHandlerCreation();
5149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
5159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** Waits for the volume handler to be created by the other thread. */
5179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private void waitForAudioHandlerCreation() {
5189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        synchronized(this) {
5199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            while (mAudioHandler == null) {
5209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                try {
5219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    // Wait for mAudioHandler to be set by the other thread
5229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    wait();
5239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                } catch (InterruptedException e) {
5249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    Log.e(TAG, "Interrupted while waiting on volume handler.");
5259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
5269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
5279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
5289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
5299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
530244820185269991186d07068b92985624cede4a5Eric Laurent    private void checkAllAliasStreamVolumes() {
531244820185269991186d07068b92985624cede4a5Eric Laurent        int numStreamTypes = AudioSystem.getNumStreamTypes();
532244820185269991186d07068b92985624cede4a5Eric Laurent        for (int streamType = 0; streamType < numStreamTypes; streamType++) {
533244820185269991186d07068b92985624cede4a5Eric Laurent            if (streamType != mStreamVolumeAlias[streamType]) {
534244820185269991186d07068b92985624cede4a5Eric Laurent                mStreamStates[streamType].
535244820185269991186d07068b92985624cede4a5Eric Laurent                                    setAllIndexes(mStreamStates[mStreamVolumeAlias[streamType]],
536244820185269991186d07068b92985624cede4a5Eric Laurent                                                  false /*lastAudible*/);
537244820185269991186d07068b92985624cede4a5Eric Laurent                mStreamStates[streamType].
538244820185269991186d07068b92985624cede4a5Eric Laurent                                    setAllIndexes(mStreamStates[mStreamVolumeAlias[streamType]],
539244820185269991186d07068b92985624cede4a5Eric Laurent                                                  true /*lastAudible*/);
540244820185269991186d07068b92985624cede4a5Eric Laurent            }
541244820185269991186d07068b92985624cede4a5Eric Laurent            // apply stream volume
542244820185269991186d07068b92985624cede4a5Eric Laurent            if (mStreamStates[streamType].muteCount() == 0) {
543244820185269991186d07068b92985624cede4a5Eric Laurent                mStreamStates[streamType].applyAllVolumes();
544244820185269991186d07068b92985624cede4a5Eric Laurent            }
545244820185269991186d07068b92985624cede4a5Eric Laurent        }
546244820185269991186d07068b92985624cede4a5Eric Laurent    }
547244820185269991186d07068b92985624cede4a5Eric Laurent
5489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private void createStreamStates() {
5499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int numStreamTypes = AudioSystem.getNumStreamTypes();
5509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        VolumeStreamState[] streams = mStreamStates = new VolumeStreamState[numStreamTypes];
5519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        for (int i = 0; i < numStreamTypes; i++) {
5536d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent            streams[i] = new VolumeStreamState(System.VOLUME_SETTINGS[mStreamVolumeAlias[i]], i);
5549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
5559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
556244820185269991186d07068b92985624cede4a5Eric Laurent        checkAllAliasStreamVolumes();
5579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
5589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
559bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent    private void dumpStreamStates(PrintWriter pw) {
560bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent        pw.println("\nStream volumes (device: index)");
561bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent        int numStreamTypes = AudioSystem.getNumStreamTypes();
562bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent        for (int i = 0; i < numStreamTypes; i++) {
563bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent            pw.println("- "+STREAM_NAMES[i]+":");
564bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent            mStreamStates[i].dump(pw);
565bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent            pw.println("");
566bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent        }
567bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent    }
568bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent
5696d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent
5706d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent    private void updateStreamVolumeAlias(boolean updateVolumes) {
5716d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent        int dtmfStreamAlias;
5726d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent        if (mVoiceCapable) {
5736d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent            mStreamVolumeAlias = STREAM_VOLUME_ALIAS;
5746d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent            dtmfStreamAlias = AudioSystem.STREAM_RING;
5756d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent        } else {
5766d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent            mStreamVolumeAlias = STREAM_VOLUME_ALIAS_NON_VOICE;
5776d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent            dtmfStreamAlias = AudioSystem.STREAM_MUSIC;
5786d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent        }
5796d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent        if (isInCommunication()) {
5806d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent            dtmfStreamAlias = AudioSystem.STREAM_VOICE_CALL;
5816d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent        }
5826d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent        mStreamVolumeAlias[AudioSystem.STREAM_DTMF] = dtmfStreamAlias;
5836d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent        if (updateVolumes) {
5846d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent            mStreamStates[AudioSystem.STREAM_DTMF].setAllIndexes(mStreamStates[dtmfStreamAlias],
5856d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent                                                                 false /*lastAudible*/);
5866d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent            mStreamStates[AudioSystem.STREAM_DTMF].setAllIndexes(mStreamStates[dtmfStreamAlias],
5876d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent                                                                 true /*lastAudible*/);
5886d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent            sendMsg(mAudioHandler,
5896d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent                    MSG_SET_ALL_VOLUMES,
5906d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent                    SENDMSG_QUEUE,
5916d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent                    0,
5926d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent                    0,
5936d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent                    mStreamStates[AudioSystem.STREAM_DTMF], 0);
5946d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent        }
5956d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent    }
5966d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent
5979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private void readPersistedSettings() {
5989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final ContentResolver cr = mContentResolver;
5999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
600bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent        int ringerModeFromSettings =
601bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent                System.getInt(cr, System.MODE_RINGER, AudioManager.RINGER_MODE_NORMAL);
602bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent        int ringerMode = ringerModeFromSettings;
60372668b2c040b581b298b069f3b5af5ed7f212d89Eric Laurent        // sanity check in case the settings are restored from a device with incompatible
60472668b2c040b581b298b069f3b5af5ed7f212d89Eric Laurent        // ringer modes
605ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten        if (!AudioManager.isValidRingerMode(ringerMode)) {
606ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten            ringerMode = AudioManager.RINGER_MODE_NORMAL;
607bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent        }
608bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent        if ((ringerMode == AudioManager.RINGER_MODE_VIBRATE) && !mHasVibrator) {
609bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent            ringerMode = AudioManager.RINGER_MODE_SILENT;
610bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent        }
611bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent        if (ringerMode != ringerModeFromSettings) {
612ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten            System.putInt(cr, System.MODE_RINGER, ringerMode);
613ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten        }
614ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten        synchronized(mSettingsLock) {
615ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten            mRingerMode = ringerMode;
61672668b2c040b581b298b069f3b5af5ed7f212d89Eric Laurent        }
6179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
618bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent        // System.VIBRATE_ON is not used any more but defaults for mVibrateSetting
619bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent        // are still needed while setVibrateSetting() and getVibrateSetting() are being deprecated.
620bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent        mVibrateSetting = getValueForVibrateSetting(0,
621bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent                                        AudioManager.VIBRATE_TYPE_NOTIFICATION,
622bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent                                        mHasVibrator ? AudioManager.VIBRATE_SETTING_ONLY_SILENT
623bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent                                                        : AudioManager.VIBRATE_SETTING_OFF);
624bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent        mVibrateSetting = getValueForVibrateSetting(mVibrateSetting,
625bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent                                        AudioManager.VIBRATE_TYPE_RINGER,
626bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent                                        mHasVibrator ? AudioManager.VIBRATE_SETTING_ONLY_SILENT
627bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent                                                        : AudioManager.VIBRATE_SETTING_OFF);
6289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
629c1d4166289ce016965d1147f7e8d37862ee347ecEric Laurent        // make sure settings for ringer mode are consistent with device type: non voice capable
630c1d4166289ce016965d1147f7e8d37862ee347ecEric Laurent        // devices (tablets) include media stream in silent mode whereas phones don't.
6319bcf401d13d47416043a704430388abd59aef7cdEric Laurent        mRingerModeAffectedStreams = Settings.System.getInt(cr,
6329bcf401d13d47416043a704430388abd59aef7cdEric Laurent                Settings.System.MODE_RINGER_STREAMS_AFFECTED,
633a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent                ((1 << AudioSystem.STREAM_RING)|(1 << AudioSystem.STREAM_NOTIFICATION)|
634c1d4166289ce016965d1147f7e8d37862ee347ecEric Laurent                 (1 << AudioSystem.STREAM_SYSTEM)|(1 << AudioSystem.STREAM_SYSTEM_ENFORCED)));
635c1d4166289ce016965d1147f7e8d37862ee347ecEric Laurent        if (mVoiceCapable) {
636c1d4166289ce016965d1147f7e8d37862ee347ecEric Laurent            mRingerModeAffectedStreams &= ~(1 << AudioSystem.STREAM_MUSIC);
637c1d4166289ce016965d1147f7e8d37862ee347ecEric Laurent        } else {
638402f7f29634a9f68e7929be828a927a3e2f5efe9Eric Laurent            mRingerModeAffectedStreams |= (1 << AudioSystem.STREAM_MUSIC);
639402f7f29634a9f68e7929be828a927a3e2f5efe9Eric Laurent        }
640c1d4166289ce016965d1147f7e8d37862ee347ecEric Laurent        Settings.System.putInt(cr,
641c1d4166289ce016965d1147f7e8d37862ee347ecEric Laurent                Settings.System.MODE_RINGER_STREAMS_AFFECTED, mRingerModeAffectedStreams);
642c1d4166289ce016965d1147f7e8d37862ee347ecEric Laurent
6439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mMuteAffectedStreams = System.getInt(cr,
6449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                System.MUTE_STREAMS_AFFECTED,
6459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                ((1 << AudioSystem.STREAM_MUSIC)|(1 << AudioSystem.STREAM_RING)|(1 << AudioSystem.STREAM_SYSTEM)));
6469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
64757978ed86286a33d5b1a0fd000ca3406ba9d87b3Justin Koh        boolean masterMute = System.getInt(cr, System.VOLUME_MASTER_MUTE, 0) == 1;
64857978ed86286a33d5b1a0fd000ca3406ba9d87b3Justin Koh        AudioSystem.setMasterMute(masterMute);
64957978ed86286a33d5b1a0fd000ca3406ba9d87b3Justin Koh        broadcastMasterMuteStatus(masterMute);
65057978ed86286a33d5b1a0fd000ca3406ba9d87b3Justin Koh
6519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // Each stream will read its own persisted settings
6529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // Broadcast the sticky intent
654ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten        broadcastRingerMode(ringerMode);
6559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // Broadcast vibrate settings
6579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        broadcastVibrateSetting(AudioManager.VIBRATE_TYPE_RINGER);
6589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        broadcastVibrateSetting(AudioManager.VIBRATE_TYPE_NOTIFICATION);
659d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi
660d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi        // Restore the default media button receiver from the system settings
661d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi        restoreMediaButtonReceiver();
6629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
6639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
664a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent    private int rescaleIndex(int index, int srcStream, int dstStream) {
665a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent        return (index * mStreamStates[dstStream].getMaxIndex() + mStreamStates[srcStream].getMaxIndex() / 2) / mStreamStates[srcStream].getMaxIndex();
666a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent    }
6679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    ///////////////////////////////////////////////////////////////////////////
6699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // IPC methods
6709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    ///////////////////////////////////////////////////////////////////////////
6719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** @see AudioManager#adjustVolume(int, int) */
6739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void adjustVolume(int direction, int flags) {
6749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        adjustSuggestedStreamVolume(direction, AudioManager.USE_DEFAULT_STREAM_TYPE, flags);
6759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
6769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6773114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    /** @see AudioManager#adjustLocalOrRemoteStreamVolume(int, int) with current assumption
6783114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     *  on streamType: fixed to STREAM_MUSIC */
6793114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    public void adjustLocalOrRemoteStreamVolume(int streamType, int direction) {
6803114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        if (DEBUG_VOL) Log.d(TAG, "adjustLocalOrRemoteStreamVolume(dir="+direction+")");
6813114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        if (checkUpdateRemoteStateIfActive(AudioSystem.STREAM_MUSIC)) {
6823114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi            adjustRemoteVolume(AudioSystem.STREAM_MUSIC, direction, 0);
6833114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        } else if (AudioSystem.isStreamActive(AudioSystem.STREAM_MUSIC, 0)) {
6843114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi            adjustStreamVolume(AudioSystem.STREAM_MUSIC, direction, 0);
6853114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        }
6863114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    }
6873114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi
6889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** @see AudioManager#adjustVolume(int, int, int) */
6899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void adjustSuggestedStreamVolume(int direction, int suggestedStreamType, int flags) {
6903114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        if (DEBUG_VOL) Log.d(TAG, "adjustSuggestedStreamVolume() stream="+suggestedStreamType);
691402f7f29634a9f68e7929be828a927a3e2f5efe9Eric Laurent        int streamType;
69245c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent        if (mVolumeControlStream != -1) {
69345c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent            streamType = mVolumeControlStream;
694402f7f29634a9f68e7929be828a927a3e2f5efe9Eric Laurent        } else {
695402f7f29634a9f68e7929be828a927a3e2f5efe9Eric Laurent            streamType = getActiveStreamType(suggestedStreamType);
696402f7f29634a9f68e7929be828a927a3e2f5efe9Eric Laurent        }
6979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6986243edd818b84adfbe712d5d233d6414b33653acAmith Yamasani        // Play sounds on STREAM_RING only and if lock screen is not on.
6993114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        if ((streamType != STREAM_REMOTE_MUSIC) &&
7003114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                (flags & AudioManager.FLAG_PLAY_SOUND) != 0 &&
7016d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent                ((mStreamVolumeAlias[streamType] != AudioSystem.STREAM_RING)
7026243edd818b84adfbe712d5d233d6414b33653acAmith Yamasani                 || (mKeyguardManager != null && mKeyguardManager.isKeyguardLocked()))) {
7039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            flags &= ~AudioManager.FLAG_PLAY_SOUND;
7049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
7059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7063114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        if (streamType == STREAM_REMOTE_MUSIC) {
7073114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi            // don't play sounds for remote
7083114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi            flags &= ~AudioManager.FLAG_PLAY_SOUND;
7093114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi            //if (DEBUG_VOL) Log.i(TAG, "Need to adjust remote volume: calling adjustRemoteVolume()");
7103114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi            adjustRemoteVolume(AudioSystem.STREAM_MUSIC, direction, flags);
7113114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        } else {
7123114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi            adjustStreamVolume(streamType, direction, flags);
7133114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        }
7149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
7159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** @see AudioManager#adjustStreamVolume(int, int, int) */
7179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void adjustStreamVolume(int streamType, int direction, int flags) {
7183114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        if (DEBUG_VOL) Log.d(TAG, "adjustStreamVolume() stream="+streamType+", dir="+direction);
7193114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi
7209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        ensureValidDirection(direction);
7219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        ensureValidStreamType(streamType);
7229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
72396a33d1caad2fab0bc28891cfbf553f4b050bf0bEric Laurent        // use stream type alias here so that streams with same alias have the same behavior,
72496a33d1caad2fab0bc28891cfbf553f4b050bf0bEric Laurent        // including with regard to silent mode control (e.g the use of STREAM_RING below and in
72596a33d1caad2fab0bc28891cfbf553f4b050bf0bEric Laurent        // checkForRingerModeChange() in place of STREAM_RING or STREAM_NOTIFICATION)
7266d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent        int streamTypeAlias = mStreamVolumeAlias[streamType];
727b024c30a80684ac08daef3137b7ba0d347fe3ce5Eric Laurent        VolumeStreamState streamState = mStreamStates[streamTypeAlias];
7289bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent
7299bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent        final int device = getDeviceForStream(streamTypeAlias);
7309bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent        // get last audible index if stream is muted, current index otherwise
731244820185269991186d07068b92985624cede4a5Eric Laurent        final int aliasIndex = streamState.getIndex(device,
7329bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                                                  (streamState.muteCount() != 0) /* lastAudible */);
7339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        boolean adjustVolume = true;
7349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
735244820185269991186d07068b92985624cede4a5Eric Laurent        // convert one UI step (+/-1) into a number of internal units on the stream alias
736244820185269991186d07068b92985624cede4a5Eric Laurent        int step = rescaleIndex(10, streamType, streamTypeAlias);
737244820185269991186d07068b92985624cede4a5Eric Laurent
7389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // If either the client forces allowing ringer modes for this adjustment,
7399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // or the stream type is one that is affected by ringer modes
74025101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent        if (((flags & AudioManager.FLAG_ALLOW_RINGER_MODES) != 0) ||
741bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent                (streamTypeAlias == getMasterStreamType())) {
742ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten            int ringerMode = getRingerMode();
743c696a53d1fe4d61373c5dc64dd057d322da90c8fAmith Yamasani            // do not vibrate if already in vibrate mode
744ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten            if (ringerMode == AudioManager.RINGER_MODE_VIBRATE) {
745cc11b1b8bb47aa6be23ff5c4caf683ff90074121Eric Laurent                flags &= ~AudioManager.FLAG_VIBRATE;
746cc11b1b8bb47aa6be23ff5c4caf683ff90074121Eric Laurent            }
7479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // Check if the ringer mode changes with this volume adjustment. If
7489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // it does, it will handle adjusting the volume, so we won't below
749244820185269991186d07068b92985624cede4a5Eric Laurent            adjustVolume = checkForRingerModeChange(aliasIndex, direction, step);
7508c78752f2bf786ca3e6f45b9dc6955d3b4bba59cEric Laurent            if ((streamTypeAlias == getMasterStreamType()) &&
7518c78752f2bf786ca3e6f45b9dc6955d3b4bba59cEric Laurent                    (mRingerMode == AudioManager.RINGER_MODE_SILENT)) {
7528c78752f2bf786ca3e6f45b9dc6955d3b4bba59cEric Laurent                streamState.setLastAudibleIndex(0, device);
7538c78752f2bf786ca3e6f45b9dc6955d3b4bba59cEric Laurent            }
7549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
7559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7565b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent        // If stream is muted, adjust last audible index only
7575b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent        int index;
758244820185269991186d07068b92985624cede4a5Eric Laurent        final int oldIndex = mStreamStates[streamType].getIndex(device,
759244820185269991186d07068b92985624cede4a5Eric Laurent                (mStreamStates[streamType].muteCount() != 0) /* lastAudible */);
760244820185269991186d07068b92985624cede4a5Eric Laurent
7615b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent        if (streamState.muteCount() != 0) {
7625b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent            if (adjustVolume) {
763244820185269991186d07068b92985624cede4a5Eric Laurent                // Post a persist volume msg
764244820185269991186d07068b92985624cede4a5Eric Laurent                // no need to persist volume on all streams sharing the same alias
765244820185269991186d07068b92985624cede4a5Eric Laurent                streamState.adjustLastAudibleIndex(direction * step, device);
766244820185269991186d07068b92985624cede4a5Eric Laurent                sendMsg(mAudioHandler,
767244820185269991186d07068b92985624cede4a5Eric Laurent                        MSG_PERSIST_VOLUME,
768244820185269991186d07068b92985624cede4a5Eric Laurent                        SENDMSG_QUEUE,
769244820185269991186d07068b92985624cede4a5Eric Laurent                        PERSIST_LAST_AUDIBLE,
770244820185269991186d07068b92985624cede4a5Eric Laurent                        device,
771244820185269991186d07068b92985624cede4a5Eric Laurent                        streamState,
772244820185269991186d07068b92985624cede4a5Eric Laurent                        PERSIST_DELAY);
7735b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent            }
774244820185269991186d07068b92985624cede4a5Eric Laurent            index = mStreamStates[streamType].getIndex(device, true  /* lastAudible */);
7755b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent        } else {
776244820185269991186d07068b92985624cede4a5Eric Laurent            if (adjustVolume && streamState.adjustIndex(direction * step, device)) {
7775b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent                // Post message to set system volume (it in turn will post a message
7785b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent                // to persist). Do not change volume if stream is muted.
779afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent                sendMsg(mAudioHandler,
7809bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                        MSG_SET_DEVICE_VOLUME,
78198ad9b9d6fd34aad487933170f50b5519313df61Eric Laurent                        SENDMSG_QUEUE,
7829bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                        device,
783afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent                        0,
784afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent                        streamState,
785afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent                        0);
7869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
787244820185269991186d07068b92985624cede4a5Eric Laurent            index = mStreamStates[streamType].getIndex(device, false  /* lastAudible */);
7889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
78925101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent
79025101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent        sendVolumeUpdate(streamType, oldIndex, index, flags);
7919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
7929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
793cbdb49dc5e1b993a0bc5c68dbfb9486bfa0cd762Mike Lockwood    /** @see AudioManager#adjustMasterVolume(int) */
7946c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang    public void adjustMasterVolume(int steps, int flags) {
7956c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang        ensureValidSteps(steps);
7969760647dd0ee67e7c20f3e9d661d2006b1df0b54Mike Lockwood        int volume = Math.round(AudioSystem.getMasterVolume() * MAX_MASTER_VOLUME);
7979760647dd0ee67e7c20f3e9d661d2006b1df0b54Mike Lockwood        int delta = 0;
7986c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang        int numSteps = Math.abs(steps);
7996c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang        int direction = steps > 0 ? AudioManager.ADJUST_RAISE : AudioManager.ADJUST_LOWER;
8006c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang        for (int i = 0; i < numSteps; ++i) {
8016c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang            delta = findVolumeDelta(direction, volume);
8026c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang            volume += delta;
803cbdb49dc5e1b993a0bc5c68dbfb9486bfa0cd762Mike Lockwood        }
80424b082f87e96c00d5c17d60c735423900be40e70RoboErik
8056c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang        //Log.d(TAG, "adjustMasterVolume volume: " + volume + " steps: " + steps);
8066c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang        setMasterVolume(volume, flags);
807cbdb49dc5e1b993a0bc5c68dbfb9486bfa0cd762Mike Lockwood    }
808cbdb49dc5e1b993a0bc5c68dbfb9486bfa0cd762Mike Lockwood
8099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** @see AudioManager#setStreamVolume(int, int, int) */
8109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void setStreamVolume(int streamType, int index, int flags) {
8119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        ensureValidStreamType(streamType);
8126d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent        VolumeStreamState streamState = mStreamStates[mStreamVolumeAlias[streamType]];
8139ce379aef155e0c21b5d82d8dc713c62792e4f30Eric Laurent
8149bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent        final int device = getDeviceForStream(streamType);
8159bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent        // get last audible index if stream is muted, current index otherwise
8169bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent        final int oldIndex = streamState.getIndex(device,
8179bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                                                  (streamState.muteCount() != 0) /* lastAudible */);
8189ce379aef155e0c21b5d82d8dc713c62792e4f30Eric Laurent
819244820185269991186d07068b92985624cede4a5Eric Laurent        index = rescaleIndex(index * 10, streamType, mStreamVolumeAlias[streamType]);
820244820185269991186d07068b92985624cede4a5Eric Laurent
821f740664cd808bebfc35ded46da6002bdc97a1a16Eric Laurent        // setting volume on master stream type also controls silent mode
822f740664cd808bebfc35ded46da6002bdc97a1a16Eric Laurent        if (((flags & AudioManager.FLAG_ALLOW_RINGER_MODES) != 0) ||
823f740664cd808bebfc35ded46da6002bdc97a1a16Eric Laurent                (mStreamVolumeAlias[streamType] == getMasterStreamType())) {
824ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten            int newRingerMode;
825b024c30a80684ac08daef3137b7ba0d347fe3ce5Eric Laurent            if (index == 0) {
826bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent                newRingerMode = mHasVibrator ? AudioManager.RINGER_MODE_VIBRATE
827bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent                                              : AudioManager.RINGER_MODE_SILENT;
8286d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent                setStreamVolumeInt(mStreamVolumeAlias[streamType],
8299bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                                   index,
8309bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                                   device,
8319bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                                   false,
8329bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                                   true);
833b024c30a80684ac08daef3137b7ba0d347fe3ce5Eric Laurent            } else {
834b024c30a80684ac08daef3137b7ba0d347fe3ce5Eric Laurent                newRingerMode = AudioManager.RINGER_MODE_NORMAL;
835b024c30a80684ac08daef3137b7ba0d347fe3ce5Eric Laurent            }
836ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten            setRingerMode(newRingerMode);
837b024c30a80684ac08daef3137b7ba0d347fe3ce5Eric Laurent        }
838b024c30a80684ac08daef3137b7ba0d347fe3ce5Eric Laurent
8396d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent        setStreamVolumeInt(mStreamVolumeAlias[streamType], index, device, false, true);
8409bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent        // get last audible index if stream is muted, current index otherwise
841244820185269991186d07068b92985624cede4a5Eric Laurent        index = mStreamStates[streamType].getIndex(device,
842244820185269991186d07068b92985624cede4a5Eric Laurent                                 (mStreamStates[streamType].muteCount() != 0) /* lastAudible */);
8435b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent
84425101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent        sendVolumeUpdate(streamType, oldIndex, index, flags);
8459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
8469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
84745c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent    /** @see AudioManager#forceVolumeControlStream(int) */
84845c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent    public void forceVolumeControlStream(int streamType, IBinder cb) {
84945c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent        synchronized(mForceControlStreamLock) {
85045c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent            mVolumeControlStream = streamType;
85145c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent            if (mVolumeControlStream == -1) {
85245c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent                if (mForceControlStreamClient != null) {
85345c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent                    mForceControlStreamClient.release();
85445c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent                    mForceControlStreamClient = null;
85545c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent                }
85645c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent            } else {
85745c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent                mForceControlStreamClient = new ForceControlStreamClient(cb);
85845c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent            }
85945c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent        }
86045c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent    }
86145c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent
86245c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent    private class ForceControlStreamClient implements IBinder.DeathRecipient {
86345c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent        private IBinder mCb; // To be notified of client's death
86445c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent
86545c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent        ForceControlStreamClient(IBinder cb) {
86645c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent            if (cb != null) {
86745c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent                try {
86845c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent                    cb.linkToDeath(this, 0);
86945c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent                } catch (RemoteException e) {
87045c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent                    // Client has died!
87145c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent                    Log.w(TAG, "ForceControlStreamClient() could not link to "+cb+" binder death");
87245c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent                    cb = null;
87345c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent                }
87445c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent            }
87545c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent            mCb = cb;
87645c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent        }
87745c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent
87845c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent        public void binderDied() {
87945c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent            synchronized(mForceControlStreamLock) {
88045c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent                Log.w(TAG, "SCO client died");
88145c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent                if (mForceControlStreamClient != this) {
88245c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent                    Log.w(TAG, "unregistered control stream client died");
88345c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent                } else {
88445c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent                    mForceControlStreamClient = null;
88545c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent                    mVolumeControlStream = -1;
88645c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent                }
88745c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent            }
88845c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent        }
88945c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent
89045c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent        public void release() {
89145c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent            if (mCb != null) {
89245c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent                mCb.unlinkToDeath(this, 0);
89345c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent                mCb = null;
89445c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent            }
89545c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent        }
89645c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent    }
89745c90cefd13a03b852bb4b8da4be218876cbbb32Eric Laurent
8986c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang    private int findVolumeDelta(int direction, int volume) {
8996c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang        int delta = 0;
9006c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang        if (direction == AudioManager.ADJUST_RAISE) {
9016c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang            if (volume == MAX_MASTER_VOLUME) {
9026c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang                return 0;
9036c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang            }
9046c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang            // This is the default value if we make it to the end
9056c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang            delta = mMasterVolumeRamp[1];
9066c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang            // If we're raising the volume move down the ramp array until we
9076c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang            // find the volume we're above and use that groups delta.
9086c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang            for (int i = mMasterVolumeRamp.length - 1; i > 1; i -= 2) {
9096c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang                if (volume >= mMasterVolumeRamp[i - 1]) {
9106c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang                    delta = mMasterVolumeRamp[i];
9116c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang                    break;
9126c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang                }
9136c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang            }
9146c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang        } else if (direction == AudioManager.ADJUST_LOWER){
9156c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang            if (volume == 0) {
9166c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang                return 0;
9176c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang            }
9186c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang            int length = mMasterVolumeRamp.length;
9196c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang            // This is the default value if we make it to the end
9206c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang            delta = -mMasterVolumeRamp[length - 1];
9216c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang            // If we're lowering the volume move up the ramp array until we
9226c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang            // find the volume we're below and use the group below it's delta
9236c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang            for (int i = 2; i < length; i += 2) {
9246c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang                if (volume <= mMasterVolumeRamp[i]) {
9256c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang                    delta = -mMasterVolumeRamp[i - 1];
9266c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang                    break;
9276c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang                }
9286c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang            }
9296c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang        }
9306c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang        return delta;
9316c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang    }
9326c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang
93325101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent    // UI update and Broadcast Intent
93425101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent    private void sendVolumeUpdate(int streamType, int oldIndex, int index, int flags) {
93525101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent        if (!mVoiceCapable && (streamType == AudioSystem.STREAM_RING)) {
93625101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent            streamType = AudioSystem.STREAM_NOTIFICATION;
93725101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent        }
93825101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent
93925101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent        mVolumePanel.postVolumeChanged(streamType, flags);
94025101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent
9419ce379aef155e0c21b5d82d8dc713c62792e4f30Eric Laurent        oldIndex = (oldIndex + 5) / 10;
9429ce379aef155e0c21b5d82d8dc713c62792e4f30Eric Laurent        index = (index + 5) / 10;
9439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        Intent intent = new Intent(AudioManager.VOLUME_CHANGED_ACTION);
9449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        intent.putExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, streamType);
9459ce379aef155e0c21b5d82d8dc713c62792e4f30Eric Laurent        intent.putExtra(AudioManager.EXTRA_VOLUME_STREAM_VALUE, index);
9469ce379aef155e0c21b5d82d8dc713c62792e4f30Eric Laurent        intent.putExtra(AudioManager.EXTRA_PREV_VOLUME_STREAM_VALUE, oldIndex);
9479ce379aef155e0c21b5d82d8dc713c62792e4f30Eric Laurent        mContext.sendBroadcast(intent);
9489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
9499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9500dc37cce9d564ae43883c8dc8672b9266b881e63Mike Lockwood    // UI update and Broadcast Intent
9510dc37cce9d564ae43883c8dc8672b9266b881e63Mike Lockwood    private void sendMasterVolumeUpdate(int flags, int oldVolume, int newVolume) {
9520dc37cce9d564ae43883c8dc8672b9266b881e63Mike Lockwood        mVolumePanel.postMasterVolumeChanged(flags);
9530dc37cce9d564ae43883c8dc8672b9266b881e63Mike Lockwood
9540dc37cce9d564ae43883c8dc8672b9266b881e63Mike Lockwood        Intent intent = new Intent(AudioManager.MASTER_VOLUME_CHANGED_ACTION);
9550dc37cce9d564ae43883c8dc8672b9266b881e63Mike Lockwood        intent.putExtra(AudioManager.EXTRA_PREV_MASTER_VOLUME_VALUE, oldVolume);
9560dc37cce9d564ae43883c8dc8672b9266b881e63Mike Lockwood        intent.putExtra(AudioManager.EXTRA_MASTER_VOLUME_VALUE, newVolume);
9570dc37cce9d564ae43883c8dc8672b9266b881e63Mike Lockwood        mContext.sendBroadcast(intent);
9580dc37cce9d564ae43883c8dc8672b9266b881e63Mike Lockwood    }
9590dc37cce9d564ae43883c8dc8672b9266b881e63Mike Lockwood
9600dc37cce9d564ae43883c8dc8672b9266b881e63Mike Lockwood    // UI update and Broadcast Intent
9610dc37cce9d564ae43883c8dc8672b9266b881e63Mike Lockwood    private void sendMasterMuteUpdate(boolean muted, int flags) {
9620dc37cce9d564ae43883c8dc8672b9266b881e63Mike Lockwood        mVolumePanel.postMasterMuteChanged(flags);
96357978ed86286a33d5b1a0fd000ca3406ba9d87b3Justin Koh        broadcastMasterMuteStatus(muted);
96457978ed86286a33d5b1a0fd000ca3406ba9d87b3Justin Koh    }
9650dc37cce9d564ae43883c8dc8672b9266b881e63Mike Lockwood
96657978ed86286a33d5b1a0fd000ca3406ba9d87b3Justin Koh    private void broadcastMasterMuteStatus(boolean muted) {
9670dc37cce9d564ae43883c8dc8672b9266b881e63Mike Lockwood        Intent intent = new Intent(AudioManager.MASTER_MUTE_CHANGED_ACTION);
9680dc37cce9d564ae43883c8dc8672b9266b881e63Mike Lockwood        intent.putExtra(AudioManager.EXTRA_MASTER_VOLUME_MUTED, muted);
96957978ed86286a33d5b1a0fd000ca3406ba9d87b3Justin Koh        intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT
97057978ed86286a33d5b1a0fd000ca3406ba9d87b3Justin Koh                | Intent.FLAG_RECEIVER_REPLACE_PENDING);
9710dc37cce9d564ae43883c8dc8672b9266b881e63Mike Lockwood        long origCallerIdentityToken = Binder.clearCallingIdentity();
9720dc37cce9d564ae43883c8dc8672b9266b881e63Mike Lockwood        mContext.sendStickyBroadcast(intent);
9730dc37cce9d564ae43883c8dc8672b9266b881e63Mike Lockwood        Binder.restoreCallingIdentity(origCallerIdentityToken);
9740dc37cce9d564ae43883c8dc8672b9266b881e63Mike Lockwood    }
9750dc37cce9d564ae43883c8dc8672b9266b881e63Mike Lockwood
9769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
9779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Sets the stream state's index, and posts a message to set system volume.
9789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * This will not call out to the UI. Assumes a valid stream type.
9799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
9809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param streamType Type of the stream
9819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param index Desired volume index of the stream
9829bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent     * @param device the device whose volume must be changed
9839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param force If true, set the volume even if the desired volume is same
9849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * as the current volume.
9859bcf401d13d47416043a704430388abd59aef7cdEric Laurent     * @param lastAudible If true, stores new index as last audible one
9869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
9879bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent    private void setStreamVolumeInt(int streamType,
9889bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                                    int index,
9899bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                                    int device,
9909bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                                    boolean force,
9919bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                                    boolean lastAudible) {
9929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        VolumeStreamState streamState = mStreamStates[streamType];
9935b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent
9945b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent        // If stream is muted, set last audible index only
9955b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent        if (streamState.muteCount() != 0) {
996758dd527f64f1e827adfe09f0141ab213733ca22Eric Laurent            // Do not allow last audible index to be 0
997758dd527f64f1e827adfe09f0141ab213733ca22Eric Laurent            if (index != 0) {
9989bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                streamState.setLastAudibleIndex(index, device);
999758dd527f64f1e827adfe09f0141ab213733ca22Eric Laurent                // Post a persist volume msg
1000afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent                sendMsg(mAudioHandler,
1001afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent                        MSG_PERSIST_VOLUME,
100298ad9b9d6fd34aad487933170f50b5519313df61Eric Laurent                        SENDMSG_QUEUE,
1003afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent                        PERSIST_LAST_AUDIBLE,
10049bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                        device,
1005afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent                        streamState,
1006afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent                        PERSIST_DELAY);
1007758dd527f64f1e827adfe09f0141ab213733ca22Eric Laurent            }
10085b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent        } else {
10099bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent            if (streamState.setIndex(index, device, lastAudible) || force) {
10105b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent                // Post message to set system volume (it in turn will post a message
10115b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent                // to persist).
1012afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent                sendMsg(mAudioHandler,
10139bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                        MSG_SET_DEVICE_VOLUME,
101498ad9b9d6fd34aad487933170f50b5519313df61Eric Laurent                        SENDMSG_QUEUE,
10159bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                        device,
1016afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent                        0,
1017afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent                        streamState,
1018afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent                        0);
10199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
10209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
10219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
10229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** @see AudioManager#setStreamSolo(int, boolean) */
10249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void setStreamSolo(int streamType, boolean state, IBinder cb) {
10259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        for (int stream = 0; stream < mStreamStates.length; stream++) {
10269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (!isStreamAffectedByMute(stream) || stream == streamType) continue;
10279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // Bring back last audible volume
10289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mStreamStates[stream].mute(cb, state);
10299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         }
10309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
10319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** @see AudioManager#setStreamMute(int, boolean) */
10339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void setStreamMute(int streamType, boolean state, IBinder cb) {
10349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (isStreamAffectedByMute(streamType)) {
10359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mStreamStates[streamType].mute(cb, state);
10369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
10379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
10389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
103925101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent    /** get stream mute state. */
104025101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent    public boolean isStreamMute(int streamType) {
104125101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent        return (mStreamStates[streamType].muteCount() != 0);
104225101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent    }
104325101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent
1044ce952c8e13c535bedde77bcdb94dfcc7508475aaMike Lockwood    /** @see AudioManager#setMasterMute(boolean, IBinder) */
10450273af55cf68d54d26d154b44d105d40fed79701Justin Koh    public void setMasterMute(boolean state, int flags, IBinder cb) {
10461ce5b26d707e0086e09af3cd0428f1b441145261Jason Simmons        if (state != AudioSystem.getMasterMute()) {
10471ce5b26d707e0086e09af3cd0428f1b441145261Jason Simmons            AudioSystem.setMasterMute(state);
104857978ed86286a33d5b1a0fd000ca3406ba9d87b3Justin Koh            // Post a persist master volume msg
104975cf9e19a575c28c200c02c0ab6f83bb79f5c50dJustin Koh            sendMsg(mAudioHandler, MSG_PERSIST_MASTER_VOLUME_MUTE, SENDMSG_REPLACE, state ? 1
105057978ed86286a33d5b1a0fd000ca3406ba9d87b3Justin Koh                    : 0, 0, null, PERSIST_DELAY);
10510273af55cf68d54d26d154b44d105d40fed79701Justin Koh            sendMasterMuteUpdate(state, flags);
10521ce5b26d707e0086e09af3cd0428f1b441145261Jason Simmons        }
1053ce952c8e13c535bedde77bcdb94dfcc7508475aaMike Lockwood    }
1054ce952c8e13c535bedde77bcdb94dfcc7508475aaMike Lockwood
1055ce952c8e13c535bedde77bcdb94dfcc7508475aaMike Lockwood    /** get master mute state. */
1056ce952c8e13c535bedde77bcdb94dfcc7508475aaMike Lockwood    public boolean isMasterMute() {
10573194ea94348bce8e7ee9f803698d877f46f8279aMike Lockwood        return AudioSystem.getMasterMute();
1058ce952c8e13c535bedde77bcdb94dfcc7508475aaMike Lockwood    }
1059ce952c8e13c535bedde77bcdb94dfcc7508475aaMike Lockwood
10609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** @see AudioManager#getStreamVolume(int) */
10619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public int getStreamVolume(int streamType) {
10629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        ensureValidStreamType(streamType);
10639bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent        int device = getDeviceForStream(streamType);
10649bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent        return (mStreamStates[streamType].getIndex(device, false  /* lastAudible */) + 5) / 10;
10659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
10669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10674767690f09ea3447b8c5c32fb28d27650aa18e00Mike Lockwood    public int getMasterVolume() {
1068ce952c8e13c535bedde77bcdb94dfcc7508475aaMike Lockwood        if (isMasterMute()) return 0;
1069ce952c8e13c535bedde77bcdb94dfcc7508475aaMike Lockwood        return getLastAudibleMasterVolume();
10708dc1dabd254249b7ddb8743e88fdb96580ffc585Mike Lockwood    }
10718dc1dabd254249b7ddb8743e88fdb96580ffc585Mike Lockwood
10724767690f09ea3447b8c5c32fb28d27650aa18e00Mike Lockwood    public void setMasterVolume(int volume, int flags) {
10739760647dd0ee67e7c20f3e9d661d2006b1df0b54Mike Lockwood        if (volume < 0) {
10749760647dd0ee67e7c20f3e9d661d2006b1df0b54Mike Lockwood            volume = 0;
10759760647dd0ee67e7c20f3e9d661d2006b1df0b54Mike Lockwood        } else if (volume > MAX_MASTER_VOLUME) {
10769760647dd0ee67e7c20f3e9d661d2006b1df0b54Mike Lockwood            volume = MAX_MASTER_VOLUME;
10779760647dd0ee67e7c20f3e9d661d2006b1df0b54Mike Lockwood        }
10785c55a051ad7d86a464fb91426f1ea3c0250e38b3Mike Lockwood        doSetMasterVolume((float)volume / MAX_MASTER_VOLUME, flags);
10795c55a051ad7d86a464fb91426f1ea3c0250e38b3Mike Lockwood    }
10805c55a051ad7d86a464fb91426f1ea3c0250e38b3Mike Lockwood
10815c55a051ad7d86a464fb91426f1ea3c0250e38b3Mike Lockwood    private void doSetMasterVolume(float volume, int flags) {
10825c55a051ad7d86a464fb91426f1ea3c0250e38b3Mike Lockwood        // don't allow changing master volume when muted
10835c55a051ad7d86a464fb91426f1ea3c0250e38b3Mike Lockwood        if (!AudioSystem.getMasterMute()) {
10845c55a051ad7d86a464fb91426f1ea3c0250e38b3Mike Lockwood            int oldVolume = getMasterVolume();
10855c55a051ad7d86a464fb91426f1ea3c0250e38b3Mike Lockwood            AudioSystem.setMasterVolume(volume);
10865c55a051ad7d86a464fb91426f1ea3c0250e38b3Mike Lockwood
10875c55a051ad7d86a464fb91426f1ea3c0250e38b3Mike Lockwood            int newVolume = getMasterVolume();
10885c55a051ad7d86a464fb91426f1ea3c0250e38b3Mike Lockwood            if (newVolume != oldVolume) {
10895c55a051ad7d86a464fb91426f1ea3c0250e38b3Mike Lockwood                // Post a persist master volume msg
10905c55a051ad7d86a464fb91426f1ea3c0250e38b3Mike Lockwood                sendMsg(mAudioHandler, MSG_PERSIST_MASTER_VOLUME, SENDMSG_REPLACE,
10915c55a051ad7d86a464fb91426f1ea3c0250e38b3Mike Lockwood                        Math.round(volume * (float)1000.0), 0, null, PERSIST_DELAY);
10925c55a051ad7d86a464fb91426f1ea3c0250e38b3Mike Lockwood            }
10933caba517253d1703fc29b50740c4567b932279fbJustin Koh            // Send the volume update regardless whether there was a change.
10943caba517253d1703fc29b50740c4567b932279fbJustin Koh            sendMasterVolumeUpdate(flags, oldVolume, newVolume);
10955c55a051ad7d86a464fb91426f1ea3c0250e38b3Mike Lockwood        }
10968dc1dabd254249b7ddb8743e88fdb96580ffc585Mike Lockwood    }
10978dc1dabd254249b7ddb8743e88fdb96580ffc585Mike Lockwood
10989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** @see AudioManager#getStreamMaxVolume(int) */
10999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public int getStreamMaxVolume(int streamType) {
11009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        ensureValidStreamType(streamType);
1101a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent        return (mStreamStates[streamType].getMaxIndex() + 5) / 10;
11029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
11039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
11044767690f09ea3447b8c5c32fb28d27650aa18e00Mike Lockwood    public int getMasterMaxVolume() {
11054767690f09ea3447b8c5c32fb28d27650aa18e00Mike Lockwood        return MAX_MASTER_VOLUME;
11064767690f09ea3447b8c5c32fb28d27650aa18e00Mike Lockwood    }
110725101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent
110825101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent    /** Get last audible volume before stream was muted. */
110925101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent    public int getLastAudibleStreamVolume(int streamType) {
111025101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent        ensureValidStreamType(streamType);
11119bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent        int device = getDeviceForStream(streamType);
11129bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent        return (mStreamStates[streamType].getIndex(device, true  /* lastAudible */) + 5) / 10;
111325101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent    }
111425101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent
1115ce952c8e13c535bedde77bcdb94dfcc7508475aaMike Lockwood    /** Get last audible master volume before it was muted. */
1116ce952c8e13c535bedde77bcdb94dfcc7508475aaMike Lockwood    public int getLastAudibleMasterVolume() {
1117ce952c8e13c535bedde77bcdb94dfcc7508475aaMike Lockwood        return Math.round(AudioSystem.getMasterVolume() * MAX_MASTER_VOLUME);
1118ce952c8e13c535bedde77bcdb94dfcc7508475aaMike Lockwood    }
1119ce952c8e13c535bedde77bcdb94dfcc7508475aaMike Lockwood
11206d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent    /** @see AudioManager#getMasterStreamType(int) */
11216d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent    public int getMasterStreamType() {
11226d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent        if (mVoiceCapable) {
11236d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent            return AudioSystem.STREAM_RING;
11246d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent        } else {
11256d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent            return AudioSystem.STREAM_MUSIC;
11266d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent        }
11276d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent    }
11286d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent
11299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** @see AudioManager#getRingerMode() */
11309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public int getRingerMode() {
1131ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten        synchronized(mSettingsLock) {
1132ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten            return mRingerMode;
1133ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten        }
1134ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten    }
1135ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten
1136ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten    private void ensureValidRingerMode(int ringerMode) {
1137ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten        if (!AudioManager.isValidRingerMode(ringerMode)) {
1138ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten            throw new IllegalArgumentException("Bad ringer mode " + ringerMode);
1139ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten        }
11409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
11419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
11429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** @see AudioManager#setRingerMode(int) */
11439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void setRingerMode(int ringerMode) {
1144244820185269991186d07068b92985624cede4a5Eric Laurent        if ((ringerMode == AudioManager.RINGER_MODE_VIBRATE) && !mHasVibrator) {
1145244820185269991186d07068b92985624cede4a5Eric Laurent            ringerMode = AudioManager.RINGER_MODE_SILENT;
1146244820185269991186d07068b92985624cede4a5Eric Laurent        }
1147ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten        if (ringerMode != getRingerMode()) {
1148ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten            setRingerModeInt(ringerMode, true);
1149ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten            // Send sticky broadcast
1150ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten            broadcastRingerMode(ringerMode);
1151b109615ebebd6f3b9ae789412279f576c3ace46bJason Parekh        }
1152b109615ebebd6f3b9ae789412279f576c3ace46bJason Parekh    }
11539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
11544050c93601b3c3609b21cc1e18a29b64747e7fa9Eric Laurent    private void setRingerModeInt(int ringerMode, boolean persist) {
1155ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten        synchronized(mSettingsLock) {
1156ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten            mRingerMode = ringerMode;
1157ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten        }
1158b109615ebebd6f3b9ae789412279f576c3ace46bJason Parekh
11595b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent        // Mute stream if not previously muted by ringer mode and ringer mode
11605b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent        // is not RINGER_MODE_NORMAL and stream is affected by ringer mode.
11615b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent        // Unmute stream if previously muted by ringer mode and ringer mode
11625b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent        // is RINGER_MODE_NORMAL or stream is not affected by ringer mode.
1163b109615ebebd6f3b9ae789412279f576c3ace46bJason Parekh        int numStreamTypes = AudioSystem.getNumStreamTypes();
11645b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent        for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
11655b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent            if (isStreamMutedByRingerMode(streamType)) {
11665b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent                if (!isStreamAffectedByRingerMode(streamType) ||
1167ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten                    ringerMode == AudioManager.RINGER_MODE_NORMAL) {
1168b024c30a80684ac08daef3137b7ba0d347fe3ce5Eric Laurent                    // ring and notifications volume should never be 0 when not silenced
1169b024c30a80684ac08daef3137b7ba0d347fe3ce5Eric Laurent                    // on voice capable devices
1170b024c30a80684ac08daef3137b7ba0d347fe3ce5Eric Laurent                    if (mVoiceCapable &&
11716d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent                            mStreamVolumeAlias[streamType] == AudioSystem.STREAM_RING) {
11723172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                        synchronized (mStreamStates[streamType]) {
11733172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                            Set set = mStreamStates[streamType].mLastAudibleIndex.entrySet();
11743172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                            Iterator i = set.iterator();
11753172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                            while (i.hasNext()) {
11763172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                                Map.Entry entry = (Map.Entry)i.next();
11773172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                                if ((Integer)entry.getValue() == 0) {
11783172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                                    entry.setValue(10);
11793172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                                }
11809bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                            }
11819bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                        }
1182b024c30a80684ac08daef3137b7ba0d347fe3ce5Eric Laurent                    }
11835b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent                    mStreamStates[streamType].mute(null, false);
11845b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent                    mRingerModeMutedStreams &= ~(1 << streamType);
11859bcf401d13d47416043a704430388abd59aef7cdEric Laurent                }
11865b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent            } else {
11875b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent                if (isStreamAffectedByRingerMode(streamType) &&
1188ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten                    ringerMode != AudioManager.RINGER_MODE_NORMAL) {
11895b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent                   mStreamStates[streamType].mute(null, true);
11905b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent                   mRingerModeMutedStreams |= (1 << streamType);
11915b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent               }
1192b109615ebebd6f3b9ae789412279f576c3ace46bJason Parekh            }
11939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1194a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent
1195b109615ebebd6f3b9ae789412279f576c3ace46bJason Parekh        // Post a persist ringer mode msg
11964050c93601b3c3609b21cc1e18a29b64747e7fa9Eric Laurent        if (persist) {
1197afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent            sendMsg(mAudioHandler, MSG_PERSIST_RINGER_MODE,
11984050c93601b3c3609b21cc1e18a29b64747e7fa9Eric Laurent                    SENDMSG_REPLACE, 0, 0, null, PERSIST_DELAY);
11994050c93601b3c3609b21cc1e18a29b64747e7fa9Eric Laurent        }
12009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
12019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12029063154a793b0ab38b3c5992cbaed046427b4a82Mike Lockwood    private void restoreMasterVolume() {
12039063154a793b0ab38b3c5992cbaed046427b4a82Mike Lockwood        if (mUseMasterVolume) {
12049063154a793b0ab38b3c5992cbaed046427b4a82Mike Lockwood            float volume = Settings.System.getFloat(mContentResolver,
12059063154a793b0ab38b3c5992cbaed046427b4a82Mike Lockwood                    Settings.System.VOLUME_MASTER, -1.0f);
12069063154a793b0ab38b3c5992cbaed046427b4a82Mike Lockwood            if (volume >= 0.0f) {
12079063154a793b0ab38b3c5992cbaed046427b4a82Mike Lockwood                AudioSystem.setMasterVolume(volume);
12089063154a793b0ab38b3c5992cbaed046427b4a82Mike Lockwood            }
12099063154a793b0ab38b3c5992cbaed046427b4a82Mike Lockwood        }
12109063154a793b0ab38b3c5992cbaed046427b4a82Mike Lockwood    }
12119063154a793b0ab38b3c5992cbaed046427b4a82Mike Lockwood
12129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** @see AudioManager#shouldVibrate(int) */
12139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public boolean shouldVibrate(int vibrateType) {
1214bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent        if (!mHasVibrator) return false;
12159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        switch (getVibrateSetting(vibrateType)) {
12179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            case AudioManager.VIBRATE_SETTING_ON:
1219ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten                return getRingerMode() != AudioManager.RINGER_MODE_SILENT;
12209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            case AudioManager.VIBRATE_SETTING_ONLY_SILENT:
1222ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten                return getRingerMode() == AudioManager.RINGER_MODE_VIBRATE;
12239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            case AudioManager.VIBRATE_SETTING_OFF:
1225bcac496076ef6f439147e7a2be71e8a2b76ddedeDaniel Sandler                // return false, even for incoming calls
1226bcac496076ef6f439147e7a2be71e8a2b76ddedeDaniel Sandler                return false;
12279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            default:
12299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return false;
12309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
12319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
12329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** @see AudioManager#getVibrateSetting(int) */
12349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public int getVibrateSetting(int vibrateType) {
1235bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent        if (!mHasVibrator) return AudioManager.VIBRATE_SETTING_OFF;
12369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return (mVibrateSetting >> (vibrateType * 2)) & 3;
12379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
12389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** @see AudioManager#setVibrateSetting(int, int) */
12409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void setVibrateSetting(int vibrateType, int vibrateSetting) {
12419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1242bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent        if (!mHasVibrator) return;
1243bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent
12449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mVibrateSetting = getValueForVibrateSetting(mVibrateSetting, vibrateType, vibrateSetting);
12459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // Broadcast change
12479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        broadcastVibrateSetting(vibrateType);
12489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
12509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
12529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @see #setVibrateSetting(int, int)
12539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
12549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static int getValueForVibrateSetting(int existingValue, int vibrateType,
12559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int vibrateSetting) {
12569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // First clear the existing setting. Each vibrate type has two bits in
12589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // the value. Note '3' is '11' in binary.
12599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        existingValue &= ~(3 << (vibrateType * 2));
12609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // Set into the old value
12629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        existingValue |= (vibrateSetting & 3) << (vibrateType * 2);
12639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return existingValue;
12659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
12669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
12679272b4b4a44fe1f33e3030810618194f817caaecEric Laurent    private class SetModeDeathHandler implements IBinder.DeathRecipient {
12689272b4b4a44fe1f33e3030810618194f817caaecEric Laurent        private IBinder mCb; // To be notified of client's death
1269f1ddd51f9cd2f92b922bc636c307210a8d587c25Marco Nelissen        private int mPid;
12709272b4b4a44fe1f33e3030810618194f817caaecEric Laurent        private int mMode = AudioSystem.MODE_NORMAL; // Current mode set by this client
12719272b4b4a44fe1f33e3030810618194f817caaecEric Laurent
12729f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent        SetModeDeathHandler(IBinder cb, int pid) {
12739272b4b4a44fe1f33e3030810618194f817caaecEric Laurent            mCb = cb;
12749f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent            mPid = pid;
12759272b4b4a44fe1f33e3030810618194f817caaecEric Laurent        }
12769272b4b4a44fe1f33e3030810618194f817caaecEric Laurent
12779272b4b4a44fe1f33e3030810618194f817caaecEric Laurent        public void binderDied() {
1278d7454be47f4111c0478a502353e11dea401378bdEric Laurent            int newModeOwnerPid = 0;
12799272b4b4a44fe1f33e3030810618194f817caaecEric Laurent            synchronized(mSetModeDeathHandlers) {
12809272b4b4a44fe1f33e3030810618194f817caaecEric Laurent                Log.w(TAG, "setMode() client died");
12819272b4b4a44fe1f33e3030810618194f817caaecEric Laurent                int index = mSetModeDeathHandlers.indexOf(this);
12829272b4b4a44fe1f33e3030810618194f817caaecEric Laurent                if (index < 0) {
12839272b4b4a44fe1f33e3030810618194f817caaecEric Laurent                    Log.w(TAG, "unregistered setMode() client died");
12849272b4b4a44fe1f33e3030810618194f817caaecEric Laurent                } else {
1285d7454be47f4111c0478a502353e11dea401378bdEric Laurent                    newModeOwnerPid = setModeInt(AudioSystem.MODE_NORMAL, mCb, mPid);
12869272b4b4a44fe1f33e3030810618194f817caaecEric Laurent                }
12879272b4b4a44fe1f33e3030810618194f817caaecEric Laurent            }
12889f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent            // when entering RINGTONE, IN_CALL or IN_COMMUNICATION mode, clear all
12899f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent            // SCO connections not started by the application changing the mode
1290d7454be47f4111c0478a502353e11dea401378bdEric Laurent            if (newModeOwnerPid != 0) {
1291d7454be47f4111c0478a502353e11dea401378bdEric Laurent                 disconnectBluetoothSco(newModeOwnerPid);
12929f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent            }
12939272b4b4a44fe1f33e3030810618194f817caaecEric Laurent        }
12949272b4b4a44fe1f33e3030810618194f817caaecEric Laurent
1295f1ddd51f9cd2f92b922bc636c307210a8d587c25Marco Nelissen        public int getPid() {
1296f1ddd51f9cd2f92b922bc636c307210a8d587c25Marco Nelissen            return mPid;
1297f1ddd51f9cd2f92b922bc636c307210a8d587c25Marco Nelissen        }
1298f1ddd51f9cd2f92b922bc636c307210a8d587c25Marco Nelissen
12999272b4b4a44fe1f33e3030810618194f817caaecEric Laurent        public void setMode(int mode) {
13009272b4b4a44fe1f33e3030810618194f817caaecEric Laurent            mMode = mode;
13019272b4b4a44fe1f33e3030810618194f817caaecEric Laurent        }
13029272b4b4a44fe1f33e3030810618194f817caaecEric Laurent
13039272b4b4a44fe1f33e3030810618194f817caaecEric Laurent        public int getMode() {
13049272b4b4a44fe1f33e3030810618194f817caaecEric Laurent            return mMode;
13059272b4b4a44fe1f33e3030810618194f817caaecEric Laurent        }
13069272b4b4a44fe1f33e3030810618194f817caaecEric Laurent
13079272b4b4a44fe1f33e3030810618194f817caaecEric Laurent        public IBinder getBinder() {
13089272b4b4a44fe1f33e3030810618194f817caaecEric Laurent            return mCb;
13099272b4b4a44fe1f33e3030810618194f817caaecEric Laurent        }
13109272b4b4a44fe1f33e3030810618194f817caaecEric Laurent    }
13119272b4b4a44fe1f33e3030810618194f817caaecEric Laurent
13129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** @see AudioManager#setMode(int) */
13139272b4b4a44fe1f33e3030810618194f817caaecEric Laurent    public void setMode(int mode, IBinder cb) {
13149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (!checkAudioSettingsPermission("setMode()")) {
13159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return;
13169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1317a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent
13188f677d66d9c3ba34c97e69b2bb9e161f129af0eeJean-Michel Trivi        if (mode < AudioSystem.MODE_CURRENT || mode >= AudioSystem.NUM_MODES) {
1319a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent            return;
1320a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent        }
1321a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent
1322d7454be47f4111c0478a502353e11dea401378bdEric Laurent        int newModeOwnerPid = 0;
13239f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent        synchronized(mSetModeDeathHandlers) {
1324a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent            if (mode == AudioSystem.MODE_CURRENT) {
1325a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent                mode = mMode;
1326a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent            }
1327d7454be47f4111c0478a502353e11dea401378bdEric Laurent            newModeOwnerPid = setModeInt(mode, cb, Binder.getCallingPid());
13289f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent        }
13299f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent        // when entering RINGTONE, IN_CALL or IN_COMMUNICATION mode, clear all
13309f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent        // SCO connections not started by the application changing the mode
1331d7454be47f4111c0478a502353e11dea401378bdEric Laurent        if (newModeOwnerPid != 0) {
1332d7454be47f4111c0478a502353e11dea401378bdEric Laurent             disconnectBluetoothSco(newModeOwnerPid);
13339f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent        }
13349f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent    }
13352ade576148fe33c5ff6098d30ccfbcf28df70e8eJean-Michel Trivi
13369f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent    // must be called synchronized on mSetModeDeathHandlers
1337d7454be47f4111c0478a502353e11dea401378bdEric Laurent    // setModeInt() returns a valid PID if the audio mode was successfully set to
13389f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent    // any mode other than NORMAL.
1339d7454be47f4111c0478a502353e11dea401378bdEric Laurent    int setModeInt(int mode, IBinder cb, int pid) {
1340d7454be47f4111c0478a502353e11dea401378bdEric Laurent        int newModeOwnerPid = 0;
13419f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent        if (cb == null) {
13429f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent            Log.e(TAG, "setModeInt() called with null binder");
1343d7454be47f4111c0478a502353e11dea401378bdEric Laurent            return newModeOwnerPid;
13449f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent        }
13452ade576148fe33c5ff6098d30ccfbcf28df70e8eJean-Michel Trivi
13469f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent        SetModeDeathHandler hdlr = null;
13479f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent        Iterator iter = mSetModeDeathHandlers.iterator();
13489f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent        while (iter.hasNext()) {
13499f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent            SetModeDeathHandler h = (SetModeDeathHandler)iter.next();
13509f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent            if (h.getPid() == pid) {
13519f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                hdlr = h;
13529f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                // Remove from client list so that it is re-inserted at top of list
13539f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                iter.remove();
13549f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                hdlr.getBinder().unlinkToDeath(hdlr, 0);
13559f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                break;
13569f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent            }
13579f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent        }
13589f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent        int status = AudioSystem.AUDIO_STATUS_OK;
13599f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent        do {
13609f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent            if (mode == AudioSystem.MODE_NORMAL) {
13619f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                // get new mode from client at top the list if any
13629f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                if (!mSetModeDeathHandlers.isEmpty()) {
13639f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                    hdlr = mSetModeDeathHandlers.get(0);
13649f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                    cb = hdlr.getBinder();
13659f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                    mode = hdlr.getMode();
13669f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                }
13679f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent            } else {
13689f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                if (hdlr == null) {
13699f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                    hdlr = new SetModeDeathHandler(cb, pid);
13709f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                }
13719f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                // Register for client death notification
13729f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                try {
13739f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                    cb.linkToDeath(hdlr, 0);
13749f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                } catch (RemoteException e) {
13759f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                    // Client has died!
13769f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                    Log.w(TAG, "setMode() could not link to "+cb+" binder death");
13779f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                }
13789272b4b4a44fe1f33e3030810618194f817caaecEric Laurent
13799f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                // Last client to call setMode() is always at top of client list
13809f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                // as required by SetModeDeathHandler.binderDied()
13819f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                mSetModeDeathHandlers.add(0, hdlr);
13829f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                hdlr.setMode(mode);
13839f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent            }
13843def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent
13859f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent            if (mode != mMode) {
13869f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                status = AudioSystem.setPhoneState(mode);
13879f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                if (status == AudioSystem.AUDIO_STATUS_OK) {
13889f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                    mMode = mode;
13899f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                } else {
13909f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                    if (hdlr != null) {
13919f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                        mSetModeDeathHandlers.remove(hdlr);
13929f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                        cb.unlinkToDeath(hdlr, 0);
13933def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                    }
13949f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                    // force reading new top of mSetModeDeathHandlers stack
13959f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                    mode = AudioSystem.MODE_NORMAL;
1396b9c9d260f21b321527c4622a123af9767630d94dEric Laurent                }
13979f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent            } else {
13989f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                status = AudioSystem.AUDIO_STATUS_OK;
13999f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent            }
14009f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent        } while (status != AudioSystem.AUDIO_STATUS_OK && !mSetModeDeathHandlers.isEmpty());
14019f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent
14029f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent        if (status == AudioSystem.AUDIO_STATUS_OK) {
14039f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent            if (mode != AudioSystem.MODE_NORMAL) {
1404d7454be47f4111c0478a502353e11dea401378bdEric Laurent                if (mSetModeDeathHandlers.isEmpty()) {
1405d7454be47f4111c0478a502353e11dea401378bdEric Laurent                    Log.e(TAG, "setMode() different from MODE_NORMAL with empty mode client stack");
1406d7454be47f4111c0478a502353e11dea401378bdEric Laurent                } else {
1407d7454be47f4111c0478a502353e11dea401378bdEric Laurent                    newModeOwnerPid = mSetModeDeathHandlers.get(0).getPid();
1408d7454be47f4111c0478a502353e11dea401378bdEric Laurent                }
14099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
14109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int streamType = getActiveStreamType(AudioManager.USE_DEFAULT_STREAM_TYPE);
14113114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi            if (streamType == STREAM_REMOTE_MUSIC) {
14123114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                // here handle remote media playback the same way as local playback
14133114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                streamType = AudioManager.STREAM_MUSIC;
14143114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi            }
14159bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent            int device = getDeviceForStream(streamType);
14166d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent            int index = mStreamStates[mStreamVolumeAlias[streamType]].getIndex(device, false);
14176d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent            setStreamVolumeInt(mStreamVolumeAlias[streamType], index, device, true, false);
14186d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent
14196d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent            updateStreamVolumeAlias(true /*updateVolumes*/);
14209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1421d7454be47f4111c0478a502353e11dea401378bdEric Laurent        return newModeOwnerPid;
14229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
14239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
14249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** @see AudioManager#getMode() */
14259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public int getMode() {
14269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return mMode;
14279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
14289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
14299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** @see AudioManager#playSoundEffect(int) */
14309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void playSoundEffect(int effectType) {
1431afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent        sendMsg(mAudioHandler, MSG_PLAY_SOUND_EFFECT, SENDMSG_NOOP,
1432a2ef57dba9ac77d8eccacd646b2b8a8d99fe9d8bEric Laurent                effectType, -1, null, 0);
14339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
14349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
14359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** @see AudioManager#playSoundEffect(int, float) */
14369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void playSoundEffectVolume(int effectType, float volume) {
1437a2ef57dba9ac77d8eccacd646b2b8a8d99fe9d8bEric Laurent        loadSoundEffects();
1438afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent        sendMsg(mAudioHandler, MSG_PLAY_SOUND_EFFECT, SENDMSG_NOOP,
14399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                effectType, (int) (volume * 1000), null, 0);
14409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
14419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
14429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
14439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Loads samples into the soundpool.
14445c17a820f9e46e0756c11795b3e6f89105f2f539Glenn Kasten     * This method must be called at first when sound effects are enabled
14459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
14469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public boolean loadSoundEffects() {
1447a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent        int status;
1448a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent
14499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        synchronized (mSoundEffectsLock) {
1450a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent            if (!mBootCompleted) {
1451a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent                Log.w(TAG, "loadSoundEffects() called before boot complete");
1452a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent                return false;
1453a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent            }
1454a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent
1455a2ef57dba9ac77d8eccacd646b2b8a8d99fe9d8bEric Laurent            if (mSoundPool != null) {
1456a2ef57dba9ac77d8eccacd646b2b8a8d99fe9d8bEric Laurent                return true;
1457a2ef57dba9ac77d8eccacd646b2b8a8d99fe9d8bEric Laurent            }
14589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mSoundPool = new SoundPool(NUM_SOUNDPOOL_CHANNELS, AudioSystem.STREAM_SYSTEM, 0);
1459a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent
1460a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent            try {
1461a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent                mSoundPoolCallBack = null;
1462a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent                mSoundPoolListenerThread = new SoundPoolListenerThread();
1463a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent                mSoundPoolListenerThread.start();
1464a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent                // Wait for mSoundPoolCallBack to be set by the other thread
1465a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent                mSoundEffectsLock.wait();
1466a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent            } catch (InterruptedException e) {
1467a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent                Log.w(TAG, "Interrupted while waiting sound pool listener thread.");
1468a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent            }
1469a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent
1470a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent            if (mSoundPoolCallBack == null) {
1471a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent                Log.w(TAG, "loadSoundEffects() could not create SoundPool listener or thread");
1472a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent                if (mSoundPoolLooper != null) {
1473a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent                    mSoundPoolLooper.quit();
1474a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent                    mSoundPoolLooper = null;
1475a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent                }
1476a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent                mSoundPoolListenerThread = null;
1477a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent                mSoundPool.release();
1478a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent                mSoundPool = null;
14799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return false;
14809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
14819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            /*
14829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project             * poolId table: The value -1 in this table indicates that corresponding
14839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project             * file (same index in SOUND_EFFECT_FILES[] has not been loaded.
14849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project             * Once loaded, the value in poolId is the sample ID and the same
14859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project             * sample can be reused for another effect using the same file.
14869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project             */
14879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int[] poolId = new int[SOUND_EFFECT_FILES.length];
14889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            for (int fileIdx = 0; fileIdx < SOUND_EFFECT_FILES.length; fileIdx++) {
14899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                poolId[fileIdx] = -1;
14909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
14919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            /*
14929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project             * Effects whose value in SOUND_EFFECT_FILES_MAP[effect][1] is -1 must be loaded.
14939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project             * If load succeeds, value in SOUND_EFFECT_FILES_MAP[effect][1] is > 0:
14949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project             * this indicates we have a valid sample loaded for this effect.
14959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project             */
1496a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent
1497117b7bb5b5a4457711f59bde3dcc83d8f111c524Eric Laurent            int lastSample = 0;
14989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            for (int effect = 0; effect < AudioManager.NUM_SOUND_EFFECTS; effect++) {
14999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // Do not load sample if this effect uses the MediaPlayer
15009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (SOUND_EFFECT_FILES_MAP[effect][1] == 0) {
15019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    continue;
15029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
15039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (poolId[SOUND_EFFECT_FILES_MAP[effect][0]] == -1) {
1504a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent                    String filePath = Environment.getRootDirectory()
1505a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent                            + SOUND_EFFECTS_PATH
1506a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent                            + SOUND_EFFECT_FILES[SOUND_EFFECT_FILES_MAP[effect][0]];
15079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    int sampleId = mSoundPool.load(filePath, 0);
15089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    if (sampleId <= 0) {
15099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        Log.w(TAG, "Soundpool could not load file: "+filePath);
1510117b7bb5b5a4457711f59bde3dcc83d8f111c524Eric Laurent                    } else {
1511117b7bb5b5a4457711f59bde3dcc83d8f111c524Eric Laurent                        SOUND_EFFECT_FILES_MAP[effect][1] = sampleId;
1512117b7bb5b5a4457711f59bde3dcc83d8f111c524Eric Laurent                        poolId[SOUND_EFFECT_FILES_MAP[effect][0]] = sampleId;
1513117b7bb5b5a4457711f59bde3dcc83d8f111c524Eric Laurent                        lastSample = sampleId;
15149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    }
15159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                } else {
15169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    SOUND_EFFECT_FILES_MAP[effect][1] = poolId[SOUND_EFFECT_FILES_MAP[effect][0]];
15179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
15189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
1519a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent            // wait for all samples to be loaded
1520117b7bb5b5a4457711f59bde3dcc83d8f111c524Eric Laurent            if (lastSample != 0) {
1521117b7bb5b5a4457711f59bde3dcc83d8f111c524Eric Laurent                mSoundPoolCallBack.setLastSample(lastSample);
1522117b7bb5b5a4457711f59bde3dcc83d8f111c524Eric Laurent
1523117b7bb5b5a4457711f59bde3dcc83d8f111c524Eric Laurent                try {
1524117b7bb5b5a4457711f59bde3dcc83d8f111c524Eric Laurent                    mSoundEffectsLock.wait();
1525117b7bb5b5a4457711f59bde3dcc83d8f111c524Eric Laurent                    status = mSoundPoolCallBack.status();
1526117b7bb5b5a4457711f59bde3dcc83d8f111c524Eric Laurent                } catch (java.lang.InterruptedException e) {
1527117b7bb5b5a4457711f59bde3dcc83d8f111c524Eric Laurent                    Log.w(TAG, "Interrupted while waiting sound pool callback.");
1528117b7bb5b5a4457711f59bde3dcc83d8f111c524Eric Laurent                    status = -1;
1529117b7bb5b5a4457711f59bde3dcc83d8f111c524Eric Laurent                }
1530117b7bb5b5a4457711f59bde3dcc83d8f111c524Eric Laurent            } else {
1531a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent                status = -1;
1532a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent            }
1533117b7bb5b5a4457711f59bde3dcc83d8f111c524Eric Laurent
1534a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent            if (mSoundPoolLooper != null) {
1535a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent                mSoundPoolLooper.quit();
1536a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent                mSoundPoolLooper = null;
1537a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent            }
1538a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent            mSoundPoolListenerThread = null;
1539a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent            if (status != 0) {
1540a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent                Log.w(TAG,
1541a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent                        "loadSoundEffects(), Error "
1542117b7bb5b5a4457711f59bde3dcc83d8f111c524Eric Laurent                                + ((lastSample != 0) ? mSoundPoolCallBack.status() : -1)
1543a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent                                + " while loading samples");
1544117b7bb5b5a4457711f59bde3dcc83d8f111c524Eric Laurent                for (int effect = 0; effect < AudioManager.NUM_SOUND_EFFECTS; effect++) {
1545117b7bb5b5a4457711f59bde3dcc83d8f111c524Eric Laurent                    if (SOUND_EFFECT_FILES_MAP[effect][1] > 0) {
1546117b7bb5b5a4457711f59bde3dcc83d8f111c524Eric Laurent                        SOUND_EFFECT_FILES_MAP[effect][1] = -1;
1547117b7bb5b5a4457711f59bde3dcc83d8f111c524Eric Laurent                    }
1548117b7bb5b5a4457711f59bde3dcc83d8f111c524Eric Laurent                }
1549117b7bb5b5a4457711f59bde3dcc83d8f111c524Eric Laurent
1550a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent                mSoundPool.release();
1551a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent                mSoundPool = null;
1552a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent            }
15539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1554a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent        return (status == 0);
15559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
15569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
15579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
15589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *  Unloads samples from the sound pool.
15599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *  This method can be called to free some memory when
15609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *  sound effects are disabled.
15619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
15629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void unloadSoundEffects() {
15639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        synchronized (mSoundEffectsLock) {
15649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (mSoundPool == null) {
15659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return;
15669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
1567a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent
1568117b7bb5b5a4457711f59bde3dcc83d8f111c524Eric Laurent            mAudioHandler.removeMessages(MSG_LOAD_SOUND_EFFECTS);
1569a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent            mAudioHandler.removeMessages(MSG_PLAY_SOUND_EFFECT);
1570a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent
15719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int[] poolId = new int[SOUND_EFFECT_FILES.length];
15729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            for (int fileIdx = 0; fileIdx < SOUND_EFFECT_FILES.length; fileIdx++) {
15739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                poolId[fileIdx] = 0;
15749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
15759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
15769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            for (int effect = 0; effect < AudioManager.NUM_SOUND_EFFECTS; effect++) {
15779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (SOUND_EFFECT_FILES_MAP[effect][1] <= 0) {
15789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    continue;
15799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
15809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (poolId[SOUND_EFFECT_FILES_MAP[effect][0]] == 0) {
15819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    mSoundPool.unload(SOUND_EFFECT_FILES_MAP[effect][1]);
15829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    SOUND_EFFECT_FILES_MAP[effect][1] = -1;
15839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    poolId[SOUND_EFFECT_FILES_MAP[effect][0]] = -1;
15849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
15859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
1586a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent            mSoundPool.release();
15879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mSoundPool = null;
15889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
15899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
15909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1591a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent    class SoundPoolListenerThread extends Thread {
1592a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent        public SoundPoolListenerThread() {
1593a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent            super("SoundPoolListenerThread");
1594a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent        }
1595a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent
1596a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent        @Override
1597a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent        public void run() {
1598a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent
1599a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent            Looper.prepare();
1600a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent            mSoundPoolLooper = Looper.myLooper();
1601a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent
1602a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent            synchronized (mSoundEffectsLock) {
1603a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent                if (mSoundPool != null) {
1604a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent                    mSoundPoolCallBack = new SoundPoolCallback();
1605a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent                    mSoundPool.setOnLoadCompleteListener(mSoundPoolCallBack);
1606a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent                }
1607a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent                mSoundEffectsLock.notify();
1608a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent            }
1609a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent            Looper.loop();
1610a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent        }
1611a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent    }
1612a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent
1613a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent    private final class SoundPoolCallback implements
1614a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent            android.media.SoundPool.OnLoadCompleteListener {
1615a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent
1616a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent        int mStatus;
1617a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent        int mLastSample;
1618a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent
1619a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent        public int status() {
1620a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent            return mStatus;
1621a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent        }
1622a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent
1623a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent        public void setLastSample(int sample) {
1624a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent            mLastSample = sample;
1625a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent        }
1626a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent
1627a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent        public void onLoadComplete(SoundPool soundPool, int sampleId, int status) {
1628a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent            synchronized (mSoundEffectsLock) {
1629a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent                if (status != 0) {
1630a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent                    mStatus = status;
1631a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent                }
1632a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent                if (sampleId == mLastSample) {
1633a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent                    mSoundEffectsLock.notify();
1634a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent                }
1635a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent            }
1636a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent        }
1637a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent    }
1638a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent
16394050c93601b3c3609b21cc1e18a29b64747e7fa9Eric Laurent    /** @see AudioManager#reloadAudioSettings() */
16404050c93601b3c3609b21cc1e18a29b64747e7fa9Eric Laurent    public void reloadAudioSettings() {
16414050c93601b3c3609b21cc1e18a29b64747e7fa9Eric Laurent        // restore ringer mode, ringer mode affected streams, mute affected streams and vibrate settings
16424050c93601b3c3609b21cc1e18a29b64747e7fa9Eric Laurent        readPersistedSettings();
16434050c93601b3c3609b21cc1e18a29b64747e7fa9Eric Laurent
16444050c93601b3c3609b21cc1e18a29b64747e7fa9Eric Laurent        // restore volume settings
16454050c93601b3c3609b21cc1e18a29b64747e7fa9Eric Laurent        int numStreamTypes = AudioSystem.getNumStreamTypes();
16464050c93601b3c3609b21cc1e18a29b64747e7fa9Eric Laurent        for (int streamType = 0; streamType < numStreamTypes; streamType++) {
16474050c93601b3c3609b21cc1e18a29b64747e7fa9Eric Laurent            VolumeStreamState streamState = mStreamStates[streamType];
16484050c93601b3c3609b21cc1e18a29b64747e7fa9Eric Laurent
16493172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent            synchronized (streamState) {
16503172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                streamState.readSettings();
1651a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent
16523172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                // unmute stream that was muted but is not affect by mute anymore
16533172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                if (streamState.muteCount() != 0 && !isStreamAffectedByMute(streamType)) {
16543172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                    int size = streamState.mDeathHandlers.size();
16553172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                    for (int i = 0; i < size; i++) {
16563172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                        streamState.mDeathHandlers.get(i).mMuteCount = 1;
16573172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                        streamState.mDeathHandlers.get(i).mute(false);
16583172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                    }
16593172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                }
16604050c93601b3c3609b21cc1e18a29b64747e7fa9Eric Laurent            }
16614050c93601b3c3609b21cc1e18a29b64747e7fa9Eric Laurent        }
16624050c93601b3c3609b21cc1e18a29b64747e7fa9Eric Laurent
1663244820185269991186d07068b92985624cede4a5Eric Laurent        checkAllAliasStreamVolumes();
1664244820185269991186d07068b92985624cede4a5Eric Laurent
16654050c93601b3c3609b21cc1e18a29b64747e7fa9Eric Laurent        // apply new ringer mode
16664050c93601b3c3609b21cc1e18a29b64747e7fa9Eric Laurent        setRingerModeInt(getRingerMode(), false);
16674050c93601b3c3609b21cc1e18a29b64747e7fa9Eric Laurent    }
16684050c93601b3c3609b21cc1e18a29b64747e7fa9Eric Laurent
1669c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent    /** @see AudioManager#setSpeakerphoneOn() */
1670c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent    public void setSpeakerphoneOn(boolean on){
1671dc1d17a1dbfc2ae01c20012133a836b62f5b6930Eric Laurent        if (!checkAudioSettingsPermission("setSpeakerphoneOn()")) {
1672dc1d17a1dbfc2ae01c20012133a836b62f5b6930Eric Laurent            return;
1673dc1d17a1dbfc2ae01c20012133a836b62f5b6930Eric Laurent        }
1674fa640154f1f42121d81242b2f1a10f03e52f0014Eric Laurent        mForcedUseForComm = on ? AudioSystem.FORCE_SPEAKER : AudioSystem.FORCE_NONE;
1675fa640154f1f42121d81242b2f1a10f03e52f0014Eric Laurent
1676afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent        sendMsg(mAudioHandler, MSG_SET_FORCE_USE, SENDMSG_QUEUE,
1677fa640154f1f42121d81242b2f1a10f03e52f0014Eric Laurent                AudioSystem.FOR_COMMUNICATION, mForcedUseForComm, null, 0);
1678c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent    }
1679c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent
1680c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent    /** @see AudioManager#isSpeakerphoneOn() */
1681c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent    public boolean isSpeakerphoneOn() {
1682fa640154f1f42121d81242b2f1a10f03e52f0014Eric Laurent        return (mForcedUseForComm == AudioSystem.FORCE_SPEAKER);
1683c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent    }
1684c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent
1685c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent    /** @see AudioManager#setBluetoothScoOn() */
1686c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent    public void setBluetoothScoOn(boolean on){
1687dc1d17a1dbfc2ae01c20012133a836b62f5b6930Eric Laurent        if (!checkAudioSettingsPermission("setBluetoothScoOn()")) {
1688dc1d17a1dbfc2ae01c20012133a836b62f5b6930Eric Laurent            return;
1689dc1d17a1dbfc2ae01c20012133a836b62f5b6930Eric Laurent        }
1690fa640154f1f42121d81242b2f1a10f03e52f0014Eric Laurent        mForcedUseForComm = on ? AudioSystem.FORCE_BT_SCO : AudioSystem.FORCE_NONE;
1691fa640154f1f42121d81242b2f1a10f03e52f0014Eric Laurent
1692afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent        sendMsg(mAudioHandler, MSG_SET_FORCE_USE, SENDMSG_QUEUE,
1693fa640154f1f42121d81242b2f1a10f03e52f0014Eric Laurent                AudioSystem.FOR_COMMUNICATION, mForcedUseForComm, null, 0);
1694afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent        sendMsg(mAudioHandler, MSG_SET_FORCE_USE, SENDMSG_QUEUE,
1695fa640154f1f42121d81242b2f1a10f03e52f0014Eric Laurent                AudioSystem.FOR_RECORD, mForcedUseForComm, null, 0);
1696c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent    }
1697c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent
1698c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent    /** @see AudioManager#isBluetoothScoOn() */
1699c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent    public boolean isBluetoothScoOn() {
1700fa640154f1f42121d81242b2f1a10f03e52f0014Eric Laurent        return (mForcedUseForComm == AudioSystem.FORCE_BT_SCO);
1701c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent    }
1702c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent
17037847211fb4699bf6018e29d214a918ed6657319bEric Laurent    /** @see AudioManager#setBluetoothA2dpOn() */
17047847211fb4699bf6018e29d214a918ed6657319bEric Laurent    public void setBluetoothA2dpOn(boolean on) {
1705c390bed06b4a572e273ead1254da9a932e04dce3Eric Laurent        synchronized (mBluetoothA2dpEnabledLock) {
1706c390bed06b4a572e273ead1254da9a932e04dce3Eric Laurent            mBluetoothA2dpEnabled = on;
1707c390bed06b4a572e273ead1254da9a932e04dce3Eric Laurent            sendMsg(mAudioHandler, MSG_SET_FORCE_BT_A2DP_USE, SENDMSG_QUEUE,
1708c390bed06b4a572e273ead1254da9a932e04dce3Eric Laurent                    AudioSystem.FOR_MEDIA,
1709c390bed06b4a572e273ead1254da9a932e04dce3Eric Laurent                    mBluetoothA2dpEnabled ? AudioSystem.FORCE_NONE : AudioSystem.FORCE_NO_BT_A2DP,
1710c390bed06b4a572e273ead1254da9a932e04dce3Eric Laurent                    null, 0);
1711c390bed06b4a572e273ead1254da9a932e04dce3Eric Laurent        }
17127847211fb4699bf6018e29d214a918ed6657319bEric Laurent    }
17137847211fb4699bf6018e29d214a918ed6657319bEric Laurent
17147847211fb4699bf6018e29d214a918ed6657319bEric Laurent    /** @see AudioManager#isBluetoothA2dpOn() */
17157847211fb4699bf6018e29d214a918ed6657319bEric Laurent    public boolean isBluetoothA2dpOn() {
17167847211fb4699bf6018e29d214a918ed6657319bEric Laurent        synchronized (mBluetoothA2dpEnabledLock) {
17177847211fb4699bf6018e29d214a918ed6657319bEric Laurent            return mBluetoothA2dpEnabled;
17187847211fb4699bf6018e29d214a918ed6657319bEric Laurent        }
17197847211fb4699bf6018e29d214a918ed6657319bEric Laurent    }
17207847211fb4699bf6018e29d214a918ed6657319bEric Laurent
17213def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent    /** @see AudioManager#startBluetoothSco() */
17223def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent    public void startBluetoothSco(IBinder cb){
1723dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent        if (!checkAudioSettingsPermission("startBluetoothSco()") ||
1724dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                !mBootCompleted) {
17253def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent            return;
17263def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent        }
1727854938a72d968c1bc0de4e2b0ea87777cfebc045Eric Laurent        ScoClient client = getScoClient(cb, true);
17283def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent        client.incCount();
17293def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent    }
17303def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent
17313def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent    /** @see AudioManager#stopBluetoothSco() */
17323def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent    public void stopBluetoothSco(IBinder cb){
1733dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent        if (!checkAudioSettingsPermission("stopBluetoothSco()") ||
1734dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                !mBootCompleted) {
17353def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent            return;
17363def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent        }
1737854938a72d968c1bc0de4e2b0ea87777cfebc045Eric Laurent        ScoClient client = getScoClient(cb, false);
1738854938a72d968c1bc0de4e2b0ea87777cfebc045Eric Laurent        if (client != null) {
1739854938a72d968c1bc0de4e2b0ea87777cfebc045Eric Laurent            client.decCount();
1740854938a72d968c1bc0de4e2b0ea87777cfebc045Eric Laurent        }
17413def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent    }
17423def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent
17437847211fb4699bf6018e29d214a918ed6657319bEric Laurent
17443def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent    private class ScoClient implements IBinder.DeathRecipient {
17453def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent        private IBinder mCb; // To be notified of client's death
1746f1ddd51f9cd2f92b922bc636c307210a8d587c25Marco Nelissen        private int mCreatorPid;
17473def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent        private int mStartcount; // number of SCO connections started by this client
17483def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent
17493def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent        ScoClient(IBinder cb) {
17503def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent            mCb = cb;
1751f1ddd51f9cd2f92b922bc636c307210a8d587c25Marco Nelissen            mCreatorPid = Binder.getCallingPid();
17523def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent            mStartcount = 0;
17533def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent        }
17543def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent
17553def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent        public void binderDied() {
17563def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent            synchronized(mScoClients) {
17573def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                Log.w(TAG, "SCO client died");
17583def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                int index = mScoClients.indexOf(this);
17593def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                if (index < 0) {
17603def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                    Log.w(TAG, "unregistered SCO client died");
17613def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                } else {
17623def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                    clearCount(true);
17633def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                    mScoClients.remove(this);
17643def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                }
17653def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent            }
17663def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent        }
17673def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent
17683def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent        public void incCount() {
17693def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent            synchronized(mScoClients) {
177082aa7f017daaaeb96c13e6e3491d5037ab471085Jaikumar Ganesh                requestScoState(BluetoothHeadset.STATE_AUDIO_CONNECTED);
17713def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                if (mStartcount == 0) {
17723def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                    try {
17733def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                        mCb.linkToDeath(this, 0);
17743def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                    } catch (RemoteException e) {
17753def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                        // client has already died!
17763def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                        Log.w(TAG, "ScoClient  incCount() could not link to "+mCb+" binder death");
17773def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                    }
17783def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                }
17793def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                mStartcount++;
17803def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent            }
17813def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent        }
17823def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent
17833def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent        public void decCount() {
17843def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent            synchronized(mScoClients) {
17853def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                if (mStartcount == 0) {
17863def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                    Log.w(TAG, "ScoClient.decCount() already 0");
17873def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                } else {
17883def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                    mStartcount--;
17893def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                    if (mStartcount == 0) {
1790e2dd8c4592762414c2c27e4589be7edc91a5ecaeEric Laurent                        try {
1791e2dd8c4592762414c2c27e4589be7edc91a5ecaeEric Laurent                            mCb.unlinkToDeath(this, 0);
1792e2dd8c4592762414c2c27e4589be7edc91a5ecaeEric Laurent                        } catch (NoSuchElementException e) {
1793e2dd8c4592762414c2c27e4589be7edc91a5ecaeEric Laurent                            Log.w(TAG, "decCount() going to 0 but not registered to binder");
1794e2dd8c4592762414c2c27e4589be7edc91a5ecaeEric Laurent                        }
17953def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                    }
179682aa7f017daaaeb96c13e6e3491d5037ab471085Jaikumar Ganesh                    requestScoState(BluetoothHeadset.STATE_AUDIO_DISCONNECTED);
17973def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                }
17983def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent            }
17993def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent        }
18003def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent
18013def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent        public void clearCount(boolean stopSco) {
18023def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent            synchronized(mScoClients) {
1803e2dd8c4592762414c2c27e4589be7edc91a5ecaeEric Laurent                if (mStartcount != 0) {
1804e2dd8c4592762414c2c27e4589be7edc91a5ecaeEric Laurent                    try {
1805e2dd8c4592762414c2c27e4589be7edc91a5ecaeEric Laurent                        mCb.unlinkToDeath(this, 0);
1806e2dd8c4592762414c2c27e4589be7edc91a5ecaeEric Laurent                    } catch (NoSuchElementException e) {
1807e2dd8c4592762414c2c27e4589be7edc91a5ecaeEric Laurent                        Log.w(TAG, "clearCount() mStartcount: "+mStartcount+" != 0 but not registered to binder");
1808e2dd8c4592762414c2c27e4589be7edc91a5ecaeEric Laurent                    }
1809e2dd8c4592762414c2c27e4589be7edc91a5ecaeEric Laurent                }
18103def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                mStartcount = 0;
18113def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                if (stopSco) {
181282aa7f017daaaeb96c13e6e3491d5037ab471085Jaikumar Ganesh                    requestScoState(BluetoothHeadset.STATE_AUDIO_DISCONNECTED);
18133def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                }
18143def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent            }
18153def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent        }
18163def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent
18173def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent        public int getCount() {
18183def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent            return mStartcount;
18193def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent        }
18203def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent
18213def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent        public IBinder getBinder() {
18223def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent            return mCb;
18233def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent        }
18243def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent
1825d7454be47f4111c0478a502353e11dea401378bdEric Laurent        public int getPid() {
1826d7454be47f4111c0478a502353e11dea401378bdEric Laurent            return mCreatorPid;
1827d7454be47f4111c0478a502353e11dea401378bdEric Laurent        }
1828d7454be47f4111c0478a502353e11dea401378bdEric Laurent
18293def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent        public int totalCount() {
18303def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent            synchronized(mScoClients) {
18313def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                int count = 0;
18323def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                int size = mScoClients.size();
18333def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                for (int i = 0; i < size; i++) {
18343def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                    count += mScoClients.get(i).getCount();
18353def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                }
18363def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                return count;
18373def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent            }
18383def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent        }
18393def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent
18403def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent        private void requestScoState(int state) {
184162ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent            checkScoAudioState();
1842dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent            if (totalCount() == 0) {
1843dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                if (state == BluetoothHeadset.STATE_AUDIO_CONNECTED) {
1844dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                    // Make sure that the state transitions to CONNECTING even if we cannot initiate
1845dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                    // the connection.
1846dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                    broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_CONNECTING);
1847dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                    // Accept SCO audio activation only in NORMAL audio mode or if the mode is
1848f1ddd51f9cd2f92b922bc636c307210a8d587c25Marco Nelissen                    // currently controlled by the same client process.
18499f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                    synchronized(mSetModeDeathHandlers) {
18509f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                        if ((mSetModeDeathHandlers.isEmpty() ||
18519f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                                mSetModeDeathHandlers.get(0).getPid() == mCreatorPid) &&
18529f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                                (mScoAudioState == SCO_STATE_INACTIVE ||
18539f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                                 mScoAudioState == SCO_STATE_DEACTIVATE_REQ)) {
18549f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                            if (mScoAudioState == SCO_STATE_INACTIVE) {
18559f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                                if (mBluetoothHeadset != null && mBluetoothHeadsetDevice != null) {
18569f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                                    if (mBluetoothHeadset.startScoUsingVirtualVoiceCall(
18579f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                                            mBluetoothHeadsetDevice)) {
18589f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                                        mScoAudioState = SCO_STATE_ACTIVE_INTERNAL;
18599f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                                    } else {
18609f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                                        broadcastScoConnectionState(
18619f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                                                AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
18629f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                                    }
18639f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                                } else if (getBluetoothHeadset()) {
18649f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                                    mScoAudioState = SCO_STATE_ACTIVATE_REQ;
1865dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                                }
18669f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                            } else {
18679f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                                mScoAudioState = SCO_STATE_ACTIVE_INTERNAL;
18689f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                                broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_CONNECTED);
1869dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                            }
1870dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                        } else {
18719f103de83f2d5d472960dcf1401e95b2ab57a477Eric Laurent                            broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
1872dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                        }
1873dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                    }
187462ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent                } else if (state == BluetoothHeadset.STATE_AUDIO_DISCONNECTED &&
1875dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                              (mScoAudioState == SCO_STATE_ACTIVE_INTERNAL ||
1876dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                               mScoAudioState == SCO_STATE_ACTIVATE_REQ)) {
1877dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                    if (mScoAudioState == SCO_STATE_ACTIVE_INTERNAL) {
1878671db6f3ba1fdb3c907e0735fe6d0d284f5c34deMarco Nelissen                        if (mBluetoothHeadset != null && mBluetoothHeadsetDevice != null) {
1879dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                            if (!mBluetoothHeadset.stopScoUsingVirtualVoiceCall(
1880dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                                    mBluetoothHeadsetDevice)) {
1881dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                                mScoAudioState = SCO_STATE_INACTIVE;
1882dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                                broadcastScoConnectionState(
1883dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                                        AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
1884dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                            }
1885dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                        } else if (getBluetoothHeadset()) {
1886dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                            mScoAudioState = SCO_STATE_DEACTIVATE_REQ;
1887dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                        }
1888dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                    } else {
1889dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                        mScoAudioState = SCO_STATE_INACTIVE;
1890dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                        broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
1891dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                    }
18923def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                }
18933def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent            }
18943def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent        }
18953def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent    }
18963def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent
189762ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent    private void checkScoAudioState() {
189862ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent        if (mBluetoothHeadset != null && mBluetoothHeadsetDevice != null &&
1899dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                mScoAudioState == SCO_STATE_INACTIVE &&
190062ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent                mBluetoothHeadset.getAudioState(mBluetoothHeadsetDevice)
190162ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent                != BluetoothHeadset.STATE_AUDIO_DISCONNECTED) {
190262ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent            mScoAudioState = SCO_STATE_ACTIVE_EXTERNAL;
190362ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent        }
190462ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent    }
190562ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent
1906854938a72d968c1bc0de4e2b0ea87777cfebc045Eric Laurent    private ScoClient getScoClient(IBinder cb, boolean create) {
19073def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent        synchronized(mScoClients) {
1908854938a72d968c1bc0de4e2b0ea87777cfebc045Eric Laurent            ScoClient client = null;
19093def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent            int size = mScoClients.size();
19103def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent            for (int i = 0; i < size; i++) {
19113def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                client = mScoClients.get(i);
19123def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                if (client.getBinder() == cb)
19133def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                    return client;
19143def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent            }
1915854938a72d968c1bc0de4e2b0ea87777cfebc045Eric Laurent            if (create) {
1916854938a72d968c1bc0de4e2b0ea87777cfebc045Eric Laurent                client = new ScoClient(cb);
1917854938a72d968c1bc0de4e2b0ea87777cfebc045Eric Laurent                mScoClients.add(client);
1918854938a72d968c1bc0de4e2b0ea87777cfebc045Eric Laurent            }
19193def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent            return client;
19203def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent        }
19213def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent    }
19223def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent
1923d7454be47f4111c0478a502353e11dea401378bdEric Laurent    public void clearAllScoClients(int exceptPid, boolean stopSco) {
19243def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent        synchronized(mScoClients) {
1925854938a72d968c1bc0de4e2b0ea87777cfebc045Eric Laurent            ScoClient savedClient = null;
19263def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent            int size = mScoClients.size();
19273def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent            for (int i = 0; i < size; i++) {
1928854938a72d968c1bc0de4e2b0ea87777cfebc045Eric Laurent                ScoClient cl = mScoClients.get(i);
1929d7454be47f4111c0478a502353e11dea401378bdEric Laurent                if (cl.getPid() != exceptPid) {
1930854938a72d968c1bc0de4e2b0ea87777cfebc045Eric Laurent                    cl.clearCount(stopSco);
1931854938a72d968c1bc0de4e2b0ea87777cfebc045Eric Laurent                } else {
1932854938a72d968c1bc0de4e2b0ea87777cfebc045Eric Laurent                    savedClient = cl;
1933854938a72d968c1bc0de4e2b0ea87777cfebc045Eric Laurent                }
1934854938a72d968c1bc0de4e2b0ea87777cfebc045Eric Laurent            }
1935854938a72d968c1bc0de4e2b0ea87777cfebc045Eric Laurent            mScoClients.clear();
1936854938a72d968c1bc0de4e2b0ea87777cfebc045Eric Laurent            if (savedClient != null) {
1937854938a72d968c1bc0de4e2b0ea87777cfebc045Eric Laurent                mScoClients.add(savedClient);
19383def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent            }
19393def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent        }
19403def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent    }
19413def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent
1942dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent    private boolean getBluetoothHeadset() {
1943dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent        boolean result = false;
1944dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent        BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
1945dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent        if (adapter != null) {
1946dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent            result = adapter.getProfileProxy(mContext, mBluetoothProfileServiceListener,
1947dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                                    BluetoothProfile.HEADSET);
1948dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent        }
1949dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent        // If we could not get a bluetooth headset proxy, send a failure message
1950dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent        // without delay to reset the SCO audio state and clear SCO clients.
1951dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent        // If we could get a proxy, send a delayed failure message that will reset our state
1952dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent        // in case we don't receive onServiceConnected().
1953afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent        sendMsg(mAudioHandler, MSG_BT_HEADSET_CNCT_FAILED,
1954dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                SENDMSG_REPLACE, 0, 0, null, result ? BT_HEADSET_CNCT_TIMEOUT_MS : 0);
1955dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent        return result;
1956dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent    }
1957dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent
1958d7454be47f4111c0478a502353e11dea401378bdEric Laurent    private void disconnectBluetoothSco(int exceptPid) {
1959dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent        synchronized(mScoClients) {
1960dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent            checkScoAudioState();
1961dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent            if (mScoAudioState == SCO_STATE_ACTIVE_EXTERNAL ||
1962dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                    mScoAudioState == SCO_STATE_DEACTIVATE_EXT_REQ) {
1963dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                if (mBluetoothHeadsetDevice != null) {
1964dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                    if (mBluetoothHeadset != null) {
1965dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                        if (!mBluetoothHeadset.stopVoiceRecognition(
1966b06ac839dd2d0437fc8314f6deb7233af5af521eEric Laurent                                mBluetoothHeadsetDevice)) {
1967afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent                            sendMsg(mAudioHandler, MSG_BT_HEADSET_CNCT_FAILED,
1968dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                                    SENDMSG_REPLACE, 0, 0, null, 0);
1969dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                        }
1970dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                    } else if (mScoAudioState == SCO_STATE_ACTIVE_EXTERNAL &&
1971dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                            getBluetoothHeadset()) {
1972dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                        mScoAudioState = SCO_STATE_DEACTIVATE_EXT_REQ;
1973dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                    }
1974dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                }
1975dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent            } else {
1976d7454be47f4111c0478a502353e11dea401378bdEric Laurent                clearAllScoClients(exceptPid, true);
1977dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent            }
1978dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent        }
1979dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent    }
1980dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent
1981dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent    private void resetBluetoothSco() {
1982dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent        synchronized(mScoClients) {
1983d7454be47f4111c0478a502353e11dea401378bdEric Laurent            clearAllScoClients(0, false);
1984dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent            mScoAudioState = SCO_STATE_INACTIVE;
1985dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent            broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
1986dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent        }
1987dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent    }
1988dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent
1989dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent    private void broadcastScoConnectionState(int state) {
1990dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent        if (state != mScoConnectionState) {
1991dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent            Intent newIntent = new Intent(AudioManager.ACTION_SCO_AUDIO_STATE_UPDATED);
1992dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent            newIntent.putExtra(AudioManager.EXTRA_SCO_AUDIO_STATE, state);
1993dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent            newIntent.putExtra(AudioManager.EXTRA_SCO_AUDIO_PREVIOUS_STATE,
1994dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                    mScoConnectionState);
1995dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent            mContext.sendStickyBroadcast(newIntent);
1996dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent            mScoConnectionState = state;
1997dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent        }
1998dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent    }
1999dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent
200082aa7f017daaaeb96c13e6e3491d5037ab471085Jaikumar Ganesh    private BluetoothProfile.ServiceListener mBluetoothProfileServiceListener =
200182aa7f017daaaeb96c13e6e3491d5037ab471085Jaikumar Ganesh        new BluetoothProfile.ServiceListener() {
200282aa7f017daaaeb96c13e6e3491d5037ab471085Jaikumar Ganesh        public void onServiceConnected(int profile, BluetoothProfile proxy) {
20036bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent            BluetoothDevice btDevice;
20046bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent            List<BluetoothDevice> deviceList;
20056bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent            switch(profile) {
20066bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent            case BluetoothProfile.A2DP:
20076bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                BluetoothA2dp a2dp = (BluetoothA2dp) proxy;
20086bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                deviceList = a2dp.getConnectedDevices();
200962ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent                if (deviceList.size() > 0) {
20106bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                    btDevice = deviceList.get(0);
2011b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent                    synchronized (mConnectedDevices) {
2012b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent                        int state = a2dp.getConnectionState(btDevice);
2013b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent                        int delay = checkSendBecomingNoisyIntent(
2014b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent                                                AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
2015b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent                                                (state == BluetoothA2dp.STATE_CONNECTED) ? 1 : 0);
2016e12c39bb9cedb8b363658979872694eb55b1386eJean-Michel Trivi                        queueMsgUnderWakeLock(mAudioHandler,
2017b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent                                MSG_SET_A2DP_CONNECTION_STATE,
2018b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent                                state,
2019b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent                                0,
2020b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent                                btDevice,
2021b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent                                delay);
2022b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent                    }
20236bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                }
20246bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                break;
20256bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent
20266bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent            case BluetoothProfile.HEADSET:
20276bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                synchronized (mScoClients) {
20286bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                    // Discard timeout message
20296bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                    mAudioHandler.removeMessages(MSG_BT_HEADSET_CNCT_FAILED);
20306bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                    mBluetoothHeadset = (BluetoothHeadset) proxy;
20316bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                    deviceList = mBluetoothHeadset.getConnectedDevices();
20326bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                    if (deviceList.size() > 0) {
20336bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                        mBluetoothHeadsetDevice = deviceList.get(0);
20346bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                    } else {
20356bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                        mBluetoothHeadsetDevice = null;
2036dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                    }
20376bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                    // Refresh SCO audio state
20386bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                    checkScoAudioState();
20396bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                    // Continue pending action if any
20406bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                    if (mScoAudioState == SCO_STATE_ACTIVATE_REQ ||
20416bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                            mScoAudioState == SCO_STATE_DEACTIVATE_REQ ||
20426bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                            mScoAudioState == SCO_STATE_DEACTIVATE_EXT_REQ) {
20436bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                        boolean status = false;
20446bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                        if (mBluetoothHeadsetDevice != null) {
20456bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                            switch (mScoAudioState) {
20466bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                            case SCO_STATE_ACTIVATE_REQ:
20476bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                                mScoAudioState = SCO_STATE_ACTIVE_INTERNAL;
20486bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                                status = mBluetoothHeadset.startScoUsingVirtualVoiceCall(
20496bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                                        mBluetoothHeadsetDevice);
20506bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                                break;
20516bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                            case SCO_STATE_DEACTIVATE_REQ:
20526bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                                status = mBluetoothHeadset.stopScoUsingVirtualVoiceCall(
20536bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                                        mBluetoothHeadsetDevice);
20546bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                                break;
20556bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                            case SCO_STATE_DEACTIVATE_EXT_REQ:
20566bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                                status = mBluetoothHeadset.stopVoiceRecognition(
20576bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                                        mBluetoothHeadsetDevice);
20586bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                            }
20596bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                        }
20606bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                        if (!status) {
2061afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent                            sendMsg(mAudioHandler, MSG_BT_HEADSET_CNCT_FAILED,
20626bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                                    SENDMSG_REPLACE, 0, 0, null, 0);
20636bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                        }
2064dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                    }
2065dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                }
20666bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                break;
20676bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent
20686bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent            default:
20696bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                break;
20703def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent            }
20713def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent        }
207282aa7f017daaaeb96c13e6e3491d5037ab471085Jaikumar Ganesh        public void onServiceDisconnected(int profile) {
20736bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent            switch(profile) {
20746bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent            case BluetoothProfile.A2DP:
20756bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                synchronized (mConnectedDevices) {
20766bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                    if (mConnectedDevices.containsKey(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP)) {
20776bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                        makeA2dpDeviceUnavailableNow(
20786bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                                mConnectedDevices.get(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP));
20796bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                    }
20806bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                }
20816bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                break;
20826bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent
20836bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent            case BluetoothProfile.HEADSET:
20846bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                synchronized (mScoClients) {
20856bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                    mBluetoothHeadset = null;
20866bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                }
20876bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                break;
20886bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent
20896bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent            default:
20906bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                break;
20913def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent            }
20923def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent        }
20933def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent    };
2094d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi
20959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    ///////////////////////////////////////////////////////////////////////////
20969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // Internal methods
20979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    ///////////////////////////////////////////////////////////////////////////
20989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
20999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
21009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Checks if the adjustment should change ringer mode instead of just
21019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * adjusting volume. If so, this will set the proper ringer mode and volume
21029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * indices on the stream states.
21039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
2104244820185269991186d07068b92985624cede4a5Eric Laurent    private boolean checkForRingerModeChange(int oldIndex, int direction,  int step) {
21059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        boolean adjustVolumeIndex = true;
2106ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten        int ringerMode = getRingerMode();
2107bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent
2108bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent        switch (ringerMode) {
2109bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent        case RINGER_MODE_NORMAL:
2110bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent            if (direction == AudioManager.ADJUST_LOWER) {
2111bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent                if (mHasVibrator) {
2112244820185269991186d07068b92985624cede4a5Eric Laurent                    // "step" is the delta in internal index units corresponding to a
2113244820185269991186d07068b92985624cede4a5Eric Laurent                    // change of 1 in UI index units.
2114244820185269991186d07068b92985624cede4a5Eric Laurent                    // Because of rounding when rescaling from one stream index range to its alias
2115244820185269991186d07068b92985624cede4a5Eric Laurent                    // index range, we cannot simply test oldIndex == step:
2116244820185269991186d07068b92985624cede4a5Eric Laurent                    //   (step <= oldIndex < 2 * step) is equivalent to: (old UI index == 1)
2117244820185269991186d07068b92985624cede4a5Eric Laurent                    if (step <= oldIndex && oldIndex < 2 * step) {
2118bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent                        ringerMode = RINGER_MODE_VIBRATE;
2119bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent                    }
2120bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent                } else {
2121244820185269991186d07068b92985624cede4a5Eric Laurent                    // (oldIndex < step) is equivalent to (old UI index == 0)
2122244820185269991186d07068b92985624cede4a5Eric Laurent                    if ((oldIndex < step) && mPrevVolDirection != AudioManager.ADJUST_LOWER) {
2123bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent                        ringerMode = RINGER_MODE_SILENT;
2124bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent                    }
21253d4c06f90726a85e89dab13c41ddc15b9c912a3fEric Laurent                }
21266329bf7b1e2217c6c9477bd57349a1edade18417Daniel Sandler            }
2127bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent            break;
2128bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent        case RINGER_MODE_VIBRATE:
2129bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent            if (!mHasVibrator) {
2130bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent                Log.e(TAG, "checkForRingerModeChange() current ringer mode is vibrate" +
2131bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent                        "but no vibrator is present");
2132bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent                break;
2133bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent            }
2134c696a53d1fe4d61373c5dc64dd057d322da90c8fAmith Yamasani            if ((direction == AudioManager.ADJUST_LOWER)) {
2135c696a53d1fe4d61373c5dc64dd057d322da90c8fAmith Yamasani                if (mPrevVolDirection != AudioManager.ADJUST_LOWER) {
2136bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent                    ringerMode = RINGER_MODE_SILENT;
2137c696a53d1fe4d61373c5dc64dd057d322da90c8fAmith Yamasani                }
2138c696a53d1fe4d61373c5dc64dd057d322da90c8fAmith Yamasani            } else if (direction == AudioManager.ADJUST_RAISE) {
2139bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent                ringerMode = RINGER_MODE_NORMAL;
2140c696a53d1fe4d61373c5dc64dd057d322da90c8fAmith Yamasani            }
2141c696a53d1fe4d61373c5dc64dd057d322da90c8fAmith Yamasani            adjustVolumeIndex = false;
2142bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent            break;
2143bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent        case RINGER_MODE_SILENT:
21449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (direction == AudioManager.ADJUST_RAISE) {
2145bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent                if (mHasVibrator) {
2146bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent                    ringerMode = RINGER_MODE_VIBRATE;
2147bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent                } else {
2148bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent                    ringerMode = RINGER_MODE_NORMAL;
2149bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent                }
21509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
2151b024c30a80684ac08daef3137b7ba0d347fe3ce5Eric Laurent            adjustVolumeIndex = false;
2152bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent            break;
2153bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent        default:
2154bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent            Log.e(TAG, "checkForRingerModeChange() wrong ringer mode: "+ringerMode);
2155bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent            break;
21569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
21579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2158bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent        setRingerMode(ringerMode);
21599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
216025101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent        mPrevVolDirection = direction;
216125101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent
21629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return adjustVolumeIndex;
21639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
21649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
21659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public boolean isStreamAffectedByRingerMode(int streamType) {
21669bcf401d13d47416043a704430388abd59aef7cdEric Laurent        return (mRingerModeAffectedStreams & (1 << streamType)) != 0;
21679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
21689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
21695b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent    private boolean isStreamMutedByRingerMode(int streamType) {
21705b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent        return (mRingerModeMutedStreams & (1 << streamType)) != 0;
21715b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent    }
21725b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent
21739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public boolean isStreamAffectedByMute(int streamType) {
21749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return (mMuteAffectedStreams & (1 << streamType)) != 0;
21759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
21769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
21779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private void ensureValidDirection(int direction) {
21789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (direction < AudioManager.ADJUST_LOWER || direction > AudioManager.ADJUST_RAISE) {
21799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            throw new IllegalArgumentException("Bad direction " + direction);
21809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
21819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
21829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
21836c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang    private void ensureValidSteps(int steps) {
21846c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang        if (Math.abs(steps) > MAX_BATCH_VOLUME_ADJUST_STEPS) {
21856c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang            throw new IllegalArgumentException("Bad volume adjust steps " + steps);
21866c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang        }
21876c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang    }
21886c798970ccb8759d1e613b57111daa8da0ab44c7Lei Zhang
21899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private void ensureValidStreamType(int streamType) {
21909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (streamType < 0 || streamType >= mStreamStates.length) {
21919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            throw new IllegalArgumentException("Bad stream type " + streamType);
21929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
21939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
21949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
21956d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent    private boolean isInCommunication() {
21966d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent        boolean isOffhook = false;
219725101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent
219825101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent        if (mVoiceCapable) {
219925101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent            try {
220025101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent                ITelephony phone = ITelephony.Stub.asInterface(ServiceManager.checkService("phone"));
220125101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent                if (phone != null) isOffhook = phone.isOffhook();
220225101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent            } catch (RemoteException e) {
220325101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent                Log.w(TAG, "Couldn't connect to phone service", e);
220425101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent            }
22056d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent        }
22066d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent        return (isOffhook || getMode() == AudioManager.MODE_IN_COMMUNICATION);
22076d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent    }
220825101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent
22096d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent    private int getActiveStreamType(int suggestedStreamType) {
22106d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent        if (mVoiceCapable) {
22116d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent            if (isInCommunication()) {
221225101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent                if (AudioSystem.getForceUse(AudioSystem.FOR_COMMUNICATION)
221325101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent                        == AudioSystem.FORCE_BT_SCO) {
221425101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent                    // Log.v(TAG, "getActiveStreamType: Forcing STREAM_BLUETOOTH_SCO...");
221525101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent                    return AudioSystem.STREAM_BLUETOOTH_SCO;
221625101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent                } else {
221725101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent                    // Log.v(TAG, "getActiveStreamType: Forcing STREAM_VOICE_CALL...");
221825101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent                    return AudioSystem.STREAM_VOICE_CALL;
221925101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent                }
22203114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi            } else if (suggestedStreamType == AudioManager.USE_DEFAULT_STREAM_TYPE) {
22213114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                // Having the suggested stream be USE_DEFAULT_STREAM_TYPE is how remote control
22223114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                // volume can have priority over STREAM_MUSIC
22233114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                if (checkUpdateRemoteStateIfActive(AudioSystem.STREAM_MUSIC)) {
22243114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                    if (DEBUG_VOL)
22253114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                        Log.v(TAG, "getActiveStreamType: Forcing STREAM_REMOTE_MUSIC");
22263114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                    return STREAM_REMOTE_MUSIC;
22273114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                } else if (AudioSystem.isStreamActive(AudioSystem.STREAM_MUSIC, 0)) {
22283114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                    if (DEBUG_VOL)
22293114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                        Log.v(TAG, "getActiveStreamType: Forcing STREAM_MUSIC stream active");
22303114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                    return AudioSystem.STREAM_MUSIC;
22313114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                } else {
22323114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                    if (DEBUG_VOL)
22333114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                        Log.v(TAG, "getActiveStreamType: Forcing STREAM_RING b/c default");
22343114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                    return AudioSystem.STREAM_RING;
22353114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                }
223625101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent            } else if (AudioSystem.isStreamActive(AudioSystem.STREAM_MUSIC, 0)) {
22373114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                if (DEBUG_VOL)
22383114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                    Log.v(TAG, "getActiveStreamType: Forcing STREAM_MUSIC stream active");
223925101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent                return AudioSystem.STREAM_MUSIC;
2240c7fcba4b7bd3d78e7cfe975a3f8e4dde2f6738b7Joe Onorato            } else {
22413114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: Returning suggested type "
22423114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                        + suggestedStreamType);
224325101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent                return suggestedStreamType;
224425101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent            }
224525101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent        } else {
22466d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent            if (isInCommunication()) {
224725101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent                if (AudioSystem.getForceUse(AudioSystem.FOR_COMMUNICATION)
224825101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent                        == AudioSystem.FORCE_BT_SCO) {
22493114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                    if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: Forcing STREAM_BLUETOOTH_SCO");
225025101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent                    return AudioSystem.STREAM_BLUETOOTH_SCO;
225125101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent                } else {
22523114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                    if (DEBUG_VOL)  Log.v(TAG, "getActiveStreamType: Forcing STREAM_VOICE_CALL");
225325101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent                    return AudioSystem.STREAM_VOICE_CALL;
225425101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent                }
225525101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent            } else if (AudioSystem.isStreamActive(AudioSystem.STREAM_NOTIFICATION,
22563114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                    NOTIFICATION_VOLUME_DELAY_MS) ||
22573114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                    AudioSystem.isStreamActive(AudioSystem.STREAM_RING,
225825101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent                            NOTIFICATION_VOLUME_DELAY_MS)) {
22593114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: Forcing STREAM_NOTIFICATION");
226025101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent                return AudioSystem.STREAM_NOTIFICATION;
22613114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi            } else if (suggestedStreamType == AudioManager.USE_DEFAULT_STREAM_TYPE) {
22623114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                if (checkUpdateRemoteStateIfActive(AudioSystem.STREAM_MUSIC)) {
22633114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                    // Having the suggested stream be USE_DEFAULT_STREAM_TYPE is how remote control
22643114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                    // volume can have priority over STREAM_MUSIC
22653114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                    if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: Forcing STREAM_REMOTE_MUSIC");
22663114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                    return STREAM_REMOTE_MUSIC;
22673114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                } else {
22683114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                    if (DEBUG_VOL)
22693114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                        Log.v(TAG, "getActiveStreamType: using STREAM_MUSIC as default");
22703114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                    return AudioSystem.STREAM_MUSIC;
22713114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                }
227225101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent            } else {
22733114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: Returning suggested type "
22743114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                        + suggestedStreamType);
227525101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent                return suggestedStreamType;
2276c7fcba4b7bd3d78e7cfe975a3f8e4dde2f6738b7Joe Onorato            }
22779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
22789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
22799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2280ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten    private void broadcastRingerMode(int ringerMode) {
22819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // Send sticky broadcast
22821c633fc89bae9bf0af6fe643ac7ad2e744f27bedDianne Hackborn        Intent broadcast = new Intent(AudioManager.RINGER_MODE_CHANGED_ACTION);
2283ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten        broadcast.putExtra(AudioManager.EXTRA_RINGER_MODE, ringerMode);
22841c633fc89bae9bf0af6fe643ac7ad2e744f27bedDianne Hackborn        broadcast.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT
22851c633fc89bae9bf0af6fe643ac7ad2e744f27bedDianne Hackborn                | Intent.FLAG_RECEIVER_REPLACE_PENDING);
22861c633fc89bae9bf0af6fe643ac7ad2e744f27bedDianne Hackborn        long origCallerIdentityToken = Binder.clearCallingIdentity();
22871c633fc89bae9bf0af6fe643ac7ad2e744f27bedDianne Hackborn        mContext.sendStickyBroadcast(broadcast);
22881c633fc89bae9bf0af6fe643ac7ad2e744f27bedDianne Hackborn        Binder.restoreCallingIdentity(origCallerIdentityToken);
22899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
22909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
22919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private void broadcastVibrateSetting(int vibrateType) {
22929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // Send broadcast
22939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (ActivityManagerNative.isSystemReady()) {
22949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            Intent broadcast = new Intent(AudioManager.VIBRATE_SETTING_CHANGED_ACTION);
22959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            broadcast.putExtra(AudioManager.EXTRA_VIBRATE_TYPE, vibrateType);
22969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            broadcast.putExtra(AudioManager.EXTRA_VIBRATE_SETTING, getVibrateSetting(vibrateType));
22979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mContext.sendBroadcast(broadcast);
22989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
22999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
23009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
23019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // Message helper methods
23022d8dab5a549b25b6f36df4614d7c0166d4d099e2Jean-Michel Trivi    /**
23032d8dab5a549b25b6f36df4614d7c0166d4d099e2Jean-Michel Trivi     * Queue a message on the given handler's message queue, after acquiring the service wake lock.
23042d8dab5a549b25b6f36df4614d7c0166d4d099e2Jean-Michel Trivi     * Note that the wake lock needs to be released after the message has been handled.
23052d8dab5a549b25b6f36df4614d7c0166d4d099e2Jean-Michel Trivi     */
23062d8dab5a549b25b6f36df4614d7c0166d4d099e2Jean-Michel Trivi    private void queueMsgUnderWakeLock(Handler handler, int msg,
23072d8dab5a549b25b6f36df4614d7c0166d4d099e2Jean-Michel Trivi            int arg1, int arg2, Object obj, int delay) {
23082d8dab5a549b25b6f36df4614d7c0166d4d099e2Jean-Michel Trivi        mMediaEventWakeLock.acquire();
23092d8dab5a549b25b6f36df4614d7c0166d4d099e2Jean-Michel Trivi        sendMsg(handler, msg, SENDMSG_QUEUE, arg1, arg2, obj, delay);
23102d8dab5a549b25b6f36df4614d7c0166d4d099e2Jean-Michel Trivi    }
23119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2312afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent    private static void sendMsg(Handler handler, int msg,
23139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int existingMsgPolicy, int arg1, int arg2, Object obj, int delay) {
23149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
23159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (existingMsgPolicy == SENDMSG_REPLACE) {
23169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            handler.removeMessages(msg);
23179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else if (existingMsgPolicy == SENDMSG_NOOP && handler.hasMessages(msg)) {
23189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return;
23199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
23209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2321afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent        handler.sendMessageDelayed(handler.obtainMessage(msg, arg1, arg2, obj), delay);
23229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
23239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
23249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    boolean checkAudioSettingsPermission(String method) {
23259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mContext.checkCallingOrSelfPermission("android.permission.MODIFY_AUDIO_SETTINGS")
23269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                == PackageManager.PERMISSION_GRANTED) {
23279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return true;
23289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
23299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        String msg = "Audio Settings Permission Denial: " + method + " from pid="
23309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                + Binder.getCallingPid()
23319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                + ", uid=" + Binder.getCallingUid();
23329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        Log.w(TAG, msg);
23339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return false;
23349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
23359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
23369bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent    private int getDeviceForStream(int stream) {
23379bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent        int device = AudioSystem.getDevicesForStream(stream);
23389bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent        if ((device & (device - 1)) != 0) {
23399bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent            // Multiple device selection is either:
23409bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent            //  - speaker + one other device: give priority to speaker in this case.
23419bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent            //  - one A2DP device + another device: happens with duplicated output. In this case
23429bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent            // retain the device on the A2DP output as the other must not correspond to an active
23439bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent            // selection if not the speaker.
23449bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent            if ((device & AudioSystem.DEVICE_OUT_SPEAKER) != 0) {
23459bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                device = AudioSystem.DEVICE_OUT_SPEAKER;
23469bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent            } else {
23479bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                device &= AudioSystem.DEVICE_OUT_ALL_A2DP;
23489bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent            }
23499bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent        }
23509bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent        return device;
23519bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent    }
23529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2353b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent    public void setWiredDeviceConnectionState(int device, int state, String name) {
2354b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent        synchronized (mConnectedDevices) {
2355b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent            int delay = checkSendBecomingNoisyIntent(device, state);
23562d8dab5a549b25b6f36df4614d7c0166d4d099e2Jean-Michel Trivi            queueMsgUnderWakeLock(mAudioHandler,
2357b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent                    MSG_SET_WIRED_DEVICE_CONNECTION_STATE,
2358b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent                    device,
2359b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent                    state,
2360b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent                    name,
2361b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent                    delay);
2362b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent        }
2363b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent    }
2364b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent
2365b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent    public int setBluetoothA2dpDeviceConnectionState(BluetoothDevice device, int state)
2366b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent    {
2367b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent        int delay;
2368b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent        synchronized (mConnectedDevices) {
2369b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent            delay = checkSendBecomingNoisyIntent(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
2370b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent                                            (state == BluetoothA2dp.STATE_CONNECTED) ? 1 : 0);
23712d8dab5a549b25b6f36df4614d7c0166d4d099e2Jean-Michel Trivi            queueMsgUnderWakeLock(mAudioHandler,
2372b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent                    MSG_SET_A2DP_CONNECTION_STATE,
2373b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent                    state,
2374b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent                    0,
2375b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent                    device,
2376b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent                    delay);
2377b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent        }
2378b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent        return delay;
2379b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent    }
2380b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent
23819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    ///////////////////////////////////////////////////////////////////////////
23829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // Inner classes
23839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    ///////////////////////////////////////////////////////////////////////////
23849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
23859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public class VolumeStreamState {
23869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        private final int mStreamType;
23879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
238811a74a75653197a3d31fe91590cd8312f5270c44Jean-Michel Trivi        private String mVolumeIndexSettingName;
238911a74a75653197a3d31fe91590cd8312f5270c44Jean-Michel Trivi        private String mLastAudibleVolumeIndexSettingName;
2390a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent        private int mIndexMax;
23913172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent        private final ConcurrentHashMap<Integer, Integer> mIndex =
23923172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                                            new ConcurrentHashMap<Integer, Integer>(8, 0.75f, 4);
23933172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent        private final ConcurrentHashMap<Integer, Integer> mLastAudibleIndex =
23943172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                                            new ConcurrentHashMap<Integer, Integer>(8, 0.75f, 4);
23959bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent        private ArrayList<VolumeDeathHandler> mDeathHandlers; //handles mute/solo clients death
23969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2397a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent        private VolumeStreamState(String settingName, int streamType) {
23989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
23999bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent            mVolumeIndexSettingName = settingName;
24009bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent            mLastAudibleVolumeIndexSettingName = settingName + System.APPEND_FOR_LAST_AUDIBLE;
24019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
24029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mStreamType = streamType;
24035982013cfc8274ff0bafaba83c676b3a8890cba9Jared Suttles            mIndexMax = MAX_STREAM_VOLUME[streamType];
2404a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent            AudioSystem.initStreamVolume(streamType, 0, mIndexMax);
2405a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent            mIndexMax *= 10;
24069bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent
24079bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent            readSettings();
24089bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent
24099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mDeathHandlers = new ArrayList<VolumeDeathHandler>();
24109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
24119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
24129bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent        public String getSettingNameForDevice(boolean lastAudible, int device) {
24139bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent            String name = lastAudible ?
24149bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                            mLastAudibleVolumeIndexSettingName :
24159bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                            mVolumeIndexSettingName;
24169bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent            String suffix = AudioSystem.getDeviceName(device);
24179bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent            if (suffix.isEmpty()) {
24189bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                return name;
24199bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent            }
24209bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent            return name + "_" + suffix;
24219bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent        }
24229bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent
24233172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent        public synchronized void readSettings() {
24249bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent            int remainingDevices = AudioSystem.DEVICE_OUT_ALL;
24259ac8d0c445a3ccde40c05f0f3ad0ec4e8265d4c6Eric Laurent
24269bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent            for (int i = 0; remainingDevices != 0; i++) {
24279bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                int device = (1 << i);
24289bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                if ((device & remainingDevices) == 0) {
24299bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                    continue;
24309bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                }
24319bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                remainingDevices &= ~device;
24329bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent
24339bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                // retrieve current volume for device
24349ac8d0c445a3ccde40c05f0f3ad0ec4e8265d4c6Eric Laurent                String name = getSettingNameForDevice(false /* lastAudible */, device);
24359ac8d0c445a3ccde40c05f0f3ad0ec4e8265d4c6Eric Laurent                // if no volume stored for current stream and device, use default volume if default
24369ac8d0c445a3ccde40c05f0f3ad0ec4e8265d4c6Eric Laurent                // device, continue otherwise
24379ac8d0c445a3ccde40c05f0f3ad0ec4e8265d4c6Eric Laurent                int defaultIndex = (device == AudioSystem.DEVICE_OUT_DEFAULT) ?
24389ac8d0c445a3ccde40c05f0f3ad0ec4e8265d4c6Eric Laurent                                        AudioManager.DEFAULT_STREAM_VOLUME[mStreamType] : -1;
24399ac8d0c445a3ccde40c05f0f3ad0ec4e8265d4c6Eric Laurent                int index = Settings.System.getInt(mContentResolver, name, defaultIndex);
24409bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                if (index == -1) {
24419bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                    continue;
24429bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                }
24439bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent
24449bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                // retrieve last audible volume for device
24459ac8d0c445a3ccde40c05f0f3ad0ec4e8265d4c6Eric Laurent                name = getSettingNameForDevice(true  /* lastAudible */, device);
24469ac8d0c445a3ccde40c05f0f3ad0ec4e8265d4c6Eric Laurent                // use stored last audible index if present, otherwise use current index if not 0
24479ac8d0c445a3ccde40c05f0f3ad0ec4e8265d4c6Eric Laurent                // or default index
24489ac8d0c445a3ccde40c05f0f3ad0ec4e8265d4c6Eric Laurent                defaultIndex = (index > 0) ?
24499ac8d0c445a3ccde40c05f0f3ad0ec4e8265d4c6Eric Laurent                                    index : AudioManager.DEFAULT_STREAM_VOLUME[mStreamType];
24509ac8d0c445a3ccde40c05f0f3ad0ec4e8265d4c6Eric Laurent                int lastAudibleIndex = Settings.System.getInt(mContentResolver, name, defaultIndex);
24519ac8d0c445a3ccde40c05f0f3ad0ec4e8265d4c6Eric Laurent
2452bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent                // a last audible index of 0 should never be stored for ring and notification
2453bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent                // streams on phones (voice capable devices).
2454bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent                // same for system stream on phones and tablets
24559ac8d0c445a3ccde40c05f0f3ad0ec4e8265d4c6Eric Laurent                if ((lastAudibleIndex == 0) &&
2456bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent                        ((mVoiceCapable &&
2457bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent                                (mStreamVolumeAlias[mStreamType] == AudioSystem.STREAM_RING)) ||
2458bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent                         (mStreamVolumeAlias[mStreamType] == AudioSystem.STREAM_SYSTEM))) {
24599ac8d0c445a3ccde40c05f0f3ad0ec4e8265d4c6Eric Laurent                    lastAudibleIndex = AudioManager.DEFAULT_STREAM_VOLUME[mStreamType];
24609ac8d0c445a3ccde40c05f0f3ad0ec4e8265d4c6Eric Laurent                    // Correct the data base
24619ac8d0c445a3ccde40c05f0f3ad0ec4e8265d4c6Eric Laurent                    sendMsg(mAudioHandler,
24629ac8d0c445a3ccde40c05f0f3ad0ec4e8265d4c6Eric Laurent                            MSG_PERSIST_VOLUME,
24639ac8d0c445a3ccde40c05f0f3ad0ec4e8265d4c6Eric Laurent                            SENDMSG_QUEUE,
24649ac8d0c445a3ccde40c05f0f3ad0ec4e8265d4c6Eric Laurent                            PERSIST_LAST_AUDIBLE,
24659ac8d0c445a3ccde40c05f0f3ad0ec4e8265d4c6Eric Laurent                            device,
24669ac8d0c445a3ccde40c05f0f3ad0ec4e8265d4c6Eric Laurent                            this,
24679ac8d0c445a3ccde40c05f0f3ad0ec4e8265d4c6Eric Laurent                            PERSIST_DELAY);
24689ac8d0c445a3ccde40c05f0f3ad0ec4e8265d4c6Eric Laurent                }
24699ac8d0c445a3ccde40c05f0f3ad0ec4e8265d4c6Eric Laurent                mLastAudibleIndex.put(device, getValidIndex(10 * lastAudibleIndex));
2470bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent                // the initial index should never be 0 for ring and notification streams on phones
2471bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent                // (voice capable devices) if not in silent or vibrate mode.
2472bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent                // same for system stream on phones and tablets
2473bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent                if ((index == 0) && (mRingerMode == AudioManager.RINGER_MODE_NORMAL) &&
2474bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent                        ((mVoiceCapable &&
2475bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent                                (mStreamVolumeAlias[mStreamType] == AudioSystem.STREAM_RING)) ||
2476bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent                         (mStreamVolumeAlias[mStreamType] == AudioSystem.STREAM_SYSTEM))) {
24779ac8d0c445a3ccde40c05f0f3ad0ec4e8265d4c6Eric Laurent                    index = lastAudibleIndex;
24789ac8d0c445a3ccde40c05f0f3ad0ec4e8265d4c6Eric Laurent                    // Correct the data base
24799ac8d0c445a3ccde40c05f0f3ad0ec4e8265d4c6Eric Laurent                    sendMsg(mAudioHandler,
24809ac8d0c445a3ccde40c05f0f3ad0ec4e8265d4c6Eric Laurent                            MSG_PERSIST_VOLUME,
24819ac8d0c445a3ccde40c05f0f3ad0ec4e8265d4c6Eric Laurent                            SENDMSG_QUEUE,
24829ac8d0c445a3ccde40c05f0f3ad0ec4e8265d4c6Eric Laurent                            PERSIST_CURRENT,
24839ac8d0c445a3ccde40c05f0f3ad0ec4e8265d4c6Eric Laurent                            device,
24849ac8d0c445a3ccde40c05f0f3ad0ec4e8265d4c6Eric Laurent                            this,
24859ac8d0c445a3ccde40c05f0f3ad0ec4e8265d4c6Eric Laurent                            PERSIST_DELAY);
24869ac8d0c445a3ccde40c05f0f3ad0ec4e8265d4c6Eric Laurent                }
24879ac8d0c445a3ccde40c05f0f3ad0ec4e8265d4c6Eric Laurent                mIndex.put(device, getValidIndex(10 * index));
24889bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent            }
24899bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent        }
24909bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent
24919bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent        public void applyDeviceVolume(int device) {
24929bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent            AudioSystem.setStreamVolumeIndex(mStreamType,
24939bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                                             (getIndex(device, false  /* lastAudible */) + 5)/10,
24949bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                                             device);
24959bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent        }
24969bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent
24973172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent        public synchronized void applyAllVolumes() {
24989bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent            // apply default volume first: by convention this will reset all
24999bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent            // devices volumes in audio policy manager to the supplied value
25009bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent            AudioSystem.setStreamVolumeIndex(mStreamType,
25019bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                    (getIndex(AudioSystem.DEVICE_OUT_DEFAULT, false /* lastAudible */) + 5)/10,
25029bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                    AudioSystem.DEVICE_OUT_DEFAULT);
25039bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent            // then apply device specific volumes
25049bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent            Set set = mIndex.entrySet();
25059bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent            Iterator i = set.iterator();
25069bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent            while (i.hasNext()) {
25079bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                Map.Entry entry = (Map.Entry)i.next();
25089bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                int device = ((Integer)entry.getKey()).intValue();
25099bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                if (device != AudioSystem.DEVICE_OUT_DEFAULT) {
25109bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                    AudioSystem.setStreamVolumeIndex(mStreamType,
25119bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                                                     ((Integer)entry.getValue() + 5)/10,
25129bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                                                     device);
25139bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                }
25149bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent            }
251511a74a75653197a3d31fe91590cd8312f5270c44Jean-Michel Trivi        }
251611a74a75653197a3d31fe91590cd8312f5270c44Jean-Michel Trivi
25179bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent        public boolean adjustIndex(int deltaIndex, int device) {
25189bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent            return setIndex(getIndex(device,
2519244820185269991186d07068b92985624cede4a5Eric Laurent                                     false  /* lastAudible */) + deltaIndex,
25209bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                            device,
25219bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                            true  /* lastAudible */);
25229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
25239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
25243172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent        public synchronized boolean setIndex(int index, int device, boolean lastAudible) {
25259bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent            int oldIndex = getIndex(device, false  /* lastAudible */);
25269bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent            index = getValidIndex(index);
25279bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent            mIndex.put(device, getValidIndex(index));
25289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
25299bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent            if (oldIndex != index) {
25309bcf401d13d47416043a704430388abd59aef7cdEric Laurent                if (lastAudible) {
25319bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                    mLastAudibleIndex.put(device, index);
25329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
2533a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent                // Apply change to all streams using this one as alias
2534bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent                // if changing volume of current device, also change volume of current
2535bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent                // device on aliased stream
2536bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent                boolean currentDevice = (device == getDeviceForStream(mStreamType));
2537a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent                int numStreamTypes = AudioSystem.getNumStreamTypes();
2538a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent                for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
2539bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent                    if (streamType != mStreamType &&
2540bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent                            mStreamVolumeAlias[streamType] == mStreamType) {
2541bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent                        int scaledIndex = rescaleIndex(index, mStreamType, streamType);
2542bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent                        mStreamStates[streamType].setIndex(scaledIndex,
2543bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent                                                           device,
25449bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                                                           lastAudible);
2545bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent                        if (currentDevice) {
2546bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent                            mStreamStates[streamType].setIndex(scaledIndex,
2547bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent                                                               getDeviceForStream(streamType),
2548bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent                                                               lastAudible);
2549bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent                        }
2550a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent                    }
2551a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent                }
25529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return true;
25539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } else {
25549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return false;
25559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
25569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
25579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
25583172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent        public synchronized int getIndex(int device, boolean lastAudible) {
25593172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent            ConcurrentHashMap <Integer, Integer> indexes;
25609bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent            if (lastAudible) {
25619bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                indexes = mLastAudibleIndex;
25629bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent            } else {
25639bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                indexes = mIndex;
25649bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent            }
25659bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent            Integer index = indexes.get(device);
25669bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent            if (index == null) {
25679bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                // there is always an entry for AudioSystem.DEVICE_OUT_DEFAULT
25689bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                index = indexes.get(AudioSystem.DEVICE_OUT_DEFAULT);
25699bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent            }
25709bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent            return index.intValue();
25719bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent        }
25729bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent
25733172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent        public synchronized void setLastAudibleIndex(int index, int device) {
2574244820185269991186d07068b92985624cede4a5Eric Laurent            // Apply change to all streams using this one as alias
2575244820185269991186d07068b92985624cede4a5Eric Laurent            // if changing volume of current device, also change volume of current
2576244820185269991186d07068b92985624cede4a5Eric Laurent            // device on aliased stream
2577244820185269991186d07068b92985624cede4a5Eric Laurent            boolean currentDevice = (device == getDeviceForStream(mStreamType));
2578244820185269991186d07068b92985624cede4a5Eric Laurent            int numStreamTypes = AudioSystem.getNumStreamTypes();
2579244820185269991186d07068b92985624cede4a5Eric Laurent            for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
2580244820185269991186d07068b92985624cede4a5Eric Laurent                if (streamType != mStreamType &&
2581244820185269991186d07068b92985624cede4a5Eric Laurent                        mStreamVolumeAlias[streamType] == mStreamType) {
2582244820185269991186d07068b92985624cede4a5Eric Laurent                    int scaledIndex = rescaleIndex(index, mStreamType, streamType);
2583244820185269991186d07068b92985624cede4a5Eric Laurent                    mStreamStates[streamType].setLastAudibleIndex(scaledIndex, device);
2584244820185269991186d07068b92985624cede4a5Eric Laurent                    if (currentDevice) {
2585244820185269991186d07068b92985624cede4a5Eric Laurent                        mStreamStates[streamType].setLastAudibleIndex(scaledIndex,
2586244820185269991186d07068b92985624cede4a5Eric Laurent                                                                   getDeviceForStream(streamType));
2587244820185269991186d07068b92985624cede4a5Eric Laurent                    }
2588244820185269991186d07068b92985624cede4a5Eric Laurent                }
2589244820185269991186d07068b92985624cede4a5Eric Laurent            }
25909bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent            mLastAudibleIndex.put(device, getValidIndex(index));
25915b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent        }
25925b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent
25933172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent        public synchronized void adjustLastAudibleIndex(int deltaIndex, int device) {
25949bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent            setLastAudibleIndex(getIndex(device,
2595244820185269991186d07068b92985624cede4a5Eric Laurent                                         true  /* lastAudible */) + deltaIndex,
25969bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                                device);
25975b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent        }
25985b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent
25999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public int getMaxIndex() {
2600a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent            return mIndexMax;
26019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
26029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
26033172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent        // only called by setAllIndexes() which is already synchronized
26043172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent        public ConcurrentHashMap <Integer, Integer> getAllIndexes(boolean lastAudible) {
26056d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent            if (lastAudible) {
26066d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent                return mLastAudibleIndex;
26076d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent            } else {
26086d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent                return mIndex;
26096d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent            }
26106d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent        }
26116d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent
26123172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent        public synchronized void setAllIndexes(VolumeStreamState srcStream, boolean lastAudible) {
26133172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent            ConcurrentHashMap <Integer, Integer> indexes = srcStream.getAllIndexes(lastAudible);
26146d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent            Set set = indexes.entrySet();
26156d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent            Iterator i = set.iterator();
26166d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent            while (i.hasNext()) {
26176d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent                Map.Entry entry = (Map.Entry)i.next();
26186d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent                int device = ((Integer)entry.getKey()).intValue();
26196d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent                int index = ((Integer)entry.getValue()).intValue();
26206d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent                index = rescaleIndex(index, srcStream.getStreamType(), mStreamType);
26216d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent                setIndex(index, device, lastAudible);
26226d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent            }
26236d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent        }
26246d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent
26253172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent        public synchronized void mute(IBinder cb, boolean state) {
26269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            VolumeDeathHandler handler = getDeathHandler(cb, state);
26279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (handler == null) {
26289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                Log.e(TAG, "Could not get client death handler for stream: "+mStreamType);
26299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return;
26309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
26319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            handler.mute(state);
26329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
26339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
26346d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent        public int getStreamType() {
26356d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent            return mStreamType;
26366d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent        }
26376d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent
26389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        private int getValidIndex(int index) {
26399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (index < 0) {
26409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return 0;
2641a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent            } else if (index > mIndexMax) {
2642a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent                return mIndexMax;
26439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
26449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
26459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return index;
26469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
26479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
26489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        private class VolumeDeathHandler implements IBinder.DeathRecipient {
26499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            private IBinder mICallback; // To be notified of client's death
26509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            private int mMuteCount; // Number of active mutes for this client
26519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
26529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            VolumeDeathHandler(IBinder cb) {
26539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mICallback = cb;
26549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
26559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
26563172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent            // must be called while synchronized on parent VolumeStreamState
26579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            public void mute(boolean state) {
26583172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                if (state) {
26593172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                    if (mMuteCount == 0) {
26603172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                        // Register for client death notification
26613172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                        try {
26623172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                            // mICallback can be 0 if muted by AudioService
26633172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                            if (mICallback != null) {
26643172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                                mICallback.linkToDeath(this, 0);
26653172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                            }
26663172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                            mDeathHandlers.add(this);
26673172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                            // If the stream is not yet muted by any client, set level to 0
26683172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                            if (muteCount() == 0) {
26693172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                                Set set = mIndex.entrySet();
26703172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                                Iterator i = set.iterator();
26713172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                                while (i.hasNext()) {
26723172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                                    Map.Entry entry = (Map.Entry)i.next();
26733172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                                    int device = ((Integer)entry.getKey()).intValue();
26743172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                                    setIndex(0, device, false /* lastAudible */);
26755b4e654d0c7de8e4d58d73e73b0d5220f19b68f7Eric Laurent                                }
26763172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                                sendMsg(mAudioHandler,
26773172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                                        MSG_SET_ALL_VOLUMES,
26783172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                                        SENDMSG_QUEUE,
26793172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                                        0,
26803172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                                        0,
26813172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                                        VolumeStreamState.this, 0);
26823172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                            }
26833172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                        } catch (RemoteException e) {
26843172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                            // Client has died!
26853172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                            binderDied();
26863172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                            return;
26873172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                        }
26883172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                    } else {
26893172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                        Log.w(TAG, "stream: "+mStreamType+" was already muted by this client");
26903172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                    }
26913172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                    mMuteCount++;
26923172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                } else {
26933172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                    if (mMuteCount == 0) {
26943172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                        Log.e(TAG, "unexpected unmute for stream: "+mStreamType);
26953172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                    } else {
26963172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                        mMuteCount--;
26973172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                        if (mMuteCount == 0) {
26983172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                            // Unregister from client death notification
26993172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                            mDeathHandlers.remove(this);
27003172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                            // mICallback can be 0 if muted by AudioService
27013172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                            if (mICallback != null) {
27023172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                                mICallback.unlinkToDeath(this, 0);
27033172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                            }
27043172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                            if (muteCount() == 0) {
27053172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                                // If the stream is not muted any more, restore its volume if
27063172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                                // ringer mode allows it
27073172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                                if (!isStreamAffectedByRingerMode(mStreamType) ||
27083172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                                        mRingerMode == AudioManager.RINGER_MODE_NORMAL) {
27099bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                                    Set set = mIndex.entrySet();
27109bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                                    Iterator i = set.iterator();
27119bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                                    while (i.hasNext()) {
27129bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                                        Map.Entry entry = (Map.Entry)i.next();
27139bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                                        int device = ((Integer)entry.getKey()).intValue();
27143172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                                        setIndex(getIndex(device,
27153172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                                                          true  /* lastAudible */),
27163172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                                                 device,
27173172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                                                 false  /* lastAudible */);
27189bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                                    }
27199bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                                    sendMsg(mAudioHandler,
27209bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                                            MSG_SET_ALL_VOLUMES,
272198ad9b9d6fd34aad487933170f50b5519313df61Eric Laurent                                            SENDMSG_QUEUE,
27229bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                                            0,
27239bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                                            0,
27249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                            VolumeStreamState.this, 0);
27259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                                }
27269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            }
27279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        }
27289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    }
27299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
27309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
27319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
27329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            public void binderDied() {
27339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                Log.w(TAG, "Volume service client died for stream: "+mStreamType);
27349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (mMuteCount != 0) {
27359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    // Reset all active mute requests from this client.
27369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    mMuteCount = 1;
27379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    mute(false);
27389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
27399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
27409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
27419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
27423172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent        private synchronized int muteCount() {
27439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int count = 0;
27449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int size = mDeathHandlers.size();
27459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            for (int i = 0; i < size; i++) {
27469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                count += mDeathHandlers.get(i).mMuteCount;
27479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
27489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return count;
27499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
27509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
27513172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent        // only called by mute() which is already synchronized
27529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        private VolumeDeathHandler getDeathHandler(IBinder cb, boolean state) {
27533172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent            VolumeDeathHandler handler;
27543172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent            int size = mDeathHandlers.size();
27553172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent            for (int i = 0; i < size; i++) {
27563172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                handler = mDeathHandlers.get(i);
27573172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                if (cb == handler.mICallback) {
27583172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                    return handler;
2759ce952c8e13c535bedde77bcdb94dfcc7508475aaMike Lockwood                }
2760ce952c8e13c535bedde77bcdb94dfcc7508475aaMike Lockwood            }
27613172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent            // If this is the first mute request for this client, create a new
27623172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent            // client death handler. Otherwise, it is an out of sequence unmute request.
27633172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent            if (state) {
27643172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                handler = new VolumeDeathHandler(cb);
27653172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent            } else {
27663172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                Log.w(TAG, "stream was not muted by this client");
27673172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent                handler = null;
27683172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent            }
27693172d5e3e7520a745fa37b71fc1c7bf244b57085Eric Laurent            return handler;
2770ce952c8e13c535bedde77bcdb94dfcc7508475aaMike Lockwood        }
2771bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent
2772bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent        private void dump(PrintWriter pw) {
2773bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent            pw.print("   Current: ");
2774bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent            Set set = mIndex.entrySet();
2775bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent            Iterator i = set.iterator();
2776bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent            while (i.hasNext()) {
2777bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent                Map.Entry entry = (Map.Entry)i.next();
2778bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent                pw.print(Integer.toHexString(((Integer)entry.getKey()).intValue())
2779bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent                             + ": " + ((((Integer)entry.getValue()).intValue() + 5) / 10)+", ");
2780bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent            }
2781bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent            pw.print("\n   Last audible: ");
2782bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent            set = mLastAudibleIndex.entrySet();
2783bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent            i = set.iterator();
2784bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent            while (i.hasNext()) {
2785bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent                Map.Entry entry = (Map.Entry)i.next();
2786bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent                pw.print(Integer.toHexString(((Integer)entry.getKey()).intValue())
2787bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent                             + ": " + ((((Integer)entry.getValue()).intValue() + 5) / 10)+", ");
2788bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent            }
2789bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent        }
2790ce952c8e13c535bedde77bcdb94dfcc7508475aaMike Lockwood    }
2791ce952c8e13c535bedde77bcdb94dfcc7508475aaMike Lockwood
27929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** Thread that handles native AudioSystem control. */
27939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private class AudioSystemThread extends Thread {
27949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        AudioSystemThread() {
27959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            super("AudioService");
27969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
27979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
27989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        @Override
27999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public void run() {
28009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // Set this thread up so the handler will work on it
28019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            Looper.prepare();
28029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
28039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            synchronized(AudioService.this) {
28049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mAudioHandler = new AudioHandler();
28059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
28069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // Notify that the handler has been created
28079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                AudioService.this.notify();
28089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
28099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
28109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // Listen for volume change requests that are set by VolumePanel
28119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            Looper.loop();
28129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
28139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
28149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
28159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** Handles internal volume messages in separate volume thread. */
28169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private class AudioHandler extends Handler {
28179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
28189bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent        private void setDeviceVolume(VolumeStreamState streamState, int device) {
28199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
28209bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent            // Apply volume
28219bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent            streamState.applyDeviceVolume(device);
2822a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent
2823a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent            // Apply change to all streams using this one as alias
2824a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent            int numStreamTypes = AudioSystem.getNumStreamTypes();
2825a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent            for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
2826a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent                if (streamType != streamState.mStreamType &&
28276d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent                        mStreamVolumeAlias[streamType] == streamState.mStreamType) {
28286d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent                    mStreamStates[streamType].applyDeviceVolume(getDeviceForStream(streamType));
2829a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent                }
2830a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent            }
28319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
28329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // Post a persist volume msg
2833afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent            sendMsg(mAudioHandler,
2834afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent                    MSG_PERSIST_VOLUME,
283598ad9b9d6fd34aad487933170f50b5519313df61Eric Laurent                    SENDMSG_QUEUE,
2836afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent                    PERSIST_CURRENT|PERSIST_LAST_AUDIBLE,
28379bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                    device,
2838afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent                    streamState,
2839afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent                    PERSIST_DELAY);
2840afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent
28419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
28429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
28439bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent        private void setAllVolumes(VolumeStreamState streamState) {
28449bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent
28459bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent            // Apply volume
28469bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent            streamState.applyAllVolumes();
28479bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent
28489bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent            // Apply change to all streams using this one as alias
28499bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent            int numStreamTypes = AudioSystem.getNumStreamTypes();
28509bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent            for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
28519bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                if (streamType != streamState.mStreamType &&
28526d5176638c2189595cede38fb92c3e7e8700e221Eric Laurent                        mStreamVolumeAlias[streamType] == streamState.mStreamType) {
28539bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                    mStreamStates[streamType].applyAllVolumes();
28549bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                }
28559bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent            }
28569bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent        }
28579bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent
2858afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent        private void persistVolume(VolumeStreamState streamState,
28599bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                                   int persistType,
28609bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                                   int device) {
2861afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent            if ((persistType & PERSIST_CURRENT) != 0) {
28629bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                System.putInt(mContentResolver,
28639bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                          streamState.getSettingNameForDevice(false /* lastAudible */, device),
28649bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                          (streamState.getIndex(device, false /* lastAudible */) + 5)/ 10);
286531951ca52aa007891b0be975318199e207c70e02Eric Laurent            }
2866afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent            if ((persistType & PERSIST_LAST_AUDIBLE) != 0) {
28679bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                System.putInt(mContentResolver,
28689bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                        streamState.getSettingNameForDevice(true /* lastAudible */, device),
28699bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                        (streamState.getIndex(device, true  /* lastAudible */) + 5) / 10);
287031951ca52aa007891b0be975318199e207c70e02Eric Laurent            }
28719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
28729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2873ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten        private void persistRingerMode(int ringerMode) {
2874ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten            System.putInt(mContentResolver, System.MODE_RINGER, ringerMode);
28759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
28769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
28779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        private void playSoundEffect(int effectType, int volume) {
28789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            synchronized (mSoundEffectsLock) {
28799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (mSoundPool == null) {
28809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    return;
28819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
2882a2ef57dba9ac77d8eccacd646b2b8a8d99fe9d8bEric Laurent                float volFloat;
288325101b0b9a84571ead15b26e9f4cd9c4298d7823Eric Laurent                // use default if volume is not specified by caller
2884a2ef57dba9ac77d8eccacd646b2b8a8d99fe9d8bEric Laurent                if (volume < 0) {
2885f2b0c11f4e797e183131261724d8de310dac5431Jean-Michel Trivi                    volFloat = (float)Math.pow(10, (float)sSoundEffectVolumeDb/20);
2886a2ef57dba9ac77d8eccacd646b2b8a8d99fe9d8bEric Laurent                } else {
2887a2ef57dba9ac77d8eccacd646b2b8a8d99fe9d8bEric Laurent                    volFloat = (float) volume / 1000.0f;
2888a2ef57dba9ac77d8eccacd646b2b8a8d99fe9d8bEric Laurent                }
28899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
28909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (SOUND_EFFECT_FILES_MAP[effectType][1] > 0) {
2891a2ef57dba9ac77d8eccacd646b2b8a8d99fe9d8bEric Laurent                    mSoundPool.play(SOUND_EFFECT_FILES_MAP[effectType][1], volFloat, volFloat, 0, 0, 1.0f);
28929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                } else {
28939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    MediaPlayer mediaPlayer = new MediaPlayer();
289462b9aec7a0a4e1cf8cfec7e39ea3103ab510d72eGlenn Kasten                    try {
289562b9aec7a0a4e1cf8cfec7e39ea3103ab510d72eGlenn Kasten                        String filePath = Environment.getRootDirectory() + SOUND_EFFECTS_PATH + SOUND_EFFECT_FILES[SOUND_EFFECT_FILES_MAP[effectType][0]];
289662b9aec7a0a4e1cf8cfec7e39ea3103ab510d72eGlenn Kasten                        mediaPlayer.setDataSource(filePath);
289762b9aec7a0a4e1cf8cfec7e39ea3103ab510d72eGlenn Kasten                        mediaPlayer.setAudioStreamType(AudioSystem.STREAM_SYSTEM);
289862b9aec7a0a4e1cf8cfec7e39ea3103ab510d72eGlenn Kasten                        mediaPlayer.prepare();
289962b9aec7a0a4e1cf8cfec7e39ea3103ab510d72eGlenn Kasten                        mediaPlayer.setVolume(volFloat, volFloat);
290062b9aec7a0a4e1cf8cfec7e39ea3103ab510d72eGlenn Kasten                        mediaPlayer.setOnCompletionListener(new OnCompletionListener() {
290162b9aec7a0a4e1cf8cfec7e39ea3103ab510d72eGlenn Kasten                            public void onCompletion(MediaPlayer mp) {
290262b9aec7a0a4e1cf8cfec7e39ea3103ab510d72eGlenn Kasten                                cleanupPlayer(mp);
290362b9aec7a0a4e1cf8cfec7e39ea3103ab510d72eGlenn Kasten                            }
290462b9aec7a0a4e1cf8cfec7e39ea3103ab510d72eGlenn Kasten                        });
290562b9aec7a0a4e1cf8cfec7e39ea3103ab510d72eGlenn Kasten                        mediaPlayer.setOnErrorListener(new OnErrorListener() {
290662b9aec7a0a4e1cf8cfec7e39ea3103ab510d72eGlenn Kasten                            public boolean onError(MediaPlayer mp, int what, int extra) {
290762b9aec7a0a4e1cf8cfec7e39ea3103ab510d72eGlenn Kasten                                cleanupPlayer(mp);
290862b9aec7a0a4e1cf8cfec7e39ea3103ab510d72eGlenn Kasten                                return true;
290962b9aec7a0a4e1cf8cfec7e39ea3103ab510d72eGlenn Kasten                            }
291062b9aec7a0a4e1cf8cfec7e39ea3103ab510d72eGlenn Kasten                        });
291162b9aec7a0a4e1cf8cfec7e39ea3103ab510d72eGlenn Kasten                        mediaPlayer.start();
291262b9aec7a0a4e1cf8cfec7e39ea3103ab510d72eGlenn Kasten                    } catch (IOException ex) {
291362b9aec7a0a4e1cf8cfec7e39ea3103ab510d72eGlenn Kasten                        Log.w(TAG, "MediaPlayer IOException: "+ex);
291462b9aec7a0a4e1cf8cfec7e39ea3103ab510d72eGlenn Kasten                    } catch (IllegalArgumentException ex) {
291562b9aec7a0a4e1cf8cfec7e39ea3103ab510d72eGlenn Kasten                        Log.w(TAG, "MediaPlayer IllegalArgumentException: "+ex);
291662b9aec7a0a4e1cf8cfec7e39ea3103ab510d72eGlenn Kasten                    } catch (IllegalStateException ex) {
291762b9aec7a0a4e1cf8cfec7e39ea3103ab510d72eGlenn Kasten                        Log.w(TAG, "MediaPlayer IllegalStateException: "+ex);
29189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    }
29199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
29209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
29219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
29229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2923f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi        private void onHandlePersistMediaButtonReceiver(ComponentName receiver) {
2924d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi            Settings.System.putString(mContentResolver, Settings.System.MEDIA_BUTTON_RECEIVER,
2925d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi                    receiver == null ? "" : receiver.flattenToString());
2926d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi        }
2927d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi
29289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        private void cleanupPlayer(MediaPlayer mp) {
29299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (mp != null) {
29309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                try {
29319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    mp.stop();
29329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    mp.release();
29339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                } catch (IllegalStateException ex) {
29349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    Log.w(TAG, "MediaPlayer IllegalStateException: "+ex);
29359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
29369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
29379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
29389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2939fa640154f1f42121d81242b2f1a10f03e52f0014Eric Laurent        private void setForceUse(int usage, int config) {
2940fa640154f1f42121d81242b2f1a10f03e52f0014Eric Laurent            AudioSystem.setForceUse(usage, config);
2941fa640154f1f42121d81242b2f1a10f03e52f0014Eric Laurent        }
2942fa640154f1f42121d81242b2f1a10f03e52f0014Eric Laurent
29439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        @Override
29449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public void handleMessage(Message msg) {
29459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2946afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent            switch (msg.what) {
29479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
29489bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                case MSG_SET_DEVICE_VOLUME:
29499bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                    setDeviceVolume((VolumeStreamState) msg.obj, msg.arg1);
29509bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                    break;
29519bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent
29529bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                case MSG_SET_ALL_VOLUMES:
29539bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                    setAllVolumes((VolumeStreamState) msg.obj);
29549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    break;
29559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
29569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                case MSG_PERSIST_VOLUME:
29579bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                    persistVolume((VolumeStreamState) msg.obj, msg.arg1, msg.arg2);
29589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    break;
29599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
29605c55a051ad7d86a464fb91426f1ea3c0250e38b3Mike Lockwood                case MSG_PERSIST_MASTER_VOLUME:
29615c55a051ad7d86a464fb91426f1ea3c0250e38b3Mike Lockwood                    Settings.System.putFloat(mContentResolver, Settings.System.VOLUME_MASTER,
29625c55a051ad7d86a464fb91426f1ea3c0250e38b3Mike Lockwood                            (float)msg.arg1 / (float)1000.0);
29635c55a051ad7d86a464fb91426f1ea3c0250e38b3Mike Lockwood                    break;
29645c55a051ad7d86a464fb91426f1ea3c0250e38b3Mike Lockwood
296557978ed86286a33d5b1a0fd000ca3406ba9d87b3Justin Koh                case MSG_PERSIST_MASTER_VOLUME_MUTE:
296657978ed86286a33d5b1a0fd000ca3406ba9d87b3Justin Koh                    Settings.System.putInt(mContentResolver, Settings.System.VOLUME_MASTER_MUTE,
296757978ed86286a33d5b1a0fd000ca3406ba9d87b3Justin Koh                            msg.arg1);
296857978ed86286a33d5b1a0fd000ca3406ba9d87b3Justin Koh                    break;
296957978ed86286a33d5b1a0fd000ca3406ba9d87b3Justin Koh
29709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                case MSG_PERSIST_RINGER_MODE:
2971ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten                    // note that the value persisted is the current ringer mode, not the
2972ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten                    // value of ringer mode as of the time the request was made to persist
2973ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten                    persistRingerMode(getRingerMode());
29749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    break;
29759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
29769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                case MSG_MEDIA_SERVER_DIED:
297789e74ba1419732dd5c7f939e48d4aa7989fd3a51Eric Laurent                    if (!mMediaServerOk) {
297889e74ba1419732dd5c7f939e48d4aa7989fd3a51Eric Laurent                        Log.e(TAG, "Media server died.");
2979a25c5d88d17f251262307ce31e799c9cf361d145Eric Laurent                        // Force creation of new IAudioFlinger interface so that we are notified
2980a25c5d88d17f251262307ce31e799c9cf361d145Eric Laurent                        // when new media_server process is back to life.
2981a25c5d88d17f251262307ce31e799c9cf361d145Eric Laurent                        AudioSystem.setErrorCallback(mAudioSystemCallback);
2982afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent                        sendMsg(mAudioHandler, MSG_MEDIA_SERVER_DIED, SENDMSG_NOOP, 0, 0,
298389e74ba1419732dd5c7f939e48d4aa7989fd3a51Eric Laurent                                null, 500);
298489e74ba1419732dd5c7f939e48d4aa7989fd3a51Eric Laurent                    }
29859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    break;
29869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
29879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                case MSG_MEDIA_SERVER_STARTED:
29889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    Log.e(TAG, "Media server started.");
29893c652ca5a546e7227a5f4bdbf0f81552b2c91383Eric Laurent                    // indicate to audio HAL that we start the reconfiguration phase after a media
29903c652ca5a546e7227a5f4bdbf0f81552b2c91383Eric Laurent                    // server crash
29913c652ca5a546e7227a5f4bdbf0f81552b2c91383Eric Laurent                    // Note that MSG_MEDIA_SERVER_STARTED message is only received when the media server
29923c652ca5a546e7227a5f4bdbf0f81552b2c91383Eric Laurent                    // process restarts after a crash, not the first time it is started.
29933c652ca5a546e7227a5f4bdbf0f81552b2c91383Eric Laurent                    AudioSystem.setParameters("restarting=true");
29943c652ca5a546e7227a5f4bdbf0f81552b2c91383Eric Laurent
2995c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent                    // Restore device connection states
29966bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                    synchronized (mConnectedDevices) {
29976bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                        Set set = mConnectedDevices.entrySet();
29986bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                        Iterator i = set.iterator();
29999bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                        while (i.hasNext()) {
30006bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                            Map.Entry device = (Map.Entry)i.next();
30016bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                            AudioSystem.setDeviceConnectionState(
30026bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                                                            ((Integer)device.getKey()).intValue(),
30036bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                                                            AudioSystem.DEVICE_STATE_AVAILABLE,
30046bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                                                            (String)device.getValue());
30056bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                        }
3006c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent                    }
3007c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent                    // Restore call state
3008c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent                    AudioSystem.setPhoneState(mMode);
3009c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent
3010d5603c126acdd94d9f7400bb1d04188020a425b4Eric Laurent                    // Restore forced usage for communcations and record
3011c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent                    AudioSystem.setForceUse(AudioSystem.FOR_COMMUNICATION, mForcedUseForComm);
3012d5603c126acdd94d9f7400bb1d04188020a425b4Eric Laurent                    AudioSystem.setForceUse(AudioSystem.FOR_RECORD, mForcedUseForComm);
3013c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent
3014a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent                    // Restore stream volumes
30159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    int numStreamTypes = AudioSystem.getNumStreamTypes();
30169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
30179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        VolumeStreamState streamState = mStreamStates[streamType];
3018c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent                        AudioSystem.initStreamVolume(streamType, 0, (streamState.mIndexMax + 5) / 10);
30199bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent
30209bc8358ddaa01c3490f9709991989633a6a3dd42Eric Laurent                        streamState.applyAllVolumes();
30219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    }
3022c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent
3023c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent                    // Restore ringer mode
3024c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7fEric Laurent                    setRingerModeInt(getRingerMode(), false);
30253c652ca5a546e7227a5f4bdbf0f81552b2c91383Eric Laurent
30269063154a793b0ab38b3c5992cbaed046427b4a82Mike Lockwood                    // Restore master volume
30279063154a793b0ab38b3c5992cbaed046427b4a82Mike Lockwood                    restoreMasterVolume();
30289063154a793b0ab38b3c5992cbaed046427b4a82Mike Lockwood
3029f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi                    // Reset device orientation (if monitored for this device)
3030f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi                    if (SystemProperties.getBoolean("ro.audio.monitorOrientation", false)) {
3031f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi                        setOrientationForAudioSystem();
3032f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi                    }
3033f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi
30347847211fb4699bf6018e29d214a918ed6657319bEric Laurent                    synchronized (mBluetoothA2dpEnabledLock) {
30357847211fb4699bf6018e29d214a918ed6657319bEric Laurent                        AudioSystem.setForceUse(AudioSystem.FOR_MEDIA,
30367847211fb4699bf6018e29d214a918ed6657319bEric Laurent                                mBluetoothA2dpEnabled ?
30377847211fb4699bf6018e29d214a918ed6657319bEric Laurent                                        AudioSystem.FORCE_NONE : AudioSystem.FORCE_NO_BT_A2DP);
30387847211fb4699bf6018e29d214a918ed6657319bEric Laurent                    }
30393c652ca5a546e7227a5f4bdbf0f81552b2c91383Eric Laurent                    // indicate the end of reconfiguration phase to audio HAL
30403c652ca5a546e7227a5f4bdbf0f81552b2c91383Eric Laurent                    AudioSystem.setParameters("restarting=false");
30419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    break;
30429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3043117b7bb5b5a4457711f59bde3dcc83d8f111c524Eric Laurent                case MSG_LOAD_SOUND_EFFECTS:
3044117b7bb5b5a4457711f59bde3dcc83d8f111c524Eric Laurent                    loadSoundEffects();
3045117b7bb5b5a4457711f59bde3dcc83d8f111c524Eric Laurent                    break;
3046117b7bb5b5a4457711f59bde3dcc83d8f111c524Eric Laurent
30479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                case MSG_PLAY_SOUND_EFFECT:
30489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    playSoundEffect(msg.arg1, msg.arg2);
30499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    break;
30504c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi
30514c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi                case MSG_BTA2DP_DOCK_TIMEOUT:
30524c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi                    // msg.obj  == address of BTA2DP device
30536bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                    synchronized (mConnectedDevices) {
30546bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                        makeA2dpDeviceUnavailableNow( (String) msg.obj );
30556bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                    }
30564c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi                    break;
3057fa640154f1f42121d81242b2f1a10f03e52f0014Eric Laurent
3058fa640154f1f42121d81242b2f1a10f03e52f0014Eric Laurent                case MSG_SET_FORCE_USE:
3059c390bed06b4a572e273ead1254da9a932e04dce3Eric Laurent                case MSG_SET_FORCE_BT_A2DP_USE:
3060fa640154f1f42121d81242b2f1a10f03e52f0014Eric Laurent                    setForceUse(msg.arg1, msg.arg2);
3061fa640154f1f42121d81242b2f1a10f03e52f0014Eric Laurent                    break;
3062d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi
3063d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi                case MSG_PERSIST_MEDIABUTTONRECEIVER:
3064f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi                    onHandlePersistMediaButtonReceiver( (ComponentName) msg.obj );
3065d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi                    break;
3066dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent
30678f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi                case MSG_RCDISPLAY_CLEAR:
30684426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi                    onRcDisplayClear();
30698f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi                    break;
30708f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi
30718f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi                case MSG_RCDISPLAY_UPDATE:
30724426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi                    // msg.obj is guaranteed to be non null
30734426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi                    onRcDisplayUpdate( (RemoteControlStackEntry) msg.obj, msg.arg1);
30748f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi                    break;
30758f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi
3076dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                case MSG_BT_HEADSET_CNCT_FAILED:
3077dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                    resetBluetoothSco();
3078dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                    break;
3079b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent
3080b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent                case MSG_SET_WIRED_DEVICE_CONNECTION_STATE:
3081b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent                    onSetWiredDeviceConnectionState(msg.arg1, msg.arg2, (String)msg.obj);
30822d8dab5a549b25b6f36df4614d7c0166d4d099e2Jean-Michel Trivi                    mMediaEventWakeLock.release();
3083b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent                    break;
3084b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent
3085b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent                case MSG_SET_A2DP_CONNECTION_STATE:
3086b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent                    onSetA2dpConnectionState((BluetoothDevice)msg.obj, msg.arg1);
30872d8dab5a549b25b6f36df4614d7c0166d4d099e2Jean-Michel Trivi                    mMediaEventWakeLock.release();
3088b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent                    break;
3089632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn
3090632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                case MSG_REPORT_NEW_ROUTES: {
3091632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                    int N = mRoutesObservers.beginBroadcast();
3092632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                    if (N > 0) {
3093632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                        AudioRoutesInfo routes;
3094632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                        synchronized (mCurAudioRoutes) {
3095632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                            routes = new AudioRoutesInfo(mCurAudioRoutes);
3096632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                        }
3097632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                        while (N > 0) {
3098632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                            N--;
3099632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                            IAudioRoutesObserver obs = mRoutesObservers.getBroadcastItem(N);
3100632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                            try {
3101632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                                obs.dispatchAudioRoutesChanged(routes);
3102632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                            } catch (RemoteException e) {
3103632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                            }
3104632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                        }
3105632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                    }
3106632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                    mRoutesObservers.finishBroadcast();
3107632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                    break;
3108632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                }
31093114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi
31103114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                case MSG_REEVALUATE_REMOTE:
31113114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                    onReevaluateRemote();
31123114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                    break;
3113f98de1e8dd6dcbd191921b4aa07a1d41b0b9db91Jean-Michel Trivi
3114f98de1e8dd6dcbd191921b4aa07a1d41b0b9db91Jean-Michel Trivi                case MSG_RCC_NEW_PLAYBACK_INFO:
3115f98de1e8dd6dcbd191921b4aa07a1d41b0b9db91Jean-Michel Trivi                    onNewPlaybackInfoForRcc(msg.arg1 /* rccId */, msg.arg2 /* key */,
3116f98de1e8dd6dcbd191921b4aa07a1d41b0b9db91Jean-Michel Trivi                            ((Integer)msg.obj).intValue() /* value */);
3117f98de1e8dd6dcbd191921b4aa07a1d41b0b9db91Jean-Michel Trivi                    break;
3118f98de1e8dd6dcbd191921b4aa07a1d41b0b9db91Jean-Michel Trivi                case MSG_RCC_NEW_VOLUME_OBS:
3119f98de1e8dd6dcbd191921b4aa07a1d41b0b9db91Jean-Michel Trivi                    onRegisterVolumeObserverForRcc(msg.arg1 /* rccId */,
3120f98de1e8dd6dcbd191921b4aa07a1d41b0b9db91Jean-Michel Trivi                            (IRemoteVolumeObserver)msg.obj /* rvo */);
3121f98de1e8dd6dcbd191921b4aa07a1d41b0b9db91Jean-Michel Trivi                    break;
31229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
31239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
31249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
31259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3126b109615ebebd6f3b9ae789412279f576c3ace46bJason Parekh    private class SettingsObserver extends ContentObserver {
3127a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent
3128b109615ebebd6f3b9ae789412279f576c3ace46bJason Parekh        SettingsObserver() {
3129b109615ebebd6f3b9ae789412279f576c3ace46bJason Parekh            super(new Handler());
3130b109615ebebd6f3b9ae789412279f576c3ace46bJason Parekh            mContentResolver.registerContentObserver(Settings.System.getUriFor(
3131b109615ebebd6f3b9ae789412279f576c3ace46bJason Parekh                Settings.System.MODE_RINGER_STREAMS_AFFECTED), false, this);
3132b109615ebebd6f3b9ae789412279f576c3ace46bJason Parekh        }
3133b109615ebebd6f3b9ae789412279f576c3ace46bJason Parekh
3134b109615ebebd6f3b9ae789412279f576c3ace46bJason Parekh        @Override
3135b109615ebebd6f3b9ae789412279f576c3ace46bJason Parekh        public void onChange(boolean selfChange) {
3136b109615ebebd6f3b9ae789412279f576c3ace46bJason Parekh            super.onChange(selfChange);
3137ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten            // FIXME This synchronized is not necessary if mSettingsLock only protects mRingerMode.
3138ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten            //       However there appear to be some missing locks around mRingerModeMutedStreams
3139ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten            //       and mRingerModeAffectedStreams, so will leave this synchronized for now.
3140ba195ebc76f23b6679443724ab58c9dc9f2df884Glenn Kasten            //       mRingerModeMutedStreams and mMuteAffectedStreams are safe (only accessed once).
3141a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent            synchronized (mSettingsLock) {
3142a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent                int ringerModeAffectedStreams = Settings.System.getInt(mContentResolver,
3143c1d4166289ce016965d1147f7e8d37862ee347ecEric Laurent                       Settings.System.MODE_RINGER_STREAMS_AFFECTED,
3144c1d4166289ce016965d1147f7e8d37862ee347ecEric Laurent                       ((1 << AudioSystem.STREAM_RING)|(1 << AudioSystem.STREAM_NOTIFICATION)|
3145c1d4166289ce016965d1147f7e8d37862ee347ecEric Laurent                       (1 << AudioSystem.STREAM_SYSTEM)|(1 << AudioSystem.STREAM_SYSTEM_ENFORCED)));
3146c1d4166289ce016965d1147f7e8d37862ee347ecEric Laurent                if (mVoiceCapable) {
3147c1d4166289ce016965d1147f7e8d37862ee347ecEric Laurent                    ringerModeAffectedStreams &= ~(1 << AudioSystem.STREAM_MUSIC);
3148c1d4166289ce016965d1147f7e8d37862ee347ecEric Laurent                } else {
3149402f7f29634a9f68e7929be828a927a3e2f5efe9Eric Laurent                    ringerModeAffectedStreams |= (1 << AudioSystem.STREAM_MUSIC);
3150402f7f29634a9f68e7929be828a927a3e2f5efe9Eric Laurent                }
3151a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent                if (ringerModeAffectedStreams != mRingerModeAffectedStreams) {
3152a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent                    /*
3153a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent                     * Ensure all stream types that should be affected by ringer mode
3154a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent                     * are in the proper state.
3155a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent                     */
3156a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent                    mRingerModeAffectedStreams = ringerModeAffectedStreams;
3157a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent                    setRingerModeInt(getRingerMode(), false);
3158a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent                }
3159a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent            }
3160b109615ebebd6f3b9ae789412279f576c3ace46bJason Parekh        }
3161b109615ebebd6f3b9ae789412279f576c3ace46bJason Parekh    }
3162a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent
31636bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent    // must be called synchronized on mConnectedDevices
31644c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi    private void makeA2dpDeviceAvailable(String address) {
31657847211fb4699bf6018e29d214a918ed6657319bEric Laurent        // enable A2DP before notifying A2DP connection to avoid unecessary processing in
31667847211fb4699bf6018e29d214a918ed6657319bEric Laurent        // audio policy manager
31677847211fb4699bf6018e29d214a918ed6657319bEric Laurent        setBluetoothA2dpOnInt(true);
31684c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi        AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
31694c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi                AudioSystem.DEVICE_STATE_AVAILABLE,
31704c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi                address);
31714c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi        // Reset A2DP suspend state each time a new sink is connected
31724c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi        AudioSystem.setParameters("A2dpSuspended=false");
31734c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi        mConnectedDevices.put( new Integer(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP),
31744c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi                address);
31754c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi    }
31764c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi
31779841818b9a0280abf59343c9e00a2976dbc084faMike Lockwood    private void sendBecomingNoisyIntent() {
31789841818b9a0280abf59343c9e00a2976dbc084faMike Lockwood        mContext.sendBroadcast(new Intent(AudioManager.ACTION_AUDIO_BECOMING_NOISY));
31799841818b9a0280abf59343c9e00a2976dbc084faMike Lockwood    }
31809841818b9a0280abf59343c9e00a2976dbc084faMike Lockwood
31816bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent    // must be called synchronized on mConnectedDevices
31824c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi    private void makeA2dpDeviceUnavailableNow(String address) {
31834c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi        AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
31844c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi                AudioSystem.DEVICE_STATE_UNAVAILABLE,
31854c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi                address);
31864c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi        mConnectedDevices.remove(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP);
31874c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi    }
31884c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi
31896bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent    // must be called synchronized on mConnectedDevices
31904c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi    private void makeA2dpDeviceUnavailableLater(String address) {
31913b5912602bec6ccbe8eef8a576730b1565f0067cEric Laurent        // prevent any activity on the A2DP audio output to avoid unwanted
31923b5912602bec6ccbe8eef8a576730b1565f0067cEric Laurent        // reconnection of the sink.
31933b5912602bec6ccbe8eef8a576730b1565f0067cEric Laurent        AudioSystem.setParameters("A2dpSuspended=true");
31944c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi        // the device will be made unavailable later, so consider it disconnected right away
31954c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi        mConnectedDevices.remove(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP);
31964c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi        // send the delayed message to make the device unavailable later
31974c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi        Message msg = mAudioHandler.obtainMessage(MSG_BTA2DP_DOCK_TIMEOUT, address);
31984c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi        mAudioHandler.sendMessageDelayed(msg, BTA2DP_DOCK_TIMEOUT_MILLIS);
31994c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi
32004c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi    }
32014c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi
32026bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent    // must be called synchronized on mConnectedDevices
3203a847ba4080675d395de725cfac5dfd9d5a993d4eJean-Michel Trivi    private void cancelA2dpDeviceTimeout() {
32044c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi        mAudioHandler.removeMessages(MSG_BTA2DP_DOCK_TIMEOUT);
32054c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi    }
32064c637b9e34f4c8db69a64ad21a4e2bcfa7485b5fJean-Michel Trivi
32076bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent    // must be called synchronized on mConnectedDevices
3208a847ba4080675d395de725cfac5dfd9d5a993d4eJean-Michel Trivi    private boolean hasScheduledA2dpDockTimeout() {
3209a847ba4080675d395de725cfac5dfd9d5a993d4eJean-Michel Trivi        return mAudioHandler.hasMessages(MSG_BTA2DP_DOCK_TIMEOUT);
3210a847ba4080675d395de725cfac5dfd9d5a993d4eJean-Michel Trivi    }
3211a847ba4080675d395de725cfac5dfd9d5a993d4eJean-Michel Trivi
3212b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent    private void onSetA2dpConnectionState(BluetoothDevice btDevice, int state)
32136bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent    {
32146bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent        if (btDevice == null) {
32156bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent            return;
32166bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent        }
32176bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent        String address = btDevice.getAddress();
32186bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent        if (!BluetoothAdapter.checkBluetoothAddress(address)) {
32196bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent            address = "";
32206bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent        }
32216bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent        synchronized (mConnectedDevices) {
32226bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent            boolean isConnected =
32236bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                (mConnectedDevices.containsKey(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP) &&
32246bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                 mConnectedDevices.get(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP).equals(address));
32256bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent
32266bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent            if (isConnected && state != BluetoothProfile.STATE_CONNECTED) {
32276bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                if (btDevice.isBluetoothDock()) {
32286bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                    if (state == BluetoothProfile.STATE_DISCONNECTED) {
32296bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                        // introduction of a delay for transient disconnections of docks when
32306bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                        // power is rapidly turned off/on, this message will be canceled if
32316bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                        // we reconnect the dock under a preset delay
32326bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                        makeA2dpDeviceUnavailableLater(address);
32336bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                        // the next time isConnected is evaluated, it will be false for the dock
32346bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                    }
32356bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                } else {
32366bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                    makeA2dpDeviceUnavailableNow(address);
32376bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                }
3238632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                synchronized (mCurAudioRoutes) {
3239632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                    if (mCurAudioRoutes.mBluetoothName != null) {
3240632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                        mCurAudioRoutes.mBluetoothName = null;
3241632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                        sendMsg(mAudioHandler, MSG_REPORT_NEW_ROUTES,
3242632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                                SENDMSG_NOOP, 0, 0, null, 0);
3243632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                    }
3244632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                }
32456bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent            } else if (!isConnected && state == BluetoothProfile.STATE_CONNECTED) {
32466bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                if (btDevice.isBluetoothDock()) {
32476bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                    // this could be a reconnection after a transient disconnection
32486bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                    cancelA2dpDeviceTimeout();
32496bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                    mDockAddress = address;
32506bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                } else {
32516bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                    // this could be a connection of another A2DP device before the timeout of
32526bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                    // a dock: cancel the dock timeout, and make the dock unavailable now
32536bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                    if(hasScheduledA2dpDockTimeout()) {
32546bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                        cancelA2dpDeviceTimeout();
32556bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                        makeA2dpDeviceUnavailableNow(mDockAddress);
32566bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                    }
32576bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                }
32586bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                makeA2dpDeviceAvailable(address);
3259632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                synchronized (mCurAudioRoutes) {
3260632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                    String name = btDevice.getAliasName();
3261632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                    if (!TextUtils.equals(mCurAudioRoutes.mBluetoothName, name)) {
3262632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                        mCurAudioRoutes.mBluetoothName = name;
3263632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                        sendMsg(mAudioHandler, MSG_REPORT_NEW_ROUTES,
3264632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                                SENDMSG_NOOP, 0, 0, null, 0);
3265632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                    }
3266632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                }
32676bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent            }
32686bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent        }
32696bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent    }
32706bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent
327159f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent    private boolean handleDeviceConnection(boolean connected, int device, String params) {
327259f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent        synchronized (mConnectedDevices) {
327359f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent            boolean isConnected = (mConnectedDevices.containsKey(device) &&
32749841818b9a0280abf59343c9e00a2976dbc084faMike Lockwood                    (params.isEmpty() || mConnectedDevices.get(device).equals(params)));
327559f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent
327659f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent            if (isConnected && !connected) {
327759f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent                AudioSystem.setDeviceConnectionState(device,
327859f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent                                              AudioSystem.DEVICE_STATE_UNAVAILABLE,
32799841818b9a0280abf59343c9e00a2976dbc084faMike Lockwood                                              mConnectedDevices.get(device));
328059f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent                 mConnectedDevices.remove(device);
328159f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent                 return true;
328259f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent            } else if (!isConnected && connected) {
328359f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent                 AudioSystem.setDeviceConnectionState(device,
328459f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent                                                      AudioSystem.DEVICE_STATE_AVAILABLE,
328559f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent                                                      params);
328659f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent                 mConnectedDevices.put(new Integer(device), params);
328759f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent                 return true;
328859f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent            }
328959f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent        }
329059f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent        return false;
329159f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent    }
329259f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent
3293b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent    // Devices which removal triggers intent ACTION_AUDIO_BECOMING_NOISY. The intent is only
3294b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent    // sent if none of these devices is connected.
3295b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent    int mBecomingNoisyIntentDevices =
3296b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent            AudioSystem.DEVICE_OUT_WIRED_HEADSET | AudioSystem.DEVICE_OUT_WIRED_HEADPHONE |
3297b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent            AudioSystem.DEVICE_OUT_ALL_A2DP;
3298b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent
3299b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent    // must be called before removing the device from mConnectedDevices
3300b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent    private int checkSendBecomingNoisyIntent(int device, int state) {
3301b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent        int delay = 0;
3302b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent        if ((state == 0) && ((device & mBecomingNoisyIntentDevices) != 0)) {
3303b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent            int devices = 0;
3304b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent            for (int dev : mConnectedDevices.keySet()) {
3305b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent                if ((dev & mBecomingNoisyIntentDevices) != 0) {
3306b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent                   devices |= dev;
3307b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent                }
3308b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent            }
3309b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent            if (devices == device) {
3310b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent                delay = 1000;
3311b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent                sendBecomingNoisyIntent();
3312b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent            }
3313b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent        }
3314b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent
3315b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent        if (mAudioHandler.hasMessages(MSG_SET_A2DP_CONNECTION_STATE) ||
3316b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent                mAudioHandler.hasMessages(MSG_SET_WIRED_DEVICE_CONNECTION_STATE)) {
3317b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent            delay = 1000;
3318b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent        }
3319b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent        return delay;
3320b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent    }
3321b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent
3322b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent    private void sendDeviceConnectionIntent(int device, int state, String name)
3323b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent    {
3324b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent        Intent intent = new Intent();
3325b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent
3326b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent        intent.putExtra("state", state);
3327b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent        intent.putExtra("name", name);
3328b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent        intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
3329b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent
3330632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn        int connType = 0;
3331632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn
3332b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent        if (device == AudioSystem.DEVICE_OUT_WIRED_HEADSET) {
3333632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn            connType = AudioRoutesInfo.MAIN_HEADSET;
3334b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent            intent.setAction(Intent.ACTION_HEADSET_PLUG);
3335b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent            intent.putExtra("microphone", 1);
3336b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent        } else if (device == AudioSystem.DEVICE_OUT_WIRED_HEADPHONE) {
3337632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn            connType = AudioRoutesInfo.MAIN_HEADPHONES;
3338b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent            intent.setAction(Intent.ACTION_HEADSET_PLUG);
3339b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent            intent.putExtra("microphone", 0);
3340b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent        } else if (device == AudioSystem.DEVICE_OUT_ANLG_DOCK_HEADSET) {
3341632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn            connType = AudioRoutesInfo.MAIN_DOCK_SPEAKERS;
3342b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent            intent.setAction(Intent.ACTION_ANALOG_AUDIO_DOCK_PLUG);
3343b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent        } else if (device == AudioSystem.DEVICE_OUT_DGTL_DOCK_HEADSET) {
3344632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn            connType = AudioRoutesInfo.MAIN_DOCK_SPEAKERS;
3345b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent            intent.setAction(Intent.ACTION_DIGITAL_AUDIO_DOCK_PLUG);
3346b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent        } else if (device == AudioSystem.DEVICE_OUT_AUX_DIGITAL) {
3347632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn            connType = AudioRoutesInfo.MAIN_HDMI;
3348b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent            intent.setAction(Intent.ACTION_HDMI_AUDIO_PLUG);
3349b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent        }
3350b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent
3351632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn        synchronized (mCurAudioRoutes) {
3352632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn            if (connType != 0) {
3353632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                int newConn = mCurAudioRoutes.mMainType;
3354632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                if (state != 0) {
3355632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                    newConn |= connType;
3356632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                } else {
3357632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                    newConn &= ~connType;
3358632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                }
3359632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                if (newConn != mCurAudioRoutes.mMainType) {
3360632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                    mCurAudioRoutes.mMainType = newConn;
3361632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                    sendMsg(mAudioHandler, MSG_REPORT_NEW_ROUTES,
3362632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                            SENDMSG_NOOP, 0, 0, null, 0);
3363632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn                }
3364632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn            }
3365632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn        }
3366632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn
3367b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent        ActivityManagerNative.broadcastStickyIntent(intent, null);
3368b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent    }
3369b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent
3370b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent    private void onSetWiredDeviceConnectionState(int device, int state, String name)
3371b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent    {
3372b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent        synchronized (mConnectedDevices) {
3373b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent            if ((state == 0) && ((device == AudioSystem.DEVICE_OUT_WIRED_HEADSET) ||
3374b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent                    (device == AudioSystem.DEVICE_OUT_WIRED_HEADPHONE))) {
3375b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent                setBluetoothA2dpOnInt(true);
3376b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent            }
3377b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent            handleDeviceConnection((state == 1), device, "");
3378b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent            if ((state != 0) && ((device == AudioSystem.DEVICE_OUT_WIRED_HEADSET) ||
3379b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent                    (device == AudioSystem.DEVICE_OUT_WIRED_HEADPHONE))) {
3380b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent                setBluetoothA2dpOnInt(false);
3381b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent            }
3382b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent            sendDeviceConnectionIntent(device, state, name);
3383b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent        }
3384b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent    }
3385b1fbaaccb656ef09a8770c28df15e3e91a452e64Eric Laurent
3386a847ba4080675d395de725cfac5dfd9d5a993d4eJean-Michel Trivi    /* cache of the address of the last dock the device was connected to */
3387a847ba4080675d395de725cfac5dfd9d5a993d4eJean-Michel Trivi    private String mDockAddress;
3388a847ba4080675d395de725cfac5dfd9d5a993d4eJean-Michel Trivi
3389a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent    /**
3390a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent     * Receiver for misc intent broadcasts the Phone app cares about.
3391a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent     */
3392a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent    private class AudioServiceBroadcastReceiver extends BroadcastReceiver {
3393a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent        @Override
3394a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent        public void onReceive(Context context, Intent intent) {
3395a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent            String action = intent.getAction();
339659f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent            int device;
339759f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent            int state;
3398a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent
3399758559e6b7e310cf46cc269437f44decd58d68d6Jean-Michel Trivi            if (action.equals(Intent.ACTION_DOCK_EVENT)) {
3400758559e6b7e310cf46cc269437f44decd58d68d6Jean-Michel Trivi                int dockState = intent.getIntExtra(Intent.EXTRA_DOCK_STATE,
3401758559e6b7e310cf46cc269437f44decd58d68d6Jean-Michel Trivi                        Intent.EXTRA_DOCK_STATE_UNDOCKED);
3402758559e6b7e310cf46cc269437f44decd58d68d6Jean-Michel Trivi                int config;
3403758559e6b7e310cf46cc269437f44decd58d68d6Jean-Michel Trivi                switch (dockState) {
3404758559e6b7e310cf46cc269437f44decd58d68d6Jean-Michel Trivi                    case Intent.EXTRA_DOCK_STATE_DESK:
3405758559e6b7e310cf46cc269437f44decd58d68d6Jean-Michel Trivi                        config = AudioSystem.FORCE_BT_DESK_DOCK;
3406758559e6b7e310cf46cc269437f44decd58d68d6Jean-Michel Trivi                        break;
3407758559e6b7e310cf46cc269437f44decd58d68d6Jean-Michel Trivi                    case Intent.EXTRA_DOCK_STATE_CAR:
3408758559e6b7e310cf46cc269437f44decd58d68d6Jean-Michel Trivi                        config = AudioSystem.FORCE_BT_CAR_DOCK;
3409758559e6b7e310cf46cc269437f44decd58d68d6Jean-Michel Trivi                        break;
341021e941bf43362ddc6639a9f2d0828053360f53d7Praveen Bharathi                    case Intent.EXTRA_DOCK_STATE_LE_DESK:
341121e941bf43362ddc6639a9f2d0828053360f53d7Praveen Bharathi                        config = AudioSystem.FORCE_ANALOG_DOCK;
341221e941bf43362ddc6639a9f2d0828053360f53d7Praveen Bharathi                        break;
341321e941bf43362ddc6639a9f2d0828053360f53d7Praveen Bharathi                    case Intent.EXTRA_DOCK_STATE_HE_DESK:
341421e941bf43362ddc6639a9f2d0828053360f53d7Praveen Bharathi                        config = AudioSystem.FORCE_DIGITAL_DOCK;
341521e941bf43362ddc6639a9f2d0828053360f53d7Praveen Bharathi                        break;
3416758559e6b7e310cf46cc269437f44decd58d68d6Jean-Michel Trivi                    case Intent.EXTRA_DOCK_STATE_UNDOCKED:
3417758559e6b7e310cf46cc269437f44decd58d68d6Jean-Michel Trivi                    default:
3418758559e6b7e310cf46cc269437f44decd58d68d6Jean-Michel Trivi                        config = AudioSystem.FORCE_NONE;
3419758559e6b7e310cf46cc269437f44decd58d68d6Jean-Michel Trivi                }
3420758559e6b7e310cf46cc269437f44decd58d68d6Jean-Michel Trivi                AudioSystem.setForceUse(AudioSystem.FOR_DOCK, config);
342182aa7f017daaaeb96c13e6e3491d5037ab471085Jaikumar Ganesh            } else if (action.equals(BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED)) {
342259f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent                state = intent.getIntExtra(BluetoothProfile.EXTRA_STATE,
342382aa7f017daaaeb96c13e6e3491d5037ab471085Jaikumar Ganesh                                               BluetoothProfile.STATE_DISCONNECTED);
342459f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent                device = AudioSystem.DEVICE_OUT_BLUETOOTH_SCO;
3425a56d1c72190462aa9e377906583eceb58e0efcddNick Pelly                String address = null;
3426dca56b9432e2cc851d1a58920071fed2e1e3d142Eric Laurent
3427dca56b9432e2cc851d1a58920071fed2e1e3d142Eric Laurent                BluetoothDevice btDevice = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
3428dca56b9432e2cc851d1a58920071fed2e1e3d142Eric Laurent                if (btDevice == null) {
3429dca56b9432e2cc851d1a58920071fed2e1e3d142Eric Laurent                    return;
3430dca56b9432e2cc851d1a58920071fed2e1e3d142Eric Laurent                }
3431dca56b9432e2cc851d1a58920071fed2e1e3d142Eric Laurent
3432dca56b9432e2cc851d1a58920071fed2e1e3d142Eric Laurent                address = btDevice.getAddress();
3433dca56b9432e2cc851d1a58920071fed2e1e3d142Eric Laurent                BluetoothClass btClass = btDevice.getBluetoothClass();
3434dca56b9432e2cc851d1a58920071fed2e1e3d142Eric Laurent                if (btClass != null) {
3435dca56b9432e2cc851d1a58920071fed2e1e3d142Eric Laurent                    switch (btClass.getDeviceClass()) {
3436dca56b9432e2cc851d1a58920071fed2e1e3d142Eric Laurent                    case BluetoothClass.Device.AUDIO_VIDEO_WEARABLE_HEADSET:
3437dca56b9432e2cc851d1a58920071fed2e1e3d142Eric Laurent                    case BluetoothClass.Device.AUDIO_VIDEO_HANDSFREE:
3438dca56b9432e2cc851d1a58920071fed2e1e3d142Eric Laurent                        device = AudioSystem.DEVICE_OUT_BLUETOOTH_SCO_HEADSET;
3439dca56b9432e2cc851d1a58920071fed2e1e3d142Eric Laurent                        break;
3440dca56b9432e2cc851d1a58920071fed2e1e3d142Eric Laurent                    case BluetoothClass.Device.AUDIO_VIDEO_CAR_AUDIO:
3441dca56b9432e2cc851d1a58920071fed2e1e3d142Eric Laurent                        device = AudioSystem.DEVICE_OUT_BLUETOOTH_SCO_CARKIT;
3442dca56b9432e2cc851d1a58920071fed2e1e3d142Eric Laurent                        break;
3443d5603c126acdd94d9f7400bb1d04188020a425b4Eric Laurent                    }
3444d5603c126acdd94d9f7400bb1d04188020a425b4Eric Laurent                }
3445d5603c126acdd94d9f7400bb1d04188020a425b4Eric Laurent
3446dca56b9432e2cc851d1a58920071fed2e1e3d142Eric Laurent                if (!BluetoothAdapter.checkBluetoothAddress(address)) {
3447dca56b9432e2cc851d1a58920071fed2e1e3d142Eric Laurent                    address = "";
3448dca56b9432e2cc851d1a58920071fed2e1e3d142Eric Laurent                }
3449d5603c126acdd94d9f7400bb1d04188020a425b4Eric Laurent
345059f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent                boolean connected = (state == BluetoothProfile.STATE_CONNECTED);
345159f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent                if (handleDeviceConnection(connected, device, address)) {
34526bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                    synchronized (mScoClients) {
345359f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent                        if (connected) {
345459f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent                            mBluetoothHeadsetDevice = btDevice;
345559f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent                        } else {
34566bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                            mBluetoothHeadsetDevice = null;
34576bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                            resetBluetoothSco();
34586bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                        }
345962ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent                    }
3460a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent                }
346159f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent            } else if (action.equals(Intent.ACTION_USB_AUDIO_ACCESSORY_PLUG) ||
346259f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent                           action.equals(Intent.ACTION_USB_AUDIO_DEVICE_PLUG)) {
346359f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent                state = intent.getIntExtra("state", 0);
346459f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent                int alsaCard = intent.getIntExtra("card", -1);
346559f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent                int alsaDevice = intent.getIntExtra("device", -1);
34669841818b9a0280abf59343c9e00a2976dbc084faMike Lockwood                String params = (alsaCard == -1 && alsaDevice == -1 ? ""
34679841818b9a0280abf59343c9e00a2976dbc084faMike Lockwood                                    : "card=" + alsaCard + ";device=" + alsaDevice);
346859f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent                device = action.equals(Intent.ACTION_USB_AUDIO_ACCESSORY_PLUG) ?
346959f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent                        AudioSystem.DEVICE_OUT_USB_ACCESSORY : AudioSystem.DEVICE_OUT_USB_DEVICE;
347059f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent                Log.v(TAG, "Broadcast Receiver: Got "
347159f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent                        + (action.equals(Intent.ACTION_USB_AUDIO_ACCESSORY_PLUG) ?
347259f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent                              "ACTION_USB_AUDIO_ACCESSORY_PLUG" : "ACTION_USB_AUDIO_DEVICE_PLUG")
347359f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent                        + ", state = " + state + ", card: " + alsaCard + ", device: " + alsaDevice);
347459f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent                handleDeviceConnection((state == 1), device, params);
34753def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent            } else if (action.equals(BluetoothHeadset.ACTION_AUDIO_STATE_CHANGED)) {
347662ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent                boolean broadcast = false;
347759f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent                int scoAudioState = AudioManager.SCO_AUDIO_STATE_ERROR;
34783def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                synchronized (mScoClients) {
347962ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent                    int btState = intent.getIntExtra(BluetoothProfile.EXTRA_STATE, -1);
3480dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                    // broadcast intent if the connection was initated by AudioService
3481dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                    if (!mScoClients.isEmpty() &&
3482dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                            (mScoAudioState == SCO_STATE_ACTIVE_INTERNAL ||
3483dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                             mScoAudioState == SCO_STATE_ACTIVATE_REQ ||
3484dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                             mScoAudioState == SCO_STATE_DEACTIVATE_REQ)) {
348562ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent                        broadcast = true;
348662ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent                    }
348762ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent                    switch (btState) {
348862ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent                    case BluetoothHeadset.STATE_AUDIO_CONNECTED:
348959f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent                        scoAudioState = AudioManager.SCO_AUDIO_STATE_CONNECTED;
3490dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                        if (mScoAudioState != SCO_STATE_ACTIVE_INTERNAL &&
3491dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                            mScoAudioState != SCO_STATE_DEACTIVATE_REQ &&
3492dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                            mScoAudioState != SCO_STATE_DEACTIVATE_EXT_REQ) {
349362ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent                            mScoAudioState = SCO_STATE_ACTIVE_EXTERNAL;
34943def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                        }
349562ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent                        break;
349662ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent                    case BluetoothHeadset.STATE_AUDIO_DISCONNECTED:
349759f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent                        scoAudioState = AudioManager.SCO_AUDIO_STATE_DISCONNECTED;
349862ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent                        mScoAudioState = SCO_STATE_INACTIVE;
3499d7454be47f4111c0478a502353e11dea401378bdEric Laurent                        clearAllScoClients(0, false);
350062ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent                        break;
350162ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent                    case BluetoothHeadset.STATE_AUDIO_CONNECTING:
3502dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                        if (mScoAudioState != SCO_STATE_ACTIVE_INTERNAL &&
3503dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                            mScoAudioState != SCO_STATE_DEACTIVATE_REQ &&
3504dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                            mScoAudioState != SCO_STATE_DEACTIVATE_EXT_REQ) {
350562ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent                            mScoAudioState = SCO_STATE_ACTIVE_EXTERNAL;
35063def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                        }
350762ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent                    default:
350862ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent                        // do not broadcast CONNECTING or invalid state
350962ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent                        broadcast = false;
351062ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent                        break;
35113def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                    }
35123def1eec2baed0b8845ec32c871e249dc533a9d9Eric Laurent                }
351362ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent                if (broadcast) {
351459f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent                    broadcastScoConnectionState(scoAudioState);
3515dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                    //FIXME: this is to maintain compatibility with deprecated intent
3516dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                    // AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED. Remove when appropriate.
351762ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent                    Intent newIntent = new Intent(AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED);
351859f482764e346a5c5ac118ee1f7b24da645c2559Eric Laurent                    newIntent.putExtra(AudioManager.EXTRA_SCO_AUDIO_STATE, scoAudioState);
351962ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent                    mContext.sendStickyBroadcast(newIntent);
352062ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent                }
352162ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent            } else if (action.equals(Intent.ACTION_BOOT_COMPLETED)) {
3522a60e212d0dda7d2a748180ce77405f2463c9cf53Eric Laurent                mBootCompleted = true;
3523afbb047c3945e9c2b7e9bc6b25098d5fb80bba4eEric Laurent                sendMsg(mAudioHandler, MSG_LOAD_SOUND_EFFECTS, SENDMSG_NOOP,
3524117b7bb5b5a4457711f59bde3dcc83d8f111c524Eric Laurent                        0, 0, null, 0);
3525dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent
35266243edd818b84adfbe712d5d233d6414b33653acAmith Yamasani                mKeyguardManager =
35276243edd818b84adfbe712d5d233d6414b33653acAmith Yamasani                        (KeyguardManager) mContext.getSystemService(Context.KEYGUARD_SERVICE);
3528dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                mScoConnectionState = AudioManager.SCO_AUDIO_STATE_ERROR;
3529dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                resetBluetoothSco();
3530dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                getBluetoothHeadset();
3531dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                //FIXME: this is to maintain compatibility with deprecated intent
3532dc03c61fe3cd8d0805480e48a974986439977a60Eric Laurent                // AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED. Remove when appropriate.
353362ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent                Intent newIntent = new Intent(AudioManager.ACTION_SCO_AUDIO_STATE_CHANGED);
353462ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent                newIntent.putExtra(AudioManager.EXTRA_SCO_AUDIO_STATE,
353562ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent                        AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
353662ef767b15a712bab31cc0d5508a330906f535c2Eric Laurent                mContext.sendStickyBroadcast(newIntent);
35376bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent
35386bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
35396bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                if (adapter != null) {
35406bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                    adapter.getProfileProxy(mContext, mBluetoothProfileServiceListener,
35416bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                                            BluetoothProfile.A2DP);
35426bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent                }
3543d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi            } else if (action.equals(Intent.ACTION_PACKAGE_REMOVED)) {
3544d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi                if (!intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) {
3545d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi                    // a package is being removed, not replaced
3546d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi                    String packageName = intent.getData().getSchemeSpecificPart();
3547d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi                    if (packageName != null) {
3548d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi                        removeMediaButtonReceiverForPackage(packageName);
3549d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi                    }
3550d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi                }
3551950e8cb40a6d826af4cc2eef9d3908c1b70486e6Eric Laurent            } else if (action.equals(Intent.ACTION_SCREEN_ON)) {
3552950e8cb40a6d826af4cc2eef9d3908c1b70486e6Eric Laurent                AudioSystem.setParameters("screen_state=on");
3553950e8cb40a6d826af4cc2eef9d3908c1b70486e6Eric Laurent            } else if (action.equals(Intent.ACTION_SCREEN_OFF)) {
3554950e8cb40a6d826af4cc2eef9d3908c1b70486e6Eric Laurent                AudioSystem.setParameters("screen_state=off");
3555f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi            } else if (action.equalsIgnoreCase(Intent.ACTION_CONFIGURATION_CHANGED)) {
3556f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi                handleConfigurationChanged(context);
3557a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent            }
3558a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent        }
3559a553c25b33c99b345cf1c8688f8df0ed8df14e5aEric Laurent    }
3560d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi
3561d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi    //==========================================================================================
3562d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi    // AudioFocus
3563d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi    //==========================================================================================
3564b4bccb6d8df16a2c5235cead187156bc721cf074Jean-Michel Trivi
3565b4bccb6d8df16a2c5235cead187156bc721cf074Jean-Michel Trivi    /* constant to identify focus stack entry that is used to hold the focus while the phone
35664dd3674e517051f130fef36d2eb201c68ff61094Jean-Michel Trivi     * is ringing or during a call. Used by com.android.internal.telephony.CallManager when
35674dd3674e517051f130fef36d2eb201c68ff61094Jean-Michel Trivi     * entering and exiting calls.
3568e5e1e870fdb35f5291790e6d178bde7126f6fe35Jean-Michel Trivi     */
35694dd3674e517051f130fef36d2eb201c68ff61094Jean-Michel Trivi    public final static String IN_VOICE_COMM_FOCUS_ID = "AudioFocus_For_Phone_Ring_And_Calls";
3570e5e1e870fdb35f5291790e6d178bde7126f6fe35Jean-Michel Trivi
3571392a2bbb52688ebd25768a7784d9edca7f498110Jean-Michel Trivi    private final static Object mAudioFocusLock = new Object();
3572392a2bbb52688ebd25768a7784d9edca7f498110Jean-Michel Trivi
3573e73131a68408a0495ba96a4d5a60799ba293c176Jean-Michel Trivi    private final static Object mRingingLock = new Object();
3574e73131a68408a0495ba96a4d5a60799ba293c176Jean-Michel Trivi
3575b4bccb6d8df16a2c5235cead187156bc721cf074Jean-Michel Trivi    private PhoneStateListener mPhoneStateListener = new PhoneStateListener() {
3576b4bccb6d8df16a2c5235cead187156bc721cf074Jean-Michel Trivi        @Override
3577b4bccb6d8df16a2c5235cead187156bc721cf074Jean-Michel Trivi        public void onCallStateChanged(int state, String incomingNumber) {
3578b4bccb6d8df16a2c5235cead187156bc721cf074Jean-Michel Trivi            if (state == TelephonyManager.CALL_STATE_RINGING) {
3579b4bccb6d8df16a2c5235cead187156bc721cf074Jean-Michel Trivi                //Log.v(TAG, " CALL_STATE_RINGING");
3580e73131a68408a0495ba96a4d5a60799ba293c176Jean-Michel Trivi                synchronized(mRingingLock) {
3581e73131a68408a0495ba96a4d5a60799ba293c176Jean-Michel Trivi                    mIsRinging = true;
3582e73131a68408a0495ba96a4d5a60799ba293c176Jean-Michel Trivi                }
35832ade576148fe33c5ff6098d30ccfbcf28df70e8eJean-Michel Trivi            } else if ((state == TelephonyManager.CALL_STATE_OFFHOOK)
35842ade576148fe33c5ff6098d30ccfbcf28df70e8eJean-Michel Trivi                    || (state == TelephonyManager.CALL_STATE_IDLE)) {
3585e73131a68408a0495ba96a4d5a60799ba293c176Jean-Michel Trivi                synchronized(mRingingLock) {
3586e73131a68408a0495ba96a4d5a60799ba293c176Jean-Michel Trivi                    mIsRinging = false;
3587e73131a68408a0495ba96a4d5a60799ba293c176Jean-Michel Trivi                }
3588e5e1e870fdb35f5291790e6d178bde7126f6fe35Jean-Michel Trivi            }
3589e5e1e870fdb35f5291790e6d178bde7126f6fe35Jean-Michel Trivi        }
3590b4bccb6d8df16a2c5235cead187156bc721cf074Jean-Michel Trivi    };
3591e5e1e870fdb35f5291790e6d178bde7126f6fe35Jean-Michel Trivi
3592e5e1e870fdb35f5291790e6d178bde7126f6fe35Jean-Michel Trivi    private void notifyTopOfAudioFocusStack() {
3593e5e1e870fdb35f5291790e6d178bde7126f6fe35Jean-Michel Trivi        // notify the top of the stack it gained focus
3594e5e1e870fdb35f5291790e6d178bde7126f6fe35Jean-Michel Trivi        if (!mFocusStack.empty() && (mFocusStack.peek().mFocusDispatcher != null)) {
3595e5e1e870fdb35f5291790e6d178bde7126f6fe35Jean-Michel Trivi            if (canReassignAudioFocus()) {
3596e5e1e870fdb35f5291790e6d178bde7126f6fe35Jean-Michel Trivi                try {
3597e5e1e870fdb35f5291790e6d178bde7126f6fe35Jean-Michel Trivi                    mFocusStack.peek().mFocusDispatcher.dispatchAudioFocusChange(
3598e5e1e870fdb35f5291790e6d178bde7126f6fe35Jean-Michel Trivi                            AudioManager.AUDIOFOCUS_GAIN, mFocusStack.peek().mClientId);
3599e5e1e870fdb35f5291790e6d178bde7126f6fe35Jean-Michel Trivi                } catch (RemoteException e) {
3600e5e1e870fdb35f5291790e6d178bde7126f6fe35Jean-Michel Trivi                    Log.e(TAG, "Failure to signal gain of audio control focus due to "+ e);
3601e5e1e870fdb35f5291790e6d178bde7126f6fe35Jean-Michel Trivi                    e.printStackTrace();
3602e5e1e870fdb35f5291790e6d178bde7126f6fe35Jean-Michel Trivi                }
3603e5e1e870fdb35f5291790e6d178bde7126f6fe35Jean-Michel Trivi            }
3604e5e1e870fdb35f5291790e6d178bde7126f6fe35Jean-Michel Trivi        }
3605e5e1e870fdb35f5291790e6d178bde7126f6fe35Jean-Michel Trivi    }
3606e5e1e870fdb35f5291790e6d178bde7126f6fe35Jean-Michel Trivi
3607d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi    private static class FocusStackEntry {
3608d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi        public int mStreamType = -1;// no stream type
3609d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi        public IAudioFocusDispatcher mFocusDispatcher = null;
3610d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi        public IBinder mSourceRef = null;
3611d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi        public String mClientId;
3612078fd47e91d495175927d1a4a8b9aad039a7ba4eJean-Michel Trivi        public int mFocusChangeType;
3613061214bb71a4a4211e670001226c68f5e8036b84Jean-Michel Trivi        public AudioFocusDeathHandler mHandler;
36148f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi        public String mPackageName;
36158f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi        public int mCallingUid;
3616d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi
3617d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi        public FocusStackEntry() {
3618d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi        }
3619d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi
36208f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi        public FocusStackEntry(int streamType, int duration,
3621061214bb71a4a4211e670001226c68f5e8036b84Jean-Michel Trivi                IAudioFocusDispatcher afl, IBinder source, String id, AudioFocusDeathHandler hdlr,
3622061214bb71a4a4211e670001226c68f5e8036b84Jean-Michel Trivi                String pn, int uid) {
3623d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi            mStreamType = streamType;
3624d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi            mFocusDispatcher = afl;
3625d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi            mSourceRef = source;
3626d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi            mClientId = id;
3627078fd47e91d495175927d1a4a8b9aad039a7ba4eJean-Michel Trivi            mFocusChangeType = duration;
3628061214bb71a4a4211e670001226c68f5e8036b84Jean-Michel Trivi            mHandler = hdlr;
36298f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi            mPackageName = pn;
36308f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi            mCallingUid = uid;
3631d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi        }
3632061214bb71a4a4211e670001226c68f5e8036b84Jean-Michel Trivi
3633e7edc868538e83152e7bc35c830fee0d629baefcJean-Michel Trivi        public void unlinkToDeath() {
3634e7edc868538e83152e7bc35c830fee0d629baefcJean-Michel Trivi            try {
3635e7edc868538e83152e7bc35c830fee0d629baefcJean-Michel Trivi                if (mSourceRef != null && mHandler != null) {
3636e7edc868538e83152e7bc35c830fee0d629baefcJean-Michel Trivi                    mSourceRef.unlinkToDeath(mHandler, 0);
3637e7edc868538e83152e7bc35c830fee0d629baefcJean-Michel Trivi                    mHandler = null;
3638e7edc868538e83152e7bc35c830fee0d629baefcJean-Michel Trivi                }
3639e7edc868538e83152e7bc35c830fee0d629baefcJean-Michel Trivi            } catch (java.util.NoSuchElementException e) {
3640e7edc868538e83152e7bc35c830fee0d629baefcJean-Michel Trivi                Log.e(TAG, "Encountered " + e + " in FocusStackEntry.unlinkToDeath()");
3641061214bb71a4a4211e670001226c68f5e8036b84Jean-Michel Trivi            }
3642061214bb71a4a4211e670001226c68f5e8036b84Jean-Michel Trivi        }
3643de1f065be109e1c313d8330c8e34210fedaac74eJean-Michel Trivi
3644de1f065be109e1c313d8330c8e34210fedaac74eJean-Michel Trivi        @Override
3645de1f065be109e1c313d8330c8e34210fedaac74eJean-Michel Trivi        protected void finalize() throws Throwable {
3646e7edc868538e83152e7bc35c830fee0d629baefcJean-Michel Trivi            unlinkToDeath(); // unlink exception handled inside method
3647e7edc868538e83152e7bc35c830fee0d629baefcJean-Michel Trivi            super.finalize();
3648de1f065be109e1c313d8330c8e34210fedaac74eJean-Michel Trivi        }
3649d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi    }
3650d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi
365130c918ce7fbe171944b28fc91b3f22b3d631872dGlenn Kasten    private final Stack<FocusStackEntry> mFocusStack = new Stack<FocusStackEntry>();
3652d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi
3653d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi    /**
3654d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi     * Helper function:
3655d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi     * Display in the log the current entries in the audio focus stack
3656d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi     */
3657d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi    private void dumpFocusStack(PrintWriter pw) {
3658b4bccb6d8df16a2c5235cead187156bc721cf074Jean-Michel Trivi        pw.println("\nAudio Focus stack entries:");
3659392a2bbb52688ebd25768a7784d9edca7f498110Jean-Michel Trivi        synchronized(mAudioFocusLock) {
3660d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi            Iterator<FocusStackEntry> stackIterator = mFocusStack.iterator();
3661d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi            while(stackIterator.hasNext()) {
3662d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi                FocusStackEntry fse = stackIterator.next();
3663d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi                pw.println("     source:" + fse.mSourceRef + " -- client: " + fse.mClientId
36648f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi                        + " -- duration: " + fse.mFocusChangeType
36658f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi                        + " -- uid: " + fse.mCallingUid);
3666d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi            }
3667d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi        }
3668d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi    }
3669d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi
3670d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi    /**
3671d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi     * Helper function:
36728f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi     * Called synchronized on mAudioFocusLock
3673d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi     * Remove a focus listener from the focus stack.
3674d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi     * @param focusListenerToRemove the focus listener
3675d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi     * @param signal if true and the listener was at the top of the focus stack, i.e. it was holding
3676d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi     *   focus, notify the next item in the stack it gained focus.
3677d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi     */
3678d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi    private void removeFocusStackEntry(String clientToRemove, boolean signal) {
3679e7edc868538e83152e7bc35c830fee0d629baefcJean-Michel Trivi        // is the current top of the focus stack abandoning focus? (because of request, not death)
3680d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi        if (!mFocusStack.empty() && mFocusStack.peek().mClientId.equals(clientToRemove))
3681d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi        {
3682d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi            //Log.i(TAG, "   removeFocusStackEntry() removing top of stack");
3683e7edc868538e83152e7bc35c830fee0d629baefcJean-Michel Trivi            FocusStackEntry fse = mFocusStack.pop();
3684e7edc868538e83152e7bc35c830fee0d629baefcJean-Michel Trivi            fse.unlinkToDeath();
3685d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi            if (signal) {
3686d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi                // notify the new top of the stack it gained focus
3687e5e1e870fdb35f5291790e6d178bde7126f6fe35Jean-Michel Trivi                notifyTopOfAudioFocusStack();
36888f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi                // there's a new top of the stack, let the remote control know
36898f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi                synchronized(mRCStack) {
3690b716f0b7b2d8e4b045843fc6a7004910eb344c19Jean-Michel Trivi                    checkUpdateRemoteControlDisplay_syncAfRcs(RC_INFO_ALL);
36918f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi                }
3692d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi            }
3693d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi        } else {
3694d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi            // focus is abandoned by a client that's not at the top of the stack,
3695d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi            // no need to update focus.
3696d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi            Iterator<FocusStackEntry> stackIterator = mFocusStack.iterator();
3697d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi            while(stackIterator.hasNext()) {
3698d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi                FocusStackEntry fse = (FocusStackEntry)stackIterator.next();
3699d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi                if(fse.mClientId.equals(clientToRemove)) {
3700d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi                    Log.i(TAG, " AudioFocus  abandonAudioFocus(): removing entry for "
3701d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi                            + fse.mClientId);
370272843377d50a8f95cceaf33d316ab68d9b47f2ebJean-Michel Trivi                    stackIterator.remove();
3703e7edc868538e83152e7bc35c830fee0d629baefcJean-Michel Trivi                    fse.unlinkToDeath();
3704d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi                }
3705d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi            }
3706d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi        }
3707d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi    }
3708d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi
3709d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi    /**
3710d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi     * Helper function:
37118f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi     * Called synchronized on mAudioFocusLock
3712e7edc868538e83152e7bc35c830fee0d629baefcJean-Michel Trivi     * Remove focus listeners from the focus stack for a particular client when it has died.
3713d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi     */
3714d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi    private void removeFocusStackEntryForClient(IBinder cb) {
3715e5e1e870fdb35f5291790e6d178bde7126f6fe35Jean-Michel Trivi        // is the owner of the audio focus part of the client to remove?
3716e5e1e870fdb35f5291790e6d178bde7126f6fe35Jean-Michel Trivi        boolean isTopOfStackForClientToRemove = !mFocusStack.isEmpty() &&
3717e5e1e870fdb35f5291790e6d178bde7126f6fe35Jean-Michel Trivi                mFocusStack.peek().mSourceRef.equals(cb);
3718d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi        Iterator<FocusStackEntry> stackIterator = mFocusStack.iterator();
3719d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi        while(stackIterator.hasNext()) {
3720d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi            FocusStackEntry fse = (FocusStackEntry)stackIterator.next();
3721d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi            if(fse.mSourceRef.equals(cb)) {
3722d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi                Log.i(TAG, " AudioFocus  abandonAudioFocus(): removing entry for "
3723d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi                        + fse.mClientId);
372472843377d50a8f95cceaf33d316ab68d9b47f2ebJean-Michel Trivi                stackIterator.remove();
3725e7edc868538e83152e7bc35c830fee0d629baefcJean-Michel Trivi                // the client just died, no need to unlink to its death
3726d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi            }
3727d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi        }
3728e5e1e870fdb35f5291790e6d178bde7126f6fe35Jean-Michel Trivi        if (isTopOfStackForClientToRemove) {
3729e5e1e870fdb35f5291790e6d178bde7126f6fe35Jean-Michel Trivi            // we removed an entry at the top of the stack:
3730e5e1e870fdb35f5291790e6d178bde7126f6fe35Jean-Michel Trivi            //  notify the new top of the stack it gained focus.
3731e5e1e870fdb35f5291790e6d178bde7126f6fe35Jean-Michel Trivi            notifyTopOfAudioFocusStack();
37328f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi            // there's a new top of the stack, let the remote control know
37338f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi            synchronized(mRCStack) {
3734b716f0b7b2d8e4b045843fc6a7004910eb344c19Jean-Michel Trivi                checkUpdateRemoteControlDisplay_syncAfRcs(RC_INFO_ALL);
37358f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi            }
3736e5e1e870fdb35f5291790e6d178bde7126f6fe35Jean-Michel Trivi        }
3737d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi    }
3738d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi
3739d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi    /**
3740d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi     * Helper function:
3741d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi     * Returns true if the system is in a state where the focus can be reevaluated, false otherwise.
3742d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi     */
3743d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi    private boolean canReassignAudioFocus() {
3744b4bccb6d8df16a2c5235cead187156bc721cf074Jean-Michel Trivi        // focus requests are rejected during a phone call or when the phone is ringing
3745b4bccb6d8df16a2c5235cead187156bc721cf074Jean-Michel Trivi        // this is equivalent to IN_VOICE_COMM_FOCUS_ID having the focus
3746b4bccb6d8df16a2c5235cead187156bc721cf074Jean-Michel Trivi        if (!mFocusStack.isEmpty() && IN_VOICE_COMM_FOCUS_ID.equals(mFocusStack.peek().mClientId)) {
3747d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi            return false;
3748d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi        }
3749d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi        return true;
3750d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi    }
3751d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi
3752d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi    /**
3753d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi     * Inner class to monitor audio focus client deaths, and remove them from the audio focus
3754d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi     * stack if necessary.
3755d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi     */
3756d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi    private class AudioFocusDeathHandler implements IBinder.DeathRecipient {
3757d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi        private IBinder mCb; // To be notified of client's death
3758d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi
3759d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi        AudioFocusDeathHandler(IBinder cb) {
3760d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi            mCb = cb;
3761d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi        }
3762d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi
3763d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi        public void binderDied() {
3764392a2bbb52688ebd25768a7784d9edca7f498110Jean-Michel Trivi            synchronized(mAudioFocusLock) {
3765d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi                Log.w(TAG, "  AudioFocus   audio focus client died");
3766d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi                removeFocusStackEntryForClient(mCb);
3767d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi            }
3768d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi        }
3769d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi
3770d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi        public IBinder getBinder() {
3771d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi            return mCb;
3772d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi        }
3773d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi    }
3774d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi
3775d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi
3776d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi    /** @see AudioManager#requestAudioFocus(IAudioFocusDispatcher, int, int) */
3777078fd47e91d495175927d1a4a8b9aad039a7ba4eJean-Michel Trivi    public int requestAudioFocus(int mainStreamType, int focusChangeHint, IBinder cb,
37788f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi            IAudioFocusDispatcher fd, String clientId, String callingPackageName) {
3779d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi        Log.i(TAG, " AudioFocus  requestAudioFocus() from " + clientId);
3780d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi        // the main stream type for the audio focus request is currently not used. It may
3781d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi        // potentially be used to handle multiple stream type-dependent audio focuses.
3782d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi
3783382f4e6ea4dcf39105b36364582ed01642daa93cJean-Michel Trivi        // we need a valid binder callback for clients
3784382f4e6ea4dcf39105b36364582ed01642daa93cJean-Michel Trivi        if (!cb.pingBinder()) {
3785382f4e6ea4dcf39105b36364582ed01642daa93cJean-Michel Trivi            Log.e(TAG, " AudioFocus DOA client for requestAudioFocus(), aborting.");
3786d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi            return AudioManager.AUDIOFOCUS_REQUEST_FAILED;
3787d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi        }
3788d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi
3789392a2bbb52688ebd25768a7784d9edca7f498110Jean-Michel Trivi        synchronized(mAudioFocusLock) {
3790392a2bbb52688ebd25768a7784d9edca7f498110Jean-Michel Trivi            if (!canReassignAudioFocus()) {
3791392a2bbb52688ebd25768a7784d9edca7f498110Jean-Michel Trivi                return AudioManager.AUDIOFOCUS_REQUEST_FAILED;
3792392a2bbb52688ebd25768a7784d9edca7f498110Jean-Michel Trivi            }
3793d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi
3794baf674eedd5ecff9da0cf8cabe9868f7699b1695Jean-Michel Trivi            // handle the potential premature death of the new holder of the focus
3795baf674eedd5ecff9da0cf8cabe9868f7699b1695Jean-Michel Trivi            // (premature death == death before abandoning focus)
3796baf674eedd5ecff9da0cf8cabe9868f7699b1695Jean-Michel Trivi            // Register for client death notification
3797baf674eedd5ecff9da0cf8cabe9868f7699b1695Jean-Michel Trivi            AudioFocusDeathHandler afdh = new AudioFocusDeathHandler(cb);
3798baf674eedd5ecff9da0cf8cabe9868f7699b1695Jean-Michel Trivi            try {
3799baf674eedd5ecff9da0cf8cabe9868f7699b1695Jean-Michel Trivi                cb.linkToDeath(afdh, 0);
3800baf674eedd5ecff9da0cf8cabe9868f7699b1695Jean-Michel Trivi            } catch (RemoteException e) {
3801baf674eedd5ecff9da0cf8cabe9868f7699b1695Jean-Michel Trivi                // client has already died!
3802baf674eedd5ecff9da0cf8cabe9868f7699b1695Jean-Michel Trivi                Log.w(TAG, "AudioFocus  requestAudioFocus() could not link to "+cb+" binder death");
3803baf674eedd5ecff9da0cf8cabe9868f7699b1695Jean-Michel Trivi                return AudioManager.AUDIOFOCUS_REQUEST_FAILED;
3804baf674eedd5ecff9da0cf8cabe9868f7699b1695Jean-Michel Trivi            }
3805baf674eedd5ecff9da0cf8cabe9868f7699b1695Jean-Michel Trivi
3806d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi            if (!mFocusStack.empty() && mFocusStack.peek().mClientId.equals(clientId)) {
3807e5e1e870fdb35f5291790e6d178bde7126f6fe35Jean-Michel Trivi                // if focus is already owned by this client and the reason for acquiring the focus
3808e5e1e870fdb35f5291790e6d178bde7126f6fe35Jean-Michel Trivi                // hasn't changed, don't do anything
3809e5e1e870fdb35f5291790e6d178bde7126f6fe35Jean-Michel Trivi                if (mFocusStack.peek().mFocusChangeType == focusChangeHint) {
3810de1f065be109e1c313d8330c8e34210fedaac74eJean-Michel Trivi                    // unlink death handler so it can be gc'ed.
3811de1f065be109e1c313d8330c8e34210fedaac74eJean-Michel Trivi                    // linkToDeath() creates a JNI global reference preventing collection.
3812de1f065be109e1c313d8330c8e34210fedaac74eJean-Michel Trivi                    cb.unlinkToDeath(afdh, 0);
3813e5e1e870fdb35f5291790e6d178bde7126f6fe35Jean-Michel Trivi                    return AudioManager.AUDIOFOCUS_REQUEST_GRANTED;
3814e5e1e870fdb35f5291790e6d178bde7126f6fe35Jean-Michel Trivi                }
3815e5e1e870fdb35f5291790e6d178bde7126f6fe35Jean-Michel Trivi                // the reason for the audio focus request has changed: remove the current top of
3816e5e1e870fdb35f5291790e6d178bde7126f6fe35Jean-Michel Trivi                // stack and respond as if we had a new focus owner
3817e7edc868538e83152e7bc35c830fee0d629baefcJean-Michel Trivi                FocusStackEntry fse = mFocusStack.pop();
3818e7edc868538e83152e7bc35c830fee0d629baefcJean-Michel Trivi                fse.unlinkToDeath();
3819d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi            }
3820d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi
3821d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi            // notify current top of stack it is losing focus
3822d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi            if (!mFocusStack.empty() && (mFocusStack.peek().mFocusDispatcher != null)) {
3823d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi                try {
3824d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi                    mFocusStack.peek().mFocusDispatcher.dispatchAudioFocusChange(
3825078fd47e91d495175927d1a4a8b9aad039a7ba4eJean-Michel Trivi                            -1 * focusChangeHint, // loss and gain codes are inverse of each other
3826d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi                            mFocusStack.peek().mClientId);
3827d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi                } catch (RemoteException e) {
3828d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi                    Log.e(TAG, " Failure to signal loss of focus due to "+ e);
3829d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi                    e.printStackTrace();
3830d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi                }
3831d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi            }
3832d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi
383355d1bb3483e17a11d122e68044e552d96ab55ff4Jean-Michel Trivi            // focus requester might already be somewhere below in the stack, remove it
3834baf674eedd5ecff9da0cf8cabe9868f7699b1695Jean-Michel Trivi            removeFocusStackEntry(clientId, false /* signal */);
3835061214bb71a4a4211e670001226c68f5e8036b84Jean-Michel Trivi
3836d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi            // push focus requester at the top of the audio focus stack
38378f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi            mFocusStack.push(new FocusStackEntry(mainStreamType, focusChangeHint, fd, cb,
3838061214bb71a4a4211e670001226c68f5e8036b84Jean-Michel Trivi                    clientId, afdh, callingPackageName, Binder.getCallingUid()));
38398f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi
38408f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi            // there's a new top of the stack, let the remote control know
38418f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi            synchronized(mRCStack) {
3842b716f0b7b2d8e4b045843fc6a7004910eb344c19Jean-Michel Trivi                checkUpdateRemoteControlDisplay_syncAfRcs(RC_INFO_ALL);
38438f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi            }
3844392a2bbb52688ebd25768a7784d9edca7f498110Jean-Michel Trivi        }//synchronized(mAudioFocusLock)
3845d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi
3846d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi        return AudioManager.AUDIOFOCUS_REQUEST_GRANTED;
3847d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi    }
3848d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi
3849d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi    /** @see AudioManager#abandonAudioFocus(IAudioFocusDispatcher) */
3850d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi    public int abandonAudioFocus(IAudioFocusDispatcher fl, String clientId) {
3851d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi        Log.i(TAG, " AudioFocus  abandonAudioFocus() from " + clientId);
3852392a2bbb52688ebd25768a7784d9edca7f498110Jean-Michel Trivi        try {
3853392a2bbb52688ebd25768a7784d9edca7f498110Jean-Michel Trivi            // this will take care of notifying the new focus owner if needed
3854392a2bbb52688ebd25768a7784d9edca7f498110Jean-Michel Trivi            synchronized(mAudioFocusLock) {
3855392a2bbb52688ebd25768a7784d9edca7f498110Jean-Michel Trivi                removeFocusStackEntry(clientId, true);
3856392a2bbb52688ebd25768a7784d9edca7f498110Jean-Michel Trivi            }
3857392a2bbb52688ebd25768a7784d9edca7f498110Jean-Michel Trivi        } catch (java.util.ConcurrentModificationException cme) {
3858392a2bbb52688ebd25768a7784d9edca7f498110Jean-Michel Trivi            // Catching this exception here is temporary. It is here just to prevent
3859392a2bbb52688ebd25768a7784d9edca7f498110Jean-Michel Trivi            // a crash seen when the "Silent" notification is played. This is believed to be fixed
3860392a2bbb52688ebd25768a7784d9edca7f498110Jean-Michel Trivi            // but this try catch block is left just to be safe.
3861392a2bbb52688ebd25768a7784d9edca7f498110Jean-Michel Trivi            Log.e(TAG, "FATAL EXCEPTION AudioFocus  abandonAudioFocus() caused " + cme);
3862392a2bbb52688ebd25768a7784d9edca7f498110Jean-Michel Trivi            cme.printStackTrace();
38632930bb2d47be279dd228ba8c749c1e39e5da8be1Jean-Michel Trivi        }
3864d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi
3865d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi        return AudioManager.AUDIOFOCUS_REQUEST_GRANTED;
3866d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi    }
3867d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi
3868d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi
3869d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi    public void unregisterAudioFocusClient(String clientId) {
3870392a2bbb52688ebd25768a7784d9edca7f498110Jean-Michel Trivi        synchronized(mAudioFocusLock) {
38712930bb2d47be279dd228ba8c749c1e39e5da8be1Jean-Michel Trivi            removeFocusStackEntry(clientId, false);
38722930bb2d47be279dd228ba8c749c1e39e5da8be1Jean-Michel Trivi        }
3873d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi    }
3874d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi
3875d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi
3876d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi    //==========================================================================================
3877d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi    // RemoteControl
3878d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi    //==========================================================================================
3879c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi    public void dispatchMediaKeyEvent(KeyEvent keyEvent) {
38804294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi        filterMediaKeyEvent(keyEvent, false /*needWakeLock*/);
3881c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi    }
3882c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi
3883c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi    public void dispatchMediaKeyEventUnderWakelock(KeyEvent keyEvent) {
38844294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi        filterMediaKeyEvent(keyEvent, true /*needWakeLock*/);
3885c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi    }
3886c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi
38874294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi    private void filterMediaKeyEvent(KeyEvent keyEvent, boolean needWakeLock) {
3888c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi        // sanity check on the incoming key event
3889c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi        if (!isValidMediaKeyEvent(keyEvent)) {
3890c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi            Log.e(TAG, "not dispatching invalid media key event " + keyEvent);
3891c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi            return;
3892c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi        }
3893722b808662eb20fa91151f1e3aa05fd911d1d226Jean-Michel Trivi        // event filtering for telephony
3894c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi        synchronized(mRingingLock) {
3895722b808662eb20fa91151f1e3aa05fd911d1d226Jean-Michel Trivi            synchronized(mRCStack) {
3896722b808662eb20fa91151f1e3aa05fd911d1d226Jean-Michel Trivi                if ((mMediaReceiverForCalls != null) &&
3897722b808662eb20fa91151f1e3aa05fd911d1d226Jean-Michel Trivi                        (mIsRinging || (getMode() == AudioSystem.MODE_IN_CALL))) {
3898722b808662eb20fa91151f1e3aa05fd911d1d226Jean-Michel Trivi                    dispatchMediaKeyEventForCalls(keyEvent, needWakeLock);
3899722b808662eb20fa91151f1e3aa05fd911d1d226Jean-Michel Trivi                    return;
3900722b808662eb20fa91151f1e3aa05fd911d1d226Jean-Michel Trivi                }
3901d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi            }
3902c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi        }
39034294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi        // event filtering based on voice-based interactions
39044294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi        if (isValidVoiceInputKeyCode(keyEvent.getKeyCode())) {
39054294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi            filterVoiceInputKeyEvent(keyEvent, needWakeLock);
39064294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi        } else {
39074294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi            dispatchMediaKeyEvent(keyEvent, needWakeLock);
39084294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi        }
39094294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi    }
39104294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi
39114294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi    /**
3912722b808662eb20fa91151f1e3aa05fd911d1d226Jean-Michel Trivi     * Handles the dispatching of the media button events to the telephony package.
3913722b808662eb20fa91151f1e3aa05fd911d1d226Jean-Michel Trivi     * Precondition: mMediaReceiverForCalls != null
3914722b808662eb20fa91151f1e3aa05fd911d1d226Jean-Michel Trivi     * @param keyEvent a non-null KeyEvent whose key code is one of the supported media buttons
3915722b808662eb20fa91151f1e3aa05fd911d1d226Jean-Michel Trivi     * @param needWakeLock true if a PARTIAL_WAKE_LOCK needs to be held while this key event
3916722b808662eb20fa91151f1e3aa05fd911d1d226Jean-Michel Trivi     *     is dispatched.
3917722b808662eb20fa91151f1e3aa05fd911d1d226Jean-Michel Trivi     */
3918722b808662eb20fa91151f1e3aa05fd911d1d226Jean-Michel Trivi    private void dispatchMediaKeyEventForCalls(KeyEvent keyEvent, boolean needWakeLock) {
3919722b808662eb20fa91151f1e3aa05fd911d1d226Jean-Michel Trivi        Intent keyIntent = new Intent(Intent.ACTION_MEDIA_BUTTON, null);
3920722b808662eb20fa91151f1e3aa05fd911d1d226Jean-Michel Trivi        keyIntent.putExtra(Intent.EXTRA_KEY_EVENT, keyEvent);
3921722b808662eb20fa91151f1e3aa05fd911d1d226Jean-Michel Trivi        keyIntent.setPackage(mMediaReceiverForCalls.getPackageName());
3922722b808662eb20fa91151f1e3aa05fd911d1d226Jean-Michel Trivi        if (needWakeLock) {
3923722b808662eb20fa91151f1e3aa05fd911d1d226Jean-Michel Trivi            mMediaEventWakeLock.acquire();
3924722b808662eb20fa91151f1e3aa05fd911d1d226Jean-Michel Trivi            keyIntent.putExtra(EXTRA_WAKELOCK_ACQUIRED, WAKELOCK_RELEASE_ON_FINISHED);
3925722b808662eb20fa91151f1e3aa05fd911d1d226Jean-Michel Trivi        }
3926722b808662eb20fa91151f1e3aa05fd911d1d226Jean-Michel Trivi        mContext.sendOrderedBroadcast(keyIntent, null, mKeyEventDone,
3927722b808662eb20fa91151f1e3aa05fd911d1d226Jean-Michel Trivi                mAudioHandler, Activity.RESULT_OK, null, null);
3928722b808662eb20fa91151f1e3aa05fd911d1d226Jean-Michel Trivi    }
3929722b808662eb20fa91151f1e3aa05fd911d1d226Jean-Michel Trivi
3930722b808662eb20fa91151f1e3aa05fd911d1d226Jean-Michel Trivi    /**
39314294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi     * Handles the dispatching of the media button events to one of the registered listeners,
39324294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi     * or if there was none, broadcast an ACTION_MEDIA_BUTTON intent to the rest of the system.
39334294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi     * @param keyEvent a non-null KeyEvent whose key code is one of the supported media buttons
39344294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi     * @param needWakeLock true if a PARTIAL_WAKE_LOCK needs to be held while this key event
39354294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi     *     is dispatched.
39364294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi     */
39374294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi    private void dispatchMediaKeyEvent(KeyEvent keyEvent, boolean needWakeLock) {
3938c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi        if (needWakeLock) {
3939c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi            mMediaEventWakeLock.acquire();
3940c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi        }
3941c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi        Intent keyIntent = new Intent(Intent.ACTION_MEDIA_BUTTON, null);
3942c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi        keyIntent.putExtra(Intent.EXTRA_KEY_EVENT, keyEvent);
3943c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi        synchronized(mRCStack) {
3944c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi            if (!mRCStack.empty()) {
3945c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi                // send the intent that was registered by the client
3946c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi                try {
3947c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi                    mRCStack.peek().mMediaIntent.send(mContext,
3948c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi                            needWakeLock ? WAKELOCK_RELEASE_ON_FINISHED : 0 /*code*/,
3949c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi                            keyIntent, AudioService.this, mAudioHandler);
3950c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi                } catch (CanceledException e) {
3951c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi                    Log.e(TAG, "Error sending pending intent " + mRCStack.peek());
3952c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi                    e.printStackTrace();
3953d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi                }
3954c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi            } else {
3955c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi                // legacy behavior when nobody registered their media button event receiver
3956c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi                //    through AudioManager
3957c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi                if (needWakeLock) {
3958c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi                    keyIntent.putExtra(EXTRA_WAKELOCK_ACQUIRED, WAKELOCK_RELEASE_ON_FINISHED);
3959d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi                }
3960c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi                mContext.sendOrderedBroadcast(keyIntent, null, mKeyEventDone,
3961c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi                        mAudioHandler, Activity.RESULT_OK, null, null);
3962d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi            }
3963d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi        }
3964d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi    }
3965d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi
39664294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi    /**
3967ab624c2fd4f0fad6ba7f422a960942e5a7035ceaJeff Brown     * The different actions performed in response to a voice button key event.
39684294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi     */
39694294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi    private final static int VOICEBUTTON_ACTION_DISCARD_CURRENT_KEY_PRESS = 1;
39704294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi    private final static int VOICEBUTTON_ACTION_START_VOICE_INPUT = 2;
39714294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi    private final static int VOICEBUTTON_ACTION_SIMULATE_KEY_PRESS = 3;
39724294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi
39734294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi    private final Object mVoiceEventLock = new Object();
3974ab624c2fd4f0fad6ba7f422a960942e5a7035ceaJeff Brown    private boolean mVoiceButtonDown;
3975ab624c2fd4f0fad6ba7f422a960942e5a7035ceaJeff Brown    private boolean mVoiceButtonHandled;
39764294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi
39774294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi    /**
39784294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi     * Filter key events that may be used for voice-based interactions
39794294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi     * @param keyEvent a non-null KeyEvent whose key code is that of one of the supported
39804294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi     *    media buttons that can be used to trigger voice-based interactions.
39814294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi     * @param needWakeLock true if a PARTIAL_WAKE_LOCK needs to be held while this key event
39824294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi     *     is dispatched.
39834294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi     */
39844294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi    private void filterVoiceInputKeyEvent(KeyEvent keyEvent, boolean needWakeLock) {
3985ab624c2fd4f0fad6ba7f422a960942e5a7035ceaJeff Brown        if (DEBUG_RC) {
3986ab624c2fd4f0fad6ba7f422a960942e5a7035ceaJeff Brown            Log.v(TAG, "voice input key event: " + keyEvent + ", needWakeLock=" + needWakeLock);
3987ab624c2fd4f0fad6ba7f422a960942e5a7035ceaJeff Brown        }
3988ab624c2fd4f0fad6ba7f422a960942e5a7035ceaJeff Brown
39894294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi        int voiceButtonAction = VOICEBUTTON_ACTION_DISCARD_CURRENT_KEY_PRESS;
39904294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi        int keyAction = keyEvent.getAction();
39914294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi        synchronized (mVoiceEventLock) {
3992ab624c2fd4f0fad6ba7f422a960942e5a7035ceaJeff Brown            if (keyAction == KeyEvent.ACTION_DOWN) {
3993ab624c2fd4f0fad6ba7f422a960942e5a7035ceaJeff Brown                if (keyEvent.getRepeatCount() == 0) {
3994ab624c2fd4f0fad6ba7f422a960942e5a7035ceaJeff Brown                    // initial down
3995ab624c2fd4f0fad6ba7f422a960942e5a7035ceaJeff Brown                    mVoiceButtonDown = true;
3996ab624c2fd4f0fad6ba7f422a960942e5a7035ceaJeff Brown                    mVoiceButtonHandled = false;
3997ab624c2fd4f0fad6ba7f422a960942e5a7035ceaJeff Brown                } else if (mVoiceButtonDown && !mVoiceButtonHandled
3998ab624c2fd4f0fad6ba7f422a960942e5a7035ceaJeff Brown                        && (keyEvent.getFlags() & KeyEvent.FLAG_LONG_PRESS) != 0) {
3999ab624c2fd4f0fad6ba7f422a960942e5a7035ceaJeff Brown                    // long-press, start voice-based interactions
4000ab624c2fd4f0fad6ba7f422a960942e5a7035ceaJeff Brown                    mVoiceButtonHandled = true;
4001ab624c2fd4f0fad6ba7f422a960942e5a7035ceaJeff Brown                    voiceButtonAction = VOICEBUTTON_ACTION_START_VOICE_INPUT;
4002ab624c2fd4f0fad6ba7f422a960942e5a7035ceaJeff Brown                }
4003ab624c2fd4f0fad6ba7f422a960942e5a7035ceaJeff Brown            } else if (keyAction == KeyEvent.ACTION_UP) {
4004ab624c2fd4f0fad6ba7f422a960942e5a7035ceaJeff Brown                if (mVoiceButtonDown) {
4005ab624c2fd4f0fad6ba7f422a960942e5a7035ceaJeff Brown                    // voice button up
4006ab624c2fd4f0fad6ba7f422a960942e5a7035ceaJeff Brown                    mVoiceButtonDown = false;
4007ab624c2fd4f0fad6ba7f422a960942e5a7035ceaJeff Brown                    if (!mVoiceButtonHandled && !keyEvent.isCanceled()) {
4008ab624c2fd4f0fad6ba7f422a960942e5a7035ceaJeff Brown                        voiceButtonAction = VOICEBUTTON_ACTION_SIMULATE_KEY_PRESS;
40094294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi                    }
4010ab624c2fd4f0fad6ba7f422a960942e5a7035ceaJeff Brown                }
40114294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi            }
40124294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi        }//synchronized (mVoiceEventLock)
40134294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi
40144294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi        // take action after media button event filtering for voice-based interactions
40154294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi        switch (voiceButtonAction) {
40164294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi            case VOICEBUTTON_ACTION_DISCARD_CURRENT_KEY_PRESS:
40174294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi                if (DEBUG_RC) Log.v(TAG, "   ignore key event");
40184294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi                break;
40194294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi            case VOICEBUTTON_ACTION_START_VOICE_INPUT:
40204294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi                if (DEBUG_RC) Log.v(TAG, "   start voice-based interactions");
40214294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi                // then start the voice-based interactions
40224294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi                startVoiceBasedInteractions(needWakeLock);
40234294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi                break;
40244294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi            case VOICEBUTTON_ACTION_SIMULATE_KEY_PRESS:
40254294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi                if (DEBUG_RC) Log.v(TAG, "   send simulated key event");
40264294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi                sendSimulatedMediaButtonEvent(keyEvent, needWakeLock);
40274294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi                break;
40284294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi        }
40294294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi    }
40304294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi
40314294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi    private void sendSimulatedMediaButtonEvent(KeyEvent originalKeyEvent, boolean needWakeLock) {
40324294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi        // send DOWN event
40334294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi        KeyEvent keyEvent = KeyEvent.changeAction(originalKeyEvent, KeyEvent.ACTION_DOWN);
40344294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi        dispatchMediaKeyEvent(keyEvent, needWakeLock);
40354294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi        // send UP event
40364294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi        keyEvent = KeyEvent.changeAction(originalKeyEvent, KeyEvent.ACTION_UP);
40374294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi        dispatchMediaKeyEvent(keyEvent, needWakeLock);
40384294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi
40394294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi    }
40404294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi
40414294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi
4042c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi    private static boolean isValidMediaKeyEvent(KeyEvent keyEvent) {
4043c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi        if (keyEvent == null) {
4044c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi            return false;
4045c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi        }
4046c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi        final int keyCode = keyEvent.getKeyCode();
4047c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi        switch (keyCode) {
4048c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi            case KeyEvent.KEYCODE_MUTE:
4049c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi            case KeyEvent.KEYCODE_HEADSETHOOK:
4050c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi            case KeyEvent.KEYCODE_MEDIA_PLAY:
4051c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi            case KeyEvent.KEYCODE_MEDIA_PAUSE:
4052c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi            case KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE:
4053c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi            case KeyEvent.KEYCODE_MEDIA_STOP:
4054c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi            case KeyEvent.KEYCODE_MEDIA_NEXT:
4055c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi            case KeyEvent.KEYCODE_MEDIA_PREVIOUS:
4056c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi            case KeyEvent.KEYCODE_MEDIA_REWIND:
4057c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi            case KeyEvent.KEYCODE_MEDIA_RECORD:
4058c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi            case KeyEvent.KEYCODE_MEDIA_FAST_FORWARD:
4059c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi            case KeyEvent.KEYCODE_MEDIA_CLOSE:
4060c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi            case KeyEvent.KEYCODE_MEDIA_EJECT:
4061c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi                break;
4062c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi            default:
4063c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi                return false;
4064c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi        }
4065c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi        return true;
4066c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi    }
4067c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi
40684294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi    /**
40694294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi     * Checks whether the given key code is one that can trigger the launch of voice-based
40704294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi     *   interactions.
40714294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi     * @param keyCode the key code associated with the key event
40724294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi     * @return true if the key is one of the supported voice-based interaction triggers
40734294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi     */
40744294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi    private static boolean isValidVoiceInputKeyCode(int keyCode) {
40754294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi        if (keyCode == KeyEvent.KEYCODE_HEADSETHOOK) {
40764294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi            return true;
40774294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi        } else {
40784294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi            return false;
40794294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi        }
40804294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi    }
40814294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi
40824294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi    /**
40834294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi     * Tell the system to start voice-based interactions / voice commands
40844294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi     */
40854294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi    private void startVoiceBasedInteractions(boolean needWakeLock) {
40863c2711fc2853394324b044632b79ca67388df8f4Jean-Michel Trivi        Intent voiceIntent = null;
40873c2711fc2853394324b044632b79ca67388df8f4Jean-Michel Trivi        // select which type of search to launch:
40883c2711fc2853394324b044632b79ca67388df8f4Jean-Michel Trivi        // - screen on and device unlocked: action is ACTION_WEB_SEARCH
40893c2711fc2853394324b044632b79ca67388df8f4Jean-Michel Trivi        // - device locked or screen off: action is ACTION_VOICE_SEARCH_HANDS_FREE
40903c2711fc2853394324b044632b79ca67388df8f4Jean-Michel Trivi        //    with EXTRA_SECURE set to true if the device is securely locked
40913c2711fc2853394324b044632b79ca67388df8f4Jean-Michel Trivi        PowerManager pm = (PowerManager)mContext.getSystemService(Context.POWER_SERVICE);
40923c2711fc2853394324b044632b79ca67388df8f4Jean-Michel Trivi        boolean isLocked = mKeyguardManager != null && mKeyguardManager.isKeyguardLocked();
40933c2711fc2853394324b044632b79ca67388df8f4Jean-Michel Trivi        if (!isLocked && pm.isScreenOn()) {
40943c2711fc2853394324b044632b79ca67388df8f4Jean-Michel Trivi            voiceIntent = new Intent(android.speech.RecognizerIntent.ACTION_WEB_SEARCH);
40953c2711fc2853394324b044632b79ca67388df8f4Jean-Michel Trivi        } else {
40963c2711fc2853394324b044632b79ca67388df8f4Jean-Michel Trivi            voiceIntent = new Intent(RecognizerIntent.ACTION_VOICE_SEARCH_HANDS_FREE);
40973c2711fc2853394324b044632b79ca67388df8f4Jean-Michel Trivi            voiceIntent.putExtra(RecognizerIntent.EXTRA_SECURE,
40983c2711fc2853394324b044632b79ca67388df8f4Jean-Michel Trivi                    isLocked && mKeyguardManager.isKeyguardSecure());
40993c2711fc2853394324b044632b79ca67388df8f4Jean-Michel Trivi        }
41003c2711fc2853394324b044632b79ca67388df8f4Jean-Michel Trivi        // start the search activity
41014294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi        if (needWakeLock) {
41024294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi            mMediaEventWakeLock.acquire();
41034294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi        }
41044294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi        try {
41053c2711fc2853394324b044632b79ca67388df8f4Jean-Michel Trivi            if (voiceIntent != null) {
41063c2711fc2853394324b044632b79ca67388df8f4Jean-Michel Trivi                voiceIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
41073c2711fc2853394324b044632b79ca67388df8f4Jean-Michel Trivi                        | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
41083c2711fc2853394324b044632b79ca67388df8f4Jean-Michel Trivi                mContext.startActivity(voiceIntent);
41094294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi            }
41104294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi        } catch (ActivityNotFoundException e) {
41113c2711fc2853394324b044632b79ca67388df8f4Jean-Michel Trivi            Log.w(TAG, "No activity for search: " + e);
41124294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi        } finally {
41134294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi            if (needWakeLock) {
41144294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi                mMediaEventWakeLock.release();
41154294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi            }
41164294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi        }
41174294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi    }
41184294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi
4119c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi    private PowerManager.WakeLock mMediaEventWakeLock;
4120c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi
4121c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi    private static final int WAKELOCK_RELEASE_ON_FINISHED = 1980; //magic number
4122c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi
4123c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi    // only set when wakelock was acquired, no need to check value when received
4124c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi    private static final String EXTRA_WAKELOCK_ACQUIRED =
4125c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi            "android.media.AudioService.WAKELOCK_ACQUIRED";
4126c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi
4127c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi    public void onSendFinished(PendingIntent pendingIntent, Intent intent,
4128c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi            int resultCode, String resultData, Bundle resultExtras) {
4129c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi        if (resultCode == WAKELOCK_RELEASE_ON_FINISHED) {
4130c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi            mMediaEventWakeLock.release();
4131c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi        }
4132c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi    }
4133c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi
4134c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi    BroadcastReceiver mKeyEventDone = new BroadcastReceiver() {
4135c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi        public void onReceive(Context context, Intent intent) {
41364294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi            if (intent == null) {
41374294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi                return;
41384294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi            }
41394294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi            Bundle extras = intent.getExtras();
41404294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi            if (extras == null) {
41414294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi                return;
41424294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi            }
41434294b83927f51e5c115ebaafd2e185ba5de91436Jean-Michel Trivi            if (extras.containsKey(EXTRA_WAKELOCK_ACQUIRED)) {
4144c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi                mMediaEventWakeLock.release();
4145c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi            }
4146c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi        }
4147c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi    };
4148c68022258ebd3dd97a5079ba99f4f3cd12b223b0Jean-Michel Trivi
4149ced110ec5970c632f523dfc0350b6071461ea9bcNeel Parekh    private final Object mCurrentRcLock = new Object();
41508f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi    /**
41514426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     * The one remote control client which will receive a request for display information.
415217da769e987de40e113c5b2a3b867b25ba7ac0a2Jean-Michel Trivi     * This object may be null.
41538f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi     * Access protected by mCurrentRcLock.
41548f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi     */
41554426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    private IRemoteControlClient mCurrentRcClient = null;
41568f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi
41577b6198cacc3e7dd31ef91537d809857d826fb7faJean-Michel Trivi    private final static int RC_INFO_NONE = 0;
41587b6198cacc3e7dd31ef91537d809857d826fb7faJean-Michel Trivi    private final static int RC_INFO_ALL =
41594426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi        RemoteControlClient.FLAG_INFORMATION_REQUEST_ALBUM_ART |
41604426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi        RemoteControlClient.FLAG_INFORMATION_REQUEST_KEY_MEDIA |
41614426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi        RemoteControlClient.FLAG_INFORMATION_REQUEST_METADATA |
41624426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi        RemoteControlClient.FLAG_INFORMATION_REQUEST_PLAYSTATE;
41637b6198cacc3e7dd31ef91537d809857d826fb7faJean-Michel Trivi
41647b6198cacc3e7dd31ef91537d809857d826fb7faJean-Michel Trivi    /**
416517da769e987de40e113c5b2a3b867b25ba7ac0a2Jean-Michel Trivi     * A monotonically increasing generation counter for mCurrentRcClient.
41668f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi     * Only accessed with a lock on mCurrentRcLock.
416717da769e987de40e113c5b2a3b867b25ba7ac0a2Jean-Michel Trivi     * No value wrap-around issues as we only act on equal values.
41688f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi     */
4169ced110ec5970c632f523dfc0350b6071461ea9bcNeel Parekh    private int mCurrentRcClientGen = 0;
41708f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi
41718f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi    /**
41728f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi     * Inner class to monitor remote control client deaths, and remove the client for the
41738f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi     * remote control stack if necessary.
41748f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi     */
41758f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi    private class RcClientDeathHandler implements IBinder.DeathRecipient {
41768f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi        private IBinder mCb; // To be notified of client's death
4177f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi        private PendingIntent mMediaIntent;
41788f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi
4179f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi        RcClientDeathHandler(IBinder cb, PendingIntent pi) {
41808f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi            mCb = cb;
4181f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi            mMediaIntent = pi;
41828f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi        }
41838f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi
41848f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi        public void binderDied() {
41858f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi            Log.w(TAG, "  RemoteControlClient died");
41868f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi            // remote control client died, make sure the displays don't use it anymore
41878f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi            //  by setting its remote control client to null
418826b3d1ff38998c7cb80a2950da0589ebd8510897Jean-Michel Trivi            registerRemoteControlClient(mMediaIntent, null/*rcClient*/, null/*ignored*/);
41893114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi            // the dead client was maybe handling remote playback, reevaluate
41903114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi            postReevaluateRemote();
41918f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi        }
41928f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi
41938f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi        public IBinder getBinder() {
41948f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi            return mCb;
41958f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi        }
41968f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi    }
41978f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi
41983114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    /**
41993114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     * A global counter for RemoteControlClient identifiers
42003114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     */
42013114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    private static int sLastRccId = 0;
42023114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi
42033114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    private class RemotePlaybackState {
42043114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        int mRccId;
42053114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        int mVolume;
42063114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        int mVolumeMax;
42073114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        int mVolumeHandling;
42083114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi
42093114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        private RemotePlaybackState(int id, int vol, int volMax) {
42103114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi            mRccId = id;
42113114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi            mVolume = vol;
42123114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi            mVolumeMax = volMax;
42133114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi            mVolumeHandling = RemoteControlClient.DEFAULT_PLAYBACK_VOLUME_HANDLING;
42143114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        }
42153114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    }
42163114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi
42173114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    /**
42183114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     * Internal cache for the playback information of the RemoteControlClient whose volume gets to
42193114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     * be controlled by the volume keys ("main"), so we don't have to iterate over the RC stack
42203114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     * every time we need this info.
42213114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     */
42223114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    private RemotePlaybackState mMainRemote;
42233114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    /**
42243114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     * Indicates whether the "main" RemoteControlClient is considered active.
42253114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     * Use synchronized on mMainRemote.
42263114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     */
42273114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    private boolean mMainRemoteIsActive;
42283114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    /**
42293114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     * Indicates whether there is remote playback going on. True even if there is no "active"
42303114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     * remote playback (mMainRemoteIsActive is false), but a RemoteControlClient has declared it
42313114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     * handles remote playback.
42323114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     * Use synchronized on mMainRemote.
42333114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     */
42343114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    private boolean mHasRemotePlayback;
42353114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi
4236d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi    private static class RemoteControlStackEntry {
42373114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        public int mRccId = RemoteControlClient.RCSE_ID_UNREGISTERED;
4238f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi        /**
4239f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi         * The target for the ACTION_MEDIA_BUTTON events.
4240f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi         * Always non null.
4241f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi         */
4242f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi        public PendingIntent mMediaIntent;
4243f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi        /**
4244f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi         * The registered media button event receiver.
4245f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi         * Always non null.
4246f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi         */
4247f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi        public ComponentName mReceiverComponent;
42488f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi        public String mCallingPackageName;
42498f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi        public int mCallingUid;
4250f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi        /**
4251f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi         * Provides access to the information to display on the remote control.
4252f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi         * May be null (when a media button event receiver is registered,
4253f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi         *     but no remote control client has been registered) */
42544426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi        public IRemoteControlClient mRcClient;
42558f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi        public RcClientDeathHandler mRcClientDeathHandler;
42563114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        /**
42573114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi         * Information only used for non-local playback
42583114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi         */
42593114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        public int mPlaybackType;
42603114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        public int mPlaybackVolume;
42613114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        public int mPlaybackVolumeMax;
42623114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        public int mPlaybackVolumeHandling;
42633114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        public int mPlaybackStream;
42643114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        public int mPlaybackState;
42651357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi        public IRemoteVolumeObserver mRemoteVolumeObs;
42663114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi
42673114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        public void resetPlaybackInfo() {
42683114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi            mPlaybackType = RemoteControlClient.PLAYBACK_TYPE_LOCAL;
42693114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi            mPlaybackVolume = RemoteControlClient.DEFAULT_PLAYBACK_VOLUME;
42703114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi            mPlaybackVolumeMax = RemoteControlClient.DEFAULT_PLAYBACK_VOLUME;
42713114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi            mPlaybackVolumeHandling = RemoteControlClient.DEFAULT_PLAYBACK_VOLUME_HANDLING;
42723114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi            mPlaybackStream = AudioManager.STREAM_MUSIC;
42733114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi            mPlaybackState = RemoteControlClient.PLAYSTATE_STOPPED;
42741357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi            mRemoteVolumeObs = null;
42753114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        }
4276d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi
4277f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi        /** precondition: mediaIntent != null, eventReceiver != null */
4278f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi        public RemoteControlStackEntry(PendingIntent mediaIntent, ComponentName eventReceiver) {
4279f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi            mMediaIntent = mediaIntent;
4280f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi            mReceiverComponent = eventReceiver;
42818f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi            mCallingUid = -1;
428217da769e987de40e113c5b2a3b867b25ba7ac0a2Jean-Michel Trivi            mRcClient = null;
42833114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi            mRccId = ++sLastRccId;
42843114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi
42853114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi            resetPlaybackInfo();
42868f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi        }
42878f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi
42888f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi        public void unlinkToRcClientDeath() {
42898f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi            if ((mRcClientDeathHandler != null) && (mRcClientDeathHandler.mCb != null)) {
42908f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi                try {
42918f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi                    mRcClientDeathHandler.mCb.unlinkToDeath(mRcClientDeathHandler, 0);
4292a9509736c85c19fe4ad4ba97a0545f0422a3dfc1Jean-Michel Trivi                    mRcClientDeathHandler = null;
42938f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi                } catch (java.util.NoSuchElementException e) {
42948f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi                    // not much we can do here
42958f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi                    Log.e(TAG, "Encountered " + e + " in unlinkToRcClientDeath()");
42968f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi                    e.printStackTrace();
42978f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi                }
42988f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi            }
4299d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi        }
4300a9509736c85c19fe4ad4ba97a0545f0422a3dfc1Jean-Michel Trivi
4301a9509736c85c19fe4ad4ba97a0545f0422a3dfc1Jean-Michel Trivi        @Override
4302a9509736c85c19fe4ad4ba97a0545f0422a3dfc1Jean-Michel Trivi        protected void finalize() throws Throwable {
4303a9509736c85c19fe4ad4ba97a0545f0422a3dfc1Jean-Michel Trivi            unlinkToRcClientDeath();// unlink exception handled inside method
4304a9509736c85c19fe4ad4ba97a0545f0422a3dfc1Jean-Michel Trivi            super.finalize();
4305a9509736c85c19fe4ad4ba97a0545f0422a3dfc1Jean-Michel Trivi        }
4306d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi    }
4307d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi
43088f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi    /**
43098f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi     *  The stack of remote control event receivers.
43108f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi     *  Code sections and methods that modify the remote control event receiver stack are
43118f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi     *  synchronized on mRCStack, but also BEFORE on mFocusLock as any change in either
43128f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi     *  stack, audio focus or RC, can lead to a change in the remote control display
43138f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi     */
431430c918ce7fbe171944b28fc91b3f22b3d631872dGlenn Kasten    private final Stack<RemoteControlStackEntry> mRCStack = new Stack<RemoteControlStackEntry>();
4315d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi
4316d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi    /**
4317722b808662eb20fa91151f1e3aa05fd911d1d226Jean-Michel Trivi     * The component the telephony package can register so telephony calls have priority to
4318722b808662eb20fa91151f1e3aa05fd911d1d226Jean-Michel Trivi     * handle media button events
4319722b808662eb20fa91151f1e3aa05fd911d1d226Jean-Michel Trivi     */
4320722b808662eb20fa91151f1e3aa05fd911d1d226Jean-Michel Trivi    private ComponentName mMediaReceiverForCalls = null;
4321722b808662eb20fa91151f1e3aa05fd911d1d226Jean-Michel Trivi
4322722b808662eb20fa91151f1e3aa05fd911d1d226Jean-Michel Trivi    /**
4323d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi     * Helper function:
4324d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi     * Display in the log the current entries in the remote control focus stack
4325d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi     */
4326d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi    private void dumpRCStack(PrintWriter pw) {
4327b4bccb6d8df16a2c5235cead187156bc721cf074Jean-Michel Trivi        pw.println("\nRemote Control stack entries:");
4328d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi        synchronized(mRCStack) {
4329d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi            Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator();
4330d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi            while(stackIterator.hasNext()) {
43318f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi                RemoteControlStackEntry rcse = stackIterator.next();
4332f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi                pw.println("  pi: " + rcse.mMediaIntent +
4333f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi                        "  -- ercvr: " + rcse.mReceiverComponent +
433417da769e987de40e113c5b2a3b867b25ba7ac0a2Jean-Michel Trivi                        "  -- client: " + rcse.mRcClient +
43353114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                        "  -- uid: " + rcse.mCallingUid +
43363114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                        "  -- type: " + rcse.mPlaybackType +
43373114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                        "  state: " + rcse.mPlaybackState);
43383114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi            }
43393114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        }
43403114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    }
43413114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi
43423114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    /**
43433114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     * Helper function:
43443114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     * Display in the log the current entries in the remote control stack, focusing
43453114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     * on RemoteControlClient data
43463114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     */
43473114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    private void dumpRCCStack(PrintWriter pw) {
43483114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        pw.println("\nRemote Control Client stack entries:");
43493114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        synchronized(mRCStack) {
43503114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi            Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator();
43513114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi            while(stackIterator.hasNext()) {
43523114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                RemoteControlStackEntry rcse = stackIterator.next();
43533114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                pw.println("  uid: " + rcse.mCallingUid +
43543114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                        "  -- id: " + rcse.mRccId +
43553114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                        "  -- type: " + rcse.mPlaybackType +
43563114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                        "  -- state: " + rcse.mPlaybackState +
43573114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                        "  -- vol handling: " + rcse.mPlaybackVolumeHandling +
43583114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                        "  -- vol: " + rcse.mPlaybackVolume +
43591357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi                        "  -- volMax: " + rcse.mPlaybackVolumeMax +
43601357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi                        "  -- volObs: " + rcse.mRemoteVolumeObs);
43611357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi
4362d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi            }
4363d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi        }
43643114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        synchronized (mMainRemote) {
43653114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi            pw.println("\nRemote Volume State:");
43663114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi            pw.println("  has remote: " + mHasRemotePlayback);
43673114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi            pw.println("  is remote active: " + mMainRemoteIsActive);
43683114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi            pw.println("  rccId: " + mMainRemote.mRccId);
43693114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi            pw.println("  volume handling: "
43703114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                    + ((mMainRemote.mVolumeHandling == RemoteControlClient.PLAYBACK_VOLUME_FIXED) ?
43713114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                            "PLAYBACK_VOLUME_FIXED(0)" : "PLAYBACK_VOLUME_VARIABLE(1)"));
43723114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi            pw.println("  volume: " + mMainRemote.mVolume);
43733114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi            pw.println("  volume steps: " + mMainRemote.mVolumeMax);
43743114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        }
4375d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi    }
4376d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi
4377d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi    /**
4378d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi     * Helper function:
4379d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi     * Remove any entry in the remote control stack that has the same package name as packageName
4380d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi     * Pre-condition: packageName != null
4381d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi     */
4382d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi    private void removeMediaButtonReceiverForPackage(String packageName) {
4383d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi        synchronized(mRCStack) {
4384d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi            if (mRCStack.empty()) {
4385d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi                return;
4386d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi            } else {
4387d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi                RemoteControlStackEntry oldTop = mRCStack.peek();
4388d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi                Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator();
4389d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi                // iterate over the stack entries
4390d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi                while(stackIterator.hasNext()) {
4391d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi                    RemoteControlStackEntry rcse = (RemoteControlStackEntry)stackIterator.next();
4392d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi                    if (packageName.equalsIgnoreCase(rcse.mReceiverComponent.getPackageName())) {
4393d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi                        // a stack entry is from the package being removed, remove it from the stack
4394d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi                        stackIterator.remove();
4395a9509736c85c19fe4ad4ba97a0545f0422a3dfc1Jean-Michel Trivi                        rcse.unlinkToRcClientDeath();
4396d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi                    }
4397d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi                }
4398d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi                if (mRCStack.empty()) {
4399d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi                    // no saved media button receiver
4400d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi                    mAudioHandler.sendMessage(
4401d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi                            mAudioHandler.obtainMessage(MSG_PERSIST_MEDIABUTTONRECEIVER, 0, 0,
4402d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi                                    null));
4403d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi                } else if (oldTop != mRCStack.peek()) {
4404d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi                    // the top of the stack has changed, save it in the system settings
4405d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi                    // by posting a message to persist it
4406d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi                    mAudioHandler.sendMessage(
4407d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi                            mAudioHandler.obtainMessage(MSG_PERSIST_MEDIABUTTONRECEIVER, 0, 0,
4408d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi                                    mRCStack.peek().mReceiverComponent));
4409d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi                }
4410d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi            }
4411d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi        }
4412d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi    }
4413d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi
4414d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi    /**
4415d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi     * Helper function:
4416f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi     * Restore remote control receiver from the system settings.
4417d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi     */
4418d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi    private void restoreMediaButtonReceiver() {
4419d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi        String receiverName = Settings.System.getString(mContentResolver,
4420d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi                Settings.System.MEDIA_BUTTON_RECEIVER);
4421d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi        if ((null != receiverName) && !receiverName.isEmpty()) {
4422f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi            ComponentName eventReceiver = ComponentName.unflattenFromString(receiverName);
4423f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi            // construct a PendingIntent targeted to the restored component name
4424f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi            // for the media button and register it
4425f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi            Intent mediaButtonIntent = new Intent(Intent.ACTION_MEDIA_BUTTON);
4426f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi            //     the associated intent will be handled by the component being registered
4427f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi            mediaButtonIntent.setComponent(eventReceiver);
4428f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi            PendingIntent pi = PendingIntent.getBroadcast(mContext,
4429f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi                    0/*requestCode, ignored*/, mediaButtonIntent, 0/*flags*/);
4430f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi            registerMediaButtonIntent(pi, eventReceiver);
4431d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi        }
4432d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi    }
4433d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi
4434d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi    /**
4435d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi     * Helper function:
4436f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi     * Set the new remote control receiver at the top of the RC focus stack.
4437f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi     * precondition: mediaIntent != null, target != null
4438d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi     */
4439f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi    private void pushMediaButtonReceiver(PendingIntent mediaIntent, ComponentName target) {
4440d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi        // already at top of stack?
4441f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi        if (!mRCStack.empty() && mRCStack.peek().mMediaIntent.equals(mediaIntent)) {
4442d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi            return;
4443d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi        }
4444d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi        Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator();
44458f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi        RemoteControlStackEntry rcse = null;
44468f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi        boolean wasInsideStack = false;
4447d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi        while(stackIterator.hasNext()) {
44488f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi            rcse = (RemoteControlStackEntry)stackIterator.next();
4449f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi            if(rcse.mMediaIntent.equals(mediaIntent)) {
44508f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi                wasInsideStack = true;
445172843377d50a8f95cceaf33d316ab68d9b47f2ebJean-Michel Trivi                stackIterator.remove();
4452d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi                break;
4453d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi            }
4454d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi        }
44558f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi        if (!wasInsideStack) {
4456f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi            rcse = new RemoteControlStackEntry(mediaIntent, target);
44578f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi        }
44588f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi        mRCStack.push(rcse);
4459d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi
4460d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi        // post message to persist the default media button receiver
4461d589fea865e90859324f00d21765fa7d7759e465Jean-Michel Trivi        mAudioHandler.sendMessage( mAudioHandler.obtainMessage(
4462f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi                MSG_PERSIST_MEDIABUTTONRECEIVER, 0, 0, target/*obj*/) );
4463d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi    }
4464d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi
4465d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi    /**
4466d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi     * Helper function:
4467f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi     * Remove the remote control receiver from the RC focus stack.
4468f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi     * precondition: pi != null
4469d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi     */
4470f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi    private void removeMediaButtonReceiver(PendingIntent pi) {
4471d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi        Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator();
4472d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi        while(stackIterator.hasNext()) {
4473d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi            RemoteControlStackEntry rcse = (RemoteControlStackEntry)stackIterator.next();
4474f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi            if(rcse.mMediaIntent.equals(pi)) {
447572843377d50a8f95cceaf33d316ab68d9b47f2ebJean-Michel Trivi                stackIterator.remove();
4476a9509736c85c19fe4ad4ba97a0545f0422a3dfc1Jean-Michel Trivi                rcse.unlinkToRcClientDeath();
4477d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi                break;
4478d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi            }
4479d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi        }
4480d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi    }
4481d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi
44828f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi    /**
44838f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi     * Helper function:
44848f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi     * Called synchronized on mRCStack
44858f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi     */
4486f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi    private boolean isCurrentRcController(PendingIntent pi) {
4487f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi        if (!mRCStack.empty() && mRCStack.peek().mMediaIntent.equals(pi)) {
44888f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi            return true;
44898f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi        }
44908f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi        return false;
44918f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi    }
44928f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi
44934426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    //==========================================================================================
44944426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    // Remote control display / client
44954426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    //==========================================================================================
44964426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    /**
44974426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     * Update the remote control displays with the new "focused" client generation
44984426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     */
449918e7bce52318f00b5023f33933a571c477f2b61cJean-Michel Trivi    private void setNewRcClientOnDisplays_syncRcsCurrc(int newClientGeneration,
4500f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi            PendingIntent newMediaIntent, boolean clearing) {
45014426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi        // NOTE: Only one IRemoteControlDisplay supported in this implementation
45024426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi        if (mRcDisplay != null) {
45034426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi            try {
45044b6df6a3dcbd9990e36438c529fa8c16b2580df9Jean-Michel Trivi                mRcDisplay.setCurrentClientId(
4505f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi                        newClientGeneration, newMediaIntent, clearing);
45064426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi            } catch (RemoteException e) {
4507db8a361629f06f62b9e1c40d4413b3b5099bd124Jean-Michel Trivi                Log.e(TAG, "Dead display in setNewRcClientOnDisplays_syncRcsCurrc() "+e);
45084426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi                // if we had a display before, stop monitoring its death
45094426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi                rcDisplay_stopDeathMonitor_syncRcStack();
45104426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi                mRcDisplay = null;
45114426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi            }
45124426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi        }
45134426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    }
45144426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi
45154426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    /**
45164426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     * Update the remote control clients with the new "focused" client generation
45174426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     */
451818e7bce52318f00b5023f33933a571c477f2b61cJean-Michel Trivi    private void setNewRcClientGenerationOnClients_syncRcsCurrc(int newClientGeneration) {
45194426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi        Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator();
45204426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi        while(stackIterator.hasNext()) {
45214426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi            RemoteControlStackEntry se = stackIterator.next();
45224426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi            if ((se != null) && (se.mRcClient != null)) {
45234426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi                try {
45244426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi                    se.mRcClient.setCurrentClientGenerationId(newClientGeneration);
45254426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi                } catch (RemoteException e) {
4526db8a361629f06f62b9e1c40d4413b3b5099bd124Jean-Michel Trivi                    Log.w(TAG, "Dead client in setNewRcClientGenerationOnClients_syncRcsCurrc()"+e);
45274426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi                    stackIterator.remove();
45284426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi                    se.unlinkToRcClientDeath();
45294426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi                }
45304426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi            }
45314426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi        }
45324426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    }
45334426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi
45344426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    /**
45354b6df6a3dcbd9990e36438c529fa8c16b2580df9Jean-Michel Trivi     * Update the displays and clients with the new "focused" client generation and name
45364b6df6a3dcbd9990e36438c529fa8c16b2580df9Jean-Michel Trivi     * @param newClientGeneration the new generation value matching a client update
45374b6df6a3dcbd9990e36438c529fa8c16b2580df9Jean-Michel Trivi     * @param newClientEventReceiver the media button event receiver associated with the client.
45384b6df6a3dcbd9990e36438c529fa8c16b2580df9Jean-Michel Trivi     *    May be null, which implies there is no registered media button event receiver.
45394b6df6a3dcbd9990e36438c529fa8c16b2580df9Jean-Michel Trivi     * @param clearing true if the new client generation value maps to a remote control update
45404b6df6a3dcbd9990e36438c529fa8c16b2580df9Jean-Michel Trivi     *    where the display should be cleared.
45414426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     */
454218e7bce52318f00b5023f33933a571c477f2b61cJean-Michel Trivi    private void setNewRcClient_syncRcsCurrc(int newClientGeneration,
4543f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi            PendingIntent newMediaIntent, boolean clearing) {
45443094d955b8321f01e50cb0c448ae1c4c461f41c9Jean-Michel Trivi        // send the new valid client generation ID to all displays
4545f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi        setNewRcClientOnDisplays_syncRcsCurrc(newClientGeneration, newMediaIntent, clearing);
45463094d955b8321f01e50cb0c448ae1c4c461f41c9Jean-Michel Trivi        // send the new valid client generation ID to all clients
454718e7bce52318f00b5023f33933a571c477f2b61cJean-Michel Trivi        setNewRcClientGenerationOnClients_syncRcsCurrc(newClientGeneration);
45484426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    }
45494426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi
45504426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    /**
45514426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     * Called when processing MSG_RCDISPLAY_CLEAR event
45524426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     */
45534426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    private void onRcDisplayClear() {
455418e7bce52318f00b5023f33933a571c477f2b61cJean-Michel Trivi        if (DEBUG_RC) Log.i(TAG, "Clear remote control display");
45554426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi
45563094d955b8321f01e50cb0c448ae1c4c461f41c9Jean-Michel Trivi        synchronized(mRCStack) {
45573094d955b8321f01e50cb0c448ae1c4c461f41c9Jean-Michel Trivi            synchronized(mCurrentRcLock) {
45583094d955b8321f01e50cb0c448ae1c4c461f41c9Jean-Michel Trivi                mCurrentRcClientGen++;
45593094d955b8321f01e50cb0c448ae1c4c461f41c9Jean-Michel Trivi                // synchronously update the displays and clients with the new client generation
456018e7bce52318f00b5023f33933a571c477f2b61cJean-Michel Trivi                setNewRcClient_syncRcsCurrc(mCurrentRcClientGen,
4561f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi                        null /*newMediaIntent*/, true /*clearing*/);
45623094d955b8321f01e50cb0c448ae1c4c461f41c9Jean-Michel Trivi            }
45634426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi        }
45644426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    }
45654426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi
45664426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    /**
45674426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     * Called when processing MSG_RCDISPLAY_UPDATE event
45684426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     */
45694426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    private void onRcDisplayUpdate(RemoteControlStackEntry rcse, int flags /* USED ?*/) {
45703094d955b8321f01e50cb0c448ae1c4c461f41c9Jean-Michel Trivi        synchronized(mRCStack) {
45713094d955b8321f01e50cb0c448ae1c4c461f41c9Jean-Michel Trivi            synchronized(mCurrentRcLock) {
45723094d955b8321f01e50cb0c448ae1c4c461f41c9Jean-Michel Trivi                if ((mCurrentRcClient != null) && (mCurrentRcClient.equals(rcse.mRcClient))) {
457318e7bce52318f00b5023f33933a571c477f2b61cJean-Michel Trivi                    if (DEBUG_RC) Log.i(TAG, "Display/update remote control ");
45743094d955b8321f01e50cb0c448ae1c4c461f41c9Jean-Michel Trivi
45753094d955b8321f01e50cb0c448ae1c4c461f41c9Jean-Michel Trivi                    mCurrentRcClientGen++;
45763094d955b8321f01e50cb0c448ae1c4c461f41c9Jean-Michel Trivi                    // synchronously update the displays and clients with
45773094d955b8321f01e50cb0c448ae1c4c461f41c9Jean-Michel Trivi                    //      the new client generation
457818e7bce52318f00b5023f33933a571c477f2b61cJean-Michel Trivi                    setNewRcClient_syncRcsCurrc(mCurrentRcClientGen,
4579f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi                            rcse.mMediaIntent /*newMediaIntent*/,
45803094d955b8321f01e50cb0c448ae1c4c461f41c9Jean-Michel Trivi                            false /*clearing*/);
45813094d955b8321f01e50cb0c448ae1c4c461f41c9Jean-Michel Trivi
4582db8a361629f06f62b9e1c40d4413b3b5099bd124Jean-Michel Trivi                    // tell the current client that it needs to send info
45833094d955b8321f01e50cb0c448ae1c4c461f41c9Jean-Michel Trivi                    try {
45843094d955b8321f01e50cb0c448ae1c4c461f41c9Jean-Michel Trivi                        mCurrentRcClient.onInformationRequested(mCurrentRcClientGen,
45853094d955b8321f01e50cb0c448ae1c4c461f41c9Jean-Michel Trivi                                flags, mArtworkExpectedWidth, mArtworkExpectedHeight);
45863094d955b8321f01e50cb0c448ae1c4c461f41c9Jean-Michel Trivi                    } catch (RemoteException e) {
45873094d955b8321f01e50cb0c448ae1c4c461f41c9Jean-Michel Trivi                        Log.e(TAG, "Current valid remote client is dead: "+e);
45883094d955b8321f01e50cb0c448ae1c4c461f41c9Jean-Michel Trivi                        mCurrentRcClient = null;
45893094d955b8321f01e50cb0c448ae1c4c461f41c9Jean-Michel Trivi                    }
45903094d955b8321f01e50cb0c448ae1c4c461f41c9Jean-Michel Trivi                } else {
45913094d955b8321f01e50cb0c448ae1c4c461f41c9Jean-Michel Trivi                    // the remote control display owner has changed between the
45923094d955b8321f01e50cb0c448ae1c4c461f41c9Jean-Michel Trivi                    // the message to update the display was sent, and the time it
45933094d955b8321f01e50cb0c448ae1c4c461f41c9Jean-Michel Trivi                    // gets to be processed (now)
45944426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi                }
45954426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi            }
45964426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi        }
45974426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    }
45984426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi
45994426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi
46008f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi    /**
46018f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi     * Helper function:
46028f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi     * Called synchronized on mRCStack
46038f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi     */
4604b716f0b7b2d8e4b045843fc6a7004910eb344c19Jean-Michel Trivi    private void clearRemoteControlDisplay_syncAfRcs() {
46058f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi        synchronized(mCurrentRcLock) {
460617da769e987de40e113c5b2a3b867b25ba7ac0a2Jean-Michel Trivi            mCurrentRcClient = null;
46078f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi        }
46084426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi        // will cause onRcDisplayClear() to be called in AudioService's handler thread
46098f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi        mAudioHandler.sendMessage( mAudioHandler.obtainMessage(MSG_RCDISPLAY_CLEAR) );
46108f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi    }
46118f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi
46128f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi    /**
4613b716f0b7b2d8e4b045843fc6a7004910eb344c19Jean-Michel Trivi     * Helper function for code readability: only to be called from
4614b716f0b7b2d8e4b045843fc6a7004910eb344c19Jean-Michel Trivi     *    checkUpdateRemoteControlDisplay_syncAfRcs() which checks the preconditions for
4615b716f0b7b2d8e4b045843fc6a7004910eb344c19Jean-Michel Trivi     *    this method.
4616b716f0b7b2d8e4b045843fc6a7004910eb344c19Jean-Michel Trivi     * Preconditions:
4617b716f0b7b2d8e4b045843fc6a7004910eb344c19Jean-Michel Trivi     *    - called synchronized mAudioFocusLock then on mRCStack
4618b716f0b7b2d8e4b045843fc6a7004910eb344c19Jean-Michel Trivi     *    - mRCStack.isEmpty() is false
46198f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi     */
4620b716f0b7b2d8e4b045843fc6a7004910eb344c19Jean-Michel Trivi    private void updateRemoteControlDisplay_syncAfRcs(int infoChangedFlags) {
46218f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi        RemoteControlStackEntry rcse = mRCStack.peek();
4622b5f04d6dbf5106140df367ae07f0e7708e1b650eJean-Michel Trivi        int infoFlagsAboutToBeUsed = infoChangedFlags;
46238f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi        // this is where we enforce opt-in for information display on the remote controls
46248f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi        //   with the new AudioManager.registerRemoteControlClient() API
462517da769e987de40e113c5b2a3b867b25ba7ac0a2Jean-Michel Trivi        if (rcse.mRcClient == null) {
462617da769e987de40e113c5b2a3b867b25ba7ac0a2Jean-Michel Trivi            //Log.w(TAG, "Can't update remote control display with null remote control client");
4627b716f0b7b2d8e4b045843fc6a7004910eb344c19Jean-Michel Trivi            clearRemoteControlDisplay_syncAfRcs();
46288f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi            return;
46298f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi        }
46308f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi        synchronized(mCurrentRcLock) {
463117da769e987de40e113c5b2a3b867b25ba7ac0a2Jean-Michel Trivi            if (!rcse.mRcClient.equals(mCurrentRcClient)) {
46327b6198cacc3e7dd31ef91537d809857d826fb7faJean-Michel Trivi                // new RC client, assume every type of information shall be queried
4633b5f04d6dbf5106140df367ae07f0e7708e1b650eJean-Michel Trivi                infoFlagsAboutToBeUsed = RC_INFO_ALL;
46347b6198cacc3e7dd31ef91537d809857d826fb7faJean-Michel Trivi            }
463517da769e987de40e113c5b2a3b867b25ba7ac0a2Jean-Michel Trivi            mCurrentRcClient = rcse.mRcClient;
46368f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi        }
46374426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi        // will cause onRcDisplayUpdate() to be called in AudioService's handler thread
4638b5f04d6dbf5106140df367ae07f0e7708e1b650eJean-Michel Trivi        mAudioHandler.sendMessage( mAudioHandler.obtainMessage(MSG_RCDISPLAY_UPDATE,
46390a9faa8cf934ef38319cd945b600825c6bb88b9cJean-Michel Trivi                infoFlagsAboutToBeUsed /* arg1 */, 0, rcse /* obj, != null */) );
46408f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi    }
46418f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi
46428f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi    /**
46438f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi     * Helper function:
4644b716f0b7b2d8e4b045843fc6a7004910eb344c19Jean-Michel Trivi     * Called synchronized on mAudioFocusLock, then mRCStack
46458f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi     * Check whether the remote control display should be updated, triggers the update if required
4646b5f04d6dbf5106140df367ae07f0e7708e1b650eJean-Michel Trivi     * @param infoChangedFlags the flags corresponding to the remote control client information
4647b5f04d6dbf5106140df367ae07f0e7708e1b650eJean-Michel Trivi     *     that has changed, if applicable (checking for the update conditions might trigger a
4648b5f04d6dbf5106140df367ae07f0e7708e1b650eJean-Michel Trivi     *     clear, rather than an update event).
46498f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi     */
4650b716f0b7b2d8e4b045843fc6a7004910eb344c19Jean-Michel Trivi    private void checkUpdateRemoteControlDisplay_syncAfRcs(int infoChangedFlags) {
46518f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi        // determine whether the remote control display should be refreshed
46528f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi        // if either stack is empty, there is a mismatch, so clear the RC display
46538f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi        if (mRCStack.isEmpty() || mFocusStack.isEmpty()) {
4654b716f0b7b2d8e4b045843fc6a7004910eb344c19Jean-Michel Trivi            clearRemoteControlDisplay_syncAfRcs();
46558f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi            return;
46568f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi        }
46578f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi        // if the top of the two stacks belong to different packages, there is a mismatch, clear
46588f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi        if ((mRCStack.peek().mCallingPackageName != null)
46598f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi                && (mFocusStack.peek().mPackageName != null)
46608f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi                && !(mRCStack.peek().mCallingPackageName.compareTo(
46618f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi                        mFocusStack.peek().mPackageName) == 0)) {
4662b716f0b7b2d8e4b045843fc6a7004910eb344c19Jean-Michel Trivi            clearRemoteControlDisplay_syncAfRcs();
46638f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi            return;
46648f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi        }
46658f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi        // if the audio focus didn't originate from the same Uid as the one in which the remote
46668f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi        //   control information will be retrieved, clear
46678f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi        if (mRCStack.peek().mCallingUid != mFocusStack.peek().mCallingUid) {
4668b716f0b7b2d8e4b045843fc6a7004910eb344c19Jean-Michel Trivi            clearRemoteControlDisplay_syncAfRcs();
46698f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi            return;
46708f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi        }
46718f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi        // refresh conditions were verified: update the remote controls
4672b716f0b7b2d8e4b045843fc6a7004910eb344c19Jean-Michel Trivi        // ok to call: synchronized mAudioFocusLock then on mRCStack, mRCStack is not empty
4673b716f0b7b2d8e4b045843fc6a7004910eb344c19Jean-Michel Trivi        updateRemoteControlDisplay_syncAfRcs(infoChangedFlags);
46748f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi    }
4675d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi
46766bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent    /**
4677f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi     * see AudioManager.registerMediaButtonIntent(PendingIntent pi, ComponentName c)
4678f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi     * precondition: mediaIntent != null, target != null
4679f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi     */
4680f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi    public void registerMediaButtonIntent(PendingIntent mediaIntent, ComponentName eventReceiver) {
4681f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi        Log.i(TAG, "  Remote Control   registerMediaButtonIntent() for " + mediaIntent);
4682d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi
46838f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi        synchronized(mAudioFocusLock) {
46848f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi            synchronized(mRCStack) {
4685f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi                pushMediaButtonReceiver(mediaIntent, eventReceiver);
4686b5f04d6dbf5106140df367ae07f0e7708e1b650eJean-Michel Trivi                // new RC client, assume every type of information shall be queried
4687b716f0b7b2d8e4b045843fc6a7004910eb344c19Jean-Michel Trivi                checkUpdateRemoteControlDisplay_syncAfRcs(RC_INFO_ALL);
46888f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi            }
4689d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi        }
4690d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi    }
4691d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi
46926bc7f2cd30b6bd90806942b0722e22daa2108493Eric Laurent    /**
4693f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi     * see AudioManager.unregisterMediaButtonIntent(PendingIntent mediaIntent)
4694f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi     * precondition: mediaIntent != null, eventReceiver != null
4695f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi     */
4696f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi    public void unregisterMediaButtonIntent(PendingIntent mediaIntent, ComponentName eventReceiver)
4697f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi    {
4698f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi        Log.i(TAG, "  Remote Control   unregisterMediaButtonIntent() for " + mediaIntent);
4699d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi
47008f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi        synchronized(mAudioFocusLock) {
47018f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi            synchronized(mRCStack) {
4702f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi                boolean topOfStackWillChange = isCurrentRcController(mediaIntent);
4703f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi                removeMediaButtonReceiver(mediaIntent);
47048f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi                if (topOfStackWillChange) {
4705b5f04d6dbf5106140df367ae07f0e7708e1b650eJean-Michel Trivi                    // current RC client will change, assume every type of info needs to be queried
4706b716f0b7b2d8e4b045843fc6a7004910eb344c19Jean-Michel Trivi                    checkUpdateRemoteControlDisplay_syncAfRcs(RC_INFO_ALL);
47078f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi                }
47088f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi            }
4709d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi        }
4710d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi    }
4711d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi
471226b3d1ff38998c7cb80a2950da0589ebd8510897Jean-Michel Trivi    /**
4713722b808662eb20fa91151f1e3aa05fd911d1d226Jean-Michel Trivi     * see AudioManager.registerMediaButtonEventReceiverForCalls(ComponentName c)
4714722b808662eb20fa91151f1e3aa05fd911d1d226Jean-Michel Trivi     * precondition: c != null
4715722b808662eb20fa91151f1e3aa05fd911d1d226Jean-Michel Trivi     */
4716722b808662eb20fa91151f1e3aa05fd911d1d226Jean-Michel Trivi    public void registerMediaButtonEventReceiverForCalls(ComponentName c) {
4717722b808662eb20fa91151f1e3aa05fd911d1d226Jean-Michel Trivi        if (mContext.checkCallingPermission("android.permission.MODIFY_PHONE_STATE")
4718722b808662eb20fa91151f1e3aa05fd911d1d226Jean-Michel Trivi                != PackageManager.PERMISSION_GRANTED) {
4719722b808662eb20fa91151f1e3aa05fd911d1d226Jean-Michel Trivi            Log.e(TAG, "Invalid permissions to register media button receiver for calls");
4720722b808662eb20fa91151f1e3aa05fd911d1d226Jean-Michel Trivi            return;
4721722b808662eb20fa91151f1e3aa05fd911d1d226Jean-Michel Trivi        }
4722722b808662eb20fa91151f1e3aa05fd911d1d226Jean-Michel Trivi        synchronized(mRCStack) {
4723722b808662eb20fa91151f1e3aa05fd911d1d226Jean-Michel Trivi            mMediaReceiverForCalls = c;
4724722b808662eb20fa91151f1e3aa05fd911d1d226Jean-Michel Trivi        }
4725722b808662eb20fa91151f1e3aa05fd911d1d226Jean-Michel Trivi    }
4726722b808662eb20fa91151f1e3aa05fd911d1d226Jean-Michel Trivi
4727722b808662eb20fa91151f1e3aa05fd911d1d226Jean-Michel Trivi    /**
4728722b808662eb20fa91151f1e3aa05fd911d1d226Jean-Michel Trivi     * see AudioManager.unregisterMediaButtonEventReceiverForCalls()
4729722b808662eb20fa91151f1e3aa05fd911d1d226Jean-Michel Trivi     */
4730722b808662eb20fa91151f1e3aa05fd911d1d226Jean-Michel Trivi    public void unregisterMediaButtonEventReceiverForCalls() {
4731722b808662eb20fa91151f1e3aa05fd911d1d226Jean-Michel Trivi        if (mContext.checkCallingPermission("android.permission.MODIFY_PHONE_STATE")
4732722b808662eb20fa91151f1e3aa05fd911d1d226Jean-Michel Trivi                != PackageManager.PERMISSION_GRANTED) {
4733722b808662eb20fa91151f1e3aa05fd911d1d226Jean-Michel Trivi            Log.e(TAG, "Invalid permissions to unregister media button receiver for calls");
4734722b808662eb20fa91151f1e3aa05fd911d1d226Jean-Michel Trivi            return;
4735722b808662eb20fa91151f1e3aa05fd911d1d226Jean-Michel Trivi        }
4736722b808662eb20fa91151f1e3aa05fd911d1d226Jean-Michel Trivi        synchronized(mRCStack) {
4737722b808662eb20fa91151f1e3aa05fd911d1d226Jean-Michel Trivi            mMediaReceiverForCalls = null;
4738722b808662eb20fa91151f1e3aa05fd911d1d226Jean-Michel Trivi        }
4739722b808662eb20fa91151f1e3aa05fd911d1d226Jean-Michel Trivi    }
4740722b808662eb20fa91151f1e3aa05fd911d1d226Jean-Michel Trivi
4741722b808662eb20fa91151f1e3aa05fd911d1d226Jean-Michel Trivi    /**
474226b3d1ff38998c7cb80a2950da0589ebd8510897Jean-Michel Trivi     * see AudioManager.registerRemoteControlClient(ComponentName eventReceiver, ...)
47433114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     * @return the unique ID of the RemoteControlStackEntry associated with the RemoteControlClient
474426b3d1ff38998c7cb80a2950da0589ebd8510897Jean-Michel Trivi     * Note: using this method with rcClient == null is a way to "disable" the IRemoteControlClient
474526b3d1ff38998c7cb80a2950da0589ebd8510897Jean-Michel Trivi     *     without modifying the RC stack, but while still causing the display to refresh (will
474626b3d1ff38998c7cb80a2950da0589ebd8510897Jean-Michel Trivi     *     become blank as a result of this)
474726b3d1ff38998c7cb80a2950da0589ebd8510897Jean-Michel Trivi     */
47483114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    public int registerRemoteControlClient(PendingIntent mediaIntent,
4749f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi            IRemoteControlClient rcClient, String callingPackageName) {
4750b716f0b7b2d8e4b045843fc6a7004910eb344c19Jean-Michel Trivi        if (DEBUG_RC) Log.i(TAG, "Register remote control client rcClient="+rcClient);
47513114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        int rccId = RemoteControlClient.RCSE_ID_UNREGISTERED;
47528f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi        synchronized(mAudioFocusLock) {
47538f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi            synchronized(mRCStack) {
47548f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi                // store the new display information
47558f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi                Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator();
47568f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi                while(stackIterator.hasNext()) {
47578f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi                    RemoteControlStackEntry rcse = stackIterator.next();
4758f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi                    if(rcse.mMediaIntent.equals(mediaIntent)) {
47598f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi                        // already had a remote control client?
47608f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi                        if (rcse.mRcClientDeathHandler != null) {
47618f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi                            // stop monitoring the old client's death
47628f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi                            rcse.unlinkToRcClientDeath();
47638f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi                        }
47648f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi                        // save the new remote control client
476517da769e987de40e113c5b2a3b867b25ba7ac0a2Jean-Michel Trivi                        rcse.mRcClient = rcClient;
476626b3d1ff38998c7cb80a2950da0589ebd8510897Jean-Michel Trivi                        rcse.mCallingPackageName = callingPackageName;
476726b3d1ff38998c7cb80a2950da0589ebd8510897Jean-Michel Trivi                        rcse.mCallingUid = Binder.getCallingUid();
476826b3d1ff38998c7cb80a2950da0589ebd8510897Jean-Michel Trivi                        if (rcClient == null) {
4769a9509736c85c19fe4ad4ba97a0545f0422a3dfc1Jean-Michel Trivi                            // here rcse.mRcClientDeathHandler is null;
47703114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                            rcse.resetPlaybackInfo();
477126b3d1ff38998c7cb80a2950da0589ebd8510897Jean-Michel Trivi                            break;
477226b3d1ff38998c7cb80a2950da0589ebd8510897Jean-Michel Trivi                        }
47733114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                        rccId = rcse.mRccId;
477426b3d1ff38998c7cb80a2950da0589ebd8510897Jean-Michel Trivi
477526b3d1ff38998c7cb80a2950da0589ebd8510897Jean-Michel Trivi                        // there is a new (non-null) client:
477626b3d1ff38998c7cb80a2950da0589ebd8510897Jean-Michel Trivi                        // 1/ give the new client the current display (if any)
47774426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi                        if (mRcDisplay != null) {
47784426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi                            try {
47794426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi                                rcse.mRcClient.plugRemoteControlDisplay(mRcDisplay);
47804426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi                            } catch (RemoteException e) {
47814426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi                                Log.e(TAG, "Error connecting remote control display to client: "+e);
47824426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi                                e.printStackTrace();
47834426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi                            }
47844426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi                        }
478526b3d1ff38998c7cb80a2950da0589ebd8510897Jean-Michel Trivi                        // 2/ monitor the new client's death
478626b3d1ff38998c7cb80a2950da0589ebd8510897Jean-Michel Trivi                        IBinder b = rcse.mRcClient.asBinder();
47878f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi                        RcClientDeathHandler rcdh =
4788f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi                                new RcClientDeathHandler(b, rcse.mMediaIntent);
47898f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi                        try {
47908f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi                            b.linkToDeath(rcdh, 0);
47918f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi                        } catch (RemoteException e) {
47928f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi                            // remote control client is DOA, disqualify it
47938f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi                            Log.w(TAG, "registerRemoteControlClient() has a dead client " + b);
479417da769e987de40e113c5b2a3b867b25ba7ac0a2Jean-Michel Trivi                            rcse.mRcClient = null;
47958f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi                        }
47968f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi                        rcse.mRcClientDeathHandler = rcdh;
47978f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi                        break;
47988f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi                    }
47998f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi                }
48008f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi                // if the eventReceiver is at the top of the stack
48018f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi                // then check for potential refresh of the remote controls
4802f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi                if (isCurrentRcController(mediaIntent)) {
4803b716f0b7b2d8e4b045843fc6a7004910eb344c19Jean-Michel Trivi                    checkUpdateRemoteControlDisplay_syncAfRcs(RC_INFO_ALL);
48048f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi                }
48058f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi            }
48068f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi        }
48073114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        return rccId;
48088f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi    }
48098f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi
48104b6df6a3dcbd9990e36438c529fa8c16b2580df9Jean-Michel Trivi    /**
4811f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi     * see AudioManager.unregisterRemoteControlClient(PendingIntent pi, ...)
48124b6df6a3dcbd9990e36438c529fa8c16b2580df9Jean-Michel Trivi     * rcClient is guaranteed non-null
48134b6df6a3dcbd9990e36438c529fa8c16b2580df9Jean-Michel Trivi     */
4814f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi    public void unregisterRemoteControlClient(PendingIntent mediaIntent,
48154426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi            IRemoteControlClient rcClient) {
48164b6df6a3dcbd9990e36438c529fa8c16b2580df9Jean-Michel Trivi        synchronized(mAudioFocusLock) {
48174b6df6a3dcbd9990e36438c529fa8c16b2580df9Jean-Michel Trivi            synchronized(mRCStack) {
48184b6df6a3dcbd9990e36438c529fa8c16b2580df9Jean-Michel Trivi                Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator();
48194b6df6a3dcbd9990e36438c529fa8c16b2580df9Jean-Michel Trivi                while(stackIterator.hasNext()) {
48204b6df6a3dcbd9990e36438c529fa8c16b2580df9Jean-Michel Trivi                    RemoteControlStackEntry rcse = stackIterator.next();
4821f0cff0456258478ba768097f73d4367ab67fd7a3Jean-Michel Trivi                    if ((rcse.mMediaIntent.equals(mediaIntent))
48224b6df6a3dcbd9990e36438c529fa8c16b2580df9Jean-Michel Trivi                            && rcClient.equals(rcse.mRcClient)) {
48234b6df6a3dcbd9990e36438c529fa8c16b2580df9Jean-Michel Trivi                        // we found the IRemoteControlClient to unregister
48244b6df6a3dcbd9990e36438c529fa8c16b2580df9Jean-Michel Trivi                        // stop monitoring its death
48254b6df6a3dcbd9990e36438c529fa8c16b2580df9Jean-Michel Trivi                        rcse.unlinkToRcClientDeath();
48264b6df6a3dcbd9990e36438c529fa8c16b2580df9Jean-Michel Trivi                        // reset the client-related fields
48274b6df6a3dcbd9990e36438c529fa8c16b2580df9Jean-Michel Trivi                        rcse.mRcClient = null;
48284b6df6a3dcbd9990e36438c529fa8c16b2580df9Jean-Michel Trivi                        rcse.mCallingPackageName = null;
48294b6df6a3dcbd9990e36438c529fa8c16b2580df9Jean-Michel Trivi                    }
48304b6df6a3dcbd9990e36438c529fa8c16b2580df9Jean-Michel Trivi                }
48314b6df6a3dcbd9990e36438c529fa8c16b2580df9Jean-Michel Trivi            }
48324b6df6a3dcbd9990e36438c529fa8c16b2580df9Jean-Michel Trivi        }
48334426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    }
48344426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi
48354426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    /**
48364426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     * The remote control displays.
48374426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     * Access synchronized on mRCStack
48384426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     * NOTE: Only one IRemoteControlDisplay supported in this implementation
48394426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     */
48404426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    private IRemoteControlDisplay mRcDisplay;
48414426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    private RcDisplayDeathHandler mRcDisplayDeathHandler;
48424426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    private int mArtworkExpectedWidth = -1;
48434426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    private int mArtworkExpectedHeight = -1;
48444426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    /**
48454426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     * Inner class to monitor remote control display deaths, and unregister them from the list
48464426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     * of displays if necessary.
48474426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi     */
48484426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    private class RcDisplayDeathHandler implements IBinder.DeathRecipient {
484918e7bce52318f00b5023f33933a571c477f2b61cJean-Michel Trivi        private IBinder mCb; // To be notified of client's death
485018e7bce52318f00b5023f33933a571c477f2b61cJean-Michel Trivi
485118e7bce52318f00b5023f33933a571c477f2b61cJean-Michel Trivi        public RcDisplayDeathHandler(IBinder b) {
485218e7bce52318f00b5023f33933a571c477f2b61cJean-Michel Trivi            if (DEBUG_RC) Log.i(TAG, "new RcDisplayDeathHandler for "+b);
485318e7bce52318f00b5023f33933a571c477f2b61cJean-Michel Trivi            mCb = b;
485418e7bce52318f00b5023f33933a571c477f2b61cJean-Michel Trivi        }
485518e7bce52318f00b5023f33933a571c477f2b61cJean-Michel Trivi
48564426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi        public void binderDied() {
48578f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi            synchronized(mRCStack) {
485818e7bce52318f00b5023f33933a571c477f2b61cJean-Michel Trivi                Log.w(TAG, "RemoteControl: display died");
48594426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi                mRcDisplay = null;
48604426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi            }
48614426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi        }
48624426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi
486318e7bce52318f00b5023f33933a571c477f2b61cJean-Michel Trivi        public void unlinkToRcDisplayDeath() {
486418e7bce52318f00b5023f33933a571c477f2b61cJean-Michel Trivi            if (DEBUG_RC) Log.i(TAG, "unlinkToRcDisplayDeath for "+mCb);
48654426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi            try {
486618e7bce52318f00b5023f33933a571c477f2b61cJean-Michel Trivi                mCb.unlinkToDeath(this, 0);
48674426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi            } catch (java.util.NoSuchElementException e) {
486818e7bce52318f00b5023f33933a571c477f2b61cJean-Michel Trivi                // not much we can do here, the display was being unregistered anyway
486918e7bce52318f00b5023f33933a571c477f2b61cJean-Michel Trivi                Log.e(TAG, "Encountered " + e + " in unlinkToRcDisplayDeath()");
48704426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi                e.printStackTrace();
48714426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi            }
48724426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi        }
487318e7bce52318f00b5023f33933a571c477f2b61cJean-Michel Trivi
487418e7bce52318f00b5023f33933a571c477f2b61cJean-Michel Trivi    }
487518e7bce52318f00b5023f33933a571c477f2b61cJean-Michel Trivi
487618e7bce52318f00b5023f33933a571c477f2b61cJean-Michel Trivi    private void rcDisplay_stopDeathMonitor_syncRcStack() {
487718e7bce52318f00b5023f33933a571c477f2b61cJean-Michel Trivi        if (mRcDisplay != null) { // implies (mRcDisplayDeathHandler != null)
487818e7bce52318f00b5023f33933a571c477f2b61cJean-Michel Trivi            // we had a display before, stop monitoring its death
487918e7bce52318f00b5023f33933a571c477f2b61cJean-Michel Trivi            mRcDisplayDeathHandler.unlinkToRcDisplayDeath();
488018e7bce52318f00b5023f33933a571c477f2b61cJean-Michel Trivi        }
48814426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    }
48824426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi
48834426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    private void rcDisplay_startDeathMonitor_syncRcStack() {
48844426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi        if (mRcDisplay != null) {
48854426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi            // new non-null display, monitor its death
48864426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi            IBinder b = mRcDisplay.asBinder();
488718e7bce52318f00b5023f33933a571c477f2b61cJean-Michel Trivi            mRcDisplayDeathHandler = new RcDisplayDeathHandler(b);
48884426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi            try {
48894426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi                b.linkToDeath(mRcDisplayDeathHandler, 0);
48904426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi            } catch (RemoteException e) {
48914426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi                // remote control display is DOA, disqualify it
48924426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi                Log.w(TAG, "registerRemoteControlDisplay() has a dead client " + b);
48934426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi                mRcDisplay = null;
48944426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi            }
48954426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi        }
48964426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    }
48974426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi
489818e7bce52318f00b5023f33933a571c477f2b61cJean-Michel Trivi    /**
4899958bba6862c9540c528263686b0de044b4a7a5f6Jean-Michel Trivi     * Register an IRemoteControlDisplay.
4900958bba6862c9540c528263686b0de044b4a7a5f6Jean-Michel Trivi     * Notify all IRemoteControlClient of the new display and cause the RemoteControlClient
4901958bba6862c9540c528263686b0de044b4a7a5f6Jean-Michel Trivi     * at the top of the stack to update the new display with its information.
490218e7bce52318f00b5023f33933a571c477f2b61cJean-Michel Trivi     * Since only one IRemoteControlDisplay is supported, this will unregister the previous display.
490318e7bce52318f00b5023f33933a571c477f2b61cJean-Michel Trivi     * @param rcd the IRemoteControlDisplay to register. No effect if null.
490418e7bce52318f00b5023f33933a571c477f2b61cJean-Michel Trivi     */
49054426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    public void registerRemoteControlDisplay(IRemoteControlDisplay rcd) {
490618e7bce52318f00b5023f33933a571c477f2b61cJean-Michel Trivi        if (DEBUG_RC) Log.d(TAG, ">>> registerRemoteControlDisplay("+rcd+")");
4907b716f0b7b2d8e4b045843fc6a7004910eb344c19Jean-Michel Trivi        synchronized(mAudioFocusLock) {
4908b716f0b7b2d8e4b045843fc6a7004910eb344c19Jean-Michel Trivi            synchronized(mRCStack) {
4909b716f0b7b2d8e4b045843fc6a7004910eb344c19Jean-Michel Trivi                if ((mRcDisplay == rcd) || (rcd == null)) {
4910b716f0b7b2d8e4b045843fc6a7004910eb344c19Jean-Michel Trivi                    return;
4911b716f0b7b2d8e4b045843fc6a7004910eb344c19Jean-Michel Trivi                }
4912b716f0b7b2d8e4b045843fc6a7004910eb344c19Jean-Michel Trivi                // if we had a display before, stop monitoring its death
4913b716f0b7b2d8e4b045843fc6a7004910eb344c19Jean-Michel Trivi                rcDisplay_stopDeathMonitor_syncRcStack();
4914b716f0b7b2d8e4b045843fc6a7004910eb344c19Jean-Michel Trivi                mRcDisplay = rcd;
4915b716f0b7b2d8e4b045843fc6a7004910eb344c19Jean-Michel Trivi                // new display, start monitoring its death
4916b716f0b7b2d8e4b045843fc6a7004910eb344c19Jean-Michel Trivi                rcDisplay_startDeathMonitor_syncRcStack();
49174426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi
4918b716f0b7b2d8e4b045843fc6a7004910eb344c19Jean-Michel Trivi                // let all the remote control clients there is a new display
4919b716f0b7b2d8e4b045843fc6a7004910eb344c19Jean-Michel Trivi                // no need to unplug the previous because we only support one display
4920b716f0b7b2d8e4b045843fc6a7004910eb344c19Jean-Michel Trivi                // and the clients don't track the death of the display
4921b716f0b7b2d8e4b045843fc6a7004910eb344c19Jean-Michel Trivi                Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator();
4922b716f0b7b2d8e4b045843fc6a7004910eb344c19Jean-Michel Trivi                while(stackIterator.hasNext()) {
4923b716f0b7b2d8e4b045843fc6a7004910eb344c19Jean-Michel Trivi                    RemoteControlStackEntry rcse = stackIterator.next();
4924b716f0b7b2d8e4b045843fc6a7004910eb344c19Jean-Michel Trivi                    if(rcse.mRcClient != null) {
4925b716f0b7b2d8e4b045843fc6a7004910eb344c19Jean-Michel Trivi                        try {
4926b716f0b7b2d8e4b045843fc6a7004910eb344c19Jean-Michel Trivi                            rcse.mRcClient.plugRemoteControlDisplay(mRcDisplay);
4927b716f0b7b2d8e4b045843fc6a7004910eb344c19Jean-Michel Trivi                        } catch (RemoteException e) {
4928b716f0b7b2d8e4b045843fc6a7004910eb344c19Jean-Michel Trivi                            Log.e(TAG, "Error connecting remote control display to client: " + e);
4929b716f0b7b2d8e4b045843fc6a7004910eb344c19Jean-Michel Trivi                            e.printStackTrace();
4930b716f0b7b2d8e4b045843fc6a7004910eb344c19Jean-Michel Trivi                        }
49314426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi                    }
49328f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi                }
4933db8a361629f06f62b9e1c40d4413b3b5099bd124Jean-Michel Trivi
4934338794576667745b060ac269b2c2b36e0c6964f2Jean-Michel Trivi                // we have a new display, of which all the clients are now aware: have it be updated
4935b716f0b7b2d8e4b045843fc6a7004910eb344c19Jean-Michel Trivi                checkUpdateRemoteControlDisplay_syncAfRcs(RC_INFO_ALL);
4936338794576667745b060ac269b2c2b36e0c6964f2Jean-Michel Trivi            }
49378f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi        }
49388f619182cb759718f64ab95fd6d61c16138f6952Jean-Michel Trivi    }
4939d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi
494018e7bce52318f00b5023f33933a571c477f2b61cJean-Michel Trivi    /**
494118e7bce52318f00b5023f33933a571c477f2b61cJean-Michel Trivi     * Unregister an IRemoteControlDisplay.
494218e7bce52318f00b5023f33933a571c477f2b61cJean-Michel Trivi     * Since only one IRemoteControlDisplay is supported, this has no effect if the one to
494318e7bce52318f00b5023f33933a571c477f2b61cJean-Michel Trivi     *    unregister is not the current one.
494418e7bce52318f00b5023f33933a571c477f2b61cJean-Michel Trivi     * @param rcd the IRemoteControlDisplay to unregister. No effect if null.
494518e7bce52318f00b5023f33933a571c477f2b61cJean-Michel Trivi     */
49464426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    public void unregisterRemoteControlDisplay(IRemoteControlDisplay rcd) {
494718e7bce52318f00b5023f33933a571c477f2b61cJean-Michel Trivi        if (DEBUG_RC) Log.d(TAG, "<<< unregisterRemoteControlDisplay("+rcd+")");
49484426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi        synchronized(mRCStack) {
494918e7bce52318f00b5023f33933a571c477f2b61cJean-Michel Trivi            // only one display here, so you can only unregister the current display
495018e7bce52318f00b5023f33933a571c477f2b61cJean-Michel Trivi            if ((rcd == null) || (rcd != mRcDisplay)) {
495118e7bce52318f00b5023f33933a571c477f2b61cJean-Michel Trivi                if (DEBUG_RC) Log.w(TAG, "    trying to unregister unregistered RCD");
495218e7bce52318f00b5023f33933a571c477f2b61cJean-Michel Trivi                return;
495318e7bce52318f00b5023f33933a571c477f2b61cJean-Michel Trivi            }
49544426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi            // if we had a display before, stop monitoring its death
49554426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi            rcDisplay_stopDeathMonitor_syncRcStack();
49564426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi            mRcDisplay = null;
49574426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi
49584426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi            // disconnect this remote control display from all the clients
49594426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi            Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator();
49604426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi            while(stackIterator.hasNext()) {
49614426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi                RemoteControlStackEntry rcse = stackIterator.next();
49624426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi                if(rcse.mRcClient != null) {
49634426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi                    try {
49644426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi                        rcse.mRcClient.unplugRemoteControlDisplay(rcd);
49654426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi                    } catch (RemoteException e) {
49664426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi                        Log.e(TAG, "Error disconnecting remote control display to client: " + e);
49674426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi                        e.printStackTrace();
49684426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi                    }
49694426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi                }
49704426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi            }
49714426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi        }
49724426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    }
49734426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi
49744426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    public void remoteControlDisplayUsesBitmapSize(IRemoteControlDisplay rcd, int w, int h) {
49754426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi        synchronized(mRCStack) {
49764426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi            // NOTE: Only one IRemoteControlDisplay supported in this implementation
49774426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi            mArtworkExpectedWidth = w;
49784426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi            mArtworkExpectedHeight = h;
49794426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi        }
49804426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi    }
49814426e42ac6107bf6b09f7c4cdad39eb161d8b9caJean-Michel Trivi
49823114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    public void setPlaybackInfoForRcc(int rccId, int what, int value) {
4983f98de1e8dd6dcbd191921b4aa07a1d41b0b9db91Jean-Michel Trivi        sendMsg(mAudioHandler, MSG_RCC_NEW_PLAYBACK_INFO, SENDMSG_QUEUE,
4984f98de1e8dd6dcbd191921b4aa07a1d41b0b9db91Jean-Michel Trivi                rccId /* arg1 */, what /* arg2 */, Integer.valueOf(value) /* obj */, 0 /* delay */);
4985f98de1e8dd6dcbd191921b4aa07a1d41b0b9db91Jean-Michel Trivi    }
4986f98de1e8dd6dcbd191921b4aa07a1d41b0b9db91Jean-Michel Trivi
4987f98de1e8dd6dcbd191921b4aa07a1d41b0b9db91Jean-Michel Trivi    // handler for MSG_RCC_NEW_PLAYBACK_INFO
4988f98de1e8dd6dcbd191921b4aa07a1d41b0b9db91Jean-Michel Trivi    private void onNewPlaybackInfoForRcc(int rccId, int key, int value) {
4989f98de1e8dd6dcbd191921b4aa07a1d41b0b9db91Jean-Michel Trivi        if(DEBUG_RC) Log.d(TAG, "onNewPlaybackInfoForRcc(id=" + rccId +
4990f98de1e8dd6dcbd191921b4aa07a1d41b0b9db91Jean-Michel Trivi                ", what=" + key + ",val=" + value + ")");
49913114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        synchronized(mRCStack) {
49923114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi            Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator();
49933114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi            while(stackIterator.hasNext()) {
49943114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                RemoteControlStackEntry rcse = stackIterator.next();
49953114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                if (rcse.mRccId == rccId) {
4996f98de1e8dd6dcbd191921b4aa07a1d41b0b9db91Jean-Michel Trivi                    switch (key) {
49973114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                        case RemoteControlClient.PLAYBACKINFO_PLAYBACK_TYPE:
49983114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                            rcse.mPlaybackType = value;
49993114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                            postReevaluateRemote();
50003114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                            break;
50013114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                        case RemoteControlClient.PLAYBACKINFO_VOLUME:
50023114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                            rcse.mPlaybackVolume = value;
50033114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                            synchronized (mMainRemote) {
50043114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                                if (rccId == mMainRemote.mRccId) {
50053114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                                    mMainRemote.mVolume = value;
50063114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                                    mVolumePanel.postHasNewRemotePlaybackInfo();
50073114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                                }
50083114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                            }
50093114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                            break;
50103114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                        case RemoteControlClient.PLAYBACKINFO_VOLUME_MAX:
50113114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                            rcse.mPlaybackVolumeMax = value;
50123114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                            synchronized (mMainRemote) {
50133114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                                if (rccId == mMainRemote.mRccId) {
50143114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                                    mMainRemote.mVolumeMax = value;
50153114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                                    mVolumePanel.postHasNewRemotePlaybackInfo();
50163114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                                }
50173114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                            }
50183114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                            break;
50193114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                        case RemoteControlClient.PLAYBACKINFO_VOLUME_HANDLING:
50203114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                            rcse.mPlaybackVolumeHandling = value;
50213114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                            synchronized (mMainRemote) {
50223114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                                if (rccId == mMainRemote.mRccId) {
50233114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                                    mMainRemote.mVolumeHandling = value;
50243114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                                    mVolumePanel.postHasNewRemotePlaybackInfo();
50253114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                                }
50263114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                            }
50273114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                            break;
50283114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                        case RemoteControlClient.PLAYBACKINFO_USES_STREAM:
50293114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                            rcse.mPlaybackStream = value;
50303114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                            break;
50313114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                        case RemoteControlClient.PLAYBACKINFO_PLAYSTATE:
50323114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                            rcse.mPlaybackState = value;
50333114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                            synchronized (mMainRemote) {
50343114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                                if (rccId == mMainRemote.mRccId) {
50353114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                                    mMainRemoteIsActive = isPlaystateActive(value);
50363114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                                    postReevaluateRemote();
50373114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                                }
50383114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                            }
50393114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                            break;
50403114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                        default:
5041f98de1e8dd6dcbd191921b4aa07a1d41b0b9db91Jean-Michel Trivi                            Log.e(TAG, "unhandled key " + key + " for RCC " + rccId);
50423114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                            break;
50433114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                    }
50443114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                    return;
50453114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                }
50463114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi            }
50473114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        }
50483114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    }
50493114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi
50501357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi    public void registerRemoteVolumeObserverForRcc(int rccId, IRemoteVolumeObserver rvo) {
5051f98de1e8dd6dcbd191921b4aa07a1d41b0b9db91Jean-Michel Trivi        sendMsg(mAudioHandler, MSG_RCC_NEW_VOLUME_OBS, SENDMSG_QUEUE,
5052f98de1e8dd6dcbd191921b4aa07a1d41b0b9db91Jean-Michel Trivi                rccId /* arg1 */, 0, rvo /* obj */, 0 /* delay */);
5053f98de1e8dd6dcbd191921b4aa07a1d41b0b9db91Jean-Michel Trivi    }
5054f98de1e8dd6dcbd191921b4aa07a1d41b0b9db91Jean-Michel Trivi
5055f98de1e8dd6dcbd191921b4aa07a1d41b0b9db91Jean-Michel Trivi    // handler for MSG_RCC_NEW_VOLUME_OBS
5056f98de1e8dd6dcbd191921b4aa07a1d41b0b9db91Jean-Michel Trivi    private void onRegisterVolumeObserverForRcc(int rccId, IRemoteVolumeObserver rvo) {
50571357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi        synchronized(mRCStack) {
50581357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi            Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator();
50591357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi            while(stackIterator.hasNext()) {
50601357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi                RemoteControlStackEntry rcse = stackIterator.next();
50611357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi                if (rcse.mRccId == rccId) {
50621357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi                    rcse.mRemoteVolumeObs = rvo;
50631357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi                    break;
50641357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi                }
50651357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi            }
50661357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi        }
50671357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi    }
50681357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi
50693114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    /**
50703114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     * Checks if a remote client is active on the supplied stream type. Update the remote stream
50713114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     * volume state if found and playing
50723114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     * @param streamType
50733114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     * @return false if no remote playing is currently playing
50743114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     */
50753114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    private boolean checkUpdateRemoteStateIfActive(int streamType) {
50763114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        synchronized(mRCStack) {
50773114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi            Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator();
50783114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi            while(stackIterator.hasNext()) {
50793114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                RemoteControlStackEntry rcse = stackIterator.next();
50803114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                if ((rcse.mPlaybackType == RemoteControlClient.PLAYBACK_TYPE_REMOTE)
50813114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                        && isPlaystateActive(rcse.mPlaybackState)
50823114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                        && (rcse.mPlaybackStream == streamType)) {
50833114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                    if (DEBUG_RC) Log.d(TAG, "remote playback active on stream " + streamType
50843114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                            + ", vol =" + rcse.mPlaybackVolume);
50853114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                    synchronized (mMainRemote) {
50863114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                        mMainRemote.mRccId = rcse.mRccId;
50873114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                        mMainRemote.mVolume = rcse.mPlaybackVolume;
50883114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                        mMainRemote.mVolumeMax = rcse.mPlaybackVolumeMax;
50893114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                        mMainRemote.mVolumeHandling = rcse.mPlaybackVolumeHandling;
50903114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                        mMainRemoteIsActive = true;
50913114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                    }
50923114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                    return true;
50933114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                }
50943114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi            }
50953114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        }
50963114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        synchronized (mMainRemote) {
50973114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi            mMainRemoteIsActive = false;
50983114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        }
50993114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        return false;
51003114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    }
51013114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi
51023114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    /**
51033114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     * Returns true if the given playback state is considered "active", i.e. it describes a state
51043114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     * where playback is happening, or about to
51053114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     * @param playState the playback state to evaluate
51063114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     * @return true if active, false otherwise (inactive or unknown)
51073114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     */
51083114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    private static boolean isPlaystateActive(int playState) {
51093114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        switch (playState) {
51103114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi            case RemoteControlClient.PLAYSTATE_PLAYING:
51113114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi            case RemoteControlClient.PLAYSTATE_BUFFERING:
51123114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi            case RemoteControlClient.PLAYSTATE_FAST_FORWARDING:
51133114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi            case RemoteControlClient.PLAYSTATE_REWINDING:
51143114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi            case RemoteControlClient.PLAYSTATE_SKIPPING_BACKWARDS:
51153114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi            case RemoteControlClient.PLAYSTATE_SKIPPING_FORWARDS:
51163114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                return true;
51173114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi            default:
51183114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                return false;
51193114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        }
51203114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    }
51213114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi
51223114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    private void adjustRemoteVolume(int streamType, int direction, int flags) {
51233114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        int rccId = RemoteControlClient.RCSE_ID_UNREGISTERED;
51243114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        boolean volFixed = false;
51253114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        synchronized (mMainRemote) {
51263114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi            if (!mMainRemoteIsActive) {
51273114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                if (DEBUG_VOL) Log.w(TAG, "adjustRemoteVolume didn't find an active client");
51283114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                return;
51293114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi            }
51303114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi            rccId = mMainRemote.mRccId;
51313114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi            volFixed = (mMainRemote.mVolumeHandling ==
51323114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                    RemoteControlClient.PLAYBACK_VOLUME_FIXED);
51333114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        }
51343114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        // unlike "local" stream volumes, we can't compute the new volume based on the direction,
51353114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        // we can only notify the remote that volume needs to be updated, and we'll get an async'
51363114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        // update through setPlaybackInfoForRcc()
51373114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        if (!volFixed) {
51383114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi            sendVolumeUpdateToRemote(rccId, direction);
51393114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        }
51403114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi
51413114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        // fire up the UI
51423114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        mVolumePanel.postRemoteVolumeChanged(streamType, flags);
51433114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    }
51443114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi
51453114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    private void sendVolumeUpdateToRemote(int rccId, int direction) {
51463114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        if (DEBUG_VOL) { Log.d(TAG, "sendVolumeUpdateToRemote(rccId="+rccId+" , dir="+direction); }
51473114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        if (direction == 0) {
51483114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi            // only handling discrete events
51493114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi            return;
51503114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        }
51511357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi        IRemoteVolumeObserver rvo = null;
51523114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        synchronized (mRCStack) {
51533114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi            Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator();
51543114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi            while(stackIterator.hasNext()) {
51553114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                RemoteControlStackEntry rcse = stackIterator.next();
51563114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                //FIXME OPTIMIZE store this info in mMainRemote so we don't have to iterate?
51573114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                if (rcse.mRccId == rccId) {
51581357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi                    rvo = rcse.mRemoteVolumeObs;
51593114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                    break;
51603114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                }
51613114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi            }
51623114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        }
51631357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi        if (rvo != null) {
51641357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi            try {
51651357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi                rvo.dispatchRemoteVolumeUpdate(direction, -1);
51661357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi            } catch (RemoteException e) {
51671357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi                Log.e(TAG, "Error dispatching relative volume update", e);
51681357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi            }
51693114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        }
51703114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    }
51713114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi
51723114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    public int getRemoteStreamMaxVolume() {
51733114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        synchronized (mMainRemote) {
51743114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi            if (mMainRemote.mRccId == RemoteControlClient.RCSE_ID_UNREGISTERED) {
51753114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                return 0;
51763114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi            }
51773114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi            return mMainRemote.mVolumeMax;
51783114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        }
51793114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    }
51803114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi
51813114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    public int getRemoteStreamVolume() {
51823114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        synchronized (mMainRemote) {
51833114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi            if (mMainRemote.mRccId == RemoteControlClient.RCSE_ID_UNREGISTERED) {
51843114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                return 0;
51853114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi            }
51863114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi            return mMainRemote.mVolume;
51873114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        }
51883114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    }
51893114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi
51903114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    public void setRemoteStreamVolume(int vol) {
51913114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        if (DEBUG_VOL) { Log.d(TAG, "setRemoteStreamVolume(vol="+vol+")"); }
51923114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        int rccId = RemoteControlClient.RCSE_ID_UNREGISTERED;
51933114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        synchronized (mMainRemote) {
51943114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi            if (mMainRemote.mRccId == RemoteControlClient.RCSE_ID_UNREGISTERED) {
51953114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                return;
51963114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi            }
51973114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi            rccId = mMainRemote.mRccId;
51983114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        }
51991357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi        IRemoteVolumeObserver rvo = null;
52003114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        synchronized (mRCStack) {
52013114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi            Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator();
52023114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi            while(stackIterator.hasNext()) {
52033114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                RemoteControlStackEntry rcse = stackIterator.next();
52043114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                if (rcse.mRccId == rccId) {
52053114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                    //FIXME OPTIMIZE store this info in mMainRemote so we don't have to iterate?
52061357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi                    rvo = rcse.mRemoteVolumeObs;
52073114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                    break;
52083114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                }
52093114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi            }
52103114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        }
52111357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi        if (rvo != null) {
52121357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi            try {
52131357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi                rvo.dispatchRemoteVolumeUpdate(0, vol);
52141357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi            } catch (RemoteException e) {
52151357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi                Log.e(TAG, "Error dispatching absolute volume update", e);
52161357012968f9066ea3051d83995e9bac69526c3cJean-Michel Trivi            }
52173114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        }
52183114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    }
52193114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi
52203114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    /**
52213114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     * Call to make AudioService reevaluate whether it's in a mode where remote players should
52223114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     * have their volume controlled. In this implementation this is only to reset whether
52233114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     * VolumePanel should display remote volumes
52243114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi     */
52253114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    private void postReevaluateRemote() {
52263114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        sendMsg(mAudioHandler, MSG_REEVALUATE_REMOTE, SENDMSG_QUEUE, 0, 0, null, 0);
52273114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    }
52283114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi
52293114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    private void onReevaluateRemote() {
52303114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        if (DEBUG_VOL) { Log.w(TAG, "onReevaluateRemote()"); }
52313114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        // is there a registered RemoteControlClient that is handling remote playback
52323114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        boolean hasRemotePlayback = false;
52333114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        synchronized (mRCStack) {
52343114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi            Iterator<RemoteControlStackEntry> stackIterator = mRCStack.iterator();
52353114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi            while(stackIterator.hasNext()) {
52363114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                RemoteControlStackEntry rcse = stackIterator.next();
52373114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                if (rcse.mPlaybackType == RemoteControlClient.PLAYBACK_TYPE_REMOTE) {
52383114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                    hasRemotePlayback = true;
52393114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                    break;
52403114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                }
52413114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi            }
52423114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        }
52433114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        synchronized (mMainRemote) {
52443114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi            if (mHasRemotePlayback != hasRemotePlayback) {
52453114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                mHasRemotePlayback = hasRemotePlayback;
52463114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi                mVolumePanel.postRemoteSliderVisibility(hasRemotePlayback);
52473114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi            }
52483114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        }
52493114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi    }
52503114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi
5251f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi    //==========================================================================================
5252f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi    // Device orientation
5253f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi    //==========================================================================================
5254f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi    /**
5255f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi     * Handles device configuration changes that may map to a change in the orientation.
5256f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi     * This feature is optional, and is defined by the definition and value of the
5257f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi     * "ro.audio.monitorOrientation" system property.
5258f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi     */
5259f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi    private void handleConfigurationChanged(Context context) {
5260f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi        try {
5261f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi            // reading new orientation "safely" (i.e. under try catch) in case anything
5262f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi            // goes wrong when obtaining resources and configuration
5263f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi            int newOrientation = context.getResources().getConfiguration().orientation;
5264f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi            if (newOrientation != mDeviceOrientation) {
5265f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi                mDeviceOrientation = newOrientation;
5266f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi                setOrientationForAudioSystem();
5267f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi            }
5268f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi        } catch (Exception e) {
5269f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi            Log.e(TAG, "Error retrieving device orientation: " + e);
5270f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi        }
5271f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi    }
5272f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi
5273f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi    private void setOrientationForAudioSystem() {
5274f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi        switch (mDeviceOrientation) {
5275f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi            case Configuration.ORIENTATION_LANDSCAPE:
5276f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi                //Log.i(TAG, "orientation is landscape");
5277f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi                AudioSystem.setParameters("orientation=landscape");
5278f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi                break;
5279f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi            case Configuration.ORIENTATION_PORTRAIT:
5280f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi                //Log.i(TAG, "orientation is portrait");
5281f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi                AudioSystem.setParameters("orientation=portrait");
5282f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi                break;
5283f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi            case Configuration.ORIENTATION_SQUARE:
5284f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi                //Log.i(TAG, "orientation is square");
5285f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi                AudioSystem.setParameters("orientation=square");
5286f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi                break;
5287f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi            case Configuration.ORIENTATION_UNDEFINED:
5288f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi                //Log.i(TAG, "orientation is undefined");
5289f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi                AudioSystem.setParameters("orientation=undefined");
5290f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi                break;
5291f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi            default:
5292f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi                Log.e(TAG, "Unknown orientation");
5293f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi        }
5294f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi    }
5295f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi
5296f26f01784e1c733c53cad3ed31918e73448ce369Jean-Michel Trivi
52977847211fb4699bf6018e29d214a918ed6657319bEric Laurent    // Handles request to override default use of A2DP for media.
52987847211fb4699bf6018e29d214a918ed6657319bEric Laurent    public void setBluetoothA2dpOnInt(boolean on) {
52997847211fb4699bf6018e29d214a918ed6657319bEric Laurent        synchronized (mBluetoothA2dpEnabledLock) {
53007847211fb4699bf6018e29d214a918ed6657319bEric Laurent            mBluetoothA2dpEnabled = on;
5301c390bed06b4a572e273ead1254da9a932e04dce3Eric Laurent            mAudioHandler.removeMessages(MSG_SET_FORCE_BT_A2DP_USE);
5302c390bed06b4a572e273ead1254da9a932e04dce3Eric Laurent            AudioSystem.setForceUse(AudioSystem.FOR_MEDIA,
5303c390bed06b4a572e273ead1254da9a932e04dce3Eric Laurent                    mBluetoothA2dpEnabled ? AudioSystem.FORCE_NONE : AudioSystem.FORCE_NO_BT_A2DP);
53047847211fb4699bf6018e29d214a918ed6657319bEric Laurent        }
53057847211fb4699bf6018e29d214a918ed6657319bEric Laurent    }
53067847211fb4699bf6018e29d214a918ed6657319bEric Laurent
5307d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi    @Override
5308098d580cc2bb6c0891c756a4e5230c6c6b0d2376Jeff Sharkey    public void setRingtonePlayer(IRingtonePlayer player) {
5309098d580cc2bb6c0891c756a4e5230c6c6b0d2376Jeff Sharkey        mContext.enforceCallingOrSelfPermission(REMOTE_AUDIO_PLAYBACK, null);
5310098d580cc2bb6c0891c756a4e5230c6c6b0d2376Jeff Sharkey        mRingtonePlayer = player;
5311098d580cc2bb6c0891c756a4e5230c6c6b0d2376Jeff Sharkey    }
5312098d580cc2bb6c0891c756a4e5230c6c6b0d2376Jeff Sharkey
5313098d580cc2bb6c0891c756a4e5230c6c6b0d2376Jeff Sharkey    @Override
5314098d580cc2bb6c0891c756a4e5230c6c6b0d2376Jeff Sharkey    public IRingtonePlayer getRingtonePlayer() {
5315098d580cc2bb6c0891c756a4e5230c6c6b0d2376Jeff Sharkey        return mRingtonePlayer;
5316098d580cc2bb6c0891c756a4e5230c6c6b0d2376Jeff Sharkey    }
5317098d580cc2bb6c0891c756a4e5230c6c6b0d2376Jeff Sharkey
5318098d580cc2bb6c0891c756a4e5230c6c6b0d2376Jeff Sharkey    @Override
5319632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn    public AudioRoutesInfo startWatchingRoutes(IAudioRoutesObserver observer) {
5320632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn        synchronized (mCurAudioRoutes) {
5321632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn            AudioRoutesInfo routes = new AudioRoutesInfo(mCurAudioRoutes);
5322632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn            mRoutesObservers.register(observer);
5323632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn            return routes;
5324632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn        }
5325632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn    }
5326632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn
5327632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn    @Override
5328d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi    protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
5329eb4cc492c93ab9635dde78b958a834120412e72aJeff Sharkey        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DUMP, TAG);
5330eb4cc492c93ab9635dde78b958a834120412e72aJeff Sharkey
5331d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi        dumpFocusStack(pw);
5332d327f21626217aa3c9c0cdb7a84a742c531e59a3Jean-Michel Trivi        dumpRCStack(pw);
53333114ce3861f20f9a5c2c59dd2629197a1f4874a8Jean-Michel Trivi        dumpRCCStack(pw);
5334bffc3d1bd33eb2d8e00a9f8b6261d815db503311Eric Laurent        dumpStreamStates(pw);
5335632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn        pw.println("\nAudio routes:");
5336632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn        pw.print("  mMainType=0x"); pw.println(Integer.toHexString(mCurAudioRoutes.mMainType));
5337632ca417f0a33e3fa9ccece531afa2db3f0d4a30Dianne Hackborn        pw.print("  mBluetoothName="); pw.println(mCurAudioRoutes.mBluetoothName);
5338d5176cfe6eae954e9cef1e2ec17859a5089e1330Jean-Michel Trivi    }
53399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
5340