AudioService.java revision c42ac9d4d03f62c3a1ba197a28a81fda44bd8b7f
1/*
2 * Copyright (C) 2006 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package android.media;
18
19import android.app.ActivityManagerNative;
20import android.content.ContentResolver;
21import android.content.Context;
22import android.content.Intent;
23import android.content.IntentFilter;
24import android.bluetooth.BluetoothIntent;
25import android.content.BroadcastReceiver;
26import android.bluetooth.BluetoothHeadset;
27import android.bluetooth.BluetoothA2dp;
28
29import android.content.pm.PackageManager;
30import android.database.ContentObserver;
31import android.media.MediaPlayer.OnCompletionListener;
32import android.media.MediaPlayer.OnErrorListener;
33import android.os.Binder;
34import android.os.Environment;
35import android.os.Handler;
36import android.os.IBinder;
37import android.os.Looper;
38import android.os.Message;
39import android.os.RemoteException;
40import android.os.ServiceManager;
41import android.provider.Settings;
42import android.provider.Settings.System;
43import android.util.Log;
44import android.view.VolumePanel;
45
46import com.android.internal.telephony.ITelephony;
47
48import java.io.IOException;
49import java.util.ArrayList;
50import java.util.HashMap;
51import java.util.Iterator;
52import java.util.Map;
53import java.util.Set;
54
55/**
56 * The implementation of the volume manager service.
57 * <p>
58 * This implementation focuses on delivering a responsive UI. Most methods are
59 * asynchronous to external calls. For example, the task of setting a volume
60 * will update our internal state, but in a separate thread will set the system
61 * volume and later persist to the database. Similarly, setting the ringer mode
62 * will update the state and broadcast a change and in a separate thread later
63 * persist the ringer mode.
64 *
65 * @hide
66 */
67public class AudioService extends IAudioService.Stub {
68
69    private static final String TAG = "AudioService";
70
71    /** How long to delay before persisting a change in volume/ringer mode. */
72    private static final int PERSIST_DELAY = 3000;
73
74    private Context mContext;
75    private ContentResolver mContentResolver;
76
77    /** The UI */
78    private VolumePanel mVolumePanel;
79
80    // sendMsg() flags
81    /** Used when a message should be shared across all stream types. */
82    private static final int SHARED_MSG = -1;
83    /** If the msg is already queued, replace it with this one. */
84    private static final int SENDMSG_REPLACE = 0;
85    /** If the msg is already queued, ignore this one and leave the old. */
86    private static final int SENDMSG_NOOP = 1;
87    /** If the msg is already queued, queue this one and leave the old. */
88    private static final int SENDMSG_QUEUE = 2;
89
90    // AudioHandler message.whats
91    private static final int MSG_SET_SYSTEM_VOLUME = 0;
92    private static final int MSG_PERSIST_VOLUME = 1;
93    private static final int MSG_PERSIST_RINGER_MODE = 3;
94    private static final int MSG_PERSIST_VIBRATE_SETTING = 4;
95    private static final int MSG_MEDIA_SERVER_DIED = 5;
96    private static final int MSG_MEDIA_SERVER_STARTED = 6;
97    private static final int MSG_PLAY_SOUND_EFFECT = 7;
98
99    /** @see AudioSystemThread */
100    private AudioSystemThread mAudioSystemThread;
101    /** @see AudioHandler */
102    private AudioHandler mAudioHandler;
103    /** @see VolumeStreamState */
104    private VolumeStreamState[] mStreamStates;
105    private SettingsObserver mSettingsObserver;
106
107    private int mMode;
108    private Object mSettingsLock = new Object();
109    private boolean mMediaServerOk;
110
111    private SoundPool mSoundPool;
112    private Object mSoundEffectsLock = new Object();
113    private static final int NUM_SOUNDPOOL_CHANNELS = 4;
114    private static final int SOUND_EFFECT_VOLUME = 1000;
115
116    /* Sound effect file names  */
117    private static final String SOUND_EFFECTS_PATH = "/media/audio/ui/";
118    private static final String[] SOUND_EFFECT_FILES = new String[] {
119        "Effect_Tick.ogg",
120        "KeypressStandard.ogg",
121        "KeypressSpacebar.ogg",
122        "KeypressDelete.ogg",
123        "KeypressReturn.ogg"
124    };
125
126    /* Sound effect file name mapping sound effect id (AudioManager.FX_xxx) to
127     * file index in SOUND_EFFECT_FILES[] (first column) and indicating if effect
128     * uses soundpool (second column) */
129    private int[][] SOUND_EFFECT_FILES_MAP = new int[][] {
130        {0, -1},  // FX_KEY_CLICK
131        {0, -1},  // FX_FOCUS_NAVIGATION_UP
132        {0, -1},  // FX_FOCUS_NAVIGATION_DOWN
133        {0, -1},  // FX_FOCUS_NAVIGATION_LEFT
134        {0, -1},  // FX_FOCUS_NAVIGATION_RIGHT
135        {1, -1},  // FX_KEYPRESS_STANDARD
136        {2, -1},  // FX_KEYPRESS_SPACEBAR
137        {3, -1},  // FX_FOCUS_DELETE
138        {4, -1}   // FX_FOCUS_RETURN
139    };
140
141    /* STREAM_VOLUME_ALIAS[] indicates for each stream if it uses the volume settings
142     * of another stream: This avoids multiplying the volume settings for hidden
143     * stream types that follow other stream behavior for volume settings
144     * NOTE: do not create loops in aliases! */
145    private int[] STREAM_VOLUME_ALIAS = new int[] {
146        AudioSystem.STREAM_VOICE_CALL,  // STREAM_VOICE_CALL
147        AudioSystem.STREAM_SYSTEM,  // STREAM_SYSTEM
148        AudioSystem.STREAM_RING,  // STREAM_RING
149        AudioSystem.STREAM_MUSIC, // STREAM_MUSIC
150        AudioSystem.STREAM_ALARM,  // STREAM_ALARM
151        AudioSystem.STREAM_NOTIFICATION,  // STREAM_NOTIFICATION
152        AudioSystem.STREAM_VOICE_CALL, // STREAM_BLUETOOTH_SCO
153        AudioSystem.STREAM_SYSTEM,  // STREAM_SYSTEM_ENFORCED
154        AudioSystem.STREAM_VOICE_CALL, // STREAM_DTMF
155        AudioSystem.STREAM_MUSIC  // STREAM_TTS
156    };
157
158    private AudioSystem.ErrorCallback mAudioSystemCallback = new AudioSystem.ErrorCallback() {
159        public void onError(int error) {
160            switch (error) {
161            case AudioSystem.AUDIO_STATUS_SERVER_DIED:
162                if (mMediaServerOk) {
163                    sendMsg(mAudioHandler, MSG_MEDIA_SERVER_DIED, SHARED_MSG, SENDMSG_NOOP, 0, 0,
164                            null, 1500);
165                }
166                break;
167            case AudioSystem.AUDIO_STATUS_OK:
168                if (!mMediaServerOk) {
169                    sendMsg(mAudioHandler, MSG_MEDIA_SERVER_STARTED, SHARED_MSG, SENDMSG_NOOP, 0, 0,
170                            null, 0);
171                }
172                break;
173            default:
174                break;
175            }
176       }
177    };
178
179    /**
180     * Current ringer mode from one of {@link AudioManager#RINGER_MODE_NORMAL},
181     * {@link AudioManager#RINGER_MODE_SILENT}, or
182     * {@link AudioManager#RINGER_MODE_VIBRATE}.
183     */
184    private int mRingerMode;
185
186    /** @see System#MODE_RINGER_STREAMS_AFFECTED */
187    private int mRingerModeAffectedStreams;
188
189    /** @see System#MUTE_STREAMS_AFFECTED */
190    private int mMuteAffectedStreams;
191
192    /**
193     * Has multiple bits per vibrate type to indicate the type's vibrate
194     * setting. See {@link #setVibrateSetting(int, int)}.
195     * <p>
196     * NOTE: This is not the final decision of whether vibrate is on/off for the
197     * type since it depends on the ringer mode. See {@link #shouldVibrate(int)}.
198     */
199    private int mVibrateSetting;
200
201    /** @see System#NOTIFICATIONS_USE_RING_VOLUME */
202    private int mNotificationsUseRingVolume;
203
204    // Broadcast receiver for device connections intent broadcasts
205    private final BroadcastReceiver mReceiver = new AudioServiceBroadcastReceiver();
206
207    //TODO: use common definitions with HeadsetObserver
208    private static final int BIT_HEADSET = (1 << 0);
209    private static final int BIT_HEADSET_NO_MIC = (1 << 1);
210    private static final int BIT_TTY = (1 << 2);
211    private static final int BIT_FM_HEADSET = (1 << 3);
212    private static final int BIT_FM_SPEAKER = (1 << 4);
213
214    private int mHeadsetState;
215
216    // Devices currently connected
217    private HashMap <Integer, String> mConnectedDevices = new HashMap <Integer, String>();
218
219    // Forced device usage for communications
220    private int mForcedUseForComm;
221
222    ///////////////////////////////////////////////////////////////////////////
223    // Construction
224    ///////////////////////////////////////////////////////////////////////////
225
226    /** @hide */
227    public AudioService(Context context) {
228        mContext = context;
229        mContentResolver = context.getContentResolver();
230        mVolumePanel = new VolumePanel(context, this);
231        mSettingsObserver = new SettingsObserver();
232        mMode = AudioSystem.MODE_NORMAL;
233        mHeadsetState = 0;
234        mForcedUseForComm = AudioSystem.FORCE_NONE;
235        createAudioSystemThread();
236        readPersistedSettings();
237        createStreamStates();
238        mMediaServerOk = true;
239        AudioSystem.setErrorCallback(mAudioSystemCallback);
240        loadSoundEffects();
241
242        // Register for device connection intent broadcasts.
243        IntentFilter intentFilter =
244                new IntentFilter(Intent.ACTION_HEADSET_PLUG);
245        intentFilter.addAction(BluetoothA2dp.SINK_STATE_CHANGED_ACTION);
246        intentFilter.addAction(BluetoothIntent.HEADSET_AUDIO_STATE_CHANGED_ACTION);
247        context.registerReceiver(mReceiver, intentFilter);
248    }
249
250    private void createAudioSystemThread() {
251        mAudioSystemThread = new AudioSystemThread();
252        mAudioSystemThread.start();
253        waitForAudioHandlerCreation();
254    }
255
256    /** Waits for the volume handler to be created by the other thread. */
257    private void waitForAudioHandlerCreation() {
258        synchronized(this) {
259            while (mAudioHandler == null) {
260                try {
261                    // Wait for mAudioHandler to be set by the other thread
262                    wait();
263                } catch (InterruptedException e) {
264                    Log.e(TAG, "Interrupted while waiting on volume handler.");
265                }
266            }
267        }
268    }
269
270    private void createStreamStates() {
271        int numStreamTypes = AudioSystem.getNumStreamTypes();
272        VolumeStreamState[] streams = mStreamStates = new VolumeStreamState[numStreamTypes];
273
274        for (int i = 0; i < numStreamTypes; i++) {
275            streams[i] = new VolumeStreamState(System.VOLUME_SETTINGS[STREAM_VOLUME_ALIAS[i]], i);
276        }
277
278        // Correct stream index values for streams with aliases
279        for (int i = 0; i < numStreamTypes; i++) {
280            if (STREAM_VOLUME_ALIAS[i] != i) {
281                int index = rescaleIndex(streams[i].mIndex, STREAM_VOLUME_ALIAS[i], i);
282                streams[i].mIndex = streams[i].getValidIndex(index);
283                setStreamVolumeIndex(i, index);
284                index = rescaleIndex(streams[i].mLastAudibleIndex, STREAM_VOLUME_ALIAS[i], i);
285                streams[i].mLastAudibleIndex = streams[i].getValidIndex(index);
286            }
287        }
288    }
289
290    private void readPersistedSettings() {
291        final ContentResolver cr = mContentResolver;
292
293        mRingerMode = System.getInt(cr, System.MODE_RINGER, AudioManager.RINGER_MODE_NORMAL);
294
295        mVibrateSetting = System.getInt(cr, System.VIBRATE_ON, 0);
296
297        mRingerModeAffectedStreams = Settings.System.getInt(cr,
298                Settings.System.MODE_RINGER_STREAMS_AFFECTED,
299                ((1 << AudioSystem.STREAM_RING)|(1 << AudioSystem.STREAM_NOTIFICATION)|
300                 (1 << AudioSystem.STREAM_SYSTEM)|(1 << AudioSystem.STREAM_SYSTEM_ENFORCED)));
301
302        mMuteAffectedStreams = System.getInt(cr,
303                System.MUTE_STREAMS_AFFECTED,
304                ((1 << AudioSystem.STREAM_MUSIC)|(1 << AudioSystem.STREAM_RING)|(1 << AudioSystem.STREAM_SYSTEM)));
305
306        mNotificationsUseRingVolume = System.getInt(cr,
307                Settings.System.NOTIFICATIONS_USE_RING_VOLUME, 1);
308
309        if (mNotificationsUseRingVolume == 1) {
310            STREAM_VOLUME_ALIAS[AudioSystem.STREAM_NOTIFICATION] = AudioSystem.STREAM_RING;
311        }
312        // Each stream will read its own persisted settings
313
314        // Broadcast the sticky intent
315        broadcastRingerMode();
316
317        // Broadcast vibrate settings
318        broadcastVibrateSetting(AudioManager.VIBRATE_TYPE_RINGER);
319        broadcastVibrateSetting(AudioManager.VIBRATE_TYPE_NOTIFICATION);
320    }
321
322    private void setStreamVolumeIndex(int stream, int index) {
323        AudioSystem.setStreamVolumeIndex(stream, (index + 5)/10);
324    }
325
326    private int rescaleIndex(int index, int srcStream, int dstStream) {
327        return (index * mStreamStates[dstStream].getMaxIndex() + mStreamStates[srcStream].getMaxIndex() / 2) / mStreamStates[srcStream].getMaxIndex();
328    }
329
330    ///////////////////////////////////////////////////////////////////////////
331    // IPC methods
332    ///////////////////////////////////////////////////////////////////////////
333
334    /** @see AudioManager#adjustVolume(int, int) */
335    public void adjustVolume(int direction, int flags) {
336        adjustSuggestedStreamVolume(direction, AudioManager.USE_DEFAULT_STREAM_TYPE, flags);
337    }
338
339    /** @see AudioManager#adjustVolume(int, int, int) */
340    public void adjustSuggestedStreamVolume(int direction, int suggestedStreamType, int flags) {
341
342        int streamType = getActiveStreamType(suggestedStreamType);
343
344        // Don't play sound on other streams
345        if (streamType != AudioSystem.STREAM_RING && (flags & AudioManager.FLAG_PLAY_SOUND) != 0) {
346            flags &= ~AudioManager.FLAG_PLAY_SOUND;
347        }
348
349        adjustStreamVolume(streamType, direction, flags);
350    }
351
352    /** @see AudioManager#adjustStreamVolume(int, int, int) */
353    public void adjustStreamVolume(int streamType, int direction, int flags) {
354        ensureValidDirection(direction);
355        ensureValidStreamType(streamType);
356
357
358        VolumeStreamState streamState = mStreamStates[STREAM_VOLUME_ALIAS[streamType]];
359        final int oldIndex = streamState.mIndex;
360        boolean adjustVolume = true;
361
362        // If either the client forces allowing ringer modes for this adjustment,
363        // or the stream type is one that is affected by ringer modes
364        if ((flags & AudioManager.FLAG_ALLOW_RINGER_MODES) != 0
365                || streamType == AudioSystem.STREAM_RING) {
366            // Check if the ringer mode changes with this volume adjustment. If
367            // it does, it will handle adjusting the volume, so we won't below
368            adjustVolume = checkForRingerModeChange(oldIndex, direction);
369        }
370
371        if (adjustVolume && streamState.adjustIndex(direction)) {
372            // Post message to set system volume (it in turn will post a message
373            // to persist). Do not change volume if stream is muted.
374            if (streamState.muteCount() == 0) {
375                sendMsg(mAudioHandler, MSG_SET_SYSTEM_VOLUME, STREAM_VOLUME_ALIAS[streamType], SENDMSG_NOOP, 0, 0,
376                        streamState, 0);
377            }
378        }
379
380        // UI
381        mVolumePanel.postVolumeChanged(streamType, flags);
382        // Broadcast Intent
383        sendVolumeUpdate(streamType);
384    }
385
386    /** @see AudioManager#setStreamVolume(int, int, int) */
387    public void setStreamVolume(int streamType, int index, int flags) {
388        ensureValidStreamType(streamType);
389        index = rescaleIndex(index * 10, streamType, STREAM_VOLUME_ALIAS[streamType]);
390        setStreamVolumeInt(STREAM_VOLUME_ALIAS[streamType], index, false, true);
391
392        // UI, etc.
393        mVolumePanel.postVolumeChanged(streamType, flags);
394        // Broadcast Intent
395        sendVolumeUpdate(streamType);
396    }
397
398    private void sendVolumeUpdate(int streamType) {
399        Intent intent = new Intent(AudioManager.VOLUME_CHANGED_ACTION);
400        intent.putExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, streamType);
401        intent.putExtra(AudioManager.EXTRA_VOLUME_STREAM_VALUE, getStreamVolume(streamType));
402
403        // Currently, sending the intent only when the stream is BLUETOOTH_SCO
404        if (streamType == AudioSystem.STREAM_BLUETOOTH_SCO) {
405            mContext.sendBroadcast(intent);
406        }
407    }
408
409    /**
410     * Sets the stream state's index, and posts a message to set system volume.
411     * This will not call out to the UI. Assumes a valid stream type.
412     *
413     * @param streamType Type of the stream
414     * @param index Desired volume index of the stream
415     * @param force If true, set the volume even if the desired volume is same
416     * as the current volume.
417     * @param lastAudible If true, stores new index as last audible one
418     */
419    private void setStreamVolumeInt(int streamType, int index, boolean force, boolean lastAudible) {
420        VolumeStreamState streamState = mStreamStates[streamType];
421        if (streamState.setIndex(index, lastAudible) || force) {
422            // Post message to set system volume (it in turn will post a message
423            // to persist). Do not change volume if stream is muted.
424            if (streamState.muteCount() == 0) {
425                sendMsg(mAudioHandler, MSG_SET_SYSTEM_VOLUME, streamType, SENDMSG_NOOP, 0, 0,
426                        streamState, 0);
427            }
428        }
429    }
430
431    /** @see AudioManager#setStreamSolo(int, boolean) */
432    public void setStreamSolo(int streamType, boolean state, IBinder cb) {
433        for (int stream = 0; stream < mStreamStates.length; stream++) {
434            if (!isStreamAffectedByMute(stream) || stream == streamType) continue;
435            // Bring back last audible volume
436            mStreamStates[stream].mute(cb, state);
437         }
438    }
439
440    /** @see AudioManager#setStreamMute(int, boolean) */
441    public void setStreamMute(int streamType, boolean state, IBinder cb) {
442        if (isStreamAffectedByMute(streamType)) {
443            mStreamStates[streamType].mute(cb, state);
444        }
445    }
446
447    /** @see AudioManager#getStreamVolume(int) */
448    public int getStreamVolume(int streamType) {
449        ensureValidStreamType(streamType);
450        return (mStreamStates[streamType].mIndex + 5) / 10;
451    }
452
453    /** @see AudioManager#getStreamMaxVolume(int) */
454    public int getStreamMaxVolume(int streamType) {
455        ensureValidStreamType(streamType);
456        return (mStreamStates[streamType].getMaxIndex() + 5) / 10;
457    }
458
459    /** @see AudioManager#getRingerMode() */
460    public int getRingerMode() {
461        return mRingerMode;
462    }
463
464    /** @see AudioManager#setRingerMode(int) */
465    public void setRingerMode(int ringerMode) {
466        synchronized (mSettingsLock) {
467            if (ringerMode != mRingerMode) {
468                setRingerModeInt(ringerMode, true);
469                // Send sticky broadcast
470                broadcastRingerMode();
471            }
472        }
473    }
474
475    private void setRingerModeInt(int ringerMode, boolean persist) {
476        mRingerMode = ringerMode;
477
478        // Adjust volumes via posting message
479        int numStreamTypes = AudioSystem.getNumStreamTypes();
480        if (mRingerMode == AudioManager.RINGER_MODE_NORMAL) {
481            for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
482                if (!isStreamAffectedByRingerMode(streamType)) continue;
483                // Bring back last audible volume
484                setStreamVolumeInt(streamType, mStreamStates[streamType].mLastAudibleIndex,
485                                   false, false);
486            }
487        } else {
488            for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
489                if (isStreamAffectedByRingerMode(streamType)) {
490                    // Either silent or vibrate, either way volume is 0
491                    setStreamVolumeInt(streamType, 0, false, false);
492                } else {
493                    // restore stream volume in the case the stream changed from affected
494                    // to non affected by ringer mode. Does not arm to do it for streams that
495                    // are not affected as well.
496                    setStreamVolumeInt(streamType, mStreamStates[streamType].mLastAudibleIndex,
497                            false, false);
498                }
499            }
500        }
501
502        // Post a persist ringer mode msg
503        if (persist) {
504            sendMsg(mAudioHandler, MSG_PERSIST_RINGER_MODE, SHARED_MSG,
505                    SENDMSG_REPLACE, 0, 0, null, PERSIST_DELAY);
506        }
507    }
508
509    /** @see AudioManager#shouldVibrate(int) */
510    public boolean shouldVibrate(int vibrateType) {
511
512        switch (getVibrateSetting(vibrateType)) {
513
514            case AudioManager.VIBRATE_SETTING_ON:
515                return mRingerMode != AudioManager.RINGER_MODE_SILENT;
516
517            case AudioManager.VIBRATE_SETTING_ONLY_SILENT:
518                return mRingerMode == AudioManager.RINGER_MODE_VIBRATE;
519
520            case AudioManager.VIBRATE_SETTING_OFF:
521                // Phone ringer should always vibrate in vibrate mode
522                if (vibrateType == AudioManager.VIBRATE_TYPE_RINGER) {
523                    return mRingerMode == AudioManager.RINGER_MODE_VIBRATE;
524                }
525
526            default:
527                return false;
528        }
529    }
530
531    /** @see AudioManager#getVibrateSetting(int) */
532    public int getVibrateSetting(int vibrateType) {
533        return (mVibrateSetting >> (vibrateType * 2)) & 3;
534    }
535
536    /** @see AudioManager#setVibrateSetting(int, int) */
537    public void setVibrateSetting(int vibrateType, int vibrateSetting) {
538
539        mVibrateSetting = getValueForVibrateSetting(mVibrateSetting, vibrateType, vibrateSetting);
540
541        // Broadcast change
542        broadcastVibrateSetting(vibrateType);
543
544        // Post message to set ringer mode (it in turn will post a message
545        // to persist)
546        sendMsg(mAudioHandler, MSG_PERSIST_VIBRATE_SETTING, SHARED_MSG, SENDMSG_NOOP, 0, 0,
547                null, 0);
548    }
549
550    /**
551     * @see #setVibrateSetting(int, int)
552     */
553    public static int getValueForVibrateSetting(int existingValue, int vibrateType,
554            int vibrateSetting) {
555
556        // First clear the existing setting. Each vibrate type has two bits in
557        // the value. Note '3' is '11' in binary.
558        existingValue &= ~(3 << (vibrateType * 2));
559
560        // Set into the old value
561        existingValue |= (vibrateSetting & 3) << (vibrateType * 2);
562
563        return existingValue;
564    }
565
566    /** @see AudioManager#setMode(int) */
567    public void setMode(int mode) {
568        if (!checkAudioSettingsPermission("setMode()")) {
569            return;
570        }
571
572        if (mode < AudioSystem.MODE_CURRENT || mode > AudioSystem.MODE_IN_CALL) {
573            return;
574        }
575
576        synchronized (mSettingsLock) {
577            if (mode == AudioSystem.MODE_CURRENT) {
578                mode = mMode;
579            }
580            if (mode != mMode) {
581                if (AudioSystem.setPhoneState(mode) == AudioSystem.AUDIO_STATUS_OK) {
582                    mMode = mode;
583                }
584            }
585            int streamType = getActiveStreamType(AudioManager.USE_DEFAULT_STREAM_TYPE);
586            int index = mStreamStates[STREAM_VOLUME_ALIAS[streamType]].mIndex;
587            setStreamVolumeInt(STREAM_VOLUME_ALIAS[streamType], index, true, true);
588        }
589    }
590
591    /** @see AudioManager#getMode() */
592    public int getMode() {
593        return mMode;
594    }
595
596    /** @see AudioManager#playSoundEffect(int) */
597    public void playSoundEffect(int effectType) {
598        sendMsg(mAudioHandler, MSG_PLAY_SOUND_EFFECT, SHARED_MSG, SENDMSG_NOOP,
599                effectType, SOUND_EFFECT_VOLUME, null, 0);
600    }
601
602    /** @see AudioManager#playSoundEffect(int, float) */
603    public void playSoundEffectVolume(int effectType, float volume) {
604        sendMsg(mAudioHandler, MSG_PLAY_SOUND_EFFECT, SHARED_MSG, SENDMSG_NOOP,
605                effectType, (int) (volume * 1000), null, 0);
606    }
607
608    /**
609     * Loads samples into the soundpool.
610     * This method must be called at when sound effects are enabled
611     */
612    public boolean loadSoundEffects() {
613        synchronized (mSoundEffectsLock) {
614            mSoundPool = new SoundPool(NUM_SOUNDPOOL_CHANNELS, AudioSystem.STREAM_SYSTEM, 0);
615            if (mSoundPool == null) {
616                return false;
617            }
618            /*
619             * poolId table: The value -1 in this table indicates that corresponding
620             * file (same index in SOUND_EFFECT_FILES[] has not been loaded.
621             * Once loaded, the value in poolId is the sample ID and the same
622             * sample can be reused for another effect using the same file.
623             */
624            int[] poolId = new int[SOUND_EFFECT_FILES.length];
625            for (int fileIdx = 0; fileIdx < SOUND_EFFECT_FILES.length; fileIdx++) {
626                poolId[fileIdx] = -1;
627            }
628            /*
629             * Effects whose value in SOUND_EFFECT_FILES_MAP[effect][1] is -1 must be loaded.
630             * If load succeeds, value in SOUND_EFFECT_FILES_MAP[effect][1] is > 0:
631             * this indicates we have a valid sample loaded for this effect.
632             */
633            for (int effect = 0; effect < AudioManager.NUM_SOUND_EFFECTS; effect++) {
634                // Do not load sample if this effect uses the MediaPlayer
635                if (SOUND_EFFECT_FILES_MAP[effect][1] == 0) {
636                    continue;
637                }
638                if (poolId[SOUND_EFFECT_FILES_MAP[effect][0]] == -1) {
639                    String filePath = Environment.getRootDirectory() + SOUND_EFFECTS_PATH + SOUND_EFFECT_FILES[SOUND_EFFECT_FILES_MAP[effect][0]];
640                    int sampleId = mSoundPool.load(filePath, 0);
641                    SOUND_EFFECT_FILES_MAP[effect][1] = sampleId;
642                    poolId[SOUND_EFFECT_FILES_MAP[effect][0]] = sampleId;
643                    if (sampleId <= 0) {
644                        Log.w(TAG, "Soundpool could not load file: "+filePath);
645                    }
646                } else {
647                    SOUND_EFFECT_FILES_MAP[effect][1] = poolId[SOUND_EFFECT_FILES_MAP[effect][0]];
648                }
649            }
650        }
651
652        return true;
653    }
654
655    /**
656     *  Unloads samples from the sound pool.
657     *  This method can be called to free some memory when
658     *  sound effects are disabled.
659     */
660    public void unloadSoundEffects() {
661        synchronized (mSoundEffectsLock) {
662            if (mSoundPool == null) {
663                return;
664            }
665            int[] poolId = new int[SOUND_EFFECT_FILES.length];
666            for (int fileIdx = 0; fileIdx < SOUND_EFFECT_FILES.length; fileIdx++) {
667                poolId[fileIdx] = 0;
668            }
669
670            for (int effect = 0; effect < AudioManager.NUM_SOUND_EFFECTS; effect++) {
671                if (SOUND_EFFECT_FILES_MAP[effect][1] <= 0) {
672                    continue;
673                }
674                if (poolId[SOUND_EFFECT_FILES_MAP[effect][0]] == 0) {
675                    mSoundPool.unload(SOUND_EFFECT_FILES_MAP[effect][1]);
676                    SOUND_EFFECT_FILES_MAP[effect][1] = -1;
677                    poolId[SOUND_EFFECT_FILES_MAP[effect][0]] = -1;
678                }
679            }
680            mSoundPool = null;
681        }
682    }
683
684    /** @see AudioManager#reloadAudioSettings() */
685    public void reloadAudioSettings() {
686        // restore ringer mode, ringer mode affected streams, mute affected streams and vibrate settings
687        readPersistedSettings();
688
689        // restore volume settings
690        int numStreamTypes = AudioSystem.getNumStreamTypes();
691        for (int streamType = 0; streamType < numStreamTypes; streamType++) {
692            VolumeStreamState streamState = mStreamStates[streamType];
693
694            String settingName = System.VOLUME_SETTINGS[STREAM_VOLUME_ALIAS[streamType]];
695            String lastAudibleSettingName = settingName + System.APPEND_FOR_LAST_AUDIBLE;
696            int index = Settings.System.getInt(mContentResolver,
697                                           settingName,
698                                           AudioManager.DEFAULT_STREAM_VOLUME[streamType]);
699            if (STREAM_VOLUME_ALIAS[streamType] != streamType) {
700                index = rescaleIndex(index * 10, STREAM_VOLUME_ALIAS[streamType], streamType);
701            } else {
702                index *= 10;
703            }
704            streamState.mIndex = streamState.getValidIndex(index);
705
706            index = (index + 5) / 10;
707            index = Settings.System.getInt(mContentResolver,
708                                            lastAudibleSettingName,
709                                            (index > 0) ? index : AudioManager.DEFAULT_STREAM_VOLUME[streamType]);
710            if (STREAM_VOLUME_ALIAS[streamType] != streamType) {
711                index = rescaleIndex(index * 10, STREAM_VOLUME_ALIAS[streamType], streamType);
712            } else {
713                index *= 10;
714            }
715            streamState.mLastAudibleIndex = streamState.getValidIndex(index);
716
717            // unmute stream that whas muted but is not affect by mute anymore
718            if (streamState.muteCount() != 0 && !isStreamAffectedByMute(streamType)) {
719                int size = streamState.mDeathHandlers.size();
720                for (int i = 0; i < size; i++) {
721                    streamState.mDeathHandlers.get(i).mMuteCount = 1;
722                    streamState.mDeathHandlers.get(i).mute(false);
723                }
724            }
725            // apply stream volume
726            if (streamState.muteCount() == 0) {
727                setStreamVolumeIndex(streamType, streamState.mIndex);
728            }
729        }
730
731        // apply new ringer mode
732        setRingerModeInt(getRingerMode(), false);
733    }
734
735    /** @see AudioManager#setSpeakerphoneOn() */
736    public void setSpeakerphoneOn(boolean on){
737        if (on) {
738            AudioSystem.setForceUse(AudioSystem.FOR_COMMUNICATION, AudioSystem.FORCE_SPEAKER);
739            mForcedUseForComm = AudioSystem.FORCE_SPEAKER;
740        } else {
741            AudioSystem.setForceUse(AudioSystem.FOR_COMMUNICATION, AudioSystem.FORCE_NONE);
742            mForcedUseForComm = AudioSystem.FORCE_NONE;
743        }
744    }
745
746    /** @see AudioManager#isSpeakerphoneOn() */
747    public boolean isSpeakerphoneOn() {
748        if (mForcedUseForComm == AudioSystem.FORCE_SPEAKER) {
749            return true;
750        } else {
751            return false;
752        }
753    }
754
755    /** @see AudioManager#setBluetoothScoOn() */
756    public void setBluetoothScoOn(boolean on){
757        if (on) {
758            AudioSystem.setForceUse(AudioSystem.FOR_COMMUNICATION, AudioSystem.FORCE_BT_SCO);
759            mForcedUseForComm = AudioSystem.FORCE_BT_SCO;
760        } else {
761            AudioSystem.setForceUse(AudioSystem.FOR_COMMUNICATION, AudioSystem.FORCE_NONE);
762            mForcedUseForComm = AudioSystem.FORCE_NONE;
763        }
764    }
765
766    /** @see AudioManager#isBluetoothScoOn() */
767    public boolean isBluetoothScoOn() {
768        if (mForcedUseForComm == AudioSystem.FORCE_BT_SCO) {
769            return true;
770        } else {
771            return false;
772        }
773    }
774
775    ///////////////////////////////////////////////////////////////////////////
776    // Internal methods
777    ///////////////////////////////////////////////////////////////////////////
778
779    /**
780     * Checks if the adjustment should change ringer mode instead of just
781     * adjusting volume. If so, this will set the proper ringer mode and volume
782     * indices on the stream states.
783     */
784    private boolean checkForRingerModeChange(int oldIndex, int direction) {
785        boolean adjustVolumeIndex = true;
786        int newRingerMode = mRingerMode;
787
788        if (mRingerMode == AudioManager.RINGER_MODE_NORMAL && (oldIndex + 5) / 10 == 1
789                && direction == AudioManager.ADJUST_LOWER) {
790            newRingerMode = AudioManager.RINGER_MODE_VIBRATE;
791        } else if (mRingerMode == AudioManager.RINGER_MODE_VIBRATE) {
792            if (direction == AudioManager.ADJUST_RAISE) {
793                newRingerMode = AudioManager.RINGER_MODE_NORMAL;
794            } else if (direction == AudioManager.ADJUST_LOWER) {
795                newRingerMode = AudioManager.RINGER_MODE_SILENT;
796            }
797        } else if (direction == AudioManager.ADJUST_RAISE
798                && mRingerMode == AudioManager.RINGER_MODE_SILENT) {
799            newRingerMode = AudioManager.RINGER_MODE_VIBRATE;
800        }
801
802        if (newRingerMode != mRingerMode) {
803            setRingerMode(newRingerMode);
804
805            /*
806             * If we are changing ringer modes, do not increment/decrement the
807             * volume index. Instead, the handler for the message above will
808             * take care of changing the index.
809             */
810            adjustVolumeIndex = false;
811        }
812
813        return adjustVolumeIndex;
814    }
815
816    public boolean isStreamAffectedByRingerMode(int streamType) {
817        return (mRingerModeAffectedStreams & (1 << streamType)) != 0;
818    }
819
820    public boolean isStreamAffectedByMute(int streamType) {
821        return (mMuteAffectedStreams & (1 << streamType)) != 0;
822    }
823
824    private void ensureValidDirection(int direction) {
825        if (direction < AudioManager.ADJUST_LOWER || direction > AudioManager.ADJUST_RAISE) {
826            throw new IllegalArgumentException("Bad direction " + direction);
827        }
828    }
829
830    private void ensureValidStreamType(int streamType) {
831        if (streamType < 0 || streamType >= mStreamStates.length) {
832            throw new IllegalArgumentException("Bad stream type " + streamType);
833        }
834    }
835
836    private int getActiveStreamType(int suggestedStreamType) {
837        boolean isOffhook = false;
838        try {
839            ITelephony phone = ITelephony.Stub.asInterface(ServiceManager.checkService("phone"));
840            if (phone != null) isOffhook = phone.isOffhook();
841        } catch (RemoteException e) {
842            Log.w(TAG, "Couldn't connect to phone service", e);
843        }
844
845        if (AudioSystem.getForceUse(AudioSystem.FOR_COMMUNICATION) == AudioSystem.FORCE_BT_SCO) {
846            // Log.v(TAG, "getActiveStreamType: Forcing STREAM_BLUETOOTH_SCO...");
847            return AudioSystem.STREAM_BLUETOOTH_SCO;
848        } else if (isOffhook) {
849            // Log.v(TAG, "getActiveStreamType: Forcing STREAM_VOICE_CALL...");
850            return AudioSystem.STREAM_VOICE_CALL;
851        } else if (AudioSystem.isMusicActive()) {
852            // Log.v(TAG, "getActiveStreamType: Forcing STREAM_MUSIC...");
853            return AudioSystem.STREAM_MUSIC;
854        } else if (suggestedStreamType == AudioManager.USE_DEFAULT_STREAM_TYPE) {
855            // Log.v(TAG, "getActiveStreamType: Forcing STREAM_RING...");
856            return AudioSystem.STREAM_RING;
857        } else {
858            // Log.v(TAG, "getActiveStreamType: Returning suggested type " + suggestedStreamType);
859            return suggestedStreamType;
860        }
861    }
862
863    private void broadcastRingerMode() {
864        // Send sticky broadcast
865        if (ActivityManagerNative.isSystemReady()) {
866            Intent broadcast = new Intent(AudioManager.RINGER_MODE_CHANGED_ACTION);
867            broadcast.putExtra(AudioManager.EXTRA_RINGER_MODE, mRingerMode);
868            long origCallerIdentityToken = Binder.clearCallingIdentity();
869            mContext.sendStickyBroadcast(broadcast);
870            Binder.restoreCallingIdentity(origCallerIdentityToken);
871        }
872    }
873
874    private void broadcastVibrateSetting(int vibrateType) {
875        // Send broadcast
876        if (ActivityManagerNative.isSystemReady()) {
877            Intent broadcast = new Intent(AudioManager.VIBRATE_SETTING_CHANGED_ACTION);
878            broadcast.putExtra(AudioManager.EXTRA_VIBRATE_TYPE, vibrateType);
879            broadcast.putExtra(AudioManager.EXTRA_VIBRATE_SETTING, getVibrateSetting(vibrateType));
880            mContext.sendBroadcast(broadcast);
881        }
882    }
883
884    // Message helper methods
885    private static int getMsg(int baseMsg, int streamType) {
886        return (baseMsg & 0xffff) | streamType << 16;
887    }
888
889    private static int getMsgBase(int msg) {
890        return msg & 0xffff;
891    }
892
893    private static void sendMsg(Handler handler, int baseMsg, int streamType,
894            int existingMsgPolicy, int arg1, int arg2, Object obj, int delay) {
895        int msg = (streamType == SHARED_MSG) ? baseMsg : getMsg(baseMsg, streamType);
896
897        if (existingMsgPolicy == SENDMSG_REPLACE) {
898            handler.removeMessages(msg);
899        } else if (existingMsgPolicy == SENDMSG_NOOP && handler.hasMessages(msg)) {
900            return;
901        }
902
903        handler
904                .sendMessageDelayed(handler.obtainMessage(msg, arg1, arg2, obj), delay);
905    }
906
907    boolean checkAudioSettingsPermission(String method) {
908        if (mContext.checkCallingOrSelfPermission("android.permission.MODIFY_AUDIO_SETTINGS")
909                == PackageManager.PERMISSION_GRANTED) {
910            return true;
911        }
912        String msg = "Audio Settings Permission Denial: " + method + " from pid="
913                + Binder.getCallingPid()
914                + ", uid=" + Binder.getCallingUid();
915        Log.w(TAG, msg);
916        return false;
917    }
918
919
920    ///////////////////////////////////////////////////////////////////////////
921    // Inner classes
922    ///////////////////////////////////////////////////////////////////////////
923
924    public class VolumeStreamState {
925        private final String mVolumeIndexSettingName;
926        private final String mLastAudibleVolumeIndexSettingName;
927        private final int mStreamType;
928
929        private int mIndexMax;
930        private int mIndex;
931        private int mLastAudibleIndex;
932        private ArrayList<VolumeDeathHandler> mDeathHandlers; //handles mute/solo requests client death
933
934        private VolumeStreamState(String settingName, int streamType) {
935
936            mVolumeIndexSettingName = settingName;
937            mLastAudibleVolumeIndexSettingName = settingName + System.APPEND_FOR_LAST_AUDIBLE;
938
939            mStreamType = streamType;
940
941            final ContentResolver cr = mContentResolver;
942            mIndexMax = AudioManager.MAX_STREAM_VOLUME[streamType];
943            mIndex = Settings.System.getInt(cr,
944                                            mVolumeIndexSettingName,
945                                            AudioManager.DEFAULT_STREAM_VOLUME[streamType]);
946            mLastAudibleIndex = Settings.System.getInt(cr,
947                                                       mLastAudibleVolumeIndexSettingName,
948                                                       (mIndex > 0) ? mIndex : AudioManager.DEFAULT_STREAM_VOLUME[streamType]);
949            AudioSystem.initStreamVolume(streamType, 0, mIndexMax);
950            mIndexMax *= 10;
951            mIndex = getValidIndex(10 * mIndex);
952            mLastAudibleIndex = getValidIndex(10 * mLastAudibleIndex);
953            setStreamVolumeIndex(streamType, mIndex);
954            mDeathHandlers = new ArrayList<VolumeDeathHandler>();
955        }
956
957        public boolean adjustIndex(int deltaIndex) {
958            return setIndex(mIndex + deltaIndex * 10, true);
959        }
960
961        public boolean setIndex(int index, boolean lastAudible) {
962            int oldIndex = mIndex;
963            mIndex = getValidIndex(index);
964
965            if (oldIndex != mIndex) {
966                if (lastAudible) {
967                    mLastAudibleIndex = mIndex;
968                }
969                // Apply change to all streams using this one as alias
970                int numStreamTypes = AudioSystem.getNumStreamTypes();
971                for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
972                    if (streamType != mStreamType && STREAM_VOLUME_ALIAS[streamType] == mStreamType) {
973                        mStreamStates[streamType].setIndex(rescaleIndex(mIndex, mStreamType, streamType), lastAudible);
974                    }
975                }
976                return true;
977            } else {
978                return false;
979            }
980        }
981
982        public int getMaxIndex() {
983            return mIndexMax;
984        }
985
986        public void mute(IBinder cb, boolean state) {
987            VolumeDeathHandler handler = getDeathHandler(cb, state);
988            if (handler == null) {
989                Log.e(TAG, "Could not get client death handler for stream: "+mStreamType);
990                return;
991            }
992            handler.mute(state);
993        }
994
995        private int getValidIndex(int index) {
996            if (index < 0) {
997                return 0;
998            } else if (index > mIndexMax) {
999                return mIndexMax;
1000            }
1001
1002            return index;
1003        }
1004
1005        private class VolumeDeathHandler implements IBinder.DeathRecipient {
1006            private IBinder mICallback; // To be notified of client's death
1007            private int mMuteCount; // Number of active mutes for this client
1008
1009            VolumeDeathHandler(IBinder cb) {
1010                mICallback = cb;
1011            }
1012
1013            public void mute(boolean state) {
1014                synchronized(mDeathHandlers) {
1015                    if (state) {
1016                        if (mMuteCount == 0) {
1017                            // Register for client death notification
1018                            try {
1019                                mICallback.linkToDeath(this, 0);
1020                                mDeathHandlers.add(this);
1021                                // If the stream is not yet muted by any client, set lvel to 0
1022                                if (muteCount() == 0) {
1023                                    setIndex(0, false);
1024                                    sendMsg(mAudioHandler, MSG_SET_SYSTEM_VOLUME, mStreamType, SENDMSG_NOOP, 0, 0,
1025                                            VolumeStreamState.this, 0);
1026                                }
1027                            } catch (RemoteException e) {
1028                                // Client has died!
1029                                binderDied();
1030                                mDeathHandlers.notify();
1031                                return;
1032                            }
1033                        } else {
1034                            Log.w(TAG, "stream: "+mStreamType+" was already muted by this client");
1035                        }
1036                        mMuteCount++;
1037                    } else {
1038                        if (mMuteCount == 0) {
1039                            Log.e(TAG, "unexpected unmute for stream: "+mStreamType);
1040                        } else {
1041                            mMuteCount--;
1042                            if (mMuteCount == 0) {
1043                                // Unregistr from client death notification
1044                                mDeathHandlers.remove(this);
1045                                mICallback.unlinkToDeath(this, 0);
1046                                if (muteCount() == 0) {
1047                                    // If the stream is not mut any more, restore it's volume if
1048                                    // ringer mode allows it
1049                                    if (!isStreamAffectedByRingerMode(mStreamType) || mRingerMode == AudioManager.RINGER_MODE_NORMAL) {
1050                                        setIndex(mLastAudibleIndex, false);
1051                                        sendMsg(mAudioHandler, MSG_SET_SYSTEM_VOLUME, mStreamType, SENDMSG_NOOP, 0, 0,
1052                                                VolumeStreamState.this, 0);
1053                                    }
1054                                }
1055                            }
1056                        }
1057                    }
1058                    mDeathHandlers.notify();
1059                }
1060            }
1061
1062            public void binderDied() {
1063                Log.w(TAG, "Volume service client died for stream: "+mStreamType);
1064                if (mMuteCount != 0) {
1065                    // Reset all active mute requests from this client.
1066                    mMuteCount = 1;
1067                    mute(false);
1068                }
1069            }
1070        }
1071
1072        private int muteCount() {
1073            int count = 0;
1074            int size = mDeathHandlers.size();
1075            for (int i = 0; i < size; i++) {
1076                count += mDeathHandlers.get(i).mMuteCount;
1077            }
1078            return count;
1079        }
1080
1081        private VolumeDeathHandler getDeathHandler(IBinder cb, boolean state) {
1082            synchronized(mDeathHandlers) {
1083                VolumeDeathHandler handler;
1084                int size = mDeathHandlers.size();
1085                for (int i = 0; i < size; i++) {
1086                    handler = mDeathHandlers.get(i);
1087                    if (cb.equals(handler.mICallback)) {
1088                        return handler;
1089                    }
1090                }
1091                // If this is the first mute request for this client, create a new
1092                // client death handler. Otherwise, it is an out of sequence unmute request.
1093                if (state) {
1094                    handler = new VolumeDeathHandler(cb);
1095                } else {
1096                    Log.w(TAG, "stream was not muted by this client");
1097                    handler = null;
1098                }
1099                return handler;
1100            }
1101        }
1102    }
1103
1104    /** Thread that handles native AudioSystem control. */
1105    private class AudioSystemThread extends Thread {
1106        AudioSystemThread() {
1107            super("AudioService");
1108        }
1109
1110        @Override
1111        public void run() {
1112            // Set this thread up so the handler will work on it
1113            Looper.prepare();
1114
1115            synchronized(AudioService.this) {
1116                mAudioHandler = new AudioHandler();
1117
1118                // Notify that the handler has been created
1119                AudioService.this.notify();
1120            }
1121
1122            // Listen for volume change requests that are set by VolumePanel
1123            Looper.loop();
1124        }
1125    }
1126
1127    /** Handles internal volume messages in separate volume thread. */
1128    private class AudioHandler extends Handler {
1129
1130        private void setSystemVolume(VolumeStreamState streamState) {
1131
1132            // Adjust volume
1133            setStreamVolumeIndex(streamState.mStreamType, streamState.mIndex);
1134
1135            // Apply change to all streams using this one as alias
1136            int numStreamTypes = AudioSystem.getNumStreamTypes();
1137            for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
1138                if (streamType != streamState.mStreamType &&
1139                    STREAM_VOLUME_ALIAS[streamType] == streamState.mStreamType) {
1140                    setStreamVolumeIndex(streamType, mStreamStates[streamType].mIndex);
1141                }
1142            }
1143
1144            // Post a persist volume msg
1145            sendMsg(mAudioHandler, MSG_PERSIST_VOLUME, streamState.mStreamType,
1146                    SENDMSG_REPLACE, 0, 0, streamState, PERSIST_DELAY);
1147        }
1148
1149        private void persistVolume(VolumeStreamState streamState) {
1150            System.putInt(mContentResolver, streamState.mVolumeIndexSettingName,
1151                    (streamState.mIndex + 5)/ 10);
1152            System.putInt(mContentResolver, streamState.mLastAudibleVolumeIndexSettingName,
1153                    (streamState.mLastAudibleIndex + 5) / 10);
1154        }
1155
1156        private void persistRingerMode() {
1157            System.putInt(mContentResolver, System.MODE_RINGER, mRingerMode);
1158        }
1159
1160        private void persistVibrateSetting() {
1161            System.putInt(mContentResolver, System.VIBRATE_ON, mVibrateSetting);
1162        }
1163
1164        private void playSoundEffect(int effectType, int volume) {
1165            synchronized (mSoundEffectsLock) {
1166                if (mSoundPool == null) {
1167                    return;
1168                }
1169
1170                if (SOUND_EFFECT_FILES_MAP[effectType][1] > 0) {
1171                    float v = (float) volume / 1000.0f;
1172                    mSoundPool.play(SOUND_EFFECT_FILES_MAP[effectType][1], v, v, 0, 0, 1.0f);
1173                } else {
1174                    MediaPlayer mediaPlayer = new MediaPlayer();
1175                    if (mediaPlayer != null) {
1176                        try {
1177                            String filePath = Environment.getRootDirectory() + SOUND_EFFECTS_PATH + SOUND_EFFECT_FILES[SOUND_EFFECT_FILES_MAP[effectType][0]];
1178                            mediaPlayer.setDataSource(filePath);
1179                            mediaPlayer.setAudioStreamType(AudioSystem.STREAM_SYSTEM);
1180                            mediaPlayer.prepare();
1181                            mediaPlayer.setOnCompletionListener(new OnCompletionListener() {
1182                                public void onCompletion(MediaPlayer mp) {
1183                                    cleanupPlayer(mp);
1184                                }
1185                            });
1186                            mediaPlayer.setOnErrorListener(new OnErrorListener() {
1187                                public boolean onError(MediaPlayer mp, int what, int extra) {
1188                                    cleanupPlayer(mp);
1189                                    return true;
1190                                }
1191                            });
1192                            mediaPlayer.start();
1193                        } catch (IOException ex) {
1194                            Log.w(TAG, "MediaPlayer IOException: "+ex);
1195                        } catch (IllegalArgumentException ex) {
1196                            Log.w(TAG, "MediaPlayer IllegalArgumentException: "+ex);
1197                        } catch (IllegalStateException ex) {
1198                            Log.w(TAG, "MediaPlayer IllegalStateException: "+ex);
1199                        }
1200                    }
1201                }
1202            }
1203        }
1204
1205        private void cleanupPlayer(MediaPlayer mp) {
1206            if (mp != null) {
1207                try {
1208                    mp.stop();
1209                    mp.release();
1210                } catch (IllegalStateException ex) {
1211                    Log.w(TAG, "MediaPlayer IllegalStateException: "+ex);
1212                }
1213            }
1214        }
1215
1216        @Override
1217        public void handleMessage(Message msg) {
1218            int baseMsgWhat = getMsgBase(msg.what);
1219
1220            switch (baseMsgWhat) {
1221
1222                case MSG_SET_SYSTEM_VOLUME:
1223                    setSystemVolume((VolumeStreamState) msg.obj);
1224                    break;
1225
1226                case MSG_PERSIST_VOLUME:
1227                    persistVolume((VolumeStreamState) msg.obj);
1228                    break;
1229
1230                case MSG_PERSIST_RINGER_MODE:
1231                    persistRingerMode();
1232                    break;
1233
1234                case MSG_PERSIST_VIBRATE_SETTING:
1235                    persistVibrateSetting();
1236                    break;
1237
1238                case MSG_MEDIA_SERVER_DIED:
1239                    Log.e(TAG, "Media server died.");
1240                    // Force creation of new IAudioflinger interface
1241                    mMediaServerOk = false;
1242                    AudioSystem.isMusicActive();
1243                    break;
1244
1245                case MSG_MEDIA_SERVER_STARTED:
1246                    Log.e(TAG, "Media server started.");
1247                    // Restore device connection states
1248                    Set set = mConnectedDevices.entrySet();
1249                    Iterator i = set.iterator();
1250                    while(i.hasNext()){
1251                        Map.Entry device = (Map.Entry)i.next();
1252                        AudioSystem.setDeviceConnectionState(((Integer)device.getKey()).intValue(),
1253                                                             AudioSystem.DEVICE_STATE_AVAILABLE,
1254                                                             (String)device.getValue());
1255                    }
1256
1257                    // Restore call state
1258                    AudioSystem.setPhoneState(mMode);
1259
1260                    // Restore forced usage for communcations
1261                    AudioSystem.setForceUse(AudioSystem.FOR_COMMUNICATION, mForcedUseForComm);
1262
1263                    // Restore stream volumes
1264                    int numStreamTypes = AudioSystem.getNumStreamTypes();
1265                    for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
1266                        int index;
1267                        VolumeStreamState streamState = mStreamStates[streamType];
1268                        AudioSystem.initStreamVolume(streamType, 0, (streamState.mIndexMax + 5) / 10);
1269                        if (streamState.muteCount() == 0) {
1270                            index = streamState.mIndex;
1271                        } else {
1272                            index = 0;
1273                        }
1274                        setStreamVolumeIndex(streamType, index);
1275                    }
1276
1277                    // Restore ringer mode
1278                    setRingerModeInt(getRingerMode(), false);
1279
1280                    mMediaServerOk = true;
1281                    break;
1282
1283                case MSG_PLAY_SOUND_EFFECT:
1284                    playSoundEffect(msg.arg1, msg.arg2);
1285                    break;
1286            }
1287        }
1288    }
1289
1290    private class SettingsObserver extends ContentObserver {
1291
1292        SettingsObserver() {
1293            super(new Handler());
1294            mContentResolver.registerContentObserver(Settings.System.getUriFor(
1295                Settings.System.MODE_RINGER_STREAMS_AFFECTED), false, this);
1296            mContentResolver.registerContentObserver(Settings.System.getUriFor(
1297                    Settings.System.NOTIFICATIONS_USE_RING_VOLUME), false, this);
1298        }
1299
1300        @Override
1301        public void onChange(boolean selfChange) {
1302            super.onChange(selfChange);
1303            synchronized (mSettingsLock) {
1304                int ringerModeAffectedStreams = Settings.System.getInt(mContentResolver,
1305                        Settings.System.MODE_RINGER_STREAMS_AFFECTED,
1306                        0);
1307                if (ringerModeAffectedStreams != mRingerModeAffectedStreams) {
1308                    /*
1309                     * Ensure all stream types that should be affected by ringer mode
1310                     * are in the proper state.
1311                     */
1312                    mRingerModeAffectedStreams = ringerModeAffectedStreams;
1313                    setRingerModeInt(getRingerMode(), false);
1314                }
1315
1316                int notificationsUseRingVolume = Settings.System.getInt(mContentResolver,
1317                        Settings.System.NOTIFICATIONS_USE_RING_VOLUME,
1318                        1);
1319                if (notificationsUseRingVolume != mNotificationsUseRingVolume) {
1320                    mNotificationsUseRingVolume = notificationsUseRingVolume;
1321                    if (mNotificationsUseRingVolume == 1) {
1322                        STREAM_VOLUME_ALIAS[AudioSystem.STREAM_NOTIFICATION] = AudioSystem.STREAM_RING;
1323                    } else {
1324                        STREAM_VOLUME_ALIAS[AudioSystem.STREAM_NOTIFICATION] = AudioSystem.STREAM_NOTIFICATION;
1325                        // Persist notification volume volume as it was not persisted while aliased to ring volume
1326                        sendMsg(mAudioHandler, MSG_PERSIST_VOLUME, AudioSystem.STREAM_NOTIFICATION,
1327                                SENDMSG_REPLACE, 0, 0, mStreamStates[AudioSystem.STREAM_NOTIFICATION], PERSIST_DELAY);
1328                    }
1329                }
1330            }
1331        }
1332    }
1333
1334    /**
1335     * Receiver for misc intent broadcasts the Phone app cares about.
1336     */
1337    private class AudioServiceBroadcastReceiver extends BroadcastReceiver {
1338        @Override
1339        public void onReceive(Context context, Intent intent) {
1340            String action = intent.getAction();
1341
1342            if (action.equals(BluetoothA2dp.SINK_STATE_CHANGED_ACTION)) {
1343                int state = intent.getIntExtra(BluetoothA2dp.SINK_STATE,
1344                                               BluetoothA2dp.STATE_DISCONNECTED);
1345                String address = intent.getStringExtra(BluetoothIntent.ADDRESS);
1346                if (state == BluetoothA2dp.STATE_DISCONNECTED) {
1347                    AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
1348                            AudioSystem.DEVICE_STATE_UNAVAILABLE,
1349                            address);
1350                    mConnectedDevices.remove(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP);
1351                } else if (state == BluetoothA2dp.STATE_CONNECTED){
1352                    AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
1353                                                         AudioSystem.DEVICE_STATE_AVAILABLE,
1354                                                         address);
1355                    mConnectedDevices.put( new Integer(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP), address);
1356                }
1357            } else if (action.equals(BluetoothIntent.HEADSET_AUDIO_STATE_CHANGED_ACTION)) {
1358                int state = intent.getIntExtra(BluetoothIntent.HEADSET_AUDIO_STATE,
1359                                               BluetoothHeadset.STATE_ERROR);
1360                String address = intent.getStringExtra(BluetoothIntent.ADDRESS);
1361                if (state == BluetoothHeadset.AUDIO_STATE_DISCONNECTED) {
1362                    AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_BLUETOOTH_SCO,
1363                                                         AudioSystem.DEVICE_STATE_UNAVAILABLE,
1364                                                         address);
1365                    mConnectedDevices.remove(AudioSystem.DEVICE_OUT_BLUETOOTH_SCO);
1366                } else if (state == BluetoothHeadset.AUDIO_STATE_CONNECTED) {
1367                    AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_BLUETOOTH_SCO,
1368                                                         AudioSystem.DEVICE_STATE_AVAILABLE,
1369                                                         address);
1370                    mConnectedDevices.put( new Integer(AudioSystem.DEVICE_OUT_BLUETOOTH_SCO), address);
1371                }
1372            } else if (action.equals(Intent.ACTION_HEADSET_PLUG)) {
1373                int state = intent.getIntExtra("state", 0);
1374                if ((state & BIT_HEADSET) == 0 &&
1375                    (mHeadsetState & BIT_HEADSET) != 0) {
1376                    AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_WIRED_HEADSET,
1377                            AudioSystem.DEVICE_STATE_UNAVAILABLE,
1378                            "");
1379                    mConnectedDevices.remove(AudioSystem.DEVICE_OUT_WIRED_HEADSET);
1380                } else if ((state & BIT_HEADSET) != 0 &&
1381                    (mHeadsetState & BIT_HEADSET) == 0)  {
1382                    AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_WIRED_HEADSET,
1383                            AudioSystem.DEVICE_STATE_AVAILABLE,
1384                            "");
1385                    mConnectedDevices.put( new Integer(AudioSystem.DEVICE_OUT_WIRED_HEADSET), "");
1386                }
1387                if ((state & BIT_HEADSET_NO_MIC) == 0 &&
1388                    (mHeadsetState & BIT_HEADSET_NO_MIC) != 0) {
1389                    AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_WIRED_HEADPHONE,
1390                            AudioSystem.DEVICE_STATE_UNAVAILABLE,
1391                            "");
1392                    mConnectedDevices.remove(AudioSystem.DEVICE_OUT_WIRED_HEADPHONE);
1393                } else if ((state & BIT_HEADSET_NO_MIC) != 0 &&
1394                    (mHeadsetState & BIT_HEADSET_NO_MIC) == 0)  {
1395                    AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_WIRED_HEADPHONE,
1396                            AudioSystem.DEVICE_STATE_AVAILABLE,
1397                            "");
1398                    mConnectedDevices.put( new Integer(AudioSystem.DEVICE_OUT_WIRED_HEADPHONE), "");
1399                }
1400                if ((state & BIT_TTY) == 0 &&
1401                    (mHeadsetState & BIT_TTY) != 0) {
1402                    AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_TTY,
1403                            AudioSystem.DEVICE_STATE_UNAVAILABLE,
1404                            "");
1405                    mConnectedDevices.remove(AudioSystem.DEVICE_OUT_TTY);
1406                } else if ((state & BIT_TTY) != 0 &&
1407                    (mHeadsetState & BIT_TTY) == 0)  {
1408                    AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_TTY,
1409                            AudioSystem.DEVICE_STATE_AVAILABLE,
1410                            "");
1411                    mConnectedDevices.put( new Integer(AudioSystem.DEVICE_OUT_TTY), "");
1412                }
1413                if ((state & BIT_FM_HEADSET) == 0 &&
1414                    (mHeadsetState & BIT_FM_HEADSET) != 0) {
1415                    AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_FM_HEADPHONE,
1416                            AudioSystem.DEVICE_STATE_UNAVAILABLE,
1417                            "");
1418                    mConnectedDevices.remove(AudioSystem.DEVICE_OUT_FM_HEADPHONE);
1419                } else if ((state & BIT_FM_HEADSET) != 0 &&
1420                    (mHeadsetState & BIT_FM_HEADSET) == 0)  {
1421                    AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_FM_HEADPHONE,
1422                            AudioSystem.DEVICE_STATE_AVAILABLE,
1423                            "");
1424                    mConnectedDevices.put( new Integer(AudioSystem.DEVICE_OUT_FM_HEADPHONE), "");
1425                }
1426                if ((state & BIT_FM_SPEAKER) == 0 &&
1427                    (mHeadsetState & BIT_FM_SPEAKER) != 0) {
1428                    AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_FM_SPEAKER,
1429                            AudioSystem.DEVICE_STATE_UNAVAILABLE,
1430                            "");
1431                    mConnectedDevices.remove(AudioSystem.DEVICE_OUT_FM_SPEAKER);
1432                } else if ((state & BIT_FM_SPEAKER) != 0 &&
1433                    (mHeadsetState & BIT_FM_SPEAKER) == 0)  {
1434                    AudioSystem.setDeviceConnectionState(AudioSystem.DEVICE_OUT_FM_SPEAKER,
1435                            AudioSystem.DEVICE_STATE_AVAILABLE,
1436                            "");
1437                    mConnectedDevices.put( new Integer(AudioSystem.DEVICE_OUT_FM_SPEAKER), "");
1438                }
1439                mHeadsetState = state;
1440            }
1441        }
1442    }
1443
1444
1445}
1446