1 /* 2 * Copyright (C) 2013 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 17 package com.android.inputmethod.keyboard.internal; 18 19 import android.os.Message; 20 import android.os.SystemClock; 21 import android.view.ViewConfiguration; 22 23 import com.android.inputmethod.keyboard.Key; 24 import com.android.inputmethod.keyboard.PointerTracker; 25 import com.android.inputmethod.latin.common.Constants; 26 import com.android.inputmethod.latin.utils.LeakGuardHandlerWrapper; 27 28 import javax.annotation.Nonnull; 29 30 public final class TimerHandler extends LeakGuardHandlerWrapper<DrawingProxy> 31 implements TimerProxy { 32 private static final int MSG_TYPING_STATE_EXPIRED = 0; 33 private static final int MSG_REPEAT_KEY = 1; 34 private static final int MSG_LONGPRESS_KEY = 2; 35 private static final int MSG_LONGPRESS_SHIFT_KEY = 3; 36 private static final int MSG_DOUBLE_TAP_SHIFT_KEY = 4; 37 private static final int MSG_UPDATE_BATCH_INPUT = 5; 38 private static final int MSG_DISMISS_KEY_PREVIEW = 6; 39 private static final int MSG_DISMISS_GESTURE_FLOATING_PREVIEW_TEXT = 7; 40 41 private final int mIgnoreAltCodeKeyTimeout; 42 private final int mGestureRecognitionUpdateTime; 43 TimerHandler(@onnull final DrawingProxy ownerInstance, final int ignoreAltCodeKeyTimeout, final int gestureRecognitionUpdateTime)44 public TimerHandler(@Nonnull final DrawingProxy ownerInstance, 45 final int ignoreAltCodeKeyTimeout, final int gestureRecognitionUpdateTime) { 46 super(ownerInstance); 47 mIgnoreAltCodeKeyTimeout = ignoreAltCodeKeyTimeout; 48 mGestureRecognitionUpdateTime = gestureRecognitionUpdateTime; 49 } 50 51 @Override handleMessage(final Message msg)52 public void handleMessage(final Message msg) { 53 final DrawingProxy drawingProxy = getOwnerInstance(); 54 if (drawingProxy == null) { 55 return; 56 } 57 switch (msg.what) { 58 case MSG_TYPING_STATE_EXPIRED: 59 drawingProxy.startWhileTypingAnimation(DrawingProxy.FADE_IN); 60 break; 61 case MSG_REPEAT_KEY: 62 final PointerTracker tracker1 = (PointerTracker) msg.obj; 63 tracker1.onKeyRepeat(msg.arg1 /* code */, msg.arg2 /* repeatCount */); 64 break; 65 case MSG_LONGPRESS_KEY: 66 case MSG_LONGPRESS_SHIFT_KEY: 67 cancelLongPressTimers(); 68 final PointerTracker tracker2 = (PointerTracker) msg.obj; 69 tracker2.onLongPressed(); 70 break; 71 case MSG_UPDATE_BATCH_INPUT: 72 final PointerTracker tracker3 = (PointerTracker) msg.obj; 73 tracker3.updateBatchInputByTimer(SystemClock.uptimeMillis()); 74 startUpdateBatchInputTimer(tracker3); 75 break; 76 case MSG_DISMISS_KEY_PREVIEW: 77 drawingProxy.onKeyReleased((Key) msg.obj, false /* withAnimation */); 78 break; 79 case MSG_DISMISS_GESTURE_FLOATING_PREVIEW_TEXT: 80 drawingProxy.dismissGestureFloatingPreviewTextWithoutDelay(); 81 break; 82 } 83 } 84 85 @Override startKeyRepeatTimerOf(@onnull final PointerTracker tracker, final int repeatCount, final int delay)86 public void startKeyRepeatTimerOf(@Nonnull final PointerTracker tracker, final int repeatCount, 87 final int delay) { 88 final Key key = tracker.getKey(); 89 if (key == null || delay == 0) { 90 return; 91 } 92 sendMessageDelayed( 93 obtainMessage(MSG_REPEAT_KEY, key.getCode(), repeatCount, tracker), delay); 94 } 95 cancelKeyRepeatTimerOf(final PointerTracker tracker)96 private void cancelKeyRepeatTimerOf(final PointerTracker tracker) { 97 removeMessages(MSG_REPEAT_KEY, tracker); 98 } 99 cancelKeyRepeatTimers()100 public void cancelKeyRepeatTimers() { 101 removeMessages(MSG_REPEAT_KEY); 102 } 103 104 // TODO: Suppress layout changes in key repeat mode isInKeyRepeat()105 public boolean isInKeyRepeat() { 106 return hasMessages(MSG_REPEAT_KEY); 107 } 108 109 @Override startLongPressTimerOf(@onnull final PointerTracker tracker, final int delay)110 public void startLongPressTimerOf(@Nonnull final PointerTracker tracker, final int delay) { 111 final Key key = tracker.getKey(); 112 if (key == null) { 113 return; 114 } 115 // Use a separate message id for long pressing shift key, because long press shift key 116 // timers should be canceled when other key is pressed. 117 final int messageId = (key.getCode() == Constants.CODE_SHIFT) 118 ? MSG_LONGPRESS_SHIFT_KEY : MSG_LONGPRESS_KEY; 119 sendMessageDelayed(obtainMessage(messageId, tracker), delay); 120 } 121 122 @Override cancelLongPressTimersOf(@onnull final PointerTracker tracker)123 public void cancelLongPressTimersOf(@Nonnull final PointerTracker tracker) { 124 removeMessages(MSG_LONGPRESS_KEY, tracker); 125 removeMessages(MSG_LONGPRESS_SHIFT_KEY, tracker); 126 } 127 128 @Override cancelLongPressShiftKeyTimer()129 public void cancelLongPressShiftKeyTimer() { 130 removeMessages(MSG_LONGPRESS_SHIFT_KEY); 131 } 132 cancelLongPressTimers()133 public void cancelLongPressTimers() { 134 removeMessages(MSG_LONGPRESS_KEY); 135 removeMessages(MSG_LONGPRESS_SHIFT_KEY); 136 } 137 138 @Override startTypingStateTimer(@onnull final Key typedKey)139 public void startTypingStateTimer(@Nonnull final Key typedKey) { 140 if (typedKey.isModifier() || typedKey.altCodeWhileTyping()) { 141 return; 142 } 143 144 final boolean isTyping = isTypingState(); 145 removeMessages(MSG_TYPING_STATE_EXPIRED); 146 final DrawingProxy drawingProxy = getOwnerInstance(); 147 if (drawingProxy == null) { 148 return; 149 } 150 151 // When user hits the space or the enter key, just cancel the while-typing timer. 152 final int typedCode = typedKey.getCode(); 153 if (typedCode == Constants.CODE_SPACE || typedCode == Constants.CODE_ENTER) { 154 if (isTyping) { 155 drawingProxy.startWhileTypingAnimation(DrawingProxy.FADE_IN); 156 } 157 return; 158 } 159 160 sendMessageDelayed( 161 obtainMessage(MSG_TYPING_STATE_EXPIRED), mIgnoreAltCodeKeyTimeout); 162 if (isTyping) { 163 return; 164 } 165 drawingProxy.startWhileTypingAnimation(DrawingProxy.FADE_OUT); 166 } 167 168 @Override isTypingState()169 public boolean isTypingState() { 170 return hasMessages(MSG_TYPING_STATE_EXPIRED); 171 } 172 173 @Override startDoubleTapShiftKeyTimer()174 public void startDoubleTapShiftKeyTimer() { 175 sendMessageDelayed(obtainMessage(MSG_DOUBLE_TAP_SHIFT_KEY), 176 ViewConfiguration.getDoubleTapTimeout()); 177 } 178 179 @Override cancelDoubleTapShiftKeyTimer()180 public void cancelDoubleTapShiftKeyTimer() { 181 removeMessages(MSG_DOUBLE_TAP_SHIFT_KEY); 182 } 183 184 @Override isInDoubleTapShiftKeyTimeout()185 public boolean isInDoubleTapShiftKeyTimeout() { 186 return hasMessages(MSG_DOUBLE_TAP_SHIFT_KEY); 187 } 188 189 @Override cancelKeyTimersOf(@onnull final PointerTracker tracker)190 public void cancelKeyTimersOf(@Nonnull final PointerTracker tracker) { 191 cancelKeyRepeatTimerOf(tracker); 192 cancelLongPressTimersOf(tracker); 193 } 194 cancelAllKeyTimers()195 public void cancelAllKeyTimers() { 196 cancelKeyRepeatTimers(); 197 cancelLongPressTimers(); 198 } 199 200 @Override startUpdateBatchInputTimer(@onnull final PointerTracker tracker)201 public void startUpdateBatchInputTimer(@Nonnull final PointerTracker tracker) { 202 if (mGestureRecognitionUpdateTime <= 0) { 203 return; 204 } 205 removeMessages(MSG_UPDATE_BATCH_INPUT, tracker); 206 sendMessageDelayed(obtainMessage(MSG_UPDATE_BATCH_INPUT, tracker), 207 mGestureRecognitionUpdateTime); 208 } 209 210 @Override cancelUpdateBatchInputTimer(@onnull final PointerTracker tracker)211 public void cancelUpdateBatchInputTimer(@Nonnull final PointerTracker tracker) { 212 removeMessages(MSG_UPDATE_BATCH_INPUT, tracker); 213 } 214 215 @Override cancelAllUpdateBatchInputTimers()216 public void cancelAllUpdateBatchInputTimers() { 217 removeMessages(MSG_UPDATE_BATCH_INPUT); 218 } 219 postDismissKeyPreview(@onnull final Key key, final long delay)220 public void postDismissKeyPreview(@Nonnull final Key key, final long delay) { 221 sendMessageDelayed(obtainMessage(MSG_DISMISS_KEY_PREVIEW, key), delay); 222 } 223 postDismissGestureFloatingPreviewText(final long delay)224 public void postDismissGestureFloatingPreviewText(final long delay) { 225 sendMessageDelayed(obtainMessage(MSG_DISMISS_GESTURE_FLOATING_PREVIEW_TEXT), delay); 226 } 227 cancelAllMessages()228 public void cancelAllMessages() { 229 cancelAllKeyTimers(); 230 cancelAllUpdateBatchInputTimers(); 231 removeMessages(MSG_DISMISS_KEY_PREVIEW); 232 removeMessages(MSG_DISMISS_GESTURE_FLOATING_PREVIEW_TEXT); 233 } 234 } 235