1 /* 2 * Copyright (C) 2012 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 * use this file except in compliance with the License. You may obtain a copy of 6 * 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, WITHOUT 12 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 * License for the specific language governing permissions and limitations under 14 * the License. 15 */ 16 17 package com.android.inputmethod.latin; 18 19 import android.content.SharedPreferences; 20 import android.inputmethodservice.InputMethodService; 21 import android.os.Build; 22 import android.os.Handler; 23 import android.os.HandlerThread; 24 import android.os.Process; 25 import android.os.SystemClock; 26 import android.preference.PreferenceManager; 27 import android.text.TextUtils; 28 import android.util.Log; 29 import android.view.MotionEvent; 30 import android.view.inputmethod.CompletionInfo; 31 import android.view.inputmethod.EditorInfo; 32 33 import com.android.inputmethod.keyboard.Key; 34 import com.android.inputmethod.keyboard.KeyDetector; 35 import com.android.inputmethod.keyboard.Keyboard; 36 import com.android.inputmethod.keyboard.internal.KeyboardState; 37 import com.android.inputmethod.latin.define.ProductionFlag; 38 39 import java.io.BufferedWriter; 40 import java.io.File; 41 import java.io.FileInputStream; 42 import java.io.FileWriter; 43 import java.io.IOException; 44 import java.io.PrintWriter; 45 import java.nio.ByteBuffer; 46 import java.nio.CharBuffer; 47 import java.nio.channels.FileChannel; 48 import java.nio.charset.Charset; 49 import java.util.Map; 50 51 /** 52 * Logs the use of the LatinIME keyboard. 53 * 54 * This class logs operations on the IME keyboard, including what the user has typed. 55 * Data is stored locally in a file in app-specific storage. 56 * 57 * This functionality is off by default. See {@link ProductionFlag#IS_EXPERIMENTAL}. 58 */ 59 public class ResearchLogger implements SharedPreferences.OnSharedPreferenceChangeListener { 60 private static final String TAG = ResearchLogger.class.getSimpleName(); 61 private static final String PREF_USABILITY_STUDY_MODE = "usability_study_mode"; 62 private static final boolean DEBUG = false; 63 64 private static final ResearchLogger sInstance = new ResearchLogger(new LogFileManager()); 65 public static boolean sIsLogging = false; 66 /* package */ final Handler mLoggingHandler; 67 private InputMethodService mIms; 68 69 /** 70 * Isolates management of files. This variable should never be null, but can be changed 71 * to support testing. 72 */ 73 /* package */ LogFileManager mLogFileManager; 74 75 /** 76 * Manages the file(s) that stores the logs. 77 * 78 * Handles creation, deletion, and provides Readers, Writers, and InputStreams to access 79 * the logs. 80 */ 81 /* package */ static class LogFileManager { 82 public static final String RESEARCH_LOG_FILENAME_KEY = "RESEARCH_LOG_FILENAME"; 83 84 private static final String DEFAULT_FILENAME = "researchLog.txt"; 85 private static final long LOGFILE_PURGE_INTERVAL = 1000 * 60 * 60 * 24; 86 87 protected InputMethodService mIms; 88 protected File mFile; 89 protected PrintWriter mPrintWriter; 90 LogFileManager()91 /* package */ LogFileManager() { 92 } 93 init(final InputMethodService ims)94 public void init(final InputMethodService ims) { 95 mIms = ims; 96 } 97 createLogFile()98 public synchronized void createLogFile() throws IOException { 99 createLogFile(DEFAULT_FILENAME); 100 } 101 createLogFile(final SharedPreferences prefs)102 public synchronized void createLogFile(final SharedPreferences prefs) 103 throws IOException { 104 final String filename = 105 prefs.getString(RESEARCH_LOG_FILENAME_KEY, DEFAULT_FILENAME); 106 createLogFile(filename); 107 } 108 createLogFile(final String filename)109 public synchronized void createLogFile(final String filename) 110 throws IOException { 111 if (mIms == null) { 112 final String msg = "InputMethodService is not configured. Logging is off."; 113 Log.w(TAG, msg); 114 throw new IOException(msg); 115 } 116 final File filesDir = mIms.getFilesDir(); 117 if (filesDir == null || !filesDir.exists()) { 118 final String msg = "Storage directory does not exist. Logging is off."; 119 Log.w(TAG, msg); 120 throw new IOException(msg); 121 } 122 close(); 123 final File file = new File(filesDir, filename); 124 mFile = file; 125 boolean append = true; 126 if (file.exists() && file.lastModified() + LOGFILE_PURGE_INTERVAL < 127 System.currentTimeMillis()) { 128 append = false; 129 } 130 mPrintWriter = new PrintWriter(new BufferedWriter(new FileWriter(file, append)), true); 131 } 132 append(final String s)133 public synchronized boolean append(final String s) { 134 PrintWriter printWriter = mPrintWriter; 135 if (printWriter == null || !mFile.exists()) { 136 if (DEBUG) { 137 Log.w(TAG, "PrintWriter is null... attempting to create default log file"); 138 } 139 try { 140 createLogFile(); 141 printWriter = mPrintWriter; 142 } catch (IOException e) { 143 Log.w(TAG, "Failed to create log file. Not logging."); 144 return false; 145 } 146 } 147 printWriter.print(s); 148 printWriter.flush(); 149 return !printWriter.checkError(); 150 } 151 reset()152 public synchronized void reset() { 153 if (mPrintWriter != null) { 154 mPrintWriter.close(); 155 mPrintWriter = null; 156 if (DEBUG) { 157 Log.d(TAG, "logfile closed"); 158 } 159 } 160 if (mFile != null) { 161 mFile.delete(); 162 if (DEBUG) { 163 Log.d(TAG, "logfile deleted"); 164 } 165 mFile = null; 166 } 167 } 168 close()169 public synchronized void close() { 170 if (mPrintWriter != null) { 171 mPrintWriter.close(); 172 mPrintWriter = null; 173 mFile = null; 174 if (DEBUG) { 175 Log.d(TAG, "logfile closed"); 176 } 177 } 178 } 179 flush()180 /* package */ synchronized void flush() { 181 if (mPrintWriter != null) { 182 mPrintWriter.flush(); 183 } 184 } 185 getContents()186 /* package */ synchronized String getContents() { 187 final File file = mFile; 188 if (file == null) { 189 return ""; 190 } 191 if (mPrintWriter != null) { 192 mPrintWriter.flush(); 193 } 194 FileInputStream stream = null; 195 FileChannel fileChannel = null; 196 String s = ""; 197 try { 198 stream = new FileInputStream(file); 199 fileChannel = stream.getChannel(); 200 final ByteBuffer byteBuffer = ByteBuffer.allocate((int) file.length()); 201 fileChannel.read(byteBuffer); 202 byteBuffer.rewind(); 203 CharBuffer charBuffer = Charset.defaultCharset().decode(byteBuffer); 204 s = charBuffer.toString(); 205 } catch (IOException e) { 206 e.printStackTrace(); 207 } finally { 208 try { 209 if (fileChannel != null) { 210 fileChannel.close(); 211 } 212 } catch (IOException e) { 213 e.printStackTrace(); 214 } finally { 215 try { 216 if (stream != null) { 217 stream.close(); 218 } 219 } catch (IOException e) { 220 e.printStackTrace(); 221 } 222 } 223 } 224 return s; 225 } 226 } 227 ResearchLogger(final LogFileManager logFileManager)228 private ResearchLogger(final LogFileManager logFileManager) { 229 final HandlerThread handlerThread = new HandlerThread("ResearchLogger logging task", 230 Process.THREAD_PRIORITY_BACKGROUND); 231 handlerThread.start(); 232 mLoggingHandler = new Handler(handlerThread.getLooper()); 233 mLogFileManager = logFileManager; 234 } 235 getInstance()236 public static ResearchLogger getInstance() { 237 return sInstance; 238 } 239 init(final InputMethodService ims, final SharedPreferences prefs)240 public static void init(final InputMethodService ims, final SharedPreferences prefs) { 241 sInstance.initInternal(ims, prefs); 242 } 243 initInternal(final InputMethodService ims, final SharedPreferences prefs)244 /* package */ void initInternal(final InputMethodService ims, final SharedPreferences prefs) { 245 mIms = ims; 246 final LogFileManager logFileManager = mLogFileManager; 247 if (logFileManager != null) { 248 logFileManager.init(ims); 249 try { 250 logFileManager.createLogFile(prefs); 251 } catch (IOException e) { 252 e.printStackTrace(); 253 } 254 } 255 if (prefs != null) { 256 sIsLogging = prefs.getBoolean(PREF_USABILITY_STUDY_MODE, false); 257 prefs.registerOnSharedPreferenceChangeListener(this); 258 } 259 } 260 261 /** 262 * Represents a category of logging events that share the same subfield structure. 263 */ 264 private static enum LogGroup { 265 MOTION_EVENT("m"), 266 KEY("k"), 267 CORRECTION("c"), 268 STATE_CHANGE("s"), 269 UNSTRUCTURED("u"); 270 271 private final String mLogString; 272 LogGroup(final String logString)273 private LogGroup(final String logString) { 274 mLogString = logString; 275 } 276 } 277 logMotionEvent(final int action, final long eventTime, final int id, final int x, final int y, final float size, final float pressure)278 public void logMotionEvent(final int action, final long eventTime, final int id, 279 final int x, final int y, final float size, final float pressure) { 280 final String eventTag; 281 switch (action) { 282 case MotionEvent.ACTION_CANCEL: eventTag = "[Cancel]"; break; 283 case MotionEvent.ACTION_UP: eventTag = "[Up]"; break; 284 case MotionEvent.ACTION_DOWN: eventTag = "[Down]"; break; 285 case MotionEvent.ACTION_POINTER_UP: eventTag = "[PointerUp]"; break; 286 case MotionEvent.ACTION_POINTER_DOWN: eventTag = "[PointerDown]"; break; 287 case MotionEvent.ACTION_MOVE: eventTag = "[Move]"; break; 288 case MotionEvent.ACTION_OUTSIDE: eventTag = "[Outside]"; break; 289 default: eventTag = "[Action" + action + "]"; break; 290 } 291 if (!TextUtils.isEmpty(eventTag)) { 292 final StringBuilder sb = new StringBuilder(); 293 sb.append(eventTag); 294 sb.append('\t'); sb.append(eventTime); 295 sb.append('\t'); sb.append(id); 296 sb.append('\t'); sb.append(x); 297 sb.append('\t'); sb.append(y); 298 sb.append('\t'); sb.append(size); 299 sb.append('\t'); sb.append(pressure); 300 write(LogGroup.MOTION_EVENT, sb.toString()); 301 } 302 } 303 logKeyEvent(final int code, final int x, final int y)304 public void logKeyEvent(final int code, final int x, final int y) { 305 final StringBuilder sb = new StringBuilder(); 306 sb.append(Keyboard.printableCode(code)); 307 sb.append('\t'); sb.append(x); 308 sb.append('\t'); sb.append(y); 309 write(LogGroup.KEY, sb.toString()); 310 } 311 logCorrection(final String subgroup, final String before, final String after, final int position)312 public void logCorrection(final String subgroup, final String before, final String after, 313 final int position) { 314 final StringBuilder sb = new StringBuilder(); 315 sb.append(subgroup); 316 sb.append('\t'); sb.append(before); 317 sb.append('\t'); sb.append(after); 318 sb.append('\t'); sb.append(position); 319 write(LogGroup.CORRECTION, sb.toString()); 320 } 321 logStateChange(final String subgroup, final String details)322 public void logStateChange(final String subgroup, final String details) { 323 write(LogGroup.STATE_CHANGE, subgroup + "\t" + details); 324 } 325 326 public static class UnsLogGroup { 327 private static final boolean DEFAULT_ENABLED = true; 328 329 private static final boolean KEYBOARDSTATE_ONCANCELINPUT_ENABLED = DEFAULT_ENABLED; 330 private static final boolean KEYBOARDSTATE_ONCODEINPUT_ENABLED = DEFAULT_ENABLED; 331 private static final boolean KEYBOARDSTATE_ONLONGPRESSTIMEOUT_ENABLED = DEFAULT_ENABLED; 332 private static final boolean KEYBOARDSTATE_ONPRESSKEY_ENABLED = DEFAULT_ENABLED; 333 private static final boolean KEYBOARDSTATE_ONRELEASEKEY_ENABLED = DEFAULT_ENABLED; 334 private static final boolean LATINIME_COMMITCURRENTAUTOCORRECTION_ENABLED = DEFAULT_ENABLED; 335 private static final boolean LATINIME_COMMITTEXT_ENABLED = DEFAULT_ENABLED; 336 private static final boolean LATINIME_DELETESURROUNDINGTEXT_ENABLED = DEFAULT_ENABLED; 337 private static final boolean LATINIME_DOUBLESPACEAUTOPERIOD_ENABLED = DEFAULT_ENABLED; 338 private static final boolean LATINIME_ONDISPLAYCOMPLETIONS_ENABLED = DEFAULT_ENABLED; 339 private static final boolean LATINIME_ONSTARTINPUTVIEWINTERNAL_ENABLED = DEFAULT_ENABLED; 340 private static final boolean LATINIME_ONUPDATESELECTION_ENABLED = DEFAULT_ENABLED; 341 private static final boolean LATINIME_PERFORMEDITORACTION_ENABLED = DEFAULT_ENABLED; 342 private static final boolean LATINIME_PICKAPPLICATIONSPECIFIEDCOMPLETION_ENABLED 343 = DEFAULT_ENABLED; 344 private static final boolean LATINIME_PICKPUNCTUATIONSUGGESTION_ENABLED = DEFAULT_ENABLED; 345 private static final boolean LATINIME_PICKSUGGESTIONMANUALLY_ENABLED = DEFAULT_ENABLED; 346 private static final boolean LATINIME_REVERTCOMMIT_ENABLED = DEFAULT_ENABLED; 347 private static final boolean LATINIME_REVERTDOUBLESPACEWHILEINBATCHEDIT_ENABLED 348 = DEFAULT_ENABLED; 349 private static final boolean LATINIME_REVERTSWAPPUNCTUATION_ENABLED = DEFAULT_ENABLED; 350 private static final boolean LATINIME_SENDKEYCODEPOINT_ENABLED = DEFAULT_ENABLED; 351 private static final boolean LATINIME_SWAPSWAPPERANDSPACEWHILEINBATCHEDIT_ENABLED 352 = DEFAULT_ENABLED; 353 private static final boolean LATINIME_SWITCHTOKEYBOARDVIEW_ENABLED = DEFAULT_ENABLED; 354 private static final boolean LATINKEYBOARDVIEW_ONLONGPRESS_ENABLED = DEFAULT_ENABLED; 355 private static final boolean LATINKEYBOARDVIEW_ONPROCESSMOTIONEVENT_ENABLED 356 = DEFAULT_ENABLED; 357 private static final boolean LATINKEYBOARDVIEW_SETKEYBOARD_ENABLED = DEFAULT_ENABLED; 358 private static final boolean POINTERTRACKER_CALLLISTENERONCANCELINPUT_ENABLED 359 = DEFAULT_ENABLED; 360 private static final boolean POINTERTRACKER_CALLLISTENERONCODEINPUT_ENABLED 361 = DEFAULT_ENABLED; 362 private static final boolean 363 POINTERTRACKER_CALLLISTENERONPRESSANDCHECKKEYBOARDLAYOUTCHANGE_ENABLED 364 = DEFAULT_ENABLED; 365 private static final boolean POINTERTRACKER_CALLLISTENERONRELEASE_ENABLED = DEFAULT_ENABLED; 366 private static final boolean POINTERTRACKER_ONDOWNEVENT_ENABLED = DEFAULT_ENABLED; 367 private static final boolean POINTERTRACKER_ONMOVEEVENT_ENABLED = DEFAULT_ENABLED; 368 private static final boolean SUDDENJUMPINGTOUCHEVENTHANDLER_ONTOUCHEVENT_ENABLED 369 = DEFAULT_ENABLED; 370 private static final boolean SUGGESTIONSVIEW_SETSUGGESTIONS_ENABLED = DEFAULT_ENABLED; 371 } 372 logUnstructured(String logGroup, final String details)373 public static void logUnstructured(String logGroup, final String details) { 374 // TODO: improve performance by making entire class static and/or implementing natively 375 getInstance().write(LogGroup.UNSTRUCTURED, logGroup + "\t" + details); 376 } 377 write(final LogGroup logGroup, final String log)378 private void write(final LogGroup logGroup, final String log) { 379 // TODO: rewrite in native for better performance 380 mLoggingHandler.post(new Runnable() { 381 @Override 382 public void run() { 383 final long currentTime = System.currentTimeMillis(); 384 final long upTime = SystemClock.uptimeMillis(); 385 final StringBuilder builder = new StringBuilder(); 386 builder.append(currentTime); 387 builder.append('\t'); builder.append(upTime); 388 builder.append('\t'); builder.append(logGroup.mLogString); 389 builder.append('\t'); builder.append(log); 390 builder.append('\n'); 391 if (DEBUG) { 392 Log.d(TAG, "Write: " + '[' + logGroup.mLogString + ']' + log); 393 } 394 final String s = builder.toString(); 395 if (mLogFileManager.append(s)) { 396 // success 397 } else { 398 if (DEBUG) { 399 Log.w(TAG, "Unable to write to log."); 400 } 401 // perhaps logfile was deleted. try to recreate and relog. 402 try { 403 mLogFileManager.createLogFile(PreferenceManager 404 .getDefaultSharedPreferences(mIms)); 405 mLogFileManager.append(s); 406 } catch (IOException e) { 407 e.printStackTrace(); 408 } 409 } 410 } 411 }); 412 } 413 clearAll()414 public void clearAll() { 415 mLoggingHandler.post(new Runnable() { 416 @Override 417 public void run() { 418 if (DEBUG) { 419 Log.d(TAG, "Delete log file."); 420 } 421 mLogFileManager.reset(); 422 } 423 }); 424 } 425 getLogFileManager()426 /* package */ LogFileManager getLogFileManager() { 427 return mLogFileManager; 428 } 429 430 @Override onSharedPreferenceChanged(SharedPreferences prefs, String key)431 public void onSharedPreferenceChanged(SharedPreferences prefs, String key) { 432 if (key == null || prefs == null) { 433 return; 434 } 435 sIsLogging = prefs.getBoolean(PREF_USABILITY_STUDY_MODE, false); 436 } 437 keyboardState_onCancelInput(final boolean isSinglePointer, final KeyboardState keyboardState)438 public static void keyboardState_onCancelInput(final boolean isSinglePointer, 439 final KeyboardState keyboardState) { 440 if (UnsLogGroup.KEYBOARDSTATE_ONCANCELINPUT_ENABLED) { 441 final String s = "onCancelInput: single=" + isSinglePointer + " " + keyboardState; 442 logUnstructured("KeyboardState_onCancelInput", s); 443 } 444 } 445 keyboardState_onCodeInput( final int code, final boolean isSinglePointer, final int autoCaps, final KeyboardState keyboardState)446 public static void keyboardState_onCodeInput( 447 final int code, final boolean isSinglePointer, final int autoCaps, 448 final KeyboardState keyboardState) { 449 if (UnsLogGroup.KEYBOARDSTATE_ONCODEINPUT_ENABLED) { 450 final String s = "onCodeInput: code=" + Keyboard.printableCode(code) 451 + " single=" + isSinglePointer 452 + " autoCaps=" + autoCaps + " " + keyboardState; 453 logUnstructured("KeyboardState_onCodeInput", s); 454 } 455 } 456 keyboardState_onLongPressTimeout(final int code, final KeyboardState keyboardState)457 public static void keyboardState_onLongPressTimeout(final int code, 458 final KeyboardState keyboardState) { 459 if (UnsLogGroup.KEYBOARDSTATE_ONLONGPRESSTIMEOUT_ENABLED) { 460 final String s = "onLongPressTimeout: code=" + Keyboard.printableCode(code) + " " 461 + keyboardState; 462 logUnstructured("KeyboardState_onLongPressTimeout", s); 463 } 464 } 465 keyboardState_onPressKey(final int code, final KeyboardState keyboardState)466 public static void keyboardState_onPressKey(final int code, 467 final KeyboardState keyboardState) { 468 if (UnsLogGroup.KEYBOARDSTATE_ONPRESSKEY_ENABLED) { 469 final String s = "onPressKey: code=" + Keyboard.printableCode(code) + " " 470 + keyboardState; 471 logUnstructured("KeyboardState_onPressKey", s); 472 } 473 } 474 keyboardState_onReleaseKey(final KeyboardState keyboardState, final int code, final boolean withSliding)475 public static void keyboardState_onReleaseKey(final KeyboardState keyboardState, final int code, 476 final boolean withSliding) { 477 if (UnsLogGroup.KEYBOARDSTATE_ONRELEASEKEY_ENABLED) { 478 final String s = "onReleaseKey: code=" + Keyboard.printableCode(code) 479 + " sliding=" + withSliding + " " + keyboardState; 480 logUnstructured("KeyboardState_onReleaseKey", s); 481 } 482 } 483 latinIME_commitCurrentAutoCorrection(final String typedWord, final String autoCorrection)484 public static void latinIME_commitCurrentAutoCorrection(final String typedWord, 485 final String autoCorrection) { 486 if (UnsLogGroup.LATINIME_COMMITCURRENTAUTOCORRECTION_ENABLED) { 487 if (typedWord.equals(autoCorrection)) { 488 getInstance().logCorrection("[----]", typedWord, autoCorrection, -1); 489 } else { 490 getInstance().logCorrection("[Auto]", typedWord, autoCorrection, -1); 491 } 492 } 493 } 494 latinIME_commitText(final CharSequence typedWord)495 public static void latinIME_commitText(final CharSequence typedWord) { 496 if (UnsLogGroup.LATINIME_COMMITTEXT_ENABLED) { 497 logUnstructured("LatinIME_commitText", typedWord.toString()); 498 } 499 } 500 latinIME_deleteSurroundingText(final int length)501 public static void latinIME_deleteSurroundingText(final int length) { 502 if (UnsLogGroup.LATINIME_DELETESURROUNDINGTEXT_ENABLED) { 503 logUnstructured("LatinIME_deleteSurroundingText", String.valueOf(length)); 504 } 505 } 506 latinIME_doubleSpaceAutoPeriod()507 public static void latinIME_doubleSpaceAutoPeriod() { 508 if (UnsLogGroup.LATINIME_DOUBLESPACEAUTOPERIOD_ENABLED) { 509 logUnstructured("LatinIME_doubleSpaceAutoPeriod", ""); 510 } 511 } 512 latinIME_onDisplayCompletions( final CompletionInfo[] applicationSpecifiedCompletions)513 public static void latinIME_onDisplayCompletions( 514 final CompletionInfo[] applicationSpecifiedCompletions) { 515 if (UnsLogGroup.LATINIME_ONDISPLAYCOMPLETIONS_ENABLED) { 516 final StringBuilder builder = new StringBuilder(); 517 builder.append("Received completions:"); 518 if (applicationSpecifiedCompletions != null) { 519 for (int i = 0; i < applicationSpecifiedCompletions.length; i++) { 520 builder.append(" #"); 521 builder.append(i); 522 builder.append(": "); 523 builder.append(applicationSpecifiedCompletions[i]); 524 builder.append("\n"); 525 } 526 } 527 logUnstructured("LatinIME_onDisplayCompletions", builder.toString()); 528 } 529 } 530 latinIME_onStartInputViewInternal(final EditorInfo editorInfo, final SharedPreferences prefs)531 public static void latinIME_onStartInputViewInternal(final EditorInfo editorInfo, 532 final SharedPreferences prefs) { 533 if (UnsLogGroup.LATINIME_ONSTARTINPUTVIEWINTERNAL_ENABLED) { 534 final StringBuilder builder = new StringBuilder(); 535 builder.append("onStartInputView: editorInfo:"); 536 builder.append("\tinputType="); 537 builder.append(Integer.toHexString(editorInfo.inputType)); 538 builder.append("\timeOptions="); 539 builder.append(Integer.toHexString(editorInfo.imeOptions)); 540 builder.append("\tdisplay="); builder.append(Build.DISPLAY); 541 builder.append("\tmodel="); builder.append(Build.MODEL); 542 for (Map.Entry<String,?> entry : prefs.getAll().entrySet()) { 543 builder.append("\t" + entry.getKey()); 544 Object value = entry.getValue(); 545 builder.append("=" + ((value == null) ? "<null>" : value.toString())); 546 } 547 logUnstructured("LatinIME_onStartInputViewInternal", builder.toString()); 548 } 549 } 550 latinIME_onUpdateSelection(final int lastSelectionStart, final int lastSelectionEnd, final int oldSelStart, final int oldSelEnd, final int newSelStart, final int newSelEnd, final int composingSpanStart, final int composingSpanEnd)551 public static void latinIME_onUpdateSelection(final int lastSelectionStart, 552 final int lastSelectionEnd, final int oldSelStart, final int oldSelEnd, 553 final int newSelStart, final int newSelEnd, final int composingSpanStart, 554 final int composingSpanEnd) { 555 if (UnsLogGroup.LATINIME_ONUPDATESELECTION_ENABLED) { 556 final String s = "onUpdateSelection: oss=" + oldSelStart 557 + ", ose=" + oldSelEnd 558 + ", lss=" + lastSelectionStart 559 + ", lse=" + lastSelectionEnd 560 + ", nss=" + newSelStart 561 + ", nse=" + newSelEnd 562 + ", cs=" + composingSpanStart 563 + ", ce=" + composingSpanEnd; 564 logUnstructured("LatinIME_onUpdateSelection", s); 565 } 566 } 567 latinIME_performEditorAction(final int imeActionNext)568 public static void latinIME_performEditorAction(final int imeActionNext) { 569 if (UnsLogGroup.LATINIME_PERFORMEDITORACTION_ENABLED) { 570 logUnstructured("LatinIME_performEditorAction", String.valueOf(imeActionNext)); 571 } 572 } 573 latinIME_pickApplicationSpecifiedCompletion(final int index, final CharSequence text, int x, int y)574 public static void latinIME_pickApplicationSpecifiedCompletion(final int index, 575 final CharSequence text, int x, int y) { 576 if (UnsLogGroup.LATINIME_PICKAPPLICATIONSPECIFIEDCOMPLETION_ENABLED) { 577 final String s = String.valueOf(index) + '\t' + text + '\t' + x + '\t' + y; 578 logUnstructured("LatinIME_pickApplicationSpecifiedCompletion", s); 579 } 580 } 581 latinIME_pickSuggestionManually(final String replacedWord, final int index, CharSequence suggestion, int x, int y)582 public static void latinIME_pickSuggestionManually(final String replacedWord, 583 final int index, CharSequence suggestion, int x, int y) { 584 if (UnsLogGroup.LATINIME_PICKSUGGESTIONMANUALLY_ENABLED) { 585 final String s = String.valueOf(index) + '\t' + suggestion + '\t' + x + '\t' + y; 586 logUnstructured("LatinIME_pickSuggestionManually", s); 587 } 588 } 589 latinIME_punctuationSuggestion(final int index, final CharSequence suggestion, int x, int y)590 public static void latinIME_punctuationSuggestion(final int index, 591 final CharSequence suggestion, int x, int y) { 592 if (UnsLogGroup.LATINIME_PICKPUNCTUATIONSUGGESTION_ENABLED) { 593 final String s = String.valueOf(index) + '\t' + suggestion + '\t' + x + '\t' + y; 594 logUnstructured("LatinIME_pickPunctuationSuggestion", s); 595 } 596 } 597 latinIME_revertDoubleSpaceWhileInBatchEdit()598 public static void latinIME_revertDoubleSpaceWhileInBatchEdit() { 599 if (UnsLogGroup.LATINIME_REVERTDOUBLESPACEWHILEINBATCHEDIT_ENABLED) { 600 logUnstructured("LatinIME_revertDoubleSpaceWhileInBatchEdit", ""); 601 } 602 } 603 latinIME_revertSwapPunctuation()604 public static void latinIME_revertSwapPunctuation() { 605 if (UnsLogGroup.LATINIME_REVERTSWAPPUNCTUATION_ENABLED) { 606 logUnstructured("LatinIME_revertSwapPunctuation", ""); 607 } 608 } 609 latinIME_sendKeyCodePoint(final int code)610 public static void latinIME_sendKeyCodePoint(final int code) { 611 if (UnsLogGroup.LATINIME_SENDKEYCODEPOINT_ENABLED) { 612 logUnstructured("LatinIME_sendKeyCodePoint", String.valueOf(code)); 613 } 614 } 615 latinIME_swapSwapperAndSpaceWhileInBatchEdit()616 public static void latinIME_swapSwapperAndSpaceWhileInBatchEdit() { 617 if (UnsLogGroup.LATINIME_SWAPSWAPPERANDSPACEWHILEINBATCHEDIT_ENABLED) { 618 logUnstructured("latinIME_swapSwapperAndSpaceWhileInBatchEdit", ""); 619 } 620 } 621 latinIME_switchToKeyboardView()622 public static void latinIME_switchToKeyboardView() { 623 if (UnsLogGroup.LATINIME_SWITCHTOKEYBOARDVIEW_ENABLED) { 624 final String s = "Switch to keyboard view."; 625 logUnstructured("LatinIME_switchToKeyboardView", s); 626 } 627 } 628 latinKeyboardView_onLongPress()629 public static void latinKeyboardView_onLongPress() { 630 if (UnsLogGroup.LATINKEYBOARDVIEW_ONLONGPRESS_ENABLED) { 631 final String s = "long press detected"; 632 logUnstructured("LatinKeyboardView_onLongPress", s); 633 } 634 } 635 latinKeyboardView_processMotionEvent(MotionEvent me, int action, long eventTime, int index, int id, int x, int y)636 public static void latinKeyboardView_processMotionEvent(MotionEvent me, int action, 637 long eventTime, int index, int id, int x, int y) { 638 if (UnsLogGroup.LATINKEYBOARDVIEW_ONPROCESSMOTIONEVENT_ENABLED) { 639 final float size = me.getSize(index); 640 final float pressure = me.getPressure(index); 641 if (action != MotionEvent.ACTION_MOVE) { 642 getInstance().logMotionEvent(action, eventTime, id, x, y, size, pressure); 643 } 644 } 645 } 646 latinKeyboardView_setKeyboard(final Keyboard keyboard)647 public static void latinKeyboardView_setKeyboard(final Keyboard keyboard) { 648 if (UnsLogGroup.LATINKEYBOARDVIEW_SETKEYBOARD_ENABLED) { 649 StringBuilder builder = new StringBuilder(); 650 builder.append("id="); 651 builder.append(keyboard.mId); 652 builder.append("\tw="); 653 builder.append(keyboard.mOccupiedWidth); 654 builder.append("\th="); 655 builder.append(keyboard.mOccupiedHeight); 656 builder.append("\tkeys=["); 657 boolean first = true; 658 for (Key key : keyboard.mKeys) { 659 if (first) { 660 first = false; 661 } else { 662 builder.append(","); 663 } 664 builder.append("{code:"); 665 builder.append(key.mCode); 666 builder.append(",altCode:"); 667 builder.append(key.mAltCode); 668 builder.append(",x:"); 669 builder.append(key.mX); 670 builder.append(",y:"); 671 builder.append(key.mY); 672 builder.append(",w:"); 673 builder.append(key.mWidth); 674 builder.append(",h:"); 675 builder.append(key.mHeight); 676 builder.append("}"); 677 } 678 builder.append("]"); 679 logUnstructured("LatinKeyboardView_setKeyboard", builder.toString()); 680 } 681 } 682 latinIME_revertCommit(final String originallyTypedWord)683 public static void latinIME_revertCommit(final String originallyTypedWord) { 684 if (UnsLogGroup.LATINIME_REVERTCOMMIT_ENABLED) { 685 logUnstructured("LatinIME_revertCommit", originallyTypedWord); 686 } 687 } 688 pointerTracker_callListenerOnCancelInput()689 public static void pointerTracker_callListenerOnCancelInput() { 690 final String s = "onCancelInput"; 691 if (UnsLogGroup.POINTERTRACKER_CALLLISTENERONCANCELINPUT_ENABLED) { 692 logUnstructured("PointerTracker_callListenerOnCancelInput", s); 693 } 694 } 695 pointerTracker_callListenerOnCodeInput(final Key key, final int x, final int y, final boolean ignoreModifierKey, final boolean altersCode, final int code)696 public static void pointerTracker_callListenerOnCodeInput(final Key key, final int x, 697 final int y, final boolean ignoreModifierKey, final boolean altersCode, 698 final int code) { 699 if (UnsLogGroup.POINTERTRACKER_CALLLISTENERONCODEINPUT_ENABLED) { 700 final String s = "onCodeInput: " + Keyboard.printableCode(code) 701 + " text=" + key.mOutputText + " x=" + x + " y=" + y 702 + " ignoreModifier=" + ignoreModifierKey + " altersCode=" + altersCode 703 + " enabled=" + key.isEnabled(); 704 logUnstructured("PointerTracker_callListenerOnCodeInput", s); 705 } 706 } 707 pointerTracker_callListenerOnPressAndCheckKeyboardLayoutChange( final Key key, final boolean ignoreModifierKey)708 public static void pointerTracker_callListenerOnPressAndCheckKeyboardLayoutChange( 709 final Key key, final boolean ignoreModifierKey) { 710 if (UnsLogGroup.POINTERTRACKER_CALLLISTENERONPRESSANDCHECKKEYBOARDLAYOUTCHANGE_ENABLED) { 711 final String s = "onPress : " + KeyDetector.printableCode(key) 712 + " ignoreModifier=" + ignoreModifierKey 713 + " enabled=" + key.isEnabled(); 714 logUnstructured("PointerTracker_callListenerOnPressAndCheckKeyboardLayoutChange", s); 715 } 716 } 717 pointerTracker_callListenerOnRelease(final Key key, final int primaryCode, final boolean withSliding, final boolean ignoreModifierKey)718 public static void pointerTracker_callListenerOnRelease(final Key key, final int primaryCode, 719 final boolean withSliding, final boolean ignoreModifierKey) { 720 if (UnsLogGroup.POINTERTRACKER_CALLLISTENERONRELEASE_ENABLED) { 721 final String s = "onRelease : " + Keyboard.printableCode(primaryCode) 722 + " sliding=" + withSliding + " ignoreModifier=" + ignoreModifierKey 723 + " enabled="+ key.isEnabled(); 724 logUnstructured("PointerTracker_callListenerOnRelease", s); 725 } 726 } 727 pointerTracker_onDownEvent(long deltaT, int distanceSquared)728 public static void pointerTracker_onDownEvent(long deltaT, int distanceSquared) { 729 if (UnsLogGroup.POINTERTRACKER_ONDOWNEVENT_ENABLED) { 730 final String s = "onDownEvent: ignore potential noise: time=" + deltaT 731 + " distance=" + distanceSquared; 732 logUnstructured("PointerTracker_onDownEvent", s); 733 } 734 } 735 pointerTracker_onMoveEvent(final int x, final int y, final int lastX, final int lastY)736 public static void pointerTracker_onMoveEvent(final int x, final int y, final int lastX, 737 final int lastY) { 738 if (UnsLogGroup.POINTERTRACKER_ONMOVEEVENT_ENABLED) { 739 final String s = String.format("onMoveEvent: sudden move is translated to " 740 + "up[%d,%d]/down[%d,%d] events", lastX, lastY, x, y); 741 logUnstructured("PointerTracker_onMoveEvent", s); 742 } 743 } 744 suddenJumpingTouchEventHandler_onTouchEvent(final MotionEvent me)745 public static void suddenJumpingTouchEventHandler_onTouchEvent(final MotionEvent me) { 746 if (UnsLogGroup.SUDDENJUMPINGTOUCHEVENTHANDLER_ONTOUCHEVENT_ENABLED) { 747 final String s = "onTouchEvent: ignore sudden jump " + me; 748 logUnstructured("SuddenJumpingTouchEventHandler_onTouchEvent", s); 749 } 750 } 751 suggestionsView_setSuggestions(final SuggestedWords mSuggestedWords)752 public static void suggestionsView_setSuggestions(final SuggestedWords mSuggestedWords) { 753 if (UnsLogGroup.SUGGESTIONSVIEW_SETSUGGESTIONS_ENABLED) { 754 logUnstructured("SuggestionsView_setSuggestions", mSuggestedWords.toString()); 755 } 756 } 757 }