Home | History | Annotate | Download | only in browser
      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  */
     16 package com.android.browser;
     17 
     18 import android.content.Context;
     19 import android.os.Handler;
     20 import android.os.Looper;
     21 import android.util.Log;
     22 import android.webkit.WebView;
     23 
     24 import java.util.Map;
     25 
     26 /**
     27  * Singleton class for handling preload requests.
     28  */
     29 public class Preloader {
     30 
     31     private final static String LOGTAG = "browser.preloader";
     32     private final static boolean LOGD_ENABLED = com.android.browser.Browser.LOGD_ENABLED;
     33 
     34     private static final int PRERENDER_TIMEOUT_MILLIS = 30 * 1000; // 30s
     35 
     36     private static Preloader sInstance;
     37 
     38     private final Context mContext;
     39     private final Handler mHandler;
     40     private final BrowserWebViewFactory mFactory;
     41     private volatile PreloaderSession mSession;
     42 
     43     public static void initialize(Context context) {
     44         sInstance = new Preloader(context);
     45     }
     46 
     47     public static Preloader getInstance() {
     48         return sInstance;
     49     }
     50 
     51     private Preloader(Context context) {
     52         mContext = context.getApplicationContext();
     53         mHandler = new Handler(Looper.getMainLooper());
     54         mSession = null;
     55         mFactory = new BrowserWebViewFactory(context);
     56 
     57     }
     58 
     59     private PreloaderSession getSession(String id) {
     60         if (mSession == null) {
     61             if (LOGD_ENABLED) Log.d(LOGTAG, "Create new preload session " + id);
     62             mSession = new PreloaderSession(id);
     63             WebViewTimersControl.getInstance().onPrerenderStart(
     64                     mSession.getWebView());
     65             return mSession;
     66         } else if (mSession.mId.equals(id)) {
     67             if (LOGD_ENABLED) Log.d(LOGTAG, "Returning existing preload session " + id);
     68             return mSession;
     69         }
     70 
     71         if (LOGD_ENABLED) Log.d(LOGTAG, "Existing session in progress : " + mSession.mId +
     72                 " returning null.");
     73         return null;
     74     }
     75 
     76     private PreloaderSession takeSession(String id) {
     77         PreloaderSession s = null;
     78         if (mSession != null && mSession.mId.equals(id)) {
     79             s = mSession;
     80             mSession = null;
     81         }
     82 
     83         if (s != null) {
     84             s.cancelTimeout();
     85         }
     86 
     87         return s;
     88     }
     89 
     90     public void handlePreloadRequest(String id, String url, Map<String, String> headers,
     91             String searchBoxQuery) {
     92         PreloaderSession s = getSession(id);
     93         if (s == null) {
     94             if (LOGD_ENABLED) Log.d(LOGTAG, "Discarding preload request, existing"
     95                     + " session in progress");
     96             return;
     97         }
     98 
     99         s.touch(); // reset timer
    100         PreloadedTabControl tab = s.getTabControl();
    101         if (searchBoxQuery != null) {
    102             tab.loadUrlIfChanged(url, headers);
    103             tab.setQuery(searchBoxQuery);
    104         } else {
    105             tab.loadUrl(url, headers);
    106         }
    107     }
    108 
    109     public void cancelSearchBoxPreload(String id) {
    110         PreloaderSession s = getSession(id);
    111         if (s != null) {
    112             s.touch(); // reset timer
    113             PreloadedTabControl tab = s.getTabControl();
    114             tab.searchBoxCancel();
    115         }
    116     }
    117 
    118     public void discardPreload(String id) {
    119         PreloaderSession s = takeSession(id);
    120         if (s != null) {
    121             if (LOGD_ENABLED) Log.d(LOGTAG, "Discard preload session " + id);
    122             WebViewTimersControl.getInstance().onPrerenderDone(s == null ? null : s.getWebView());
    123             PreloadedTabControl t = s.getTabControl();
    124             t.destroy();
    125         } else {
    126             if (LOGD_ENABLED) Log.d(LOGTAG, "Ignored discard request " + id);
    127         }
    128     }
    129 
    130     /**
    131      * Return a preloaded tab, and remove it from the preloader. This is used when the
    132      * view is about to be displayed.
    133      */
    134     public PreloadedTabControl getPreloadedTab(String id) {
    135         PreloaderSession s = takeSession(id);
    136         if (LOGD_ENABLED) Log.d(LOGTAG, "Showing preload session " + id + "=" + s);
    137         return s == null ? null : s.getTabControl();
    138     }
    139 
    140     private class PreloaderSession {
    141         private final String mId;
    142         private final PreloadedTabControl mTabControl;
    143 
    144         private final Runnable mTimeoutTask = new Runnable(){
    145             @Override
    146             public void run() {
    147                 if (LOGD_ENABLED) Log.d(LOGTAG, "Preload session timeout " + mId);
    148                 discardPreload(mId);
    149             }};
    150 
    151         public PreloaderSession(String id) {
    152             mId = id;
    153             mTabControl = new PreloadedTabControl(
    154                     new Tab(new PreloadController(mContext), mFactory.createWebView(false)));
    155             touch();
    156         }
    157 
    158         public void cancelTimeout() {
    159             mHandler.removeCallbacks(mTimeoutTask);
    160         }
    161 
    162         public void touch() {
    163             cancelTimeout();
    164             mHandler.postDelayed(mTimeoutTask, PRERENDER_TIMEOUT_MILLIS);
    165         }
    166 
    167         public PreloadedTabControl getTabControl() {
    168             return mTabControl;
    169         }
    170 
    171         public WebView getWebView() {
    172             Tab t = mTabControl.getTab();
    173             return t == null? null : t.getWebView();
    174         }
    175 
    176     }
    177 
    178 }
    179