| Index: chrome/android/java/src/org/chromium/chrome/browser/omnibox/KeyboardHideHelper.java
|
| diff --git a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/KeyboardHideHelper.java b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/KeyboardHideHelper.java
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..673472c6f9ebfcc9646a0ac5cfa3123b41bd0954
|
| --- /dev/null
|
| +++ b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/KeyboardHideHelper.java
|
| @@ -0,0 +1,119 @@
|
| +// Copyright 2017 The Chromium Authors. All rights reserved.
|
| +// Use of this source code is governed by a BSD-style license that can be
|
| +// found in the LICENSE file.
|
| +
|
| +package org.chromium.chrome.browser.omnibox;
|
| +
|
| +import android.content.res.Configuration;
|
| +import android.graphics.Rect;
|
| +import android.view.View;
|
| +import android.view.ViewTreeObserver;
|
| +import android.view.WindowManager;
|
| +
|
| +import org.chromium.base.VisibleForTesting;
|
| +import org.chromium.chrome.browser.WindowDelegate;
|
| +
|
| +/**
|
| + * Helps to detect whether the virtual keyboard was hidden to allow unfocusing of the omnibox.
|
| + * <p>
|
| + * There are no Android APIs to determine the visibility of a soft keyboard, so this class
|
| + * aggressively detects signals that might indicate the keyboard has been hidden.
|
| + */
|
| +class KeyboardHideHelper implements ViewTreeObserver.OnGlobalLayoutListener {
|
| + private static final long SOFT_KEYBOARD_HIDDEN_TIMEOUT_MS = 1000;
|
| +
|
| + private final View mView;
|
| + private final Runnable mOnHideCallback;
|
| + private final Runnable mClearListenerDelayedTask;
|
| + private final Rect mTempRect;
|
| +
|
| + private WindowDelegate mWindowDelegate;
|
| + private boolean mIsLayoutListenerAttached;
|
| + private int mInitialViewportHeight;
|
| +
|
| + /**
|
| + * Constructs the helper for hiding the keyboard.
|
| + *
|
| + * @param view The view the keyboard is shown for.
|
| + * @param onHideCallback The callback to be triggered when the keyboard is detected as hidden.
|
| + */
|
| + public KeyboardHideHelper(View view, Runnable onHideCallback) {
|
| + mView = view;
|
| + mOnHideCallback = onHideCallback;
|
| + mClearListenerDelayedTask = new Runnable() {
|
| + @Override
|
| + public void run() {
|
| + cleanUp();
|
| + }
|
| + };
|
| + mTempRect = new Rect();
|
| + }
|
| +
|
| + /**
|
| + * Initialize the delegate that allows interaction with the Window.
|
| + */
|
| + public void setWindowDelegate(WindowDelegate windowDelegate) {
|
| + mWindowDelegate = windowDelegate;
|
| + }
|
| +
|
| + /**
|
| + * Begin monitoring for keyboard hidden and defocuses the omnibox if it is detected.
|
| + * <p>
|
| + * Only call this method once a strong signal arrives that indicates the keyboard likely will
|
| + * be hidden (i.e. KeyEvent.KEYCODE_BACK in View#onKeyPreIme). Any increase in window size will
|
| + * trigger the hide callback to be notified after this is called. This is meant to be a "good"
|
| + * approximation for user intent to dimiss the keyboard to compensate for the lack of a proper
|
| + * signal from the system.
|
| + */
|
| + public void monitorForKeyboardHidden() {
|
| + cleanUp();
|
| +
|
| + // If a hardware keyboard is attached, they might be hiding the virtual keyboard, but
|
| + // attempting to continue typing with the hardware keyboard. Disable unfocusing the
|
| + // omnibox automatically if we detect this case might be possible.
|
| + if (mView.getResources().getConfiguration().keyboard == Configuration.KEYBOARD_QWERTY) {
|
| + return;
|
| + }
|
| +
|
| + if (mWindowDelegate != null) {
|
| + assert mWindowDelegate.getWindowSoftInputMode()
|
| + != WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING
|
| + : "SOFT_INPUT_ADJUST_NOTHING prevents detecting window size changes.";
|
| + }
|
| +
|
| + mView.getViewTreeObserver().addOnGlobalLayoutListener(this);
|
| + mIsLayoutListenerAttached = true;
|
| +
|
| + mInitialViewportHeight = availableWindowHeight();
|
| + mView.postDelayed(mClearListenerDelayedTask, SOFT_KEYBOARD_HIDDEN_TIMEOUT_MS);
|
| + }
|
| +
|
| + @Override
|
| + public void onGlobalLayout() {
|
| + if (availableWindowHeight() > mInitialViewportHeight) {
|
| + mOnHideCallback.run();
|
| + cleanUp();
|
| + }
|
| + }
|
| +
|
| + @VisibleForTesting
|
| + boolean isMonitoringForLayoutChanges() {
|
| + return mIsLayoutListenerAttached;
|
| + }
|
| +
|
| + private int availableWindowHeight() {
|
| + if (mWindowDelegate == null) {
|
| + return mView.getRootView().getHeight();
|
| + }
|
| +
|
| + mWindowDelegate.getWindowVisibleDisplayFrame(mTempRect);
|
| + return Math.min(mTempRect.height(), mWindowDelegate.getDecorViewHeight());
|
| + }
|
| +
|
| + private void cleanUp() {
|
| + if (!mIsLayoutListenerAttached) return;
|
| + mView.removeCallbacks(mClearListenerDelayedTask);
|
| + mView.getViewTreeObserver().removeOnGlobalLayoutListener(this);
|
| + mIsLayoutListenerAttached = false;
|
| + }
|
| +}
|
|
|