/CircleIME/src/com/marvin/circleime/SoftKeyboard.java
Java | 773 lines | 483 code | 102 blank | 188 comment | 155 complexity | dd1f59891313dc58efa8c9c899761922 MD5 | raw file
1/* 2 * Copyright (C) 2008-2009 Google Inc. 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 17package com.marvin.circleime; 18 19import com.google.tts.TextToSpeechBeta; 20 21import android.content.res.Configuration; 22import android.inputmethodservice.InputMethodService; 23import android.inputmethodservice.Keyboard; 24import android.inputmethodservice.KeyboardView; 25import android.text.method.MetaKeyKeyListener; 26import android.util.Log; 27import android.view.KeyCharacterMap; 28import android.view.KeyEvent; 29import android.view.MotionEvent; 30import android.view.View; 31import android.view.ViewGroup.LayoutParams; 32import android.view.inputmethod.CompletionInfo; 33import android.view.inputmethod.EditorInfo; 34import android.view.inputmethod.InputConnection; 35import android.view.inputmethod.InputMethodManager; 36import android.widget.FrameLayout; 37 38import java.util.ArrayList; 39import java.util.List; 40 41/** 42 * Example of writing an input method for a soft keyboard. This code is focused 43 * on simplicity over completeness, so it should in no way be considered to be a 44 * complete soft keyboard implementation. Its purpose is to provide a basic 45 * example for how you would get started writing an input method, to be fleshed 46 * out as appropriate. 47 */ 48public class SoftKeyboard extends InputMethodService implements 49 KeyboardView.OnKeyboardActionListener { 50 static final boolean DEBUG = false; 51 52 /** 53 * This boolean indicates the optional example code for performing 54 * processing of hard keys in addition to regular text generation from 55 * on-screen interaction. It would be used for input methods that perform 56 * language translations (such as converting text entered on a QWERTY 57 * keyboard to Chinese), but may not be used for input methods that are 58 * primarily intended to be used for on-screen text entry. 59 */ 60 static final boolean PROCESS_HARD_KEYS = true; 61 62 private KeyboardView mInputView; 63 64 private CandidateView mCandidateView; 65 66 private CompletionInfo[] mCompletions; 67 68 private StringBuilder mComposing = new StringBuilder(); 69 70 private boolean mPredictionOn; 71 72 private boolean mCompletionOn; 73 74 private int mLastDisplayWidth; 75 76 private boolean mCapsLock; 77 78 private long mLastShiftTime; 79 80 private long mMetaState; 81 82 private LatinKeyboard mSymbolsKeyboard; 83 84 private LatinKeyboard mSymbolsShiftedKeyboard; 85 86 private LatinKeyboard mQwertyKeyboard; 87 88 private LatinKeyboard mCurKeyboard; 89 90 private String mWordSeparators; 91 92 public TextToSpeechBeta mTts; 93 94 /** 95 * Main initialization of the input method component. Be sure to call to 96 * super class. 97 */ 98 99 @Override 100 public void onCreate() { 101 super.onCreate(); 102 mWordSeparators = getResources().getString(R.string.word_separators); 103 mTts = new TextToSpeechBeta(this, null); 104 } 105 106 @Override 107 public void onDestroy() { 108 if (mTts != null) { 109 mTts.shutdown(); 110 } 111 super.onDestroy(); 112 } 113 114 /** 115 * This is the point where you can do all of your UI initialization. It is 116 * called after creation and any configuration change. 117 */ 118 @Override 119 public void onInitializeInterface() { 120 if (mQwertyKeyboard != null) { 121 // Configuration changes can happen after the keyboard gets 122 // recreated, 123 // so we need to be able to re-build the keyboards if the available 124 // space has changed. 125 int displayWidth = getMaxWidth(); 126 if (displayWidth == mLastDisplayWidth) 127 return; 128 mLastDisplayWidth = displayWidth; 129 } 130 mQwertyKeyboard = new LatinKeyboard(this, R.xml.qwerty); 131 mSymbolsKeyboard = new LatinKeyboard(this, R.xml.symbols); 132 mSymbolsShiftedKeyboard = new LatinKeyboard(this, R.xml.symbols_shift); 133 } 134 135 /** 136 * Called by the framework when your view for creating input needs to be 137 * generated. This will be called the first time your input method is 138 * displayed, and every time it needs to be re-created such as due to a 139 * configuration change. 140 */ 141 @Override 142 public View onCreateInputView() { 143 mInputView = (KeyboardView) getLayoutInflater().inflate(R.layout.input, null); 144 mInputView.setOnKeyboardActionListener(this); 145 mInputView.setKeyboard(mQwertyKeyboard); 146 return mInputView; 147 } 148 149 /** 150 * Called by the framework when your view for showing candidates needs to be 151 * generated, like {@link #onCreateInputView}. 152 */ 153 @Override 154 public View onCreateCandidatesView() { 155 return null; 156 } 157 158 /** 159 * This is the main point where we do our initialization of the input method 160 * to begin operating on an application. At this point we have been bound to 161 * the client, and are now receiving all of the detailed information about 162 * the target of our edits. 163 */ 164 @Override 165 public void onStartInput(EditorInfo attribute, boolean restarting) { 166 super.onStartInput(attribute, restarting); 167 168 // Reset our state. We want to do this even if restarting, because 169 // the underlying state of the text editor could have changed in any 170 // way. 171 mComposing.setLength(0); 172 updateCandidates(); 173 174 if (!restarting) { 175 // Clear shift states. 176 mMetaState = 0; 177 } 178 179 mPredictionOn = false; 180 mCompletionOn = false; 181 mCompletions = null; 182 183 // We are now going to initialize our state based on the type of 184 // text being edited. 185 switch (attribute.inputType & EditorInfo.TYPE_MASK_CLASS) { 186 case EditorInfo.TYPE_CLASS_NUMBER: 187 case EditorInfo.TYPE_CLASS_DATETIME: 188 // Numbers and dates default to the symbols keyboard, with 189 // no extra features. 190 mCurKeyboard = mSymbolsKeyboard; 191 break; 192 193 case EditorInfo.TYPE_CLASS_PHONE: 194 // Phones will also default to the symbols keyboard, though 195 // often you will want to have a dedicated phone keyboard. 196 mCurKeyboard = mSymbolsKeyboard; 197 break; 198 199 case EditorInfo.TYPE_CLASS_TEXT: 200 // This is general text editing. We will default to the 201 // normal alphabetic keyboard, and assume that we should 202 // be doing predictive text (showing candidates as the 203 // user types). 204 mCurKeyboard = mQwertyKeyboard; 205 mPredictionOn = true; 206 207 // We now look for a few special variations of text that will 208 // modify our behavior. 209 int variation = attribute.inputType & EditorInfo.TYPE_MASK_VARIATION; 210 if (variation == EditorInfo.TYPE_TEXT_VARIATION_PASSWORD 211 || variation == EditorInfo.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD) { 212 // Do not display predictions / what the user is typing 213 // when they are entering a password. 214 mPredictionOn = false; 215 } 216 217 if (variation == EditorInfo.TYPE_TEXT_VARIATION_EMAIL_ADDRESS 218 || variation == EditorInfo.TYPE_TEXT_VARIATION_URI 219 || variation == EditorInfo.TYPE_TEXT_VARIATION_FILTER) { 220 // Our predictions are not useful for e-mail addresses 221 // or URIs. 222 mPredictionOn = false; 223 } 224 225 if ((attribute.inputType & EditorInfo.TYPE_TEXT_FLAG_AUTO_COMPLETE) != 0) { 226 // If this is an auto-complete text view, then our 227 // predictions 228 // will not be shown and instead we will allow the editor 229 // to supply their own. We only show the editor's 230 // candidates when in fullscreen mode, otherwise relying 231 // own it displaying its own UI. 232 mPredictionOn = false; 233 mCompletionOn = isFullscreenMode(); 234 } 235 236 // We also want to look at the current state of the editor 237 // to decide whether our alphabetic keyboard should start out 238 // shifted. 239 updateShiftKeyState(attribute); 240 break; 241 242 default: 243 // For all unknown input types, default to the alphabetic 244 // keyboard with no special features. 245 mCurKeyboard = mQwertyKeyboard; 246 updateShiftKeyState(attribute); 247 } 248 249 // Update the label on the enter key, depending on what the application 250 // says it will do. 251 mCurKeyboard.setImeOptions(getResources(), attribute.imeOptions); 252 } 253 254 /** 255 * This is called when the user is done editing a field. We can use this to 256 * reset our state. 257 */ 258 @Override 259 public void onFinishInput() { 260 super.onFinishInput(); 261 262 // Clear current composing text and candidates. 263 mComposing.setLength(0); 264 updateCandidates(); 265 266 // We only hide the candidates window when finishing input on 267 // a particular editor, to avoid popping the underlying application 268 // up and down if the user is entering text into the bottom of 269 // its window. 270 setCandidatesViewShown(false); 271 272 mCurKeyboard = mQwertyKeyboard; 273 if (mInputView != null) { 274 mInputView.closing(); 275 } 276 } 277 278 @Override 279 public void onStartInputView(EditorInfo attribute, boolean restarting) { 280 super.onStartInputView(attribute, restarting); 281 // Apply the selected keyboard to the input view. 282 mInputView.setKeyboard(mCurKeyboard); 283 mInputView.closing(); 284 } 285 286 /** 287 * Deal with the editor reporting movement of its cursor. 288 */ 289 @Override 290 public void onUpdateSelection(int oldSelStart, int oldSelEnd, int newSelStart, int newSelEnd, 291 int candidatesStart, int candidatesEnd) { 292 super.onUpdateSelection(oldSelStart, oldSelEnd, newSelStart, newSelEnd, candidatesStart, 293 candidatesEnd); 294 295 // If the current selection in the text view changes, we should 296 // clear whatever candidate text we have. 297 if (mComposing.length() > 0 && (newSelStart != candidatesEnd || newSelEnd != candidatesEnd)) { 298 mComposing.setLength(0); 299 updateCandidates(); 300 InputConnection ic = getCurrentInputConnection(); 301 if (ic != null) { 302 ic.finishComposingText(); 303 } 304 } 305 } 306 307 /** 308 * This tells us about completions that the editor has determined based on 309 * the current text in it. We want to use this in fullscreen mode to show 310 * the completions ourself, since the editor can not be seen in that 311 * situation. 312 */ 313 @Override 314 public void onDisplayCompletions(CompletionInfo[] completions) { 315 if (mCompletionOn) { 316 mCompletions = completions; 317 if (completions == null) { 318 setSuggestions(null, false, false); 319 return; 320 } 321 322 List<String> stringList = new ArrayList<String>(); 323 for (int i = 0; i < (completions != null ? completions.length : 0); i++) { 324 CompletionInfo ci = completions[i]; 325 if ((ci != null) && (ci.getText() != null)) 326 stringList.add(ci.getText().toString()); 327 } 328 setSuggestions(stringList, true, true); 329 } 330 } 331 332 /** 333 * This translates incoming hard key events in to edit operations on an 334 * InputConnection. It is only needed when using the PROCESS_HARD_KEYS 335 * option. 336 */ 337 private boolean translateKeyDown(int keyCode, KeyEvent event) { 338 mMetaState = MetaKeyKeyListener.handleKeyDown(mMetaState, keyCode, event); 339 int c = event.getUnicodeChar(MetaKeyKeyListener.getMetaState(mMetaState)); 340 mMetaState = MetaKeyKeyListener.adjustMetaAfterKeypress(mMetaState); 341 InputConnection ic = getCurrentInputConnection(); 342 if (c == 0 || ic == null) { 343 return false; 344 } 345 346 boolean dead = false; 347 348 if ((c & KeyCharacterMap.COMBINING_ACCENT) != 0) { 349 dead = true; 350 c = c & KeyCharacterMap.COMBINING_ACCENT_MASK; 351 } 352 353 if (mComposing.length() > 0) { 354 char accent = mComposing.charAt(mComposing.length() - 1); 355 int composed = KeyEvent.getDeadChar(accent, c); 356 357 if (composed != 0) { 358 c = composed; 359 mComposing.setLength(mComposing.length() - 1); 360 } 361 } 362 363 onKey(c, null); 364 365 return true; 366 } 367 368 /** 369 * Use this to monitor key events being delivered to the application. We get 370 * first crack at them, and can either resume them or let them continue to 371 * the app. 372 */ 373 @Override 374 public boolean onKeyDown(int keyCode, KeyEvent event) { 375 switch (keyCode) { 376 // Use search as an alternate enter key 377 case KeyEvent.KEYCODE_SEARCH: 378 this.sendDefaultEditorAction(false); 379 return true; 380 381 // TODO: Use menu as a "safer" way to dismiss the IME 382 case KeyEvent.KEYCODE_MENU: 383 Log.e("menu hit", "0"); 384 return true; 385 386 case KeyEvent.KEYCODE_BACK: 387 // The InputMethodService already takes care of the back 388 // key for us, to dismiss the input method if it is shown. 389 // However, our keyboard could be showing a pop-up window 390 // that back should dismiss, so we first allow it to do that. 391 if (event.getRepeatCount() == 0 && mInputView != null) { 392 if (mInputView.handleBack()) { 393 return true; 394 } 395 } 396 break; 397 398 case KeyEvent.KEYCODE_DEL: 399 // Special handling of the delete key: if we currently are 400 // composing text for the user, we want to modify that instead 401 // of let the application to the delete itself. 402 if (mComposing.length() > 0) { 403 onKey(Keyboard.KEYCODE_DELETE, null); 404 return true; 405 } 406 break; 407 408 case KeyEvent.KEYCODE_ENTER: 409 // Let the underlying text editor always handle these. 410 return false; 411 412 default: 413 // For all other keys, if we want to do transformations on 414 // text being entered with a hard keyboard, we need to process 415 // it and do the appropriate action. 416 if (PROCESS_HARD_KEYS) { 417 if (keyCode == KeyEvent.KEYCODE_SPACE 418 && (event.getMetaState() & KeyEvent.META_ALT_ON) != 0) { 419 // A silly example: in our input method, Alt+Space 420 // is a shortcut for 'android' in lower case. 421 InputConnection ic = getCurrentInputConnection(); 422 if (ic != null) { 423 // First, tell the editor that it is no longer in 424 // the 425 // shift state, since we are consuming this. 426 ic.clearMetaKeyStates(KeyEvent.META_ALT_ON); 427 keyDownUp(KeyEvent.KEYCODE_A); 428 keyDownUp(KeyEvent.KEYCODE_N); 429 keyDownUp(KeyEvent.KEYCODE_D); 430 keyDownUp(KeyEvent.KEYCODE_R); 431 keyDownUp(KeyEvent.KEYCODE_O); 432 keyDownUp(KeyEvent.KEYCODE_I); 433 keyDownUp(KeyEvent.KEYCODE_D); 434 // And we consume this event. 435 return true; 436 } 437 } 438 if (mPredictionOn && translateKeyDown(keyCode, event)) { 439 return true; 440 } 441 } 442 } 443 444 return super.onKeyDown(keyCode, event); 445 } 446 447 /** 448 * Use this to monitor key events being delivered to the application. We get 449 * first crack at them, and can either resume them or let them continue to 450 * the app. 451 */ 452 @Override 453 public boolean onKeyUp(int keyCode, KeyEvent event) { 454 // If we want to do transformations on text being entered with a hard 455 // keyboard, we need to process the up events to update the meta key 456 // state we are tracking. 457 if (PROCESS_HARD_KEYS) { 458 if (mPredictionOn) { 459 mMetaState = MetaKeyKeyListener.handleKeyUp(mMetaState, keyCode, event); 460 } 461 } 462 463 return super.onKeyUp(keyCode, event); 464 } 465 466 /** 467 * Helper function to commit any text being composed in to the editor. 468 */ 469 private void commitTyped(InputConnection inputConnection) { 470 if (mComposing.length() > 0) { 471 inputConnection.commitText(mComposing, mComposing.length()); 472 mComposing.setLength(0); 473 updateCandidates(); 474 } 475 } 476 477 /** 478 * Helper to update the shift state of our keyboard based on the initial 479 * editor state. 480 */ 481 private void updateShiftKeyState(EditorInfo attr) { 482 if (attr != null && mInputView != null && mQwertyKeyboard == mInputView.getKeyboard()) { 483 int caps = 0; 484 EditorInfo ei = getCurrentInputEditorInfo(); 485 if (ei != null && ei.inputType != EditorInfo.TYPE_NULL) { 486 caps = getCurrentInputConnection().getCursorCapsMode(attr.inputType); 487 } 488 mInputView.setShifted(mCapsLock || caps != 0); 489 } 490 } 491 492 /** 493 * Helper to determine if a given character code is alphabetic. 494 */ 495 private boolean isAlphabet(int code) { 496 if (Character.isLetter(code)) { 497 return true; 498 } else { 499 return false; 500 } 501 } 502 503 /** 504 * Helper to send a key down / key up pair to the current editor. 505 */ 506 private void keyDownUp(int keyEventCode) { 507 getCurrentInputConnection().sendKeyEvent(new KeyEvent(KeyEvent.ACTION_DOWN, keyEventCode)); 508 getCurrentInputConnection().sendKeyEvent(new KeyEvent(KeyEvent.ACTION_UP, keyEventCode)); 509 } 510 511 /** 512 * Helper to send a character to the editor as raw key events. 513 */ 514 private void sendKey(int keyCode) { 515 switch (keyCode) { 516 case '\n': 517 keyDownUp(KeyEvent.KEYCODE_ENTER); 518 break; 519 default: 520 if (keyCode >= '0' && keyCode <= '9') { 521 keyDownUp(keyCode - '0' + KeyEvent.KEYCODE_0); 522 } else { 523 getCurrentInputConnection().commitText(String.valueOf((char) keyCode), 1); 524 } 525 break; 526 } 527 } 528 529 // Implementation of KeyboardViewListener 530 531 public void onKey(int primaryCode, int[] keyCodes) { 532 if (isWordSeparator(primaryCode)) { 533 // Handle separator 534 if (mComposing.length() > 0) { 535 commitTyped(getCurrentInputConnection()); 536 } 537 sendKey(primaryCode); 538 updateShiftKeyState(getCurrentInputEditorInfo()); 539 } else if (primaryCode == Keyboard.KEYCODE_DELETE) { 540 handleBackspace(); 541 } else if (primaryCode == Keyboard.KEYCODE_SHIFT) { 542 handleShift(); 543 } else if (primaryCode == Keyboard.KEYCODE_CANCEL) { 544 handleClose(); 545 return; 546 } else if (primaryCode == Keyboard.KEYCODE_MODE_CHANGE && mInputView != null) { 547 Keyboard current = mInputView.getKeyboard(); 548 if (current == mSymbolsKeyboard || current == mSymbolsShiftedKeyboard) { 549 current = mQwertyKeyboard; 550 } else { 551 current = mSymbolsKeyboard; 552 } 553 mInputView.setKeyboard(current); 554 if (current == mSymbolsKeyboard) { 555 current.setShifted(false); 556 } 557 } else { 558 handleCharacter(primaryCode, keyCodes); 559 } 560 } 561 562 public void onText(CharSequence text) { 563 InputConnection ic = getCurrentInputConnection(); 564 if (ic == null) 565 return; 566 ic.beginBatchEdit(); 567 if (mComposing.length() > 0) { 568 commitTyped(ic); 569 } 570 ic.commitText(text, 0); 571 ic.endBatchEdit(); 572 updateShiftKeyState(getCurrentInputEditorInfo()); 573 } 574 575 /** 576 * Update the list of available candidates from the current composing text. 577 * This will need to be filled in by however you are determining candidates. 578 */ 579 private void updateCandidates() { 580 if (!mCompletionOn) { 581 if (mComposing.length() > 0) { 582 ArrayList<String> list = new ArrayList<String>(); 583 list.add(mComposing.toString()); 584 setSuggestions(list, true, true); 585 } else { 586 setSuggestions(null, false, false); 587 } 588 } 589 } 590 591 public void setSuggestions(List<String> suggestions, boolean completions, boolean typedWordValid) { 592 if (suggestions != null && suggestions.size() > 0) { 593 setCandidatesViewShown(true); 594 } else if (isExtractViewShown()) { 595 setCandidatesViewShown(true); 596 } 597 if (mCandidateView != null) { 598 mCandidateView.setSuggestions(suggestions, completions, typedWordValid); 599 } 600 } 601 602 public void handleBackspace() { 603 final int length = mComposing.length(); 604 if (length > 1) { 605 mComposing.delete(length - 1, length); 606 getCurrentInputConnection().setComposingText(mComposing, 1); 607 updateCandidates(); 608 } else if (length > 0) { 609 mComposing.setLength(0); 610 getCurrentInputConnection().commitText("", 0); 611 updateCandidates(); 612 } else { 613 keyDownUp(KeyEvent.KEYCODE_DEL); 614 } 615 updateShiftKeyState(getCurrentInputEditorInfo()); 616 } 617 618 private void handleShift() { 619 if (mInputView == null) { 620 return; 621 } 622 623 Keyboard currentKeyboard = mInputView.getKeyboard(); 624 if (mQwertyKeyboard == currentKeyboard) { 625 // Alphabet keyboard 626 checkToggleCapsLock(); 627 mInputView.setShifted(mCapsLock || !mInputView.isShifted()); 628 } else if (currentKeyboard == mSymbolsKeyboard) { 629 mSymbolsKeyboard.setShifted(true); 630 mInputView.setKeyboard(mSymbolsShiftedKeyboard); 631 mSymbolsShiftedKeyboard.setShifted(true); 632 } else if (currentKeyboard == mSymbolsShiftedKeyboard) { 633 mSymbolsShiftedKeyboard.setShifted(false); 634 mInputView.setKeyboard(mSymbolsKeyboard); 635 mSymbolsKeyboard.setShifted(false); 636 } 637 } 638 639 private void handleCharacter(int primaryCode, int[] keyCodes) { 640 if (isInputViewShown()) { 641 if (mInputView.isShifted()) { 642 primaryCode = Character.toUpperCase(primaryCode); 643 } 644 } 645 if (isAlphabet(primaryCode) && mPredictionOn) { 646 mComposing.append((char) primaryCode); 647 getCurrentInputConnection().setComposingText(mComposing, 1); 648 updateShiftKeyState(getCurrentInputEditorInfo()); 649 updateCandidates(); 650 } else { 651 getCurrentInputConnection().commitText(String.valueOf((char) primaryCode), 1); 652 } 653 } 654 655 private void handleClose() { 656 commitTyped(getCurrentInputConnection()); 657 requestHideSelf(0); 658 mInputView.closing(); 659 } 660 661 private void checkToggleCapsLock() { 662 long now = System.currentTimeMillis(); 663 if (mLastShiftTime + 800 > now) { 664 mCapsLock = !mCapsLock; 665 mLastShiftTime = 0; 666 } else { 667 mLastShiftTime = now; 668 } 669 } 670 671 private String getWordSeparators() { 672 return mWordSeparators; 673 } 674 675 public boolean isWordSeparator(int code) { 676 String separators = getWordSeparators(); 677 return separators.contains(String.valueOf((char) code)); 678 } 679 680 public void pickDefaultCandidate() { 681 pickSuggestionManually(0); 682 } 683 684 public void pickSuggestionManually(int index) { 685 if (mCompletionOn && mCompletions != null && index >= 0 && index < mCompletions.length) { 686 CompletionInfo ci = mCompletions[index]; 687 getCurrentInputConnection().commitCompletion(ci); 688 if (mCandidateView != null) { 689 mCandidateView.clear(); 690 } 691 updateShiftKeyState(getCurrentInputEditorInfo()); 692 } else if (mComposing.length() > 0) { 693 // If we were generating candidate suggestions for the current 694 // text, we would commit one of them here. But for this sample, 695 // we will just commit the current text. 696 commitTyped(getCurrentInputConnection()); 697 } 698 } 699 700 public void swipeRight() { 701 if (mCompletionOn) { 702 pickDefaultCandidate(); 703 } 704 } 705 706 public void swipeLeft() { 707 handleBackspace(); 708 } 709 710 public void swipeDown() { 711 handleClose(); 712 } 713 714 public void swipeUp() { 715 } 716 717 public void onPress(int primaryCode) { 718 } 719 720 public void onRelease(int primaryCode) { 721 } 722 723 /* 724 public void onComputeInsets(Insets outInsets) { 725 View decor = getWindow().getWindow().getDecorView(); 726 outInsets.visibleTopInsets = decor.getHeight(); //0; 727 outInsets.contentTopInsets = 0; //decor.getHeight(); 728 outInsets.touchableInsets = Insets.TOUCHABLE_INSETS_FRAME; 729 } 730 */ 731 732 733 public boolean isLandscape() { 734 if (getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE){ 735 return true; 736 } 737 return false; 738 } 739 740 @Override 741 public boolean onEvaluateFullscreenMode(){ 742 return true; 743 } 744 745 @Override 746 public void onUpdateExtractingVisibility (EditorInfo ei){ 747 ei.imeOptions = EditorInfo.TYPE_NULL; 748// ei.imeOptions = EditorInfo.IME_FLAG_NO_EXTRACT_UI; 749 setExtractViewShown(false); 750 } 751 752 @Override 753 public void onUpdateExtractingViews(EditorInfo ei){ 754 ei.imeOptions = EditorInfo.TYPE_NULL; 755 // EditorInfo.IME_FLAG_NO_EXTRACT_UI; 756 setExtractViewShown(false); 757 } 758 759 @Override 760 public View onCreateExtractTextView (){ 761 return null; 762 //View extractTextView = super.onCreateExtractTextView(); 763 //extractTextView.setVisibility(View.GONE); 764 //return extractTextView; 765 } 766 767 @Override 768 public void onWindowHidden(){ 769 this.stopSelf(); 770 } 771 772 773}