1/*
2 * Copyright (C) 2011 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16package com.android.browser;
17
18import android.net.Uri;
19import android.text.TextUtils;
20import android.util.Log;
21import android.webkit.SearchBox;
22
23import java.util.Map;
24import java.util.regex.Pattern;
25
26/**
27 * Class to manage the controlling of preloaded tab.
28 */
29public class PreloadedTabControl {
30    private static final boolean LOGD_ENABLED = com.android.browser.Browser.LOGD_ENABLED;
31    private static final String LOGTAG = "PreloadedTabControl";
32
33    final Tab mTab;
34    private String mLastQuery;
35    private boolean mDestroyed;
36
37    public PreloadedTabControl(Tab t) {
38        if (LOGD_ENABLED) Log.d(LOGTAG, "PreloadedTabControl.<init>");
39        mTab = t;
40    }
41
42    private void maybeSetQuery(final String query, SearchBox sb) {
43        if (!TextUtils.equals(mLastQuery, query)) {
44            if (sb != null) {
45                if (LOGD_ENABLED) Log.d(LOGTAG, "Changing searchbox query to " + query);
46                sb.setVerbatim(true);
47                sb.setQuery(query);
48                sb.onchange(new SearchBox.SearchBoxListener() {
49                    @Override
50                    public void onChangeComplete(boolean called) {
51                        if (mDestroyed) return;
52                        if (LOGD_ENABLED) Log.d(LOGTAG, "Changed searchbox query: " + called);
53                        if (called) {
54                            mLastQuery = query;
55                        }
56                    }
57                });
58            } else {
59                if (LOGD_ENABLED) Log.d(LOGTAG, "Cannot set query: no searchbox interface");
60            }
61        }
62    }
63
64    public void setQuery(String query) {
65        maybeSetQuery(query, mTab.getWebView().getSearchBox());
66    }
67
68    public boolean searchBoxSubmit(final String query,
69            final String fallbackUrl, final Map<String, String> fallbackHeaders) {
70        final SearchBox sb = mTab.getWebView().getSearchBox();
71        if (sb == null) {
72            // no searchbox, cannot submit. Fallback to regular tab creation
73            if (LOGD_ENABLED) Log.d(LOGTAG, "No searchbox, cannot submit query");
74            return false;
75        }
76        maybeSetQuery(query, sb);
77        if (LOGD_ENABLED) Log.d(LOGTAG, "Submitting query " + query);
78        final String currentUrl = mTab.getUrl();
79        sb.onsubmit(new SearchBox.SearchBoxListener() {
80            @Override
81            public void onSubmitComplete(boolean called) {
82                if (mDestroyed) return;
83                if (LOGD_ENABLED) Log.d(LOGTAG, "Query submitted: " + called);
84                if (!called) {
85                    if (LOGD_ENABLED) Log.d(LOGTAG, "Query not submitted; falling back");
86                    loadUrl(fallbackUrl, fallbackHeaders);
87                    // make sure that the failed, preloaded URL is cleared from the back stack
88                    mTab.clearBackStackWhenItemAdded(Pattern.compile(
89                            "^" + Pattern.quote(fallbackUrl) + "$"));
90                } else {
91                    // ignore the next fragment change, to avoid leaving a blank page in the browser
92                    // after the query has been submitted.
93                    String currentWithoutFragment = Uri.parse(currentUrl)
94                            .buildUpon()
95                            .fragment(null)
96                            .toString();
97                    mTab.clearBackStackWhenItemAdded(
98                            Pattern.compile(
99                                    "^" +
100                                    Pattern.quote(currentWithoutFragment) +
101                                    "(\\#.*)?" +
102                                    "$"));
103                }
104            }});
105        return true;
106    }
107
108    public void searchBoxCancel() {
109        SearchBox sb = mTab.getWebView().getSearchBox();
110        if (sb != null) {
111            mLastQuery = null;
112            sb.oncancel(new SearchBox.SearchBoxListener(){
113                @Override
114                public void onCancelComplete(boolean called) {
115                    if (LOGD_ENABLED) Log.d(LOGTAG, "Query cancelled: " + called);
116                }
117            });
118        }
119    }
120
121    public void loadUrlIfChanged(String url, Map<String, String> headers) {
122        String currentUrl = mTab.getUrl();
123        if (!TextUtils.isEmpty(currentUrl)) {
124            try {
125                // remove fragment:
126                currentUrl = Uri.parse(currentUrl).buildUpon().fragment(null).build().toString();
127            } catch (UnsupportedOperationException e) {
128                // carry on
129            }
130        }
131        if (LOGD_ENABLED) Log.d(LOGTAG, "loadUrlIfChanged\nnew: " + url + "\nold: " +currentUrl);
132        if (!TextUtils.equals(url, currentUrl)) {
133            loadUrl(url, headers);
134        }
135    }
136
137    public void loadUrl(String url, Map<String, String> headers) {
138        if (LOGD_ENABLED) Log.d(LOGTAG, "Preloading " + url);
139        mTab.loadUrl(url, headers);
140    }
141
142    public void destroy() {
143        if (LOGD_ENABLED) Log.d(LOGTAG, "PreloadedTabControl.destroy");
144        mDestroyed = true;
145        mTab.destroy();
146    }
147
148    public Tab getTab() {
149        return mTab;
150    }
151
152}
153