blob: dcd46abe604d13393fb6933cddca35f19b255823 [file] [log] [blame]
// Copyright 2015 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.Context;
import android.graphics.Canvas;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.view.TouchDelegate;
import android.view.View;
import android.view.WindowManager;
import org.chromium.chrome.R;
import org.chromium.chrome.browser.WindowDelegate;
/**
* A location bar implementation specific for smaller/phone screens.
*/
public class LocationBarPhone extends LocationBarLayout {
private static final int KEYBOARD_MODE_CHANGE_DELAY_MS = 300;
private static final int KEYBOARD_HIDE_DELAY_MS = 150;
private static final int ACTION_BUTTON_TOUCH_OVERFLOW_LEFT = 15;
private View mFirstVisibleFocusedView;
private Runnable mKeyboardResizeModeTask;
/**
* Constructor used to inflate from XML.
*/
public LocationBarPhone(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
protected void onFinishInflate() {
super.onFinishInflate();
mFirstVisibleFocusedView = findViewById(R.id.url_bar);
Rect delegateArea = new Rect();
mUrlActionContainer.getHitRect(delegateArea);
delegateArea.left -= ACTION_BUTTON_TOUCH_OVERFLOW_LEFT;
TouchDelegate touchDelegate = new TouchDelegate(delegateArea, mUrlActionContainer);
assert mUrlActionContainer.getParent() == this;
setTouchDelegate(touchDelegate);
}
/**
* @return The first view visible when the location bar is focused.
*/
public View getFirstViewVisibleWhenFocused() {
return mFirstVisibleFocusedView;
}
/**
* Updates percentage of current the URL focus change animation.
* @param percent 1.0 is 100% focused, 0 is completely unfocused.
*/
public void setUrlFocusChangePercent(float percent) {
mUrlFocusChangePercent = percent;
if (percent > 0f) {
mUrlActionContainer.setVisibility(VISIBLE);
} else if (percent == 0f && !isUrlFocusChangeInProgress()) {
// If a URL focus change is in progress, then it will handle setting the visibility
// correctly after it completes. If done here, it would cause the URL to jump due
// to a badly timed layout call.
mUrlActionContainer.setVisibility(GONE);
}
updateButtonVisibility();
}
@Override
public void onUrlFocusChange(boolean hasFocus) {
if (hasFocus) {
// Remove the focus of this view once the URL field has taken focus as this view no
// longer needs it.
setFocusable(false);
setFocusableInTouchMode(false);
}
setUrlFocusChangeInProgress(true);
super.onUrlFocusChange(hasFocus);
}
@Override
protected boolean drawChild(Canvas canvas, View child, long drawingTime) {
boolean needsCanvasRestore = false;
if (child == mUrlBar && mUrlActionContainer.getVisibility() == VISIBLE) {
canvas.save();
// Clip the URL bar contents to ensure they do not draw under the URL actions during
// focus animations. Based on the RTL state of the location bar, the url actions
// container can be on the left or right side, so clip accordingly.
if (mUrlBar.getLeft() < mUrlActionContainer.getLeft()) {
canvas.clipRect(0, 0, (int) mUrlActionContainer.getX(), getBottom());
} else {
canvas.clipRect(mUrlActionContainer.getX() + mUrlActionContainer.getWidth(), 0,
getWidth(), getBottom());
}
needsCanvasRestore = true;
}
boolean retVal = super.drawChild(canvas, child, drawingTime);
if (needsCanvasRestore) {
canvas.restore();
}
return retVal;
}
/**
* Handles any actions to be performed after all other actions triggered by the URL focus
* change. This will be called after any animations are performed to transition from one
* focus state to the other.
* @param hasFocus Whether the URL field has gained focus.
*/
public void finishUrlFocusChange(boolean hasFocus) {
if (!hasFocus) {
// The animation rendering may not yet be 100% complete and hiding the keyboard makes
// the animation quite choppy.
postDelayed(new Runnable() {
@Override
public void run() {
getWindowAndroid().getKeyboardDelegate().hideKeyboard(mUrlBar);
}
}, KEYBOARD_HIDE_DELAY_MS);
// Convert the keyboard back to resize mode (delay the change for an arbitrary amount
// of time in hopes the keyboard will be completely hidden before making this change).
setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE, true);
mUrlActionContainer.setVisibility(GONE);
} else {
setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN, false);
getWindowAndroid().getKeyboardDelegate().showKeyboard(mUrlBar);
}
setUrlFocusChangeInProgress(false);
}
@Override
protected void updateButtonVisibility() {
super.updateButtonVisibility();
updateMicButtonVisibility(mUrlFocusChangePercent);
}
@Override
public boolean shouldAnimateIconChanges() {
return super.shouldAnimateIconChanges() || isUrlFocusChangeInProgress();
}
/**
* @param softInputMode The software input resize mode.
* @param delay Delay the change in input mode.
*/
private void setSoftInputMode(final int softInputMode, boolean delay) {
final WindowDelegate delegate = getWindowDelegate();
if (mKeyboardResizeModeTask != null) {
removeCallbacks(mKeyboardResizeModeTask);
mKeyboardResizeModeTask = null;
}
if (delegate == null || delegate.getWindowSoftInputMode() == softInputMode) return;
if (delay) {
mKeyboardResizeModeTask = new Runnable() {
@Override
public void run() {
delegate.setWindowSoftInputMode(softInputMode);
mKeyboardResizeModeTask = null;
}
};
postDelayed(mKeyboardResizeModeTask, KEYBOARD_MODE_CHANGE_DELAY_MS);
} else {
delegate.setWindowSoftInputMode(softInputMode);
}
}
}