/** Clears the selection. */
 void clearSelection() {
   ContentViewCore baseContentView = getBaseContentView();
   if (baseContentView != null) {
     baseContentView.clearSelection();
   }
   resetAllStates();
 }
  /**
   * Injects a <script> tag into the current web site that pulls in the ChromeVox script for
   * accessibility support. Only injects if accessibility is turned on by {@link
   * AccessibilityManager#isEnabled()}, accessibility script injection is turned on, and javascript
   * is enabled on this page.
   *
   * @see AccessibilityManager#isEnabled()
   */
  public void injectAccessibilityScriptIntoPage() {
    if (!accessibilityIsAvailable()) return;

    int axsParameterValue = getAxsUrlParameterValue();
    if (axsParameterValue == ACCESSIBILITY_SCRIPT_INJECTION_UNDEFINED) {
      try {
        Field field = Settings.Secure.class.getField("ACCESSIBILITY_SCRIPT_INJECTION");
        field.setAccessible(true);
        String ACCESSIBILITY_SCRIPT_INJECTION = (String) field.get(null);

        boolean onDeviceScriptInjectionEnabled =
            (Settings.Secure.getInt(
                    mContentViewCore.getContext().getContentResolver(),
                    ACCESSIBILITY_SCRIPT_INJECTION,
                    0)
                == 1);
        String js = getScreenReaderInjectingJs();

        if (onDeviceScriptInjectionEnabled && js != null && mContentViewCore.isAlive()) {
          addOrRemoveAccessibilityApisIfNecessary();
          mContentViewCore.evaluateJavaScript(js, null);
          mInjectedScriptEnabled = true;
          mScriptInjected = true;
        }
      } catch (NoSuchFieldException ex) {
      } catch (IllegalArgumentException ex) {
      } catch (IllegalAccessException ex) {
      }
    }
  }
  @CalledByNative
  private void showAutofillPopup(
      float x,
      float y,
      float width,
      float height,
      boolean isRtl,
      AutofillSuggestion[] suggestions) {

    if (mContentViewCore == null) return;

    if (mAutofillPopup == null) {
      mAutofillPopup =
          new AutofillPopup(
              mContentViewCore.getContext(),
              mContentViewCore.getViewAndroidDelegate(),
              new AutofillPopup.AutofillPopupDelegate() {
                @Override
                public void dismissed() {}

                @Override
                public void suggestionSelected(int listIndex) {
                  nativeSuggestionSelected(mNativeXWalkAutofillClient, listIndex);
                }
              });
    }
    mAutofillPopup.setAnchorRect(x, y, width, height);
    mAutofillPopup.filterAndShow(suggestions, isRtl);
  }
 /**
  * Initializes the rendering surface parameters of {@code contentViewCore}. Note that this does
  * not size the actual {@link ContentViewCore}.
  *
  * @param contentViewCore The {@link ContentViewCore} to initialize.
  */
 private void initializeContentViewCore(ContentViewCore contentViewCore) {
   contentViewCore.setCurrentMotionEventOffsets(0.f, 0.f);
   contentViewCore.setTopControlsHeight(
       getTopControlsHeightPixels(), contentViewCore.doTopControlsShrinkBlinkSize());
   contentViewCore.onPhysicalBackingSizeChanged(
       mCompositorView.getWidth(), mCompositorView.getHeight());
   contentViewCore.onOverdrawBottomHeightChanged(mCompositorView.getOverdrawBottomHeight());
 }
  /**
   * Expands the current selection by the specified amounts.
   *
   * @param selectionStartAdjust The start offset adjustment of the selection to use to highlight
   *     the search term.
   * @param selectionEndAdjust The end offset adjustment of the selection to use to highlight the
   *     search term.
   */
  void adjustSelection(int selectionStartAdjust, int selectionEndAdjust) {
    // TODO(donnd): add code to verify that the selection is still valid before changing it.
    // crbug.com/508354

    if (selectionStartAdjust == 0 && selectionEndAdjust == 0) return;
    ContentViewCore basePageContentView = getBaseContentView();
    if (basePageContentView != null && basePageContentView.getWebContents() != null) {
      mDidExpandSelection = true;
      basePageContentView
          .getWebContents()
          .adjustSelectionByCharacterOffset(selectionStartAdjust, selectionEndAdjust);
    }
  }
  protected void removeAccessibilityApis() {
    if (mTextToSpeech != null) {
      mContentViewCore.removeJavascriptInterface(ALIAS_ACCESSIBILITY_JS_INTERFACE);
      mTextToSpeech.stop();
      mTextToSpeech.shutdownInternal();
      mTextToSpeech = null;
    }

    if (mVibrator != null) {
      mContentViewCore.removeJavascriptInterface(ALIAS_ACCESSIBILITY_JS_INTERFACE_2);
      mVibrator.cancel();
      mVibrator = null;
    }
  }
  protected void addAccessibilityApis() {
    Context context = mContentViewCore.getContext();
    if (context != null) {
      // Enabled, we should try to add if we have to.
      if (mTextToSpeech == null) {
        mTextToSpeech = new TextToSpeechWrapper(mContentViewCore.getContainerView(), context);
        mContentViewCore.addJavascriptInterface(mTextToSpeech, ALIAS_ACCESSIBILITY_JS_INTERFACE);
      }

      if (mVibrator == null) {
        mVibrator = new VibratorWrapper(context);
        mContentViewCore.addJavascriptInterface(mVibrator, ALIAS_ACCESSIBILITY_JS_INTERFACE_2);
      }
    }
  }
  /**
   * Sets whether or not the script is enabled. If the script is disabled, we also stop any we
   * output that is occurring.
   *
   * @param enabled Whether or not to enable the script.
   */
  public void setScriptEnabled(boolean enabled) {
    if (!accessibilityIsAvailable() || mInjectedScriptEnabled == enabled) return;

    mInjectedScriptEnabled = enabled;
    if (mContentViewCore.isAlive()) {
      String js =
          String.format(TOGGLE_CHROME_VOX_JAVASCRIPT, Boolean.toString(mInjectedScriptEnabled));
      mContentViewCore.evaluateJavaScript(js, null);

      if (!mInjectedScriptEnabled) {
        // Stop any TTS/Vibration right now.
        onPageLostFocus();
      }
    }
  }
