Home | History | Annotate | Download | only in internal
      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 
     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
     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
     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 
     96     private void cancelKeyRepeatTimerOf(final PointerTracker tracker) {
     97         removeMessages(MSG_REPEAT_KEY, tracker);
     98     }
     99 
    100     public void cancelKeyRepeatTimers() {
    101         removeMessages(MSG_REPEAT_KEY);
    102     }
    103 
    104     // TODO: Suppress layout changes in key repeat mode
    105     public boolean isInKeyRepeat() {
    106         return hasMessages(MSG_REPEAT_KEY);
    107     }
    108 
    109     @Override
    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
    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
    129     public void cancelLongPressShiftKeyTimer() {
    130         removeMessages(MSG_LONGPRESS_SHIFT_KEY);
    131     }
    132 
    133     public void cancelLongPressTimers() {
    134         removeMessages(MSG_LONGPRESS_KEY);
    135         removeMessages(MSG_LONGPRESS_SHIFT_KEY);
    136     }
    137 
    138     @Override
    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
    169     public boolean isTypingState() {
    170         return hasMessages(MSG_TYPING_STATE_EXPIRED);
    171     }
    172 
    173     @Override
    174     public void startDoubleTapShiftKeyTimer() {
    175         sendMessageDelayed(obtainMessage(MSG_DOUBLE_TAP_SHIFT_KEY),
    176                 ViewConfiguration.getDoubleTapTimeout());
    177     }
    178 
    179     @Override
    180     public void cancelDoubleTapShiftKeyTimer() {
    181         removeMessages(MSG_DOUBLE_TAP_SHIFT_KEY);
    182     }
    183 
    184     @Override
    185     public boolean isInDoubleTapShiftKeyTimeout() {
    186         return hasMessages(MSG_DOUBLE_TAP_SHIFT_KEY);
    187     }
    188 
    189     @Override
    190     public void cancelKeyTimersOf(@Nonnull final PointerTracker tracker) {
    191         cancelKeyRepeatTimerOf(tracker);
    192         cancelLongPressTimersOf(tracker);
    193     }
    194 
    195     public void cancelAllKeyTimers() {
    196         cancelKeyRepeatTimers();
    197         cancelLongPressTimers();
    198     }
    199 
    200     @Override
    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
    211     public void cancelUpdateBatchInputTimer(@Nonnull final PointerTracker tracker) {
    212         removeMessages(MSG_UPDATE_BATCH_INPUT, tracker);
    213     }
    214 
    215     @Override
    216     public void cancelAllUpdateBatchInputTimers() {
    217         removeMessages(MSG_UPDATE_BATCH_INPUT);
    218     }
    219 
    220     public void postDismissKeyPreview(@Nonnull final Key key, final long delay) {
    221         sendMessageDelayed(obtainMessage(MSG_DISMISS_KEY_PREVIEW, key), delay);
    222     }
    223 
    224     public void postDismissGestureFloatingPreviewText(final long delay) {
    225         sendMessageDelayed(obtainMessage(MSG_DISMISS_GESTURE_FLOATING_PREVIEW_TEXT), delay);
    226     }
    227 
    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