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