Example #9
0
  @Override
  public void setUp() throws Exception {
    super.setUp();

    launchContentShellWithUrl(DATA_URL);
    assertTrue("Page failed to load", waitForActiveShellToBeDoneLoading());
    mContentViewCore = getContentViewCore();
    mWebContents = getWebContents();

    mInputMethodManagerWrapper = new TestInputMethodManagerWrapper(mContentViewCore);
    getImeAdapter().setInputMethodManagerWrapper(mInputMethodManagerWrapper);
    assertEquals(0, mInputMethodManagerWrapper.getShowSoftInputCounter());
    mContentViewCore.setAdapterInputConnectionFactory(new TestAdapterInputConnectionFactory());

    mCallbackContainer = new TestCallbackHelperContainer(mContentViewCore);
    // TODO(aurimas) remove this wait once crbug.com/179511 is fixed.
    assertWaitForPageScaleFactorMatch(2);
    assertTrue(DOMUtils.waitForNonZeroNodeBounds(mWebContents, "input_text"));
    DOMUtils.clickNode(this, mContentViewCore, "input_text");
    assertWaitForKeyboardStatus(true);

    mConnection = (TestAdapterInputConnection) getAdapterInputConnection();
    mImeAdapter = getImeAdapter();

    waitAndVerifyEditableCallback(mConnection.mImeUpdateQueue, 0, "", 0, 0, -1, -1);
    assertEquals(1, mInputMethodManagerWrapper.getShowSoftInputCounter());
    assertEquals(0, mInputMethodManagerWrapper.getEditorInfo().initialSelStart);
    assertEquals(0, mInputMethodManagerWrapper.getEditorInfo().initialSelEnd);
  }
 @VisibleForTesting
 boolean isValidSelection(String selection, ContentViewCore baseContentView) {
   if (selection.length() > MAX_SELECTION_LENGTH || !doesContainAWord(selection)) {
     return false;
   }
   return baseContentView != null && !baseContentView.isFocusedNodeEditable();
 }
