1718a24d6c9671fe2da4112a3b5f30fd3939b38e8John Reck/* 2718a24d6c9671fe2da4112a3b5f30fd3939b38e8John Reck * Copyright (C) 2011 The Android Open Source Project 3718a24d6c9671fe2da4112a3b5f30fd3939b38e8John Reck * 4718a24d6c9671fe2da4112a3b5f30fd3939b38e8John Reck * Licensed under the Apache License, Version 2.0 (the "License"); 5718a24d6c9671fe2da4112a3b5f30fd3939b38e8John Reck * you may not use this file except in compliance with the License. 6718a24d6c9671fe2da4112a3b5f30fd3939b38e8John Reck * You may obtain a copy of the License at 7718a24d6c9671fe2da4112a3b5f30fd3939b38e8John Reck * 8718a24d6c9671fe2da4112a3b5f30fd3939b38e8John Reck * http://www.apache.org/licenses/LICENSE-2.0 9718a24d6c9671fe2da4112a3b5f30fd3939b38e8John Reck * 10718a24d6c9671fe2da4112a3b5f30fd3939b38e8John Reck * Unless required by applicable law or agreed to in writing, software 11718a24d6c9671fe2da4112a3b5f30fd3939b38e8John Reck * distributed under the License is distributed on an "AS IS" BASIS, 12718a24d6c9671fe2da4112a3b5f30fd3939b38e8John Reck * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13718a24d6c9671fe2da4112a3b5f30fd3939b38e8John Reck * See the License for the specific language governing permissions and 14718a24d6c9671fe2da4112a3b5f30fd3939b38e8John Reck * limitations under the License. 15718a24d6c9671fe2da4112a3b5f30fd3939b38e8John Reck */ 16718a24d6c9671fe2da4112a3b5f30fd3939b38e8John Reckpackage com.android.browser; 17718a24d6c9671fe2da4112a3b5f30fd3939b38e8John Reck 18bb3a4f2a57b137a62f2cc2dc8acf51a17e62dd74John Reckimport android.os.SystemClock; 19718a24d6c9671fe2da4112a3b5f30fd3939b38e8John Reckimport android.view.MotionEvent; 20718a24d6c9671fe2da4112a3b5f30fd3939b38e8John Reckimport android.view.View; 21718a24d6c9671fe2da4112a3b5f30fd3939b38e8John Reckimport android.view.View.OnTouchListener; 22718a24d6c9671fe2da4112a3b5f30fd3939b38e8John Reckimport android.view.ViewConfiguration; 23718a24d6c9671fe2da4112a3b5f30fd3939b38e8John Reckimport android.webkit.WebView; 24718a24d6c9671fe2da4112a3b5f30fd3939b38e8John Reck 25718a24d6c9671fe2da4112a3b5f30fd3939b38e8John Reckimport com.android.browser.BrowserWebView.OnScrollChangedListener; 26718a24d6c9671fe2da4112a3b5f30fd3939b38e8John Reck 27718a24d6c9671fe2da4112a3b5f30fd3939b38e8John Reck/** 28718a24d6c9671fe2da4112a3b5f30fd3939b38e8John Reck * Helper class to manage when to show the URL bar based off of touch 29718a24d6c9671fe2da4112a3b5f30fd3939b38e8John Reck * input, and when to begin the hide timer. 30718a24d6c9671fe2da4112a3b5f30fd3939b38e8John Reck */ 31718a24d6c9671fe2da4112a3b5f30fd3939b38e8John Reckpublic class UrlBarAutoShowManager implements OnTouchListener, 32718a24d6c9671fe2da4112a3b5f30fd3939b38e8John Reck OnScrollChangedListener { 33718a24d6c9671fe2da4112a3b5f30fd3939b38e8John Reck 34718a24d6c9671fe2da4112a3b5f30fd3939b38e8John Reck private static float V_TRIGGER_ANGLE = .9f; 35bc6adb4501853dbaba1c3bb592a159ee901b70e7John Reck private static long SCROLL_TIMEOUT_DURATION = 150; 36bc6adb4501853dbaba1c3bb592a159ee901b70e7John Reck private static long IGNORE_INTERVAL = 250; 37718a24d6c9671fe2da4112a3b5f30fd3939b38e8John Reck 38718a24d6c9671fe2da4112a3b5f30fd3939b38e8John Reck private BrowserWebView mTarget; 39718a24d6c9671fe2da4112a3b5f30fd3939b38e8John Reck private BaseUi mUi; 40718a24d6c9671fe2da4112a3b5f30fd3939b38e8John Reck 41718a24d6c9671fe2da4112a3b5f30fd3939b38e8John Reck private int mSlop; 42718a24d6c9671fe2da4112a3b5f30fd3939b38e8John Reck 43718a24d6c9671fe2da4112a3b5f30fd3939b38e8John Reck private float mStartTouchX; 44718a24d6c9671fe2da4112a3b5f30fd3939b38e8John Reck private float mStartTouchY; 45718a24d6c9671fe2da4112a3b5f30fd3939b38e8John Reck private boolean mIsTracking; 46718a24d6c9671fe2da4112a3b5f30fd3939b38e8John Reck private boolean mHasTriggered; 47bc6adb4501853dbaba1c3bb592a159ee901b70e7John Reck private long mLastScrollTime; 48bc6adb4501853dbaba1c3bb592a159ee901b70e7John Reck private long mTriggeredTime; 49868efdf4ad75e35f45d129532ccaa935a0ee28adJohn Reck private boolean mIsScrolling; 50718a24d6c9671fe2da4112a3b5f30fd3939b38e8John Reck 51718a24d6c9671fe2da4112a3b5f30fd3939b38e8John Reck public UrlBarAutoShowManager(BaseUi ui) { 52718a24d6c9671fe2da4112a3b5f30fd3939b38e8John Reck mUi = ui; 53718a24d6c9671fe2da4112a3b5f30fd3939b38e8John Reck ViewConfiguration config = ViewConfiguration.get(mUi.getActivity()); 54718a24d6c9671fe2da4112a3b5f30fd3939b38e8John Reck mSlop = config.getScaledTouchSlop() * 2; 55718a24d6c9671fe2da4112a3b5f30fd3939b38e8John Reck } 56718a24d6c9671fe2da4112a3b5f30fd3939b38e8John Reck 57718a24d6c9671fe2da4112a3b5f30fd3939b38e8John Reck public void setTarget(BrowserWebView v) { 58718a24d6c9671fe2da4112a3b5f30fd3939b38e8John Reck if (mTarget == v) return; 59718a24d6c9671fe2da4112a3b5f30fd3939b38e8John Reck 60718a24d6c9671fe2da4112a3b5f30fd3939b38e8John Reck if (mTarget != null) { 61718a24d6c9671fe2da4112a3b5f30fd3939b38e8John Reck mTarget.setOnTouchListener(null); 62718a24d6c9671fe2da4112a3b5f30fd3939b38e8John Reck mTarget.setOnScrollChangedListener(null); 63718a24d6c9671fe2da4112a3b5f30fd3939b38e8John Reck } 64718a24d6c9671fe2da4112a3b5f30fd3939b38e8John Reck mTarget = v; 65718a24d6c9671fe2da4112a3b5f30fd3939b38e8John Reck if (mTarget != null) { 66718a24d6c9671fe2da4112a3b5f30fd3939b38e8John Reck mTarget.setOnTouchListener(this); 67718a24d6c9671fe2da4112a3b5f30fd3939b38e8John Reck mTarget.setOnScrollChangedListener(this); 68718a24d6c9671fe2da4112a3b5f30fd3939b38e8John Reck } 69718a24d6c9671fe2da4112a3b5f30fd3939b38e8John Reck } 70718a24d6c9671fe2da4112a3b5f30fd3939b38e8John Reck 71718a24d6c9671fe2da4112a3b5f30fd3939b38e8John Reck @Override 72718a24d6c9671fe2da4112a3b5f30fd3939b38e8John Reck public void onScrollChanged(int l, int t, int oldl, int oldt) { 73bb3a4f2a57b137a62f2cc2dc8acf51a17e62dd74John Reck mLastScrollTime = SystemClock.uptimeMillis(); 74576c37f1a4e3d978f489956eba4b7c2486ced324John Reck mIsScrolling = true; 75576c37f1a4e3d978f489956eba4b7c2486ced324John Reck if (t != 0) { 76576c37f1a4e3d978f489956eba4b7c2486ced324John Reck // If it is showing, extend it 77576c37f1a4e3d978f489956eba4b7c2486ced324John Reck if (mUi.isTitleBarShowing()) { 78576c37f1a4e3d978f489956eba4b7c2486ced324John Reck long remaining = mLastScrollTime - mTriggeredTime; 79576c37f1a4e3d978f489956eba4b7c2486ced324John Reck remaining = Math.max(BaseUi.HIDE_TITLEBAR_DELAY - remaining, 80576c37f1a4e3d978f489956eba4b7c2486ced324John Reck SCROLL_TIMEOUT_DURATION); 81576c37f1a4e3d978f489956eba4b7c2486ced324John Reck mUi.showTitleBarForDuration(remaining); 82718a24d6c9671fe2da4112a3b5f30fd3939b38e8John Reck } 83576c37f1a4e3d978f489956eba4b7c2486ced324John Reck } else { 84576c37f1a4e3d978f489956eba4b7c2486ced324John Reck mUi.suggestHideTitleBar(); 85718a24d6c9671fe2da4112a3b5f30fd3939b38e8John Reck } 86718a24d6c9671fe2da4112a3b5f30fd3939b38e8John Reck } 87718a24d6c9671fe2da4112a3b5f30fd3939b38e8John Reck 88718a24d6c9671fe2da4112a3b5f30fd3939b38e8John Reck void stopTracking() { 89718a24d6c9671fe2da4112a3b5f30fd3939b38e8John Reck if (mIsTracking) { 90718a24d6c9671fe2da4112a3b5f30fd3939b38e8John Reck mIsTracking = false; 91868efdf4ad75e35f45d129532ccaa935a0ee28adJohn Reck mIsScrolling = false; 92718a24d6c9671fe2da4112a3b5f30fd3939b38e8John Reck if (mUi.isTitleBarShowing()) { 93718a24d6c9671fe2da4112a3b5f30fd3939b38e8John Reck mUi.showTitleBarForDuration(); 94718a24d6c9671fe2da4112a3b5f30fd3939b38e8John Reck } 95718a24d6c9671fe2da4112a3b5f30fd3939b38e8John Reck } 96718a24d6c9671fe2da4112a3b5f30fd3939b38e8John Reck } 97718a24d6c9671fe2da4112a3b5f30fd3939b38e8John Reck 98718a24d6c9671fe2da4112a3b5f30fd3939b38e8John Reck @Override 99718a24d6c9671fe2da4112a3b5f30fd3939b38e8John Reck public boolean onTouch(View v, MotionEvent event) { 100718a24d6c9671fe2da4112a3b5f30fd3939b38e8John Reck if (event.getPointerCount() > 1) { 101718a24d6c9671fe2da4112a3b5f30fd3939b38e8John Reck stopTracking(); 102718a24d6c9671fe2da4112a3b5f30fd3939b38e8John Reck } 103718a24d6c9671fe2da4112a3b5f30fd3939b38e8John Reck switch (event.getAction()) { 104718a24d6c9671fe2da4112a3b5f30fd3939b38e8John Reck case MotionEvent.ACTION_DOWN: 105718a24d6c9671fe2da4112a3b5f30fd3939b38e8John Reck if (!mIsTracking && event.getPointerCount() == 1) { 106bc6adb4501853dbaba1c3bb592a159ee901b70e7John Reck long sinceLastScroll = 107da5d348361f46f9700e51f9ddd76ac5acee7a34cJohn Reck SystemClock.uptimeMillis() - mLastScrollTime; 108bc6adb4501853dbaba1c3bb592a159ee901b70e7John Reck if (sinceLastScroll < IGNORE_INTERVAL) { 109bc6adb4501853dbaba1c3bb592a159ee901b70e7John Reck break; 110bc6adb4501853dbaba1c3bb592a159ee901b70e7John Reck } 111718a24d6c9671fe2da4112a3b5f30fd3939b38e8John Reck mStartTouchY = event.getY(); 112718a24d6c9671fe2da4112a3b5f30fd3939b38e8John Reck mStartTouchX = event.getX(); 113718a24d6c9671fe2da4112a3b5f30fd3939b38e8John Reck mIsTracking = true; 114718a24d6c9671fe2da4112a3b5f30fd3939b38e8John Reck mHasTriggered = false; 115718a24d6c9671fe2da4112a3b5f30fd3939b38e8John Reck } 116718a24d6c9671fe2da4112a3b5f30fd3939b38e8John Reck break; 117718a24d6c9671fe2da4112a3b5f30fd3939b38e8John Reck case MotionEvent.ACTION_MOVE: 118718a24d6c9671fe2da4112a3b5f30fd3939b38e8John Reck if (mIsTracking && !mHasTriggered) { 119718a24d6c9671fe2da4112a3b5f30fd3939b38e8John Reck WebView web = (WebView) v; 120718a24d6c9671fe2da4112a3b5f30fd3939b38e8John Reck float dy = event.getY() - mStartTouchY; 121718a24d6c9671fe2da4112a3b5f30fd3939b38e8John Reck float ady = Math.abs(dy); 122718a24d6c9671fe2da4112a3b5f30fd3939b38e8John Reck float adx = Math.abs(event.getX() - mStartTouchX); 123718a24d6c9671fe2da4112a3b5f30fd3939b38e8John Reck if (ady > mSlop) { 124718a24d6c9671fe2da4112a3b5f30fd3939b38e8John Reck mHasTriggered = true; 125718a24d6c9671fe2da4112a3b5f30fd3939b38e8John Reck float angle = (float) Math.atan2(ady, adx); 126718a24d6c9671fe2da4112a3b5f30fd3939b38e8John Reck if (dy > mSlop && angle > V_TRIGGER_ANGLE 127718a24d6c9671fe2da4112a3b5f30fd3939b38e8John Reck && !mUi.isTitleBarShowing() 128868efdf4ad75e35f45d129532ccaa935a0ee28adJohn Reck && (web.getVisibleTitleHeight() == 0 129868efdf4ad75e35f45d129532ccaa935a0ee28adJohn Reck || (!mIsScrolling && web.getScrollY() > 0))) { 130bb3a4f2a57b137a62f2cc2dc8acf51a17e62dd74John Reck mTriggeredTime = SystemClock.uptimeMillis(); 131718a24d6c9671fe2da4112a3b5f30fd3939b38e8John Reck mUi.showTitleBar(); 132718a24d6c9671fe2da4112a3b5f30fd3939b38e8John Reck } 133718a24d6c9671fe2da4112a3b5f30fd3939b38e8John Reck } 134718a24d6c9671fe2da4112a3b5f30fd3939b38e8John Reck } 135718a24d6c9671fe2da4112a3b5f30fd3939b38e8John Reck break; 136718a24d6c9671fe2da4112a3b5f30fd3939b38e8John Reck case MotionEvent.ACTION_CANCEL: 137718a24d6c9671fe2da4112a3b5f30fd3939b38e8John Reck case MotionEvent.ACTION_UP: 138718a24d6c9671fe2da4112a3b5f30fd3939b38e8John Reck stopTracking(); 139718a24d6c9671fe2da4112a3b5f30fd3939b38e8John Reck break; 140718a24d6c9671fe2da4112a3b5f30fd3939b38e8John Reck } 141718a24d6c9671fe2da4112a3b5f30fd3939b38e8John Reck return false; 142718a24d6c9671fe2da4112a3b5f30fd3939b38e8John Reck } 143718a24d6c9671fe2da4112a3b5f30fd3939b38e8John Reck 144718a24d6c9671fe2da4112a3b5f30fd3939b38e8John Reck} 145