blob: 473845e73f1e48a03609a8b94d786e23b1504610 [file] [log] [blame]
Michael Kolb8233fac2010-10-26 16:08:53 -07001/*
2 * Copyright (C) 2010 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
Bijan Amirzada41242f22014-03-21 12:12:18 -070017package com.android.browser;
Michael Kolb8233fac2010-10-26 16:08:53 -070018
Michael Kolb8233fac2010-10-26 16:08:53 -070019import android.app.Activity;
Bijan Amirzada9b1e9882014-02-26 17:15:46 -080020
luxiaolb40014b2013-07-19 10:01:43 +080021import android.app.AlertDialog;
John Reck68234a92012-04-19 15:27:12 -070022import android.app.Dialog;
Michael Kolb8233fac2010-10-26 16:08:53 -070023import android.app.DownloadManager;
John Reck68234a92012-04-19 15:27:12 -070024import android.app.ProgressDialog;
Vivek Sekharce2a4832014-03-26 13:26:53 -070025import android.content.Context;
26import android.content.res.Resources;
Michael Kolb8233fac2010-10-26 16:08:53 -070027import android.content.ClipboardManager;
Michael Kolb8233fac2010-10-26 16:08:53 -070028import android.content.ContentResolver;
John Reckd8c74522011-06-14 08:45:00 -070029import android.content.ContentUris;
Michael Kolb8233fac2010-10-26 16:08:53 -070030import android.content.ContentValues;
31import android.content.Context;
John Reck68234a92012-04-19 15:27:12 -070032import android.content.DialogInterface;
33import android.content.DialogInterface.OnCancelListener;
Michael Kolb8233fac2010-10-26 16:08:53 -070034import android.content.Intent;
35import android.content.pm.PackageManager;
36import android.content.pm.ResolveInfo;
37import android.content.res.Configuration;
John Reck30b065e2011-07-19 10:58:05 -070038import android.content.res.TypedArray;
Leon Scroggins1961ed22010-12-07 15:22:21 -050039import android.database.ContentObserver;
Michael Kolb8233fac2010-10-26 16:08:53 -070040import android.database.Cursor;
41import android.database.sqlite.SQLiteDatabase;
Mattias Nilsson561d1952011-10-04 10:18:50 +020042import android.database.sqlite.SQLiteException;
Michael Kolb8233fac2010-10-26 16:08:53 -070043import android.graphics.Bitmap;
kaiyiz6e5b3e02013-08-19 20:02:01 +080044import android.graphics.BitmapFactory;
Michael Kolb8233fac2010-10-26 16:08:53 -070045import android.graphics.Canvas;
Bijan Amirzada9b1e9882014-02-26 17:15:46 -080046import android.graphics.Paint;
47import android.graphics.Rect;
kaiyiza016da12013-08-26 17:50:22 +080048import android.net.ConnectivityManager;
49import android.net.NetworkInfo;
Michael Kolb8233fac2010-10-26 16:08:53 -070050import android.net.Uri;
51import android.net.http.SslError;
kaiyiza016da12013-08-26 17:50:22 +080052import android.net.wifi.WifiManager;
kaiyizb7bf1f22013-10-02 11:42:23 +080053import android.net.wifi.ScanResult;
Michael Kolb8233fac2010-10-26 16:08:53 -070054import android.os.AsyncTask;
55import android.os.Bundle;
George Mount387d45d2011-10-07 15:57:53 -070056import android.os.Environment;
Michael Kolb8233fac2010-10-26 16:08:53 -070057import android.os.Handler;
58import android.os.Message;
59import android.os.PowerManager;
60import android.os.PowerManager.WakeLock;
Ben Murdoch8029a772010-11-16 11:58:21 +000061import android.preference.PreferenceActivity;
Michael Kolb8233fac2010-10-26 16:08:53 -070062import android.provider.Browser;
Michael Kolb8233fac2010-10-26 16:08:53 -070063import android.provider.ContactsContract;
64import android.provider.ContactsContract.Intents.Insert;
kaiyiza016da12013-08-26 17:50:22 +080065import android.provider.Settings;
Michael Kolb0b129122012-06-04 16:31:58 -070066import android.speech.RecognizerIntent;
Michael Kolb8233fac2010-10-26 16:08:53 -070067import android.text.TextUtils;
68import android.util.Log;
John Recka00cbbd2010-12-16 12:38:19 -080069import android.util.Patterns;
Michael Kolb8233fac2010-10-26 16:08:53 -070070import android.view.ActionMode;
71import android.view.ContextMenu;
72import android.view.ContextMenu.ContextMenuInfo;
73import android.view.Gravity;
74import android.view.KeyEvent;
Michael Kolb8233fac2010-10-26 16:08:53 -070075import android.view.Menu;
76import android.view.MenuInflater;
77import android.view.MenuItem;
78import android.view.MenuItem.OnMenuItemClickListener;
Michael Kolbc3af0672011-08-09 10:24:41 -070079import android.view.MotionEvent;
Michael Kolb8233fac2010-10-26 16:08:53 -070080import android.view.View;
George Mount387d45d2011-10-07 15:57:53 -070081import android.webkit.MimeTypeMap;
Michael Kolb8233fac2010-10-26 16:08:53 -070082import android.webkit.ValueCallback;
Bijan Amirzada9b1e9882014-02-26 17:15:46 -080083import android.webkit.WebChromeClient.CustomViewCallback;
Michael Kolb8233fac2010-10-26 16:08:53 -070084import android.webkit.WebIconDatabase;
Leon Scrogginsac993842011-02-02 12:54:07 -050085import android.widget.Toast;
Michael Kolb8233fac2010-10-26 16:08:53 -070086
Bijan Amirzada9b1e9882014-02-26 17:15:46 -080087import org.codeaurora.swe.CookieManager;
88import org.codeaurora.swe.CookieSyncManager;
89import org.codeaurora.swe.HttpAuthHandler;
90import org.codeaurora.swe.SslErrorHandler;
91import org.codeaurora.swe.WebSettings;
92import org.codeaurora.swe.WebView;
93
Bijan Amirzada41242f22014-03-21 12:12:18 -070094import com.android.browser.R;
95import com.android.browser.IntentHandler.UrlData;
96import com.android.browser.UI.ComboViews;
97import com.android.browser.mynavigation.AddMyNavigationPage;
98import com.android.browser.mynavigation.MyNavigationUtil;
99import com.android.browser.platformsupport.BrowserContract;
100import com.android.browser.platformsupport.WebAddress;
101import com.android.browser.platformsupport.BrowserContract.Images;
102import com.android.browser.provider.BrowserProvider2.Thumbnails;
103import com.android.browser.provider.SnapshotProvider.Snapshots;
104import com.android.browser.reflect.ReflectHelper;
Michael Kolb4bd767d2011-05-27 11:33:55 -0700105
Michael Kolb8233fac2010-10-26 16:08:53 -0700106import java.io.ByteArrayOutputStream;
George Mount387d45d2011-10-07 15:57:53 -0700107import java.io.File;
108import java.io.FileOutputStream;
109import java.io.IOException;
Michael Kolb8233fac2010-10-26 16:08:53 -0700110import java.net.URLEncoder;
George Mount387d45d2011-10-07 15:57:53 -0700111import java.text.DateFormat;
112import java.text.SimpleDateFormat;
John Reck1cf4b792011-07-26 10:22:22 -0700113import java.util.ArrayList;
Michael Kolb8233fac2010-10-26 16:08:53 -0700114import java.util.Calendar;
George Mount387d45d2011-10-07 15:57:53 -0700115import java.util.Date;
Michael Kolb8233fac2010-10-26 16:08:53 -0700116import java.util.HashMap;
Michael Kolb1bf23132010-11-19 12:55:12 -0800117import java.util.List;
Johan Redestigaa676182012-10-03 13:33:01 +0200118import java.util.Locale;
John Reck26b18322011-06-21 13:08:58 -0700119import java.util.Map;
Michael Kolb8233fac2010-10-26 16:08:53 -0700120
121/**
122 * Controller for browser
123 */
124public class Controller
John Reck9c35b9c2012-05-30 10:08:50 -0700125 implements WebViewController, UiController, ActivityController {
Michael Kolb8233fac2010-10-26 16:08:53 -0700126
127 private static final String LOGTAG = "Controller";
Michael Kolbcfa3af52010-12-14 10:36:11 -0800128 private static final String SEND_APP_ID_EXTRA =
129 "android.speech.extras.SEND_APPLICATION_ID_EXTRA";
Michael Kolba4261fd2011-05-05 11:27:37 -0700130 private static final String INCOGNITO_URI = "browser:incognito";
Bijan Amirzada9b1e9882014-02-26 17:15:46 -0800131
132
kaiyiza016da12013-08-26 17:50:22 +0800133 private static final String PROP_NETSWITCH = "persist.env.browser.netswitch";
134 private static final String INTENT_WIFI_SELECTION_DATA_CONNECTION =
135 "android.net.wifi.cmcc.WIFI_SELECTION_DATA_CONNECTION";
kaiyiz6e5b3e02013-08-19 20:02:01 +0800136 private static final String OFFLINE_PAGE =
Bijan Amirzada41242f22014-03-21 12:12:18 -0700137 "content://com.android.browser.mynavigation/websites";
kaiyizb7bf1f22013-10-02 11:42:23 +0800138 private static final String INTENT_PICK_NETWORK =
139 "android.net.wifi.cmcc.PICK_WIFI_NETWORK_AND_GPRS";
Bijan Amirzada9b1e9882014-02-26 17:15:46 -0800140
141 public final static String EXTRA_SHARE_SCREENSHOT = "share_screenshot";
142 public final static String EXTRA_SHARE_FAVICON = "share_favicon";
Michael Kolb8233fac2010-10-26 16:08:53 -0700143 // public message ids
144 public final static int LOAD_URL = 1001;
145 public final static int STOP_LOAD = 1002;
146
147 // Message Ids
148 private static final int FOCUS_NODE_HREF = 102;
149 private static final int RELEASE_WAKELOCK = 107;
150
151 static final int UPDATE_BOOKMARK_THUMBNAIL = 108;
152
153 private static final int OPEN_BOOKMARKS = 201;
kaiyiz591110b2013-08-06 17:11:06 +0800154 private static final int OPEN_MENU = 202;
Michael Kolb8233fac2010-10-26 16:08:53 -0700155
156 private static final int EMPTY_MENU = -1;
157
Michael Kolb8233fac2010-10-26 16:08:53 -0700158 // activity requestCode
John Reckd3e4d5b2011-07-13 15:48:43 -0700159 final static int COMBO_VIEW = 1;
Michael Kolb8233fac2010-10-26 16:08:53 -0700160 final static int PREFERENCES_PAGE = 3;
161 final static int FILE_SELECTED = 4;
Ben Murdoch8029a772010-11-16 11:58:21 +0000162 final static int AUTOFILL_SETUP = 5;
Michael Kolb0b129122012-06-04 16:31:58 -0700163 final static int VOICE_RESULT = 6;
kaiyiz6e5b3e02013-08-19 20:02:01 +0800164 final static int MY_NAVIGATION = 7;
Ben Murdoch8029a772010-11-16 11:58:21 +0000165
Michael Kolb8233fac2010-10-26 16:08:53 -0700166 private final static int WAKELOCK_TIMEOUT = 5 * 60 * 1000; // 5 minutes
167
168 // As the ids are dynamically created, we can't guarantee that they will
169 // be in sequence, so this static array maps ids to a window number.
170 final static private int[] WINDOW_SHORTCUT_ID_ARRAY =
171 { R.id.window_one_menu_id, R.id.window_two_menu_id,
172 R.id.window_three_menu_id, R.id.window_four_menu_id,
173 R.id.window_five_menu_id, R.id.window_six_menu_id,
174 R.id.window_seven_menu_id, R.id.window_eight_menu_id };
175
176 // "source" parameter for Google search through search key
177 final static String GOOGLE_SEARCH_SOURCE_SEARCHKEY = "browser-key";
178 // "source" parameter for Google search through simplily type
179 final static String GOOGLE_SEARCH_SOURCE_TYPE = "browser-type";
180
George Mount387d45d2011-10-07 15:57:53 -0700181 // "no-crash-recovery" parameter in intent to suppress crash recovery
Guang Zhu9e78f512011-05-04 11:45:11 -0700182 final static String NO_CRASH_RECOVERY = "no-crash-recovery";
183
John Reckd7dd9b22011-08-30 09:18:29 -0700184 // A bitmap that is re-used in createScreenshot as scratch space
185 private static Bitmap sThumbnailBitmap;
186
Michael Kolb8233fac2010-10-26 16:08:53 -0700187 private Activity mActivity;
188 private UI mUi;
189 private TabControl mTabControl;
190 private BrowserSettings mSettings;
191 private WebViewFactory mFactory;
192
193 private WakeLock mWakeLock;
194
195 private UrlHandler mUrlHandler;
196 private UploadHandler mUploadHandler;
197 private IntentHandler mIntentHandler;
Michael Kolb8233fac2010-10-26 16:08:53 -0700198 private PageDialogsHandler mPageDialogsHandler;
199 private NetworkStateHandler mNetworkHandler;
200
Ben Murdoch8029a772010-11-16 11:58:21 +0000201 private Message mAutoFillSetupMessage;
202
Michael Kolb8233fac2010-10-26 16:08:53 -0700203 private boolean mShouldShowErrorConsole;
kaiyiza016da12013-08-26 17:50:22 +0800204 private boolean mNetworkShouldNotify = true;
Michael Kolb8233fac2010-10-26 16:08:53 -0700205
206 private SystemAllowGeolocationOrigins mSystemAllowGeolocationOrigins;
207
208 // FIXME, temp address onPrepareMenu performance problem.
209 // When we move everything out of view, we should rewrite this.
210 private int mCurrentMenuState = 0;
211 private int mMenuState = R.id.MAIN_MENU;
212 private int mOldMenuState = EMPTY_MENU;
213 private Menu mCachedMenu;
214
Michael Kolb8233fac2010-10-26 16:08:53 -0700215 private boolean mMenuIsDown;
216
217 // For select and find, we keep track of the ActionMode so that
218 // finish() can be called as desired.
219 private ActionMode mActionMode;
220
221 /**
222 * Only meaningful when mOptionsMenuOpen is true. This variable keeps track
223 * of whether the configuration has changed. The first onMenuOpened call
224 * after a configuration change is simply a reopening of the same menu
225 * (i.e. mIconView did not change).
226 */
227 private boolean mConfigChanged;
228
229 /**
230 * Keeps track of whether the options menu is open. This is important in
231 * determining whether to show or hide the title bar overlay
232 */
233 private boolean mOptionsMenuOpen;
234
235 /**
236 * Whether or not the options menu is in its bigger, popup menu form. When
237 * true, we want the title bar overlay to be gone. When false, we do not.
238 * Only meaningful if mOptionsMenuOpen is true.
239 */
240 private boolean mExtendedMenuOpen;
241
Michael Kolb8233fac2010-10-26 16:08:53 -0700242 private boolean mActivityPaused = true;
243 private boolean mLoadStopped;
244
245 private Handler mHandler;
Leon Scroggins1961ed22010-12-07 15:22:21 -0500246 // Checks to see when the bookmarks database has changed, and updates the
247 // Tabs' notion of whether they represent bookmarked sites.
248 private ContentObserver mBookmarksObserver;
John Reck847b5322011-04-14 17:02:18 -0700249 private CrashRecoveryHandler mCrashRecoveryHandler;
Michael Kolb8233fac2010-10-26 16:08:53 -0700250
Michael Kolbc3af0672011-08-09 10:24:41 -0700251 private boolean mBlockEvents;
252
Michael Kolb0b129122012-06-04 16:31:58 -0700253 private String mVoiceResult;
kaiyiz6e5b3e02013-08-19 20:02:01 +0800254 private boolean mUpdateMyNavThumbnail;
255 private String mUpdateMyNavThumbnailUrl;
Michael Kolb0b129122012-06-04 16:31:58 -0700256
George Mount3636d0a2011-11-21 09:08:21 -0800257 public Controller(Activity browser) {
Michael Kolb8233fac2010-10-26 16:08:53 -0700258 mActivity = browser;
259 mSettings = BrowserSettings.getInstance();
260 mTabControl = new TabControl(this);
261 mSettings.setController(this);
John Reck378a4102011-06-09 16:23:01 -0700262 mCrashRecoveryHandler = CrashRecoveryHandler.initialize(this);
George Mount3636d0a2011-11-21 09:08:21 -0800263 mCrashRecoveryHandler.preloadCrashState();
Michael Kolb14612442011-06-24 13:06:29 -0700264 mFactory = new BrowserWebViewFactory(browser);
Michael Kolb8233fac2010-10-26 16:08:53 -0700265
266 mUrlHandler = new UrlHandler(this);
267 mIntentHandler = new IntentHandler(mActivity, this);
Michael Kolb8233fac2010-10-26 16:08:53 -0700268 mPageDialogsHandler = new PageDialogsHandler(mActivity, this);
269
Bijan Amirzada9b1e9882014-02-26 17:15:46 -0800270 // Creating dummy Webview for browser to force loading of library;
271 // in order for CookieManager calls to be invoked properly and
272 // awBrowserContext to be initialized
273 (mFactory.createWebView(false)).destroy();
274
Michael Kolb8233fac2010-10-26 16:08:53 -0700275 startHandler();
Leon Scroggins1961ed22010-12-07 15:22:21 -0500276 mBookmarksObserver = new ContentObserver(mHandler) {
277 @Override
278 public void onChange(boolean selfChange) {
279 int size = mTabControl.getTabCount();
280 for (int i = 0; i < size; i++) {
281 mTabControl.getTab(i).updateBookmarkedStatus();
282 }
283 }
284
285 };
286 browser.getContentResolver().registerContentObserver(
287 BrowserContract.Bookmarks.CONTENT_URI, true, mBookmarksObserver);
Michael Kolb8233fac2010-10-26 16:08:53 -0700288
289 mNetworkHandler = new NetworkStateHandler(mActivity, this);
290 // Start watching the default geolocation permissions
291 mSystemAllowGeolocationOrigins =
292 new SystemAllowGeolocationOrigins(mActivity.getApplicationContext());
293 mSystemAllowGeolocationOrigins.start();
294
John Reckaf262e72011-07-25 13:55:44 -0700295 openIconDatabase();
Michael Kolb8233fac2010-10-26 16:08:53 -0700296 }
297
John Reck9c35b9c2012-05-30 10:08:50 -0700298 @Override
299 public void start(final Intent intent) {
Bijan Amirzada9b1e9882014-02-26 17:15:46 -0800300 WebView.setShouldMonitorWebCoreThread();
George Mount3636d0a2011-11-21 09:08:21 -0800301 // mCrashRecoverHandler has any previously saved state.
302 mCrashRecoveryHandler.startRecovery(intent);
John Reck847b5322011-04-14 17:02:18 -0700303 }
304
George Mount3636d0a2011-11-21 09:08:21 -0800305 void doStart(final Bundle icicle, final Intent intent) {
Michael Kolb8233fac2010-10-26 16:08:53 -0700306 // Unless the last browser usage was within 24 hours, destroy any
307 // remaining incognito tabs.
308
309 Calendar lastActiveDate = icicle != null ?
310 (Calendar) icicle.getSerializable("lastActiveDate") : null;
311 Calendar today = Calendar.getInstance();
312 Calendar yesterday = Calendar.getInstance();
313 yesterday.add(Calendar.DATE, -1);
314
Bijan Amirzada9b1e9882014-02-26 17:15:46 -0800315 // we dont want to ever recover incognito tabs
316 final boolean restoreIncognitoTabs = false;
Michael Kolb8233fac2010-10-26 16:08:53 -0700317
Patrick Scott7d50a932011-02-04 09:27:26 -0500318 // Find out if we will restore any state and remember the tab.
Michael Kolbc831b632011-05-11 09:30:34 -0700319 final long currentTabId =
Patrick Scott7d50a932011-02-04 09:27:26 -0500320 mTabControl.canRestoreState(icicle, restoreIncognitoTabs);
Kristian Monsen2cd97012010-12-07 11:11:40 +0000321
Bijan Amirzada9b1e9882014-02-26 17:15:46 -0800322 mSettings.initializeCookieSettings();
Michael Kolbc831b632011-05-11 09:30:34 -0700323 if (currentTabId == -1) {
Patrick Scott7d50a932011-02-04 09:27:26 -0500324 // Not able to restore so we go ahead and clear session cookies. We
325 // must do this before trying to login the user as we don't want to
326 // clear any session cookies set during login.
327 CookieManager.getInstance().removeSessionCookie();
328 }
329
Patrick Scottd43e75a2011-03-14 14:47:23 -0400330 GoogleAccountLogin.startLoginIfNeeded(mActivity,
Patrick Scott7d50a932011-02-04 09:27:26 -0500331 new Runnable() {
332 @Override public void run() {
George Mount3636d0a2011-11-21 09:08:21 -0800333 onPreloginFinished(icicle, intent, currentTabId,
334 restoreIncognitoTabs);
Patrick Scott7d50a932011-02-04 09:27:26 -0500335 }
336 });
337 }
338
Michael Kolbc831b632011-05-11 09:30:34 -0700339 private void onPreloginFinished(Bundle icicle, Intent intent, long currentTabId,
George Mount3636d0a2011-11-21 09:08:21 -0800340 boolean restoreIncognitoTabs) {
Michael Kolbc831b632011-05-11 09:30:34 -0700341 if (currentTabId == -1) {
John Reck1cf4b792011-07-26 10:22:22 -0700342 BackgroundHandler.execute(new PruneThumbnails(mActivity, null));
George Mount3636d0a2011-11-21 09:08:21 -0800343 if (intent == null) {
344 // This won't happen under common scenarios. The icicle is
345 // not null, but there aren't any tabs to restore.
346 openTabToHomePage();
Michael Kolb7bcafde2011-05-09 13:55:59 -0700347 } else {
George Mount3636d0a2011-11-21 09:08:21 -0800348 final Bundle extra = intent.getExtras();
349 // Create an initial tab.
350 // If the intent is ACTION_VIEW and data is not null, the Browser is
351 // invoked to view the content by another application. In this case,
352 // the tab will be close when exit.
kaiyiz6e5b3e02013-08-19 20:02:01 +0800353 UrlData urlData = null;
354 if (intent.getData() != null
355 && Intent.ACTION_VIEW.equals(intent.getAction())
356 && intent.getData().toString().startsWith("content://")) {
357 urlData = new UrlData(intent.getData().toString());
358 } else {
359 urlData = IntentHandler.getUrlDataFromIntent(intent);
360 }
George Mount3636d0a2011-11-21 09:08:21 -0800361 Tab t = null;
362 if (urlData.isEmpty()) {
Vivek Sekharce2a4832014-03-26 13:26:53 -0700363 Resources res = mActivity.getResources();
364 String browserRes = res.getString(R.string.config_carrier_resource);
Bijan Amirzada9b1e9882014-02-26 17:15:46 -0800365 if (browserRes.equals(
kaiyiz6e5b3e02013-08-19 20:02:01 +0800366 "cmcc")) {
367 t = openTab(OFFLINE_PAGE, false, true, true);
368 } else {
369 t = openTabToHomePage();
370 }
George Mount3636d0a2011-11-21 09:08:21 -0800371 } else {
372 t = openTab(urlData);
373 }
374 if (t != null) {
375 t.setAppId(intent.getStringExtra(Browser.EXTRA_APPLICATION_ID));
376 }
377 WebView webView = t.getWebView();
378 if (extra != null) {
379 int scale = extra.getInt(Browser.INITIAL_ZOOM_LEVEL, 0);
380 if (scale > 0 && scale <= 1000) {
381 webView.setInitialScale(scale);
382 }
Michael Kolb8233fac2010-10-26 16:08:53 -0700383 }
384 }
John Reckd8c74522011-06-14 08:45:00 -0700385 mUi.updateTabs(mTabControl.getTabs());
Michael Kolb8233fac2010-10-26 16:08:53 -0700386 } else {
Michael Kolbc831b632011-05-11 09:30:34 -0700387 mTabControl.restoreState(icicle, currentTabId, restoreIncognitoTabs,
Patrick Scott7d50a932011-02-04 09:27:26 -0500388 mUi.needsRestoreAllTabs());
John Reck1cf4b792011-07-26 10:22:22 -0700389 List<Tab> tabs = mTabControl.getTabs();
390 ArrayList<Long> restoredTabs = new ArrayList<Long>(tabs.size());
391 for (Tab t : tabs) {
392 restoredTabs.add(t.getId());
393 }
394 BackgroundHandler.execute(new PruneThumbnails(mActivity, restoredTabs));
John Reck52be4782011-08-26 15:37:29 -0700395 if (tabs.size() == 0) {
396 openTabToHomePage();
397 }
John Reck1cf4b792011-07-26 10:22:22 -0700398 mUi.updateTabs(tabs);
Michael Kolb8233fac2010-10-26 16:08:53 -0700399 // TabControl.restoreState() will create a new tab even if
400 // restoring the state fails.
401 setActiveTab(mTabControl.getCurrentTab());
George Mount3636d0a2011-11-21 09:08:21 -0800402 // Intent is non-null when framework thinks the browser should be
403 // launching with a new intent (icicle is null).
404 if (intent != null) {
John Reck9dd4a412011-10-05 14:55:30 -0700405 mIntentHandler.onNewIntent(intent);
406 }
Michael Kolb8233fac2010-10-26 16:08:53 -0700407 }
Michael Kolb8233fac2010-10-26 16:08:53 -0700408 // Read JavaScript flags if it exists.
John Reck35e9dd62011-04-25 09:01:54 -0700409 String jsFlags = getSettings().getJsEngineFlags();
Bijan Amirzada9b1e9882014-02-26 17:15:46 -0800410 if (jsFlags.trim().length() != 0) {
411 getCurrentWebView().setJsFlags(jsFlags);
Michael Kolb8233fac2010-10-26 16:08:53 -0700412 }
George Mount3636d0a2011-11-21 09:08:21 -0800413 if (intent != null
414 && BrowserActivity.ACTION_SHOW_BOOKMARKS.equals(intent.getAction())) {
Michael Kolb315d5022011-10-13 12:47:11 -0700415 bookmarksOrHistoryPicker(ComboViews.Bookmarks);
John Reck439c9a52010-12-14 10:04:39 -0800416 }
Michael Kolb8233fac2010-10-26 16:08:53 -0700417 }
418
John Reck1cf4b792011-07-26 10:22:22 -0700419 private static class PruneThumbnails implements Runnable {
420 private Context mContext;
421 private List<Long> mIds;
422
423 PruneThumbnails(Context context, List<Long> preserveIds) {
424 mContext = context.getApplicationContext();
425 mIds = preserveIds;
426 }
427
428 @Override
429 public void run() {
430 ContentResolver cr = mContext.getContentResolver();
431 if (mIds == null || mIds.size() == 0) {
432 cr.delete(Thumbnails.CONTENT_URI, null, null);
433 } else {
434 int length = mIds.size();
435 StringBuilder where = new StringBuilder();
436 where.append(Thumbnails._ID);
437 where.append(" not in (");
438 for (int i = 0; i < length; i++) {
439 where.append(mIds.get(i));
440 if (i < (length - 1)) {
441 where.append(",");
442 }
443 }
444 where.append(")");
445 cr.delete(Thumbnails.CONTENT_URI, where.toString(), null);
446 }
447 }
448
449 }
450
Michael Kolb1514bb72010-11-22 09:11:48 -0800451 @Override
452 public WebViewFactory getWebViewFactory() {
Michael Kolb8233fac2010-10-26 16:08:53 -0700453 return mFactory;
454 }
455
456 @Override
Michael Kolba713ec82010-11-29 17:27:06 -0800457 public void onSetWebView(Tab tab, WebView view) {
Bijan Amirzada9b1e9882014-02-26 17:15:46 -0800458 if (tab.hasCrashed)
459 tab.showCrashView();
460 else
461 mUi.onSetWebView(tab, view);
Michael Kolba713ec82010-11-29 17:27:06 -0800462 }
463
464 @Override
Michael Kolb1514bb72010-11-22 09:11:48 -0800465 public void createSubWindow(Tab tab) {
466 endActionMode();
467 WebView mainView = tab.getWebView();
468 WebView subView = mFactory.createWebView((mainView == null)
469 ? false
470 : mainView.isPrivateBrowsingEnabled());
471 mUi.createSubWindow(tab, subView);
472 }
473
474 @Override
Michael Kolb14612442011-06-24 13:06:29 -0700475 public Context getContext() {
476 return mActivity;
477 }
478
479 @Override
Michael Kolb8233fac2010-10-26 16:08:53 -0700480 public Activity getActivity() {
481 return mActivity;
482 }
483
484 void setUi(UI ui) {
485 mUi = ui;
486 }
487
Michael Kolbaf63dba2012-05-16 12:58:05 -0700488 @Override
489 public BrowserSettings getSettings() {
Michael Kolb8233fac2010-10-26 16:08:53 -0700490 return mSettings;
491 }
492
493 IntentHandler getIntentHandler() {
494 return mIntentHandler;
495 }
496
497 @Override
498 public UI getUi() {
499 return mUi;
500 }
501
502 int getMaxTabs() {
503 return mActivity.getResources().getInteger(R.integer.max_tabs);
504 }
505
506 @Override
507 public TabControl getTabControl() {
508 return mTabControl;
509 }
510
Michael Kolb1bf23132010-11-19 12:55:12 -0800511 @Override
512 public List<Tab> getTabs() {
513 return mTabControl.getTabs();
514 }
515
John Reckaf262e72011-07-25 13:55:44 -0700516 // Open the icon database.
517 private void openIconDatabase() {
518 // We have to call getInstance on the UI thread
519 final WebIconDatabase instance = WebIconDatabase.getInstance();
520 BackgroundHandler.execute(new Runnable() {
Ben Murdoch9446b932010-11-25 16:20:14 +0000521
John Reckaf262e72011-07-25 13:55:44 -0700522 @Override
523 public void run() {
524 instance.open(mActivity.getDir("icons", 0).getPath());
Michael Kolb8233fac2010-10-26 16:08:53 -0700525 }
John Reckaf262e72011-07-25 13:55:44 -0700526 });
Michael Kolb8233fac2010-10-26 16:08:53 -0700527 }
528
529 private void startHandler() {
530 mHandler = new Handler() {
531
532 @Override
533 public void handleMessage(Message msg) {
534 switch (msg.what) {
535 case OPEN_BOOKMARKS:
Michael Kolb315d5022011-10-13 12:47:11 -0700536 bookmarksOrHistoryPicker(ComboViews.Bookmarks);
Michael Kolb8233fac2010-10-26 16:08:53 -0700537 break;
538 case FOCUS_NODE_HREF:
539 {
540 String url = (String) msg.getData().get("url");
541 String title = (String) msg.getData().get("title");
Cary Clark043c2d62010-12-15 11:19:39 -0500542 String src = (String) msg.getData().get("src");
543 if (url == "") url = src; // use image if no anchor
Michael Kolb8233fac2010-10-26 16:08:53 -0700544 if (TextUtils.isEmpty(url)) {
545 break;
546 }
547 HashMap focusNodeMap = (HashMap) msg.obj;
548 WebView view = (WebView) focusNodeMap.get("webview");
549 // Only apply the action if the top window did not change.
550 if (getCurrentTopWebView() != view) {
551 break;
552 }
553 switch (msg.arg1) {
554 case R.id.open_context_menu_id:
John Reck26b18322011-06-21 13:08:58 -0700555 loadUrlFromContext(url);
Michael Kolb8233fac2010-10-26 16:08:53 -0700556 break;
Cary Clark043c2d62010-12-15 11:19:39 -0500557 case R.id.view_image_context_menu_id:
John Reck26b18322011-06-21 13:08:58 -0700558 loadUrlFromContext(src);
Cary Clark043c2d62010-12-15 11:19:39 -0500559 break;
Leon Scroggins026f2542010-11-22 13:26:12 -0500560 case R.id.open_newtab_context_menu_id:
561 final Tab parent = mTabControl.getCurrentTab();
John Reck5949c662011-05-27 09:52:29 -0700562 openTab(url, parent,
563 !mSettings.openInBackground(), true);
Leon Scroggins026f2542010-11-22 13:26:12 -0500564 break;
Michael Kolb8233fac2010-10-26 16:08:53 -0700565 case R.id.copy_link_context_menu_id:
566 copy(url);
567 break;
568 case R.id.save_link_context_menu_id:
569 case R.id.download_context_menu_id:
Leon Scroggins63c02662010-11-18 15:16:27 -0500570 DownloadHandler.onDownloadStartNoStream(
Bijan Amirzada9b1e9882014-02-26 17:15:46 -0800571 mActivity, url, view.getSettings().getUserAgentString(),
572 null, null, null, view.isPrivateBrowsingEnabled(), 0);
Michael Kolb8233fac2010-10-26 16:08:53 -0700573 break;
574 }
575 break;
576 }
577
578 case LOAD_URL:
John Reck26b18322011-06-21 13:08:58 -0700579 loadUrlFromContext((String) msg.obj);
Michael Kolb8233fac2010-10-26 16:08:53 -0700580 break;
581
582 case STOP_LOAD:
583 stopLoading();
584 break;
585
586 case RELEASE_WAKELOCK:
John Reckf57c0292011-07-21 18:15:39 -0700587 if (mWakeLock != null && mWakeLock.isHeld()) {
Michael Kolb8233fac2010-10-26 16:08:53 -0700588 mWakeLock.release();
589 // if we reach here, Browser should be still in the
590 // background loading after WAKELOCK_TIMEOUT (5-min).
591 // To avoid burning the battery, stop loading.
592 mTabControl.stopAllLoading();
593 }
594 break;
595
596 case UPDATE_BOOKMARK_THUMBNAIL:
John Reck34ef2672011-02-10 11:30:55 -0800597 Tab tab = (Tab) msg.obj;
598 if (tab != null) {
599 updateScreenshot(tab);
Michael Kolb8233fac2010-10-26 16:08:53 -0700600 }
601 break;
kaiyiz591110b2013-08-06 17:11:06 +0800602 case OPEN_MENU:
603 if (!mOptionsMenuOpen && mActivity != null ) {
604 mActivity.openOptionsMenu();
605 }
606 break;
Michael Kolb8233fac2010-10-26 16:08:53 -0700607 }
608 }
609 };
610
611 }
612
John Reckef654f12011-07-12 16:42:08 -0700613 @Override
Martijn Coenenb2f93552011-06-14 10:48:35 +0200614 public Tab getCurrentTab() {
615 return mTabControl.getCurrentTab();
616 }
617
Michael Kolbba99c5d2010-11-29 14:57:41 -0800618 @Override
619 public void shareCurrentPage() {
620 shareCurrentPage(mTabControl.getCurrentTab());
621 }
622
623 private void shareCurrentPage(Tab tab) {
624 if (tab != null) {
Michael Kolbba99c5d2010-11-29 14:57:41 -0800625 sharePage(mActivity, tab.getTitle(),
626 tab.getUrl(), tab.getFavicon(),
627 createScreenshot(tab.getWebView(),
628 getDesiredThumbnailWidth(mActivity),
629 getDesiredThumbnailHeight(mActivity)));
630 }
631 }
632
Michael Kolb8233fac2010-10-26 16:08:53 -0700633 /**
634 * Share a page, providing the title, url, favicon, and a screenshot. Uses
635 * an {@link Intent} to launch the Activity chooser.
636 * @param c Context used to launch a new Activity.
637 * @param title Title of the page. Stored in the Intent with
638 * {@link Intent#EXTRA_SUBJECT}
639 * @param url URL of the page. Stored in the Intent with
640 * {@link Intent#EXTRA_TEXT}
641 * @param favicon Bitmap of the favicon for the page. Stored in the Intent
642 * with {@link Browser#EXTRA_SHARE_FAVICON}
643 * @param screenshot Bitmap of a screenshot of the page. Stored in the
644 * Intent with {@link Browser#EXTRA_SHARE_SCREENSHOT}
645 */
646 static final void sharePage(Context c, String title, String url,
647 Bitmap favicon, Bitmap screenshot) {
648 Intent send = new Intent(Intent.ACTION_SEND);
649 send.setType("text/plain");
650 send.putExtra(Intent.EXTRA_TEXT, url);
651 send.putExtra(Intent.EXTRA_SUBJECT, title);
Bijan Amirzada9b1e9882014-02-26 17:15:46 -0800652 send.putExtra(EXTRA_SHARE_FAVICON, favicon);
653 send.putExtra(EXTRA_SHARE_SCREENSHOT, screenshot);
Michael Kolb8233fac2010-10-26 16:08:53 -0700654 try {
655 c.startActivity(Intent.createChooser(send, c.getString(
656 R.string.choosertitle_sharevia)));
657 } catch(android.content.ActivityNotFoundException ex) {
658 // if no app handles it, do nothing
659 }
660 }
661
662 private void copy(CharSequence text) {
663 ClipboardManager cm = (ClipboardManager) mActivity
664 .getSystemService(Context.CLIPBOARD_SERVICE);
665 cm.setText(text);
666 }
667
668 // lifecycle
669
John Reck9c35b9c2012-05-30 10:08:50 -0700670 @Override
671 public void onConfgurationChanged(Configuration config) {
Michael Kolb8233fac2010-10-26 16:08:53 -0700672 mConfigChanged = true;
Michael Kolb18f252f2012-03-06 13:36:20 -0800673 // update the menu in case of a locale change
674 mActivity.invalidateOptionsMenu();
kaiyiz591110b2013-08-06 17:11:06 +0800675 if (mOptionsMenuOpen) {
676 mActivity.closeOptionsMenu();
677 mHandler.sendMessageDelayed(mHandler.obtainMessage(OPEN_MENU), 100);
678 }
Michael Kolb8233fac2010-10-26 16:08:53 -0700679 if (mPageDialogsHandler != null) {
680 mPageDialogsHandler.onConfigurationChanged(config);
681 }
682 mUi.onConfigurationChanged(config);
683 }
684
685 @Override
686 public void handleNewIntent(Intent intent) {
Michael Kolb59e232c2011-08-18 17:19:53 -0700687 if (!mUi.isWebShowing()) {
688 mUi.showWeb(false);
689 }
Michael Kolb8233fac2010-10-26 16:08:53 -0700690 mIntentHandler.onNewIntent(intent);
691 }
692
John Reck9c35b9c2012-05-30 10:08:50 -0700693 @Override
694 public void onPause() {
Michael Kolb11fe02d2011-02-02 09:52:16 -0800695 if (mUi.isCustomViewShowing()) {
696 hideCustomView();
697 }
Michael Kolb8233fac2010-10-26 16:08:53 -0700698 if (mActivityPaused) {
699 Log.e(LOGTAG, "BrowserActivity is already paused.");
700 return;
701 }
Michael Kolb8233fac2010-10-26 16:08:53 -0700702 mActivityPaused = true;
Michael Kolb70976932010-11-30 11:34:01 -0800703 Tab tab = mTabControl.getCurrentTab();
704 if (tab != null) {
705 tab.pause();
706 if (!pauseWebViewTimers(tab)) {
John Reckf57c0292011-07-21 18:15:39 -0700707 if (mWakeLock == null) {
708 PowerManager pm = (PowerManager) mActivity
709 .getSystemService(Context.POWER_SERVICE);
710 mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "Browser");
711 }
Michael Kolb70976932010-11-30 11:34:01 -0800712 mWakeLock.acquire();
713 mHandler.sendMessageDelayed(mHandler
714 .obtainMessage(RELEASE_WAKELOCK), WAKELOCK_TIMEOUT);
715 }
Michael Kolb8233fac2010-10-26 16:08:53 -0700716 }
717 mUi.onPause();
718 mNetworkHandler.onPause();
719
720 WebView.disablePlatformNotifications();
Ben Murdoch015e1e32011-09-01 23:45:31 +0100721 NfcHandler.unregister(mActivity);
John Reckd7dd9b22011-08-30 09:18:29 -0700722 if (sThumbnailBitmap != null) {
723 sThumbnailBitmap.recycle();
724 sThumbnailBitmap = null;
725 }
Michael Kolb8233fac2010-10-26 16:08:53 -0700726 }
727
John Reck9c35b9c2012-05-30 10:08:50 -0700728 @Override
729 public void onSaveInstanceState(Bundle outState) {
Michael Kolb8233fac2010-10-26 16:08:53 -0700730 // Save all the tabs
George Mount3636d0a2011-11-21 09:08:21 -0800731 Bundle saveState = createSaveState();
732
733 // crash recovery manages all save & restore state
734 mCrashRecoveryHandler.writeState(saveState);
735 mSettings.setLastRunPaused(true);
736 }
737
738 /**
739 * Save the current state to outState. Does not write the state to
740 * disk.
741 * @return Bundle containing the current state of all tabs.
742 */
743 /* package */ Bundle createSaveState() {
744 Bundle saveState = new Bundle();
745 mTabControl.saveState(saveState);
746 if (!saveState.isEmpty()) {
John Reck24f18262011-06-17 14:47:20 -0700747 // Save time so that we know how old incognito tabs (if any) are.
George Mount3636d0a2011-11-21 09:08:21 -0800748 saveState.putSerializable("lastActiveDate", Calendar.getInstance());
John Reck24f18262011-06-17 14:47:20 -0700749 }
George Mount3636d0a2011-11-21 09:08:21 -0800750 return saveState;
Michael Kolb8233fac2010-10-26 16:08:53 -0700751 }
752
John Reck9c35b9c2012-05-30 10:08:50 -0700753 @Override
754 public void onResume() {
Michael Kolb8233fac2010-10-26 16:08:53 -0700755 if (!mActivityPaused) {
756 Log.e(LOGTAG, "BrowserActivity is already resumed.");
757 return;
758 }
George Mount3636d0a2011-11-21 09:08:21 -0800759 mSettings.setLastRunPaused(false);
Michael Kolb8233fac2010-10-26 16:08:53 -0700760 mActivityPaused = false;
Michael Kolb70976932010-11-30 11:34:01 -0800761 Tab current = mTabControl.getCurrentTab();
762 if (current != null) {
763 current.resume();
764 resumeWebViewTimers(current);
765 }
John Reckf57c0292011-07-21 18:15:39 -0700766 releaseWakeLock();
Martijn Coenenb2f93552011-06-14 10:48:35 +0200767
Michael Kolb8233fac2010-10-26 16:08:53 -0700768 mUi.onResume();
769 mNetworkHandler.onResume();
770 WebView.enablePlatformNotifications();
Ben Murdoch015e1e32011-09-01 23:45:31 +0100771 NfcHandler.register(mActivity, this);
Michael Kolb0b129122012-06-04 16:31:58 -0700772 if (mVoiceResult != null) {
773 mUi.onVoiceResult(mVoiceResult);
774 mVoiceResult = null;
775 }
Bijan Amirzada9b1e9882014-02-26 17:15:46 -0800776 if (current != null && current.hasCrashed) {
777 current.showCrashView();
778 }
Michael Kolb8233fac2010-10-26 16:08:53 -0700779 }
780
John Reckf57c0292011-07-21 18:15:39 -0700781 private void releaseWakeLock() {
782 if (mWakeLock != null && mWakeLock.isHeld()) {
783 mHandler.removeMessages(RELEASE_WAKELOCK);
784 mWakeLock.release();
785 }
786 }
787
Michael Kolb70976932010-11-30 11:34:01 -0800788 /**
Michael Kolbba99c5d2010-11-29 14:57:41 -0800789 * resume all WebView timers using the WebView instance of the given tab
Michael Kolb70976932010-11-30 11:34:01 -0800790 * @param tab guaranteed non-null
791 */
792 private void resumeWebViewTimers(Tab tab) {
Michael Kolb8233fac2010-10-26 16:08:53 -0700793 boolean inLoad = tab.inPageLoad();
794 if ((!mActivityPaused && !inLoad) || (mActivityPaused && inLoad)) {
795 CookieSyncManager.getInstance().startSync();
796 WebView w = tab.getWebView();
Mathew Inwoode1dbb952011-07-08 17:27:38 +0100797 WebViewTimersControl.getInstance().onBrowserActivityResume(w);
Michael Kolb8233fac2010-10-26 16:08:53 -0700798 }
799 }
800
Michael Kolb70976932010-11-30 11:34:01 -0800801 /**
802 * Pause all WebView timers using the WebView of the given tab
803 * @param tab
804 * @return true if the timers are paused or tab is null
805 */
806 private boolean pauseWebViewTimers(Tab tab) {
807 if (tab == null) {
808 return true;
809 } else if (!tab.inPageLoad()) {
Michael Kolb8233fac2010-10-26 16:08:53 -0700810 CookieSyncManager.getInstance().stopSync();
Mathew Inwoode1dbb952011-07-08 17:27:38 +0100811 WebViewTimersControl.getInstance().onBrowserActivityPause(getCurrentWebView());
Michael Kolb8233fac2010-10-26 16:08:53 -0700812 return true;
Michael Kolb8233fac2010-10-26 16:08:53 -0700813 }
Michael Kolb70976932010-11-30 11:34:01 -0800814 return false;
Michael Kolb8233fac2010-10-26 16:08:53 -0700815 }
816
John Reck9c35b9c2012-05-30 10:08:50 -0700817 @Override
818 public void onDestroy() {
John Reck38b4bf52011-02-22 14:39:34 -0800819 if (mUploadHandler != null && !mUploadHandler.handled()) {
Michael Kolb8233fac2010-10-26 16:08:53 -0700820 mUploadHandler.onResult(Activity.RESULT_CANCELED, null);
821 mUploadHandler = null;
822 }
823 if (mTabControl == null) return;
824 mUi.onDestroy();
825 // Remove the current tab and sub window
826 Tab t = mTabControl.getCurrentTab();
827 if (t != null) {
828 dismissSubWindow(t);
829 removeTab(t);
830 }
Leon Scroggins1961ed22010-12-07 15:22:21 -0500831 mActivity.getContentResolver().unregisterContentObserver(mBookmarksObserver);
Michael Kolb8233fac2010-10-26 16:08:53 -0700832 // Destroy all the tabs
833 mTabControl.destroy();
834 WebIconDatabase.getInstance().close();
835 // Stop watching the default geolocation permissions
836 mSystemAllowGeolocationOrigins.stop();
837 mSystemAllowGeolocationOrigins = null;
838 }
839
840 protected boolean isActivityPaused() {
841 return mActivityPaused;
842 }
843
John Reck9c35b9c2012-05-30 10:08:50 -0700844 @Override
845 public void onLowMemory() {
Michael Kolb8233fac2010-10-26 16:08:53 -0700846 mTabControl.freeMemory();
847 }
848
849 @Override
850 public boolean shouldShowErrorConsole() {
851 return mShouldShowErrorConsole;
852 }
853
854 protected void setShouldShowErrorConsole(boolean show) {
855 if (show == mShouldShowErrorConsole) {
856 // Nothing to do.
857 return;
858 }
859 mShouldShowErrorConsole = show;
860 Tab t = mTabControl.getCurrentTab();
861 if (t == null) {
862 // There is no current tab so we cannot toggle the error console
863 return;
864 }
865 mUi.setShouldShowErrorConsole(t, show);
866 }
867
868 @Override
869 public void stopLoading() {
870 mLoadStopped = true;
871 Tab tab = mTabControl.getCurrentTab();
Michael Kolb8233fac2010-10-26 16:08:53 -0700872 WebView w = getCurrentTopWebView();
Michael Kolb778a4882012-04-12 15:27:28 -0700873 if (w != null) {
874 w.stopLoading();
875 mUi.onPageStopped(tab);
876 }
Michael Kolb8233fac2010-10-26 16:08:53 -0700877 }
878
879 boolean didUserStopLoading() {
880 return mLoadStopped;
881 }
882
kaiyiza016da12013-08-26 17:50:22 +0800883 private void handleNetworkNotify(WebView view) {
884 ConnectivityManager conMgr = (ConnectivityManager) this.getContext().getSystemService(
885 Context.CONNECTIVITY_SERVICE);
886 WifiManager wifiMgr = (WifiManager) this.getContext()
887 .getSystemService(Context.WIFI_SERVICE);
888 int networkSwitchTypeOK = this.getContext().getResources()
889 .getInteger(R.integer.netswitch_type_remind);
890
891 if (wifiMgr.isWifiEnabled()) {
892 NetworkInfo mNetworkInfo = conMgr.getActiveNetworkInfo();
893 if (mNetworkInfo == null
894 || (mNetworkInfo != null && (mNetworkInfo.getType() !=
895 ConnectivityManager.TYPE_WIFI))) {
kaiyizb7bf1f22013-10-02 11:42:23 +0800896 List<ScanResult> list = wifiMgr.getScanResults();
897 if (list != null && list.size() == 0) {
898 int isReminder = Settings.System.getInt(
899 mActivity.getContentResolver(),
900 this.getContext().getResources()
901 .getString(R.string.network_switch_remind_type),
902 networkSwitchTypeOK);
903 if (isReminder == networkSwitchTypeOK) {
904 Intent intent = new Intent(
905 INTENT_WIFI_SELECTION_DATA_CONNECTION);
906 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
907 this.getContext().startActivity(intent);
908 }
909 } else {
Bijan Amirzada9b1e9882014-02-26 17:15:46 -0800910 if ((Boolean)ReflectHelper.invokeStaticMethod(
911 "ActivityManagerNative", "isSystemReady", null, null)) {
kaiyizb7bf1f22013-10-02 11:42:23 +0800912 try {
913 Intent intent = new Intent(INTENT_PICK_NETWORK);
914 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
915 this.getContext().startActivity(intent);
916 } catch (Exception e) {
917 String err_msg = this.getContext().getString(
918 R.string.acivity_not_found, INTENT_PICK_NETWORK);
919 Toast.makeText(this.getContext(), err_msg, Toast.LENGTH_LONG).show();
920 }
921 } else {
922 Log.e(LOGTAG, "System is not ready!");
923 }
kaiyiza016da12013-08-26 17:50:22 +0800924 }
925 mNetworkShouldNotify = false;
926 }
927 } else {
928 if (!mNetworkHandler.isNetworkUp()) {
929 view.setNetworkAvailable(false);
930 Log.v(LOGTAG, "handleNetworkNotify() Wlan is not enabled.");
931 }
932 }
933 }
Michael Kolb8233fac2010-10-26 16:08:53 -0700934 // WebViewController
935
936 @Override
John Reck324d4402011-01-11 16:56:42 -0800937 public void onPageStarted(Tab tab, WebView view, Bitmap favicon) {
Michael Kolb8233fac2010-10-26 16:08:53 -0700938
939 // We've started to load a new page. If there was a pending message
940 // to save a screenshot then we will now take the new page and save
941 // an incorrect screenshot. Therefore, remove any pending thumbnail
942 // messages from the queue.
943 mHandler.removeMessages(Controller.UPDATE_BOOKMARK_THUMBNAIL,
John Reck34ef2672011-02-10 11:30:55 -0800944 tab);
Michael Kolb8233fac2010-10-26 16:08:53 -0700945
946 // reset sync timer to avoid sync starts during loading a page
947 CookieSyncManager.getInstance().resetSync();
Bijan Amirzada9b1e9882014-02-26 17:15:46 -0800948 Object[] params = {new String(PROP_NETSWITCH),
949 new Boolean(false)};
950 Class[] type = new Class[] {String.class, boolean.class};
951 Boolean result = (Boolean) ReflectHelper.invokeStaticMethod(
952 "android.os.SystemProperties", "getBoolean",
953 type, params);
954 if (result) {
kaiyiza016da12013-08-26 17:50:22 +0800955 if (!mNetworkHandler.isNetworkUp()) {
956 Log.d(LOGTAG, "onPageStarted() network unavailable");
957 if (mNetworkShouldNotify) {
958 handleNetworkNotify(view);
959 } else {
960 view.setNetworkAvailable(false);
961 }
962 mNetworkShouldNotify = false;
963 } else {
964 Log.d(LOGTAG, "onPageStarted() network available");
965 if (mNetworkShouldNotify) {
966 handleNetworkNotify(view);
967 }
968 mNetworkShouldNotify = false;
969 }
970 } else {
971 if (!mNetworkHandler.isNetworkUp()) {
972 view.setNetworkAvailable(false);
973 }
Michael Kolb8233fac2010-10-26 16:08:53 -0700974 }
975
976 // when BrowserActivity just starts, onPageStarted may be called before
977 // onResume as it is triggered from onCreate. Call resumeWebViewTimers
978 // to start the timer. As we won't switch tabs while an activity is in
979 // pause state, we can ensure calling resume and pause in pair.
980 if (mActivityPaused) {
Michael Kolb70976932010-11-30 11:34:01 -0800981 resumeWebViewTimers(tab);
Michael Kolb8233fac2010-10-26 16:08:53 -0700982 }
983 mLoadStopped = false;
Michael Kolb8233fac2010-10-26 16:08:53 -0700984 endActionMode();
985
John Reck30c714c2010-12-16 17:30:34 -0800986 mUi.onTabDataChanged(tab);
Michael Kolb8233fac2010-10-26 16:08:53 -0700987
John Reck324d4402011-01-11 16:56:42 -0800988 String url = tab.getUrl();
Michael Kolb8233fac2010-10-26 16:08:53 -0700989 // update the bookmark database for favicon
990 maybeUpdateFavicon(tab, null, url, favicon);
991
992 Performance.tracePageStart(url);
993
994 // Performance probe
995 if (false) {
996 Performance.onPageStarted();
997 }
998
999 }
1000
1001 @Override
John Reck324d4402011-01-11 16:56:42 -08001002 public void onPageFinished(Tab tab) {
Michael Kolb72864272012-05-03 15:42:15 -07001003 mCrashRecoveryHandler.backupState();
John Reck30c714c2010-12-16 17:30:34 -08001004 mUi.onTabDataChanged(tab);
Martijn Coenenb2f93552011-06-14 10:48:35 +02001005
Michael Kolb8233fac2010-10-26 16:08:53 -07001006 // Performance probe
1007 if (false) {
John Reck324d4402011-01-11 16:56:42 -08001008 Performance.onPageFinished(tab.getUrl());
Michael Kolb8233fac2010-10-26 16:08:53 -07001009 }
1010
1011 Performance.tracePageFinished();
1012 }
1013
1014 @Override
John Reck30c714c2010-12-16 17:30:34 -08001015 public void onProgressChanged(Tab tab) {
1016 int newProgress = tab.getLoadProgress();
Michael Kolb8233fac2010-10-26 16:08:53 -07001017
1018 if (newProgress == 100) {
1019 CookieSyncManager.getInstance().sync();
1020 // onProgressChanged() may continue to be called after the main
1021 // frame has finished loading, as any remaining sub frames continue
1022 // to load. We'll only get called once though with newProgress as
1023 // 100 when everything is loaded. (onPageFinished is called once
1024 // when the main frame completes loading regardless of the state of
1025 // any sub frames so calls to onProgressChanges may continue after
1026 // onPageFinished has executed)
Michael Kolbb1fb70c2011-11-21 12:38:14 -08001027 if (tab.inPageLoad()) {
1028 updateInLoadMenuItems(mCachedMenu, tab);
Mattias Falk9cc2d032012-05-25 09:40:31 +02001029 } else if (mActivityPaused && pauseWebViewTimers(tab)) {
1030 // pause the WebView timer and release the wake lock if it is
1031 // finished while BrowserActivity is in pause state.
1032 releaseWakeLock();
Michael Kolb8233fac2010-10-26 16:08:53 -07001033 }
John Reckd9862372012-02-21 15:04:50 -08001034 if (!tab.isPrivateBrowsingEnabled()
1035 && !TextUtils.isEmpty(tab.getUrl())
1036 && !tab.isSnapshot()) {
1037 // Only update the bookmark screenshot if the user did not
1038 // cancel the load early and there is not already
1039 // a pending update for the tab.
Michael Kolb72864272012-05-03 15:42:15 -07001040 if (tab.shouldUpdateThumbnail() &&
1041 (tab.inForeground() && !didUserStopLoading()
1042 || !tab.inForeground())) {
John Reckd9862372012-02-21 15:04:50 -08001043 if (!mHandler.hasMessages(UPDATE_BOOKMARK_THUMBNAIL, tab)) {
1044 mHandler.sendMessageDelayed(mHandler.obtainMessage(
1045 UPDATE_BOOKMARK_THUMBNAIL, 0, 0, tab),
Bijan Amirzada9b1e9882014-02-26 17:15:46 -08001046 1500);
John Reckd9862372012-02-21 15:04:50 -08001047 }
1048 }
1049 }
Michael Kolb8233fac2010-10-26 16:08:53 -07001050 } else {
Michael Kolbb1fb70c2011-11-21 12:38:14 -08001051 if (!tab.inPageLoad()) {
Michael Kolb8233fac2010-10-26 16:08:53 -07001052 // onPageFinished may have already been called but a subframe is
Michael Kolbb1fb70c2011-11-21 12:38:14 -08001053 // still loading
1054 // updating the progress and
Michael Kolb8233fac2010-10-26 16:08:53 -07001055 // update the menu items.
Michael Kolbb1fb70c2011-11-21 12:38:14 -08001056 updateInLoadMenuItems(mCachedMenu, tab);
Michael Kolb8233fac2010-10-26 16:08:53 -07001057 }
1058 }
John Reck30c714c2010-12-16 17:30:34 -08001059 mUi.onProgressChanged(tab);
1060 }
1061
1062 @Override
Steve Block2466eff2011-10-03 15:33:09 +01001063 public void onUpdatedSecurityState(Tab tab) {
John Reck30c714c2010-12-16 17:30:34 -08001064 mUi.onTabDataChanged(tab);
Michael Kolb8233fac2010-10-26 16:08:53 -07001065 }
1066
1067 @Override
1068 public void onReceivedTitle(Tab tab, final String title) {
John Reck30c714c2010-12-16 17:30:34 -08001069 mUi.onTabDataChanged(tab);
John Reck49a603c2011-03-03 09:33:05 -08001070 final String pageUrl = tab.getOriginalUrl();
John Reck324d4402011-01-11 16:56:42 -08001071 if (TextUtils.isEmpty(pageUrl) || pageUrl.length()
Michael Kolb8233fac2010-10-26 16:08:53 -07001072 >= SQLiteDatabase.SQLITE_MAX_LIKE_PATTERN_LENGTH) {
1073 return;
1074 }
1075 // Update the title in the history database if not in private browsing mode
1076 if (!tab.isPrivateBrowsingEnabled()) {
John Reckf57c0292011-07-21 18:15:39 -07001077 DataController.getInstance(mActivity).updateHistoryTitle(pageUrl, title);
Michael Kolb8233fac2010-10-26 16:08:53 -07001078 }
1079 }
1080
1081 @Override
1082 public void onFavicon(Tab tab, WebView view, Bitmap icon) {
John Reck30c714c2010-12-16 17:30:34 -08001083 mUi.onTabDataChanged(tab);
Michael Kolb8233fac2010-10-26 16:08:53 -07001084 maybeUpdateFavicon(tab, view.getOriginalUrl(), view.getUrl(), icon);
1085 }
1086
1087 @Override
Michael Kolb18eb3772010-12-10 14:29:51 -08001088 public boolean shouldOverrideUrlLoading(Tab tab, WebView view, String url) {
1089 return mUrlHandler.shouldOverrideUrlLoading(tab, view, url);
Michael Kolb8233fac2010-10-26 16:08:53 -07001090 }
1091
1092 @Override
1093 public boolean shouldOverrideKeyEvent(KeyEvent event) {
1094 if (mMenuIsDown) {
1095 // only check shortcut key when MENU is held
1096 return mActivity.getWindow().isShortcutKey(event.getKeyCode(),
1097 event);
Michael Kolb8233fac2010-10-26 16:08:53 -07001098 }
Bijan Amirzada9b1e9882014-02-26 17:15:46 -08001099 int keyCode = event.getKeyCode();
1100 // We need to send almost every key to WebKit. However:
1101 // 1. We don't want to block the device on the renderer for
1102 // some keys like menu, home, call.
1103 // 2. There are no WebKit equivalents for some of these keys
1104 // (see app/keyboard_codes_win.h)
1105 // Note that these are not the same set as KeyEvent.isSystemKey:
1106 // for instance, AKEYCODE_MEDIA_* will be dispatched to webkit.
1107 if (keyCode == KeyEvent.KEYCODE_MENU ||
1108 keyCode == KeyEvent.KEYCODE_HOME ||
1109 keyCode == KeyEvent.KEYCODE_BACK ||
1110 keyCode == KeyEvent.KEYCODE_CALL ||
1111 keyCode == KeyEvent.KEYCODE_ENDCALL ||
1112 keyCode == KeyEvent.KEYCODE_POWER ||
1113 keyCode == KeyEvent.KEYCODE_HEADSETHOOK ||
1114 keyCode == KeyEvent.KEYCODE_CAMERA ||
1115 keyCode == KeyEvent.KEYCODE_FOCUS ||
1116 keyCode == KeyEvent.KEYCODE_VOLUME_DOWN ||
1117 keyCode == KeyEvent.KEYCODE_VOLUME_MUTE ||
1118 keyCode == KeyEvent.KEYCODE_VOLUME_UP) {
1119 return true;
1120 }
1121
1122 // We also have to intercept some shortcuts before we send them to the ContentView.
1123 if (event.isCtrlPressed() && (
1124 keyCode == KeyEvent.KEYCODE_TAB ||
1125 keyCode == KeyEvent.KEYCODE_W ||
1126 keyCode == KeyEvent.KEYCODE_F4)) {
1127 return true;
1128 }
1129
1130 return false;
Michael Kolb8233fac2010-10-26 16:08:53 -07001131 }
1132
1133 @Override
John Reck997b1b72012-04-19 18:08:25 -07001134 public boolean onUnhandledKeyEvent(KeyEvent event) {
Michael Kolb8233fac2010-10-26 16:08:53 -07001135 if (!isActivityPaused()) {
1136 if (event.getAction() == KeyEvent.ACTION_DOWN) {
John Reck997b1b72012-04-19 18:08:25 -07001137 return mActivity.onKeyDown(event.getKeyCode(), event);
Michael Kolb8233fac2010-10-26 16:08:53 -07001138 } else {
John Reck997b1b72012-04-19 18:08:25 -07001139 return mActivity.onKeyUp(event.getKeyCode(), event);
Michael Kolb8233fac2010-10-26 16:08:53 -07001140 }
1141 }
John Reck997b1b72012-04-19 18:08:25 -07001142 return false;
Michael Kolb8233fac2010-10-26 16:08:53 -07001143 }
1144
1145 @Override
John Reck324d4402011-01-11 16:56:42 -08001146 public void doUpdateVisitedHistory(Tab tab, boolean isReload) {
Michael Kolb8233fac2010-10-26 16:08:53 -07001147 // Don't save anything in private browsing mode
1148 if (tab.isPrivateBrowsingEnabled()) return;
John Reck49a603c2011-03-03 09:33:05 -08001149 String url = tab.getOriginalUrl();
Michael Kolb8233fac2010-10-26 16:08:53 -07001150
John Reck324d4402011-01-11 16:56:42 -08001151 if (TextUtils.isEmpty(url)
1152 || url.regionMatches(true, 0, "about:", 0, 6)) {
Michael Kolb8233fac2010-10-26 16:08:53 -07001153 return;
1154 }
Bijan Amirzada9b1e9882014-02-26 17:15:46 -08001155
John Reckf57c0292011-07-21 18:15:39 -07001156 DataController.getInstance(mActivity).updateVisitedHistory(url);
John Reck6c2e2f32011-08-22 13:41:23 -07001157 mCrashRecoveryHandler.backupState();
Michael Kolb8233fac2010-10-26 16:08:53 -07001158 }
1159
1160 @Override
1161 public void getVisitedHistory(final ValueCallback<String[]> callback) {
1162 AsyncTask<Void, Void, String[]> task =
1163 new AsyncTask<Void, Void, String[]>() {
1164 @Override
1165 public String[] doInBackground(Void... unused) {
Bijan Amirzada9b1e9882014-02-26 17:15:46 -08001166 Object[] params = {mActivity.getContentResolver()};
1167 Class[] type = new Class[] {ContentResolver.class};
1168 return (String[])ReflectHelper.invokeStaticMethod(
1169 "android.provider.Browser","getVisitedHistory",
1170 type, params);
Michael Kolb8233fac2010-10-26 16:08:53 -07001171 }
1172 @Override
1173 public void onPostExecute(String[] result) {
1174 callback.onReceiveValue(result);
1175 }
1176 };
1177 task.execute();
1178 }
1179
1180 @Override
1181 public void onReceivedHttpAuthRequest(Tab tab, WebView view,
1182 final HttpAuthHandler handler, final String host,
1183 final String realm) {
1184 String username = null;
1185 String password = null;
1186
1187 boolean reuseHttpAuthUsernamePassword
1188 = handler.useHttpAuthUsernamePassword();
1189
1190 if (reuseHttpAuthUsernamePassword && view != null) {
1191 String[] credentials = view.getHttpAuthUsernamePassword(host, realm);
1192 if (credentials != null && credentials.length == 2) {
1193 username = credentials[0];
1194 password = credentials[1];
1195 }
1196 }
1197
1198 if (username != null && password != null) {
1199 handler.proceed(username, password);
1200 } else {
Bijan Amirzada9b1e9882014-02-26 17:15:46 -08001201 if (tab.inForeground() /*&& !handler.suppressDialog()*/) {
Michael Kolb8233fac2010-10-26 16:08:53 -07001202 mPageDialogsHandler.showHttpAuthentication(tab, handler, host, realm);
1203 } else {
1204 handler.cancel();
1205 }
1206 }
1207 }
1208
1209 @Override
1210 public void onDownloadStart(Tab tab, String url, String userAgent,
Selim Gurun0b3d66f2012-08-29 13:08:13 -07001211 String contentDisposition, String mimetype, String referer,
1212 long contentLength) {
Kristian Monsenbc5cc752011-03-02 13:14:03 +00001213 WebView w = tab.getWebView();
qqzhoua95a2e22013-04-18 17:28:31 +08001214 boolean ret = DownloadHandler.onDownloadStart(mActivity, url, userAgent,
luxiaol62677b02013-07-22 07:54:49 +08001215 contentDisposition, mimetype, referer, w.isPrivateBrowsingEnabled(), contentLength);
qqzhoua95a2e22013-04-18 17:28:31 +08001216 if (ret == false && w.copyBackForwardList().getSize() == 0) {
Michael Kolb8233fac2010-10-26 16:08:53 -07001217 // This Tab was opened for the sole purpose of downloading a
1218 // file. Remove it.
1219 if (tab == mTabControl.getCurrentTab()) {
1220 // In this case, the Tab is still on top.
1221 goBackOnePageOrQuit();
1222 } else {
1223 // In this case, it is not.
1224 closeTab(tab);
1225 }
1226 }
1227 }
1228
1229 @Override
1230 public Bitmap getDefaultVideoPoster() {
1231 return mUi.getDefaultVideoPoster();
1232 }
1233
1234 @Override
1235 public View getVideoLoadingProgressView() {
1236 return mUi.getVideoLoadingProgressView();
1237 }
1238
1239 @Override
1240 public void showSslCertificateOnError(WebView view, SslErrorHandler handler,
1241 SslError error) {
1242 mPageDialogsHandler.showSSLCertificateOnError(view, handler, error);
1243 }
1244
Patrick Scott92066772011-03-10 08:46:27 -05001245 @Override
1246 public void showAutoLogin(Tab tab) {
1247 assert tab.inForeground();
1248 // Update the title bar to show the auto-login request.
1249 mUi.showAutoLogin(tab);
1250 }
1251
1252 @Override
1253 public void hideAutoLogin(Tab tab) {
1254 assert tab.inForeground();
1255 mUi.hideAutoLogin(tab);
1256 }
1257
Michael Kolb8233fac2010-10-26 16:08:53 -07001258 // helper method
1259
1260 /*
1261 * Update the favorites icon if the private browsing isn't enabled and the
1262 * icon is valid.
1263 */
1264 private void maybeUpdateFavicon(Tab tab, final String originalUrl,
1265 final String url, Bitmap favicon) {
1266 if (favicon == null) {
1267 return;
1268 }
1269 if (!tab.isPrivateBrowsingEnabled()) {
1270 Bookmarks.updateFavicon(mActivity
1271 .getContentResolver(), originalUrl, url, favicon);
1272 }
1273 }
1274
Leon Scroggins4cd97792010-12-03 15:31:56 -05001275 @Override
1276 public void bookmarkedStatusHasChanged(Tab tab) {
John Recke969cc52010-12-21 17:24:43 -08001277 // TODO: Switch to using onTabDataChanged after b/3262950 is fixed
Leon Scroggins4cd97792010-12-03 15:31:56 -05001278 mUi.bookmarkedStatusHasChanged(tab);
1279 }
1280
Michael Kolb8233fac2010-10-26 16:08:53 -07001281 // end WebViewController
1282
1283 protected void pageUp() {
1284 getCurrentTopWebView().pageUp(false);
1285 }
1286
1287 protected void pageDown() {
1288 getCurrentTopWebView().pageDown(false);
1289 }
1290
1291 // callback from phone title bar
John Reck9c35b9c2012-05-30 10:08:50 -07001292 @Override
Michael Kolb8233fac2010-10-26 16:08:53 -07001293 public void editUrl() {
1294 if (mOptionsMenuOpen) mActivity.closeOptionsMenu();
Michael Kolb1f9b3562012-04-24 14:38:34 -07001295 mUi.editUrl(false, true);
Michael Kolb8233fac2010-10-26 16:08:53 -07001296 }
1297
John Reck9c35b9c2012-05-30 10:08:50 -07001298 @Override
Derek Sollenberger2d4f1e22011-06-01 14:50:42 -04001299 public void showCustomView(Tab tab, View view, int requestedOrientation,
Bijan Amirzada9b1e9882014-02-26 17:15:46 -08001300 CustomViewCallback callback) {
Michael Kolb8233fac2010-10-26 16:08:53 -07001301 if (tab.inForeground()) {
1302 if (mUi.isCustomViewShowing()) {
1303 callback.onCustomViewHidden();
1304 return;
1305 }
Derek Sollenberger2d4f1e22011-06-01 14:50:42 -04001306 mUi.showCustomView(view, requestedOrientation, callback);
Michael Kolb8233fac2010-10-26 16:08:53 -07001307 // Save the menu state and set it to empty while the custom
1308 // view is showing.
1309 mOldMenuState = mMenuState;
1310 mMenuState = EMPTY_MENU;
John Reckd73c5a22010-12-22 10:22:50 -08001311 mActivity.invalidateOptionsMenu();
Michael Kolb8233fac2010-10-26 16:08:53 -07001312 }
1313 }
1314
1315 @Override
1316 public void hideCustomView() {
1317 if (mUi.isCustomViewShowing()) {
1318 mUi.onHideCustomView();
1319 // Reset the old menu state.
1320 mMenuState = mOldMenuState;
1321 mOldMenuState = EMPTY_MENU;
John Reckd73c5a22010-12-22 10:22:50 -08001322 mActivity.invalidateOptionsMenu();
Michael Kolb8233fac2010-10-26 16:08:53 -07001323 }
1324 }
1325
John Reck9c35b9c2012-05-30 10:08:50 -07001326 @Override
1327 public void onActivityResult(int requestCode, int resultCode,
Michael Kolb8233fac2010-10-26 16:08:53 -07001328 Intent intent) {
1329 if (getCurrentTopWebView() == null) return;
1330 switch (requestCode) {
1331 case PREFERENCES_PAGE:
1332 if (resultCode == Activity.RESULT_OK && intent != null) {
1333 String action = intent.getStringExtra(Intent.EXTRA_TEXT);
John Reck35e9dd62011-04-25 09:01:54 -07001334 if (PreferenceKeys.PREF_PRIVACY_CLEAR_HISTORY.equals(action)) {
Michael Kolb8233fac2010-10-26 16:08:53 -07001335 mTabControl.removeParentChildRelationShips();
1336 }
1337 }
1338 break;
1339 case FILE_SELECTED:
Ben Murdoch51f6a2f2011-02-21 12:27:07 +00001340 // Chose a file from the file picker.
John Reck9dfcdb12011-02-22 16:40:46 -08001341 if (null == mUploadHandler) break;
Michael Kolb8233fac2010-10-26 16:08:53 -07001342 mUploadHandler.onResult(resultCode, intent);
Michael Kolb8233fac2010-10-26 16:08:53 -07001343 break;
Ben Murdoch8029a772010-11-16 11:58:21 +00001344 case AUTOFILL_SETUP:
1345 // Determine whether a profile was actually set up or not
1346 // and if so, send the message back to the WebTextView to
1347 // fill the form with the new profile.
1348 if (getSettings().getAutoFillProfile() != null) {
1349 mAutoFillSetupMessage.sendToTarget();
1350 mAutoFillSetupMessage = null;
1351 }
1352 break;
John Reckd3e4d5b2011-07-13 15:48:43 -07001353 case COMBO_VIEW:
1354 if (intent == null || resultCode != Activity.RESULT_OK) {
1355 break;
1356 }
John Reck3ba45532011-08-11 16:26:53 -07001357 mUi.showWeb(false);
John Reckd3e4d5b2011-07-13 15:48:43 -07001358 if (Intent.ACTION_VIEW.equals(intent.getAction())) {
1359 Tab t = getCurrentTab();
1360 Uri uri = intent.getData();
kaiyiz6e5b3e02013-08-19 20:02:01 +08001361 mUpdateMyNavThumbnail = true;
1362 mUpdateMyNavThumbnailUrl = uri.toString();
John Reckd3e4d5b2011-07-13 15:48:43 -07001363 loadUrl(t, uri.toString());
1364 } else if (intent.hasExtra(ComboViewActivity.EXTRA_OPEN_ALL)) {
1365 String[] urls = intent.getStringArrayExtra(
1366 ComboViewActivity.EXTRA_OPEN_ALL);
1367 Tab parent = getCurrentTab();
1368 for (String url : urls) {
kaiyiz47097d62013-08-09 09:30:28 +08001369 if (url != null) {
1370 parent = openTab(url, parent,
1371 !mSettings.openInBackground(), true);
1372 }
John Reckd3e4d5b2011-07-13 15:48:43 -07001373 }
1374 } else if (intent.hasExtra(ComboViewActivity.EXTRA_OPEN_SNAPSHOT)) {
1375 long id = intent.getLongExtra(
1376 ComboViewActivity.EXTRA_OPEN_SNAPSHOT, -1);
1377 if (id >= 0) {
Bijan Amirzada9b1e9882014-02-26 17:15:46 -08001378 createNewSnapshotTab(id, true);
John Reckd3e4d5b2011-07-13 15:48:43 -07001379 }
1380 }
1381 break;
Michael Kolb0b129122012-06-04 16:31:58 -07001382 case VOICE_RESULT:
1383 if (resultCode == Activity.RESULT_OK && intent != null) {
1384 ArrayList<String> results = intent.getStringArrayListExtra(
1385 RecognizerIntent.EXTRA_RESULTS);
1386 if (results.size() >= 1) {
1387 mVoiceResult = results.get(0);
1388 }
1389 }
1390 break;
kaiyiz6e5b3e02013-08-19 20:02:01 +08001391 case MY_NAVIGATION:
1392 if (intent == null || resultCode != Activity.RESULT_OK) {
1393 break;
1394 }
1395
1396 if (intent.getBooleanExtra("need_refresh", false) &&
1397 getCurrentTopWebView() != null) {
1398 getCurrentTopWebView().reload();
1399 }
1400 break;
Michael Kolb8233fac2010-10-26 16:08:53 -07001401 default:
1402 break;
1403 }
1404 getCurrentTopWebView().requestFocus();
1405 }
1406
1407 /**
1408 * Open the Go page.
1409 * @param startWithHistory If true, open starting on the history tab.
1410 * Otherwise, start with the bookmarks tab.
1411 */
1412 @Override
Michael Kolb315d5022011-10-13 12:47:11 -07001413 public void bookmarksOrHistoryPicker(ComboViews startView) {
Michael Kolb8233fac2010-10-26 16:08:53 -07001414 if (mTabControl.getCurrentWebView() == null) {
1415 return;
1416 }
Michael Kolbbd3dd942011-01-12 11:09:38 -08001417 // clear action mode
1418 if (isInCustomActionMode()) {
1419 endActionMode();
1420 }
Michael Kolb8233fac2010-10-26 16:08:53 -07001421 Bundle extras = new Bundle();
1422 // Disable opening in a new window if we have maxed out the windows
1423 extras.putBoolean(BrowserBookmarksPage.EXTRA_DISABLE_WINDOW,
1424 !mTabControl.canCreateNewTab());
Michael Kolb315d5022011-10-13 12:47:11 -07001425 mUi.showComboView(startView, extras);
Michael Kolb8233fac2010-10-26 16:08:53 -07001426 }
1427
1428 // combo view callbacks
1429
Michael Kolb8233fac2010-10-26 16:08:53 -07001430 // key handling
1431 protected void onBackKey() {
1432 if (!mUi.onBackKey()) {
1433 WebView subwindow = mTabControl.getCurrentSubWindow();
1434 if (subwindow != null) {
1435 if (subwindow.canGoBack()) {
1436 subwindow.goBack();
1437 } else {
1438 dismissSubWindow(mTabControl.getCurrentTab());
1439 }
1440 } else {
1441 goBackOnePageOrQuit();
1442 }
1443 }
1444 }
1445
Michael Kolb4bd767d2011-05-27 11:33:55 -07001446 protected boolean onMenuKey() {
1447 return mUi.onMenuKey();
Michael Kolb2814a362011-05-19 15:49:41 -07001448 }
1449
Michael Kolb8233fac2010-10-26 16:08:53 -07001450 // menu handling and state
1451 // TODO: maybe put into separate handler
1452
John Reck9c35b9c2012-05-30 10:08:50 -07001453 @Override
1454 public boolean onCreateOptionsMenu(Menu menu) {
John Reckd73c5a22010-12-22 10:22:50 -08001455 if (mMenuState == EMPTY_MENU) {
1456 return false;
1457 }
Michael Kolb8233fac2010-10-26 16:08:53 -07001458 MenuInflater inflater = mActivity.getMenuInflater();
1459 inflater.inflate(R.menu.browser, menu);
Michael Kolb8233fac2010-10-26 16:08:53 -07001460 return true;
1461 }
1462
John Reck9c35b9c2012-05-30 10:08:50 -07001463 @Override
1464 public void onCreateContextMenu(ContextMenu menu, View v,
Michael Kolb8233fac2010-10-26 16:08:53 -07001465 ContextMenuInfo menuInfo) {
John Reck0f602f32011-07-07 15:38:43 -07001466 if (v instanceof TitleBar) {
Michael Kolb8233fac2010-10-26 16:08:53 -07001467 return;
1468 }
1469 if (!(v instanceof WebView)) {
1470 return;
1471 }
Leon Scroggins026f2542010-11-22 13:26:12 -05001472 final WebView webview = (WebView) v;
Michael Kolb8233fac2010-10-26 16:08:53 -07001473 WebView.HitTestResult result = webview.getHitTestResult();
1474 if (result == null) {
1475 return;
1476 }
1477
1478 int type = result.getType();
1479 if (type == WebView.HitTestResult.UNKNOWN_TYPE) {
1480 Log.w(LOGTAG,
1481 "We should not show context menu when nothing is touched");
1482 return;
1483 }
1484 if (type == WebView.HitTestResult.EDIT_TEXT_TYPE) {
1485 // let TextView handles context menu
1486 return;
1487 }
1488
1489 // Note, http://b/issue?id=1106666 is requesting that
1490 // an inflated menu can be used again. This is not available
1491 // yet, so inflate each time (yuk!)
1492 MenuInflater inflater = mActivity.getMenuInflater();
1493 inflater.inflate(R.menu.browsercontext, menu);
1494
1495 // Show the correct menu group
1496 final String extra = result.getExtra();
kaiyiz6e5b3e02013-08-19 20:02:01 +08001497 final String navigationUrl = MyNavigationUtil.getMyNavigationUrl(extra);
Michael Kolbc159c1a2011-12-15 16:06:38 -08001498 if (extra == null) return;
Michael Kolb8233fac2010-10-26 16:08:53 -07001499 menu.setGroupVisible(R.id.PHONE_MENU,
1500 type == WebView.HitTestResult.PHONE_TYPE);
1501 menu.setGroupVisible(R.id.EMAIL_MENU,
1502 type == WebView.HitTestResult.EMAIL_TYPE);
1503 menu.setGroupVisible(R.id.GEO_MENU,
1504 type == WebView.HitTestResult.GEO_TYPE);
kaiyiz6e5b3e02013-08-19 20:02:01 +08001505 String itemUrl = null;
1506 String url = webview.getOriginalUrl();
1507 if (url != null && url.equalsIgnoreCase(MyNavigationUtil.MY_NAVIGATION)) {
1508 itemUrl = Uri.decode(navigationUrl);
1509 if (itemUrl != null && !MyNavigationUtil.isDefaultMyNavigation(itemUrl)) {
1510 menu.setGroupVisible(R.id.MY_NAVIGATION_MENU,
1511 type == WebView.HitTestResult.SRC_IMAGE_ANCHOR_TYPE);
1512 } else {
1513 menu.setGroupVisible(R.id.MY_NAVIGATION_MENU, false);
1514 }
1515 menu.setGroupVisible(R.id.IMAGE_MENU, false);
1516 menu.setGroupVisible(R.id.ANCHOR_MENU, false);
1517 } else {
1518 menu.setGroupVisible(R.id.MY_NAVIGATION_MENU, false);
1519
1520 menu.setGroupVisible(R.id.IMAGE_MENU,
1521 type == WebView.HitTestResult.IMAGE_TYPE
1522 || type == WebView.HitTestResult.SRC_IMAGE_ANCHOR_TYPE);
1523 menu.setGroupVisible(R.id.ANCHOR_MENU,
1524 type == WebView.HitTestResult.SRC_ANCHOR_TYPE
1525 || type == WebView.HitTestResult.SRC_IMAGE_ANCHOR_TYPE);
1526 }
Michael Kolb8233fac2010-10-26 16:08:53 -07001527 // Setup custom handling depending on the type
1528 switch (type) {
1529 case WebView.HitTestResult.PHONE_TYPE:
1530 menu.setHeaderTitle(Uri.decode(extra));
1531 menu.findItem(R.id.dial_context_menu_id).setIntent(
1532 new Intent(Intent.ACTION_VIEW, Uri
1533 .parse(WebView.SCHEME_TEL + extra)));
1534 Intent addIntent = new Intent(Intent.ACTION_INSERT_OR_EDIT);
1535 addIntent.putExtra(Insert.PHONE, Uri.decode(extra));
1536 addIntent.setType(ContactsContract.Contacts.CONTENT_ITEM_TYPE);
1537 menu.findItem(R.id.add_contact_context_menu_id).setIntent(
1538 addIntent);
1539 menu.findItem(R.id.copy_phone_context_menu_id)
1540 .setOnMenuItemClickListener(
1541 new Copy(extra));
1542 break;
1543
1544 case WebView.HitTestResult.EMAIL_TYPE:
1545 menu.setHeaderTitle(extra);
1546 menu.findItem(R.id.email_context_menu_id).setIntent(
1547 new Intent(Intent.ACTION_VIEW, Uri
1548 .parse(WebView.SCHEME_MAILTO + extra)));
1549 menu.findItem(R.id.copy_mail_context_menu_id)
1550 .setOnMenuItemClickListener(
1551 new Copy(extra));
1552 break;
1553
1554 case WebView.HitTestResult.GEO_TYPE:
1555 menu.setHeaderTitle(extra);
1556 menu.findItem(R.id.map_context_menu_id).setIntent(
1557 new Intent(Intent.ACTION_VIEW, Uri
1558 .parse(WebView.SCHEME_GEO
1559 + URLEncoder.encode(extra))));
1560 menu.findItem(R.id.copy_geo_context_menu_id)
1561 .setOnMenuItemClickListener(
1562 new Copy(extra));
1563 break;
1564
1565 case WebView.HitTestResult.SRC_ANCHOR_TYPE:
1566 case WebView.HitTestResult.SRC_IMAGE_ANCHOR_TYPE:
Michael Kolb4c537ce2011-01-13 15:19:33 -08001567 menu.setHeaderTitle(extra);
Michael Kolb8233fac2010-10-26 16:08:53 -07001568 // decide whether to show the open link in new tab option
1569 boolean showNewTab = mTabControl.canCreateNewTab();
1570 MenuItem newTabItem
1571 = menu.findItem(R.id.open_newtab_context_menu_id);
John Reck35e9dd62011-04-25 09:01:54 -07001572 newTabItem.setTitle(getSettings().openInBackground()
Michael Kolb2dd65c82011-01-14 11:07:38 -08001573 ? R.string.contextmenu_openlink_newwindow_background
1574 : R.string.contextmenu_openlink_newwindow);
Michael Kolb8233fac2010-10-26 16:08:53 -07001575 newTabItem.setVisible(showNewTab);
1576 if (showNewTab) {
Leon Scroggins026f2542010-11-22 13:26:12 -05001577 if (WebView.HitTestResult.SRC_IMAGE_ANCHOR_TYPE == type) {
1578 newTabItem.setOnMenuItemClickListener(
1579 new MenuItem.OnMenuItemClickListener() {
1580 @Override
1581 public boolean onMenuItemClick(MenuItem item) {
1582 final HashMap<String, WebView> hrefMap =
1583 new HashMap<String, WebView>();
1584 hrefMap.put("webview", webview);
1585 final Message msg = mHandler.obtainMessage(
1586 FOCUS_NODE_HREF,
1587 R.id.open_newtab_context_menu_id,
1588 0, hrefMap);
1589 webview.requestFocusNodeHref(msg);
1590 return true;
Michael Kolb8233fac2010-10-26 16:08:53 -07001591 }
Leon Scroggins026f2542010-11-22 13:26:12 -05001592 });
1593 } else {
1594 newTabItem.setOnMenuItemClickListener(
1595 new MenuItem.OnMenuItemClickListener() {
1596 @Override
1597 public boolean onMenuItemClick(MenuItem item) {
1598 final Tab parent = mTabControl.getCurrentTab();
John Reck5949c662011-05-27 09:52:29 -07001599 openTab(extra, parent,
1600 !mSettings.openInBackground(),
1601 true);
Leon Scroggins026f2542010-11-22 13:26:12 -05001602 return true;
1603 }
1604 });
1605 }
Michael Kolb8233fac2010-10-26 16:08:53 -07001606 }
kaiyiz6e5b3e02013-08-19 20:02:01 +08001607 if (url != null && url.equalsIgnoreCase(MyNavigationUtil.MY_NAVIGATION)) {
1608 menu.setHeaderTitle(navigationUrl);
1609 menu.findItem(R.id.open_newtab_context_menu_id).setVisible(false);
1610
1611 if (itemUrl != null) {
1612 if (!MyNavigationUtil.isDefaultMyNavigation(itemUrl)) {
1613 menu.findItem(R.id.edit_my_navigation_context_menu_id)
1614 .setOnMenuItemClickListener(new OnMenuItemClickListener() {
1615 @Override
1616 public boolean onMenuItemClick(MenuItem item) {
1617 final Intent intent = new Intent(Controller.this
1618 .getContext(),
1619 AddMyNavigationPage.class);
1620 Bundle bundle = new Bundle();
1621 String url = Uri.decode(navigationUrl);
1622 bundle.putBoolean("isAdding", false);
1623 bundle.putString("url", url);
1624 bundle.putString("name", getNameFromUrl(url));
1625 intent.putExtra("websites", bundle);
1626 mActivity.startActivityForResult(intent, MY_NAVIGATION);
1627 return false;
1628 }
1629 });
1630 menu.findItem(R.id.delete_my_navigation_context_menu_id)
1631 .setOnMenuItemClickListener(new OnMenuItemClickListener() {
1632 @Override
1633 public boolean onMenuItemClick(MenuItem item) {
1634 showMyNavigationDeleteDialog(Uri.decode(navigationUrl));
1635 return false;
1636 }
1637 });
1638 }
1639 } else {
1640 Log.e(LOGTAG, "mynavigation onCreateContextMenu itemUrl is null!");
1641 }
1642 }
Michael Kolb8233fac2010-10-26 16:08:53 -07001643 if (type == WebView.HitTestResult.SRC_ANCHOR_TYPE) {
1644 break;
1645 }
1646 // otherwise fall through to handle image part
1647 case WebView.HitTestResult.IMAGE_TYPE:
Victoria Lease5987b802012-03-12 13:05:23 -07001648 MenuItem shareItem = menu.findItem(R.id.share_link_context_menu_id);
1649 shareItem.setVisible(type == WebView.HitTestResult.IMAGE_TYPE);
Michael Kolb8233fac2010-10-26 16:08:53 -07001650 if (type == WebView.HitTestResult.IMAGE_TYPE) {
1651 menu.setHeaderTitle(extra);
Victoria Lease5987b802012-03-12 13:05:23 -07001652 shareItem.setOnMenuItemClickListener(
1653 new MenuItem.OnMenuItemClickListener() {
1654 @Override
1655 public boolean onMenuItemClick(MenuItem item) {
1656 sharePage(mActivity, null, extra, null,
1657 null);
1658 return true;
1659 }
1660 }
1661 );
Michael Kolb8233fac2010-10-26 16:08:53 -07001662 }
Michael Kolb3639c4c2011-09-28 15:36:40 -07001663 menu.findItem(R.id.view_image_context_menu_id)
1664 .setOnMenuItemClickListener(new OnMenuItemClickListener() {
1665 @Override
1666 public boolean onMenuItemClick(MenuItem item) {
1667 openTab(extra, mTabControl.getCurrentTab(), true, true);
1668 return false;
1669 }
1670 });
Andreas Sandblad8e4ce662012-06-11 11:02:49 +02001671 menu.findItem(R.id.download_context_menu_id).setOnMenuItemClickListener(
1672 new Download(mActivity, extra, webview.isPrivateBrowsingEnabled(),
1673 webview.getSettings().getUserAgentString()));
John Reck3527dd12011-02-22 10:35:29 -08001674 menu.findItem(R.id.set_wallpaper_context_menu_id).
1675 setOnMenuItemClickListener(new WallpaperHandler(mActivity,
1676 extra));
Michael Kolb8233fac2010-10-26 16:08:53 -07001677 break;
1678
1679 default:
1680 Log.w(LOGTAG, "We should not get here.");
1681 break;
1682 }
1683 //update the ui
1684 mUi.onContextMenuCreated(menu);
1685 }
1686
kaiyiz6e5b3e02013-08-19 20:02:01 +08001687 public void startAddMyNavigation(String url) {
1688 final Intent intent = new Intent(Controller.this.getContext(), AddMyNavigationPage.class);
1689 Bundle bundle = new Bundle();
1690 bundle.putBoolean("isAdding", true);
1691 bundle.putString("url", url);
1692 bundle.putString("name", getNameFromUrl(url));
1693 intent.putExtra("websites", bundle);
1694 mActivity.startActivityForResult(intent, MY_NAVIGATION);
1695 }
1696
1697 private void showMyNavigationDeleteDialog(final String itemUrl) {
1698 new AlertDialog.Builder(this.getContext())
1699 .setTitle(R.string.my_navigation_delete_label)
1700 .setIcon(android.R.drawable.ic_dialog_alert)
1701 .setMessage(R.string.my_navigation_delete_msg)
1702 .setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() {
1703 @Override
1704 public void onClick(DialogInterface dialog, int whichButton) {
1705 deleteMyNavigationItem(itemUrl);
1706 }
1707 })
1708 .setNegativeButton(R.string.cancel, null)
1709 .show();
1710 }
1711
1712 private void deleteMyNavigationItem(final String itemUrl) {
1713 ContentResolver cr = this.getContext().getContentResolver();
1714 Cursor cursor = null;
1715
1716 try {
1717 cursor = cr.query(MyNavigationUtil.MY_NAVIGATION_URI,
1718 new String[] {
1719 MyNavigationUtil.ID
1720 }, "url = ?", new String[] {
1721 itemUrl
1722 }, null);
1723 if (null != cursor && cursor.moveToFirst()) {
1724 Uri uri = ContentUris.withAppendedId(MyNavigationUtil.MY_NAVIGATION_URI,
1725 cursor.getLong(0));
1726
1727 ContentValues values = new ContentValues();
1728 values.put(MyNavigationUtil.TITLE, "");
1729 values.put(MyNavigationUtil.URL, "ae://" + cursor.getLong(0) + "add-fav");
1730 values.put(MyNavigationUtil.WEBSITE, 0 + "");
1731 ByteArrayOutputStream os = new ByteArrayOutputStream();
1732 Bitmap bm = BitmapFactory.decodeResource(this.getContext().getResources(),
1733 R.raw.my_navigation_add);
1734 bm.compress(Bitmap.CompressFormat.PNG, 100, os);
1735 values.put(MyNavigationUtil.THUMBNAIL, os.toByteArray());
1736 Log.d(LOGTAG, "deleteMyNavigationItem uri is : " + uri);
1737 cr.update(uri, values, null, null);
1738 } else {
1739 Log.e(LOGTAG, "deleteMyNavigationItem the item does not exist!");
1740 }
1741 } catch (IllegalStateException e) {
1742 Log.e(LOGTAG, "deleteMyNavigationItem", e);
1743 } finally {
1744 if (null != cursor) {
1745 cursor.close();
1746 }
1747 }
1748
1749 if (getCurrentTopWebView() != null) {
1750 getCurrentTopWebView().reload();
1751 }
1752 }
1753
1754 private String getNameFromUrl(String itemUrl) {
1755 ContentResolver cr = this.getContext().getContentResolver();
1756 Cursor cursor = null;
1757 String name = null;
1758
1759 try {
1760 cursor = cr.query(MyNavigationUtil.MY_NAVIGATION_URI,
1761 new String[] {
1762 MyNavigationUtil.TITLE
1763 }, "url = ?", new String[] {
1764 itemUrl
1765 }, null);
1766 if (null != cursor && cursor.moveToFirst()) {
1767 name = cursor.getString(0);
1768 } else {
1769 Log.e(LOGTAG, "this item does not exist!");
1770 }
1771 } catch (IllegalStateException e) {
1772 Log.e(LOGTAG, "getNameFromUrl", e);
1773 } finally {
1774 if (null != cursor) {
1775 cursor.close();
1776 }
1777 }
1778 return name;
1779 }
1780
1781 private void updateMyNavigationThumbnail(final String itemUrl, WebView webView) {
1782 int width = mActivity.getResources().getDimensionPixelOffset(
1783 R.dimen.myNavigationThumbnailWidth);
1784 int height = mActivity.getResources().getDimensionPixelOffset(
1785 R.dimen.myNavigationThumbnailHeight);
1786
1787 final Bitmap bm = createScreenshot(webView, width, height);
1788
1789 if (bm == null) {
1790 Log.e(LOGTAG, "updateMyNavigationThumbnail bm is null!");
1791 return;
1792 }
1793
1794 final ContentResolver cr = mActivity.getContentResolver();
1795 new AsyncTask<Void, Void, Void>() {
1796 @Override
1797 protected Void doInBackground(Void... unused) {
1798 ContentResolver cr = mActivity.getContentResolver();
1799 Cursor cursor = null;
1800 try {
1801 cursor = cr.query(MyNavigationUtil.MY_NAVIGATION_URI,
1802 new String[] {
1803 MyNavigationUtil.ID
1804 }, "url = ?", new String[] {
1805 itemUrl
1806 }, null);
1807 if (null != cursor && cursor.moveToFirst()) {
1808 final ByteArrayOutputStream os = new ByteArrayOutputStream();
1809 bm.compress(Bitmap.CompressFormat.PNG, 100, os);
1810
1811 ContentValues values = new ContentValues();
1812 values.put(MyNavigationUtil.THUMBNAIL, os.toByteArray());
1813 Uri uri = ContentUris.withAppendedId(MyNavigationUtil.MY_NAVIGATION_URI,
1814 cursor.getLong(0));
1815 Log.d(LOGTAG, "updateMyNavigationThumbnail uri is " + uri);
1816 cr.update(uri, values, null, null);
1817 os.close();
1818 }
1819 } catch (IllegalStateException e) {
1820 Log.e(LOGTAG, "updateMyNavigationThumbnail", e);
1821 } catch (IOException e) {
1822 Log.e(LOGTAG, "updateMyNavigationThumbnail", e);
1823 } finally {
1824 if (null != cursor) {
1825 cursor.close();
1826 }
1827 }
1828 return null;
1829 }
1830 }.execute();
1831 }
Michael Kolb8233fac2010-10-26 16:08:53 -07001832 /**
1833 * As the menu can be open when loading state changes
1834 * we must manually update the state of the stop/reload menu
1835 * item
1836 */
Michael Kolbb1fb70c2011-11-21 12:38:14 -08001837 private void updateInLoadMenuItems(Menu menu, Tab tab) {
Michael Kolb8233fac2010-10-26 16:08:53 -07001838 if (menu == null) {
1839 return;
1840 }
1841 MenuItem dest = menu.findItem(R.id.stop_reload_menu_id);
Michael Kolbb8337132011-11-28 15:07:39 -08001842 MenuItem src = ((tab != null) && tab.inPageLoad()) ?
Michael Kolb8233fac2010-10-26 16:08:53 -07001843 menu.findItem(R.id.stop_menu_id):
1844 menu.findItem(R.id.reload_menu_id);
1845 if (src != null) {
1846 dest.setIcon(src.getIcon());
1847 dest.setTitle(src.getTitle());
1848 }
1849 }
1850
John Reck9c35b9c2012-05-30 10:08:50 -07001851 @Override
1852 public boolean onPrepareOptionsMenu(Menu menu) {
Michael Kolbb1fb70c2011-11-21 12:38:14 -08001853 updateInLoadMenuItems(menu, getCurrentTab());
John Recke1a03a32011-09-14 17:04:16 -07001854 // hold on to the menu reference here; it is used by the page callbacks
1855 // to update the menu based on loading state
1856 mCachedMenu = menu;
Michael Kolb8233fac2010-10-26 16:08:53 -07001857 // Note: setVisible will decide whether an item is visible; while
1858 // setEnabled() will decide whether an item is enabled, which also means
1859 // whether the matching shortcut key will function.
1860 switch (mMenuState) {
1861 case EMPTY_MENU:
1862 if (mCurrentMenuState != mMenuState) {
1863 menu.setGroupVisible(R.id.MAIN_MENU, false);
1864 menu.setGroupEnabled(R.id.MAIN_MENU, false);
1865 menu.setGroupEnabled(R.id.MAIN_SHORTCUT_MENU, false);
1866 }
1867 break;
1868 default:
1869 if (mCurrentMenuState != mMenuState) {
1870 menu.setGroupVisible(R.id.MAIN_MENU, true);
1871 menu.setGroupEnabled(R.id.MAIN_MENU, true);
1872 menu.setGroupEnabled(R.id.MAIN_SHORTCUT_MENU, true);
1873 }
Michael Kolb4bf79712011-07-14 14:18:12 -07001874 updateMenuState(getCurrentTab(), menu);
Michael Kolb8233fac2010-10-26 16:08:53 -07001875 break;
1876 }
1877 mCurrentMenuState = mMenuState;
Michael Kolb1acef692011-03-08 14:12:06 -08001878 return mUi.onPrepareOptionsMenu(menu);
Michael Kolb8233fac2010-10-26 16:08:53 -07001879 }
1880
Michael Kolb4bf79712011-07-14 14:18:12 -07001881 @Override
1882 public void updateMenuState(Tab tab, Menu menu) {
1883 boolean canGoBack = false;
1884 boolean canGoForward = false;
John Reck42229bc2011-08-19 13:26:43 -07001885 boolean isDesktopUa = false;
John Recke1a03a32011-09-14 17:04:16 -07001886 boolean isLive = false;
Michael Kolb4bf79712011-07-14 14:18:12 -07001887 if (tab != null) {
1888 canGoBack = tab.canGoBack();
1889 canGoForward = tab.canGoForward();
John Reck42229bc2011-08-19 13:26:43 -07001890 isDesktopUa = mSettings.hasDesktopUseragent(tab.getWebView());
John Recke1a03a32011-09-14 17:04:16 -07001891 isLive = !tab.isSnapshot();
Michael Kolb4bf79712011-07-14 14:18:12 -07001892 }
1893 final MenuItem back = menu.findItem(R.id.back_menu_id);
1894 back.setEnabled(canGoBack);
1895
1896 final MenuItem home = menu.findItem(R.id.homepage_menu_id);
Michael Kolb4bf79712011-07-14 14:18:12 -07001897
1898 final MenuItem forward = menu.findItem(R.id.forward_menu_id);
1899 forward.setEnabled(canGoForward);
1900
Michael Kolbb1fb70c2011-11-21 12:38:14 -08001901 final MenuItem source = menu.findItem(isInLoad() ? R.id.stop_menu_id
1902 : R.id.reload_menu_id);
Michael Kolb4bf79712011-07-14 14:18:12 -07001903 final MenuItem dest = menu.findItem(R.id.stop_reload_menu_id);
Michael Kolb7ab75ee2011-07-14 16:36:38 -07001904 if (source != null && dest != null) {
1905 dest.setTitle(source.getTitle());
1906 dest.setIcon(source.getIcon());
1907 }
John Recke1a03a32011-09-14 17:04:16 -07001908 menu.setGroupVisible(R.id.NAV_MENU, isLive);
Michael Kolb4bf79712011-07-14 14:18:12 -07001909
1910 // decide whether to show the share link option
1911 PackageManager pm = mActivity.getPackageManager();
1912 Intent send = new Intent(Intent.ACTION_SEND);
1913 send.setType("text/plain");
1914 ResolveInfo ri = pm.resolveActivity(send,
1915 PackageManager.MATCH_DEFAULT_ONLY);
1916 menu.findItem(R.id.share_page_menu_id).setVisible(ri != null);
1917
1918 boolean isNavDump = mSettings.enableNavDump();
1919 final MenuItem nav = menu.findItem(R.id.dump_nav_menu_id);
1920 nav.setVisible(isNavDump);
1921 nav.setEnabled(isNavDump);
1922
1923 boolean showDebugSettings = mSettings.isDebugEnabled();
John Reck42229bc2011-08-19 13:26:43 -07001924 final MenuItem uaSwitcher = menu.findItem(R.id.ua_desktop_menu_id);
1925 uaSwitcher.setChecked(isDesktopUa);
John Recke1a03a32011-09-14 17:04:16 -07001926 menu.setGroupVisible(R.id.LIVE_MENU, isLive);
1927 menu.setGroupVisible(R.id.SNAPSHOT_MENU, !isLive);
kaiyiza8b6dbb2013-07-29 18:11:22 +08001928 // history and snapshots item are the members of COMBO menu group,
1929 // so if show history item, only make snapshots item invisible.
1930 menu.findItem(R.id.snapshots_menu_id).setVisible(false);
Michael Kolb4bf79712011-07-14 14:18:12 -07001931
Michael Kolb7bdee0b2011-08-01 11:55:38 -07001932 mUi.updateMenuState(tab, menu);
Michael Kolb4bf79712011-07-14 14:18:12 -07001933 }
1934
John Reck9c35b9c2012-05-30 10:08:50 -07001935 @Override
Michael Kolb8233fac2010-10-26 16:08:53 -07001936 public boolean onOptionsItemSelected(MenuItem item) {
Michael Kolb8233fac2010-10-26 16:08:53 -07001937 if (null == getCurrentTopWebView()) {
1938 return false;
1939 }
1940 if (mMenuIsDown) {
1941 // The shortcut action consumes the MENU. Even if it is still down,
1942 // it won't trigger the next shortcut action. In the case of the
1943 // shortcut action triggering a new activity, like Bookmarks, we
1944 // won't get onKeyUp for MENU. So it is important to reset it here.
1945 mMenuIsDown = false;
1946 }
Michael Kolb3ca12752011-07-20 13:52:25 -07001947 if (mUi.onOptionsItemSelected(item)) {
1948 // ui callback handled it
1949 return true;
1950 }
Michael Kolb8233fac2010-10-26 16:08:53 -07001951 switch (item.getItemId()) {
1952 // -- Main menu
1953 case R.id.new_tab_menu_id:
1954 openTabToHomePage();
1955 break;
1956
1957 case R.id.incognito_menu_id:
Michael Kolb519d2282011-05-09 17:03:19 -07001958 openIncognitoTab();
Michael Kolb8233fac2010-10-26 16:08:53 -07001959 break;
1960
Afzal Najamd4e33312012-04-26 01:54:01 -04001961 case R.id.close_other_tabs_id:
1962 closeOtherTabs();
1963 break;
1964
Michael Kolb8233fac2010-10-26 16:08:53 -07001965 case R.id.goto_menu_id:
1966 editUrl();
1967 break;
1968
1969 case R.id.bookmarks_menu_id:
Michael Kolb315d5022011-10-13 12:47:11 -07001970 bookmarksOrHistoryPicker(ComboViews.Bookmarks);
1971 break;
1972
1973 case R.id.history_menu_id:
1974 bookmarksOrHistoryPicker(ComboViews.History);
1975 break;
1976
1977 case R.id.snapshots_menu_id:
1978 bookmarksOrHistoryPicker(ComboViews.Snapshots);
Michael Kolb8233fac2010-10-26 16:08:53 -07001979 break;
1980
Michael Kolb8233fac2010-10-26 16:08:53 -07001981 case R.id.add_bookmark_menu_id:
Michael Kolb80f75082012-04-10 10:50:06 -07001982 bookmarkCurrentPage();
Michael Kolb8233fac2010-10-26 16:08:53 -07001983 break;
1984
1985 case R.id.stop_reload_menu_id:
Michael Kolbb1fb70c2011-11-21 12:38:14 -08001986 if (isInLoad()) {
Michael Kolb8233fac2010-10-26 16:08:53 -07001987 stopLoading();
1988 } else {
Bijan Amirzada9b1e9882014-02-26 17:15:46 -08001989 Tab currentTab = mTabControl.getCurrentTab();
1990 if (currentTab.hasCrashed) {
1991 currentTab.replaceCrashView(getCurrentTopWebView(),
1992 currentTab.getViewContainer());
1993 }
Michael Kolb8233fac2010-10-26 16:08:53 -07001994 getCurrentTopWebView().reload();
1995 }
1996 break;
1997
1998 case R.id.back_menu_id:
John Reckef654f12011-07-12 16:42:08 -07001999 getCurrentTab().goBack();
Michael Kolb8233fac2010-10-26 16:08:53 -07002000 break;
2001
2002 case R.id.forward_menu_id:
John Reckef654f12011-07-12 16:42:08 -07002003 getCurrentTab().goForward();
Michael Kolb8233fac2010-10-26 16:08:53 -07002004 break;
2005
2006 case R.id.close_menu_id:
2007 // Close the subwindow if it exists.
2008 if (mTabControl.getCurrentSubWindow() != null) {
2009 dismissSubWindow(mTabControl.getCurrentTab());
2010 break;
2011 }
2012 closeCurrentTab();
2013 break;
2014
kaiyiza8b6dbb2013-07-29 18:11:22 +08002015 case R.id.exit_menu_id:
Bijan Amirzada9b1e9882014-02-26 17:15:46 -08002016 Object[] params = { new String("persist.debug.browsermonkeytest")};
2017 Class[] type = new Class[] {String.class};
2018 String ret = (String)ReflectHelper.invokeStaticMethod(
2019 "android.os.SystemProperties","get", type, params);
kaiyiza8b6dbb2013-07-29 18:11:22 +08002020 if (ret != null && ret.equals("enable"))
2021 break;
luxiaolb40014b2013-07-19 10:01:43 +08002022 showExitDialog(mActivity);
2023 return true;
Michael Kolb8233fac2010-10-26 16:08:53 -07002024 case R.id.homepage_menu_id:
2025 Tab current = mTabControl.getCurrentTab();
John Reck26b18322011-06-21 13:08:58 -07002026 loadUrl(current, mSettings.getHomePage());
Michael Kolb8233fac2010-10-26 16:08:53 -07002027 break;
2028
2029 case R.id.preferences_menu_id:
Michael Kolb80f75082012-04-10 10:50:06 -07002030 openPreferences();
Michael Kolb8233fac2010-10-26 16:08:53 -07002031 break;
2032
2033 case R.id.find_menu_id:
Michael Kolbe11b9212012-04-13 13:39:54 -07002034 findOnPage();
Michael Kolb8233fac2010-10-26 16:08:53 -07002035 break;
2036
John Reck2bc80422011-06-30 15:11:49 -07002037 case R.id.save_snapshot_menu_id:
2038 final Tab source = getTabControl().getCurrentTab();
John Reckf33b1632011-06-04 20:00:23 -07002039 if (source == null) break;
John Reck68234a92012-04-19 15:27:12 -07002040 new SaveSnapshotTask(source).execute();
Leon Scrogginsac993842011-02-02 12:54:07 -05002041 break;
2042
Michael Kolb8233fac2010-10-26 16:08:53 -07002043 case R.id.page_info_menu_id:
Michael Kolb315d5022011-10-13 12:47:11 -07002044 showPageInfo();
Michael Kolb8233fac2010-10-26 16:08:53 -07002045 break;
2046
John Recke1a03a32011-09-14 17:04:16 -07002047 case R.id.snapshot_go_live:
2048 goLive();
2049 return true;
2050
Michael Kolb8233fac2010-10-26 16:08:53 -07002051 case R.id.share_page_menu_id:
2052 Tab currentTab = mTabControl.getCurrentTab();
2053 if (null == currentTab) {
Michael Kolb8233fac2010-10-26 16:08:53 -07002054 return false;
2055 }
Michael Kolbba99c5d2010-11-29 14:57:41 -08002056 shareCurrentPage(currentTab);
Michael Kolb8233fac2010-10-26 16:08:53 -07002057 break;
2058
2059 case R.id.dump_nav_menu_id:
2060 getCurrentTopWebView().debugDump();
2061 break;
2062
Michael Kolb8233fac2010-10-26 16:08:53 -07002063 case R.id.zoom_in_menu_id:
2064 getCurrentTopWebView().zoomIn();
2065 break;
2066
2067 case R.id.zoom_out_menu_id:
2068 getCurrentTopWebView().zoomOut();
2069 break;
2070
2071 case R.id.view_downloads_menu_id:
2072 viewDownloads();
2073 break;
2074
John Reck42229bc2011-08-19 13:26:43 -07002075 case R.id.ua_desktop_menu_id:
Michael Kolb80f75082012-04-10 10:50:06 -07002076 toggleUserAgent();
John Reck42229bc2011-08-19 13:26:43 -07002077 break;
2078
Michael Kolb8233fac2010-10-26 16:08:53 -07002079 case R.id.window_one_menu_id:
2080 case R.id.window_two_menu_id:
2081 case R.id.window_three_menu_id:
2082 case R.id.window_four_menu_id:
2083 case R.id.window_five_menu_id:
2084 case R.id.window_six_menu_id:
2085 case R.id.window_seven_menu_id:
2086 case R.id.window_eight_menu_id:
2087 {
2088 int menuid = item.getItemId();
2089 for (int id = 0; id < WINDOW_SHORTCUT_ID_ARRAY.length; id++) {
2090 if (WINDOW_SHORTCUT_ID_ARRAY[id] == menuid) {
2091 Tab desiredTab = mTabControl.getTab(id);
2092 if (desiredTab != null &&
2093 desiredTab != mTabControl.getCurrentTab()) {
Michael Kolbc831b632011-05-11 09:30:34 -07002094 switchToTab(desiredTab);
Michael Kolb8233fac2010-10-26 16:08:53 -07002095 }
2096 break;
2097 }
2098 }
2099 }
2100 break;
2101
2102 default:
2103 return false;
2104 }
Michael Kolb8233fac2010-10-26 16:08:53 -07002105 return true;
2106 }
2107
John Reck68234a92012-04-19 15:27:12 -07002108 private class SaveSnapshotTask extends AsyncTask<Void, Void, Long>
2109 implements OnCancelListener {
2110
2111 private Tab mTab;
2112 private Dialog mProgressDialog;
2113 private ContentValues mValues;
2114
2115 private SaveSnapshotTask(Tab tab) {
2116 mTab = tab;
2117 }
2118
2119 @Override
2120 protected void onPreExecute() {
2121 CharSequence message = mActivity.getText(R.string.saving_snapshot);
2122 mProgressDialog = ProgressDialog.show(mActivity, null, message,
2123 true, true, this);
2124 mValues = mTab.createSnapshotValues();
2125 }
2126
2127 @Override
2128 protected Long doInBackground(Void... params) {
2129 if (!mTab.saveViewState(mValues)) {
2130 return null;
2131 }
2132 if (isCancelled()) {
2133 String path = mValues.getAsString(Snapshots.VIEWSTATE_PATH);
2134 File file = mActivity.getFileStreamPath(path);
2135 if (!file.delete()) {
2136 file.deleteOnExit();
2137 }
2138 return null;
2139 }
2140 final ContentResolver cr = mActivity.getContentResolver();
2141 Uri result = cr.insert(Snapshots.CONTENT_URI, mValues);
2142 if (result == null) {
2143 return null;
2144 }
2145 long id = ContentUris.parseId(result);
2146 return id;
2147 }
2148
2149 @Override
2150 protected void onPostExecute(Long id) {
2151 if (isCancelled()) {
2152 return;
2153 }
2154 mProgressDialog.dismiss();
2155 if (id == null) {
2156 Toast.makeText(mActivity, R.string.snapshot_failed,
2157 Toast.LENGTH_SHORT).show();
2158 return;
2159 }
2160 Bundle b = new Bundle();
2161 b.putLong(BrowserSnapshotPage.EXTRA_ANIMATE_ID, id);
2162 mUi.showComboView(ComboViews.Snapshots, b);
2163 }
2164
2165 @Override
2166 public void onCancel(DialogInterface dialog) {
2167 cancel(true);
2168 }
2169 }
2170
Michael Kolb80f75082012-04-10 10:50:06 -07002171 @Override
2172 public void toggleUserAgent() {
2173 WebView web = getCurrentWebView();
2174 mSettings.toggleDesktopUseragent(web);
2175 web.loadUrl(web.getOriginalUrl());
2176 }
2177
2178 @Override
2179 public void findOnPage() {
2180 getCurrentTopWebView().showFindDialog(null, true);
2181 }
2182
2183 @Override
2184 public void openPreferences() {
2185 Intent intent = new Intent(mActivity, BrowserPreferencesPage.class);
2186 intent.putExtra(BrowserPreferencesPage.CURRENT_PAGE,
2187 getCurrentTopWebView().getUrl());
2188 mActivity.startActivityForResult(intent, PREFERENCES_PAGE);
2189 }
2190
2191 @Override
2192 public void bookmarkCurrentPage() {
2193 Intent bookmarkIntent = createBookmarkCurrentPageIntent(false);
2194 if (bookmarkIntent != null) {
2195 mActivity.startActivity(bookmarkIntent);
2196 }
2197 }
2198
John Recke1a03a32011-09-14 17:04:16 -07002199 private void goLive() {
Bijan Amirzada9b1e9882014-02-26 17:15:46 -08002200 SnapshotTab t = (SnapshotTab) getCurrentTab();
2201 t.loadUrl(t.getLiveUrl(), null);
John Recke1a03a32011-09-14 17:04:16 -07002202 }
2203
luxiaolb40014b2013-07-19 10:01:43 +08002204 private void showExitDialog(final Activity activity) {
2205 new AlertDialog.Builder(activity)
2206 .setTitle(R.string.exit_browser_title)
2207 .setIcon(android.R.drawable.ic_dialog_alert)
2208 .setMessage(R.string.exit_browser_msg)
2209 .setNegativeButton(R.string.exit_minimize, new DialogInterface.OnClickListener() {
2210 public void onClick(DialogInterface dialog, int which) {
2211 activity.moveTaskToBack(true);
2212 dialog.dismiss();
2213 }
2214 })
2215 .setPositiveButton(R.string.exit_quit, new DialogInterface.OnClickListener() {
2216 public void onClick(DialogInterface dialog, int which) {
2217 activity.finish();
2218 mHandler.postDelayed(new Runnable() {
2219 @Override
2220 public void run() {
2221 // TODO Auto-generated method stub
2222 mCrashRecoveryHandler.clearState(true);
2223 int pid = android.os.Process.myPid();
2224 android.os.Process.killProcess(pid);
2225 }
2226 }, 300);
2227 dialog.dismiss();
2228 }
2229 })
2230 .show();
2231 }
Michael Kolb315d5022011-10-13 12:47:11 -07002232 @Override
2233 public void showPageInfo() {
2234 mPageDialogsHandler.showPageInfo(mTabControl.getCurrentTab(), false, null);
2235 }
2236
John Reck9c35b9c2012-05-30 10:08:50 -07002237 @Override
Michael Kolb8233fac2010-10-26 16:08:53 -07002238 public boolean onContextItemSelected(MenuItem item) {
John Reckdbf57df2010-11-09 16:34:03 -08002239 // Let the History and Bookmark fragments handle menus they created.
2240 if (item.getGroupId() == R.id.CONTEXT_MENU) {
2241 return false;
2242 }
2243
Michael Kolb8233fac2010-10-26 16:08:53 -07002244 int id = item.getItemId();
2245 boolean result = true;
2246 switch (id) {
Michael Kolb8233fac2010-10-26 16:08:53 -07002247 // -- Browser context menu
2248 case R.id.open_context_menu_id:
Michael Kolb8233fac2010-10-26 16:08:53 -07002249 case R.id.save_link_context_menu_id:
Michael Kolb8233fac2010-10-26 16:08:53 -07002250 case R.id.copy_link_context_menu_id:
2251 final WebView webView = getCurrentTopWebView();
2252 if (null == webView) {
2253 result = false;
2254 break;
2255 }
2256 final HashMap<String, WebView> hrefMap =
2257 new HashMap<String, WebView>();
2258 hrefMap.put("webview", webView);
2259 final Message msg = mHandler.obtainMessage(
2260 FOCUS_NODE_HREF, id, 0, hrefMap);
2261 webView.requestFocusNodeHref(msg);
2262 break;
2263
2264 default:
2265 // For other context menus
2266 result = onOptionsItemSelected(item);
2267 }
Michael Kolb8233fac2010-10-26 16:08:53 -07002268 return result;
2269 }
2270
2271 /**
2272 * support programmatically opening the context menu
2273 */
2274 public void openContextMenu(View view) {
2275 mActivity.openContextMenu(view);
2276 }
2277
2278 /**
2279 * programmatically open the options menu
2280 */
2281 public void openOptionsMenu() {
2282 mActivity.openOptionsMenu();
2283 }
2284
John Reck9c35b9c2012-05-30 10:08:50 -07002285 @Override
Michael Kolb8233fac2010-10-26 16:08:53 -07002286 public boolean onMenuOpened(int featureId, Menu menu) {
2287 if (mOptionsMenuOpen) {
2288 if (mConfigChanged) {
2289 // We do not need to make any changes to the state of the
2290 // title bar, since the only thing that happened was a
2291 // change in orientation
2292 mConfigChanged = false;
2293 } else {
2294 if (!mExtendedMenuOpen) {
2295 mExtendedMenuOpen = true;
2296 mUi.onExtendedMenuOpened();
2297 } else {
2298 // Switching the menu back to icon view, so show the
2299 // title bar once again.
2300 mExtendedMenuOpen = false;
Michael Kolbb1fb70c2011-11-21 12:38:14 -08002301 mUi.onExtendedMenuClosed(isInLoad());
Michael Kolb8233fac2010-10-26 16:08:53 -07002302 }
2303 }
2304 } else {
2305 // The options menu is closed, so open it, and show the title
2306 mOptionsMenuOpen = true;
2307 mConfigChanged = false;
2308 mExtendedMenuOpen = false;
2309 mUi.onOptionsMenuOpened();
2310 }
2311 return true;
2312 }
2313
John Reck9c35b9c2012-05-30 10:08:50 -07002314 @Override
Michael Kolb8233fac2010-10-26 16:08:53 -07002315 public void onOptionsMenuClosed(Menu menu) {
2316 mOptionsMenuOpen = false;
Michael Kolbb1fb70c2011-11-21 12:38:14 -08002317 mUi.onOptionsMenuClosed(isInLoad());
Michael Kolb8233fac2010-10-26 16:08:53 -07002318 }
2319
John Reck9c35b9c2012-05-30 10:08:50 -07002320 @Override
Michael Kolb8233fac2010-10-26 16:08:53 -07002321 public void onContextMenuClosed(Menu menu) {
Michael Kolbb1fb70c2011-11-21 12:38:14 -08002322 mUi.onContextMenuClosed(menu, isInLoad());
Michael Kolb8233fac2010-10-26 16:08:53 -07002323 }
2324
2325 // Helper method for getting the top window.
2326 @Override
2327 public WebView getCurrentTopWebView() {
2328 return mTabControl.getCurrentTopWebView();
2329 }
2330
2331 @Override
2332 public WebView getCurrentWebView() {
2333 return mTabControl.getCurrentWebView();
2334 }
2335
2336 /*
2337 * This method is called as a result of the user selecting the options
2338 * menu to see the download window. It shows the download window on top of
2339 * the current window.
2340 */
2341 void viewDownloads() {
2342 Intent intent = new Intent(DownloadManager.ACTION_VIEW_DOWNLOADS);
2343 mActivity.startActivity(intent);
2344 }
2345
John Reck30b065e2011-07-19 10:58:05 -07002346 int getActionModeHeight() {
2347 TypedArray actionBarSizeTypedArray = mActivity.obtainStyledAttributes(
2348 new int[] { android.R.attr.actionBarSize });
2349 int size = (int) actionBarSizeTypedArray.getDimension(0, 0f);
2350 actionBarSizeTypedArray.recycle();
2351 return size;
2352 }
2353
Michael Kolb8233fac2010-10-26 16:08:53 -07002354 // action mode
2355
John Reck9c35b9c2012-05-30 10:08:50 -07002356 @Override
2357 public void onActionModeStarted(ActionMode mode) {
Michael Kolb8233fac2010-10-26 16:08:53 -07002358 mUi.onActionModeStarted(mode);
2359 mActionMode = mode;
2360 }
2361
2362 /*
2363 * True if a custom ActionMode (i.e. find or select) is in use.
2364 */
2365 @Override
2366 public boolean isInCustomActionMode() {
2367 return mActionMode != null;
2368 }
2369
2370 /*
2371 * End the current ActionMode.
2372 */
2373 @Override
2374 public void endActionMode() {
2375 if (mActionMode != null) {
2376 mActionMode.finish();
2377 }
2378 }
2379
2380 /*
2381 * Called by find and select when they are finished. Replace title bars
2382 * as necessary.
2383 */
John Reck9c35b9c2012-05-30 10:08:50 -07002384 @Override
Michael Kolb8233fac2010-10-26 16:08:53 -07002385 public void onActionModeFinished(ActionMode mode) {
2386 if (!isInCustomActionMode()) return;
Michael Kolbb1fb70c2011-11-21 12:38:14 -08002387 mUi.onActionModeFinished(isInLoad());
Michael Kolb8233fac2010-10-26 16:08:53 -07002388 mActionMode = null;
2389 }
2390
2391 boolean isInLoad() {
Michael Kolbc5b0b2d2011-11-29 16:13:35 -08002392 final Tab tab = getCurrentTab();
2393 return (tab != null) && tab.inPageLoad();
Michael Kolb8233fac2010-10-26 16:08:53 -07002394 }
2395
2396 // bookmark handling
2397
2398 /**
2399 * add the current page as a bookmark to the given folder id
2400 * @param folderId use -1 for the default folder
John Reckd3e4d5b2011-07-13 15:48:43 -07002401 * @param editExisting If true, check to see whether the site is already
Leon Scrogginsbdff8a72011-02-11 15:49:04 -05002402 * bookmarked, and if it is, edit that bookmark. If false, and
2403 * the site is already bookmarked, do not attempt to edit the
2404 * existing bookmark.
Michael Kolb8233fac2010-10-26 16:08:53 -07002405 */
2406 @Override
John Reckd3e4d5b2011-07-13 15:48:43 -07002407 public Intent createBookmarkCurrentPageIntent(boolean editExisting) {
John Recka60fffa2011-09-06 16:30:29 -07002408 WebView w = getCurrentTopWebView();
2409 if (w == null) {
2410 return null;
2411 }
Michael Kolb8233fac2010-10-26 16:08:53 -07002412 Intent i = new Intent(mActivity,
2413 AddBookmarkPage.class);
Michael Kolb8233fac2010-10-26 16:08:53 -07002414 i.putExtra(BrowserContract.Bookmarks.URL, w.getUrl());
2415 i.putExtra(BrowserContract.Bookmarks.TITLE, w.getTitle());
2416 String touchIconUrl = w.getTouchIconUrl();
2417 if (touchIconUrl != null) {
2418 i.putExtra(AddBookmarkPage.TOUCH_ICON_URL, touchIconUrl);
2419 WebSettings settings = w.getSettings();
2420 if (settings != null) {
2421 i.putExtra(AddBookmarkPage.USER_AGENT,
2422 settings.getUserAgentString());
2423 }
2424 }
2425 i.putExtra(BrowserContract.Bookmarks.THUMBNAIL,
2426 createScreenshot(w, getDesiredThumbnailWidth(mActivity),
2427 getDesiredThumbnailHeight(mActivity)));
2428 i.putExtra(BrowserContract.Bookmarks.FAVICON, w.getFavicon());
John Reckd3e4d5b2011-07-13 15:48:43 -07002429 if (editExisting) {
Leon Scrogginsbdff8a72011-02-11 15:49:04 -05002430 i.putExtra(AddBookmarkPage.CHECK_FOR_DUPE, true);
2431 }
Michael Kolb8233fac2010-10-26 16:08:53 -07002432 // Put the dialog at the upper right of the screen, covering the
2433 // star on the title bar.
2434 i.putExtra("gravity", Gravity.RIGHT | Gravity.TOP);
John Reckd3e4d5b2011-07-13 15:48:43 -07002435 return i;
Michael Kolb8233fac2010-10-26 16:08:53 -07002436 }
2437
2438 // file chooser
John Reck9c35b9c2012-05-30 10:08:50 -07002439 @Override
Ben Murdoch8cad4132012-01-11 10:56:43 +00002440 public void openFileChooser(ValueCallback<Uri> uploadMsg, String acceptType, String capture) {
Michael Kolb8233fac2010-10-26 16:08:53 -07002441 mUploadHandler = new UploadHandler(this);
Ben Murdoch8cad4132012-01-11 10:56:43 +00002442 mUploadHandler.openFileChooser(uploadMsg, acceptType, capture);
Michael Kolb8233fac2010-10-26 16:08:53 -07002443 }
2444
2445 // thumbnails
2446
2447 /**
2448 * Return the desired width for thumbnail screenshots, which are stored in
2449 * the database, and used on the bookmarks screen.
2450 * @param context Context for finding out the density of the screen.
2451 * @return desired width for thumbnail screenshot.
2452 */
2453 static int getDesiredThumbnailWidth(Context context) {
2454 return context.getResources().getDimensionPixelOffset(
2455 R.dimen.bookmarkThumbnailWidth);
2456 }
2457
2458 /**
2459 * Return the desired height for thumbnail screenshots, which are stored in
2460 * the database, and used on the bookmarks screen.
2461 * @param context Context for finding out the density of the screen.
2462 * @return desired height for thumbnail screenshot.
2463 */
2464 static int getDesiredThumbnailHeight(Context context) {
2465 return context.getResources().getDimensionPixelOffset(
2466 R.dimen.bookmarkThumbnailHeight);
2467 }
2468
John Reck8cc92352011-07-06 17:41:52 -07002469 static Bitmap createScreenshot(WebView view, int width, int height) {
Bijan Amirzada9b1e9882014-02-26 17:15:46 -08002470 if (view == null || width == 0 || height == 0) {
John Reckd7dd9b22011-08-30 09:18:29 -07002471 return null;
2472 }
Bijan Amirzada9b1e9882014-02-26 17:15:46 -08002473
2474 Bitmap viewportBitmap = view.getViewportBitmap();
2475 if (viewportBitmap == null) {
2476 return null;
2477 }
2478
2479 float aspectRatio = (float) width/height;
2480 int viewportWidth = viewportBitmap.getWidth();
2481 int viewportHeight = viewportBitmap.getHeight();
2482
2483 //modify the size to attain the same aspect ratio of desired thumbnail size
2484 if (viewportHeight > viewportWidth) {
2485 viewportHeight= (int)Math.round(viewportWidth * aspectRatio);
2486 } else {
2487 viewportWidth = (int)Math.round(viewportHeight * aspectRatio);
2488 }
2489
2490 Rect srcRect = new Rect(0, 0, viewportWidth, viewportHeight);
2491 Rect dstRect = new Rect(0, 0, width, height);
2492
2493 if (sThumbnailBitmap == null || sThumbnailBitmap.getWidth() != width
2494 || sThumbnailBitmap.getHeight() != height) {
John Reckd7dd9b22011-08-30 09:18:29 -07002495 if (sThumbnailBitmap != null) {
2496 sThumbnailBitmap.recycle();
2497 sThumbnailBitmap = null;
2498 }
Bijan Amirzada9b1e9882014-02-26 17:15:46 -08002499
2500 sThumbnailBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565);
Michael Kolb8233fac2010-10-26 16:08:53 -07002501 }
Bijan Amirzada9b1e9882014-02-26 17:15:46 -08002502
John Reckd7dd9b22011-08-30 09:18:29 -07002503 Canvas canvas = new Canvas(sThumbnailBitmap);
Bijan Amirzada9b1e9882014-02-26 17:15:46 -08002504 canvas.drawBitmap(viewportBitmap, srcRect, dstRect, new Paint(Paint.FILTER_BITMAP_FLAG));
John Reckd7dd9b22011-08-30 09:18:29 -07002505
Bijan Amirzada9b1e9882014-02-26 17:15:46 -08002506 return sThumbnailBitmap;
Michael Kolb8233fac2010-10-26 16:08:53 -07002507 }
2508
John Reck34ef2672011-02-10 11:30:55 -08002509 private void updateScreenshot(Tab tab) {
Michael Kolb8233fac2010-10-26 16:08:53 -07002510 // If this is a bookmarked site, add a screenshot to the database.
Michael Kolb8233fac2010-10-26 16:08:53 -07002511 // FIXME: Would like to make sure there is actually something to
2512 // draw, but the API for that (WebViewCore.pictureReady()) is not
2513 // currently accessible here.
2514
John Reck34ef2672011-02-10 11:30:55 -08002515 WebView view = tab.getWebView();
John Reck7a591202011-02-16 15:44:01 -08002516 if (view == null) {
2517 // Tab was destroyed
2518 return;
2519 }
John Reck34ef2672011-02-10 11:30:55 -08002520 final String url = tab.getUrl();
2521 final String originalUrl = view.getOriginalUrl();
kaiyiz6e5b3e02013-08-19 20:02:01 +08002522 final String thumbnailUrl = mUpdateMyNavThumbnailUrl;
John Reck34ef2672011-02-10 11:30:55 -08002523 if (TextUtils.isEmpty(url)) {
2524 return;
2525 }
2526
kaiyiz6e5b3e02013-08-19 20:02:01 +08002527 //update My Navigation Thumbnails
2528 boolean isMyNavigationUrl = MyNavigationUtil.isMyNavigationUrl(mActivity, url);
2529 if (isMyNavigationUrl) {
2530 updateMyNavigationThumbnail(url, view);
2531 }
John Reck34ef2672011-02-10 11:30:55 -08002532 // Only update thumbnails for web urls (http(s)://), not for
2533 // about:, javascript:, data:, etc...
2534 // Unless it is a bookmarked site, then always update
2535 if (!Patterns.WEB_URL.matcher(url).matches() && !tab.isBookmarkedSite()) {
2536 return;
2537 }
2538
kaiyiz6e5b3e02013-08-19 20:02:01 +08002539 if (url != null && mUpdateMyNavThumbnailUrl != null
2540 && Patterns.WEB_URL.matcher(url).matches()
2541 && Patterns.WEB_URL.matcher(mUpdateMyNavThumbnailUrl).matches()) {
2542 String urlHost = (new WebAddress(url)).getHost();
2543 String bookmarkHost = (new WebAddress(mUpdateMyNavThumbnailUrl)).getHost();
2544 if (urlHost == null || urlHost.length() == 0 || bookmarkHost == null
2545 || bookmarkHost.length() == 0) {
2546 return;
2547 }
2548 String urlDomain = urlHost.substring(urlHost.indexOf('.'), urlHost.length());
2549 String bookmarkDomain = bookmarkHost.substring(bookmarkHost.indexOf('.'),
2550 bookmarkHost.length());
2551 Log.d(LOGTAG, "addressUrl domain is " + urlDomain);
2552 Log.d(LOGTAG, "bookmarkUrl domain is " + bookmarkDomain);
2553 if (!bookmarkDomain.equals(urlDomain)) {
2554 return;
2555 }
2556 }
Michael Kolb8233fac2010-10-26 16:08:53 -07002557 final Bitmap bm = createScreenshot(view, getDesiredThumbnailWidth(mActivity),
2558 getDesiredThumbnailHeight(mActivity));
2559 if (bm == null) {
Bijan Amirzada9b1e9882014-02-26 17:15:46 -08002560 if (!mHandler.hasMessages(UPDATE_BOOKMARK_THUMBNAIL, tab)) {
2561 mHandler.sendMessageDelayed(mHandler.obtainMessage(
2562 UPDATE_BOOKMARK_THUMBNAIL, 0, 0, tab),
2563 500);
2564 }
Michael Kolb8233fac2010-10-26 16:08:53 -07002565 return;
2566 }
2567
2568 final ContentResolver cr = mActivity.getContentResolver();
John Reck34ef2672011-02-10 11:30:55 -08002569 new AsyncTask<Void, Void, Void>() {
2570 @Override
2571 protected Void doInBackground(Void... unused) {
2572 Cursor cursor = null;
2573 try {
2574 // TODO: Clean this up
kaiyiz6e5b3e02013-08-19 20:02:01 +08002575 cursor = Bookmarks.queryCombinedForUrl(cr, originalUrl,
2576 mUpdateMyNavThumbnail ? ((thumbnailUrl != null) ? thumbnailUrl : url)
2577 : url);
2578 if (mUpdateMyNavThumbnail) {
2579 mUpdateMyNavThumbnail = false;
2580 mUpdateMyNavThumbnailUrl = null;
2581 }
John Reck34ef2672011-02-10 11:30:55 -08002582 if (cursor != null && cursor.moveToFirst()) {
2583 final ByteArrayOutputStream os =
2584 new ByteArrayOutputStream();
2585 bm.compress(Bitmap.CompressFormat.PNG, 100, os);
Michael Kolb8233fac2010-10-26 16:08:53 -07002586
John Reck34ef2672011-02-10 11:30:55 -08002587 ContentValues values = new ContentValues();
2588 values.put(Images.THUMBNAIL, os.toByteArray());
Michael Kolb8233fac2010-10-26 16:08:53 -07002589
John Reck34ef2672011-02-10 11:30:55 -08002590 do {
John Reck617fd832011-02-16 14:35:59 -08002591 values.put(Images.URL, cursor.getString(0));
John Reck34ef2672011-02-10 11:30:55 -08002592 cr.update(Images.CONTENT_URI, values, null, null);
2593 } while (cursor.moveToNext());
Michael Kolb8233fac2010-10-26 16:08:53 -07002594 }
John Reck34ef2672011-02-10 11:30:55 -08002595 } catch (IllegalStateException e) {
2596 // Ignore
Mattias Nilsson561d1952011-10-04 10:18:50 +02002597 } catch (SQLiteException s) {
2598 // Added for possible error when user tries to remove the same bookmark
2599 // that is being updated with a screen shot
2600 Log.w(LOGTAG, "Error when running updateScreenshot ", s);
John Reck34ef2672011-02-10 11:30:55 -08002601 } finally {
2602 if (cursor != null) cursor.close();
Michael Kolb8233fac2010-10-26 16:08:53 -07002603 }
John Reck34ef2672011-02-10 11:30:55 -08002604 return null;
2605 }
2606 }.execute();
Michael Kolb8233fac2010-10-26 16:08:53 -07002607 }
2608
2609 private class Copy implements OnMenuItemClickListener {
2610 private CharSequence mText;
2611
John Reck9c35b9c2012-05-30 10:08:50 -07002612 @Override
Michael Kolb8233fac2010-10-26 16:08:53 -07002613 public boolean onMenuItemClick(MenuItem item) {
2614 copy(mText);
2615 return true;
2616 }
2617
2618 public Copy(CharSequence toCopy) {
2619 mText = toCopy;
2620 }
2621 }
2622
Leon Scroggins63c02662010-11-18 15:16:27 -05002623 private static class Download implements OnMenuItemClickListener {
2624 private Activity mActivity;
Michael Kolb8233fac2010-10-26 16:08:53 -07002625 private String mText;
Kristian Monsenbc5cc752011-03-02 13:14:03 +00002626 private boolean mPrivateBrowsing;
Andreas Sandblad8e4ce662012-06-11 11:02:49 +02002627 private String mUserAgent;
George Mount387d45d2011-10-07 15:57:53 -07002628 private static final String FALLBACK_EXTENSION = "dat";
2629 private static final String IMAGE_BASE_FORMAT = "yyyy-MM-dd-HH-mm-ss-";
Michael Kolb8233fac2010-10-26 16:08:53 -07002630
John Reck9c35b9c2012-05-30 10:08:50 -07002631 @Override
Michael Kolb8233fac2010-10-26 16:08:53 -07002632 public boolean onMenuItemClick(MenuItem item) {
George Mount387d45d2011-10-07 15:57:53 -07002633 if (DataUri.isDataUri(mText)) {
2634 saveDataUri();
2635 } else {
Andreas Sandblad8e4ce662012-06-11 11:02:49 +02002636 DownloadHandler.onDownloadStartNoStream(mActivity, mText, mUserAgent,
luxiaol62677b02013-07-22 07:54:49 +08002637 null, null, null, mPrivateBrowsing, 0);
George Mount387d45d2011-10-07 15:57:53 -07002638 }
Michael Kolb8233fac2010-10-26 16:08:53 -07002639 return true;
2640 }
2641
Andreas Sandblad8e4ce662012-06-11 11:02:49 +02002642 public Download(Activity activity, String toDownload, boolean privateBrowsing,
2643 String userAgent) {
Leon Scroggins63c02662010-11-18 15:16:27 -05002644 mActivity = activity;
Michael Kolb8233fac2010-10-26 16:08:53 -07002645 mText = toDownload;
Kristian Monsenbc5cc752011-03-02 13:14:03 +00002646 mPrivateBrowsing = privateBrowsing;
Andreas Sandblad8e4ce662012-06-11 11:02:49 +02002647 mUserAgent = userAgent;
Michael Kolb8233fac2010-10-26 16:08:53 -07002648 }
George Mount387d45d2011-10-07 15:57:53 -07002649
2650 /**
2651 * Treats mText as a data URI and writes its contents to a file
2652 * based on the current time.
2653 */
2654 private void saveDataUri() {
2655 FileOutputStream outputStream = null;
2656 try {
2657 DataUri uri = new DataUri(mText);
2658 File target = getTarget(uri);
2659 outputStream = new FileOutputStream(target);
2660 outputStream.write(uri.getData());
2661 final DownloadManager manager =
2662 (DownloadManager) mActivity.getSystemService(Context.DOWNLOAD_SERVICE);
2663 manager.addCompletedDownload(target.getName(),
2664 mActivity.getTitle().toString(), false,
2665 uri.getMimeType(), target.getAbsolutePath(),
John Reck9c35b9c2012-05-30 10:08:50 -07002666 uri.getData().length, true);
George Mount387d45d2011-10-07 15:57:53 -07002667 } catch (IOException e) {
2668 Log.e(LOGTAG, "Could not save data URL");
2669 } finally {
2670 if (outputStream != null) {
2671 try {
2672 outputStream.close();
2673 } catch (IOException e) {
2674 // ignore close errors
2675 }
2676 }
2677 }
2678 }
2679
2680 /**
2681 * Creates a File based on the current time stamp and uses
2682 * the mime type of the DataUri to get the extension.
2683 */
2684 private File getTarget(DataUri uri) throws IOException {
2685 File dir = mActivity.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS);
Johan Redestigaa676182012-10-03 13:33:01 +02002686 DateFormat format = new SimpleDateFormat(IMAGE_BASE_FORMAT, Locale.US);
George Mount387d45d2011-10-07 15:57:53 -07002687 String nameBase = format.format(new Date());
2688 String mimeType = uri.getMimeType();
2689 MimeTypeMap mimeTypeMap = MimeTypeMap.getSingleton();
2690 String extension = mimeTypeMap.getExtensionFromMimeType(mimeType);
2691 if (extension == null) {
2692 Log.w(LOGTAG, "Unknown mime type in data URI" + mimeType);
2693 extension = FALLBACK_EXTENSION;
2694 }
2695 extension = "." + extension; // createTempFile needs the '.'
2696 File targetFile = File.createTempFile(nameBase, extension, dir);
2697 return targetFile;
2698 }
Michael Kolb8233fac2010-10-26 16:08:53 -07002699 }
2700
Cary Clark8974d282010-11-22 10:46:05 -05002701 private static class SelectText implements OnMenuItemClickListener {
Bijan Amirzada9b1e9882014-02-26 17:15:46 -08002702 private WebView mWebView;
Cary Clark8974d282010-11-22 10:46:05 -05002703
John Reck9c35b9c2012-05-30 10:08:50 -07002704 @Override
Cary Clark8974d282010-11-22 10:46:05 -05002705 public boolean onMenuItemClick(MenuItem item) {
2706 if (mWebView != null) {
2707 return mWebView.selectText();
2708 }
2709 return false;
2710 }
2711
2712 public SelectText(WebView webView) {
Bijan Amirzada9b1e9882014-02-26 17:15:46 -08002713 mWebView = webView;
Cary Clark8974d282010-11-22 10:46:05 -05002714 }
2715
2716 }
2717
Michael Kolb8233fac2010-10-26 16:08:53 -07002718 /********************** TODO: UI stuff *****************************/
2719
2720 // these methods have been copied, they still need to be cleaned up
2721
2722 /****************** tabs ***************************************************/
2723
2724 // basic tab interactions:
2725
2726 // it is assumed that tabcontrol already knows about the tab
2727 protected void addTab(Tab tab) {
2728 mUi.addTab(tab);
2729 }
2730
2731 protected void removeTab(Tab tab) {
2732 mUi.removeTab(tab);
2733 mTabControl.removeTab(tab);
John Reck378a4102011-06-09 16:23:01 -07002734 mCrashRecoveryHandler.backupState();
Michael Kolb8233fac2010-10-26 16:08:53 -07002735 }
2736
Michael Kolbf2055602011-04-09 17:20:03 -07002737 @Override
2738 public void setActiveTab(Tab tab) {
Michael Kolbcd424e92011-02-24 10:26:26 -08002739 // monkey protection against delayed start
2740 if (tab != null) {
2741 mTabControl.setCurrentTab(tab);
2742 // the tab is guaranteed to have a webview after setCurrentTab
2743 mUi.setActiveTab(tab);
Bijan Amirzada9b1e9882014-02-26 17:15:46 -08002744 tab.setTimeStamp();
Michael Kolbcd424e92011-02-24 10:26:26 -08002745 }
Michael Kolb8233fac2010-10-26 16:08:53 -07002746 }
2747
John Reck8bcafc12011-08-29 16:43:02 -07002748 protected void closeEmptyTab() {
Michael Kolb8233fac2010-10-26 16:08:53 -07002749 Tab current = mTabControl.getCurrentTab();
2750 if (current != null
2751 && current.getWebView().copyBackForwardList().getSize() == 0) {
John Reck8bcafc12011-08-29 16:43:02 -07002752 closeCurrentTab();
Michael Kolb8233fac2010-10-26 16:08:53 -07002753 }
2754 }
2755
John Reck26b18322011-06-21 13:08:58 -07002756 protected void reuseTab(Tab appTab, UrlData urlData) {
Michael Kolb8233fac2010-10-26 16:08:53 -07002757 // Dismiss the subwindow if applicable.
2758 dismissSubWindow(appTab);
2759 // Since we might kill the WebView, remove it from the
2760 // content view first.
2761 mUi.detachTab(appTab);
2762 // Recreate the main WebView after destroying the old one.
John Reck30c714c2010-12-16 17:30:34 -08002763 mTabControl.recreateWebView(appTab);
Michael Kolb8233fac2010-10-26 16:08:53 -07002764 // TODO: analyze why the remove and add are necessary
2765 mUi.attachTab(appTab);
2766 if (mTabControl.getCurrentTab() != appTab) {
Michael Kolbc831b632011-05-11 09:30:34 -07002767 switchToTab(appTab);
John Reck30c714c2010-12-16 17:30:34 -08002768 loadUrlDataIn(appTab, urlData);
Michael Kolb8233fac2010-10-26 16:08:53 -07002769 } else {
2770 // If the tab was the current tab, we have to attach
2771 // it to the view system again.
2772 setActiveTab(appTab);
John Reck30c714c2010-12-16 17:30:34 -08002773 loadUrlDataIn(appTab, urlData);
Michael Kolb8233fac2010-10-26 16:08:53 -07002774 }
2775 }
2776
2777 // Remove the sub window if it exists. Also called by TabControl when the
2778 // user clicks the 'X' to dismiss a sub window.
John Reck9c35b9c2012-05-30 10:08:50 -07002779 @Override
Michael Kolb8233fac2010-10-26 16:08:53 -07002780 public void dismissSubWindow(Tab tab) {
2781 removeSubWindow(tab);
2782 // dismiss the subwindow. This will destroy the WebView.
2783 tab.dismissSubWindow();
Michael Kolbe8c97572011-11-21 14:03:56 -08002784 WebView wv = getCurrentTopWebView();
2785 if (wv != null) {
2786 wv.requestFocus();
2787 }
Michael Kolb8233fac2010-10-26 16:08:53 -07002788 }
2789
2790 @Override
2791 public void removeSubWindow(Tab t) {
2792 if (t.getSubWebView() != null) {
2793 mUi.removeSubWindow(t.getSubViewContainer());
2794 }
2795 }
2796
2797 @Override
2798 public void attachSubWindow(Tab tab) {
2799 if (tab.getSubWebView() != null) {
2800 mUi.attachSubWindow(tab.getSubViewContainer());
2801 getCurrentTopWebView().requestFocus();
2802 }
2803 }
2804
Mathew Inwood29721c22011-06-29 17:55:24 +01002805 private Tab showPreloadedTab(final UrlData urlData) {
2806 if (!urlData.isPreloaded()) {
2807 return null;
2808 }
2809 final PreloadedTabControl tabControl = urlData.getPreloadedTab();
2810 final String sbQuery = urlData.getSearchBoxQueryToSubmit();
2811 if (sbQuery != null) {
Mathew Inwood9ad1eac2011-09-15 11:29:50 +01002812 if (!tabControl.searchBoxSubmit(sbQuery, urlData.mUrl, urlData.mHeaders)) {
Mathew Inwood29721c22011-06-29 17:55:24 +01002813 // Could not submit query. Fallback to regular tab creation
2814 tabControl.destroy();
2815 return null;
2816 }
2817 }
Michael Kolbff6a7482011-07-26 16:37:15 -07002818 // check tab count and make room for new tab
2819 if (!mTabControl.canCreateNewTab()) {
2820 Tab leastUsed = mTabControl.getLeastUsedTab(getCurrentTab());
2821 if (leastUsed != null) {
2822 closeTab(leastUsed);
2823 }
2824 }
Mathew Inwood29721c22011-06-29 17:55:24 +01002825 Tab t = tabControl.getTab();
Mathew Inwoode09305e2011-09-02 12:03:26 +01002826 t.refreshIdAfterPreload();
Mathew Inwood29721c22011-06-29 17:55:24 +01002827 mTabControl.addPreloadedTab(t);
2828 addTab(t);
2829 setActiveTab(t);
2830 return t;
2831 }
2832
Michael Kolb7bcafde2011-05-09 13:55:59 -07002833 // open a non inconito tab with the given url data
2834 // and set as active tab
2835 public Tab openTab(UrlData urlData) {
Mathew Inwood29721c22011-06-29 17:55:24 +01002836 Tab tab = showPreloadedTab(urlData);
2837 if (tab == null) {
2838 tab = createNewTab(false, true, true);
Michael Kolb14612442011-06-24 13:06:29 -07002839 if ((tab != null) && !urlData.isEmpty()) {
2840 loadUrlDataIn(tab, urlData);
2841 }
Michael Kolb7bcafde2011-05-09 13:55:59 -07002842 }
Mathew Inwood29721c22011-06-29 17:55:24 +01002843 return tab;
Michael Kolb7bcafde2011-05-09 13:55:59 -07002844 }
2845
Michael Kolb843510f2010-12-09 10:51:49 -08002846 @Override
2847 public Tab openTabToHomePage() {
Michael Kolb7bcafde2011-05-09 13:55:59 -07002848 return openTab(mSettings.getHomePage(), false, true, false);
Michael Kolb8233fac2010-10-26 16:08:53 -07002849 }
2850
Michael Kolb8233fac2010-10-26 16:08:53 -07002851 @Override
Michael Kolb519d2282011-05-09 17:03:19 -07002852 public Tab openIncognitoTab() {
2853 return openTab(INCOGNITO_URI, true, true, false);
2854 }
2855
2856 @Override
Michael Kolb7bcafde2011-05-09 13:55:59 -07002857 public Tab openTab(String url, boolean incognito, boolean setActive,
2858 boolean useCurrent) {
John Reck5949c662011-05-27 09:52:29 -07002859 return openTab(url, incognito, setActive, useCurrent, null);
2860 }
2861
2862 @Override
2863 public Tab openTab(String url, Tab parent, boolean setActive,
2864 boolean useCurrent) {
2865 return openTab(url, (parent != null) && parent.isPrivateBrowsingEnabled(),
2866 setActive, useCurrent, parent);
2867 }
2868
2869 public Tab openTab(String url, boolean incognito, boolean setActive,
2870 boolean useCurrent, Tab parent) {
Michael Kolb7bcafde2011-05-09 13:55:59 -07002871 Tab tab = createNewTab(incognito, setActive, useCurrent);
2872 if (tab != null) {
John Reck5949c662011-05-27 09:52:29 -07002873 if (parent != null && parent != tab) {
2874 parent.addChildTab(tab);
2875 }
Michael Kolb519d2282011-05-09 17:03:19 -07002876 if (url != null) {
John Reck26b18322011-06-21 13:08:58 -07002877 loadUrl(tab, url);
Michael Kolb519d2282011-05-09 17:03:19 -07002878 }
Michael Kolb8233fac2010-10-26 16:08:53 -07002879 }
Michael Kolb7bcafde2011-05-09 13:55:59 -07002880 return tab;
2881 }
2882
2883 // this method will attempt to create a new tab
2884 // incognito: private browsing tab
2885 // setActive: ste tab as current tab
2886 // useCurrent: if no new tab can be created, return current tab
2887 private Tab createNewTab(boolean incognito, boolean setActive,
2888 boolean useCurrent) {
2889 Tab tab = null;
Bijan Amirzada9b1e9882014-02-26 17:15:46 -08002890 MemoryMonitor memMonitor = null;
Michael Kolb7bcafde2011-05-09 13:55:59 -07002891 if (mTabControl.canCreateNewTab()) {
Bijan Amirzada9b1e9882014-02-26 17:15:46 -08002892 if (mSettings.enableMemoryMonitor()) {
2893 Log.d(LOGTAG, " Memory Monitor Enabled .");
2894 memMonitor = MemoryMonitor.getInstance(mActivity.getApplicationContext(),this);
2895 if (memMonitor != null) {
2896 //Remove webview associated with the oldest tab
2897 memMonitor.destroyLeastRecentlyActiveTab();
2898 }
2899 } else {
2900 Log.d(LOGTAG, " Memory Monitor disabled .");
2901 }
Michael Kolb7bcafde2011-05-09 13:55:59 -07002902 tab = mTabControl.createNewTab(incognito);
2903 addTab(tab);
Bijan Amirzada9b1e9882014-02-26 17:15:46 -08002904 tab.setTimeStamp();
Michael Kolb7bcafde2011-05-09 13:55:59 -07002905 if (setActive) {
2906 setActiveTab(tab);
2907 }
2908 } else {
2909 if (useCurrent) {
2910 tab = mTabControl.getCurrentTab();
John Reck26b18322011-06-21 13:08:58 -07002911 reuseTab(tab, null);
Michael Kolb7bcafde2011-05-09 13:55:59 -07002912 } else {
2913 mUi.showMaxTabsWarning();
2914 }
2915 }
2916 return tab;
Michael Kolb8233fac2010-10-26 16:08:53 -07002917 }
2918
John Reck2bc80422011-06-30 15:11:49 -07002919 @Override
2920 public SnapshotTab createNewSnapshotTab(long snapshotId, boolean setActive) {
2921 SnapshotTab tab = null;
2922 if (mTabControl.canCreateNewTab()) {
2923 tab = mTabControl.createSnapshotTab(snapshotId);
2924 addTab(tab);
2925 if (setActive) {
2926 setActiveTab(tab);
2927 }
2928 } else {
2929 mUi.showMaxTabsWarning();
John Reckd8c74522011-06-14 08:45:00 -07002930 }
2931 return tab;
2932 }
2933
Michael Kolb8233fac2010-10-26 16:08:53 -07002934 /**
Michael Kolbc831b632011-05-11 09:30:34 -07002935 * @param tab the tab to switch to
Michael Kolb8233fac2010-10-26 16:08:53 -07002936 * @return boolean True if we successfully switched to a different tab. If
2937 * the indexth tab is null, or if that tab is the same as
2938 * the current one, return false.
2939 */
2940 @Override
Michael Kolbc831b632011-05-11 09:30:34 -07002941 public boolean switchToTab(Tab tab) {
Michael Kolb8233fac2010-10-26 16:08:53 -07002942 Tab currentTab = mTabControl.getCurrentTab();
2943 if (tab == null || tab == currentTab) {
2944 return false;
2945 }
2946 setActiveTab(tab);
2947 return true;
2948 }
2949
2950 @Override
Michael Kolb8233fac2010-10-26 16:08:53 -07002951 public void closeCurrentTab() {
Michael Kolb2ae6ef72011-08-22 14:49:34 -07002952 closeCurrentTab(false);
2953 }
2954
2955 protected void closeCurrentTab(boolean andQuit) {
Michael Kolb8233fac2010-10-26 16:08:53 -07002956 if (mTabControl.getTabCount() == 1) {
John Reckbc490d22011-07-22 15:04:59 -07002957 mCrashRecoveryHandler.clearState();
Michael Kolbc1eeb122011-08-01 09:56:26 -07002958 mTabControl.removeTab(getCurrentTab());
John Reck958b2422010-12-03 17:56:17 -08002959 mActivity.finish();
Michael Kolb8233fac2010-10-26 16:08:53 -07002960 return;
2961 }
Michael Kolbc831b632011-05-11 09:30:34 -07002962 final Tab current = mTabControl.getCurrentTab();
2963 final int pos = mTabControl.getCurrentPosition();
2964 Tab newTab = current.getParent();
2965 if (newTab == null) {
2966 newTab = mTabControl.getTab(pos + 1);
2967 if (newTab == null) {
2968 newTab = mTabControl.getTab(pos - 1);
Michael Kolb8233fac2010-10-26 16:08:53 -07002969 }
2970 }
Michael Kolb2ae6ef72011-08-22 14:49:34 -07002971 if (andQuit) {
2972 mTabControl.setCurrentTab(newTab);
2973 closeTab(current);
2974 } else if (switchToTab(newTab)) {
Michael Kolb8233fac2010-10-26 16:08:53 -07002975 // Close window
2976 closeTab(current);
2977 }
2978 }
2979
2980 /**
2981 * Close the tab, remove its associated title bar, and adjust mTabControl's
2982 * current tab to a valid value.
2983 */
2984 @Override
2985 public void closeTab(Tab tab) {
John Reck28263772011-10-11 17:13:42 -07002986 if (tab == mTabControl.getCurrentTab()) {
2987 closeCurrentTab();
2988 } else {
2989 removeTab(tab);
2990 }
Michael Kolb8233fac2010-10-26 16:08:53 -07002991 }
2992
Afzal Najamd4e33312012-04-26 01:54:01 -04002993 /**
2994 * Close all tabs except the current one
2995 */
2996 @Override
2997 public void closeOtherTabs() {
2998 int inactiveTabs = mTabControl.getTabCount() - 1;
2999 for (int i = inactiveTabs; i >= 0; i--) {
3000 Tab tab = mTabControl.getTab(i);
3001 if (tab != mTabControl.getCurrentTab()) {
3002 removeTab(tab);
3003 }
3004 }
3005 }
3006
Michael Kolb8233fac2010-10-26 16:08:53 -07003007 // Called when loading from context menu or LOAD_URL message
John Reck26b18322011-06-21 13:08:58 -07003008 protected void loadUrlFromContext(String url) {
3009 Tab tab = getCurrentTab();
3010 WebView view = tab != null ? tab.getWebView() : null;
Michael Kolb8233fac2010-10-26 16:08:53 -07003011 // In case the user enters nothing.
John Reck26b18322011-06-21 13:08:58 -07003012 if (url != null && url.length() != 0 && tab != null && view != null) {
Michael Kolb8233fac2010-10-26 16:08:53 -07003013 url = UrlUtils.smartUrlFilter(url);
Jonathan Dixone1d6dfc2012-12-17 13:39:17 -08003014 if (!((BrowserWebView) view).getWebViewClient().
Jonathan Dixon4d2fcab2012-02-24 00:13:06 +00003015 shouldOverrideUrlLoading(view, url)) {
John Reck26b18322011-06-21 13:08:58 -07003016 loadUrl(tab, url);
Michael Kolb8233fac2010-10-26 16:08:53 -07003017 }
3018 }
3019 }
3020
3021 /**
3022 * Load the URL into the given WebView and update the title bar
3023 * to reflect the new load. Call this instead of WebView.loadUrl
3024 * directly.
3025 * @param view The WebView used to load url.
3026 * @param url The URL to load.
3027 */
John Reck71e51422011-07-01 16:49:28 -07003028 @Override
3029 public void loadUrl(Tab tab, String url) {
John Reck26b18322011-06-21 13:08:58 -07003030 loadUrl(tab, url, null);
3031 }
3032
3033 protected void loadUrl(Tab tab, String url, Map<String, String> headers) {
3034 if (tab != null) {
3035 dismissSubWindow(tab);
3036 tab.loadUrl(url, headers);
Bijan Amirzada9b1e9882014-02-26 17:15:46 -08003037 if (tab.hasCrashed) {
3038 tab.replaceCrashView(tab.getWebView(), tab.getViewContainer());
3039 }
Michael Kolba53c9892011-10-05 13:31:40 -07003040 mUi.onProgressChanged(tab);
John Reck26b18322011-06-21 13:08:58 -07003041 }
Michael Kolb8233fac2010-10-26 16:08:53 -07003042 }
3043
3044 /**
3045 * Load UrlData into a Tab and update the title bar to reflect the new
3046 * load. Call this instead of UrlData.loadIn directly.
3047 * @param t The Tab used to load.
3048 * @param data The UrlData being loaded.
3049 */
3050 protected void loadUrlDataIn(Tab t, UrlData data) {
John Reck26b18322011-06-21 13:08:58 -07003051 if (data != null) {
Michael Kolb5ff5c8b2012-05-03 11:37:58 -07003052 if (data.isPreloaded()) {
Michael Kolb14612442011-06-24 13:06:29 -07003053 // this isn't called for preloaded tabs
John Reck26b18322011-06-21 13:08:58 -07003054 } else {
John Reck38b39652012-06-05 09:22:59 -07003055 if (t != null && data.mDisableUrlOverride) {
3056 t.disableUrlOverridingForLoad();
3057 }
John Reck26b18322011-06-21 13:08:58 -07003058 loadUrl(t, data.mUrl, data.mHeaders);
3059 }
3060 }
Michael Kolb8233fac2010-10-26 16:08:53 -07003061 }
3062
John Reck30c714c2010-12-16 17:30:34 -08003063 @Override
3064 public void onUserCanceledSsl(Tab tab) {
John Reck30c714c2010-12-16 17:30:34 -08003065 // TODO: Figure out the "right" behavior
John Reckef654f12011-07-12 16:42:08 -07003066 if (tab.canGoBack()) {
3067 tab.goBack();
John Reck30c714c2010-12-16 17:30:34 -08003068 } else {
John Reckef654f12011-07-12 16:42:08 -07003069 tab.loadUrl(mSettings.getHomePage(), null);
John Reck30c714c2010-12-16 17:30:34 -08003070 }
Michael Kolb8233fac2010-10-26 16:08:53 -07003071 }
3072
3073 void goBackOnePageOrQuit() {
3074 Tab current = mTabControl.getCurrentTab();
3075 if (current == null) {
3076 /*
3077 * Instead of finishing the activity, simply push this to the back
3078 * of the stack and let ActivityManager to choose the foreground
3079 * activity. As BrowserActivity is singleTask, it will be always the
3080 * root of the task. So we can use either true or false for
3081 * moveTaskToBack().
3082 */
luxiaolb40014b2013-07-19 10:01:43 +08003083 showExitDialog(mActivity);
Michael Kolb8233fac2010-10-26 16:08:53 -07003084 return;
3085 }
John Reckef654f12011-07-12 16:42:08 -07003086 if (current.canGoBack()) {
3087 current.goBack();
Michael Kolb8233fac2010-10-26 16:08:53 -07003088 } else {
3089 // Check to see if we are closing a window that was created by
3090 // another window. If so, we switch back to that window.
Michael Kolbc831b632011-05-11 09:30:34 -07003091 Tab parent = current.getParent();
Michael Kolb8233fac2010-10-26 16:08:53 -07003092 if (parent != null) {
Michael Kolbc831b632011-05-11 09:30:34 -07003093 switchToTab(parent);
Michael Kolb8233fac2010-10-26 16:08:53 -07003094 // Now we close the other tab
3095 closeTab(current);
3096 } else {
Michael Kolb8233fac2010-10-26 16:08:53 -07003097 /*
3098 * Instead of finishing the activity, simply push this to the back
3099 * of the stack and let ActivityManager to choose the foreground
3100 * activity. As BrowserActivity is singleTask, it will be always the
3101 * root of the task. So we can use either true or false for
3102 * moveTaskToBack().
3103 */
luxiaolb40014b2013-07-19 10:01:43 +08003104 showExitDialog(mActivity);
Michael Kolb8233fac2010-10-26 16:08:53 -07003105 }
3106 }
3107 }
3108
3109 /**
Michael Kolb0035fad2011-03-14 13:25:28 -07003110 * helper method for key handler
3111 * returns the current tab if it can't advance
3112 */
Michael Kolbc831b632011-05-11 09:30:34 -07003113 private Tab getNextTab() {
Michael Kolbf5261da2011-12-15 15:07:35 -08003114 int pos = mTabControl.getCurrentPosition() + 1;
3115 if (pos >= mTabControl.getTabCount()) {
3116 pos = 0;
3117 }
3118 return mTabControl.getTab(pos);
Michael Kolb0035fad2011-03-14 13:25:28 -07003119 }
3120
3121 /**
3122 * helper method for key handler
3123 * returns the current tab if it can't advance
3124 */
Michael Kolbc831b632011-05-11 09:30:34 -07003125 private Tab getPrevTab() {
Michael Kolbf5261da2011-12-15 15:07:35 -08003126 int pos = mTabControl.getCurrentPosition() - 1;
3127 if ( pos < 0) {
3128 pos = mTabControl.getTabCount() - 1;
3129 }
3130 return mTabControl.getTab(pos);
Michael Kolb0035fad2011-03-14 13:25:28 -07003131 }
3132
John Reckbcef87f2012-02-03 14:58:34 -08003133 boolean isMenuOrCtrlKey(int keyCode) {
3134 return (KeyEvent.KEYCODE_MENU == keyCode)
3135 || (KeyEvent.KEYCODE_CTRL_LEFT == keyCode)
3136 || (KeyEvent.KEYCODE_CTRL_RIGHT == keyCode);
3137 }
3138
Michael Kolb0035fad2011-03-14 13:25:28 -07003139 /**
Michael Kolb8233fac2010-10-26 16:08:53 -07003140 * handle key events in browser
3141 *
3142 * @param keyCode
3143 * @param event
3144 * @return true if handled, false to pass to super
3145 */
John Reck9c35b9c2012-05-30 10:08:50 -07003146 @Override
3147 public boolean onKeyDown(int keyCode, KeyEvent event) {
Cary Clark160bbb92011-01-10 11:17:07 -05003148 boolean noModifiers = event.hasNoModifiers();
Michael Kolb8233fac2010-10-26 16:08:53 -07003149 // Even if MENU is already held down, we need to call to super to open
3150 // the IME on long press.
John Reckbcef87f2012-02-03 14:58:34 -08003151 if (!noModifiers && isMenuOrCtrlKey(keyCode)) {
Michael Kolb8233fac2010-10-26 16:08:53 -07003152 mMenuIsDown = true;
3153 return false;
3154 }
Michael Kolb8233fac2010-10-26 16:08:53 -07003155
Cary Clark8ff8c662010-12-29 15:03:05 -05003156 WebView webView = getCurrentTopWebView();
John Reckef654f12011-07-12 16:42:08 -07003157 Tab tab = getCurrentTab();
3158 if (webView == null || tab == null) return false;
Cary Clark8ff8c662010-12-29 15:03:05 -05003159
Cary Clark160bbb92011-01-10 11:17:07 -05003160 boolean ctrl = event.hasModifiers(KeyEvent.META_CTRL_ON);
3161 boolean shift = event.hasModifiers(KeyEvent.META_SHIFT_ON);
Cary Clark8ff8c662010-12-29 15:03:05 -05003162
Michael Kolb8233fac2010-10-26 16:08:53 -07003163 switch(keyCode) {
Michael Kolb0035fad2011-03-14 13:25:28 -07003164 case KeyEvent.KEYCODE_TAB:
3165 if (event.isCtrlPressed()) {
3166 if (event.isShiftPressed()) {
3167 // prev tab
Michael Kolbc831b632011-05-11 09:30:34 -07003168 switchToTab(getPrevTab());
Michael Kolb0035fad2011-03-14 13:25:28 -07003169 } else {
3170 // next tab
Michael Kolbc831b632011-05-11 09:30:34 -07003171 switchToTab(getNextTab());
Michael Kolb0035fad2011-03-14 13:25:28 -07003172 }
3173 return true;
3174 }
3175 break;
Michael Kolb8233fac2010-10-26 16:08:53 -07003176 case KeyEvent.KEYCODE_SPACE:
3177 // WebView/WebTextView handle the keys in the KeyDown. As
3178 // the Activity's shortcut keys are only handled when WebView
3179 // doesn't, have to do it in onKeyDown instead of onKeyUp.
Cary Clark160bbb92011-01-10 11:17:07 -05003180 if (shift) {
Michael Kolb8233fac2010-10-26 16:08:53 -07003181 pageUp();
Cary Clark160bbb92011-01-10 11:17:07 -05003182 } else if (noModifiers) {
Michael Kolb8233fac2010-10-26 16:08:53 -07003183 pageDown();
3184 }
3185 return true;
3186 case KeyEvent.KEYCODE_BACK:
Cary Clark160bbb92011-01-10 11:17:07 -05003187 if (!noModifiers) break;
John Recke6bf4ab2011-02-24 15:48:05 -08003188 event.startTracking();
3189 return true;
Michael Kolbe9e1d4a2011-07-14 15:02:17 -07003190 case KeyEvent.KEYCODE_FORWARD:
3191 if (!noModifiers) break;
3192 tab.goForward();
3193 return true;
Cary Clark8ff8c662010-12-29 15:03:05 -05003194 case KeyEvent.KEYCODE_DPAD_LEFT:
3195 if (ctrl) {
John Reckef654f12011-07-12 16:42:08 -07003196 tab.goBack();
Cary Clark8ff8c662010-12-29 15:03:05 -05003197 return true;
3198 }
3199 break;
3200 case KeyEvent.KEYCODE_DPAD_RIGHT:
3201 if (ctrl) {
John Reckef654f12011-07-12 16:42:08 -07003202 tab.goForward();
Cary Clark8ff8c662010-12-29 15:03:05 -05003203 return true;
3204 }
3205 break;
3206 case KeyEvent.KEYCODE_A:
Bijan Amirzada9b1e9882014-02-26 17:15:46 -08003207 if (ctrl) {
3208 webView.selectAll();
Cary Clark8ff8c662010-12-29 15:03:05 -05003209 return true;
3210 }
3211 break;
Michael Kolba4183062011-01-16 10:43:21 -08003212// case KeyEvent.KEYCODE_B: // menu
Cary Clark8ff8c662010-12-29 15:03:05 -05003213 case KeyEvent.KEYCODE_C:
Bijan Amirzada9b1e9882014-02-26 17:15:46 -08003214 if (ctrl ) {
3215 webView.copySelection();
Cary Clark8ff8c662010-12-29 15:03:05 -05003216 return true;
3217 }
3218 break;
Michael Kolba4183062011-01-16 10:43:21 -08003219// case KeyEvent.KEYCODE_D: // menu
Cary Clark8ff8c662010-12-29 15:03:05 -05003220// case KeyEvent.KEYCODE_E: // in Chrome: puts '?' in URL bar
Michael Kolba4183062011-01-16 10:43:21 -08003221// case KeyEvent.KEYCODE_F: // menu
Cary Clark8ff8c662010-12-29 15:03:05 -05003222// case KeyEvent.KEYCODE_G: // in Chrome: finds next match
Michael Kolba4183062011-01-16 10:43:21 -08003223// case KeyEvent.KEYCODE_H: // menu
Cary Clark8ff8c662010-12-29 15:03:05 -05003224// case KeyEvent.KEYCODE_I: // unused
Michael Kolba4183062011-01-16 10:43:21 -08003225// case KeyEvent.KEYCODE_J: // menu
Cary Clark8ff8c662010-12-29 15:03:05 -05003226// case KeyEvent.KEYCODE_K: // in Chrome: puts '?' in URL bar
Michael Kolba4183062011-01-16 10:43:21 -08003227// case KeyEvent.KEYCODE_L: // menu
Cary Clark8ff8c662010-12-29 15:03:05 -05003228// case KeyEvent.KEYCODE_M: // unused
3229// case KeyEvent.KEYCODE_N: // in Chrome: new window
3230// case KeyEvent.KEYCODE_O: // in Chrome: open file
3231// case KeyEvent.KEYCODE_P: // in Chrome: print page
3232// case KeyEvent.KEYCODE_Q: // unused
Michael Kolbdc2ee1b2011-02-14 14:34:40 -08003233// case KeyEvent.KEYCODE_R:
Cary Clark8ff8c662010-12-29 15:03:05 -05003234// case KeyEvent.KEYCODE_S: // in Chrome: saves page
3235 case KeyEvent.KEYCODE_T:
Michael Kolbdc2ee1b2011-02-14 14:34:40 -08003236 // we can't use the ctrl/shift flags, they check for
3237 // exclusive use of a modifier
3238 if (event.isCtrlPressed()) {
Cary Clark8ff8c662010-12-29 15:03:05 -05003239 if (event.isShiftPressed()) {
Michael Kolb519d2282011-05-09 17:03:19 -07003240 openIncognitoTab();
Cary Clark8ff8c662010-12-29 15:03:05 -05003241 } else {
3242 openTabToHomePage();
3243 }
3244 return true;
3245 }
3246 break;
3247// case KeyEvent.KEYCODE_U: // in Chrome: opens source of page
3248// case KeyEvent.KEYCODE_V: // text view intercepts to paste
Michael Kolb5ae15bd2011-08-16 17:09:27 -07003249// case KeyEvent.KEYCODE_W: // menu
Cary Clark8ff8c662010-12-29 15:03:05 -05003250// case KeyEvent.KEYCODE_X: // text view intercepts to cut
3251// case KeyEvent.KEYCODE_Y: // unused
3252// case KeyEvent.KEYCODE_Z: // unused
Michael Kolb8233fac2010-10-26 16:08:53 -07003253 }
Michael Kolbdc2ee1b2011-02-14 14:34:40 -08003254 // it is a regular key and webview is not null
3255 return mUi.dispatchKey(keyCode, event);
Michael Kolb8233fac2010-10-26 16:08:53 -07003256 }
3257
John Reck9c35b9c2012-05-30 10:08:50 -07003258 @Override
3259 public boolean onKeyLongPress(int keyCode, KeyEvent event) {
John Recke6bf4ab2011-02-24 15:48:05 -08003260 switch(keyCode) {
3261 case KeyEvent.KEYCODE_BACK:
John Reck3ba45532011-08-11 16:26:53 -07003262 if (mUi.isWebShowing()) {
Michael Kolb315d5022011-10-13 12:47:11 -07003263 bookmarksOrHistoryPicker(ComboViews.History);
John Recke6bf4ab2011-02-24 15:48:05 -08003264 return true;
3265 }
3266 break;
3267 }
3268 return false;
3269 }
3270
John Reck9c35b9c2012-05-30 10:08:50 -07003271 @Override
3272 public boolean onKeyUp(int keyCode, KeyEvent event) {
John Reckbcef87f2012-02-03 14:58:34 -08003273 if (isMenuOrCtrlKey(keyCode)) {
Michael Kolb2814a362011-05-19 15:49:41 -07003274 mMenuIsDown = false;
John Reckbcef87f2012-02-03 14:58:34 -08003275 if (KeyEvent.KEYCODE_MENU == keyCode
3276 && event.isTracking() && !event.isCanceled()) {
Michael Kolb4bd767d2011-05-27 11:33:55 -07003277 return onMenuKey();
Michael Kolb2814a362011-05-19 15:49:41 -07003278 }
3279 }
Cary Clark160bbb92011-01-10 11:17:07 -05003280 if (!event.hasNoModifiers()) return false;
Michael Kolb8233fac2010-10-26 16:08:53 -07003281 switch(keyCode) {
Michael Kolb8233fac2010-10-26 16:08:53 -07003282 case KeyEvent.KEYCODE_BACK:
3283 if (event.isTracking() && !event.isCanceled()) {
3284 onBackKey();
3285 return true;
3286 }
3287 break;
3288 }
3289 return false;
3290 }
3291
3292 public boolean isMenuDown() {
3293 return mMenuIsDown;
3294 }
3295
John Reck9c35b9c2012-05-30 10:08:50 -07003296 @Override
Ben Murdoch8029a772010-11-16 11:58:21 +00003297 public void setupAutoFill(Message message) {
3298 // Open the settings activity at the AutoFill profile fragment so that
3299 // the user can create a new profile. When they return, we will dispatch
3300 // the message so that we can autofill the form using their new profile.
3301 Intent intent = new Intent(mActivity, BrowserPreferencesPage.class);
3302 intent.putExtra(PreferenceActivity.EXTRA_SHOW_FRAGMENT,
3303 AutoFillSettingsFragment.class.getName());
3304 mAutoFillSetupMessage = message;
3305 mActivity.startActivityForResult(intent, AUTOFILL_SETUP);
3306 }
John Reckb3417f02011-01-14 11:01:05 -08003307
John Reck9c35b9c2012-05-30 10:08:50 -07003308 @Override
Michael Kolbfbc579a2011-07-07 15:59:33 -07003309 public boolean onSearchRequested() {
Michael Kolb1f9b3562012-04-24 14:38:34 -07003310 mUi.editUrl(false, true);
Michael Kolbfbc579a2011-07-07 15:59:33 -07003311 return true;
3312 }
3313
John Reck1cf4b792011-07-26 10:22:22 -07003314 @Override
3315 public boolean shouldCaptureThumbnails() {
3316 return mUi.shouldCaptureThumbnails();
3317 }
3318
Michael Kolbc3af0672011-08-09 10:24:41 -07003319 @Override
Michael Kolb0b129122012-06-04 16:31:58 -07003320 public boolean supportsVoice() {
3321 PackageManager pm = mActivity.getPackageManager();
3322 List activities = pm.queryIntentActivities(new Intent(
3323 RecognizerIntent.ACTION_RECOGNIZE_SPEECH), 0);
3324 return activities.size() != 0;
3325 }
3326
3327 @Override
3328 public void startVoiceRecognizer() {
3329 Intent voice = new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH);
Bijan Amirzada9b1e9882014-02-26 17:15:46 -08003330 voice.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL,
Michael Kolb0b129122012-06-04 16:31:58 -07003331 RecognizerIntent.LANGUAGE_MODEL_FREE_FORM);
3332 voice.putExtra(RecognizerIntent.EXTRA_MAX_RESULTS, 1);
3333 mActivity.startActivityForResult(voice, VOICE_RESULT);
3334 }
3335
3336 @Override
Michael Kolbc3af0672011-08-09 10:24:41 -07003337 public void setBlockEvents(boolean block) {
3338 mBlockEvents = block;
3339 }
3340
John Reck9c35b9c2012-05-30 10:08:50 -07003341 @Override
Michael Kolbc3af0672011-08-09 10:24:41 -07003342 public boolean dispatchKeyEvent(KeyEvent event) {
Michael Kolb87357642011-08-24 14:19:18 -07003343 return mBlockEvents;
Michael Kolbc3af0672011-08-09 10:24:41 -07003344 }
3345
John Reck9c35b9c2012-05-30 10:08:50 -07003346 @Override
Michael Kolbc3af0672011-08-09 10:24:41 -07003347 public boolean dispatchKeyShortcutEvent(KeyEvent event) {
Michael Kolb87357642011-08-24 14:19:18 -07003348 return mBlockEvents;
Michael Kolbc3af0672011-08-09 10:24:41 -07003349 }
3350
John Reck9c35b9c2012-05-30 10:08:50 -07003351 @Override
Michael Kolbc3af0672011-08-09 10:24:41 -07003352 public boolean dispatchTouchEvent(MotionEvent ev) {
Michael Kolb87357642011-08-24 14:19:18 -07003353 return mBlockEvents;
Michael Kolbc3af0672011-08-09 10:24:41 -07003354 }
3355
John Reck9c35b9c2012-05-30 10:08:50 -07003356 @Override
Michael Kolbc3af0672011-08-09 10:24:41 -07003357 public boolean dispatchTrackballEvent(MotionEvent ev) {
Michael Kolb87357642011-08-24 14:19:18 -07003358 return mBlockEvents;
Michael Kolbc3af0672011-08-09 10:24:41 -07003359 }
3360
John Reck9c35b9c2012-05-30 10:08:50 -07003361 @Override
Michael Kolbc3af0672011-08-09 10:24:41 -07003362 public boolean dispatchGenericMotionEvent(MotionEvent ev) {
Michael Kolb87357642011-08-24 14:19:18 -07003363 return mBlockEvents;
Michael Kolbc3af0672011-08-09 10:24:41 -07003364 }
3365
Michael Kolb8233fac2010-10-26 16:08:53 -07003366}