Example #11
0
  private AccessibilityManager getAccessibilityManager() {
    if (mAccessibilityManager == null) {
      mAccessibilityManager =
          (AccessibilityManager)
              mContentViewCore.getContext().getSystemService(Context.ACCESSIBILITY_SERVICE);
    }

    return mAccessibilityManager;
  }
Example #12
0
  private int getAxsUrlParameterValue() {
    if (mContentViewCore.getUrl() == null) return ACCESSIBILITY_SCRIPT_INJECTION_UNDEFINED;

    try {
      List<NameValuePair> params = URLEncodedUtils.parse(new URI(mContentViewCore.getUrl()), null);

      for (NameValuePair param : params) {
        if ("axs".equals(param.getName())) {
          return Integer.parseInt(param.getValue());
        }
      }
    } catch (URISyntaxException ex) {
    } catch (NumberFormatException ex) {
    } catch (IllegalArgumentException ex) {
    }

    return ACCESSIBILITY_SCRIPT_INJECTION_UNDEFINED;
  }
Example #13
0
  /** Checks whether or not touch to explore is enabled on the system. */
  public boolean accessibilityIsAvailable() {
    if (!getAccessibilityManager().isEnabled()
        || mContentViewCore.getContentSettings() == null
        || !mContentViewCore.getContentSettings().getJavaScriptEnabled()) {
      return false;
    }

    try {
      // Check that there is actually a service running that requires injecting this script.
      List<AccessibilityServiceInfo> services =
          getAccessibilityManager()
              .getEnabledAccessibilityServiceList(
                  FEEDBACK_BRAILLE | AccessibilityServiceInfo.FEEDBACK_SPOKEN);
      return services.size() > 0;
    } catch (NullPointerException e) {
      // getEnabledAccessibilityServiceList() can throw an NPE due to a bad
      // AccessibilityService.
      return false;
    }
  }
Example #14
0
  @SmallTest
  @Feature({"TextInput"})
  public void testTextHandlesPreservedWithDpadNavigation() throws Throwable {
    DOMUtils.longPressNode(this, mContentViewCore, "plain_text");
    assertWaitForSelectActionBarStatus(true);
    assertTrue(mContentViewCore.hasSelection());

    ThreadUtils.runOnUiThreadBlocking(
        new Runnable() {
          @Override
          public void run() {
            final KeyEvent downKeyEvent =
                new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DPAD_DOWN);
            mImeAdapter.dispatchKeyEvent(downKeyEvent);
          }
        });

    assertWaitForSelectActionBarStatus(true);
    assertTrue(mContentViewCore.hasSelection());
  }
 /**
  * Starts evaluation of a given JavaScript code on a given contentViewCore.
  *
  * @param contentViewCore A ContentViewCore instance to be used.
  * @param code A JavaScript code to be evaluated.
  */
 public void evaluateJavaScript(ContentViewCore contentViewCore, String code) {
   JavaScriptCallback callback =
       new JavaScriptCallback() {
         @Override
         public void handleJavaScriptResult(String jsonResult) {
           notifyCalled(jsonResult);
         }
       };
   contentViewCore.evaluateJavaScript(code, callback);
   mJsonResult = null;
 }
