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