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 25564496bad6207f02e7a653872213bc5954e84ce4Jean Chalard/** 26564496bad6207f02e7a653872213bc5954e84ce4Jean Chalard * This class gathers audio feedback and haptic feedback functions. 27564496bad6207f02e7a653872213bc5954e84ce4Jean Chalard * 28564496bad6207f02e7a653872213bc5954e84ce4Jean Chalard * It offers a consistent and simple interface that allows LatinIME to forget about the 29564496bad6207f02e7a653872213bc5954e84ce4Jean Chalard * complexity of settings and the like. 30564496bad6207f02e7a653872213bc5954e84ce4Jean Chalard */ 31a28a05e971cc242b338331a3b78276fa95188d19Tadashi G. Takaokapublic final class AudioAndHapticFeedbackManager { 32b17b88742528d09eaa36adb3dae5348b99c234e0Tadashi G. Takaoka private AudioManager mAudioManager; 33b17b88742528d09eaa36adb3dae5348b99c234e0Tadashi G. Takaoka private Vibrator mVibrator; 348e360c68f1861a70fdb91652334efa513e25fcd2Tadashi G. Takaoka 358e360c68f1861a70fdb91652334efa513e25fcd2Tadashi G. Takaoka private SettingsValues mSettingsValues; 362651b17fc4fb4457deb5078114b26d3a1ec66799Jean Chalard private boolean mSoundOn; 37564496bad6207f02e7a653872213bc5954e84ce4Jean Chalard 38b17b88742528d09eaa36adb3dae5348b99c234e0Tadashi G. Takaoka private static final AudioAndHapticFeedbackManager sInstance = 39b17b88742528d09eaa36adb3dae5348b99c234e0Tadashi G. Takaoka new AudioAndHapticFeedbackManager(); 40b17b88742528d09eaa36adb3dae5348b99c234e0Tadashi G. Takaoka 41b17b88742528d09eaa36adb3dae5348b99c234e0Tadashi G. Takaoka public static AudioAndHapticFeedbackManager getInstance() { 42b17b88742528d09eaa36adb3dae5348b99c234e0Tadashi G. Takaoka return sInstance; 43b17b88742528d09eaa36adb3dae5348b99c234e0Tadashi G. Takaoka } 44b17b88742528d09eaa36adb3dae5348b99c234e0Tadashi G. Takaoka 45b17b88742528d09eaa36adb3dae5348b99c234e0Tadashi G. Takaoka private AudioAndHapticFeedbackManager() { 46b17b88742528d09eaa36adb3dae5348b99c234e0Tadashi G. Takaoka // Intentional empty constructor for singleton. 47b17b88742528d09eaa36adb3dae5348b99c234e0Tadashi G. Takaoka } 48b17b88742528d09eaa36adb3dae5348b99c234e0Tadashi G. Takaoka 49b17b88742528d09eaa36adb3dae5348b99c234e0Tadashi G. Takaoka public static void init(final Context context) { 50b17b88742528d09eaa36adb3dae5348b99c234e0Tadashi G. Takaoka sInstance.initInternal(context); 51b17b88742528d09eaa36adb3dae5348b99c234e0Tadashi G. Takaoka } 52b17b88742528d09eaa36adb3dae5348b99c234e0Tadashi G. Takaoka 53b17b88742528d09eaa36adb3dae5348b99c234e0Tadashi G. Takaoka private void initInternal(final Context context) { 54b17b88742528d09eaa36adb3dae5348b99c234e0Tadashi G. Takaoka mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE); 55b17b88742528d09eaa36adb3dae5348b99c234e0Tadashi G. Takaoka mVibrator = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE); 56564496bad6207f02e7a653872213bc5954e84ce4Jean Chalard } 57564496bad6207f02e7a653872213bc5954e84ce4Jean Chalard 58544c3c29527927239a6484efc30bc22f9cc4dad1Jean Chalard public void hapticAndAudioFeedback(final int primaryCode, 59544c3c29527927239a6484efc30bc22f9cc4dad1Jean Chalard final View viewToPerformHapticFeedbackOn) { 60b17b88742528d09eaa36adb3dae5348b99c234e0Tadashi G. Takaoka vibrateInternal(viewToPerformHapticFeedbackOn); 61564496bad6207f02e7a653872213bc5954e84ce4Jean Chalard playKeyClick(primaryCode); 62564496bad6207f02e7a653872213bc5954e84ce4Jean Chalard } 63564496bad6207f02e7a653872213bc5954e84ce4Jean Chalard 64b17b88742528d09eaa36adb3dae5348b99c234e0Tadashi G. Takaoka public boolean hasVibrator() { 65b17b88742528d09eaa36adb3dae5348b99c234e0Tadashi G. Takaoka return mVibrator != null && mVibrator.hasVibrator(); 66b17b88742528d09eaa36adb3dae5348b99c234e0Tadashi G. Takaoka } 67b17b88742528d09eaa36adb3dae5348b99c234e0Tadashi G. Takaoka 68b17b88742528d09eaa36adb3dae5348b99c234e0Tadashi G. Takaoka public void vibrate(final long milliseconds) { 69b17b88742528d09eaa36adb3dae5348b99c234e0Tadashi G. Takaoka if (mVibrator == null) { 70b17b88742528d09eaa36adb3dae5348b99c234e0Tadashi G. Takaoka return; 71b17b88742528d09eaa36adb3dae5348b99c234e0Tadashi G. Takaoka } 72b17b88742528d09eaa36adb3dae5348b99c234e0Tadashi G. Takaoka mVibrator.vibrate(milliseconds); 73b17b88742528d09eaa36adb3dae5348b99c234e0Tadashi G. Takaoka } 74b17b88742528d09eaa36adb3dae5348b99c234e0Tadashi G. Takaoka 75bdbb22bb3315bc22e1641fb8ecd150fc2de4a19dJean Chalard private boolean reevaluateIfSoundIsOn() { 768e360c68f1861a70fdb91652334efa513e25fcd2Tadashi G. Takaoka if (mSettingsValues == null || !mSettingsValues.mSoundOn || mAudioManager == null) { 77bdbb22bb3315bc22e1641fb8ecd150fc2de4a19dJean Chalard return false; 78564496bad6207f02e7a653872213bc5954e84ce4Jean Chalard } 79b17b88742528d09eaa36adb3dae5348b99c234e0Tadashi G. Takaoka return mAudioManager.getRingerMode() == AudioManager.RINGER_MODE_NORMAL; 80564496bad6207f02e7a653872213bc5954e84ce4Jean Chalard } 81564496bad6207f02e7a653872213bc5954e84ce4Jean Chalard 82b17b88742528d09eaa36adb3dae5348b99c234e0Tadashi G. Takaoka private void playKeyClick(final int primaryCode) { 83793791cdf0d54a55a73f931ffe3c62590c881f1eJean Chalard // if mAudioManager is null, we can't play a sound anyway, so return 84b17b88742528d09eaa36adb3dae5348b99c234e0Tadashi G. Takaoka if (mAudioManager == null) { 85b17b88742528d09eaa36adb3dae5348b99c234e0Tadashi G. Takaoka return; 86b17b88742528d09eaa36adb3dae5348b99c234e0Tadashi G. Takaoka } 87bdbb22bb3315bc22e1641fb8ecd150fc2de4a19dJean Chalard if (mSoundOn) { 88564496bad6207f02e7a653872213bc5954e84ce4Jean Chalard final int sound; 89564496bad6207f02e7a653872213bc5954e84ce4Jean Chalard switch (primaryCode) { 90240871ecafde7834ebb4270cd7758fc904a5f3a7Tadashi G. Takaoka case Constants.CODE_DELETE: 91564496bad6207f02e7a653872213bc5954e84ce4Jean Chalard sound = AudioManager.FX_KEYPRESS_DELETE; 92564496bad6207f02e7a653872213bc5954e84ce4Jean Chalard break; 93240871ecafde7834ebb4270cd7758fc904a5f3a7Tadashi G. Takaoka case Constants.CODE_ENTER: 94564496bad6207f02e7a653872213bc5954e84ce4Jean Chalard sound = AudioManager.FX_KEYPRESS_RETURN; 95564496bad6207f02e7a653872213bc5954e84ce4Jean Chalard break; 96240871ecafde7834ebb4270cd7758fc904a5f3a7Tadashi G. Takaoka case Constants.CODE_SPACE: 97564496bad6207f02e7a653872213bc5954e84ce4Jean Chalard sound = AudioManager.FX_KEYPRESS_SPACEBAR; 98564496bad6207f02e7a653872213bc5954e84ce4Jean Chalard break; 99564496bad6207f02e7a653872213bc5954e84ce4Jean Chalard default: 100564496bad6207f02e7a653872213bc5954e84ce4Jean Chalard sound = AudioManager.FX_KEYPRESS_STANDARD; 101564496bad6207f02e7a653872213bc5954e84ce4Jean Chalard break; 102564496bad6207f02e7a653872213bc5954e84ce4Jean Chalard } 103d3b0ecec22cda883150851dced32c1eda2910a66Tadashi G. Takaoka mAudioManager.playSoundEffect(sound, mSettingsValues.mKeypressSoundVolume); 104564496bad6207f02e7a653872213bc5954e84ce4Jean Chalard } 105564496bad6207f02e7a653872213bc5954e84ce4Jean Chalard } 106564496bad6207f02e7a653872213bc5954e84ce4Jean Chalard 107b17b88742528d09eaa36adb3dae5348b99c234e0Tadashi G. Takaoka private void vibrateInternal(final View viewToPerformHapticFeedbackOn) { 108564496bad6207f02e7a653872213bc5954e84ce4Jean Chalard if (!mSettingsValues.mVibrateOn) { 109564496bad6207f02e7a653872213bc5954e84ce4Jean Chalard return; 110564496bad6207f02e7a653872213bc5954e84ce4Jean Chalard } 111564496bad6207f02e7a653872213bc5954e84ce4Jean Chalard if (mSettingsValues.mKeypressVibrationDuration < 0) { 112564496bad6207f02e7a653872213bc5954e84ce4Jean Chalard // Go ahead with the system default 113544c3c29527927239a6484efc30bc22f9cc4dad1Jean Chalard if (viewToPerformHapticFeedbackOn != null) { 114544c3c29527927239a6484efc30bc22f9cc4dad1Jean Chalard viewToPerformHapticFeedbackOn.performHapticFeedback( 115564496bad6207f02e7a653872213bc5954e84ce4Jean Chalard HapticFeedbackConstants.KEYBOARD_TAP, 116564496bad6207f02e7a653872213bc5954e84ce4Jean Chalard HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING); 117564496bad6207f02e7a653872213bc5954e84ce4Jean Chalard } 118b17b88742528d09eaa36adb3dae5348b99c234e0Tadashi G. Takaoka return; 119564496bad6207f02e7a653872213bc5954e84ce4Jean Chalard } 120b17b88742528d09eaa36adb3dae5348b99c234e0Tadashi G. Takaoka vibrate(mSettingsValues.mKeypressVibrationDuration); 121564496bad6207f02e7a653872213bc5954e84ce4Jean Chalard } 122564496bad6207f02e7a653872213bc5954e84ce4Jean Chalard 1238e360c68f1861a70fdb91652334efa513e25fcd2Tadashi G. Takaoka public void onSettingsChanged(final SettingsValues settingsValues) { 1248e360c68f1861a70fdb91652334efa513e25fcd2Tadashi G. Takaoka mSettingsValues = settingsValues; 1258e360c68f1861a70fdb91652334efa513e25fcd2Tadashi G. Takaoka mSoundOn = reevaluateIfSoundIsOn(); 1268e360c68f1861a70fdb91652334efa513e25fcd2Tadashi G. Takaoka } 1278e360c68f1861a70fdb91652334efa513e25fcd2Tadashi G. Takaoka 12821af2f40c59de3ea5ec183aa278406bf28d5e3bdJean Chalard public void onRingerModeChanged() { 12921af2f40c59de3ea5ec183aa278406bf28d5e3bdJean Chalard mSoundOn = reevaluateIfSoundIsOn(); 130564496bad6207f02e7a653872213bc5954e84ce4Jean Chalard } 131564496bad6207f02e7a653872213bc5954e84ce4Jean Chalard} 132