Example #16
0
 @SmallTest
 @Feature({"TextInput"})
 public void testKeyboardNotDismissedAfterCopySelection() throws Exception {
   commitText(mConnection, "Sample Text", 1);
   waitAndVerifyEditableCallback(mConnection.mImeUpdateQueue, 1, "Sample Text", 11, 11, -1, -1);
   DOMUtils.clickNode(this, mContentViewCore, "input_text");
   assertWaitForKeyboardStatus(true);
   DOMUtils.longPressNode(this, mContentViewCore, "input_text");
   selectAll(mImeAdapter);
   copy(mImeAdapter);
   assertWaitForKeyboardStatus(true);
   assertEquals(11, Selection.getSelectionEnd(mContentViewCore.getEditableForTest()));
 }
  /**
   * Handles a notification that a selection event took place.
   *
   * @param eventType The type of event that took place.
   * @param posXPix The x coordinate of the selection start handle.
   * @param posYPix The y coordinate of the selection start handle.
   */
  void handleSelectionEvent(int eventType, float posXPix, float posYPix) {
    boolean shouldHandleSelection = false;
    switch (eventType) {
      case SelectionEventType.SELECTION_HANDLES_SHOWN:
        mWasTapGestureDetected = false;
        mSelectionType = SelectionType.LONG_PRESS;
        shouldHandleSelection = true;
        // Since we're showing pins, we don't care if the previous tap was invalid anymore.
        unscheduleInvalidTapNotification();
        break;
      case SelectionEventType.SELECTION_HANDLES_CLEARED:
        mHandler.handleSelectionDismissal();
        resetAllStates();
        break;
      case SelectionEventType.SELECTION_HANDLE_DRAG_STOPPED:
        shouldHandleSelection = mShouldHandleSelectionModification;
        break;
      case SelectionEventType.SELECTION_ESTABLISHED:
        mIsSelectionEstablished = true;
        break;
      case SelectionEventType.SELECTION_DISSOLVED:
        mIsSelectionEstablished = false;
        break;
      default:
    }

    if (shouldHandleSelection) {
      ContentViewCore baseContentView = getBaseContentView();
      if (baseContentView != null) {
        String selection = baseContentView.getSelectedText();
        if (selection != null) {
          mX = posXPix;
          mY = posYPix;
          mSelectedText = selection;
          handleSelection(selection, SelectionType.LONG_PRESS);
        }
      }
    }
  }
  /**
   * Tests that the showing select popup does not get closed because an unrelated ContentView gets
   * destroyed. @LargeTest @Feature({"Browser"}) BUG 172967
   */
  @DisabledTest
  public void testPopupNotClosedByOtherContentView()
      throws InterruptedException, Exception, Throwable {
    // Load the test page.
    launchChromeShellWithUrl(SELECT_URL);
    assertTrue("Page failed to load", waitForActiveShellToBeDoneLoading());

    final ContentViewCore viewCore = getActivity().getActiveContentViewCore();

    // Once clicked, the popup should show up.
    DOMUtils.clickNode(this, viewCore, "select");
    assertTrue(
        "The select popup did not show up on click.",
        CriteriaHelper.pollForCriteria(new PopupShowingCriteria()));

    // Now create and destroy a different ContentView.
    ThreadUtils.runOnUiThreadBlocking(
        new Runnable() {
          @Override
          public void run() {
            long nativeWebContents = ContentViewUtil.createNativeWebContents(false);
            WindowAndroid windowAndroid = new ActivityWindowAndroid(getActivity());

            ContentViewCore contentViewCore = new ContentViewCore(getActivity());
            ContentView cv = ContentView.newInstance(getActivity(), contentViewCore);
            contentViewCore.initialize(cv, cv, nativeWebContents, windowAndroid);
            contentViewCore.destroy();
          }
        });

    // Process some more events to give a chance to the dialog to hide if it were to.
    getInstrumentation().waitForIdleSync();

    // The popup should still be shown.
    assertNotNull(
        "The select popup got hidden by destroying of unrelated ContentViewCore.",
        viewCore.getSelectPopupForTest());
  }
 public TestCallbackHelperContainer(final ContentViewCore contentViewCore) {
   mTestContentViewClient = new TestContentViewClient();
   contentViewCore.setContentViewClient(mTestContentViewClient);
   // TODO(yfriedman): Change callers to be executed on the UI thread. Unfortunately this is
   // super convenient as the caller is nearly always on the test thread which is fine to block
   // and it's cumbersome to keep bouncing to the UI thread.
   ThreadUtils.runOnUiThreadBlocking(
       new Runnable() {
         @Override
         public void run() {
           mTestWebContentsObserver = new TestWebContentsObserver(contentViewCore);
         }
       });
 }
  private void setContentViewMotionEventOffsets(MotionEvent e, boolean canClear) {
    // TODO(dtrainor): Factor this out to LayoutDriver.
    if (e == null || mTabVisible == null) return;

    ContentViewCore contentViewCore = mTabVisible.getContentViewCore();
    if (contentViewCore == null) return;

    int actionMasked = e.getActionMasked();

    if (SPenSupport.isSPenSupported(getContext())) {
      actionMasked = SPenSupport.convertSPenEventAction(actionMasked);
    }

    if (actionMasked == MotionEvent.ACTION_DOWN || actionMasked == MotionEvent.ACTION_HOVER_ENTER) {
      if (mLayoutManager != null) mLayoutManager.getViewportPixel(mCacheViewport);
      contentViewCore.setCurrentMotionEventOffsets(-mCacheViewport.left, -mCacheViewport.top);
    } else if (canClear
        && (actionMasked == MotionEvent.ACTION_UP
            || actionMasked == MotionEvent.ACTION_CANCEL
            || actionMasked == MotionEvent.ACTION_HOVER_EXIT)) {
      contentViewCore.setCurrentMotionEventOffsets(0.f, 0.f);
    }
  }
