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