11461244018a225006a8d4c203f9dfe294ffe94faMichael Kolb/*
21461244018a225006a8d4c203f9dfe294ffe94faMichael Kolb * Copyright (C) 2011 The Android Open Source Project
31461244018a225006a8d4c203f9dfe294ffe94faMichael Kolb *
41461244018a225006a8d4c203f9dfe294ffe94faMichael Kolb * Licensed under the Apache License, Version 2.0 (the "License");
51461244018a225006a8d4c203f9dfe294ffe94faMichael Kolb * you may not use this file except in compliance with the License.
61461244018a225006a8d4c203f9dfe294ffe94faMichael Kolb * You may obtain a copy of the License at
71461244018a225006a8d4c203f9dfe294ffe94faMichael Kolb *
81461244018a225006a8d4c203f9dfe294ffe94faMichael Kolb *      http://www.apache.org/licenses/LICENSE-2.0
91461244018a225006a8d4c203f9dfe294ffe94faMichael Kolb *
101461244018a225006a8d4c203f9dfe294ffe94faMichael Kolb * Unless required by applicable law or agreed to in writing, software
111461244018a225006a8d4c203f9dfe294ffe94faMichael Kolb * distributed under the License is distributed on an "AS IS" BASIS,
121461244018a225006a8d4c203f9dfe294ffe94faMichael Kolb * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
131461244018a225006a8d4c203f9dfe294ffe94faMichael Kolb * See the License for the specific language governing permissions and
141461244018a225006a8d4c203f9dfe294ffe94faMichael Kolb * limitations under the License.
151461244018a225006a8d4c203f9dfe294ffe94faMichael Kolb */
161461244018a225006a8d4c203f9dfe294ffe94faMichael Kolbpackage com.android.browser;
171461244018a225006a8d4c203f9dfe294ffe94faMichael Kolb
181461244018a225006a8d4c203f9dfe294ffe94faMichael Kolbimport android.content.Context;
191461244018a225006a8d4c203f9dfe294ffe94faMichael Kolbimport android.os.Handler;
201461244018a225006a8d4c203f9dfe294ffe94faMichael Kolbimport android.os.Looper;
211461244018a225006a8d4c203f9dfe294ffe94faMichael Kolbimport android.util.Log;
22e1dbb956d762c3f07033f247c05270a9882a79a7Mathew Inwoodimport android.webkit.WebView;
231461244018a225006a8d4c203f9dfe294ffe94faMichael Kolb
241461244018a225006a8d4c203f9dfe294ffe94faMichael Kolbimport java.util.Map;
251461244018a225006a8d4c203f9dfe294ffe94faMichael Kolb
261461244018a225006a8d4c203f9dfe294ffe94faMichael Kolb/**
271461244018a225006a8d4c203f9dfe294ffe94faMichael Kolb * Singleton class for handling preload requests.
281461244018a225006a8d4c203f9dfe294ffe94faMichael Kolb */
291461244018a225006a8d4c203f9dfe294ffe94faMichael Kolbpublic class Preloader {
301461244018a225006a8d4c203f9dfe294ffe94faMichael Kolb
311461244018a225006a8d4c203f9dfe294ffe94faMichael Kolb    private final static String LOGTAG = "browser.preloader";
3229721c2c6cc7f79a52962556c4431b71bb3ce46eMathew Inwood    private final static boolean LOGD_ENABLED = com.android.browser.Browser.LOGD_ENABLED;
331461244018a225006a8d4c203f9dfe294ffe94faMichael Kolb
341461244018a225006a8d4c203f9dfe294ffe94faMichael Kolb    private static final int PRERENDER_TIMEOUT_MILLIS = 30 * 1000; // 30s
351461244018a225006a8d4c203f9dfe294ffe94faMichael Kolb
361461244018a225006a8d4c203f9dfe294ffe94faMichael Kolb    private static Preloader sInstance;
371461244018a225006a8d4c203f9dfe294ffe94faMichael Kolb
381461244018a225006a8d4c203f9dfe294ffe94faMichael Kolb    private final Context mContext;
391461244018a225006a8d4c203f9dfe294ffe94faMichael Kolb    private final Handler mHandler;
401461244018a225006a8d4c203f9dfe294ffe94faMichael Kolb    private final BrowserWebViewFactory mFactory;
41f27b710afe310d5df6ae3fac9c88b23ac78cbfe6Narayan Kamath    private volatile PreloaderSession mSession;
421461244018a225006a8d4c203f9dfe294ffe94faMichael Kolb
431461244018a225006a8d4c203f9dfe294ffe94faMichael Kolb    public static void initialize(Context context) {
441461244018a225006a8d4c203f9dfe294ffe94faMichael Kolb        sInstance = new Preloader(context);
451461244018a225006a8d4c203f9dfe294ffe94faMichael Kolb    }
461461244018a225006a8d4c203f9dfe294ffe94faMichael Kolb
471461244018a225006a8d4c203f9dfe294ffe94faMichael Kolb    public static Preloader getInstance() {
481461244018a225006a8d4c203f9dfe294ffe94faMichael Kolb        return sInstance;
491461244018a225006a8d4c203f9dfe294ffe94faMichael Kolb    }
501461244018a225006a8d4c203f9dfe294ffe94faMichael Kolb
511461244018a225006a8d4c203f9dfe294ffe94faMichael Kolb    private Preloader(Context context) {
52914c5591baeb86bf30a5bc28930071442a822d60Ben Murdoch        mContext = context.getApplicationContext();
531461244018a225006a8d4c203f9dfe294ffe94faMichael Kolb        mHandler = new Handler(Looper.getMainLooper());
54f27b710afe310d5df6ae3fac9c88b23ac78cbfe6Narayan Kamath        mSession = null;
551461244018a225006a8d4c203f9dfe294ffe94faMichael Kolb        mFactory = new BrowserWebViewFactory(context);
561461244018a225006a8d4c203f9dfe294ffe94faMichael Kolb
571461244018a225006a8d4c203f9dfe294ffe94faMichael Kolb    }
581461244018a225006a8d4c203f9dfe294ffe94faMichael Kolb
591461244018a225006a8d4c203f9dfe294ffe94faMichael Kolb    private PreloaderSession getSession(String id) {
60f27b710afe310d5df6ae3fac9c88b23ac78cbfe6Narayan Kamath        if (mSession == null) {
611461244018a225006a8d4c203f9dfe294ffe94faMichael Kolb            if (LOGD_ENABLED) Log.d(LOGTAG, "Create new preload session " + id);
62f27b710afe310d5df6ae3fac9c88b23ac78cbfe6Narayan Kamath            mSession = new PreloaderSession(id);
63f27b710afe310d5df6ae3fac9c88b23ac78cbfe6Narayan Kamath            WebViewTimersControl.getInstance().onPrerenderStart(
64f27b710afe310d5df6ae3fac9c88b23ac78cbfe6Narayan Kamath                    mSession.getWebView());
65f27b710afe310d5df6ae3fac9c88b23ac78cbfe6Narayan Kamath            return mSession;
66f27b710afe310d5df6ae3fac9c88b23ac78cbfe6Narayan Kamath        } else if (mSession.mId.equals(id)) {
67f27b710afe310d5df6ae3fac9c88b23ac78cbfe6Narayan Kamath            if (LOGD_ENABLED) Log.d(LOGTAG, "Returning existing preload session " + id);
68f27b710afe310d5df6ae3fac9c88b23ac78cbfe6Narayan Kamath            return mSession;
691461244018a225006a8d4c203f9dfe294ffe94faMichael Kolb        }
70f27b710afe310d5df6ae3fac9c88b23ac78cbfe6Narayan Kamath
71f27b710afe310d5df6ae3fac9c88b23ac78cbfe6Narayan Kamath        if (LOGD_ENABLED) Log.d(LOGTAG, "Existing session in progress : " + mSession.mId +
72f27b710afe310d5df6ae3fac9c88b23ac78cbfe6Narayan Kamath                " returning null.");
73f27b710afe310d5df6ae3fac9c88b23ac78cbfe6Narayan Kamath        return null;
741461244018a225006a8d4c203f9dfe294ffe94faMichael Kolb    }
751461244018a225006a8d4c203f9dfe294ffe94faMichael Kolb
761461244018a225006a8d4c203f9dfe294ffe94faMichael Kolb    private PreloaderSession takeSession(String id) {
77f27b710afe310d5df6ae3fac9c88b23ac78cbfe6Narayan Kamath        PreloaderSession s = null;
78f27b710afe310d5df6ae3fac9c88b23ac78cbfe6Narayan Kamath        if (mSession != null && mSession.mId.equals(id)) {
79f27b710afe310d5df6ae3fac9c88b23ac78cbfe6Narayan Kamath            s = mSession;
80f27b710afe310d5df6ae3fac9c88b23ac78cbfe6Narayan Kamath            mSession = null;
81f27b710afe310d5df6ae3fac9c88b23ac78cbfe6Narayan Kamath        }
82f27b710afe310d5df6ae3fac9c88b23ac78cbfe6Narayan Kamath
831461244018a225006a8d4c203f9dfe294ffe94faMichael Kolb        if (s != null) {
841461244018a225006a8d4c203f9dfe294ffe94faMichael Kolb            s.cancelTimeout();
851461244018a225006a8d4c203f9dfe294ffe94faMichael Kolb        }
86f27b710afe310d5df6ae3fac9c88b23ac78cbfe6Narayan Kamath
871461244018a225006a8d4c203f9dfe294ffe94faMichael Kolb        return s;
881461244018a225006a8d4c203f9dfe294ffe94faMichael Kolb    }
891461244018a225006a8d4c203f9dfe294ffe94faMichael Kolb
9029721c2c6cc7f79a52962556c4431b71bb3ce46eMathew Inwood    public void handlePreloadRequest(String id, String url, Map<String, String> headers,
9129721c2c6cc7f79a52962556c4431b71bb3ce46eMathew Inwood            String searchBoxQuery) {
921461244018a225006a8d4c203f9dfe294ffe94faMichael Kolb        PreloaderSession s = getSession(id);
93f27b710afe310d5df6ae3fac9c88b23ac78cbfe6Narayan Kamath        if (s == null) {
94f27b710afe310d5df6ae3fac9c88b23ac78cbfe6Narayan Kamath            if (LOGD_ENABLED) Log.d(LOGTAG, "Discarding preload request, existing"
95f27b710afe310d5df6ae3fac9c88b23ac78cbfe6Narayan Kamath                    + " session in progress");
96f27b710afe310d5df6ae3fac9c88b23ac78cbfe6Narayan Kamath            return;
97f27b710afe310d5df6ae3fac9c88b23ac78cbfe6Narayan Kamath        }
98f27b710afe310d5df6ae3fac9c88b23ac78cbfe6Narayan Kamath
991461244018a225006a8d4c203f9dfe294ffe94faMichael Kolb        s.touch(); // reset timer
10029721c2c6cc7f79a52962556c4431b71bb3ce46eMathew Inwood        PreloadedTabControl tab = s.getTabControl();
10129721c2c6cc7f79a52962556c4431b71bb3ce46eMathew Inwood        if (searchBoxQuery != null) {
10229721c2c6cc7f79a52962556c4431b71bb3ce46eMathew Inwood            tab.loadUrlIfChanged(url, headers);
10329721c2c6cc7f79a52962556c4431b71bb3ce46eMathew Inwood            tab.setQuery(searchBoxQuery);
10429721c2c6cc7f79a52962556c4431b71bb3ce46eMathew Inwood        } else {
10529721c2c6cc7f79a52962556c4431b71bb3ce46eMathew Inwood            tab.loadUrl(url, headers);
10629721c2c6cc7f79a52962556c4431b71bb3ce46eMathew Inwood        }
1071461244018a225006a8d4c203f9dfe294ffe94faMichael Kolb    }
1081461244018a225006a8d4c203f9dfe294ffe94faMichael Kolb
109dffa72f926d051c089981adf52a44d2c933a0de4Mathew Inwood    public void cancelSearchBoxPreload(String id) {
110dffa72f926d051c089981adf52a44d2c933a0de4Mathew Inwood        PreloaderSession s = getSession(id);
111dffa72f926d051c089981adf52a44d2c933a0de4Mathew Inwood        if (s != null) {
112dffa72f926d051c089981adf52a44d2c933a0de4Mathew Inwood            s.touch(); // reset timer
113dffa72f926d051c089981adf52a44d2c933a0de4Mathew Inwood            PreloadedTabControl tab = s.getTabControl();
114dffa72f926d051c089981adf52a44d2c933a0de4Mathew Inwood            tab.searchBoxCancel();
115dffa72f926d051c089981adf52a44d2c933a0de4Mathew Inwood        }
116dffa72f926d051c089981adf52a44d2c933a0de4Mathew Inwood    }
117dffa72f926d051c089981adf52a44d2c933a0de4Mathew Inwood
1181461244018a225006a8d4c203f9dfe294ffe94faMichael Kolb    public void discardPreload(String id) {
1191461244018a225006a8d4c203f9dfe294ffe94faMichael Kolb        PreloaderSession s = takeSession(id);
1201461244018a225006a8d4c203f9dfe294ffe94faMichael Kolb        if (s != null) {
1211461244018a225006a8d4c203f9dfe294ffe94faMichael Kolb            if (LOGD_ENABLED) Log.d(LOGTAG, "Discard preload session " + id);
122cf9120ebd80d9ecdf54ec387bc1e8c4b9b91c6eaMathew Inwood            WebViewTimersControl.getInstance().onPrerenderDone(s == null ? null : s.getWebView());
12329721c2c6cc7f79a52962556c4431b71bb3ce46eMathew Inwood            PreloadedTabControl t = s.getTabControl();
1241461244018a225006a8d4c203f9dfe294ffe94faMichael Kolb            t.destroy();
12529721c2c6cc7f79a52962556c4431b71bb3ce46eMathew Inwood        } else {
12629721c2c6cc7f79a52962556c4431b71bb3ce46eMathew Inwood            if (LOGD_ENABLED) Log.d(LOGTAG, "Ignored discard request " + id);
1271461244018a225006a8d4c203f9dfe294ffe94faMichael Kolb        }
1281461244018a225006a8d4c203f9dfe294ffe94faMichael Kolb    }
1291461244018a225006a8d4c203f9dfe294ffe94faMichael Kolb
1301461244018a225006a8d4c203f9dfe294ffe94faMichael Kolb    /**
1311461244018a225006a8d4c203f9dfe294ffe94faMichael Kolb     * Return a preloaded tab, and remove it from the preloader. This is used when the
1321461244018a225006a8d4c203f9dfe294ffe94faMichael Kolb     * view is about to be displayed.
1331461244018a225006a8d4c203f9dfe294ffe94faMichael Kolb     */
13429721c2c6cc7f79a52962556c4431b71bb3ce46eMathew Inwood    public PreloadedTabControl getPreloadedTab(String id) {
1351461244018a225006a8d4c203f9dfe294ffe94faMichael Kolb        PreloaderSession s = takeSession(id);
1361461244018a225006a8d4c203f9dfe294ffe94faMichael Kolb        if (LOGD_ENABLED) Log.d(LOGTAG, "Showing preload session " + id + "=" + s);
13729721c2c6cc7f79a52962556c4431b71bb3ce46eMathew Inwood        return s == null ? null : s.getTabControl();
1381461244018a225006a8d4c203f9dfe294ffe94faMichael Kolb    }
1391461244018a225006a8d4c203f9dfe294ffe94faMichael Kolb
1401461244018a225006a8d4c203f9dfe294ffe94faMichael Kolb    private class PreloaderSession {
1411461244018a225006a8d4c203f9dfe294ffe94faMichael Kolb        private final String mId;
14229721c2c6cc7f79a52962556c4431b71bb3ce46eMathew Inwood        private final PreloadedTabControl mTabControl;
1431461244018a225006a8d4c203f9dfe294ffe94faMichael Kolb
1441461244018a225006a8d4c203f9dfe294ffe94faMichael Kolb        private final Runnable mTimeoutTask = new Runnable(){
1451461244018a225006a8d4c203f9dfe294ffe94faMichael Kolb            @Override
1461461244018a225006a8d4c203f9dfe294ffe94faMichael Kolb            public void run() {
1471461244018a225006a8d4c203f9dfe294ffe94faMichael Kolb                if (LOGD_ENABLED) Log.d(LOGTAG, "Preload session timeout " + mId);
1481461244018a225006a8d4c203f9dfe294ffe94faMichael Kolb                discardPreload(mId);
1491461244018a225006a8d4c203f9dfe294ffe94faMichael Kolb            }};
1501461244018a225006a8d4c203f9dfe294ffe94faMichael Kolb
1511461244018a225006a8d4c203f9dfe294ffe94faMichael Kolb        public PreloaderSession(String id) {
1521461244018a225006a8d4c203f9dfe294ffe94faMichael Kolb            mId = id;
15329721c2c6cc7f79a52962556c4431b71bb3ce46eMathew Inwood            mTabControl = new PreloadedTabControl(
15429721c2c6cc7f79a52962556c4431b71bb3ce46eMathew Inwood                    new Tab(new PreloadController(mContext), mFactory.createWebView(false)));
1551461244018a225006a8d4c203f9dfe294ffe94faMichael Kolb            touch();
1561461244018a225006a8d4c203f9dfe294ffe94faMichael Kolb        }
1571461244018a225006a8d4c203f9dfe294ffe94faMichael Kolb
1581461244018a225006a8d4c203f9dfe294ffe94faMichael Kolb        public void cancelTimeout() {
1591461244018a225006a8d4c203f9dfe294ffe94faMichael Kolb            mHandler.removeCallbacks(mTimeoutTask);
1601461244018a225006a8d4c203f9dfe294ffe94faMichael Kolb        }
1611461244018a225006a8d4c203f9dfe294ffe94faMichael Kolb
1621461244018a225006a8d4c203f9dfe294ffe94faMichael Kolb        public void touch() {
1631461244018a225006a8d4c203f9dfe294ffe94faMichael Kolb            cancelTimeout();
1641461244018a225006a8d4c203f9dfe294ffe94faMichael Kolb            mHandler.postDelayed(mTimeoutTask, PRERENDER_TIMEOUT_MILLIS);
1651461244018a225006a8d4c203f9dfe294ffe94faMichael Kolb        }
1661461244018a225006a8d4c203f9dfe294ffe94faMichael Kolb
16729721c2c6cc7f79a52962556c4431b71bb3ce46eMathew Inwood        public PreloadedTabControl getTabControl() {
16829721c2c6cc7f79a52962556c4431b71bb3ce46eMathew Inwood            return mTabControl;
1691461244018a225006a8d4c203f9dfe294ffe94faMichael Kolb        }
1701461244018a225006a8d4c203f9dfe294ffe94faMichael Kolb
171e1dbb956d762c3f07033f247c05270a9882a79a7Mathew Inwood        public WebView getWebView() {
172e1dbb956d762c3f07033f247c05270a9882a79a7Mathew Inwood            Tab t = mTabControl.getTab();
173e1dbb956d762c3f07033f247c05270a9882a79a7Mathew Inwood            return t == null? null : t.getWebView();
174e1dbb956d762c3f07033f247c05270a9882a79a7Mathew Inwood        }
175e1dbb956d762c3f07033f247c05270a9882a79a7Mathew Inwood
1761461244018a225006a8d4c203f9dfe294ffe94faMichael Kolb    }
1771461244018a225006a8d4c203f9dfe294ffe94faMichael Kolb
1781461244018a225006a8d4c203f9dfe294ffe94faMichael Kolb}
179