Example #21
0
  @SmallTest
  @Feature({"TextInput", "Main"})
  public void testDpadKeyCodesWhileSwipingText() throws Throwable {
    DOMUtils.focusNode(mWebContents, "textarea");
    assertWaitForKeyboardStatus(true);

    mConnection = (TestAdapterInputConnection) getAdapterInputConnection();
    waitAndVerifyEditableCallback(mConnection.mImeUpdateQueue, 0, "", 0, 0, -1, -1);

    // DPAD_CENTER should cause keyboard to appear
    expectUpdateStateCall(mConnection);
    KeyEvent event = new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DPAD_CENTER);
    mContentViewCore.dispatchKeyEvent(event);
    assertUpdateStateCall(mConnection, 1000);
  }
  /**
   * Starts showing a context menu for {@code view} based on {@code params}.
   *
   * @param contentViewCore The {@link ContentViewCore} to show the menu to.
   * @param params The {@link ContextMenuParams} that indicate what menu items to show.
   */
  @CalledByNative
  private void showContextMenu(ContentViewCore contentViewCore, ContextMenuParams params) {
    final View view = contentViewCore.getContainerView();

    if (!shouldShowMenu(params)
        || view == null
        || view.getVisibility() != View.VISIBLE
        || view.getParent() == null) {
      return;
    }

    mCurrentContextMenuParams = params;

    view.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
    view.setOnCreateContextMenuListener(this);
    view.showContextMenu();
  }
Example #23
0
  @SmallTest
  @Feature({"TextInput"})
  public void testPastePopupShowOnLongPress() throws Throwable {
    commitText(mConnection, "hello", 1);
    waitAndVerifyEditableCallback(mConnection.mImeUpdateQueue, 1, "hello", 5, 5, -1, -1);

    selectAll(mImeAdapter);
    waitAndVerifyEditableCallback(mConnection.mImeUpdateQueue, 2, "hello", 0, 5, -1, -1);

    cut(mImeAdapter);
    waitAndVerifyEditableCallback(mConnection.mImeUpdateQueue, 0, "", 0, 0, -1, -1);

    DOMUtils.longPressNode(this, mContentViewCore, "input_text");
    final PastePopupMenu pastePopup = mContentViewCore.getPastePopupForTest();
    assertTrue(
        CriteriaHelper.pollForCriteria(
            new Criteria() {
              @Override
              public boolean isSatisfied() {
                return pastePopup.isShowing();
              }
            }));
  }
