1564496bad6207f02e7a653872213bc5954e84ce4Jean Chalard/*
2564496bad6207f02e7a653872213bc5954e84ce4Jean Chalard * Copyright (C) 2012 The Android Open Source Project
3564496bad6207f02e7a653872213bc5954e84ce4Jean Chalard *
48aa9963a895f9dd5bb1bc92ab2e4f461e058f87aTadashi G. Takaoka * Licensed under the Apache License, Version 2.0 (the "License");
58aa9963a895f9dd5bb1bc92ab2e4f461e058f87aTadashi G. Takaoka * you may not use this file except in compliance with the License.
68aa9963a895f9dd5bb1bc92ab2e4f461e058f87aTadashi G. Takaoka * You may obtain a copy of the License at
7564496bad6207f02e7a653872213bc5954e84ce4Jean Chalard *
88aa9963a895f9dd5bb1bc92ab2e4f461e058f87aTadashi G. Takaoka *      http://www.apache.org/licenses/LICENSE-2.0
9564496bad6207f02e7a653872213bc5954e84ce4Jean Chalard *
10564496bad6207f02e7a653872213bc5954e84ce4Jean Chalard * Unless required by applicable law or agreed to in writing, software
118aa9963a895f9dd5bb1bc92ab2e4f461e058f87aTadashi G. Takaoka * distributed under the License is distributed on an "AS IS" BASIS,
128aa9963a895f9dd5bb1bc92ab2e4f461e058f87aTadashi G. Takaoka * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
138aa9963a895f9dd5bb1bc92ab2e4f461e058f87aTadashi G. Takaoka * See the License for the specific language governing permissions and
148aa9963a895f9dd5bb1bc92ab2e4f461e058f87aTadashi G. Takaoka * limitations under the License.
15564496bad6207f02e7a653872213bc5954e84ce4Jean Chalard */
16564496bad6207f02e7a653872213bc5954e84ce4Jean Chalard
17564496bad6207f02e7a653872213bc5954e84ce4Jean Chalardpackage com.android.inputmethod.latin;
18564496bad6207f02e7a653872213bc5954e84ce4Jean Chalard
19564496bad6207f02e7a653872213bc5954e84ce4Jean Chalardimport android.content.Context;
20564496bad6207f02e7a653872213bc5954e84ce4Jean Chalardimport android.media.AudioManager;
21b17b88742528d09eaa36adb3dae5348b99c234e0Tadashi G. Takaokaimport android.os.Vibrator;
22564496bad6207f02e7a653872213bc5954e84ce4Jean Chalardimport android.view.HapticFeedbackConstants;
23544c3c29527927239a6484efc30bc22f9cc4dad1Jean Chalardimport android.view.View;
24564496bad6207f02e7a653872213bc5954e84ce4Jean Chalard
259342484e8d573a40f470b6a593df31c602fa4076Ken Wakasaimport com.android.inputmethod.latin.common.Constants;
26874a600dc805b6ab9fe92fccddfe4765b8d29a35Tadashi G. Takaokaimport com.android.inputmethod.latin.settings.SettingsValues;
27874a600dc805b6ab9fe92fccddfe4765b8d29a35Tadashi G. Takaoka
28564496bad6207f02e7a653872213bc5954e84ce4Jean Chalard/**
29564496bad6207f02e7a653872213bc5954e84ce4Jean Chalard * This class gathers audio feedback and haptic feedback functions.
30564496bad6207f02e7a653872213bc5954e84ce4Jean Chalard *
31564496bad6207f02e7a653872213bc5954e84ce4Jean Chalard * It offers a consistent and simple interface that allows LatinIME to forget about the
32564496bad6207f02e7a653872213bc5954e84ce4Jean Chalard * complexity of settings and the like.
33564496bad6207f02e7a653872213bc5954e84ce4Jean Chalard */
34a28a05e971cc242b338331a3b78276fa95188d19Tadashi G. Takaokapublic final class AudioAndHapticFeedbackManager {
35b17b88742528d09eaa36adb3dae5348b99c234e0Tadashi G. Takaoka    private AudioManager mAudioManager;
36b17b88742528d09eaa36adb3dae5348b99c234e0Tadashi G. Takaoka    private Vibrator mVibrator;
378e360c68f1861a70fdb91652334efa513e25fcd2Tadashi G. Takaoka
388e360c68f1861a70fdb91652334efa513e25fcd2Tadashi G. Takaoka    private SettingsValues mSettingsValues;
392651b17fc4fb4457deb5078114b26d3a1ec66799Jean Chalard    private boolean mSoundOn;
40564496bad6207f02e7a653872213bc5954e84ce4Jean Chalard
41b17b88742528d09eaa36adb3dae5348b99c234e0Tadashi G. Takaoka    private static final AudioAndHapticFeedbackManager sInstance =
42b17b88742528d09eaa36adb3dae5348b99c234e0Tadashi G. Takaoka            new AudioAndHapticFeedbackManager();
43b17b88742528d09eaa36adb3dae5348b99c234e0Tadashi G. Takaoka
44b17b88742528d09eaa36adb3dae5348b99c234e0Tadashi G. Takaoka    public static AudioAndHapticFeedbackManager getInstance() {
45b17b88742528d09eaa36adb3dae5348b99c234e0Tadashi G. Takaoka        return sInstance;
46b17b88742528d09eaa36adb3dae5348b99c234e0Tadashi G. Takaoka    }
47b17b88742528d09eaa36adb3dae5348b99c234e0Tadashi G. Takaoka
48b17b88742528d09eaa36adb3dae5348b99c234e0Tadashi G. Takaoka    private AudioAndHapticFeedbackManager() {
49b17b88742528d09eaa36adb3dae5348b99c234e0Tadashi G. Takaoka        // Intentional empty constructor for singleton.
50b17b88742528d09eaa36adb3dae5348b99c234e0Tadashi G. Takaoka    }
51b17b88742528d09eaa36adb3dae5348b99c234e0Tadashi G. Takaoka
52b17b88742528d09eaa36adb3dae5348b99c234e0Tadashi G. Takaoka    public static void init(final Context context) {
53b17b88742528d09eaa36adb3dae5348b99c234e0Tadashi G. Takaoka        sInstance.initInternal(context);
54b17b88742528d09eaa36adb3dae5348b99c234e0Tadashi G. Takaoka    }
55b17b88742528d09eaa36adb3dae5348b99c234e0Tadashi G. Takaoka
56b17b88742528d09eaa36adb3dae5348b99c234e0Tadashi G. Takaoka    private void initInternal(final Context context) {
57b17b88742528d09eaa36adb3dae5348b99c234e0Tadashi G. Takaoka        mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
58b17b88742528d09eaa36adb3dae5348b99c234e0Tadashi G. Takaoka        mVibrator = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE);
59564496bad6207f02e7a653872213bc5954e84ce4Jean Chalard    }
60564496bad6207f02e7a653872213bc5954e84ce4Jean Chalard
61ab16237e69061bb0aa7f882e48e5d93459c22ef3Tadashi G. Takaoka    public void performHapticAndAudioFeedback(final int code,
62544c3c29527927239a6484efc30bc22f9cc4dad1Jean Chalard            final View viewToPerformHapticFeedbackOn) {
63ab16237e69061bb0aa7f882e48e5d93459c22ef3Tadashi G. Takaoka        performHapticFeedback(viewToPerformHapticFeedbackOn);
64ab16237e69061bb0aa7f882e48e5d93459c22ef3Tadashi G. Takaoka        performAudioFeedback(code);
65564496bad6207f02e7a653872213bc5954e84ce4Jean Chalard    }
66564496bad6207f02e7a653872213bc5954e84ce4Jean Chalard
67b17b88742528d09eaa36adb3dae5348b99c234e0Tadashi G. Takaoka    public boolean hasVibrator() {
68b17b88742528d09eaa36adb3dae5348b99c234e0Tadashi G. Takaoka        return mVibrator != null && mVibrator.hasVibrator();
69b17b88742528d09eaa36adb3dae5348b99c234e0Tadashi G. Takaoka    }
70b17b88742528d09eaa36adb3dae5348b99c234e0Tadashi G. Takaoka
71b17b88742528d09eaa36adb3dae5348b99c234e0Tadashi G. Takaoka    public void vibrate(final long milliseconds) {
72b17b88742528d09eaa36adb3dae5348b99c234e0Tadashi G. Takaoka        if (mVibrator == null) {
73b17b88742528d09eaa36adb3dae5348b99c234e0Tadashi G. Takaoka            return;
74b17b88742528d09eaa36adb3dae5348b99c234e0Tadashi G. Takaoka        }
75b17b88742528d09eaa36adb3dae5348b99c234e0Tadashi G. Takaoka        mVibrator.vibrate(milliseconds);
76b17b88742528d09eaa36adb3dae5348b99c234e0Tadashi G. Takaoka    }
77b17b88742528d09eaa36adb3dae5348b99c234e0Tadashi G. Takaoka
78bdbb22bb3315bc22e1641fb8ecd150fc2de4a19dJean Chalard    private boolean reevaluateIfSoundIsOn() {
798e360c68f1861a70fdb91652334efa513e25fcd2Tadashi G. Takaoka        if (mSettingsValues == null || !mSettingsValues.mSoundOn || mAudioManager == null) {
80bdbb22bb3315bc22e1641fb8ecd150fc2de4a19dJean Chalard            return false;
81564496bad6207f02e7a653872213bc5954e84ce4Jean Chalard        }
82b17b88742528d09eaa36adb3dae5348b99c234e0Tadashi G. Takaoka        return mAudioManager.getRingerMode() == AudioManager.RINGER_MODE_NORMAL;
83564496bad6207f02e7a653872213bc5954e84ce4Jean Chalard    }
84564496bad6207f02e7a653872213bc5954e84ce4Jean Chalard
85ab16237e69061bb0aa7f882e48e5d93459c22ef3Tadashi G. Takaoka    public void performAudioFeedback(final int code) {
86793791cdf0d54a55a73f931ffe3c62590c881f1eJean Chalard        // if mAudioManager is null, we can't play a sound anyway, so return
87b17b88742528d09eaa36adb3dae5348b99c234e0Tadashi G. Takaoka        if (mAudioManager == null) {
88b17b88742528d09eaa36adb3dae5348b99c234e0Tadashi G. Takaoka            return;
89b17b88742528d09eaa36adb3dae5348b99c234e0Tadashi G. Takaoka        }
90874a600dc805b6ab9fe92fccddfe4765b8d29a35Tadashi G. Takaoka        if (!mSoundOn) {
91874a600dc805b6ab9fe92fccddfe4765b8d29a35Tadashi G. Takaoka            return;
92874a600dc805b6ab9fe92fccddfe4765b8d29a35Tadashi G. Takaoka        }
93874a600dc805b6ab9fe92fccddfe4765b8d29a35Tadashi G. Takaoka        final int sound;
94874a600dc805b6ab9fe92fccddfe4765b8d29a35Tadashi G. Takaoka        switch (code) {
95874a600dc805b6ab9fe92fccddfe4765b8d29a35Tadashi G. Takaoka        case Constants.CODE_DELETE:
96874a600dc805b6ab9fe92fccddfe4765b8d29a35Tadashi G. Takaoka            sound = AudioManager.FX_KEYPRESS_DELETE;
97874a600dc805b6ab9fe92fccddfe4765b8d29a35Tadashi G. Takaoka            break;
98874a600dc805b6ab9fe92fccddfe4765b8d29a35Tadashi G. Takaoka        case Constants.CODE_ENTER:
99874a600dc805b6ab9fe92fccddfe4765b8d29a35Tadashi G. Takaoka            sound = AudioManager.FX_KEYPRESS_RETURN;
100874a600dc805b6ab9fe92fccddfe4765b8d29a35Tadashi G. Takaoka            break;
101874a600dc805b6ab9fe92fccddfe4765b8d29a35Tadashi G. Takaoka        case Constants.CODE_SPACE:
102874a600dc805b6ab9fe92fccddfe4765b8d29a35Tadashi G. Takaoka            sound = AudioManager.FX_KEYPRESS_SPACEBAR;
103874a600dc805b6ab9fe92fccddfe4765b8d29a35Tadashi G. Takaoka            break;
104874a600dc805b6ab9fe92fccddfe4765b8d29a35Tadashi G. Takaoka        default:
105874a600dc805b6ab9fe92fccddfe4765b8d29a35Tadashi G. Takaoka            sound = AudioManager.FX_KEYPRESS_STANDARD;
106874a600dc805b6ab9fe92fccddfe4765b8d29a35Tadashi G. Takaoka            break;
107564496bad6207f02e7a653872213bc5954e84ce4Jean Chalard        }
108874a600dc805b6ab9fe92fccddfe4765b8d29a35Tadashi G. Takaoka        mAudioManager.playSoundEffect(sound, mSettingsValues.mKeypressSoundVolume);
109564496bad6207f02e7a653872213bc5954e84ce4Jean Chalard    }
110564496bad6207f02e7a653872213bc5954e84ce4Jean Chalard
111ab16237e69061bb0aa7f882e48e5d93459c22ef3Tadashi G. Takaoka    public void performHapticFeedback(final View viewToPerformHapticFeedbackOn) {
112564496bad6207f02e7a653872213bc5954e84ce4Jean Chalard        if (!mSettingsValues.mVibrateOn) {
113564496bad6207f02e7a653872213bc5954e84ce4Jean Chalard            return;
114564496bad6207f02e7a653872213bc5954e84ce4Jean Chalard        }
115874a600dc805b6ab9fe92fccddfe4765b8d29a35Tadashi G. Takaoka        if (mSettingsValues.mKeypressVibrationDuration >= 0) {
116874a600dc805b6ab9fe92fccddfe4765b8d29a35Tadashi G. Takaoka            vibrate(mSettingsValues.mKeypressVibrationDuration);
117b17b88742528d09eaa36adb3dae5348b99c234e0Tadashi G. Takaoka            return;
118564496bad6207f02e7a653872213bc5954e84ce4Jean Chalard        }
119874a600dc805b6ab9fe92fccddfe4765b8d29a35Tadashi G. Takaoka        // Go ahead with the system default
120874a600dc805b6ab9fe92fccddfe4765b8d29a35Tadashi G. Takaoka        if (viewToPerformHapticFeedbackOn != null) {
121874a600dc805b6ab9fe92fccddfe4765b8d29a35Tadashi G. Takaoka            viewToPerformHapticFeedbackOn.performHapticFeedback(
122874a600dc805b6ab9fe92fccddfe4765b8d29a35Tadashi G. Takaoka                    HapticFeedbackConstants.KEYBOARD_TAP,
123874a600dc805b6ab9fe92fccddfe4765b8d29a35Tadashi G. Takaoka                    HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING);
124874a600dc805b6ab9fe92fccddfe4765b8d29a35Tadashi G. Takaoka        }
125564496bad6207f02e7a653872213bc5954e84ce4Jean Chalard    }
126564496bad6207f02e7a653872213bc5954e84ce4Jean Chalard
1278e360c68f1861a70fdb91652334efa513e25fcd2Tadashi G. Takaoka    public void onSettingsChanged(final SettingsValues settingsValues) {
1288e360c68f1861a70fdb91652334efa513e25fcd2Tadashi G. Takaoka        mSettingsValues = settingsValues;
1298e360c68f1861a70fdb91652334efa513e25fcd2Tadashi G. Takaoka        mSoundOn = reevaluateIfSoundIsOn();
1308e360c68f1861a70fdb91652334efa513e25fcd2Tadashi G. Takaoka    }
1318e360c68f1861a70fdb91652334efa513e25fcd2Tadashi G. Takaoka
13221af2f40c59de3ea5ec183aa278406bf28d5e3bdJean Chalard    public void onRingerModeChanged() {
13321af2f40c59de3ea5ec183aa278406bf28d5e3bdJean Chalard        mSoundOn = reevaluateIfSoundIsOn();
134564496bad6207f02e7a653872213bc5954e84ce4Jean Chalard    }
135564496bad6207f02e7a653872213bc5954e84ce4Jean Chalard}
136