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