1/* 2 * Copyright (C) 2017 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 */ 16package android.support.text.emoji.util; 17 18import android.app.Instrumentation; 19import android.text.Selection; 20import android.text.Spannable; 21import android.text.method.QwertyKeyListener; 22import android.text.method.TextKeyListener; 23import android.view.KeyEvent; 24import android.view.inputmethod.EditorInfo; 25import android.view.inputmethod.InputConnection; 26import android.widget.TextView; 27 28import java.util.concurrent.CountDownLatch; 29 30/** 31 * Utility class for KeyEvents 32 */ 33public class KeyboardUtil { 34 private static final int ALT = KeyEvent.META_ALT_ON | KeyEvent.META_ALT_LEFT_ON; 35 private static final int CTRL = KeyEvent.META_CTRL_ON | KeyEvent.META_CTRL_LEFT_ON; 36 private static final int SHIFT = KeyEvent.META_SHIFT_ON | KeyEvent.META_SHIFT_LEFT_ON; 37 private static final int FN = KeyEvent.META_FUNCTION_ON; 38 39 public static KeyEvent zero() { 40 return keyEvent(KeyEvent.KEYCODE_0); 41 } 42 43 public static KeyEvent del() { 44 return keyEvent(KeyEvent.KEYCODE_DEL); 45 } 46 47 public static KeyEvent altDel() { 48 return keyEvent(KeyEvent.KEYCODE_DEL, ALT); 49 } 50 51 public static KeyEvent ctrlDel() { 52 return keyEvent(KeyEvent.KEYCODE_DEL, CTRL); 53 } 54 55 public static KeyEvent shiftDel() { 56 return keyEvent(KeyEvent.KEYCODE_DEL, SHIFT); 57 } 58 59 public static KeyEvent fnDel() { 60 return keyEvent(KeyEvent.KEYCODE_DEL, FN); 61 } 62 63 public static KeyEvent forwardDel() { 64 return keyEvent(KeyEvent.KEYCODE_FORWARD_DEL); 65 } 66 67 public static KeyEvent keyEvent(int keycode, int metaState) { 68 final long currentTime = System.currentTimeMillis(); 69 return new KeyEvent(currentTime, currentTime, KeyEvent.ACTION_DOWN, keycode, 0, metaState); 70 } 71 72 public static KeyEvent keyEvent(int keycode) { 73 final long currentTime = System.currentTimeMillis(); 74 return new KeyEvent(currentTime, currentTime, KeyEvent.ACTION_DOWN, keycode, 0); 75 } 76 77 public static void setComposingTextInBatch(final Instrumentation instrumentation, 78 final InputConnection inputConnection, final CharSequence text) 79 throws InterruptedException { 80 final CountDownLatch latch = new CountDownLatch(1); 81 instrumentation.runOnMainSync(new Runnable() { 82 @Override 83 public void run() { 84 inputConnection.beginBatchEdit(); 85 inputConnection.setComposingText(text, 1); 86 inputConnection.endBatchEdit(); 87 latch.countDown(); 88 } 89 }); 90 91 latch.await(); 92 instrumentation.waitForIdleSync(); 93 } 94 95 public static void deleteSurroundingText(final Instrumentation instrumentation, 96 final InputConnection inputConnection, final int before, final int after) 97 throws InterruptedException { 98 final CountDownLatch latch = new CountDownLatch(1); 99 instrumentation.runOnMainSync(new Runnable() { 100 @Override 101 public void run() { 102 inputConnection.beginBatchEdit(); 103 inputConnection.deleteSurroundingText(before, after); 104 inputConnection.endBatchEdit(); 105 latch.countDown(); 106 } 107 }); 108 latch.await(); 109 instrumentation.waitForIdleSync(); 110 } 111 112 public static void setSelection(Instrumentation instrumentation, final Spannable spannable, 113 final int start) throws InterruptedException { 114 setSelection(instrumentation, spannable, start, start); 115 } 116 117 public static void setSelection(Instrumentation instrumentation, final Spannable spannable, 118 final int start, final int end) throws InterruptedException { 119 final CountDownLatch latch = new CountDownLatch(1); 120 instrumentation.runOnMainSync(new Runnable() { 121 @Override 122 public void run() { 123 Selection.setSelection(spannable, start, end); 124 latch.countDown(); 125 } 126 }); 127 latch.await(); 128 instrumentation.waitForIdleSync(); 129 } 130 131 public static InputConnection initTextViewForSimulatedIme(Instrumentation instrumentation, 132 final TextView textView) throws InterruptedException { 133 final CountDownLatch latch = new CountDownLatch(1); 134 instrumentation.runOnMainSync(new Runnable() { 135 @Override 136 public void run() { 137 textView.setKeyListener( 138 QwertyKeyListener.getInstance(false, TextKeyListener.Capitalize.NONE)); 139 textView.setText("", TextView.BufferType.EDITABLE); 140 latch.countDown(); 141 } 142 }); 143 latch.await(); 144 instrumentation.waitForIdleSync(); 145 return textView.onCreateInputConnection(new EditorInfo()); 146 } 147} 148