blob: c4c9669575162fcbb591a7ee740f471a1451e60f [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;
Tarun Nainani700b69b2014-03-26 16:07:25 -0700574 case R.id.save_link_bookmark_context_menu_id:
575 bookmarkCurrentPage();
576 break;
Michael Kolb8233fac2010-10-26 16:08:53 -0700577 }
578 break;
579 }
580
581 case LOAD_URL:
John Reck26b18322011-06-21 13:08:58 -0700582 loadUrlFromContext((String) msg.obj);
Michael Kolb8233fac2010-10-26 16:08:53 -0700583 break;
584
585 case STOP_LOAD:
586 stopLoading();
587 break;
588
589 case RELEASE_WAKELOCK:
John Reckf57c0292011-07-21 18:15:39 -0700590 if (mWakeLock != null && mWakeLock.isHeld()) {
Michael Kolb8233fac2010-10-26 16:08:53 -0700591 mWakeLock.release();
592 // if we reach here, Browser should be still in the
593 // background loading after WAKELOCK_TIMEOUT (5-min).
594 // To avoid burning the battery, stop loading.
595 mTabControl.stopAllLoading();
596 }
597 break;
598
599 case UPDATE_BOOKMARK_THUMBNAIL:
John Reck34ef2672011-02-10 11:30:55 -0800600 Tab tab = (Tab) msg.obj;
601 if (tab != null) {
602 updateScreenshot(tab);
Michael Kolb8233fac2010-10-26 16:08:53 -0700603 }
604 break;
kaiyiz591110b2013-08-06 17:11:06 +0800605 case OPEN_MENU:
606 if (!mOptionsMenuOpen && mActivity != null ) {
607 mActivity.openOptionsMenu();
608 }
609 break;
Michael Kolb8233fac2010-10-26 16:08:53 -0700610 }
611 }
612 };
613
614 }
615
John Reckef654f12011-07-12 16:42:08 -0700616 @Override
Martijn Coenenb2f93552011-06-14 10:48:35 +0200617 public Tab getCurrentTab() {
618 return mTabControl.getCurrentTab();
619 }
620
Michael Kolbba99c5d2010-11-29 14:57:41 -0800621 @Override
622 public void shareCurrentPage() {
623 shareCurrentPage(mTabControl.getCurrentTab());
624 }
625
626 private void shareCurrentPage(Tab tab) {
627 if (tab != null) {
Michael Kolbba99c5d2010-11-29 14:57:41 -0800628 sharePage(mActivity, tab.getTitle(),
629 tab.getUrl(), tab.getFavicon(),
630 createScreenshot(tab.getWebView(),
631 getDesiredThumbnailWidth(mActivity),
632 getDesiredThumbnailHeight(mActivity)));
633 }
634 }
635
Michael Kolb8233fac2010-10-26 16:08:53 -0700636 /**
637 * Share a page, providing the title, url, favicon, and a screenshot. Uses
638 * an {@link Intent} to launch the Activity chooser.
639 * @param c Context used to launch a new Activity.
640 * @param title Title of the page. Stored in the Intent with
641 * {@link Intent#EXTRA_SUBJECT}
642 * @param url URL of the page. Stored in the Intent with
643 * {@link Intent#EXTRA_TEXT}
644 * @param favicon Bitmap of the favicon for the page. Stored in the Intent
645 * with {@link Browser#EXTRA_SHARE_FAVICON}
646 * @param screenshot Bitmap of a screenshot of the page. Stored in the
647 * Intent with {@link Browser#EXTRA_SHARE_SCREENSHOT}
648 */
649 static final void sharePage(Context c, String title, String url,
650 Bitmap favicon, Bitmap screenshot) {
651 Intent send = new Intent(Intent.ACTION_SEND);
652 send.setType("text/plain");
653 send.putExtra(Intent.EXTRA_TEXT, url);
654 send.putExtra(Intent.EXTRA_SUBJECT, title);
Bijan Amirzada9b1e9882014-02-26 17:15:46 -0800655 send.putExtra(EXTRA_SHARE_FAVICON, favicon);
656 send.putExtra(EXTRA_SHARE_SCREENSHOT, screenshot);
Michael Kolb8233fac2010-10-26 16:08:53 -0700657 try {
658 c.startActivity(Intent.createChooser(send, c.getString(
659 R.string.choosertitle_sharevia)));
660 } catch(android.content.ActivityNotFoundException ex) {
661 // if no app handles it, do nothing
662 }
663 }
664
665 private void copy(CharSequence text) {
666 ClipboardManager cm = (ClipboardManager) mActivity
667 .getSystemService(Context.CLIPBOARD_SERVICE);
668 cm.setText(text);
669 }
670
671 // lifecycle
672
John Reck9c35b9c2012-05-30 10:08:50 -0700673 @Override
674 public void onConfgurationChanged(Configuration config) {
Michael Kolb8233fac2010-10-26 16:08:53 -0700675 mConfigChanged = true;
Michael Kolb18f252f2012-03-06 13:36:20 -0800676 // update the menu in case of a locale change
677 mActivity.invalidateOptionsMenu();
kaiyiz591110b2013-08-06 17:11:06 +0800678 if (mOptionsMenuOpen) {
679 mActivity.closeOptionsMenu();
680 mHandler.sendMessageDelayed(mHandler.obtainMessage(OPEN_MENU), 100);
681 }
Michael Kolb8233fac2010-10-26 16:08:53 -0700682 if (mPageDialogsHandler != null) {
683 mPageDialogsHandler.onConfigurationChanged(config);
684 }
685 mUi.onConfigurationChanged(config);
686 }
687
688 @Override
689 public void handleNewIntent(Intent intent) {
Michael Kolb59e232c2011-08-18 17:19:53 -0700690 if (!mUi.isWebShowing()) {
691 mUi.showWeb(false);
692 }
Michael Kolb8233fac2010-10-26 16:08:53 -0700693 mIntentHandler.onNewIntent(intent);
694 }
695
John Reck9c35b9c2012-05-30 10:08:50 -0700696 @Override
697 public void onPause() {
Michael Kolb11fe02d2011-02-02 09:52:16 -0800698 if (mUi.isCustomViewShowing()) {
699 hideCustomView();
700 }
Michael Kolb8233fac2010-10-26 16:08:53 -0700701 if (mActivityPaused) {
702 Log.e(LOGTAG, "BrowserActivity is already paused.");
703 return;
704 }
Michael Kolb8233fac2010-10-26 16:08:53 -0700705 mActivityPaused = true;
Michael Kolb70976932010-11-30 11:34:01 -0800706 Tab tab = mTabControl.getCurrentTab();
707 if (tab != null) {
708 tab.pause();
709 if (!pauseWebViewTimers(tab)) {
John Reckf57c0292011-07-21 18:15:39 -0700710 if (mWakeLock == null) {
711 PowerManager pm = (PowerManager) mActivity
712 .getSystemService(Context.POWER_SERVICE);
713 mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "Browser");
714 }
Michael Kolb70976932010-11-30 11:34:01 -0800715 mWakeLock.acquire();
716 mHandler.sendMessageDelayed(mHandler
717 .obtainMessage(RELEASE_WAKELOCK), WAKELOCK_TIMEOUT);
718 }
Michael Kolb8233fac2010-10-26 16:08:53 -0700719 }
720 mUi.onPause();
721 mNetworkHandler.onPause();
722
723 WebView.disablePlatformNotifications();
Ben Murdoch015e1e32011-09-01 23:45:31 +0100724 NfcHandler.unregister(mActivity);
John Reckd7dd9b22011-08-30 09:18:29 -0700725 if (sThumbnailBitmap != null) {
726 sThumbnailBitmap.recycle();
727 sThumbnailBitmap = null;
728 }
Michael Kolb8233fac2010-10-26 16:08:53 -0700729 }
730
John Reck9c35b9c2012-05-30 10:08:50 -0700731 @Override
732 public void onSaveInstanceState(Bundle outState) {
Michael Kolb8233fac2010-10-26 16:08:53 -0700733 // Save all the tabs
George Mount3636d0a2011-11-21 09:08:21 -0800734 Bundle saveState = createSaveState();
735
736 // crash recovery manages all save & restore state
737 mCrashRecoveryHandler.writeState(saveState);
738 mSettings.setLastRunPaused(true);
739 }
740
741 /**
742 * Save the current state to outState. Does not write the state to
743 * disk.
744 * @return Bundle containing the current state of all tabs.
745 */
746 /* package */ Bundle createSaveState() {
747 Bundle saveState = new Bundle();
748 mTabControl.saveState(saveState);
749 if (!saveState.isEmpty()) {
John Reck24f18262011-06-17 14:47:20 -0700750 // Save time so that we know how old incognito tabs (if any) are.
George Mount3636d0a2011-11-21 09:08:21 -0800751 saveState.putSerializable("lastActiveDate", Calendar.getInstance());
John Reck24f18262011-06-17 14:47:20 -0700752 }
George Mount3636d0a2011-11-21 09:08:21 -0800753 return saveState;
Michael Kolb8233fac2010-10-26 16:08:53 -0700754 }
755
John Reck9c35b9c2012-05-30 10:08:50 -0700756 @Override
757 public void onResume() {
Michael Kolb8233fac2010-10-26 16:08:53 -0700758 if (!mActivityPaused) {
759 Log.e(LOGTAG, "BrowserActivity is already resumed.");
760 return;
761 }
George Mount3636d0a2011-11-21 09:08:21 -0800762 mSettings.setLastRunPaused(false);
Michael Kolb8233fac2010-10-26 16:08:53 -0700763 mActivityPaused = false;
Michael Kolb70976932010-11-30 11:34:01 -0800764 Tab current = mTabControl.getCurrentTab();
765 if (current != null) {
766 current.resume();
767 resumeWebViewTimers(current);
768 }
John Reckf57c0292011-07-21 18:15:39 -0700769 releaseWakeLock();
Martijn Coenenb2f93552011-06-14 10:48:35 +0200770
Michael Kolb8233fac2010-10-26 16:08:53 -0700771 mUi.onResume();
772 mNetworkHandler.onResume();
773 WebView.enablePlatformNotifications();
Ben Murdoch015e1e32011-09-01 23:45:31 +0100774 NfcHandler.register(mActivity, this);
Michael Kolb0b129122012-06-04 16:31:58 -0700775 if (mVoiceResult != null) {
776 mUi.onVoiceResult(mVoiceResult);
777 mVoiceResult = null;
778 }
Bijan Amirzada9b1e9882014-02-26 17:15:46 -0800779 if (current != null && current.hasCrashed) {
780 current.showCrashView();
781 }
Michael Kolb8233fac2010-10-26 16:08:53 -0700782 }
783
John Reckf57c0292011-07-21 18:15:39 -0700784 private void releaseWakeLock() {
785 if (mWakeLock != null && mWakeLock.isHeld()) {
786 mHandler.removeMessages(RELEASE_WAKELOCK);
787 mWakeLock.release();
788 }
789 }
790
Michael Kolb70976932010-11-30 11:34:01 -0800791 /**
Michael Kolbba99c5d2010-11-29 14:57:41 -0800792 * resume all WebView timers using the WebView instance of the given tab
Michael Kolb70976932010-11-30 11:34:01 -0800793 * @param tab guaranteed non-null
794 */
795 private void resumeWebViewTimers(Tab tab) {
Michael Kolb8233fac2010-10-26 16:08:53 -0700796 boolean inLoad = tab.inPageLoad();
797 if ((!mActivityPaused && !inLoad) || (mActivityPaused && inLoad)) {
798 CookieSyncManager.getInstance().startSync();
799 WebView w = tab.getWebView();
Mathew Inwoode1dbb952011-07-08 17:27:38 +0100800 WebViewTimersControl.getInstance().onBrowserActivityResume(w);
Michael Kolb8233fac2010-10-26 16:08:53 -0700801 }
802 }
803
Michael Kolb70976932010-11-30 11:34:01 -0800804 /**
805 * Pause all WebView timers using the WebView of the given tab
806 * @param tab
807 * @return true if the timers are paused or tab is null
808 */
809 private boolean pauseWebViewTimers(Tab tab) {
810 if (tab == null) {
811 return true;
812 } else if (!tab.inPageLoad()) {
Michael Kolb8233fac2010-10-26 16:08:53 -0700813 CookieSyncManager.getInstance().stopSync();
Mathew Inwoode1dbb952011-07-08 17:27:38 +0100814 WebViewTimersControl.getInstance().onBrowserActivityPause(getCurrentWebView());
Michael Kolb8233fac2010-10-26 16:08:53 -0700815 return true;
Michael Kolb8233fac2010-10-26 16:08:53 -0700816 }
Michael Kolb70976932010-11-30 11:34:01 -0800817 return false;
Michael Kolb8233fac2010-10-26 16:08:53 -0700818 }
819
John Reck9c35b9c2012-05-30 10:08:50 -0700820 @Override
821 public void onDestroy() {
John Reck38b4bf52011-02-22 14:39:34 -0800822 if (mUploadHandler != null && !mUploadHandler.handled()) {
Michael Kolb8233fac2010-10-26 16:08:53 -0700823 mUploadHandler.onResult(Activity.RESULT_CANCELED, null);
824 mUploadHandler = null;
825 }
826 if (mTabControl == null) return;
827 mUi.onDestroy();
828 // Remove the current tab and sub window
829 Tab t = mTabControl.getCurrentTab();
830 if (t != null) {
831 dismissSubWindow(t);
832 removeTab(t);
833 }
Leon Scroggins1961ed22010-12-07 15:22:21 -0500834 mActivity.getContentResolver().unregisterContentObserver(mBookmarksObserver);
Michael Kolb8233fac2010-10-26 16:08:53 -0700835 // Destroy all the tabs
836 mTabControl.destroy();
837 WebIconDatabase.getInstance().close();
838 // Stop watching the default geolocation permissions
839 mSystemAllowGeolocationOrigins.stop();
840 mSystemAllowGeolocationOrigins = null;
841 }
842
843 protected boolean isActivityPaused() {
844 return mActivityPaused;
845 }
846
John Reck9c35b9c2012-05-30 10:08:50 -0700847 @Override
848 public void onLowMemory() {
Michael Kolb8233fac2010-10-26 16:08:53 -0700849 mTabControl.freeMemory();
850 }
851
852 @Override
853 public boolean shouldShowErrorConsole() {
854 return mShouldShowErrorConsole;
855 }
856
857 protected void setShouldShowErrorConsole(boolean show) {
858 if (show == mShouldShowErrorConsole) {
859 // Nothing to do.
860 return;
861 }
862 mShouldShowErrorConsole = show;
863 Tab t = mTabControl.getCurrentTab();
864 if (t == null) {
865 // There is no current tab so we cannot toggle the error console
866 return;
867 }
868 mUi.setShouldShowErrorConsole(t, show);
869 }
870
871 @Override
872 public void stopLoading() {
873 mLoadStopped = true;
874 Tab tab = mTabControl.getCurrentTab();
Michael Kolb8233fac2010-10-26 16:08:53 -0700875 WebView w = getCurrentTopWebView();
Michael Kolb778a4882012-04-12 15:27:28 -0700876 if (w != null) {
877 w.stopLoading();
878 mUi.onPageStopped(tab);
879 }
Michael Kolb8233fac2010-10-26 16:08:53 -0700880 }
881
882 boolean didUserStopLoading() {
883 return mLoadStopped;
884 }
885
kaiyiza016da12013-08-26 17:50:22 +0800886 private void handleNetworkNotify(WebView view) {
887 ConnectivityManager conMgr = (ConnectivityManager) this.getContext().getSystemService(
888 Context.CONNECTIVITY_SERVICE);
889 WifiManager wifiMgr = (WifiManager) this.getContext()
890 .getSystemService(Context.WIFI_SERVICE);
891 int networkSwitchTypeOK = this.getContext().getResources()
892 .getInteger(R.integer.netswitch_type_remind);
893
894 if (wifiMgr.isWifiEnabled()) {
895 NetworkInfo mNetworkInfo = conMgr.getActiveNetworkInfo();
896 if (mNetworkInfo == null
897 || (mNetworkInfo != null && (mNetworkInfo.getType() !=
898 ConnectivityManager.TYPE_WIFI))) {
kaiyizb7bf1f22013-10-02 11:42:23 +0800899 List<ScanResult> list = wifiMgr.getScanResults();
900 if (list != null && list.size() == 0) {
901 int isReminder = Settings.System.getInt(
902 mActivity.getContentResolver(),
903 this.getContext().getResources()
904 .getString(R.string.network_switch_remind_type),
905 networkSwitchTypeOK);
906 if (isReminder == networkSwitchTypeOK) {
907 Intent intent = new Intent(
908 INTENT_WIFI_SELECTION_DATA_CONNECTION);
909 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
910 this.getContext().startActivity(intent);
911 }
912 } else {
Bijan Amirzada9b1e9882014-02-26 17:15:46 -0800913 if ((Boolean)ReflectHelper.invokeStaticMethod(
914 "ActivityManagerNative", "isSystemReady", null, null)) {
kaiyizb7bf1f22013-10-02 11:42:23 +0800915 try {
916 Intent intent = new Intent(INTENT_PICK_NETWORK);
917 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
918 this.getContext().startActivity(intent);
919 } catch (Exception e) {
920 String err_msg = this.getContext().getString(
921 R.string.acivity_not_found, INTENT_PICK_NETWORK);
922 Toast.makeText(this.getContext(), err_msg, Toast.LENGTH_LONG).show();
923 }
924 } else {
925 Log.e(LOGTAG, "System is not ready!");
926 }
kaiyiza016da12013-08-26 17:50:22 +0800927 }
928 mNetworkShouldNotify = false;
929 }
930 } else {
931 if (!mNetworkHandler.isNetworkUp()) {
932 view.setNetworkAvailable(false);
933 Log.v(LOGTAG, "handleNetworkNotify() Wlan is not enabled.");
934 }
935 }
936 }
Michael Kolb8233fac2010-10-26 16:08:53 -0700937 // WebViewController
938
939 @Override
John Reck324d4402011-01-11 16:56:42 -0800940 public void onPageStarted(Tab tab, WebView view, Bitmap favicon) {
Michael Kolb8233fac2010-10-26 16:08:53 -0700941
942 // We've started to load a new page. If there was a pending message
943 // to save a screenshot then we will now take the new page and save
944 // an incorrect screenshot. Therefore, remove any pending thumbnail
945 // messages from the queue.
946 mHandler.removeMessages(Controller.UPDATE_BOOKMARK_THUMBNAIL,
John Reck34ef2672011-02-10 11:30:55 -0800947 tab);
Michael Kolb8233fac2010-10-26 16:08:53 -0700948
949 // reset sync timer to avoid sync starts during loading a page
950 CookieSyncManager.getInstance().resetSync();
Bijan Amirzada9b1e9882014-02-26 17:15:46 -0800951 Object[] params = {new String(PROP_NETSWITCH),
952 new Boolean(false)};
953 Class[] type = new Class[] {String.class, boolean.class};
954 Boolean result = (Boolean) ReflectHelper.invokeStaticMethod(
955 "android.os.SystemProperties", "getBoolean",
956 type, params);
957 if (result) {
kaiyiza016da12013-08-26 17:50:22 +0800958 if (!mNetworkHandler.isNetworkUp()) {
959 Log.d(LOGTAG, "onPageStarted() network unavailable");
960 if (mNetworkShouldNotify) {
961 handleNetworkNotify(view);
962 } else {
963 view.setNetworkAvailable(false);
964 }
965 mNetworkShouldNotify = false;
966 } else {
967 Log.d(LOGTAG, "onPageStarted() network available");
968 if (mNetworkShouldNotify) {
969 handleNetworkNotify(view);
970 }
971 mNetworkShouldNotify = false;
972 }
973 } else {
974 if (!mNetworkHandler.isNetworkUp()) {
975 view.setNetworkAvailable(false);
976 }
Michael Kolb8233fac2010-10-26 16:08:53 -0700977 }
978
979 // when BrowserActivity just starts, onPageStarted may be called before
980 // onResume as it is triggered from onCreate. Call resumeWebViewTimers
981 // to start the timer. As we won't switch tabs while an activity is in
982 // pause state, we can ensure calling resume and pause in pair.
983 if (mActivityPaused) {
Michael Kolb70976932010-11-30 11:34:01 -0800984 resumeWebViewTimers(tab);
Michael Kolb8233fac2010-10-26 16:08:53 -0700985 }
986 mLoadStopped = false;
Michael Kolb8233fac2010-10-26 16:08:53 -0700987 endActionMode();
988
John Reck30c714c2010-12-16 17:30:34 -0800989 mUi.onTabDataChanged(tab);
Michael Kolb8233fac2010-10-26 16:08:53 -0700990
John Reck324d4402011-01-11 16:56:42 -0800991 String url = tab.getUrl();
Michael Kolb8233fac2010-10-26 16:08:53 -0700992 // update the bookmark database for favicon
993 maybeUpdateFavicon(tab, null, url, favicon);
994
995 Performance.tracePageStart(url);
996
997 // Performance probe
998 if (false) {
999 Performance.onPageStarted();
1000 }
1001
1002 }
1003
1004 @Override
John Reck324d4402011-01-11 16:56:42 -08001005 public void onPageFinished(Tab tab) {
Michael Kolb72864272012-05-03 15:42:15 -07001006 mCrashRecoveryHandler.backupState();
John Reck30c714c2010-12-16 17:30:34 -08001007 mUi.onTabDataChanged(tab);
Martijn Coenenb2f93552011-06-14 10:48:35 +02001008
Michael Kolb8233fac2010-10-26 16:08:53 -07001009 // Performance probe
1010 if (false) {
John Reck324d4402011-01-11 16:56:42 -08001011 Performance.onPageFinished(tab.getUrl());
Michael Kolb8233fac2010-10-26 16:08:53 -07001012 }
1013
1014 Performance.tracePageFinished();
1015 }
1016
1017 @Override
John Reck30c714c2010-12-16 17:30:34 -08001018 public void onProgressChanged(Tab tab) {
1019 int newProgress = tab.getLoadProgress();
Michael Kolb8233fac2010-10-26 16:08:53 -07001020
1021 if (newProgress == 100) {
1022 CookieSyncManager.getInstance().sync();
1023 // onProgressChanged() may continue to be called after the main
1024 // frame has finished loading, as any remaining sub frames continue
1025 // to load. We'll only get called once though with newProgress as
1026 // 100 when everything is loaded. (onPageFinished is called once
1027 // when the main frame completes loading regardless of the state of
1028 // any sub frames so calls to onProgressChanges may continue after
1029 // onPageFinished has executed)
Michael Kolbb1fb70c2011-11-21 12:38:14 -08001030 if (tab.inPageLoad()) {
1031 updateInLoadMenuItems(mCachedMenu, tab);
Mattias Falk9cc2d032012-05-25 09:40:31 +02001032 } else if (mActivityPaused && pauseWebViewTimers(tab)) {
1033 // pause the WebView timer and release the wake lock if it is
1034 // finished while BrowserActivity is in pause state.
1035 releaseWakeLock();
Michael Kolb8233fac2010-10-26 16:08:53 -07001036 }
John Reckd9862372012-02-21 15:04:50 -08001037 if (!tab.isPrivateBrowsingEnabled()
1038 && !TextUtils.isEmpty(tab.getUrl())
1039 && !tab.isSnapshot()) {
1040 // Only update the bookmark screenshot if the user did not
1041 // cancel the load early and there is not already
1042 // a pending update for the tab.
Michael Kolb72864272012-05-03 15:42:15 -07001043 if (tab.shouldUpdateThumbnail() &&
1044 (tab.inForeground() && !didUserStopLoading()
1045 || !tab.inForeground())) {
John Reckd9862372012-02-21 15:04:50 -08001046 if (!mHandler.hasMessages(UPDATE_BOOKMARK_THUMBNAIL, tab)) {
1047 mHandler.sendMessageDelayed(mHandler.obtainMessage(
1048 UPDATE_BOOKMARK_THUMBNAIL, 0, 0, tab),
Bijan Amirzada9b1e9882014-02-26 17:15:46 -08001049 1500);
John Reckd9862372012-02-21 15:04:50 -08001050 }
1051 }
1052 }
Michael Kolb8233fac2010-10-26 16:08:53 -07001053 } else {
Michael Kolbb1fb70c2011-11-21 12:38:14 -08001054 if (!tab.inPageLoad()) {
Michael Kolb8233fac2010-10-26 16:08:53 -07001055 // onPageFinished may have already been called but a subframe is
Michael Kolbb1fb70c2011-11-21 12:38:14 -08001056 // still loading
1057 // updating the progress and
Michael Kolb8233fac2010-10-26 16:08:53 -07001058 // update the menu items.
Michael Kolbb1fb70c2011-11-21 12:38:14 -08001059 updateInLoadMenuItems(mCachedMenu, tab);
Michael Kolb8233fac2010-10-26 16:08:53 -07001060 }
1061 }
John Reck30c714c2010-12-16 17:30:34 -08001062 mUi.onProgressChanged(tab);
1063 }
1064
1065 @Override
Steve Block2466eff2011-10-03 15:33:09 +01001066 public void onUpdatedSecurityState(Tab tab) {
John Reck30c714c2010-12-16 17:30:34 -08001067 mUi.onTabDataChanged(tab);
Michael Kolb8233fac2010-10-26 16:08:53 -07001068 }
1069
1070 @Override
1071 public void onReceivedTitle(Tab tab, final String title) {
John Reck30c714c2010-12-16 17:30:34 -08001072 mUi.onTabDataChanged(tab);
John Reck49a603c2011-03-03 09:33:05 -08001073 final String pageUrl = tab.getOriginalUrl();
John Reck324d4402011-01-11 16:56:42 -08001074 if (TextUtils.isEmpty(pageUrl) || pageUrl.length()
Michael Kolb8233fac2010-10-26 16:08:53 -07001075 >= SQLiteDatabase.SQLITE_MAX_LIKE_PATTERN_LENGTH) {
1076 return;
1077 }
1078 // Update the title in the history database if not in private browsing mode
1079 if (!tab.isPrivateBrowsingEnabled()) {
John Reckf57c0292011-07-21 18:15:39 -07001080 DataController.getInstance(mActivity).updateHistoryTitle(pageUrl, title);
Michael Kolb8233fac2010-10-26 16:08:53 -07001081 }
1082 }
1083
1084 @Override
1085 public void onFavicon(Tab tab, WebView view, Bitmap icon) {
John Reck30c714c2010-12-16 17:30:34 -08001086 mUi.onTabDataChanged(tab);
Michael Kolb8233fac2010-10-26 16:08:53 -07001087 maybeUpdateFavicon(tab, view.getOriginalUrl(), view.getUrl(), icon);
1088 }
1089
1090 @Override
Michael Kolb18eb3772010-12-10 14:29:51 -08001091 public boolean shouldOverrideUrlLoading(Tab tab, WebView view, String url) {
1092 return mUrlHandler.shouldOverrideUrlLoading(tab, view, url);
Michael Kolb8233fac2010-10-26 16:08:53 -07001093 }
1094
1095 @Override
1096 public boolean shouldOverrideKeyEvent(KeyEvent event) {
1097 if (mMenuIsDown) {
1098 // only check shortcut key when MENU is held
1099 return mActivity.getWindow().isShortcutKey(event.getKeyCode(),
1100 event);
Michael Kolb8233fac2010-10-26 16:08:53 -07001101 }
Bijan Amirzada9b1e9882014-02-26 17:15:46 -08001102 int keyCode = event.getKeyCode();
1103 // We need to send almost every key to WebKit. However:
1104 // 1. We don't want to block the device on the renderer for
1105 // some keys like menu, home, call.
1106 // 2. There are no WebKit equivalents for some of these keys
1107 // (see app/keyboard_codes_win.h)
1108 // Note that these are not the same set as KeyEvent.isSystemKey:
1109 // for instance, AKEYCODE_MEDIA_* will be dispatched to webkit.
1110 if (keyCode == KeyEvent.KEYCODE_MENU ||
1111 keyCode == KeyEvent.KEYCODE_HOME ||
1112 keyCode == KeyEvent.KEYCODE_BACK ||
1113 keyCode == KeyEvent.KEYCODE_CALL ||
1114 keyCode == KeyEvent.KEYCODE_ENDCALL ||
1115 keyCode == KeyEvent.KEYCODE_POWER ||
1116 keyCode == KeyEvent.KEYCODE_HEADSETHOOK ||
1117 keyCode == KeyEvent.KEYCODE_CAMERA ||
1118 keyCode == KeyEvent.KEYCODE_FOCUS ||
1119 keyCode == KeyEvent.KEYCODE_VOLUME_DOWN ||
1120 keyCode == KeyEvent.KEYCODE_VOLUME_MUTE ||
1121 keyCode == KeyEvent.KEYCODE_VOLUME_UP) {
1122 return true;
1123 }
1124
1125 // We also have to intercept some shortcuts before we send them to the ContentView.
1126 if (event.isCtrlPressed() && (
1127 keyCode == KeyEvent.KEYCODE_TAB ||
1128 keyCode == KeyEvent.KEYCODE_W ||
1129 keyCode == KeyEvent.KEYCODE_F4)) {
1130 return true;
1131 }
1132
1133 return false;
Michael Kolb8233fac2010-10-26 16:08:53 -07001134 }
1135
1136 @Override
John Reck997b1b72012-04-19 18:08:25 -07001137 public boolean onUnhandledKeyEvent(KeyEvent event) {
Michael Kolb8233fac2010-10-26 16:08:53 -07001138 if (!isActivityPaused()) {
1139 if (event.getAction() == KeyEvent.ACTION_DOWN) {
John Reck997b1b72012-04-19 18:08:25 -07001140 return mActivity.onKeyDown(event.getKeyCode(), event);
Michael Kolb8233fac2010-10-26 16:08:53 -07001141 } else {
John Reck997b1b72012-04-19 18:08:25 -07001142 return mActivity.onKeyUp(event.getKeyCode(), event);
Michael Kolb8233fac2010-10-26 16:08:53 -07001143 }
1144 }
John Reck997b1b72012-04-19 18:08:25 -07001145 return false;
Michael Kolb8233fac2010-10-26 16:08:53 -07001146 }
1147
1148 @Override
John Reck324d4402011-01-11 16:56:42 -08001149 public void doUpdateVisitedHistory(Tab tab, boolean isReload) {
Michael Kolb8233fac2010-10-26 16:08:53 -07001150 // Don't save anything in private browsing mode
1151 if (tab.isPrivateBrowsingEnabled()) return;
John Reck49a603c2011-03-03 09:33:05 -08001152 String url = tab.getOriginalUrl();
Michael Kolb8233fac2010-10-26 16:08:53 -07001153
John Reck324d4402011-01-11 16:56:42 -08001154 if (TextUtils.isEmpty(url)
1155 || url.regionMatches(true, 0, "about:", 0, 6)) {
Michael Kolb8233fac2010-10-26 16:08:53 -07001156 return;
1157 }
Bijan Amirzada9b1e9882014-02-26 17:15:46 -08001158
John Reckf57c0292011-07-21 18:15:39 -07001159 DataController.getInstance(mActivity).updateVisitedHistory(url);
John Reck6c2e2f32011-08-22 13:41:23 -07001160 mCrashRecoveryHandler.backupState();
Michael Kolb8233fac2010-10-26 16:08:53 -07001161 }
1162
1163 @Override
1164 public void getVisitedHistory(final ValueCallback<String[]> callback) {
1165 AsyncTask<Void, Void, String[]> task =
1166 new AsyncTask<Void, Void, String[]>() {
1167 @Override
1168 public String[] doInBackground(Void... unused) {
Bijan Amirzada9b1e9882014-02-26 17:15:46 -08001169 Object[] params = {mActivity.getContentResolver()};
1170 Class[] type = new Class[] {ContentResolver.class};
1171 return (String[])ReflectHelper.invokeStaticMethod(
1172 "android.provider.Browser","getVisitedHistory",
1173 type, params);
Michael Kolb8233fac2010-10-26 16:08:53 -07001174 }
1175 @Override
1176 public void onPostExecute(String[] result) {
1177 callback.onReceiveValue(result);
1178 }
1179 };
1180 task.execute();
1181 }
1182
1183 @Override
1184 public void onReceivedHttpAuthRequest(Tab tab, WebView view,
1185 final HttpAuthHandler handler, final String host,
1186 final String realm) {
1187 String username = null;
1188 String password = null;
1189
1190 boolean reuseHttpAuthUsernamePassword
1191 = handler.useHttpAuthUsernamePassword();
1192
1193 if (reuseHttpAuthUsernamePassword && view != null) {
1194 String[] credentials = view.getHttpAuthUsernamePassword(host, realm);
1195 if (credentials != null && credentials.length == 2) {
1196 username = credentials[0];
1197 password = credentials[1];
1198 }
1199 }
1200
1201 if (username != null && password != null) {
1202 handler.proceed(username, password);
1203 } else {
Bijan Amirzada9b1e9882014-02-26 17:15:46 -08001204 if (tab.inForeground() /*&& !handler.suppressDialog()*/) {
Michael Kolb8233fac2010-10-26 16:08:53 -07001205 mPageDialogsHandler.showHttpAuthentication(tab, handler, host, realm);
1206 } else {
1207 handler.cancel();
1208 }
1209 }
1210 }
1211
1212 @Override
1213 public void onDownloadStart(Tab tab, String url, String userAgent,
Selim Gurun0b3d66f2012-08-29 13:08:13 -07001214 String contentDisposition, String mimetype, String referer,
1215 long contentLength) {
Kristian Monsenbc5cc752011-03-02 13:14:03 +00001216 WebView w = tab.getWebView();
qqzhoua95a2e22013-04-18 17:28:31 +08001217 boolean ret = DownloadHandler.onDownloadStart(mActivity, url, userAgent,
luxiaol62677b02013-07-22 07:54:49 +08001218 contentDisposition, mimetype, referer, w.isPrivateBrowsingEnabled(), contentLength);
qqzhoua95a2e22013-04-18 17:28:31 +08001219 if (ret == false && w.copyBackForwardList().getSize() == 0) {
Michael Kolb8233fac2010-10-26 16:08:53 -07001220 // This Tab was opened for the sole purpose of downloading a
1221 // file. Remove it.
1222 if (tab == mTabControl.getCurrentTab()) {
1223 // In this case, the Tab is still on top.
1224 goBackOnePageOrQuit();
1225 } else {
1226 // In this case, it is not.
1227 closeTab(tab);
1228 }
1229 }
1230 }
1231
1232 @Override
1233 public Bitmap getDefaultVideoPoster() {
1234 return mUi.getDefaultVideoPoster();
1235 }
1236
1237 @Override
1238 public View getVideoLoadingProgressView() {
1239 return mUi.getVideoLoadingProgressView();
1240 }
1241
1242 @Override
1243 public void showSslCertificateOnError(WebView view, SslErrorHandler handler,
1244 SslError error) {
1245 mPageDialogsHandler.showSSLCertificateOnError(view, handler, error);
1246 }
1247
Patrick Scott92066772011-03-10 08:46:27 -05001248 @Override
1249 public void showAutoLogin(Tab tab) {
1250 assert tab.inForeground();
1251 // Update the title bar to show the auto-login request.
1252 mUi.showAutoLogin(tab);
1253 }
1254
1255 @Override
1256 public void hideAutoLogin(Tab tab) {
1257 assert tab.inForeground();
1258 mUi.hideAutoLogin(tab);
1259 }
1260
Michael Kolb8233fac2010-10-26 16:08:53 -07001261 // helper method
1262
1263 /*
1264 * Update the favorites icon if the private browsing isn't enabled and the
1265 * icon is valid.
1266 */
1267 private void maybeUpdateFavicon(Tab tab, final String originalUrl,
1268 final String url, Bitmap favicon) {
1269 if (favicon == null) {
1270 return;
1271 }
1272 if (!tab.isPrivateBrowsingEnabled()) {
1273 Bookmarks.updateFavicon(mActivity
1274 .getContentResolver(), originalUrl, url, favicon);
1275 }
1276 }
1277
Leon Scroggins4cd97792010-12-03 15:31:56 -05001278 @Override
1279 public void bookmarkedStatusHasChanged(Tab tab) {
John Recke969cc52010-12-21 17:24:43 -08001280 // TODO: Switch to using onTabDataChanged after b/3262950 is fixed
Leon Scroggins4cd97792010-12-03 15:31:56 -05001281 mUi.bookmarkedStatusHasChanged(tab);
1282 }
1283
Michael Kolb8233fac2010-10-26 16:08:53 -07001284 // end WebViewController
1285
1286 protected void pageUp() {
1287 getCurrentTopWebView().pageUp(false);
1288 }
1289
1290 protected void pageDown() {
1291 getCurrentTopWebView().pageDown(false);
1292 }
1293
1294 // callback from phone title bar
John Reck9c35b9c2012-05-30 10:08:50 -07001295 @Override
Michael Kolb8233fac2010-10-26 16:08:53 -07001296 public void editUrl() {
1297 if (mOptionsMenuOpen) mActivity.closeOptionsMenu();
Michael Kolb1f9b3562012-04-24 14:38:34 -07001298 mUi.editUrl(false, true);
Michael Kolb8233fac2010-10-26 16:08:53 -07001299 }
1300
John Reck9c35b9c2012-05-30 10:08:50 -07001301 @Override
Derek Sollenberger2d4f1e22011-06-01 14:50:42 -04001302 public void showCustomView(Tab tab, View view, int requestedOrientation,
Bijan Amirzada9b1e9882014-02-26 17:15:46 -08001303 CustomViewCallback callback) {
Michael Kolb8233fac2010-10-26 16:08:53 -07001304 if (tab.inForeground()) {
1305 if (mUi.isCustomViewShowing()) {
1306 callback.onCustomViewHidden();
1307 return;
1308 }
Derek Sollenberger2d4f1e22011-06-01 14:50:42 -04001309 mUi.showCustomView(view, requestedOrientation, callback);
Michael Kolb8233fac2010-10-26 16:08:53 -07001310 // Save the menu state and set it to empty while the custom
1311 // view is showing.
1312 mOldMenuState = mMenuState;
1313 mMenuState = EMPTY_MENU;
John Reckd73c5a22010-12-22 10:22:50 -08001314 mActivity.invalidateOptionsMenu();
Michael Kolb8233fac2010-10-26 16:08:53 -07001315 }
1316 }
1317
1318 @Override
1319 public void hideCustomView() {
1320 if (mUi.isCustomViewShowing()) {
1321 mUi.onHideCustomView();
1322 // Reset the old menu state.
1323 mMenuState = mOldMenuState;
1324 mOldMenuState = EMPTY_MENU;
John Reckd73c5a22010-12-22 10:22:50 -08001325 mActivity.invalidateOptionsMenu();
Michael Kolb8233fac2010-10-26 16:08:53 -07001326 }
1327 }
1328
John Reck9c35b9c2012-05-30 10:08:50 -07001329 @Override
1330 public void onActivityResult(int requestCode, int resultCode,
Michael Kolb8233fac2010-10-26 16:08:53 -07001331 Intent intent) {
1332 if (getCurrentTopWebView() == null) return;
1333 switch (requestCode) {
1334 case PREFERENCES_PAGE:
1335 if (resultCode == Activity.RESULT_OK && intent != null) {
1336 String action = intent.getStringExtra(Intent.EXTRA_TEXT);
John Reck35e9dd62011-04-25 09:01:54 -07001337 if (PreferenceKeys.PREF_PRIVACY_CLEAR_HISTORY.equals(action)) {
Michael Kolb8233fac2010-10-26 16:08:53 -07001338 mTabControl.removeParentChildRelationShips();
1339 }
1340 }
1341 break;
1342 case FILE_SELECTED:
Ben Murdoch51f6a2f2011-02-21 12:27:07 +00001343 // Chose a file from the file picker.
John Reck9dfcdb12011-02-22 16:40:46 -08001344 if (null == mUploadHandler) break;
Michael Kolb8233fac2010-10-26 16:08:53 -07001345 mUploadHandler.onResult(resultCode, intent);
Michael Kolb8233fac2010-10-26 16:08:53 -07001346 break;
Ben Murdoch8029a772010-11-16 11:58:21 +00001347 case AUTOFILL_SETUP:
1348 // Determine whether a profile was actually set up or not
1349 // and if so, send the message back to the WebTextView to
1350 // fill the form with the new profile.
1351 if (getSettings().getAutoFillProfile() != null) {
1352 mAutoFillSetupMessage.sendToTarget();
1353 mAutoFillSetupMessage = null;
1354 }
1355 break;
John Reckd3e4d5b2011-07-13 15:48:43 -07001356 case COMBO_VIEW:
1357 if (intent == null || resultCode != Activity.RESULT_OK) {
1358 break;
1359 }
John Reck3ba45532011-08-11 16:26:53 -07001360 mUi.showWeb(false);
John Reckd3e4d5b2011-07-13 15:48:43 -07001361 if (Intent.ACTION_VIEW.equals(intent.getAction())) {
1362 Tab t = getCurrentTab();
1363 Uri uri = intent.getData();
kaiyiz6e5b3e02013-08-19 20:02:01 +08001364 mUpdateMyNavThumbnail = true;
1365 mUpdateMyNavThumbnailUrl = uri.toString();
John Reckd3e4d5b2011-07-13 15:48:43 -07001366 loadUrl(t, uri.toString());
1367 } else if (intent.hasExtra(ComboViewActivity.EXTRA_OPEN_ALL)) {
1368 String[] urls = intent.getStringArrayExtra(
1369 ComboViewActivity.EXTRA_OPEN_ALL);
1370 Tab parent = getCurrentTab();
1371 for (String url : urls) {
kaiyiz47097d62013-08-09 09:30:28 +08001372 if (url != null) {
1373 parent = openTab(url, parent,
1374 !mSettings.openInBackground(), true);
1375 }
John Reckd3e4d5b2011-07-13 15:48:43 -07001376 }
1377 } else if (intent.hasExtra(ComboViewActivity.EXTRA_OPEN_SNAPSHOT)) {
1378 long id = intent.getLongExtra(
1379 ComboViewActivity.EXTRA_OPEN_SNAPSHOT, -1);
1380 if (id >= 0) {
Bijan Amirzada9b1e9882014-02-26 17:15:46 -08001381 createNewSnapshotTab(id, true);
John Reckd3e4d5b2011-07-13 15:48:43 -07001382 }
1383 }
1384 break;
Michael Kolb0b129122012-06-04 16:31:58 -07001385 case VOICE_RESULT:
1386 if (resultCode == Activity.RESULT_OK && intent != null) {
1387 ArrayList<String> results = intent.getStringArrayListExtra(
1388 RecognizerIntent.EXTRA_RESULTS);
1389 if (results.size() >= 1) {
1390 mVoiceResult = results.get(0);
1391 }
1392 }
1393 break;
kaiyiz6e5b3e02013-08-19 20:02:01 +08001394 case MY_NAVIGATION:
1395 if (intent == null || resultCode != Activity.RESULT_OK) {
1396 break;
1397 }
1398
1399 if (intent.getBooleanExtra("need_refresh", false) &&
1400 getCurrentTopWebView() != null) {
1401 getCurrentTopWebView().reload();
1402 }
1403 break;
Michael Kolb8233fac2010-10-26 16:08:53 -07001404 default:
1405 break;
1406 }
1407 getCurrentTopWebView().requestFocus();
1408 }
1409
1410 /**
1411 * Open the Go page.
1412 * @param startWithHistory If true, open starting on the history tab.
1413 * Otherwise, start with the bookmarks tab.
1414 */
1415 @Override
Michael Kolb315d5022011-10-13 12:47:11 -07001416 public void bookmarksOrHistoryPicker(ComboViews startView) {
Michael Kolb8233fac2010-10-26 16:08:53 -07001417 if (mTabControl.getCurrentWebView() == null) {
1418 return;
1419 }
Michael Kolbbd3dd942011-01-12 11:09:38 -08001420 // clear action mode
1421 if (isInCustomActionMode()) {
1422 endActionMode();
1423 }
Michael Kolb8233fac2010-10-26 16:08:53 -07001424 Bundle extras = new Bundle();
1425 // Disable opening in a new window if we have maxed out the windows
1426 extras.putBoolean(BrowserBookmarksPage.EXTRA_DISABLE_WINDOW,
1427 !mTabControl.canCreateNewTab());
Michael Kolb315d5022011-10-13 12:47:11 -07001428 mUi.showComboView(startView, extras);
Michael Kolb8233fac2010-10-26 16:08:53 -07001429 }
1430
1431 // combo view callbacks
1432
Michael Kolb8233fac2010-10-26 16:08:53 -07001433 // key handling
1434 protected void onBackKey() {
1435 if (!mUi.onBackKey()) {
1436 WebView subwindow = mTabControl.getCurrentSubWindow();
1437 if (subwindow != null) {
1438 if (subwindow.canGoBack()) {
1439 subwindow.goBack();
1440 } else {
1441 dismissSubWindow(mTabControl.getCurrentTab());
1442 }
1443 } else {
1444 goBackOnePageOrQuit();
1445 }
1446 }
1447 }
1448
Michael Kolb4bd767d2011-05-27 11:33:55 -07001449 protected boolean onMenuKey() {
1450 return mUi.onMenuKey();
Michael Kolb2814a362011-05-19 15:49:41 -07001451 }
1452
Michael Kolb8233fac2010-10-26 16:08:53 -07001453 // menu handling and state
1454 // TODO: maybe put into separate handler
1455
John Reck9c35b9c2012-05-30 10:08:50 -07001456 @Override
1457 public boolean onCreateOptionsMenu(Menu menu) {
John Reckd73c5a22010-12-22 10:22:50 -08001458 if (mMenuState == EMPTY_MENU) {
1459 return false;
1460 }
Michael Kolb8233fac2010-10-26 16:08:53 -07001461 MenuInflater inflater = mActivity.getMenuInflater();
1462 inflater.inflate(R.menu.browser, menu);
Michael Kolb8233fac2010-10-26 16:08:53 -07001463 return true;
1464 }
1465
John Reck9c35b9c2012-05-30 10:08:50 -07001466 @Override
1467 public void onCreateContextMenu(ContextMenu menu, View v,
Michael Kolb8233fac2010-10-26 16:08:53 -07001468 ContextMenuInfo menuInfo) {
John Reck0f602f32011-07-07 15:38:43 -07001469 if (v instanceof TitleBar) {
Michael Kolb8233fac2010-10-26 16:08:53 -07001470 return;
1471 }
1472 if (!(v instanceof WebView)) {
1473 return;
1474 }
Leon Scroggins026f2542010-11-22 13:26:12 -05001475 final WebView webview = (WebView) v;
Michael Kolb8233fac2010-10-26 16:08:53 -07001476 WebView.HitTestResult result = webview.getHitTestResult();
1477 if (result == null) {
1478 return;
1479 }
1480
1481 int type = result.getType();
1482 if (type == WebView.HitTestResult.UNKNOWN_TYPE) {
1483 Log.w(LOGTAG,
1484 "We should not show context menu when nothing is touched");
1485 return;
1486 }
1487 if (type == WebView.HitTestResult.EDIT_TEXT_TYPE) {
1488 // let TextView handles context menu
1489 return;
1490 }
1491
1492 // Note, http://b/issue?id=1106666 is requesting that
1493 // an inflated menu can be used again. This is not available
1494 // yet, so inflate each time (yuk!)
1495 MenuInflater inflater = mActivity.getMenuInflater();
1496 inflater.inflate(R.menu.browsercontext, menu);
1497
1498 // Show the correct menu group
1499 final String extra = result.getExtra();
kaiyiz6e5b3e02013-08-19 20:02:01 +08001500 final String navigationUrl = MyNavigationUtil.getMyNavigationUrl(extra);
Michael Kolbc159c1a2011-12-15 16:06:38 -08001501 if (extra == null) return;
Michael Kolb8233fac2010-10-26 16:08:53 -07001502 menu.setGroupVisible(R.id.PHONE_MENU,
1503 type == WebView.HitTestResult.PHONE_TYPE);
1504 menu.setGroupVisible(R.id.EMAIL_MENU,
1505 type == WebView.HitTestResult.EMAIL_TYPE);
1506 menu.setGroupVisible(R.id.GEO_MENU,
1507 type == WebView.HitTestResult.GEO_TYPE);
kaiyiz6e5b3e02013-08-19 20:02:01 +08001508 String itemUrl = null;
1509 String url = webview.getOriginalUrl();
1510 if (url != null && url.equalsIgnoreCase(MyNavigationUtil.MY_NAVIGATION)) {
1511 itemUrl = Uri.decode(navigationUrl);
1512 if (itemUrl != null && !MyNavigationUtil.isDefaultMyNavigation(itemUrl)) {
1513 menu.setGroupVisible(R.id.MY_NAVIGATION_MENU,
1514 type == WebView.HitTestResult.SRC_IMAGE_ANCHOR_TYPE);
1515 } else {
1516 menu.setGroupVisible(R.id.MY_NAVIGATION_MENU, false);
1517 }
1518 menu.setGroupVisible(R.id.IMAGE_MENU, false);
1519 menu.setGroupVisible(R.id.ANCHOR_MENU, false);
1520 } else {
1521 menu.setGroupVisible(R.id.MY_NAVIGATION_MENU, false);
1522
1523 menu.setGroupVisible(R.id.IMAGE_MENU,
1524 type == WebView.HitTestResult.IMAGE_TYPE
1525 || type == WebView.HitTestResult.SRC_IMAGE_ANCHOR_TYPE);
1526 menu.setGroupVisible(R.id.ANCHOR_MENU,
1527 type == WebView.HitTestResult.SRC_ANCHOR_TYPE
1528 || type == WebView.HitTestResult.SRC_IMAGE_ANCHOR_TYPE);
1529 }
Michael Kolb8233fac2010-10-26 16:08:53 -07001530 // Setup custom handling depending on the type
1531 switch (type) {
1532 case WebView.HitTestResult.PHONE_TYPE:
1533 menu.setHeaderTitle(Uri.decode(extra));
1534 menu.findItem(R.id.dial_context_menu_id).setIntent(
1535 new Intent(Intent.ACTION_VIEW, Uri
1536 .parse(WebView.SCHEME_TEL + extra)));
1537 Intent addIntent = new Intent(Intent.ACTION_INSERT_OR_EDIT);
1538 addIntent.putExtra(Insert.PHONE, Uri.decode(extra));
1539 addIntent.setType(ContactsContract.Contacts.CONTENT_ITEM_TYPE);
1540 menu.findItem(R.id.add_contact_context_menu_id).setIntent(
1541 addIntent);
1542 menu.findItem(R.id.copy_phone_context_menu_id)
1543 .setOnMenuItemClickListener(
1544 new Copy(extra));
1545 break;
1546
1547 case WebView.HitTestResult.EMAIL_TYPE:
1548 menu.setHeaderTitle(extra);
1549 menu.findItem(R.id.email_context_menu_id).setIntent(
1550 new Intent(Intent.ACTION_VIEW, Uri
1551 .parse(WebView.SCHEME_MAILTO + extra)));
1552 menu.findItem(R.id.copy_mail_context_menu_id)
1553 .setOnMenuItemClickListener(
1554 new Copy(extra));
1555 break;
1556
1557 case WebView.HitTestResult.GEO_TYPE:
1558 menu.setHeaderTitle(extra);
1559 menu.findItem(R.id.map_context_menu_id).setIntent(
1560 new Intent(Intent.ACTION_VIEW, Uri
1561 .parse(WebView.SCHEME_GEO
1562 + URLEncoder.encode(extra))));
1563 menu.findItem(R.id.copy_geo_context_menu_id)
1564 .setOnMenuItemClickListener(
1565 new Copy(extra));
1566 break;
1567
1568 case WebView.HitTestResult.SRC_ANCHOR_TYPE:
1569 case WebView.HitTestResult.SRC_IMAGE_ANCHOR_TYPE:
Michael Kolb4c537ce2011-01-13 15:19:33 -08001570 menu.setHeaderTitle(extra);
Michael Kolb8233fac2010-10-26 16:08:53 -07001571 // decide whether to show the open link in new tab option
1572 boolean showNewTab = mTabControl.canCreateNewTab();
1573 MenuItem newTabItem
1574 = menu.findItem(R.id.open_newtab_context_menu_id);
John Reck35e9dd62011-04-25 09:01:54 -07001575 newTabItem.setTitle(getSettings().openInBackground()
Michael Kolb2dd65c82011-01-14 11:07:38 -08001576 ? R.string.contextmenu_openlink_newwindow_background
1577 : R.string.contextmenu_openlink_newwindow);
Michael Kolb8233fac2010-10-26 16:08:53 -07001578 newTabItem.setVisible(showNewTab);
1579 if (showNewTab) {
Leon Scroggins026f2542010-11-22 13:26:12 -05001580 if (WebView.HitTestResult.SRC_IMAGE_ANCHOR_TYPE == type) {
1581 newTabItem.setOnMenuItemClickListener(
1582 new MenuItem.OnMenuItemClickListener() {
1583 @Override
1584 public boolean onMenuItemClick(MenuItem item) {
1585 final HashMap<String, WebView> hrefMap =
1586 new HashMap<String, WebView>();
1587 hrefMap.put("webview", webview);
1588 final Message msg = mHandler.obtainMessage(
1589 FOCUS_NODE_HREF,
1590 R.id.open_newtab_context_menu_id,
1591 0, hrefMap);
1592 webview.requestFocusNodeHref(msg);
1593 return true;
Michael Kolb8233fac2010-10-26 16:08:53 -07001594 }
Leon Scroggins026f2542010-11-22 13:26:12 -05001595 });
1596 } else {
1597 newTabItem.setOnMenuItemClickListener(
1598 new MenuItem.OnMenuItemClickListener() {
1599 @Override
1600 public boolean onMenuItemClick(MenuItem item) {
1601 final Tab parent = mTabControl.getCurrentTab();
John Reck5949c662011-05-27 09:52:29 -07001602 openTab(extra, parent,
1603 !mSettings.openInBackground(),
1604 true);
Leon Scroggins026f2542010-11-22 13:26:12 -05001605 return true;
1606 }
1607 });
1608 }
Michael Kolb8233fac2010-10-26 16:08:53 -07001609 }
kaiyiz6e5b3e02013-08-19 20:02:01 +08001610 if (url != null && url.equalsIgnoreCase(MyNavigationUtil.MY_NAVIGATION)) {
1611 menu.setHeaderTitle(navigationUrl);
1612 menu.findItem(R.id.open_newtab_context_menu_id).setVisible(false);
1613
1614 if (itemUrl != null) {
1615 if (!MyNavigationUtil.isDefaultMyNavigation(itemUrl)) {
1616 menu.findItem(R.id.edit_my_navigation_context_menu_id)
1617 .setOnMenuItemClickListener(new OnMenuItemClickListener() {
1618 @Override
1619 public boolean onMenuItemClick(MenuItem item) {
1620 final Intent intent = new Intent(Controller.this
1621 .getContext(),
1622 AddMyNavigationPage.class);
1623 Bundle bundle = new Bundle();
1624 String url = Uri.decode(navigationUrl);
1625 bundle.putBoolean("isAdding", false);
1626 bundle.putString("url", url);
1627 bundle.putString("name", getNameFromUrl(url));
1628 intent.putExtra("websites", bundle);
1629 mActivity.startActivityForResult(intent, MY_NAVIGATION);
1630 return false;
1631 }
1632 });
1633 menu.findItem(R.id.delete_my_navigation_context_menu_id)
1634 .setOnMenuItemClickListener(new OnMenuItemClickListener() {
1635 @Override
1636 public boolean onMenuItemClick(MenuItem item) {
1637 showMyNavigationDeleteDialog(Uri.decode(navigationUrl));
1638 return false;
1639 }
1640 });
1641 }
1642 } else {
1643 Log.e(LOGTAG, "mynavigation onCreateContextMenu itemUrl is null!");
1644 }
1645 }
Michael Kolb8233fac2010-10-26 16:08:53 -07001646 if (type == WebView.HitTestResult.SRC_ANCHOR_TYPE) {
1647 break;
1648 }
1649 // otherwise fall through to handle image part
1650 case WebView.HitTestResult.IMAGE_TYPE:
Victoria Lease5987b802012-03-12 13:05:23 -07001651 MenuItem shareItem = menu.findItem(R.id.share_link_context_menu_id);
1652 shareItem.setVisible(type == WebView.HitTestResult.IMAGE_TYPE);
Michael Kolb8233fac2010-10-26 16:08:53 -07001653 if (type == WebView.HitTestResult.IMAGE_TYPE) {
1654 menu.setHeaderTitle(extra);
Victoria Lease5987b802012-03-12 13:05:23 -07001655 shareItem.setOnMenuItemClickListener(
1656 new MenuItem.OnMenuItemClickListener() {
1657 @Override
1658 public boolean onMenuItemClick(MenuItem item) {
1659 sharePage(mActivity, null, extra, null,
1660 null);
1661 return true;
1662 }
1663 }
1664 );
Michael Kolb8233fac2010-10-26 16:08:53 -07001665 }
Michael Kolb3639c4c2011-09-28 15:36:40 -07001666 menu.findItem(R.id.view_image_context_menu_id)
1667 .setOnMenuItemClickListener(new OnMenuItemClickListener() {
1668 @Override
1669 public boolean onMenuItemClick(MenuItem item) {
1670 openTab(extra, mTabControl.getCurrentTab(), true, true);
1671 return false;
1672 }
1673 });
Andreas Sandblad8e4ce662012-06-11 11:02:49 +02001674 menu.findItem(R.id.download_context_menu_id).setOnMenuItemClickListener(
1675 new Download(mActivity, extra, webview.isPrivateBrowsingEnabled(),
1676 webview.getSettings().getUserAgentString()));
John Reck3527dd12011-02-22 10:35:29 -08001677 menu.findItem(R.id.set_wallpaper_context_menu_id).
1678 setOnMenuItemClickListener(new WallpaperHandler(mActivity,
1679 extra));
Michael Kolb8233fac2010-10-26 16:08:53 -07001680 break;
1681
1682 default:
1683 Log.w(LOGTAG, "We should not get here.");
1684 break;
1685 }
1686 //update the ui
1687 mUi.onContextMenuCreated(menu);
1688 }
1689
kaiyiz6e5b3e02013-08-19 20:02:01 +08001690 public void startAddMyNavigation(String url) {
1691 final Intent intent = new Intent(Controller.this.getContext(), AddMyNavigationPage.class);
1692 Bundle bundle = new Bundle();
1693 bundle.putBoolean("isAdding", true);
1694 bundle.putString("url", url);
1695 bundle.putString("name", getNameFromUrl(url));
1696 intent.putExtra("websites", bundle);
1697 mActivity.startActivityForResult(intent, MY_NAVIGATION);
1698 }
1699
1700 private void showMyNavigationDeleteDialog(final String itemUrl) {
1701 new AlertDialog.Builder(this.getContext())
1702 .setTitle(R.string.my_navigation_delete_label)
1703 .setIcon(android.R.drawable.ic_dialog_alert)
1704 .setMessage(R.string.my_navigation_delete_msg)
1705 .setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() {
1706 @Override
1707 public void onClick(DialogInterface dialog, int whichButton) {
1708 deleteMyNavigationItem(itemUrl);
1709 }
1710 })
1711 .setNegativeButton(R.string.cancel, null)
1712 .show();
1713 }
1714
1715 private void deleteMyNavigationItem(final String itemUrl) {
1716 ContentResolver cr = this.getContext().getContentResolver();
1717 Cursor cursor = null;
1718
1719 try {
1720 cursor = cr.query(MyNavigationUtil.MY_NAVIGATION_URI,
1721 new String[] {
1722 MyNavigationUtil.ID
1723 }, "url = ?", new String[] {
1724 itemUrl
1725 }, null);
1726 if (null != cursor && cursor.moveToFirst()) {
1727 Uri uri = ContentUris.withAppendedId(MyNavigationUtil.MY_NAVIGATION_URI,
1728 cursor.getLong(0));
1729
1730 ContentValues values = new ContentValues();
1731 values.put(MyNavigationUtil.TITLE, "");
1732 values.put(MyNavigationUtil.URL, "ae://" + cursor.getLong(0) + "add-fav");
1733 values.put(MyNavigationUtil.WEBSITE, 0 + "");
1734 ByteArrayOutputStream os = new ByteArrayOutputStream();
1735 Bitmap bm = BitmapFactory.decodeResource(this.getContext().getResources(),
1736 R.raw.my_navigation_add);
1737 bm.compress(Bitmap.CompressFormat.PNG, 100, os);
1738 values.put(MyNavigationUtil.THUMBNAIL, os.toByteArray());
1739 Log.d(LOGTAG, "deleteMyNavigationItem uri is : " + uri);
1740 cr.update(uri, values, null, null);
1741 } else {
1742 Log.e(LOGTAG, "deleteMyNavigationItem the item does not exist!");
1743 }
1744 } catch (IllegalStateException e) {
1745 Log.e(LOGTAG, "deleteMyNavigationItem", e);
1746 } finally {
1747 if (null != cursor) {
1748 cursor.close();
1749 }
1750 }
1751
1752 if (getCurrentTopWebView() != null) {
1753 getCurrentTopWebView().reload();
1754 }
1755 }
1756
1757 private String getNameFromUrl(String itemUrl) {
1758 ContentResolver cr = this.getContext().getContentResolver();
1759 Cursor cursor = null;
1760 String name = null;
1761
1762 try {
1763 cursor = cr.query(MyNavigationUtil.MY_NAVIGATION_URI,
1764 new String[] {
1765 MyNavigationUtil.TITLE
1766 }, "url = ?", new String[] {
1767 itemUrl
1768 }, null);
1769 if (null != cursor && cursor.moveToFirst()) {
1770 name = cursor.getString(0);
1771 } else {
1772 Log.e(LOGTAG, "this item does not exist!");
1773 }
1774 } catch (IllegalStateException e) {
1775 Log.e(LOGTAG, "getNameFromUrl", e);
1776 } finally {
1777 if (null != cursor) {
1778 cursor.close();
1779 }
1780 }
1781 return name;
1782 }
1783
1784 private void updateMyNavigationThumbnail(final String itemUrl, WebView webView) {
1785 int width = mActivity.getResources().getDimensionPixelOffset(
1786 R.dimen.myNavigationThumbnailWidth);
1787 int height = mActivity.getResources().getDimensionPixelOffset(
1788 R.dimen.myNavigationThumbnailHeight);
1789
1790 final Bitmap bm = createScreenshot(webView, width, height);
1791
1792 if (bm == null) {
1793 Log.e(LOGTAG, "updateMyNavigationThumbnail bm is null!");
1794 return;
1795 }
1796
1797 final ContentResolver cr = mActivity.getContentResolver();
1798 new AsyncTask<Void, Void, Void>() {
1799 @Override
1800 protected Void doInBackground(Void... unused) {
1801 ContentResolver cr = mActivity.getContentResolver();
1802 Cursor cursor = null;
1803 try {
1804 cursor = cr.query(MyNavigationUtil.MY_NAVIGATION_URI,
1805 new String[] {
1806 MyNavigationUtil.ID
1807 }, "url = ?", new String[] {
1808 itemUrl
1809 }, null);
1810 if (null != cursor && cursor.moveToFirst()) {
1811 final ByteArrayOutputStream os = new ByteArrayOutputStream();
1812 bm.compress(Bitmap.CompressFormat.PNG, 100, os);
1813
1814 ContentValues values = new ContentValues();
1815 values.put(MyNavigationUtil.THUMBNAIL, os.toByteArray());
1816 Uri uri = ContentUris.withAppendedId(MyNavigationUtil.MY_NAVIGATION_URI,
1817 cursor.getLong(0));
1818 Log.d(LOGTAG, "updateMyNavigationThumbnail uri is " + uri);
1819 cr.update(uri, values, null, null);
1820 os.close();
1821 }
1822 } catch (IllegalStateException e) {
1823 Log.e(LOGTAG, "updateMyNavigationThumbnail", e);
1824 } catch (IOException e) {
1825 Log.e(LOGTAG, "updateMyNavigationThumbnail", e);
1826 } finally {
1827 if (null != cursor) {
1828 cursor.close();
1829 }
1830 }
1831 return null;
1832 }
1833 }.execute();
1834 }
Michael Kolb8233fac2010-10-26 16:08:53 -07001835 /**
1836 * As the menu can be open when loading state changes
1837 * we must manually update the state of the stop/reload menu
1838 * item
1839 */
Michael Kolbb1fb70c2011-11-21 12:38:14 -08001840 private void updateInLoadMenuItems(Menu menu, Tab tab) {
Michael Kolb8233fac2010-10-26 16:08:53 -07001841 if (menu == null) {
1842 return;
1843 }
1844 MenuItem dest = menu.findItem(R.id.stop_reload_menu_id);
Michael Kolbb8337132011-11-28 15:07:39 -08001845 MenuItem src = ((tab != null) && tab.inPageLoad()) ?
Michael Kolb8233fac2010-10-26 16:08:53 -07001846 menu.findItem(R.id.stop_menu_id):
1847 menu.findItem(R.id.reload_menu_id);
1848 if (src != null) {
1849 dest.setIcon(src.getIcon());
1850 dest.setTitle(src.getTitle());
1851 }
1852 }
1853
John Reck9c35b9c2012-05-30 10:08:50 -07001854 @Override
1855 public boolean onPrepareOptionsMenu(Menu menu) {
Michael Kolbb1fb70c2011-11-21 12:38:14 -08001856 updateInLoadMenuItems(menu, getCurrentTab());
John Recke1a03a32011-09-14 17:04:16 -07001857 // hold on to the menu reference here; it is used by the page callbacks
1858 // to update the menu based on loading state
1859 mCachedMenu = menu;
Michael Kolb8233fac2010-10-26 16:08:53 -07001860 // Note: setVisible will decide whether an item is visible; while
1861 // setEnabled() will decide whether an item is enabled, which also means
1862 // whether the matching shortcut key will function.
1863 switch (mMenuState) {
1864 case EMPTY_MENU:
1865 if (mCurrentMenuState != mMenuState) {
1866 menu.setGroupVisible(R.id.MAIN_MENU, false);
1867 menu.setGroupEnabled(R.id.MAIN_MENU, false);
1868 menu.setGroupEnabled(R.id.MAIN_SHORTCUT_MENU, false);
1869 }
1870 break;
1871 default:
1872 if (mCurrentMenuState != mMenuState) {
1873 menu.setGroupVisible(R.id.MAIN_MENU, true);
1874 menu.setGroupEnabled(R.id.MAIN_MENU, true);
1875 menu.setGroupEnabled(R.id.MAIN_SHORTCUT_MENU, true);
1876 }
Michael Kolb4bf79712011-07-14 14:18:12 -07001877 updateMenuState(getCurrentTab(), menu);
Michael Kolb8233fac2010-10-26 16:08:53 -07001878 break;
1879 }
1880 mCurrentMenuState = mMenuState;
Michael Kolb1acef692011-03-08 14:12:06 -08001881 return mUi.onPrepareOptionsMenu(menu);
Michael Kolb8233fac2010-10-26 16:08:53 -07001882 }
1883
Michael Kolb4bf79712011-07-14 14:18:12 -07001884 @Override
1885 public void updateMenuState(Tab tab, Menu menu) {
1886 boolean canGoBack = false;
1887 boolean canGoForward = false;
John Reck42229bc2011-08-19 13:26:43 -07001888 boolean isDesktopUa = false;
John Recke1a03a32011-09-14 17:04:16 -07001889 boolean isLive = false;
Michael Kolb4bf79712011-07-14 14:18:12 -07001890 if (tab != null) {
1891 canGoBack = tab.canGoBack();
1892 canGoForward = tab.canGoForward();
John Reck42229bc2011-08-19 13:26:43 -07001893 isDesktopUa = mSettings.hasDesktopUseragent(tab.getWebView());
John Recke1a03a32011-09-14 17:04:16 -07001894 isLive = !tab.isSnapshot();
Michael Kolb4bf79712011-07-14 14:18:12 -07001895 }
1896 final MenuItem back = menu.findItem(R.id.back_menu_id);
1897 back.setEnabled(canGoBack);
1898
1899 final MenuItem home = menu.findItem(R.id.homepage_menu_id);
Michael Kolb4bf79712011-07-14 14:18:12 -07001900
1901 final MenuItem forward = menu.findItem(R.id.forward_menu_id);
1902 forward.setEnabled(canGoForward);
1903
Michael Kolbb1fb70c2011-11-21 12:38:14 -08001904 final MenuItem source = menu.findItem(isInLoad() ? R.id.stop_menu_id
1905 : R.id.reload_menu_id);
Michael Kolb4bf79712011-07-14 14:18:12 -07001906 final MenuItem dest = menu.findItem(R.id.stop_reload_menu_id);
Michael Kolb7ab75ee2011-07-14 16:36:38 -07001907 if (source != null && dest != null) {
1908 dest.setTitle(source.getTitle());
1909 dest.setIcon(source.getIcon());
1910 }
John Recke1a03a32011-09-14 17:04:16 -07001911 menu.setGroupVisible(R.id.NAV_MENU, isLive);
Michael Kolb4bf79712011-07-14 14:18:12 -07001912
1913 // decide whether to show the share link option
1914 PackageManager pm = mActivity.getPackageManager();
1915 Intent send = new Intent(Intent.ACTION_SEND);
1916 send.setType("text/plain");
1917 ResolveInfo ri = pm.resolveActivity(send,
1918 PackageManager.MATCH_DEFAULT_ONLY);
1919 menu.findItem(R.id.share_page_menu_id).setVisible(ri != null);
1920
1921 boolean isNavDump = mSettings.enableNavDump();
1922 final MenuItem nav = menu.findItem(R.id.dump_nav_menu_id);
1923 nav.setVisible(isNavDump);
1924 nav.setEnabled(isNavDump);
1925
1926 boolean showDebugSettings = mSettings.isDebugEnabled();
John Reck42229bc2011-08-19 13:26:43 -07001927 final MenuItem uaSwitcher = menu.findItem(R.id.ua_desktop_menu_id);
1928 uaSwitcher.setChecked(isDesktopUa);
John Recke1a03a32011-09-14 17:04:16 -07001929 menu.setGroupVisible(R.id.LIVE_MENU, isLive);
1930 menu.setGroupVisible(R.id.SNAPSHOT_MENU, !isLive);
kaiyiza8b6dbb2013-07-29 18:11:22 +08001931 // history and snapshots item are the members of COMBO menu group,
1932 // so if show history item, only make snapshots item invisible.
1933 menu.findItem(R.id.snapshots_menu_id).setVisible(false);
Michael Kolb4bf79712011-07-14 14:18:12 -07001934
Michael Kolb7bdee0b2011-08-01 11:55:38 -07001935 mUi.updateMenuState(tab, menu);
Michael Kolb4bf79712011-07-14 14:18:12 -07001936 }
1937
John Reck9c35b9c2012-05-30 10:08:50 -07001938 @Override
Michael Kolb8233fac2010-10-26 16:08:53 -07001939 public boolean onOptionsItemSelected(MenuItem item) {
Michael Kolb8233fac2010-10-26 16:08:53 -07001940 if (null == getCurrentTopWebView()) {
1941 return false;
1942 }
1943 if (mMenuIsDown) {
1944 // The shortcut action consumes the MENU. Even if it is still down,
1945 // it won't trigger the next shortcut action. In the case of the
1946 // shortcut action triggering a new activity, like Bookmarks, we
1947 // won't get onKeyUp for MENU. So it is important to reset it here.
1948 mMenuIsDown = false;
1949 }
Michael Kolb3ca12752011-07-20 13:52:25 -07001950 if (mUi.onOptionsItemSelected(item)) {
1951 // ui callback handled it
1952 return true;
1953 }
Michael Kolb8233fac2010-10-26 16:08:53 -07001954 switch (item.getItemId()) {
1955 // -- Main menu
1956 case R.id.new_tab_menu_id:
1957 openTabToHomePage();
1958 break;
1959
1960 case R.id.incognito_menu_id:
Michael Kolb519d2282011-05-09 17:03:19 -07001961 openIncognitoTab();
Michael Kolb8233fac2010-10-26 16:08:53 -07001962 break;
1963
Afzal Najamd4e33312012-04-26 01:54:01 -04001964 case R.id.close_other_tabs_id:
1965 closeOtherTabs();
1966 break;
1967
Michael Kolb8233fac2010-10-26 16:08:53 -07001968 case R.id.goto_menu_id:
1969 editUrl();
1970 break;
1971
1972 case R.id.bookmarks_menu_id:
Michael Kolb315d5022011-10-13 12:47:11 -07001973 bookmarksOrHistoryPicker(ComboViews.Bookmarks);
1974 break;
1975
1976 case R.id.history_menu_id:
1977 bookmarksOrHistoryPicker(ComboViews.History);
1978 break;
1979
1980 case R.id.snapshots_menu_id:
1981 bookmarksOrHistoryPicker(ComboViews.Snapshots);
Michael Kolb8233fac2010-10-26 16:08:53 -07001982 break;
1983
Michael Kolb8233fac2010-10-26 16:08:53 -07001984 case R.id.add_bookmark_menu_id:
Michael Kolb80f75082012-04-10 10:50:06 -07001985 bookmarkCurrentPage();
Michael Kolb8233fac2010-10-26 16:08:53 -07001986 break;
1987
1988 case R.id.stop_reload_menu_id:
Michael Kolbb1fb70c2011-11-21 12:38:14 -08001989 if (isInLoad()) {
Michael Kolb8233fac2010-10-26 16:08:53 -07001990 stopLoading();
1991 } else {
Bijan Amirzada9b1e9882014-02-26 17:15:46 -08001992 Tab currentTab = mTabControl.getCurrentTab();
1993 if (currentTab.hasCrashed) {
1994 currentTab.replaceCrashView(getCurrentTopWebView(),
1995 currentTab.getViewContainer());
1996 }
Michael Kolb8233fac2010-10-26 16:08:53 -07001997 getCurrentTopWebView().reload();
1998 }
1999 break;
2000
2001 case R.id.back_menu_id:
John Reckef654f12011-07-12 16:42:08 -07002002 getCurrentTab().goBack();
Michael Kolb8233fac2010-10-26 16:08:53 -07002003 break;
2004
2005 case R.id.forward_menu_id:
John Reckef654f12011-07-12 16:42:08 -07002006 getCurrentTab().goForward();
Michael Kolb8233fac2010-10-26 16:08:53 -07002007 break;
2008
2009 case R.id.close_menu_id:
2010 // Close the subwindow if it exists.
2011 if (mTabControl.getCurrentSubWindow() != null) {
2012 dismissSubWindow(mTabControl.getCurrentTab());
2013 break;
2014 }
2015 closeCurrentTab();
2016 break;
2017
kaiyiza8b6dbb2013-07-29 18:11:22 +08002018 case R.id.exit_menu_id:
Bijan Amirzada9b1e9882014-02-26 17:15:46 -08002019 Object[] params = { new String("persist.debug.browsermonkeytest")};
2020 Class[] type = new Class[] {String.class};
2021 String ret = (String)ReflectHelper.invokeStaticMethod(
2022 "android.os.SystemProperties","get", type, params);
kaiyiza8b6dbb2013-07-29 18:11:22 +08002023 if (ret != null && ret.equals("enable"))
2024 break;
luxiaolb40014b2013-07-19 10:01:43 +08002025 showExitDialog(mActivity);
2026 return true;
Michael Kolb8233fac2010-10-26 16:08:53 -07002027 case R.id.homepage_menu_id:
2028 Tab current = mTabControl.getCurrentTab();
John Reck26b18322011-06-21 13:08:58 -07002029 loadUrl(current, mSettings.getHomePage());
Michael Kolb8233fac2010-10-26 16:08:53 -07002030 break;
2031
2032 case R.id.preferences_menu_id:
Michael Kolb80f75082012-04-10 10:50:06 -07002033 openPreferences();
Michael Kolb8233fac2010-10-26 16:08:53 -07002034 break;
2035
2036 case R.id.find_menu_id:
Michael Kolbe11b9212012-04-13 13:39:54 -07002037 findOnPage();
Michael Kolb8233fac2010-10-26 16:08:53 -07002038 break;
2039
John Reck2bc80422011-06-30 15:11:49 -07002040 case R.id.save_snapshot_menu_id:
2041 final Tab source = getTabControl().getCurrentTab();
John Reckf33b1632011-06-04 20:00:23 -07002042 if (source == null) break;
John Reck68234a92012-04-19 15:27:12 -07002043 new SaveSnapshotTask(source).execute();
Leon Scrogginsac993842011-02-02 12:54:07 -05002044 break;
2045
Michael Kolb8233fac2010-10-26 16:08:53 -07002046 case R.id.page_info_menu_id:
Michael Kolb315d5022011-10-13 12:47:11 -07002047 showPageInfo();
Michael Kolb8233fac2010-10-26 16:08:53 -07002048 break;
2049
John Recke1a03a32011-09-14 17:04:16 -07002050 case R.id.snapshot_go_live:
2051 goLive();
2052 return true;
2053
Michael Kolb8233fac2010-10-26 16:08:53 -07002054 case R.id.share_page_menu_id:
2055 Tab currentTab = mTabControl.getCurrentTab();
2056 if (null == currentTab) {
Michael Kolb8233fac2010-10-26 16:08:53 -07002057 return false;
2058 }
Michael Kolbba99c5d2010-11-29 14:57:41 -08002059 shareCurrentPage(currentTab);
Michael Kolb8233fac2010-10-26 16:08:53 -07002060 break;
2061
2062 case R.id.dump_nav_menu_id:
2063 getCurrentTopWebView().debugDump();
2064 break;
2065
Michael Kolb8233fac2010-10-26 16:08:53 -07002066 case R.id.zoom_in_menu_id:
2067 getCurrentTopWebView().zoomIn();
2068 break;
2069
2070 case R.id.zoom_out_menu_id:
2071 getCurrentTopWebView().zoomOut();
2072 break;
2073
2074 case R.id.view_downloads_menu_id:
2075 viewDownloads();
2076 break;
2077
John Reck42229bc2011-08-19 13:26:43 -07002078 case R.id.ua_desktop_menu_id:
Michael Kolb80f75082012-04-10 10:50:06 -07002079 toggleUserAgent();
John Reck42229bc2011-08-19 13:26:43 -07002080 break;
2081
Michael Kolb8233fac2010-10-26 16:08:53 -07002082 case R.id.window_one_menu_id:
2083 case R.id.window_two_menu_id:
2084 case R.id.window_three_menu_id:
2085 case R.id.window_four_menu_id:
2086 case R.id.window_five_menu_id:
2087 case R.id.window_six_menu_id:
2088 case R.id.window_seven_menu_id:
2089 case R.id.window_eight_menu_id:
2090 {
2091 int menuid = item.getItemId();
2092 for (int id = 0; id < WINDOW_SHORTCUT_ID_ARRAY.length; id++) {
2093 if (WINDOW_SHORTCUT_ID_ARRAY[id] == menuid) {
2094 Tab desiredTab = mTabControl.getTab(id);
2095 if (desiredTab != null &&
2096 desiredTab != mTabControl.getCurrentTab()) {
Michael Kolbc831b632011-05-11 09:30:34 -07002097 switchToTab(desiredTab);
Michael Kolb8233fac2010-10-26 16:08:53 -07002098 }
2099 break;
2100 }
2101 }
2102 }
2103 break;
2104
2105 default:
2106 return false;
2107 }
Michael Kolb8233fac2010-10-26 16:08:53 -07002108 return true;
2109 }
2110
John Reck68234a92012-04-19 15:27:12 -07002111 private class SaveSnapshotTask extends AsyncTask<Void, Void, Long>
2112 implements OnCancelListener {
2113
2114 private Tab mTab;
2115 private Dialog mProgressDialog;
2116 private ContentValues mValues;
2117
2118 private SaveSnapshotTask(Tab tab) {
2119 mTab = tab;
2120 }
2121
2122 @Override
2123 protected void onPreExecute() {
2124 CharSequence message = mActivity.getText(R.string.saving_snapshot);
2125 mProgressDialog = ProgressDialog.show(mActivity, null, message,
2126 true, true, this);
2127 mValues = mTab.createSnapshotValues();
2128 }
2129
2130 @Override
2131 protected Long doInBackground(Void... params) {
2132 if (!mTab.saveViewState(mValues)) {
2133 return null;
2134 }
2135 if (isCancelled()) {
2136 String path = mValues.getAsString(Snapshots.VIEWSTATE_PATH);
2137 File file = mActivity.getFileStreamPath(path);
2138 if (!file.delete()) {
2139 file.deleteOnExit();
2140 }
2141 return null;
2142 }
2143 final ContentResolver cr = mActivity.getContentResolver();
2144 Uri result = cr.insert(Snapshots.CONTENT_URI, mValues);
2145 if (result == null) {
2146 return null;
2147 }
2148 long id = ContentUris.parseId(result);
2149 return id;
2150 }
2151
2152 @Override
2153 protected void onPostExecute(Long id) {
2154 if (isCancelled()) {
2155 return;
2156 }
2157 mProgressDialog.dismiss();
2158 if (id == null) {
2159 Toast.makeText(mActivity, R.string.snapshot_failed,
2160 Toast.LENGTH_SHORT).show();
2161 return;
2162 }
2163 Bundle b = new Bundle();
2164 b.putLong(BrowserSnapshotPage.EXTRA_ANIMATE_ID, id);
2165 mUi.showComboView(ComboViews.Snapshots, b);
2166 }
2167
2168 @Override
2169 public void onCancel(DialogInterface dialog) {
2170 cancel(true);
2171 }
2172 }
2173
Michael Kolb80f75082012-04-10 10:50:06 -07002174 @Override
2175 public void toggleUserAgent() {
2176 WebView web = getCurrentWebView();
2177 mSettings.toggleDesktopUseragent(web);
2178 web.loadUrl(web.getOriginalUrl());
2179 }
2180
2181 @Override
2182 public void findOnPage() {
2183 getCurrentTopWebView().showFindDialog(null, true);
2184 }
2185
2186 @Override
2187 public void openPreferences() {
2188 Intent intent = new Intent(mActivity, BrowserPreferencesPage.class);
2189 intent.putExtra(BrowserPreferencesPage.CURRENT_PAGE,
2190 getCurrentTopWebView().getUrl());
2191 mActivity.startActivityForResult(intent, PREFERENCES_PAGE);
2192 }
2193
2194 @Override
2195 public void bookmarkCurrentPage() {
2196 Intent bookmarkIntent = createBookmarkCurrentPageIntent(false);
2197 if (bookmarkIntent != null) {
2198 mActivity.startActivity(bookmarkIntent);
2199 }
2200 }
2201
John Recke1a03a32011-09-14 17:04:16 -07002202 private void goLive() {
Bijan Amirzada9b1e9882014-02-26 17:15:46 -08002203 SnapshotTab t = (SnapshotTab) getCurrentTab();
2204 t.loadUrl(t.getLiveUrl(), null);
John Recke1a03a32011-09-14 17:04:16 -07002205 }
2206
luxiaolb40014b2013-07-19 10:01:43 +08002207 private void showExitDialog(final Activity activity) {
2208 new AlertDialog.Builder(activity)
2209 .setTitle(R.string.exit_browser_title)
2210 .setIcon(android.R.drawable.ic_dialog_alert)
2211 .setMessage(R.string.exit_browser_msg)
2212 .setNegativeButton(R.string.exit_minimize, new DialogInterface.OnClickListener() {
2213 public void onClick(DialogInterface dialog, int which) {
2214 activity.moveTaskToBack(true);
2215 dialog.dismiss();
2216 }
2217 })
2218 .setPositiveButton(R.string.exit_quit, new DialogInterface.OnClickListener() {
2219 public void onClick(DialogInterface dialog, int which) {
2220 activity.finish();
2221 mHandler.postDelayed(new Runnable() {
2222 @Override
2223 public void run() {
2224 // TODO Auto-generated method stub
2225 mCrashRecoveryHandler.clearState(true);
2226 int pid = android.os.Process.myPid();
2227 android.os.Process.killProcess(pid);
2228 }
2229 }, 300);
2230 dialog.dismiss();
2231 }
2232 })
2233 .show();
2234 }
Michael Kolb315d5022011-10-13 12:47:11 -07002235 @Override
2236 public void showPageInfo() {
2237 mPageDialogsHandler.showPageInfo(mTabControl.getCurrentTab(), false, null);
2238 }
2239
John Reck9c35b9c2012-05-30 10:08:50 -07002240 @Override
Michael Kolb8233fac2010-10-26 16:08:53 -07002241 public boolean onContextItemSelected(MenuItem item) {
John Reckdbf57df2010-11-09 16:34:03 -08002242 // Let the History and Bookmark fragments handle menus they created.
2243 if (item.getGroupId() == R.id.CONTEXT_MENU) {
2244 return false;
2245 }
2246
Michael Kolb8233fac2010-10-26 16:08:53 -07002247 int id = item.getItemId();
2248 boolean result = true;
2249 switch (id) {
Michael Kolb8233fac2010-10-26 16:08:53 -07002250 // -- Browser context menu
2251 case R.id.open_context_menu_id:
Michael Kolb8233fac2010-10-26 16:08:53 -07002252 case R.id.save_link_context_menu_id:
Tarun Nainani700b69b2014-03-26 16:07:25 -07002253 case R.id.save_link_bookmark_context_menu_id:
Michael Kolb8233fac2010-10-26 16:08:53 -07002254 case R.id.copy_link_context_menu_id:
2255 final WebView webView = getCurrentTopWebView();
2256 if (null == webView) {
2257 result = false;
2258 break;
2259 }
2260 final HashMap<String, WebView> hrefMap =
2261 new HashMap<String, WebView>();
2262 hrefMap.put("webview", webView);
2263 final Message msg = mHandler.obtainMessage(
2264 FOCUS_NODE_HREF, id, 0, hrefMap);
2265 webView.requestFocusNodeHref(msg);
2266 break;
2267
2268 default:
2269 // For other context menus
2270 result = onOptionsItemSelected(item);
2271 }
Michael Kolb8233fac2010-10-26 16:08:53 -07002272 return result;
2273 }
2274
2275 /**
2276 * support programmatically opening the context menu
2277 */
2278 public void openContextMenu(View view) {
2279 mActivity.openContextMenu(view);
2280 }
2281
2282 /**
2283 * programmatically open the options menu
2284 */
2285 public void openOptionsMenu() {
2286 mActivity.openOptionsMenu();
2287 }
2288
John Reck9c35b9c2012-05-30 10:08:50 -07002289 @Override
Michael Kolb8233fac2010-10-26 16:08:53 -07002290 public boolean onMenuOpened(int featureId, Menu menu) {
2291 if (mOptionsMenuOpen) {
2292 if (mConfigChanged) {
2293 // We do not need to make any changes to the state of the
2294 // title bar, since the only thing that happened was a
2295 // change in orientation
2296 mConfigChanged = false;
2297 } else {
2298 if (!mExtendedMenuOpen) {
2299 mExtendedMenuOpen = true;
2300 mUi.onExtendedMenuOpened();
2301 } else {
2302 // Switching the menu back to icon view, so show the
2303 // title bar once again.
2304 mExtendedMenuOpen = false;
Michael Kolbb1fb70c2011-11-21 12:38:14 -08002305 mUi.onExtendedMenuClosed(isInLoad());
Michael Kolb8233fac2010-10-26 16:08:53 -07002306 }
2307 }
2308 } else {
2309 // The options menu is closed, so open it, and show the title
2310 mOptionsMenuOpen = true;
2311 mConfigChanged = false;
2312 mExtendedMenuOpen = false;
2313 mUi.onOptionsMenuOpened();
2314 }
2315 return true;
2316 }
2317
John Reck9c35b9c2012-05-30 10:08:50 -07002318 @Override
Michael Kolb8233fac2010-10-26 16:08:53 -07002319 public void onOptionsMenuClosed(Menu menu) {
2320 mOptionsMenuOpen = false;
Michael Kolbb1fb70c2011-11-21 12:38:14 -08002321 mUi.onOptionsMenuClosed(isInLoad());
Michael Kolb8233fac2010-10-26 16:08:53 -07002322 }
2323
John Reck9c35b9c2012-05-30 10:08:50 -07002324 @Override
Michael Kolb8233fac2010-10-26 16:08:53 -07002325 public void onContextMenuClosed(Menu menu) {
Michael Kolbb1fb70c2011-11-21 12:38:14 -08002326 mUi.onContextMenuClosed(menu, isInLoad());
Michael Kolb8233fac2010-10-26 16:08:53 -07002327 }
2328
2329 // Helper method for getting the top window.
2330 @Override
2331 public WebView getCurrentTopWebView() {
2332 return mTabControl.getCurrentTopWebView();
2333 }
2334
2335 @Override
2336 public WebView getCurrentWebView() {
2337 return mTabControl.getCurrentWebView();
2338 }
2339
2340 /*
2341 * This method is called as a result of the user selecting the options
2342 * menu to see the download window. It shows the download window on top of
2343 * the current window.
2344 */
2345 void viewDownloads() {
2346 Intent intent = new Intent(DownloadManager.ACTION_VIEW_DOWNLOADS);
2347 mActivity.startActivity(intent);
2348 }
2349
John Reck30b065e2011-07-19 10:58:05 -07002350 int getActionModeHeight() {
2351 TypedArray actionBarSizeTypedArray = mActivity.obtainStyledAttributes(
2352 new int[] { android.R.attr.actionBarSize });
2353 int size = (int) actionBarSizeTypedArray.getDimension(0, 0f);
2354 actionBarSizeTypedArray.recycle();
2355 return size;
2356 }
2357
Michael Kolb8233fac2010-10-26 16:08:53 -07002358 // action mode
2359
John Reck9c35b9c2012-05-30 10:08:50 -07002360 @Override
2361 public void onActionModeStarted(ActionMode mode) {
Michael Kolb8233fac2010-10-26 16:08:53 -07002362 mUi.onActionModeStarted(mode);
2363 mActionMode = mode;
2364 }
2365
2366 /*
2367 * True if a custom ActionMode (i.e. find or select) is in use.
2368 */
2369 @Override
2370 public boolean isInCustomActionMode() {
2371 return mActionMode != null;
2372 }
2373
2374 /*
2375 * End the current ActionMode.
2376 */
2377 @Override
2378 public void endActionMode() {
2379 if (mActionMode != null) {
2380 mActionMode.finish();
2381 }
2382 }
2383
2384 /*
2385 * Called by find and select when they are finished. Replace title bars
2386 * as necessary.
2387 */
John Reck9c35b9c2012-05-30 10:08:50 -07002388 @Override
Michael Kolb8233fac2010-10-26 16:08:53 -07002389 public void onActionModeFinished(ActionMode mode) {
2390 if (!isInCustomActionMode()) return;
Michael Kolbb1fb70c2011-11-21 12:38:14 -08002391 mUi.onActionModeFinished(isInLoad());
Michael Kolb8233fac2010-10-26 16:08:53 -07002392 mActionMode = null;
2393 }
2394
2395 boolean isInLoad() {
Michael Kolbc5b0b2d2011-11-29 16:13:35 -08002396 final Tab tab = getCurrentTab();
2397 return (tab != null) && tab.inPageLoad();
Michael Kolb8233fac2010-10-26 16:08:53 -07002398 }
2399
2400 // bookmark handling
2401
2402 /**
2403 * add the current page as a bookmark to the given folder id
2404 * @param folderId use -1 for the default folder
John Reckd3e4d5b2011-07-13 15:48:43 -07002405 * @param editExisting If true, check to see whether the site is already
Leon Scrogginsbdff8a72011-02-11 15:49:04 -05002406 * bookmarked, and if it is, edit that bookmark. If false, and
2407 * the site is already bookmarked, do not attempt to edit the
2408 * existing bookmark.
Michael Kolb8233fac2010-10-26 16:08:53 -07002409 */
2410 @Override
John Reckd3e4d5b2011-07-13 15:48:43 -07002411 public Intent createBookmarkCurrentPageIntent(boolean editExisting) {
John Recka60fffa2011-09-06 16:30:29 -07002412 WebView w = getCurrentTopWebView();
2413 if (w == null) {
2414 return null;
2415 }
Michael Kolb8233fac2010-10-26 16:08:53 -07002416 Intent i = new Intent(mActivity,
2417 AddBookmarkPage.class);
Michael Kolb8233fac2010-10-26 16:08:53 -07002418 i.putExtra(BrowserContract.Bookmarks.URL, w.getUrl());
2419 i.putExtra(BrowserContract.Bookmarks.TITLE, w.getTitle());
2420 String touchIconUrl = w.getTouchIconUrl();
2421 if (touchIconUrl != null) {
2422 i.putExtra(AddBookmarkPage.TOUCH_ICON_URL, touchIconUrl);
2423 WebSettings settings = w.getSettings();
2424 if (settings != null) {
2425 i.putExtra(AddBookmarkPage.USER_AGENT,
2426 settings.getUserAgentString());
2427 }
2428 }
2429 i.putExtra(BrowserContract.Bookmarks.THUMBNAIL,
2430 createScreenshot(w, getDesiredThumbnailWidth(mActivity),
2431 getDesiredThumbnailHeight(mActivity)));
2432 i.putExtra(BrowserContract.Bookmarks.FAVICON, w.getFavicon());
John Reckd3e4d5b2011-07-13 15:48:43 -07002433 if (editExisting) {
Leon Scrogginsbdff8a72011-02-11 15:49:04 -05002434 i.putExtra(AddBookmarkPage.CHECK_FOR_DUPE, true);
2435 }
Michael Kolb8233fac2010-10-26 16:08:53 -07002436 // Put the dialog at the upper right of the screen, covering the
2437 // star on the title bar.
2438 i.putExtra("gravity", Gravity.RIGHT | Gravity.TOP);
John Reckd3e4d5b2011-07-13 15:48:43 -07002439 return i;
Michael Kolb8233fac2010-10-26 16:08:53 -07002440 }
2441
2442 // file chooser
John Reck9c35b9c2012-05-30 10:08:50 -07002443 @Override
Ben Murdoch8cad4132012-01-11 10:56:43 +00002444 public void openFileChooser(ValueCallback<Uri> uploadMsg, String acceptType, String capture) {
Michael Kolb8233fac2010-10-26 16:08:53 -07002445 mUploadHandler = new UploadHandler(this);
Ben Murdoch8cad4132012-01-11 10:56:43 +00002446 mUploadHandler.openFileChooser(uploadMsg, acceptType, capture);
Michael Kolb8233fac2010-10-26 16:08:53 -07002447 }
2448
2449 // thumbnails
2450
2451 /**
2452 * Return the desired width for thumbnail screenshots, which are stored in
2453 * the database, and used on the bookmarks screen.
2454 * @param context Context for finding out the density of the screen.
2455 * @return desired width for thumbnail screenshot.
2456 */
2457 static int getDesiredThumbnailWidth(Context context) {
2458 return context.getResources().getDimensionPixelOffset(
2459 R.dimen.bookmarkThumbnailWidth);
2460 }
2461
2462 /**
2463 * Return the desired height for thumbnail screenshots, which are stored in
2464 * the database, and used on the bookmarks screen.
2465 * @param context Context for finding out the density of the screen.
2466 * @return desired height for thumbnail screenshot.
2467 */
2468 static int getDesiredThumbnailHeight(Context context) {
2469 return context.getResources().getDimensionPixelOffset(
2470 R.dimen.bookmarkThumbnailHeight);
2471 }
2472
John Reck8cc92352011-07-06 17:41:52 -07002473 static Bitmap createScreenshot(WebView view, int width, int height) {
Bijan Amirzada9b1e9882014-02-26 17:15:46 -08002474 if (view == null || width == 0 || height == 0) {
John Reckd7dd9b22011-08-30 09:18:29 -07002475 return null;
2476 }
Bijan Amirzada9b1e9882014-02-26 17:15:46 -08002477
2478 Bitmap viewportBitmap = view.getViewportBitmap();
2479 if (viewportBitmap == null) {
2480 return null;
2481 }
2482
2483 float aspectRatio = (float) width/height;
2484 int viewportWidth = viewportBitmap.getWidth();
2485 int viewportHeight = viewportBitmap.getHeight();
2486
2487 //modify the size to attain the same aspect ratio of desired thumbnail size
2488 if (viewportHeight > viewportWidth) {
2489 viewportHeight= (int)Math.round(viewportWidth * aspectRatio);
2490 } else {
2491 viewportWidth = (int)Math.round(viewportHeight * aspectRatio);
2492 }
2493
2494 Rect srcRect = new Rect(0, 0, viewportWidth, viewportHeight);
2495 Rect dstRect = new Rect(0, 0, width, height);
2496
2497 if (sThumbnailBitmap == null || sThumbnailBitmap.getWidth() != width
2498 || sThumbnailBitmap.getHeight() != height) {
John Reckd7dd9b22011-08-30 09:18:29 -07002499 if (sThumbnailBitmap != null) {
2500 sThumbnailBitmap.recycle();
2501 sThumbnailBitmap = null;
2502 }
Bijan Amirzada9b1e9882014-02-26 17:15:46 -08002503
2504 sThumbnailBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565);
Michael Kolb8233fac2010-10-26 16:08:53 -07002505 }
Bijan Amirzada9b1e9882014-02-26 17:15:46 -08002506
John Reckd7dd9b22011-08-30 09:18:29 -07002507 Canvas canvas = new Canvas(sThumbnailBitmap);
Bijan Amirzada9b1e9882014-02-26 17:15:46 -08002508 canvas.drawBitmap(viewportBitmap, srcRect, dstRect, new Paint(Paint.FILTER_BITMAP_FLAG));
John Reckd7dd9b22011-08-30 09:18:29 -07002509
Bijan Amirzada9b1e9882014-02-26 17:15:46 -08002510 return sThumbnailBitmap;
Michael Kolb8233fac2010-10-26 16:08:53 -07002511 }
2512
John Reck34ef2672011-02-10 11:30:55 -08002513 private void updateScreenshot(Tab tab) {
Michael Kolb8233fac2010-10-26 16:08:53 -07002514 // If this is a bookmarked site, add a screenshot to the database.
Michael Kolb8233fac2010-10-26 16:08:53 -07002515 // FIXME: Would like to make sure there is actually something to
2516 // draw, but the API for that (WebViewCore.pictureReady()) is not
2517 // currently accessible here.
2518
John Reck34ef2672011-02-10 11:30:55 -08002519 WebView view = tab.getWebView();
John Reck7a591202011-02-16 15:44:01 -08002520 if (view == null) {
2521 // Tab was destroyed
2522 return;
2523 }
John Reck34ef2672011-02-10 11:30:55 -08002524 final String url = tab.getUrl();
2525 final String originalUrl = view.getOriginalUrl();
kaiyiz6e5b3e02013-08-19 20:02:01 +08002526 final String thumbnailUrl = mUpdateMyNavThumbnailUrl;
John Reck34ef2672011-02-10 11:30:55 -08002527 if (TextUtils.isEmpty(url)) {
2528 return;
2529 }
2530
kaiyiz6e5b3e02013-08-19 20:02:01 +08002531 //update My Navigation Thumbnails
2532 boolean isMyNavigationUrl = MyNavigationUtil.isMyNavigationUrl(mActivity, url);
2533 if (isMyNavigationUrl) {
2534 updateMyNavigationThumbnail(url, view);
2535 }
John Reck34ef2672011-02-10 11:30:55 -08002536 // Only update thumbnails for web urls (http(s)://), not for
2537 // about:, javascript:, data:, etc...
2538 // Unless it is a bookmarked site, then always update
2539 if (!Patterns.WEB_URL.matcher(url).matches() && !tab.isBookmarkedSite()) {
2540 return;
2541 }
2542
kaiyiz6e5b3e02013-08-19 20:02:01 +08002543 if (url != null && mUpdateMyNavThumbnailUrl != null
2544 && Patterns.WEB_URL.matcher(url).matches()
2545 && Patterns.WEB_URL.matcher(mUpdateMyNavThumbnailUrl).matches()) {
2546 String urlHost = (new WebAddress(url)).getHost();
2547 String bookmarkHost = (new WebAddress(mUpdateMyNavThumbnailUrl)).getHost();
2548 if (urlHost == null || urlHost.length() == 0 || bookmarkHost == null
2549 || bookmarkHost.length() == 0) {
2550 return;
2551 }
2552 String urlDomain = urlHost.substring(urlHost.indexOf('.'), urlHost.length());
2553 String bookmarkDomain = bookmarkHost.substring(bookmarkHost.indexOf('.'),
2554 bookmarkHost.length());
2555 Log.d(LOGTAG, "addressUrl domain is " + urlDomain);
2556 Log.d(LOGTAG, "bookmarkUrl domain is " + bookmarkDomain);
2557 if (!bookmarkDomain.equals(urlDomain)) {
2558 return;
2559 }
2560 }
Michael Kolb8233fac2010-10-26 16:08:53 -07002561 final Bitmap bm = createScreenshot(view, getDesiredThumbnailWidth(mActivity),
2562 getDesiredThumbnailHeight(mActivity));
2563 if (bm == null) {
Bijan Amirzada9b1e9882014-02-26 17:15:46 -08002564 if (!mHandler.hasMessages(UPDATE_BOOKMARK_THUMBNAIL, tab)) {
2565 mHandler.sendMessageDelayed(mHandler.obtainMessage(
2566 UPDATE_BOOKMARK_THUMBNAIL, 0, 0, tab),
2567 500);
2568 }
Michael Kolb8233fac2010-10-26 16:08:53 -07002569 return;
2570 }
2571
2572 final ContentResolver cr = mActivity.getContentResolver();
John Reck34ef2672011-02-10 11:30:55 -08002573 new AsyncTask<Void, Void, Void>() {
2574 @Override
2575 protected Void doInBackground(Void... unused) {
2576 Cursor cursor = null;
2577 try {
2578 // TODO: Clean this up
kaiyiz6e5b3e02013-08-19 20:02:01 +08002579 cursor = Bookmarks.queryCombinedForUrl(cr, originalUrl,
2580 mUpdateMyNavThumbnail ? ((thumbnailUrl != null) ? thumbnailUrl : url)
2581 : url);
2582 if (mUpdateMyNavThumbnail) {
2583 mUpdateMyNavThumbnail = false;
2584 mUpdateMyNavThumbnailUrl = null;
2585 }
John Reck34ef2672011-02-10 11:30:55 -08002586 if (cursor != null && cursor.moveToFirst()) {
2587 final ByteArrayOutputStream os =
2588 new ByteArrayOutputStream();
2589 bm.compress(Bitmap.CompressFormat.PNG, 100, os);
Michael Kolb8233fac2010-10-26 16:08:53 -07002590
John Reck34ef2672011-02-10 11:30:55 -08002591 ContentValues values = new ContentValues();
2592 values.put(Images.THUMBNAIL, os.toByteArray());
Michael Kolb8233fac2010-10-26 16:08:53 -07002593
John Reck34ef2672011-02-10 11:30:55 -08002594 do {
John Reck617fd832011-02-16 14:35:59 -08002595 values.put(Images.URL, cursor.getString(0));
John Reck34ef2672011-02-10 11:30:55 -08002596 cr.update(Images.CONTENT_URI, values, null, null);
2597 } while (cursor.moveToNext());
Michael Kolb8233fac2010-10-26 16:08:53 -07002598 }
John Reck34ef2672011-02-10 11:30:55 -08002599 } catch (IllegalStateException e) {
2600 // Ignore
Mattias Nilsson561d1952011-10-04 10:18:50 +02002601 } catch (SQLiteException s) {
2602 // Added for possible error when user tries to remove the same bookmark
2603 // that is being updated with a screen shot
2604 Log.w(LOGTAG, "Error when running updateScreenshot ", s);
John Reck34ef2672011-02-10 11:30:55 -08002605 } finally {
2606 if (cursor != null) cursor.close();
Michael Kolb8233fac2010-10-26 16:08:53 -07002607 }
John Reck34ef2672011-02-10 11:30:55 -08002608 return null;
2609 }
2610 }.execute();
Michael Kolb8233fac2010-10-26 16:08:53 -07002611 }
2612
2613 private class Copy implements OnMenuItemClickListener {
2614 private CharSequence mText;
2615
John Reck9c35b9c2012-05-30 10:08:50 -07002616 @Override
Michael Kolb8233fac2010-10-26 16:08:53 -07002617 public boolean onMenuItemClick(MenuItem item) {
2618 copy(mText);
2619 return true;
2620 }
2621
2622 public Copy(CharSequence toCopy) {
2623 mText = toCopy;
2624 }
2625 }
2626
Leon Scroggins63c02662010-11-18 15:16:27 -05002627 private static class Download implements OnMenuItemClickListener {
2628 private Activity mActivity;
Michael Kolb8233fac2010-10-26 16:08:53 -07002629 private String mText;
Kristian Monsenbc5cc752011-03-02 13:14:03 +00002630 private boolean mPrivateBrowsing;
Andreas Sandblad8e4ce662012-06-11 11:02:49 +02002631 private String mUserAgent;
George Mount387d45d2011-10-07 15:57:53 -07002632 private static final String FALLBACK_EXTENSION = "dat";
2633 private static final String IMAGE_BASE_FORMAT = "yyyy-MM-dd-HH-mm-ss-";
Michael Kolb8233fac2010-10-26 16:08:53 -07002634
John Reck9c35b9c2012-05-30 10:08:50 -07002635 @Override
Michael Kolb8233fac2010-10-26 16:08:53 -07002636 public boolean onMenuItemClick(MenuItem item) {
George Mount387d45d2011-10-07 15:57:53 -07002637 if (DataUri.isDataUri(mText)) {
2638 saveDataUri();
2639 } else {
Andreas Sandblad8e4ce662012-06-11 11:02:49 +02002640 DownloadHandler.onDownloadStartNoStream(mActivity, mText, mUserAgent,
luxiaol62677b02013-07-22 07:54:49 +08002641 null, null, null, mPrivateBrowsing, 0);
George Mount387d45d2011-10-07 15:57:53 -07002642 }
Michael Kolb8233fac2010-10-26 16:08:53 -07002643 return true;
2644 }
2645
Andreas Sandblad8e4ce662012-06-11 11:02:49 +02002646 public Download(Activity activity, String toDownload, boolean privateBrowsing,
2647 String userAgent) {
Leon Scroggins63c02662010-11-18 15:16:27 -05002648 mActivity = activity;
Michael Kolb8233fac2010-10-26 16:08:53 -07002649 mText = toDownload;
Kristian Monsenbc5cc752011-03-02 13:14:03 +00002650 mPrivateBrowsing = privateBrowsing;
Andreas Sandblad8e4ce662012-06-11 11:02:49 +02002651 mUserAgent = userAgent;
Michael Kolb8233fac2010-10-26 16:08:53 -07002652 }
George Mount387d45d2011-10-07 15:57:53 -07002653
2654 /**
2655 * Treats mText as a data URI and writes its contents to a file
2656 * based on the current time.
2657 */
2658 private void saveDataUri() {
2659 FileOutputStream outputStream = null;
2660 try {
2661 DataUri uri = new DataUri(mText);
2662 File target = getTarget(uri);
2663 outputStream = new FileOutputStream(target);
2664 outputStream.write(uri.getData());
2665 final DownloadManager manager =
2666 (DownloadManager) mActivity.getSystemService(Context.DOWNLOAD_SERVICE);
2667 manager.addCompletedDownload(target.getName(),
2668 mActivity.getTitle().toString(), false,
2669 uri.getMimeType(), target.getAbsolutePath(),
John Reck9c35b9c2012-05-30 10:08:50 -07002670 uri.getData().length, true);
George Mount387d45d2011-10-07 15:57:53 -07002671 } catch (IOException e) {
2672 Log.e(LOGTAG, "Could not save data URL");
2673 } finally {
2674 if (outputStream != null) {
2675 try {
2676 outputStream.close();
2677 } catch (IOException e) {
2678 // ignore close errors
2679 }
2680 }
2681 }
2682 }
2683
2684 /**
2685 * Creates a File based on the current time stamp and uses
2686 * the mime type of the DataUri to get the extension.
2687 */
2688 private File getTarget(DataUri uri) throws IOException {
2689 File dir = mActivity.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS);
Johan Redestigaa676182012-10-03 13:33:01 +02002690 DateFormat format = new SimpleDateFormat(IMAGE_BASE_FORMAT, Locale.US);
George Mount387d45d2011-10-07 15:57:53 -07002691 String nameBase = format.format(new Date());
2692 String mimeType = uri.getMimeType();
2693 MimeTypeMap mimeTypeMap = MimeTypeMap.getSingleton();
2694 String extension = mimeTypeMap.getExtensionFromMimeType(mimeType);
2695 if (extension == null) {
2696 Log.w(LOGTAG, "Unknown mime type in data URI" + mimeType);
2697 extension = FALLBACK_EXTENSION;
2698 }
2699 extension = "." + extension; // createTempFile needs the '.'
2700 File targetFile = File.createTempFile(nameBase, extension, dir);
2701 return targetFile;
2702 }
Michael Kolb8233fac2010-10-26 16:08:53 -07002703 }
2704
Cary Clark8974d282010-11-22 10:46:05 -05002705 private static class SelectText implements OnMenuItemClickListener {
Bijan Amirzada9b1e9882014-02-26 17:15:46 -08002706 private WebView mWebView;
Cary Clark8974d282010-11-22 10:46:05 -05002707
John Reck9c35b9c2012-05-30 10:08:50 -07002708 @Override
Cary Clark8974d282010-11-22 10:46:05 -05002709 public boolean onMenuItemClick(MenuItem item) {
2710 if (mWebView != null) {
2711 return mWebView.selectText();
2712 }
2713 return false;
2714 }
2715
2716 public SelectText(WebView webView) {
Bijan Amirzada9b1e9882014-02-26 17:15:46 -08002717 mWebView = webView;
Cary Clark8974d282010-11-22 10:46:05 -05002718 }
2719
2720 }
2721
Michael Kolb8233fac2010-10-26 16:08:53 -07002722 /********************** TODO: UI stuff *****************************/
2723
2724 // these methods have been copied, they still need to be cleaned up
2725
2726 /****************** tabs ***************************************************/
2727
2728 // basic tab interactions:
2729
2730 // it is assumed that tabcontrol already knows about the tab
2731 protected void addTab(Tab tab) {
2732 mUi.addTab(tab);
2733 }
2734
2735 protected void removeTab(Tab tab) {
2736 mUi.removeTab(tab);
2737 mTabControl.removeTab(tab);
John Reck378a4102011-06-09 16:23:01 -07002738 mCrashRecoveryHandler.backupState();
Michael Kolb8233fac2010-10-26 16:08:53 -07002739 }
2740
Michael Kolbf2055602011-04-09 17:20:03 -07002741 @Override
2742 public void setActiveTab(Tab tab) {
Michael Kolbcd424e92011-02-24 10:26:26 -08002743 // monkey protection against delayed start
2744 if (tab != null) {
2745 mTabControl.setCurrentTab(tab);
2746 // the tab is guaranteed to have a webview after setCurrentTab
2747 mUi.setActiveTab(tab);
Bijan Amirzada9b1e9882014-02-26 17:15:46 -08002748 tab.setTimeStamp();
Michael Kolbcd424e92011-02-24 10:26:26 -08002749 }
Michael Kolb8233fac2010-10-26 16:08:53 -07002750 }
2751
John Reck8bcafc12011-08-29 16:43:02 -07002752 protected void closeEmptyTab() {
Michael Kolb8233fac2010-10-26 16:08:53 -07002753 Tab current = mTabControl.getCurrentTab();
2754 if (current != null
2755 && current.getWebView().copyBackForwardList().getSize() == 0) {
John Reck8bcafc12011-08-29 16:43:02 -07002756 closeCurrentTab();
Michael Kolb8233fac2010-10-26 16:08:53 -07002757 }
2758 }
2759
John Reck26b18322011-06-21 13:08:58 -07002760 protected void reuseTab(Tab appTab, UrlData urlData) {
Michael Kolb8233fac2010-10-26 16:08:53 -07002761 // Dismiss the subwindow if applicable.
2762 dismissSubWindow(appTab);
2763 // Since we might kill the WebView, remove it from the
2764 // content view first.
2765 mUi.detachTab(appTab);
2766 // Recreate the main WebView after destroying the old one.
John Reck30c714c2010-12-16 17:30:34 -08002767 mTabControl.recreateWebView(appTab);
Michael Kolb8233fac2010-10-26 16:08:53 -07002768 // TODO: analyze why the remove and add are necessary
2769 mUi.attachTab(appTab);
2770 if (mTabControl.getCurrentTab() != appTab) {
Michael Kolbc831b632011-05-11 09:30:34 -07002771 switchToTab(appTab);
John Reck30c714c2010-12-16 17:30:34 -08002772 loadUrlDataIn(appTab, urlData);
Michael Kolb8233fac2010-10-26 16:08:53 -07002773 } else {
2774 // If the tab was the current tab, we have to attach
2775 // it to the view system again.
2776 setActiveTab(appTab);
John Reck30c714c2010-12-16 17:30:34 -08002777 loadUrlDataIn(appTab, urlData);
Michael Kolb8233fac2010-10-26 16:08:53 -07002778 }
2779 }
2780
2781 // Remove the sub window if it exists. Also called by TabControl when the
2782 // user clicks the 'X' to dismiss a sub window.
John Reck9c35b9c2012-05-30 10:08:50 -07002783 @Override
Michael Kolb8233fac2010-10-26 16:08:53 -07002784 public void dismissSubWindow(Tab tab) {
2785 removeSubWindow(tab);
2786 // dismiss the subwindow. This will destroy the WebView.
2787 tab.dismissSubWindow();
Michael Kolbe8c97572011-11-21 14:03:56 -08002788 WebView wv = getCurrentTopWebView();
2789 if (wv != null) {
2790 wv.requestFocus();
2791 }
Michael Kolb8233fac2010-10-26 16:08:53 -07002792 }
2793
2794 @Override
2795 public void removeSubWindow(Tab t) {
2796 if (t.getSubWebView() != null) {
2797 mUi.removeSubWindow(t.getSubViewContainer());
2798 }
2799 }
2800
2801 @Override
2802 public void attachSubWindow(Tab tab) {
2803 if (tab.getSubWebView() != null) {
2804 mUi.attachSubWindow(tab.getSubViewContainer());
2805 getCurrentTopWebView().requestFocus();
2806 }
2807 }
2808
Mathew Inwood29721c22011-06-29 17:55:24 +01002809 private Tab showPreloadedTab(final UrlData urlData) {
2810 if (!urlData.isPreloaded()) {
2811 return null;
2812 }
2813 final PreloadedTabControl tabControl = urlData.getPreloadedTab();
2814 final String sbQuery = urlData.getSearchBoxQueryToSubmit();
2815 if (sbQuery != null) {
Mathew Inwood9ad1eac2011-09-15 11:29:50 +01002816 if (!tabControl.searchBoxSubmit(sbQuery, urlData.mUrl, urlData.mHeaders)) {
Mathew Inwood29721c22011-06-29 17:55:24 +01002817 // Could not submit query. Fallback to regular tab creation
2818 tabControl.destroy();
2819 return null;
2820 }
2821 }
Michael Kolbff6a7482011-07-26 16:37:15 -07002822 // check tab count and make room for new tab
2823 if (!mTabControl.canCreateNewTab()) {
2824 Tab leastUsed = mTabControl.getLeastUsedTab(getCurrentTab());
2825 if (leastUsed != null) {
2826 closeTab(leastUsed);
2827 }
2828 }
Mathew Inwood29721c22011-06-29 17:55:24 +01002829 Tab t = tabControl.getTab();
Mathew Inwoode09305e2011-09-02 12:03:26 +01002830 t.refreshIdAfterPreload();
Mathew Inwood29721c22011-06-29 17:55:24 +01002831 mTabControl.addPreloadedTab(t);
2832 addTab(t);
2833 setActiveTab(t);
2834 return t;
2835 }
2836
Michael Kolb7bcafde2011-05-09 13:55:59 -07002837 // open a non inconito tab with the given url data
2838 // and set as active tab
2839 public Tab openTab(UrlData urlData) {
Mathew Inwood29721c22011-06-29 17:55:24 +01002840 Tab tab = showPreloadedTab(urlData);
2841 if (tab == null) {
2842 tab = createNewTab(false, true, true);
Michael Kolb14612442011-06-24 13:06:29 -07002843 if ((tab != null) && !urlData.isEmpty()) {
2844 loadUrlDataIn(tab, urlData);
2845 }
Michael Kolb7bcafde2011-05-09 13:55:59 -07002846 }
Mathew Inwood29721c22011-06-29 17:55:24 +01002847 return tab;
Michael Kolb7bcafde2011-05-09 13:55:59 -07002848 }
2849
Michael Kolb843510f2010-12-09 10:51:49 -08002850 @Override
2851 public Tab openTabToHomePage() {
Michael Kolb7bcafde2011-05-09 13:55:59 -07002852 return openTab(mSettings.getHomePage(), false, true, false);
Michael Kolb8233fac2010-10-26 16:08:53 -07002853 }
2854
Michael Kolb8233fac2010-10-26 16:08:53 -07002855 @Override
Michael Kolb519d2282011-05-09 17:03:19 -07002856 public Tab openIncognitoTab() {
2857 return openTab(INCOGNITO_URI, true, true, false);
2858 }
2859
2860 @Override
Michael Kolb7bcafde2011-05-09 13:55:59 -07002861 public Tab openTab(String url, boolean incognito, boolean setActive,
2862 boolean useCurrent) {
John Reck5949c662011-05-27 09:52:29 -07002863 return openTab(url, incognito, setActive, useCurrent, null);
2864 }
2865
2866 @Override
2867 public Tab openTab(String url, Tab parent, boolean setActive,
2868 boolean useCurrent) {
2869 return openTab(url, (parent != null) && parent.isPrivateBrowsingEnabled(),
2870 setActive, useCurrent, parent);
2871 }
2872
2873 public Tab openTab(String url, boolean incognito, boolean setActive,
2874 boolean useCurrent, Tab parent) {
Michael Kolb7bcafde2011-05-09 13:55:59 -07002875 Tab tab = createNewTab(incognito, setActive, useCurrent);
2876 if (tab != null) {
John Reck5949c662011-05-27 09:52:29 -07002877 if (parent != null && parent != tab) {
2878 parent.addChildTab(tab);
2879 }
Michael Kolb519d2282011-05-09 17:03:19 -07002880 if (url != null) {
John Reck26b18322011-06-21 13:08:58 -07002881 loadUrl(tab, url);
Michael Kolb519d2282011-05-09 17:03:19 -07002882 }
Michael Kolb8233fac2010-10-26 16:08:53 -07002883 }
Michael Kolb7bcafde2011-05-09 13:55:59 -07002884 return tab;
2885 }
2886
2887 // this method will attempt to create a new tab
2888 // incognito: private browsing tab
2889 // setActive: ste tab as current tab
2890 // useCurrent: if no new tab can be created, return current tab
2891 private Tab createNewTab(boolean incognito, boolean setActive,
2892 boolean useCurrent) {
2893 Tab tab = null;
Bijan Amirzada9b1e9882014-02-26 17:15:46 -08002894 MemoryMonitor memMonitor = null;
Michael Kolb7bcafde2011-05-09 13:55:59 -07002895 if (mTabControl.canCreateNewTab()) {
Bijan Amirzada9b1e9882014-02-26 17:15:46 -08002896 if (mSettings.enableMemoryMonitor()) {
2897 Log.d(LOGTAG, " Memory Monitor Enabled .");
2898 memMonitor = MemoryMonitor.getInstance(mActivity.getApplicationContext(),this);
2899 if (memMonitor != null) {
2900 //Remove webview associated with the oldest tab
2901 memMonitor.destroyLeastRecentlyActiveTab();
2902 }
2903 } else {
2904 Log.d(LOGTAG, " Memory Monitor disabled .");
2905 }
Michael Kolb7bcafde2011-05-09 13:55:59 -07002906 tab = mTabControl.createNewTab(incognito);
2907 addTab(tab);
Bijan Amirzada9b1e9882014-02-26 17:15:46 -08002908 tab.setTimeStamp();
Michael Kolb7bcafde2011-05-09 13:55:59 -07002909 if (setActive) {
2910 setActiveTab(tab);
2911 }
2912 } else {
2913 if (useCurrent) {
2914 tab = mTabControl.getCurrentTab();
John Reck26b18322011-06-21 13:08:58 -07002915 reuseTab(tab, null);
Michael Kolb7bcafde2011-05-09 13:55:59 -07002916 } else {
2917 mUi.showMaxTabsWarning();
2918 }
2919 }
2920 return tab;
Michael Kolb8233fac2010-10-26 16:08:53 -07002921 }
2922
John Reck2bc80422011-06-30 15:11:49 -07002923 @Override
2924 public SnapshotTab createNewSnapshotTab(long snapshotId, boolean setActive) {
2925 SnapshotTab tab = null;
2926 if (mTabControl.canCreateNewTab()) {
2927 tab = mTabControl.createSnapshotTab(snapshotId);
2928 addTab(tab);
2929 if (setActive) {
2930 setActiveTab(tab);
2931 }
2932 } else {
2933 mUi.showMaxTabsWarning();
John Reckd8c74522011-06-14 08:45:00 -07002934 }
2935 return tab;
2936 }
2937
Michael Kolb8233fac2010-10-26 16:08:53 -07002938 /**
Michael Kolbc831b632011-05-11 09:30:34 -07002939 * @param tab the tab to switch to
Michael Kolb8233fac2010-10-26 16:08:53 -07002940 * @return boolean True if we successfully switched to a different tab. If
2941 * the indexth tab is null, or if that tab is the same as
2942 * the current one, return false.
2943 */
2944 @Override
Michael Kolbc831b632011-05-11 09:30:34 -07002945 public boolean switchToTab(Tab tab) {
Michael Kolb8233fac2010-10-26 16:08:53 -07002946 Tab currentTab = mTabControl.getCurrentTab();
2947 if (tab == null || tab == currentTab) {
2948 return false;
2949 }
2950 setActiveTab(tab);
2951 return true;
2952 }
2953
2954 @Override
Michael Kolb8233fac2010-10-26 16:08:53 -07002955 public void closeCurrentTab() {
Michael Kolb2ae6ef72011-08-22 14:49:34 -07002956 closeCurrentTab(false);
2957 }
2958
2959 protected void closeCurrentTab(boolean andQuit) {
Michael Kolb8233fac2010-10-26 16:08:53 -07002960 if (mTabControl.getTabCount() == 1) {
John Reckbc490d22011-07-22 15:04:59 -07002961 mCrashRecoveryHandler.clearState();
Michael Kolbc1eeb122011-08-01 09:56:26 -07002962 mTabControl.removeTab(getCurrentTab());
John Reck958b2422010-12-03 17:56:17 -08002963 mActivity.finish();
Michael Kolb8233fac2010-10-26 16:08:53 -07002964 return;
2965 }
Michael Kolbc831b632011-05-11 09:30:34 -07002966 final Tab current = mTabControl.getCurrentTab();
2967 final int pos = mTabControl.getCurrentPosition();
2968 Tab newTab = current.getParent();
2969 if (newTab == null) {
2970 newTab = mTabControl.getTab(pos + 1);
2971 if (newTab == null) {
2972 newTab = mTabControl.getTab(pos - 1);
Michael Kolb8233fac2010-10-26 16:08:53 -07002973 }
2974 }
Michael Kolb2ae6ef72011-08-22 14:49:34 -07002975 if (andQuit) {
2976 mTabControl.setCurrentTab(newTab);
2977 closeTab(current);
2978 } else if (switchToTab(newTab)) {
Michael Kolb8233fac2010-10-26 16:08:53 -07002979 // Close window
2980 closeTab(current);
2981 }
2982 }
2983
2984 /**
2985 * Close the tab, remove its associated title bar, and adjust mTabControl's
2986 * current tab to a valid value.
2987 */
2988 @Override
2989 public void closeTab(Tab tab) {
John Reck28263772011-10-11 17:13:42 -07002990 if (tab == mTabControl.getCurrentTab()) {
2991 closeCurrentTab();
2992 } else {
2993 removeTab(tab);
2994 }
Michael Kolb8233fac2010-10-26 16:08:53 -07002995 }
2996
Afzal Najamd4e33312012-04-26 01:54:01 -04002997 /**
2998 * Close all tabs except the current one
2999 */
3000 @Override
3001 public void closeOtherTabs() {
3002 int inactiveTabs = mTabControl.getTabCount() - 1;
3003 for (int i = inactiveTabs; i >= 0; i--) {
3004 Tab tab = mTabControl.getTab(i);
3005 if (tab != mTabControl.getCurrentTab()) {
3006 removeTab(tab);
3007 }
3008 }
3009 }
3010
Michael Kolb8233fac2010-10-26 16:08:53 -07003011 // Called when loading from context menu or LOAD_URL message
John Reck26b18322011-06-21 13:08:58 -07003012 protected void loadUrlFromContext(String url) {
3013 Tab tab = getCurrentTab();
3014 WebView view = tab != null ? tab.getWebView() : null;
Michael Kolb8233fac2010-10-26 16:08:53 -07003015 // In case the user enters nothing.
John Reck26b18322011-06-21 13:08:58 -07003016 if (url != null && url.length() != 0 && tab != null && view != null) {
Michael Kolb8233fac2010-10-26 16:08:53 -07003017 url = UrlUtils.smartUrlFilter(url);
Jonathan Dixone1d6dfc2012-12-17 13:39:17 -08003018 if (!((BrowserWebView) view).getWebViewClient().
Jonathan Dixon4d2fcab2012-02-24 00:13:06 +00003019 shouldOverrideUrlLoading(view, url)) {
John Reck26b18322011-06-21 13:08:58 -07003020 loadUrl(tab, url);
Michael Kolb8233fac2010-10-26 16:08:53 -07003021 }
3022 }
3023 }
3024
3025 /**
3026 * Load the URL into the given WebView and update the title bar
3027 * to reflect the new load. Call this instead of WebView.loadUrl
3028 * directly.
3029 * @param view The WebView used to load url.
3030 * @param url The URL to load.
3031 */
John Reck71e51422011-07-01 16:49:28 -07003032 @Override
3033 public void loadUrl(Tab tab, String url) {
John Reck26b18322011-06-21 13:08:58 -07003034 loadUrl(tab, url, null);
3035 }
3036
3037 protected void loadUrl(Tab tab, String url, Map<String, String> headers) {
3038 if (tab != null) {
3039 dismissSubWindow(tab);
3040 tab.loadUrl(url, headers);
Bijan Amirzada9b1e9882014-02-26 17:15:46 -08003041 if (tab.hasCrashed) {
3042 tab.replaceCrashView(tab.getWebView(), tab.getViewContainer());
3043 }
Michael Kolba53c9892011-10-05 13:31:40 -07003044 mUi.onProgressChanged(tab);
John Reck26b18322011-06-21 13:08:58 -07003045 }
Michael Kolb8233fac2010-10-26 16:08:53 -07003046 }
3047
3048 /**
3049 * Load UrlData into a Tab and update the title bar to reflect the new
3050 * load. Call this instead of UrlData.loadIn directly.
3051 * @param t The Tab used to load.
3052 * @param data The UrlData being loaded.
3053 */
3054 protected void loadUrlDataIn(Tab t, UrlData data) {
John Reck26b18322011-06-21 13:08:58 -07003055 if (data != null) {
Michael Kolb5ff5c8b2012-05-03 11:37:58 -07003056 if (data.isPreloaded()) {
Michael Kolb14612442011-06-24 13:06:29 -07003057 // this isn't called for preloaded tabs
John Reck26b18322011-06-21 13:08:58 -07003058 } else {
John Reck38b39652012-06-05 09:22:59 -07003059 if (t != null && data.mDisableUrlOverride) {
3060 t.disableUrlOverridingForLoad();
3061 }
John Reck26b18322011-06-21 13:08:58 -07003062 loadUrl(t, data.mUrl, data.mHeaders);
3063 }
3064 }
Michael Kolb8233fac2010-10-26 16:08:53 -07003065 }
3066
John Reck30c714c2010-12-16 17:30:34 -08003067 @Override
3068 public void onUserCanceledSsl(Tab tab) {
John Reck30c714c2010-12-16 17:30:34 -08003069 // TODO: Figure out the "right" behavior
John Reckef654f12011-07-12 16:42:08 -07003070 if (tab.canGoBack()) {
3071 tab.goBack();
John Reck30c714c2010-12-16 17:30:34 -08003072 } else {
John Reckef654f12011-07-12 16:42:08 -07003073 tab.loadUrl(mSettings.getHomePage(), null);
John Reck30c714c2010-12-16 17:30:34 -08003074 }
Michael Kolb8233fac2010-10-26 16:08:53 -07003075 }
3076
3077 void goBackOnePageOrQuit() {
3078 Tab current = mTabControl.getCurrentTab();
3079 if (current == null) {
3080 /*
3081 * Instead of finishing the activity, simply push this to the back
3082 * of the stack and let ActivityManager to choose the foreground
3083 * activity. As BrowserActivity is singleTask, it will be always the
3084 * root of the task. So we can use either true or false for
3085 * moveTaskToBack().
3086 */
luxiaolb40014b2013-07-19 10:01:43 +08003087 showExitDialog(mActivity);
Michael Kolb8233fac2010-10-26 16:08:53 -07003088 return;
3089 }
John Reckef654f12011-07-12 16:42:08 -07003090 if (current.canGoBack()) {
3091 current.goBack();
Michael Kolb8233fac2010-10-26 16:08:53 -07003092 } else {
3093 // Check to see if we are closing a window that was created by
3094 // another window. If so, we switch back to that window.
Michael Kolbc831b632011-05-11 09:30:34 -07003095 Tab parent = current.getParent();
Michael Kolb8233fac2010-10-26 16:08:53 -07003096 if (parent != null) {
Michael Kolbc831b632011-05-11 09:30:34 -07003097 switchToTab(parent);
Michael Kolb8233fac2010-10-26 16:08:53 -07003098 // Now we close the other tab
3099 closeTab(current);
3100 } else {
Michael Kolb8233fac2010-10-26 16:08:53 -07003101 /*
3102 * Instead of finishing the activity, simply push this to the back
3103 * of the stack and let ActivityManager to choose the foreground
3104 * activity. As BrowserActivity is singleTask, it will be always the
3105 * root of the task. So we can use either true or false for
3106 * moveTaskToBack().
3107 */
luxiaolb40014b2013-07-19 10:01:43 +08003108 showExitDialog(mActivity);
Michael Kolb8233fac2010-10-26 16:08:53 -07003109 }
3110 }
3111 }
3112
3113 /**
Michael Kolb0035fad2011-03-14 13:25:28 -07003114 * helper method for key handler
3115 * returns the current tab if it can't advance
3116 */
Michael Kolbc831b632011-05-11 09:30:34 -07003117 private Tab getNextTab() {
Michael Kolbf5261da2011-12-15 15:07:35 -08003118 int pos = mTabControl.getCurrentPosition() + 1;
3119 if (pos >= mTabControl.getTabCount()) {
3120 pos = 0;
3121 }
3122 return mTabControl.getTab(pos);
Michael Kolb0035fad2011-03-14 13:25:28 -07003123 }
3124
3125 /**
3126 * helper method for key handler
3127 * returns the current tab if it can't advance
3128 */
Michael Kolbc831b632011-05-11 09:30:34 -07003129 private Tab getPrevTab() {
Michael Kolbf5261da2011-12-15 15:07:35 -08003130 int pos = mTabControl.getCurrentPosition() - 1;
3131 if ( pos < 0) {
3132 pos = mTabControl.getTabCount() - 1;
3133 }
3134 return mTabControl.getTab(pos);
Michael Kolb0035fad2011-03-14 13:25:28 -07003135 }
3136
John Reckbcef87f2012-02-03 14:58:34 -08003137 boolean isMenuOrCtrlKey(int keyCode) {
3138 return (KeyEvent.KEYCODE_MENU == keyCode)
3139 || (KeyEvent.KEYCODE_CTRL_LEFT == keyCode)
3140 || (KeyEvent.KEYCODE_CTRL_RIGHT == keyCode);
3141 }
3142
Michael Kolb0035fad2011-03-14 13:25:28 -07003143 /**
Michael Kolb8233fac2010-10-26 16:08:53 -07003144 * handle key events in browser
3145 *
3146 * @param keyCode
3147 * @param event
3148 * @return true if handled, false to pass to super
3149 */
John Reck9c35b9c2012-05-30 10:08:50 -07003150 @Override
3151 public boolean onKeyDown(int keyCode, KeyEvent event) {
Cary Clark160bbb92011-01-10 11:17:07 -05003152 boolean noModifiers = event.hasNoModifiers();
Michael Kolb8233fac2010-10-26 16:08:53 -07003153 // Even if MENU is already held down, we need to call to super to open
3154 // the IME on long press.
John Reckbcef87f2012-02-03 14:58:34 -08003155 if (!noModifiers && isMenuOrCtrlKey(keyCode)) {
Michael Kolb8233fac2010-10-26 16:08:53 -07003156 mMenuIsDown = true;
3157 return false;
3158 }
Michael Kolb8233fac2010-10-26 16:08:53 -07003159
Cary Clark8ff8c662010-12-29 15:03:05 -05003160 WebView webView = getCurrentTopWebView();
John Reckef654f12011-07-12 16:42:08 -07003161 Tab tab = getCurrentTab();
3162 if (webView == null || tab == null) return false;
Cary Clark8ff8c662010-12-29 15:03:05 -05003163
Cary Clark160bbb92011-01-10 11:17:07 -05003164 boolean ctrl = event.hasModifiers(KeyEvent.META_CTRL_ON);
3165 boolean shift = event.hasModifiers(KeyEvent.META_SHIFT_ON);
Cary Clark8ff8c662010-12-29 15:03:05 -05003166
Michael Kolb8233fac2010-10-26 16:08:53 -07003167 switch(keyCode) {
Michael Kolb0035fad2011-03-14 13:25:28 -07003168 case KeyEvent.KEYCODE_TAB:
3169 if (event.isCtrlPressed()) {
3170 if (event.isShiftPressed()) {
3171 // prev tab
Michael Kolbc831b632011-05-11 09:30:34 -07003172 switchToTab(getPrevTab());
Michael Kolb0035fad2011-03-14 13:25:28 -07003173 } else {
3174 // next tab
Michael Kolbc831b632011-05-11 09:30:34 -07003175 switchToTab(getNextTab());
Michael Kolb0035fad2011-03-14 13:25:28 -07003176 }
3177 return true;
3178 }
3179 break;
Michael Kolb8233fac2010-10-26 16:08:53 -07003180 case KeyEvent.KEYCODE_SPACE:
3181 // WebView/WebTextView handle the keys in the KeyDown. As
3182 // the Activity's shortcut keys are only handled when WebView
3183 // doesn't, have to do it in onKeyDown instead of onKeyUp.
Cary Clark160bbb92011-01-10 11:17:07 -05003184 if (shift) {
Michael Kolb8233fac2010-10-26 16:08:53 -07003185 pageUp();
Cary Clark160bbb92011-01-10 11:17:07 -05003186 } else if (noModifiers) {
Michael Kolb8233fac2010-10-26 16:08:53 -07003187 pageDown();
3188 }
3189 return true;
3190 case KeyEvent.KEYCODE_BACK:
Cary Clark160bbb92011-01-10 11:17:07 -05003191 if (!noModifiers) break;
John Recke6bf4ab2011-02-24 15:48:05 -08003192 event.startTracking();
3193 return true;
Michael Kolbe9e1d4a2011-07-14 15:02:17 -07003194 case KeyEvent.KEYCODE_FORWARD:
3195 if (!noModifiers) break;
3196 tab.goForward();
3197 return true;
Cary Clark8ff8c662010-12-29 15:03:05 -05003198 case KeyEvent.KEYCODE_DPAD_LEFT:
3199 if (ctrl) {
John Reckef654f12011-07-12 16:42:08 -07003200 tab.goBack();
Cary Clark8ff8c662010-12-29 15:03:05 -05003201 return true;
3202 }
3203 break;
3204 case KeyEvent.KEYCODE_DPAD_RIGHT:
3205 if (ctrl) {
John Reckef654f12011-07-12 16:42:08 -07003206 tab.goForward();
Cary Clark8ff8c662010-12-29 15:03:05 -05003207 return true;
3208 }
3209 break;
3210 case KeyEvent.KEYCODE_A:
Bijan Amirzada9b1e9882014-02-26 17:15:46 -08003211 if (ctrl) {
3212 webView.selectAll();
Cary Clark8ff8c662010-12-29 15:03:05 -05003213 return true;
3214 }
3215 break;
Michael Kolba4183062011-01-16 10:43:21 -08003216// case KeyEvent.KEYCODE_B: // menu
Cary Clark8ff8c662010-12-29 15:03:05 -05003217 case KeyEvent.KEYCODE_C:
Bijan Amirzada9b1e9882014-02-26 17:15:46 -08003218 if (ctrl ) {
3219 webView.copySelection();
Cary Clark8ff8c662010-12-29 15:03:05 -05003220 return true;
3221 }
3222 break;
Michael Kolba4183062011-01-16 10:43:21 -08003223// case KeyEvent.KEYCODE_D: // menu
Cary Clark8ff8c662010-12-29 15:03:05 -05003224// case KeyEvent.KEYCODE_E: // in Chrome: puts '?' in URL bar
Michael Kolba4183062011-01-16 10:43:21 -08003225// case KeyEvent.KEYCODE_F: // menu
Cary Clark8ff8c662010-12-29 15:03:05 -05003226// case KeyEvent.KEYCODE_G: // in Chrome: finds next match
Michael Kolba4183062011-01-16 10:43:21 -08003227// case KeyEvent.KEYCODE_H: // menu
Cary Clark8ff8c662010-12-29 15:03:05 -05003228// case KeyEvent.KEYCODE_I: // unused
Michael Kolba4183062011-01-16 10:43:21 -08003229// case KeyEvent.KEYCODE_J: // menu
Cary Clark8ff8c662010-12-29 15:03:05 -05003230// case KeyEvent.KEYCODE_K: // in Chrome: puts '?' in URL bar
Michael Kolba4183062011-01-16 10:43:21 -08003231// case KeyEvent.KEYCODE_L: // menu
Cary Clark8ff8c662010-12-29 15:03:05 -05003232// case KeyEvent.KEYCODE_M: // unused
3233// case KeyEvent.KEYCODE_N: // in Chrome: new window
3234// case KeyEvent.KEYCODE_O: // in Chrome: open file
3235// case KeyEvent.KEYCODE_P: // in Chrome: print page
3236// case KeyEvent.KEYCODE_Q: // unused
Michael Kolbdc2ee1b2011-02-14 14:34:40 -08003237// case KeyEvent.KEYCODE_R:
Cary Clark8ff8c662010-12-29 15:03:05 -05003238// case KeyEvent.KEYCODE_S: // in Chrome: saves page
3239 case KeyEvent.KEYCODE_T:
Michael Kolbdc2ee1b2011-02-14 14:34:40 -08003240 // we can't use the ctrl/shift flags, they check for
3241 // exclusive use of a modifier
3242 if (event.isCtrlPressed()) {
Cary Clark8ff8c662010-12-29 15:03:05 -05003243 if (event.isShiftPressed()) {
Michael Kolb519d2282011-05-09 17:03:19 -07003244 openIncognitoTab();
Cary Clark8ff8c662010-12-29 15:03:05 -05003245 } else {
3246 openTabToHomePage();
3247 }
3248 return true;
3249 }
3250 break;
3251// case KeyEvent.KEYCODE_U: // in Chrome: opens source of page
3252// case KeyEvent.KEYCODE_V: // text view intercepts to paste
Michael Kolb5ae15bd2011-08-16 17:09:27 -07003253// case KeyEvent.KEYCODE_W: // menu
Cary Clark8ff8c662010-12-29 15:03:05 -05003254// case KeyEvent.KEYCODE_X: // text view intercepts to cut
3255// case KeyEvent.KEYCODE_Y: // unused
3256// case KeyEvent.KEYCODE_Z: // unused
Michael Kolb8233fac2010-10-26 16:08:53 -07003257 }
Michael Kolbdc2ee1b2011-02-14 14:34:40 -08003258 // it is a regular key and webview is not null
3259 return mUi.dispatchKey(keyCode, event);
Michael Kolb8233fac2010-10-26 16:08:53 -07003260 }
3261
John Reck9c35b9c2012-05-30 10:08:50 -07003262 @Override
3263 public boolean onKeyLongPress(int keyCode, KeyEvent event) {
John Recke6bf4ab2011-02-24 15:48:05 -08003264 switch(keyCode) {
3265 case KeyEvent.KEYCODE_BACK:
John Reck3ba45532011-08-11 16:26:53 -07003266 if (mUi.isWebShowing()) {
Michael Kolb315d5022011-10-13 12:47:11 -07003267 bookmarksOrHistoryPicker(ComboViews.History);
John Recke6bf4ab2011-02-24 15:48:05 -08003268 return true;
3269 }
3270 break;
3271 }
3272 return false;
3273 }
3274
John Reck9c35b9c2012-05-30 10:08:50 -07003275 @Override
3276 public boolean onKeyUp(int keyCode, KeyEvent event) {
John Reckbcef87f2012-02-03 14:58:34 -08003277 if (isMenuOrCtrlKey(keyCode)) {
Michael Kolb2814a362011-05-19 15:49:41 -07003278 mMenuIsDown = false;
John Reckbcef87f2012-02-03 14:58:34 -08003279 if (KeyEvent.KEYCODE_MENU == keyCode
3280 && event.isTracking() && !event.isCanceled()) {
Michael Kolb4bd767d2011-05-27 11:33:55 -07003281 return onMenuKey();
Michael Kolb2814a362011-05-19 15:49:41 -07003282 }
3283 }
Cary Clark160bbb92011-01-10 11:17:07 -05003284 if (!event.hasNoModifiers()) return false;
Michael Kolb8233fac2010-10-26 16:08:53 -07003285 switch(keyCode) {
Michael Kolb8233fac2010-10-26 16:08:53 -07003286 case KeyEvent.KEYCODE_BACK:
3287 if (event.isTracking() && !event.isCanceled()) {
3288 onBackKey();
3289 return true;
3290 }
3291 break;
3292 }
3293 return false;
3294 }
3295
3296 public boolean isMenuDown() {
3297 return mMenuIsDown;
3298 }
3299
John Reck9c35b9c2012-05-30 10:08:50 -07003300 @Override
Ben Murdoch8029a772010-11-16 11:58:21 +00003301 public void setupAutoFill(Message message) {
3302 // Open the settings activity at the AutoFill profile fragment so that
3303 // the user can create a new profile. When they return, we will dispatch
3304 // the message so that we can autofill the form using their new profile.
3305 Intent intent = new Intent(mActivity, BrowserPreferencesPage.class);
3306 intent.putExtra(PreferenceActivity.EXTRA_SHOW_FRAGMENT,
3307 AutoFillSettingsFragment.class.getName());
3308 mAutoFillSetupMessage = message;
3309 mActivity.startActivityForResult(intent, AUTOFILL_SETUP);
3310 }
John Reckb3417f02011-01-14 11:01:05 -08003311
John Reck9c35b9c2012-05-30 10:08:50 -07003312 @Override
Michael Kolbfbc579a2011-07-07 15:59:33 -07003313 public boolean onSearchRequested() {
Michael Kolb1f9b3562012-04-24 14:38:34 -07003314 mUi.editUrl(false, true);
Michael Kolbfbc579a2011-07-07 15:59:33 -07003315 return true;
3316 }
3317
John Reck1cf4b792011-07-26 10:22:22 -07003318 @Override
3319 public boolean shouldCaptureThumbnails() {
3320 return mUi.shouldCaptureThumbnails();
3321 }
3322
Michael Kolbc3af0672011-08-09 10:24:41 -07003323 @Override
Michael Kolb0b129122012-06-04 16:31:58 -07003324 public boolean supportsVoice() {
3325 PackageManager pm = mActivity.getPackageManager();
3326 List activities = pm.queryIntentActivities(new Intent(
3327 RecognizerIntent.ACTION_RECOGNIZE_SPEECH), 0);
3328 return activities.size() != 0;
3329 }
3330
3331 @Override
3332 public void startVoiceRecognizer() {
3333 Intent voice = new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH);
Bijan Amirzada9b1e9882014-02-26 17:15:46 -08003334 voice.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL,
Michael Kolb0b129122012-06-04 16:31:58 -07003335 RecognizerIntent.LANGUAGE_MODEL_FREE_FORM);
3336 voice.putExtra(RecognizerIntent.EXTRA_MAX_RESULTS, 1);
3337 mActivity.startActivityForResult(voice, VOICE_RESULT);
3338 }
3339
3340 @Override
Michael Kolbc3af0672011-08-09 10:24:41 -07003341 public void setBlockEvents(boolean block) {
3342 mBlockEvents = block;
3343 }
3344
John Reck9c35b9c2012-05-30 10:08:50 -07003345 @Override
Michael Kolbc3af0672011-08-09 10:24:41 -07003346 public boolean dispatchKeyEvent(KeyEvent event) {
Michael Kolb87357642011-08-24 14:19:18 -07003347 return mBlockEvents;
Michael Kolbc3af0672011-08-09 10:24:41 -07003348 }
3349
John Reck9c35b9c2012-05-30 10:08:50 -07003350 @Override
Michael Kolbc3af0672011-08-09 10:24:41 -07003351 public boolean dispatchKeyShortcutEvent(KeyEvent event) {
Michael Kolb87357642011-08-24 14:19:18 -07003352 return mBlockEvents;
Michael Kolbc3af0672011-08-09 10:24:41 -07003353 }
3354
John Reck9c35b9c2012-05-30 10:08:50 -07003355 @Override
Michael Kolbc3af0672011-08-09 10:24:41 -07003356 public boolean dispatchTouchEvent(MotionEvent ev) {
Michael Kolb87357642011-08-24 14:19:18 -07003357 return mBlockEvents;
Michael Kolbc3af0672011-08-09 10:24:41 -07003358 }
3359
John Reck9c35b9c2012-05-30 10:08:50 -07003360 @Override
Michael Kolbc3af0672011-08-09 10:24:41 -07003361 public boolean dispatchTrackballEvent(MotionEvent ev) {
Michael Kolb87357642011-08-24 14:19:18 -07003362 return mBlockEvents;
Michael Kolbc3af0672011-08-09 10:24:41 -07003363 }
3364
John Reck9c35b9c2012-05-30 10:08:50 -07003365 @Override
Michael Kolbc3af0672011-08-09 10:24:41 -07003366 public boolean dispatchGenericMotionEvent(MotionEvent ev) {
Michael Kolb87357642011-08-24 14:19:18 -07003367 return mBlockEvents;
Michael Kolbc3af0672011-08-09 10:24:41 -07003368 }
3369
Michael Kolb8233fac2010-10-26 16:08:53 -07003370}