1/*
2 * Copyright (C) 2012 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 com.android.inputmethod.latin;
18
19import android.content.Context;
20import android.media.AudioManager;
21import android.os.Vibrator;
22import android.view.HapticFeedbackConstants;
23import android.view.View;
24
25import com.android.inputmethod.latin.common.Constants;
26import com.android.inputmethod.latin.settings.SettingsValues;
27
28/**
29 * This class gathers audio feedback and haptic feedback functions.
30 *
31 * It offers a consistent and simple interface that allows LatinIME to forget about the
32 * complexity of settings and the like.
33 */
34public final class AudioAndHapticFeedbackManager {
35    private AudioManager mAudioManager;
36    private Vibrator mVibrator;
37
38    private SettingsValues mSettingsValues;
39    private boolean mSoundOn;
40
41    private static final AudioAndHapticFeedbackManager sInstance =
42            new AudioAndHapticFeedbackManager();
43
44    public static AudioAndHapticFeedbackManager getInstance() {
45        return sInstance;
46    }
47
48    private AudioAndHapticFeedbackManager() {
49        // Intentional empty constructor for singleton.
50    }
51
52    public static void init(final Context context) {
53        sInstance.initInternal(context);
54    }
55
56    private void initInternal(final Context context) {
57        mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
58        mVibrator = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE);
59    }
60
61    public void performHapticAndAudioFeedback(final int code,
62            final View viewToPerformHapticFeedbackOn) {
63        performHapticFeedback(viewToPerformHapticFeedbackOn);
64        performAudioFeedback(code);
65    }
66
67    public boolean hasVibrator() {
68        return mVibrator != null && mVibrator.hasVibrator();
69    }
70
71    public void vibrate(final long milliseconds) {
72        if (mVibrator == null) {
73            return;
74        }
75        mVibrator.vibrate(milliseconds);
76    }
77
78    private boolean reevaluateIfSoundIsOn() {
79        if (mSettingsValues == null || !mSettingsValues.mSoundOn || mAudioManager == null) {
80            return false;
81        }
82        return mAudioManager.getRingerMode() == AudioManager.RINGER_MODE_NORMAL;
83    }
84
85    public void performAudioFeedback(final int code) {
86        // if mAudioManager is null, we can't play a sound anyway, so return
87        if (mAudioManager == null) {
88            return;
89        }
90        if (!mSoundOn) {
91            return;
92        }
93        final int sound;
94        switch (code) {
95        case Constants.CODE_DELETE:
96            sound = AudioManager.FX_KEYPRESS_DELETE;
97            break;
98        case Constants.CODE_ENTER:
99            sound = AudioManager.FX_KEYPRESS_RETURN;
100            break;
101        case Constants.CODE_SPACE:
102            sound = AudioManager.FX_KEYPRESS_SPACEBAR;
103            break;
104        default:
105            sound = AudioManager.FX_KEYPRESS_STANDARD;
106            break;
107        }
108        mAudioManager.playSoundEffect(sound, mSettingsValues.mKeypressSoundVolume);
109    }
110
111    public void performHapticFeedback(final View viewToPerformHapticFeedbackOn) {
112        if (!mSettingsValues.mVibrateOn) {
113            return;
114        }
115        if (mSettingsValues.mKeypressVibrationDuration >= 0) {
116            vibrate(mSettingsValues.mKeypressVibrationDuration);
117            return;
118        }
119        // Go ahead with the system default
120        if (viewToPerformHapticFeedbackOn != null) {
121            viewToPerformHapticFeedbackOn.performHapticFeedback(
122                    HapticFeedbackConstants.KEYBOARD_TAP,
123                    HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING);
124        }
125    }
126
127    public void onSettingsChanged(final SettingsValues settingsValues) {
128        mSettingsValues = settingsValues;
129        mSoundOn = reevaluateIfSoundIsOn();
130    }
131
132    public void onRingerModeChanged() {
133        mSoundOn = reevaluateIfSoundIsOn();
134    }
135}
136