Example #24
0
 private static boolean isGamepadAPIActive(ChromeActivity activity) {
   ContentViewCore cvc = activity.getCurrentContentViewCore();
   return (cvc != null) ? cvc.isGamepadAPIActive() : false;
 }
 @Override
 public boolean isSatisfied() {
   ContentViewCore contentViewCore = getActivity().getActiveContentViewCore();
   return contentViewCore.getSelectPopupForTest() != null;
 }
Example #26
0
 private AdapterInputConnection getAdapterInputConnection() {
   return mContentViewCore.getInputConnectionForTest();
 }
Example #27
0
 private ImeAdapter getImeAdapter() {
   return mContentViewCore.getImeAdapterForTest();
 }
Example #28
0
  /**
   * This should be called from the Activity's onKeyDown() to handle keyboard shortcuts.
   *
   * <p>Note: onKeyDown() is called after the active view or web page has had a chance to handle the
   * key event. So the keys handled here *can* be overridden by any view or web page.
   *
   * @param event The KeyEvent to handle.
   * @param activity The ChromeActivity in which the key was pressed.
   * @param isCurrentTabVisible Whether page-related actions are valid, e.g. reload, zoom in. This
   *     should be false when in the tab switcher.
   * @param tabSwitchingEnabled Whether shortcuts that switch between tabs are enabled (e.g.
   *     Ctrl+Tab, Ctrl+3).
   * @return Whether the key event was handled.
   */
  public static boolean onKeyDown(
      KeyEvent event,
      ChromeActivity activity,
      boolean isCurrentTabVisible,
      boolean tabSwitchingEnabled) {
    int keyCode = event.getKeyCode();
    if (event.getRepeatCount() != 0 || KeyEvent.isModifierKey(keyCode)) return false;
    if (KeyEvent.isGamepadButton(keyCode)) {
      if (isGamepadAPIActive(activity)) return false;
    } else if (!event.isCtrlPressed()
        && !event.isAltPressed()
        && keyCode != KeyEvent.KEYCODE_F3
        && keyCode != KeyEvent.KEYCODE_F5
        && keyCode != KeyEvent.KEYCODE_F10
        && keyCode != KeyEvent.KEYCODE_FORWARD) {
      return false;
    }

    TabModel curModel = activity.getCurrentTabModel();
    int count = curModel.getCount();

    int metaState = getMetaState(event);
    int keyCodeAndMeta = keyCode | metaState;

    switch (keyCodeAndMeta) {
      case CTRL | SHIFT | KeyEvent.KEYCODE_T:
        activity.onMenuOrKeyboardAction(R.id.open_recently_closed_tab, false);
        return true;
      case CTRL | KeyEvent.KEYCODE_T:
        activity.onMenuOrKeyboardAction(
            curModel.isIncognito() ? R.id.new_incognito_tab_menu_id : R.id.new_tab_menu_id, false);
        return true;
      case CTRL | KeyEvent.KEYCODE_N:
        activity.onMenuOrKeyboardAction(R.id.new_tab_menu_id, false);
        return true;
      case CTRL | SHIFT | KeyEvent.KEYCODE_N:
        activity.onMenuOrKeyboardAction(R.id.new_incognito_tab_menu_id, false);
        return true;
        // Alt+E represents a special character ยด (latin code: &#180) in Android.
        // If an EditText or ContentView has focus, Alt+E will be swallowed by
        // the default dispatchKeyEvent and cannot open the menu.
      case ALT | KeyEvent.KEYCODE_E:
      case ALT | KeyEvent.KEYCODE_F:
      case KeyEvent.KEYCODE_F10:
      case KeyEvent.KEYCODE_BUTTON_Y:
        activity.onMenuOrKeyboardAction(R.id.show_menu, false);
        return true;
    }

    if (isCurrentTabVisible) {
      if (tabSwitchingEnabled && (metaState == CTRL || metaState == ALT)) {
        int numCode = keyCode - KeyEvent.KEYCODE_0;
        if (numCode > 0 && numCode <= Math.min(count, 8)) {
          // Ctrl+1 to Ctrl+8: select tab by index
          TabModelUtils.setIndex(curModel, numCode - 1);
          return true;
        } else if (numCode == 9 && count != 0) {
          // Ctrl+9: select last tab
          TabModelUtils.setIndex(curModel, count - 1);
          return true;
        }
      }

      switch (keyCodeAndMeta) {
        case CTRL | KeyEvent.KEYCODE_TAB:
        case CTRL | KeyEvent.KEYCODE_PAGE_DOWN:
        case KeyEvent.KEYCODE_BUTTON_R1:
          if (tabSwitchingEnabled && count > 1) {
            TabModelUtils.setIndex(curModel, (curModel.index() + 1) % count);
          }
          return true;
        case CTRL | SHIFT | KeyEvent.KEYCODE_TAB:
        case CTRL | KeyEvent.KEYCODE_PAGE_UP:
        case KeyEvent.KEYCODE_BUTTON_L1:
          if (tabSwitchingEnabled && count > 1) {
            TabModelUtils.setIndex(curModel, (curModel.index() + count - 1) % count);
          }
          return true;
        case CTRL | KeyEvent.KEYCODE_W:
        case CTRL | KeyEvent.KEYCODE_F4:
        case KeyEvent.KEYCODE_BUTTON_B:
          TabModelUtils.closeCurrentTab(curModel);
          return true;
        case CTRL | KeyEvent.KEYCODE_F:
        case CTRL | KeyEvent.KEYCODE_G:
        case CTRL | SHIFT | KeyEvent.KEYCODE_G:
        case KeyEvent.KEYCODE_F3:
        case SHIFT | KeyEvent.KEYCODE_F3:
          activity.onMenuOrKeyboardAction(R.id.find_in_page_id, false);
          return true;
        case CTRL | KeyEvent.KEYCODE_L:
        case ALT | KeyEvent.KEYCODE_D:
        case KeyEvent.KEYCODE_BUTTON_X:
          activity.onMenuOrKeyboardAction(R.id.focus_url_bar, false);
          return true;
        case CTRL | SHIFT | KeyEvent.KEYCODE_B:
          activity.onMenuOrKeyboardAction(R.id.all_bookmarks_menu_id, false);
          return true;
        case KeyEvent.KEYCODE_BOOKMARK:
        case CTRL | KeyEvent.KEYCODE_D:
          activity.onMenuOrKeyboardAction(R.id.bookmark_this_page_id, false);
          return true;
        case CTRL | KeyEvent.KEYCODE_H:
          activity.onMenuOrKeyboardAction(R.id.open_history_menu_id, false);
          return true;
        case CTRL | KeyEvent.KEYCODE_P:
          activity.onMenuOrKeyboardAction(R.id.print_id, false);
          return true;
        case CTRL | KeyEvent.KEYCODE_PLUS:
        case CTRL | KeyEvent.KEYCODE_EQUALS:
        case CTRL | SHIFT | KeyEvent.KEYCODE_PLUS:
        case CTRL | SHIFT | KeyEvent.KEYCODE_EQUALS:
        case KeyEvent.KEYCODE_ZOOM_IN:
          ContentViewCore cvc = activity.getCurrentContentViewCore();
          if (cvc != null) cvc.zoomIn();
          return true;
        case CTRL | KeyEvent.KEYCODE_MINUS:
        case KeyEvent.KEYCODE_ZOOM_OUT:
          cvc = activity.getCurrentContentViewCore();
          if (cvc != null) cvc.zoomOut();
          return true;
        case CTRL | KeyEvent.KEYCODE_0:
          cvc = activity.getCurrentContentViewCore();
          if (cvc != null) cvc.zoomReset();
          return true;
        case SHIFT | CTRL | KeyEvent.KEYCODE_R:
        case CTRL | KeyEvent.KEYCODE_R:
        case SHIFT | KeyEvent.KEYCODE_F5:
        case KeyEvent.KEYCODE_F5:
          Tab tab = activity.getActivityTab();
          if (tab != null) {
            if ((keyCodeAndMeta & SHIFT) == SHIFT) {
              tab.reloadIgnoringCache();
            } else {
              tab.reload();
            }

            if (activity.getToolbarManager() != null
                && tab.getWebContents() != null
                && tab.getWebContents().focusLocationBarByDefault()) {
              activity.getToolbarManager().revertLocationBarChanges();
            } else {
              tab.requestFocus();
            }
          }
          return true;
        case ALT | KeyEvent.KEYCODE_DPAD_LEFT:
          tab = activity.getActivityTab();
          if (tab != null && tab.canGoBack()) tab.goBack();
          return true;
        case ALT | KeyEvent.KEYCODE_DPAD_RIGHT:
        case KeyEvent.KEYCODE_FORWARD:
        case KeyEvent.KEYCODE_BUTTON_START:
          tab = activity.getActivityTab();
          if (tab != null && tab.canGoForward()) tab.goForward();
          return true;
        case CTRL | SHIFT | KeyEvent.KEYCODE_SLASH: // i.e. Ctrl+?
          activity.onMenuOrKeyboardAction(R.id.help_id, false);
          return true;
      }
    }

    return false;
  }
 @Override
 public void onContentViewCoreAdded(ContentViewCore content) {
   // TODO(dtrainor): Look into rolling this into onContentChanged().
   initializeContentViewCore(content);
   setSizeOfUnattachedView(content.getContainerView());
 }
  private void updateContentOverlayVisibility(boolean show) {
    if (mView == null) return;

    sCachedCVCList.clear();
    if (mLayoutManager != null) {
      mLayoutManager.getActiveLayout().getAllContentViewCores(sCachedCVCList);
    }
    if (show) {
      if (mView.getParent() != this) {
        // Make sure the view isn't a child of something else before we attempt to add it.
        if (mView.getParent() != null && mView.getParent() instanceof ViewGroup) {
          ((ViewGroup) mView.getParent()).removeView(mView);
        }

        for (int i = 0; i < sCachedCVCList.size(); i++) {
          ContentViewCore content = sCachedCVCList.get(i);
          assert content.isAlive();
          content.getContainerView().setVisibility(View.VISIBLE);
          if (mFullscreenManager != null) {
            mFullscreenManager.updateContentViewViewportSize(content);
          }
        }

        FrameLayout.LayoutParams layoutParams =
            new FrameLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
        if (mView.getLayoutParams() instanceof MarginLayoutParams) {
          MarginLayoutParams existingLayoutParams = (MarginLayoutParams) mView.getLayoutParams();
          layoutParams.leftMargin = existingLayoutParams.leftMargin;
          layoutParams.rightMargin = existingLayoutParams.rightMargin;
          layoutParams.topMargin = existingLayoutParams.topMargin;
          layoutParams.bottomMargin = existingLayoutParams.bottomMargin;
        }
        addView(mView, layoutParams);

        setFocusable(false);
        setFocusableInTouchMode(false);

        // Claim focus for the new view unless the user is currently using the URL bar.
        if (mUrlBar == null || !mUrlBar.hasFocus()) mView.requestFocus();
      }
    } else {
      if (mView.getParent() == this) {
        setFocusable(true);
        setFocusableInTouchMode(true);

        for (int i = 0; i < sCachedCVCList.size(); i++) {
          ContentViewCore content = sCachedCVCList.get(i);
          if (content.isAlive()) content.getContainerView().setVisibility(View.INVISIBLE);
        }

        if (hasFocus()) {
          InputMethodManager manager =
              (InputMethodManager) getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
          if (manager.isActive(this)) {
            manager.hideSoftInputFromWindow(getWindowToken(), 0, null);
          }
        }
        removeView(mView);
      }
    }
    sCachedCVCList.clear();
  }