diff options
Diffstat (limited to 'mobile/android/base/GeckoApp.java')
-rw-r--r-- | mobile/android/base/GeckoApp.java | 2466 |
1 files changed, 0 insertions, 2466 deletions
diff --git a/mobile/android/base/GeckoApp.java b/mobile/android/base/GeckoApp.java deleted file mode 100644 index df436f5f8..000000000 --- a/mobile/android/base/GeckoApp.java +++ /dev/null @@ -1,2466 +0,0 @@ -/* -*- Mode: Java; c-basic-offset: 4; tab-width: 4; indent-tabs-mode: nil; -*- - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -package org.mozilla.gecko; - -import org.mozilla.gecko.DataReportingNotification; -import org.mozilla.gecko.db.BrowserDB; -import org.mozilla.gecko.gfx.BitmapUtils; -import org.mozilla.gecko.gfx.Layer; -import org.mozilla.gecko.gfx.LayerView; -import org.mozilla.gecko.gfx.PluginLayer; -import org.mozilla.gecko.menu.GeckoMenu; -import org.mozilla.gecko.menu.GeckoMenuInflater; -import org.mozilla.gecko.menu.MenuPanel; -// import org.mozilla.gecko.health.BrowserHealthRecorder; -// import org.mozilla.gecko.health.BrowserHealthRecorder.SessionInformation; -import org.mozilla.gecko.updater.UpdateService; -import org.mozilla.gecko.updater.UpdateServiceHelper; -import org.mozilla.gecko.util.EventDispatcher; -import org.mozilla.gecko.util.GeckoEventListener; -import org.mozilla.gecko.util.GeckoEventResponder; -import org.mozilla.gecko.util.HardwareUtils; -import org.mozilla.gecko.util.ThreadUtils; -import org.mozilla.gecko.util.UiAsyncTask; - -import org.json.JSONArray; -import org.json.JSONException; -import org.json.JSONObject; - -import android.app.Activity; -import android.app.AlertDialog; -import android.app.Dialog; -import android.app.Notification; -import android.app.PendingIntent; -import android.app.WallpaperManager; -import android.content.Context; -import android.content.DialogInterface; -import android.content.Intent; -import android.content.SharedPreferences; -import android.content.pm.PackageManager.NameNotFoundException; -import android.content.res.Configuration; -import android.graphics.Bitmap; -import android.graphics.BitmapFactory; -import android.graphics.Point; -import android.graphics.Rect; -import android.hardware.Sensor; -import android.hardware.SensorEvent; -import android.hardware.SensorEventListener; -import android.location.Location; -import android.location.LocationListener; -import android.net.Uri; -import android.os.Build; -import android.os.Bundle; -import android.os.Handler; -import android.os.PowerManager; -import android.os.StrictMode; -import android.preference.PreferenceManager; -import android.provider.ContactsContract; - -import android.text.TextUtils; -import android.util.AttributeSet; -import android.util.Base64; -import android.util.Log; -import android.util.SparseBooleanArray; -import android.view.Display; -import android.view.Gravity; -import android.view.KeyEvent; -import android.view.LayoutInflater; -import android.view.Menu; -import android.view.MenuInflater; -import android.view.MenuItem; -import android.view.MotionEvent; -import android.view.OrientationEventListener; -import android.view.Surface; -import android.view.SurfaceHolder; -import android.view.SurfaceView; -import android.view.TextureView; -import android.view.View; -import android.view.ViewGroup; -import android.view.Window; -import android.view.WindowManager; -import android.widget.AbsoluteLayout; -import android.widget.FrameLayout; -import android.widget.ListView; -import android.widget.RelativeLayout; -import android.widget.SimpleAdapter; -import android.widget.TextView; -import android.widget.Toast; - -import java.io.BufferedReader; -import java.io.ByteArrayOutputStream; -import java.io.File; -import java.io.FileReader; -import java.io.IOException; -import java.io.InputStream; -import java.net.HttpURLConnection; -import java.net.URL; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.Iterator; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -abstract public class GeckoApp - extends GeckoActivity - implements GeckoEventListener, SensorEventListener, LocationListener, - Tabs.OnTabsChangedListener, GeckoEventResponder, - GeckoMenu.Callback, GeckoMenu.MenuPresenter, - ContextGetter, GeckoAppShell.GeckoInterface -{ - private static final String LOGTAG = "GeckoApp"; - - private static enum StartupAction { - NORMAL, /* normal application start */ - URL, /* launched with a passed URL */ - PREFETCH /* launched with a passed URL that we prefetch */ - } - - public static final String ACTION_ALERT_CALLBACK = "org.mozilla.gecko.ACTION_ALERT_CALLBACK"; - public static final String ACTION_WEBAPP_PREFIX = "org.mozilla.gecko.WEBAPP"; - public static final String ACTION_DEBUG = "org.mozilla.gecko.DEBUG"; - public static final String ACTION_BOOKMARK = "org.mozilla.gecko.BOOKMARK"; - public static final String ACTION_LOAD = "org.mozilla.gecko.LOAD"; - public static final String ACTION_LAUNCH_SETTINGS = "org.mozilla.gecko.SETTINGS"; - public static final String ACTION_INIT_PW = "org.mozilla.gecko.INIT_PW"; - public static final String SAVED_STATE_INTENT_HANDLED = "intentHandled"; - public static final String SAVED_STATE_IN_BACKGROUND = "inBackground"; - public static final String SAVED_STATE_PRIVATE_SESSION = "privateSession"; - - public static final String PREFS_NAME = "GeckoApp"; - public static final String PREFS_OOM_EXCEPTION = "OOMException"; - public static final String PREFS_WAS_STOPPED = "wasStopped"; - public static final String PREFS_CRASHED = "crashed"; - public static final String PREFS_VERSION_CODE = "versionCode"; - - static public final int RESTORE_NONE = 0; - static public final int RESTORE_NORMAL = 1; - static public final int RESTORE_CRASH = 2; - - protected RelativeLayout mMainLayout; - protected RelativeLayout mGeckoLayout; - public View getView() { return mGeckoLayout; } - private View mCameraView; - private OrientationEventListener mCameraOrientationEventListener; - public List<GeckoAppShell.AppStateListener> mAppStateListeners; - private static GeckoApp sAppContext; - protected MenuPanel mMenuPanel; - protected Menu mMenu; - private static GeckoThread sGeckoThread; - private GeckoProfile mProfile; - public static int mOrientation; - protected boolean mIsRestoringActivity; - private boolean mIntentHandled; - private String mCurrentResponse = ""; - public static boolean sIsUsingCustomProfile = false; - - private PromptService mPromptService; - private TextSelection mTextSelection; - - protected DoorHangerPopup mDoorHangerPopup; - protected FormAssistPopup mFormAssistPopup; - protected TabsPanel mTabsPanel; - - // Handles notification messages from javascript - protected NotificationHelper mNotificationHelper; - - protected LayerView mLayerView; - private AbsoluteLayout mPluginContainer; - - private FullScreenHolder mFullScreenPluginContainer; - private View mFullScreenPluginView; - - private HashMap<String, PowerManager.WakeLock> mWakeLocks = new HashMap<String, PowerManager.WakeLock>(); - - protected int mRestoreMode = RESTORE_NONE; - protected boolean mInitialized = false; - - private String mPrivateBrowsingSession; - -// private volatile BrowserHealthRecorder mHealthRecorder = null; - - abstract public int getLayout(); - abstract public boolean hasTabsSideBar(); - abstract protected String getDefaultProfileName(); - - private static final String RESTARTER_ACTION = "org.mozilla.gecko.restart"; - private static final String RESTARTER_CLASS = "org.mozilla.gecko.Restarter"; - - @SuppressWarnings("serial") - class SessionRestoreException extends Exception { - public SessionRestoreException(Exception e) { - super(e); - } - - public SessionRestoreException(String message) { - super(message); - } - } - - void toggleChrome(final boolean aShow) { } - - void focusChrome() { } - - public Context getContext() { - return sAppContext; - } - - public Activity getActivity() { - return this; - } - - public LocationListener getLocationListener() { - return this; - } - - public SensorEventListener getSensorEventListener() { - return this; - } - - public static SharedPreferences getAppSharedPreferences() { - return GeckoApp.sAppContext.getSharedPreferences(PREFS_NAME, 0); - } - - public View getCameraView() { - return mCameraView; - } - - public void addAppStateListener(GeckoAppShell.AppStateListener listener) { - mAppStateListeners.add(listener); - } - - public void removeAppStateListener(GeckoAppShell.AppStateListener listener) { - mAppStateListeners.remove(listener); - } - - public FormAssistPopup getFormAssistPopup() { - return mFormAssistPopup; - } - - @Override - public void onTabChanged(Tab tab, Tabs.TabEvents msg, Object data) { - // When a tab is closed, it is always unselected first. - // When a tab is unselected, another tab is always selected first. - switch(msg) { - case UNSELECTED: - hidePlugins(tab); - break; - - case LOCATION_CHANGE: - // We only care about location change for the selected tab. - if (!Tabs.getInstance().isSelectedTab(tab)) - break; - // Fall through... - case SELECTED: - invalidateOptionsMenu(); - if (mFormAssistPopup != null) - mFormAssistPopup.hide(); - break; - - case LOADED: - // Sync up the layer view and the tab if the tab is - // currently displayed. - LayerView layerView = mLayerView; - if (layerView != null && Tabs.getInstance().isSelectedTab(tab)) - layerView.setBackgroundColor(tab.getBackgroundColor()); - break; - - case DESKTOP_MODE_CHANGE: - if (Tabs.getInstance().isSelectedTab(tab)) - invalidateOptionsMenu(); - break; - } - } - - public void refreshChrome() { } - - @Override - public void invalidateOptionsMenu() { - if (mMenu == null) - return; - - onPrepareOptionsMenu(mMenu); - - if (Build.VERSION.SDK_INT >= 11) - super.invalidateOptionsMenu(); - } - - @Override - public boolean onCreateOptionsMenu(Menu menu) { - mMenu = menu; - - MenuInflater inflater = getMenuInflater(); - inflater.inflate(R.menu.gecko_app_menu, mMenu); - return true; - } - - @Override - public MenuInflater getMenuInflater() { - if (Build.VERSION.SDK_INT >= 11) - return new GeckoMenuInflater(this); - else - return super.getMenuInflater(); - } - - public MenuPanel getMenuPanel() { - return mMenuPanel; - } - - @Override - public boolean onMenuItemSelected(MenuItem item) { - return onOptionsItemSelected(item); - } - - @Override - public void openMenu() { - openOptionsMenu(); - } - - @Override - public void showMenu(View menu) { - // Hide the menu only if we are showing the MenuPopup. - if (!HardwareUtils.hasMenuButton()) - closeMenu(); - - mMenuPanel.removeAllViews(); - mMenuPanel.addView(menu); - - openOptionsMenu(); - } - - @Override - public void closeMenu() { - closeOptionsMenu(); - } - - @Override - public View onCreatePanelView(int featureId) { - if (Build.VERSION.SDK_INT >= 11 && featureId == Window.FEATURE_OPTIONS_PANEL) { - if (mMenuPanel == null) { - mMenuPanel = new MenuPanel(this, null); - } else { - // Prepare the panel everytime before showing the menu. - onPreparePanel(featureId, mMenuPanel, mMenu); - } - - return mMenuPanel; - } - - return super.onCreatePanelView(featureId); - } - - @Override - public boolean onCreatePanelMenu(int featureId, Menu menu) { - if (Build.VERSION.SDK_INT >= 11 && featureId == Window.FEATURE_OPTIONS_PANEL) { - if (mMenuPanel == null) { - mMenuPanel = (MenuPanel) onCreatePanelView(featureId); - } - - GeckoMenu gMenu = new GeckoMenu(this, null); - gMenu.setCallback(this); - gMenu.setMenuPresenter(this); - menu = gMenu; - mMenuPanel.addView(gMenu); - - return onCreateOptionsMenu(menu); - } - - return super.onCreatePanelMenu(featureId, menu); - } - - @Override - public boolean onPreparePanel(int featureId, View view, Menu menu) { - if (Build.VERSION.SDK_INT >= 11 && featureId == Window.FEATURE_OPTIONS_PANEL) - return onPrepareOptionsMenu(menu); - - return super.onPreparePanel(featureId, view, menu); - } - - @Override - public boolean onMenuOpened(int featureId, Menu menu) { - // exit full-screen mode whenever the menu is opened - if (mLayerView != null && mLayerView.isFullScreen()) { - GeckoAppShell.sendEventToGecko(GeckoEvent.createBroadcastEvent("FullScreen:Exit", null)); - } - - if (Build.VERSION.SDK_INT >= 11 && featureId == Window.FEATURE_OPTIONS_PANEL) { - if (mMenu == null) { - onCreatePanelMenu(featureId, menu); - onPreparePanel(featureId, mMenuPanel, mMenu); - } - - // Scroll custom menu to the top - if (mMenuPanel != null) - mMenuPanel.scrollTo(0, 0); - - return true; - } - - return super.onMenuOpened(featureId, menu); - } - - @Override - public boolean onOptionsItemSelected(MenuItem item) { - switch (item.getItemId()) { - case R.id.quit: - if (GeckoThread.checkAndSetLaunchState(GeckoThread.LaunchState.GeckoRunning, GeckoThread.LaunchState.GeckoExiting)) { - GeckoAppShell.notifyGeckoOfEvent(GeckoEvent.createBroadcastEvent("Browser:Quit", null)); - } else { - System.exit(0); - } - return true; - default: - return super.onOptionsItemSelected(item); - } - } - - @Override - public void onOptionsMenuClosed(Menu menu) { - if (Build.VERSION.SDK_INT >= 11) { - mMenuPanel.removeAllViews(); - mMenuPanel.addView((GeckoMenu) mMenu); - } - } - - @Override - public boolean onKeyDown(int keyCode, KeyEvent event) { - // Handle hardware menu key presses separately so that we can show a custom menu in some cases. - if (keyCode == KeyEvent.KEYCODE_MENU) { - openOptionsMenu(); - return true; - } - - return super.onKeyDown(keyCode, event); - } - - @Override - protected void onSaveInstanceState(Bundle outState) { - super.onSaveInstanceState(outState); - - if (outState == null) - outState = new Bundle(); - - outState.putBoolean(SAVED_STATE_IN_BACKGROUND, isApplicationInBackground()); - outState.putString(SAVED_STATE_PRIVATE_SESSION, mPrivateBrowsingSession); - - // Bug 896992 - Replace intent action with ACTION_MAIN on restart. - if (mIntentHandled) { - outState.putBoolean(SAVED_STATE_INTENT_HANDLED, true); - } - } - - void handleFaviconRequest(final String url) { - (new UiAsyncTask<Void, Void, String>(ThreadUtils.getBackgroundHandler()) { - @Override - public String doInBackground(Void... params) { - return Favicons.getInstance().getFaviconUrlForPageUrl(url); - } - - @Override - public void onPostExecute(String faviconUrl) { - JSONObject args = new JSONObject(); - - if (faviconUrl != null) { - try { - args.put("url", url); - args.put("faviconUrl", faviconUrl); - } catch (JSONException e) { - Log.w(LOGTAG, "Error building JSON favicon arguments.", e); - } - } - - GeckoAppShell.sendEventToGecko(GeckoEvent.createBroadcastEvent("Reader:FaviconReturn", args.toString())); - } - }).execute(); - } - - void handleClearHistory() { - BrowserDB.clearHistory(getContentResolver()); - } - - public void addTab() { } - - public void addPrivateTab() { } - - public void showNormalTabs() { } - - public void showPrivateTabs() { } - - public void showRemoteTabs() { } - - private void showTabs(TabsPanel.Panel panel) { } - - public void hideTabs() { } - - /** - * Close the tab UI indirectly (not as the result of a direct user - * action). This does not force the UI to close; for example in Firefox - * tablet mode it will remain open unless the user explicitly closes it. - * - * @return True if the tab UI was hidden. - */ - public boolean autoHideTabs() { return false; } - - public boolean areTabsShown() { return false; } - - @Override - public void handleMessage(String event, JSONObject message) { - try { - if (event.equals("Toast:Show")) { - final String msg = message.getString("message"); - final String duration = message.getString("duration"); - handleShowToast(msg, duration); - } else if (event.equals("log")) { - // generic log listener - final String msg = message.getString("msg"); - Log.d(LOGTAG, "Log: " + msg); - } else if (event.equals("Reader:FaviconRequest")) { - final String url = message.getString("url"); - handleFaviconRequest(url); - } else if (event.equals("Reader:GoToReadingList")) { - showReadingList(); - } else if (event.equals("Gecko:Ready")) { - geckoConnected(); - } else if (event.equals("ToggleChrome:Hide")) { - toggleChrome(false); - } else if (event.equals("ToggleChrome:Show")) { - toggleChrome(true); - } else if (event.equals("ToggleChrome:Focus")) { - focusChrome(); - } else if (event.equals("DOMFullScreen:Start")) { - // Local ref to layerView for thread safety - LayerView layerView = mLayerView; - if (layerView != null) { - layerView.setFullScreen(true); - } - } else if (event.equals("DOMFullScreen:Stop")) { - // Local ref to layerView for thread safety - LayerView layerView = mLayerView; - if (layerView != null) { - layerView.setFullScreen(false); - } - } else if (event.equals("Permissions:Data")) { - String host = message.getString("host"); - JSONArray permissions = message.getJSONArray("permissions"); - showSiteSettingsDialog(host, permissions); - } else if (event.equals("Tab:ViewportMetadata")) { - int tabId = message.getInt("tabID"); - Tab tab = Tabs.getInstance().getTab(tabId); - if (tab == null) - return; - tab.setZoomConstraints(new ZoomConstraints(message)); - tab.setIsRTL(message.getBoolean("isRTL")); - // Sync up the layer view and the tab if the tab is currently displayed. - LayerView layerView = mLayerView; - if (layerView != null && Tabs.getInstance().isSelectedTab(tab)) { - layerView.setZoomConstraints(tab.getZoomConstraints()); - layerView.setIsRTL(tab.getIsRTL()); - } - } else if (event.equals("Session:StatePurged")) { - onStatePurged(); - } else if (event.equals("Bookmark:Insert")) { - final String url = message.getString("url"); - final String title = message.getString("title"); - final Context context = this; - ThreadUtils.postToUiThread(new Runnable() { - @Override - public void run() { - Toast.makeText(context, R.string.bookmark_added, Toast.LENGTH_SHORT).show(); - ThreadUtils.postToBackgroundThread(new Runnable() { - @Override - public void run() { - BrowserDB.addBookmark(getContentResolver(), title, url); - } - }); - } - }); - } else if (event.equals("Accessibility:Event")) { - GeckoAccessibility.sendAccessibilityEvent(message); - } else if (event.equals("Accessibility:Ready")) { - GeckoAccessibility.updateAccessibilitySettings(this); - } else if (event.equals("Shortcut:Remove")) { - final String url = message.getString("url"); - final String origin = message.getString("origin"); - final String title = message.getString("title"); - final String type = message.getString("shortcutType"); - GeckoAppShell.removeShortcut(title, url, origin, type); - } else if (event.equals("WebApps:Open")) { - String manifestURL = message.getString("manifestURL"); - String origin = message.getString("origin"); - Intent intent = GeckoAppShell.getWebAppIntent(manifestURL, origin, "", null); - if (intent == null) - return; - startActivity(intent); - } else if (event.equals("WebApps:Install")) { - String name = message.getString("name"); - String manifestURL = message.getString("manifestURL"); - String iconURL = message.getString("iconURL"); - String origin = message.getString("origin"); - // preInstallWebapp will return a File object pointing to the profile directory of the webapp - mCurrentResponse = GeckoAppShell.preInstallWebApp(name, manifestURL, origin).toString(); - GeckoAppShell.postInstallWebApp(name, manifestURL, origin, iconURL); - } else if (event.equals("WebApps:PreInstall")) { - String name = message.getString("name"); - String manifestURL = message.getString("manifestURL"); - String origin = message.getString("origin"); - // preInstallWebapp will return a File object pointing to the profile directory of the webapp - mCurrentResponse = GeckoAppShell.preInstallWebApp(name, manifestURL, origin).toString(); - } else if (event.equals("WebApps:PostInstall")) { - String name = message.getString("name"); - String manifestURL = message.getString("manifestURL"); - String iconURL = message.getString("iconURL"); - String origin = message.getString("origin"); - GeckoAppShell.postInstallWebApp(name, manifestURL, origin, iconURL); - } else if (event.equals("WebApps:Uninstall")) { - String origin = message.getString("origin"); - GeckoAppShell.uninstallWebApp(origin); - } else if (event.equals("Share:Text")) { - String text = message.getString("text"); - GeckoAppShell.openUriExternal(text, "text/plain", "", "", Intent.ACTION_SEND, ""); - } else if (event.equals("Share:Image")) { - String src = message.getString("url"); - String type = message.getString("mime"); - GeckoAppShell.shareImage(src, type); - } else if (event.equals("Wallpaper:Set")) { - String src = message.getString("url"); - setImageAsWallpaper(src); - } else if (event.equals("Sanitize:ClearHistory")) { - handleClearHistory(); - } else if (event.equals("Update:Check")) { - startService(new Intent(UpdateServiceHelper.ACTION_CHECK_FOR_UPDATE, null, this, UpdateService.class)); - } else if (event.equals("Update:Download")) { - startService(new Intent(UpdateServiceHelper.ACTION_DOWNLOAD_UPDATE, null, this, UpdateService.class)); - } else if (event.equals("Update:Install")) { - startService(new Intent(UpdateServiceHelper.ACTION_APPLY_UPDATE, null, this, UpdateService.class)); - } else if (event.equals("PrivateBrowsing:Data")) { - // null strings return "null" (http://code.google.com/p/android/issues/detail?id=13830) - if (message.isNull("session")) { - mPrivateBrowsingSession = null; - } else { - mPrivateBrowsingSession = message.getString("session"); - } - } else if (event.equals("Contact:Add")) { - if (!message.isNull("email")) { - Uri contactUri = Uri.parse(message.getString("email")); - Intent i = new Intent(ContactsContract.Intents.SHOW_OR_CREATE_CONTACT, contactUri); - startActivity(i); - } else if (!message.isNull("phone")) { - Uri contactUri = Uri.parse(message.getString("phone")); - Intent i = new Intent(ContactsContract.Intents.SHOW_OR_CREATE_CONTACT, contactUri); - startActivity(i); - } else { - // something went wrong. - Log.e(LOGTAG, "Received Contact:Add message with no email nor phone number"); - } - } - } catch (Exception e) { - Log.e(LOGTAG, "Exception handling message \"" + event + "\":", e); - } - } - - public String getResponse(JSONObject origMessage) { - String res = mCurrentResponse; - mCurrentResponse = ""; - return res; - } - - void onStatePurged() { } - - /** - * @param aPermissions - * Array of JSON objects to represent site permissions. - * Example: { type: "offline-app", setting: "Store Offline Data", value: "Allow" } - */ - private void showSiteSettingsDialog(String aHost, JSONArray aPermissions) { - final AlertDialog.Builder builder = new AlertDialog.Builder(this); - - View customTitleView = getLayoutInflater().inflate(R.layout.site_setting_title, null); - ((TextView) customTitleView.findViewById(R.id.title)).setText(R.string.site_settings_title); - ((TextView) customTitleView.findViewById(R.id.host)).setText(aHost); - builder.setCustomTitle(customTitleView); - - // If there are no permissions to clear, show the user a message about that. - // In the future, we want to disable the menu item if there are no permissions to clear. - if (aPermissions.length() == 0) { - builder.setMessage(R.string.site_settings_no_settings); - } else { - - ArrayList <HashMap<String, String>> itemList = new ArrayList <HashMap<String, String>>(); - for (int i = 0; i < aPermissions.length(); i++) { - try { - JSONObject permObj = aPermissions.getJSONObject(i); - HashMap<String, String> map = new HashMap<String, String>(); - map.put("setting", permObj.getString("setting")); - map.put("value", permObj.getString("value")); - itemList.add(map); - } catch (JSONException e) { - Log.w(LOGTAG, "Exception populating settings items.", e); - } - } - - // setMultiChoiceItems doesn't support using an adapter, so we're creating a hack with - // setSingleChoiceItems and changing the choiceMode below when we create the dialog - builder.setSingleChoiceItems(new SimpleAdapter( - GeckoApp.this, - itemList, - R.layout.site_setting_item, - new String[] { "setting", "value" }, - new int[] { R.id.setting, R.id.value } - ), -1, new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int id) { } - }); - - builder.setPositiveButton(R.string.site_settings_clear, new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int id) { - ListView listView = ((AlertDialog) dialog).getListView(); - SparseBooleanArray checkedItemPositions = listView.getCheckedItemPositions(); - - // An array of the indices of the permissions we want to clear - JSONArray permissionsToClear = new JSONArray(); - for (int i = 0; i < checkedItemPositions.size(); i++) - if (checkedItemPositions.get(i)) - permissionsToClear.put(i); - - GeckoAppShell.sendEventToGecko(GeckoEvent.createBroadcastEvent( - "Permissions:Clear", permissionsToClear.toString())); - } - }); - } - - builder.setNegativeButton(R.string.site_settings_cancel, new DialogInterface.OnClickListener(){ - @Override - public void onClick(DialogInterface dialog, int id) { - dialog.cancel(); - } - }); - - ThreadUtils.postToUiThread(new Runnable() { - @Override - public void run() { - Dialog dialog = builder.create(); - dialog.show(); - - ListView listView = ((AlertDialog) dialog).getListView(); - if (listView != null) { - listView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE); - int listSize = listView.getAdapter().getCount(); - for (int i = 0; i < listSize; i++) - listView.setItemChecked(i, true); - } - } - }); - } - - public void showToast(final int resId, final int duration) { - ThreadUtils.postToUiThread(new Runnable() { - @Override - public void run() { - Toast.makeText(GeckoApp.this, resId, duration).show(); - } - }); - } - - void handleShowToast(final String message, final String duration) { - ThreadUtils.postToUiThread(new Runnable() { - @Override - public void run() { - Toast toast; - if (duration.equals("long")) - toast = Toast.makeText(GeckoApp.this, message, Toast.LENGTH_LONG); - else - toast = Toast.makeText(GeckoApp.this, message, Toast.LENGTH_SHORT); - toast.show(); - } - }); - } - - private void addFullScreenPluginView(View view) { - if (mFullScreenPluginView != null) { - Log.w(LOGTAG, "Already have a fullscreen plugin view"); - return; - } - - setFullScreen(true); - - view.setWillNotDraw(false); - if (view instanceof SurfaceView) { - ((SurfaceView) view).setZOrderOnTop(true); - } - - mFullScreenPluginContainer = new FullScreenHolder(this); - - FrameLayout.LayoutParams layoutParams = new FrameLayout.LayoutParams( - ViewGroup.LayoutParams.FILL_PARENT, - ViewGroup.LayoutParams.FILL_PARENT, - Gravity.CENTER); - mFullScreenPluginContainer.addView(view, layoutParams); - - - FrameLayout decor = (FrameLayout)getWindow().getDecorView(); - decor.addView(mFullScreenPluginContainer, layoutParams); - - mFullScreenPluginView = view; - } - - public void addPluginView(final View view, final Rect rect, final boolean isFullScreen) { - ThreadUtils.postToUiThread(new Runnable() { - @Override - public void run() { - Tabs tabs = Tabs.getInstance(); - Tab tab = tabs.getSelectedTab(); - - if (isFullScreen) { - addFullScreenPluginView(view); - return; - } - - PluginLayer layer = (PluginLayer) tab.getPluginLayer(view); - if (layer == null) { - layer = new PluginLayer(view, rect, mLayerView.getRenderer().getMaxTextureSize()); - tab.addPluginLayer(view, layer); - } else { - layer.reset(rect); - layer.setVisible(true); - } - - mLayerView.addLayer(layer); - } - }); - } - - private void removeFullScreenPluginView(View view) { - if (mFullScreenPluginView == null) { - Log.w(LOGTAG, "Don't have a fullscreen plugin view"); - return; - } - - if (mFullScreenPluginView != view) { - Log.w(LOGTAG, "Passed view is not the current full screen view"); - return; - } - - mFullScreenPluginContainer.removeView(mFullScreenPluginView); - - // We need do do this on the next iteration in order to avoid - // a deadlock, see comment below in FullScreenHolder - ThreadUtils.postToUiThread(new Runnable() { - @Override - public void run() { - mLayerView.show(); - } - }); - - FrameLayout decor = (FrameLayout)getWindow().getDecorView(); - decor.removeView(mFullScreenPluginContainer); - - mFullScreenPluginView = null; - - GeckoScreenOrientationListener.getInstance().unlockScreenOrientation(); - setFullScreen(false); - } - - public void removePluginView(final View view, final boolean isFullScreen) { - ThreadUtils.postToUiThread(new Runnable() { - @Override - public void run() { - Tabs tabs = Tabs.getInstance(); - Tab tab = tabs.getSelectedTab(); - - if (isFullScreen) { - removeFullScreenPluginView(view); - return; - } - - PluginLayer layer = (PluginLayer) tab.removePluginLayer(view); - if (layer != null) { - layer.destroy(); - } - } - }); - } - - private void setImageAsWallpaper(final String aSrc) { - final String progText = getString(R.string.wallpaper_progress); - final String successText = getString(R.string.wallpaper_success); - final String failureText = getString(R.string.wallpaper_fail); - final String fileName = aSrc.substring(aSrc.lastIndexOf("/") + 1); - final PendingIntent emptyIntent = PendingIntent.getActivity(this, 0, new Intent(), 0); - final AlertNotification notification = new AlertNotification(this, fileName.hashCode(), - R.drawable.alert_download, fileName, progText, System.currentTimeMillis(), null); - notification.setLatestEventInfo(this, fileName, progText, emptyIntent ); - notification.flags |= Notification.FLAG_ONGOING_EVENT; - notification.show(); - new UiAsyncTask<Void, Void, Boolean>(ThreadUtils.getBackgroundHandler()) { - - @Override - protected Boolean doInBackground(Void... params) { - WallpaperManager mgr = WallpaperManager.getInstance(GeckoApp.this); - if (mgr == null) { - return false; - } - - // Determine the ideal width and height of the wallpaper - // for the device - - int idealWidth = mgr.getDesiredMinimumWidth(); - int idealHeight = mgr.getDesiredMinimumHeight(); - - // Sometimes WallpaperManager's getDesiredMinimum*() methods - // can return 0 if a Remote Exception occurs when calling the - // Wallpaper Service. So if that fails, we are calculating - // the ideal width and height from the device's display - // resolution (excluding the decorated area) - - if (idealWidth <= 0 || idealHeight <= 0) { - int orientation; - Display defaultDisplay = getWindowManager().getDefaultDisplay(); - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.FROYO) { - orientation = defaultDisplay.getRotation(); - } else { - orientation = defaultDisplay.getOrientation(); - } - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) { - Point size = new Point(); - defaultDisplay.getSize(size); - // The ideal wallpaper width is always twice the size of - // display width - if (orientation == Surface.ROTATION_0 || orientation == Surface.ROTATION_270) { - idealWidth = size.x * 2; - idealHeight = size.y; - } else { - idealWidth = size.y; - idealHeight = size.x * 2; - } - } else { - if (orientation == Surface.ROTATION_0 || orientation == Surface.ROTATION_270) { - idealWidth = defaultDisplay.getWidth() * 2; - idealHeight = defaultDisplay.getHeight(); - } else { - idealWidth = defaultDisplay.getHeight(); - idealHeight = defaultDisplay.getWidth() * 2; - } - } - } - - boolean isDataURI = aSrc.startsWith("data:"); - BitmapFactory.Options options = new BitmapFactory.Options(); - options.inJustDecodeBounds = true; - Bitmap image = null; - InputStream is = null; - ByteArrayOutputStream os = null; - try{ - if (isDataURI) { - int dataStart = aSrc.indexOf(','); - byte[] buf = Base64.decode(aSrc.substring(dataStart+1), Base64.DEFAULT); - BitmapUtils.decodeByteArray(buf, options); - options.inSampleSize = getBitmapSampleSize(options, idealWidth, idealHeight); - options.inJustDecodeBounds = false; - image = BitmapUtils.decodeByteArray(buf, options); - } else { - int byteRead; - byte[] buf = new byte[4192]; - os = new ByteArrayOutputStream(); - URL url = new URL(aSrc); - is = url.openStream(); - - // Cannot read from same stream twice. Also, InputStream from - // URL does not support reset. So converting to byte array - - while((byteRead = is.read(buf)) != -1) { - os.write(buf, 0, byteRead); - } - byte[] imgBuffer = os.toByteArray(); - BitmapUtils.decodeByteArray(imgBuffer, options); - options.inSampleSize = getBitmapSampleSize(options, idealWidth, idealHeight); - options.inJustDecodeBounds = false; - image = BitmapUtils.decodeByteArray(imgBuffer, options); - } - if(image != null) { - mgr.setBitmap(image); - return true; - } else { - return false; - } - } catch(OutOfMemoryError ome) { - Log.e(LOGTAG, "Out of Memory when converting to byte array", ome); - return false; - } catch(IOException ioe) { - Log.e(LOGTAG, "I/O Exception while setting wallpaper", ioe); - return false; - } finally { - if(is != null) { - try { - is.close(); - } catch(IOException ioe) { - Log.w(LOGTAG, "I/O Exception while closing stream", ioe); - } - } - if(os != null) { - try { - os.close(); - } catch(IOException ioe) { - Log.w(LOGTAG, "I/O Exception while closing stream", ioe); - } - } - } - } - - @Override - protected void onPostExecute(Boolean success) { - notification.cancel(); - notification.flags = 0; - notification.flags |= Notification.FLAG_AUTO_CANCEL; - if(!success) { - notification.tickerText = failureText; - notification.setLatestEventInfo(GeckoApp.this, fileName, failureText, emptyIntent); - } else { - notification.tickerText = successText; - notification.setLatestEventInfo(GeckoApp.this, fileName, successText, emptyIntent); - } - notification.show(); - } - }.execute(); - } - - private int getBitmapSampleSize(BitmapFactory.Options options, int idealWidth, int idealHeight) { - int width = options.outWidth; - int height = options.outHeight; - int inSampleSize = 1; - if (height > idealHeight || width > idealWidth) { - if (width > height) { - inSampleSize = Math.round((float)height / (float)idealHeight); - } else { - inSampleSize = Math.round((float)width / (float)idealWidth); - } - } - return inSampleSize; - } - - private void hidePluginLayer(Layer layer) { - LayerView layerView = mLayerView; - layerView.removeLayer(layer); - layerView.requestRender(); - } - - private void showPluginLayer(Layer layer) { - LayerView layerView = mLayerView; - layerView.addLayer(layer); - layerView.requestRender(); - } - - public void requestRender() { - mLayerView.requestRender(); - } - - public void hidePlugins(Tab tab) { - for (Layer layer : tab.getPluginLayers()) { - if (layer instanceof PluginLayer) { - ((PluginLayer) layer).setVisible(false); - } - - hidePluginLayer(layer); - } - - requestRender(); - } - - public void showPlugins() { - Tabs tabs = Tabs.getInstance(); - Tab tab = tabs.getSelectedTab(); - - showPlugins(tab); - } - - public void showPlugins(Tab tab) { - for (Layer layer : tab.getPluginLayers()) { - showPluginLayer(layer); - - if (layer instanceof PluginLayer) { - ((PluginLayer) layer).setVisible(true); - } - } - - requestRender(); - } - - public void setFullScreen(final boolean fullscreen) { - ThreadUtils.postToUiThread(new Runnable() { - @Override - public void run() { - // Hide/show the system notification bar - Window window = getWindow(); - window.setFlags(fullscreen ? - WindowManager.LayoutParams.FLAG_FULLSCREEN : 0, - WindowManager.LayoutParams.FLAG_FULLSCREEN); - - if (Build.VERSION.SDK_INT >= 11) - window.getDecorView().setSystemUiVisibility(fullscreen ? 1 : 0); - } - }); - } - - /** - * Called when the activity is first created. - * - * Here we initialize all of our profile settings, Firefox Health Report, - * and other one-shot constructions. - **/ - @Override - public void onCreate(Bundle savedInstanceState) - { - GeckoAppShell.registerGlobalExceptionHandler(); - - // Enable Android Strict Mode for developers' local builds (the "default" channel). - if ("default".equals(AppConstants.MOZ_UPDATE_CHANNEL)) { - enableStrictMode(); - } - - String args = getIntent().getStringExtra("args"); - - String profileName = null; - String profilePath = null; - if (args != null) { - if (args.contains("-P")) { - Pattern p = Pattern.compile("(?:-P\\s*)(\\w*)(\\s*)"); - Matcher m = p.matcher(args); - if (m.find()) { - profileName = m.group(1); - } - } - - if (args.contains("-profile")) { - Pattern p = Pattern.compile("(?:-profile\\s*)(\\S*)(\\s*)"); - Matcher m = p.matcher(args); - if (m.find()) { - profilePath = m.group(1); - } - if (profileName == null) { - profileName = getDefaultProfileName(); - if (profileName == null) - profileName = "default"; - } - GeckoApp.sIsUsingCustomProfile = true; - } - - if (profileName != null || profilePath != null) { - mProfile = GeckoProfile.get(this, profileName, profilePath); - } - } - - BrowserDB.initialize(getProfile().getName()); - ((GeckoApplication)getApplication()).initialize(); - - sAppContext = this; - GeckoAppShell.setContextGetter(this); - GeckoAppShell.setGeckoInterface(this); - ThreadUtils.setUiThread(Thread.currentThread(), new Handler()); - - Tabs.getInstance().attachToActivity(this); - Favicons.getInstance().attachToContext(this); - - // When we detect a locale change, we need to restart Gecko, which - // actually means restarting the entire application. This logic should - // actually be handled elsewhere since GeckoApp may not be alive to - // handle this event if "Don't keep activities" is enabled (filed as - // bug 889082). - if (((GeckoApplication)getApplication()).needsRestart()) { - doRestart(); - System.exit(0); - return; - } - - if (sGeckoThread != null) { - // This happens when the GeckoApp activity is destroyed by Android - // without killing the entire application (see Bug 769269). - mIsRestoringActivity = true; - } - - // Fix for Bug 830557 on Tegra boards running Froyo. - // This fix must be done before doing layout. - // Assume the bug is fixed in Gingerbread and up. - if (Build.VERSION.SDK_INT < 9) { - try { - Class<?> inputBindResultClass = - Class.forName("com.android.internal.view.InputBindResult"); - java.lang.reflect.Field creatorField = - inputBindResultClass.getField("CREATOR"); - Log.i(LOGTAG, "froyo startup fix: " + String.valueOf(creatorField.get(null))); - } catch (Exception e) { - Log.w(LOGTAG, "froyo startup fix failed", e); - } - } - - LayoutInflater.from(this).setFactory(this); - - super.onCreate(savedInstanceState); - - mOrientation = getResources().getConfiguration().orientation; - - setContentView(getLayout()); - - // Set up Gecko layout. - mGeckoLayout = (RelativeLayout) findViewById(R.id.gecko_layout); - mMainLayout = (RelativeLayout) findViewById(R.id.main_layout); - - // Set up tabs panel. - mTabsPanel = (TabsPanel) findViewById(R.id.tabs_panel); - mNotificationHelper = new NotificationHelper(this); - - // Check if the last run was exited due to a normal kill while - // we were in the background, or a more harsh kill while we were - // active. - mRestoreMode = getSessionRestoreState(savedInstanceState); - if (mRestoreMode == RESTORE_NORMAL && savedInstanceState != null) { - boolean wasInBackground = - savedInstanceState.getBoolean(SAVED_STATE_IN_BACKGROUND, false); - - if (savedInstanceState.getBoolean(SAVED_STATE_INTENT_HANDLED, false)) { - Intent thisIntent = getIntent(); - // Bug 896992 - This intent has already been handled, clear the intent action. - thisIntent.setAction(Intent.ACTION_MAIN); - setIntent(thisIntent); - - // Persist this flag for reincarnations of this Activity Intent. - mIntentHandled = true; - } - - mPrivateBrowsingSession = savedInstanceState.getString(SAVED_STATE_PRIVATE_SESSION); - } - - // Perform background initialization. - ThreadUtils.postToBackgroundThread(new Runnable() { - @Override - public void run() { - final SharedPreferences prefs = GeckoApp.getAppSharedPreferences(); - -// SessionInformation previousSession = SessionInformation.fromSharedPrefs(prefs); - - SharedPreferences.Editor editor = prefs.edit(); - editor.putBoolean(GeckoApp.PREFS_OOM_EXCEPTION, false); - - // Put a flag to check if we got a normal `onSaveInstanceState` - // on exit, or if we were suddenly killed (crash or native OOM). - editor.putBoolean(GeckoApp.PREFS_WAS_STOPPED, false); - - editor.commit(); - - // The lifecycle of mHealthRecorder is "shortly after onCreate" - // through "onDestroy" -- essentially the same as the lifecycle - // of the activity itself. - final String profilePath = getProfile().getDir().getAbsolutePath(); - final EventDispatcher dispatcher = GeckoAppShell.getEventDispatcher(); -// Log.i(LOGTAG, "Creating BrowserHealthRecorder."); -// mHealthRecorder = new BrowserHealthRecorder(GeckoApp.this, profilePath, dispatcher, -// previousSession); - } - }); - - GeckoAppShell.setNotificationClient(makeNotificationClient()); - } - - protected void initializeChrome() { - mDoorHangerPopup = new DoorHangerPopup(this, null); - mPluginContainer = (AbsoluteLayout) findViewById(R.id.plugin_container); - mFormAssistPopup = (FormAssistPopup) findViewById(R.id.form_assist_popup); - - if (mCameraView == null) { - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.ICE_CREAM_SANDWICH) { - mCameraView = new SurfaceView(this); - ((SurfaceView)mCameraView).getHolder().setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS); - } else { - mCameraView = new TextureView(this); - } - } - - if (mLayerView == null) { - LayerView layerView = (LayerView) findViewById(R.id.layer_view); - layerView.initializeView(GeckoAppShell.getEventDispatcher()); - mLayerView = layerView; - GeckoAppShell.setLayerView(layerView); - // bind the GeckoEditable instance to the new LayerView - GeckoAppShell.notifyIMEContext(GeckoEditableListener.IME_STATE_DISABLED, "", "", ""); - } - } - - /** - * Loads the initial tab at Fennec startup. - * - * If Fennec was opened with an external URL, that URL will be loaded. - * Otherwise, unless there was a session restore, the default URL - * (about:home) be loaded. - * - * @param url External URL to load, or null to load the default URL - */ - protected void loadStartupTab(String url) { - if (url == null) { - if (mRestoreMode == RESTORE_NONE) { - // Show about:home if we aren't restoring previous session and - // there's no external URL - Tab tab = Tabs.getInstance().loadUrl("about:home", Tabs.LOADURL_NEW_TAB); - } - } else { - // If given an external URL, load it - int flags = Tabs.LOADURL_NEW_TAB | Tabs.LOADURL_USER_ENTERED | Tabs.LOADURL_EXTERNAL; - Tabs.getInstance().loadUrl(url, flags); - } - } - - private void initialize() { - mInitialized = true; - - invalidateOptionsMenu(); - - Intent intent = getIntent(); - String action = intent.getAction(); - - String passedUri = null; - String uri = getURIFromIntent(intent); - if (uri != null && uri.length() > 0) { - passedUri = uri; - } - - final boolean isExternalURL = passedUri != null && !passedUri.equals("about:home"); - StartupAction startupAction; - if (isExternalURL) { - startupAction = StartupAction.URL; - } else { - startupAction = StartupAction.NORMAL; - } - - // Start migrating as early as possible, can do this in - // parallel with Gecko load. - checkMigrateProfile(); - - Uri data = intent.getData(); - if (data != null && "http".equals(data.getScheme())) { - startupAction = StartupAction.PREFETCH; - ThreadUtils.postToBackgroundThread(new PrefetchRunnable(data.toString())); - } - - Tabs.registerOnTabsChangedListener(this); - - initializeChrome(); - - // If we are doing a restore, read the session data and send it to Gecko - String restoreMessage = null; - if (mRestoreMode != RESTORE_NONE && !mIsRestoringActivity) { - try { - // restoreSessionTabs() will create simple tab stubs with the - // URL and title for each page, but we also need to restore - // session history. restoreSessionTabs() will inject the IDs - // of the tab stubs into the JSON data (which holds the session - // history). This JSON data is then sent to Gecko so session - // history can be restored for each tab. - restoreMessage = restoreSessionTabs(isExternalURL); - } catch (SessionRestoreException e) { - // If restore failed, do a normal startup - Log.e(LOGTAG, "An error occurred during restore", e); - mRestoreMode = RESTORE_NONE; - } - } - - GeckoAppShell.sendEventToGecko(GeckoEvent.createBroadcastEvent("Session:Restore", restoreMessage)); - - if (!mIsRestoringActivity) { - loadStartupTab(isExternalURL ? passedUri : null); - } - - if (mRestoreMode == RESTORE_NORMAL) { - // If we successfully did an OOM restore, we now have tab stubs - // from the last session. Any future tabs should be animated. - Tabs.getInstance().notifyListeners(null, Tabs.TabEvents.RESTORED); - } else { - // Move the session file if it exists - getProfile().moveSessionFile(); - } - - if (mRestoreMode == RESTORE_NONE) { - Tabs.getInstance().notifyListeners(null, Tabs.TabEvents.RESTORED); - } - - if (!mIsRestoringActivity) { - sGeckoThread = new GeckoThread(intent, passedUri); - ThreadUtils.setGeckoThread(sGeckoThread); - } - if (!ACTION_DEBUG.equals(action) && - GeckoThread.checkAndSetLaunchState(GeckoThread.LaunchState.Launching, GeckoThread.LaunchState.Launched)) { - sGeckoThread.start(); - } else if (ACTION_DEBUG.equals(action) && - GeckoThread.checkAndSetLaunchState(GeckoThread.LaunchState.Launching, GeckoThread.LaunchState.WaitForDebugger)) { - ThreadUtils.getUiHandler().postDelayed(new Runnable() { - @Override - public void run() { - GeckoThread.setLaunchState(GeckoThread.LaunchState.Launching); - sGeckoThread.start(); - } - }, 1000 * 5 /* 5 seconds */); - } - - // Check if launched from data reporting notification. - if (ACTION_LAUNCH_SETTINGS.equals(action)) { - mIntentHandled = true; - Intent settingsIntent = new Intent(GeckoApp.this, GeckoPreferences.class); - // Copy extras. - settingsIntent.putExtras(intent); - startActivity(settingsIntent); - } - - //app state callbacks - mAppStateListeners = new LinkedList<GeckoAppShell.AppStateListener>(); - - //register for events - registerEventListener("log"); - registerEventListener("Reader:ListCountRequest"); - registerEventListener("Reader:Added"); - registerEventListener("Reader:Removed"); - registerEventListener("Reader:Share"); - registerEventListener("Reader:FaviconRequest"); - registerEventListener("Reader:GoToReadingList"); - registerEventListener("onCameraCapture"); - registerEventListener("Menu:Add"); - registerEventListener("Menu:Remove"); - registerEventListener("Menu:Update"); - registerEventListener("Gecko:Ready"); - registerEventListener("Toast:Show"); - registerEventListener("DOMFullScreen:Start"); - registerEventListener("DOMFullScreen:Stop"); - registerEventListener("ToggleChrome:Hide"); - registerEventListener("ToggleChrome:Show"); - registerEventListener("ToggleChrome:Focus"); - registerEventListener("Permissions:Data"); - registerEventListener("Tab:ViewportMetadata"); - registerEventListener("Session:StatePurged"); - registerEventListener("Bookmark:Insert"); - registerEventListener("Accessibility:Event"); - registerEventListener("Accessibility:Ready"); - registerEventListener("Shortcut:Remove"); - registerEventListener("WebApps:Open"); - registerEventListener("WebApps:PreInstall"); - registerEventListener("WebApps:PostInstall"); - registerEventListener("WebApps:Install"); - registerEventListener("WebApps:Uninstall"); - registerEventListener("Share:Text"); - registerEventListener("Share:Image"); - registerEventListener("Wallpaper:Set"); - registerEventListener("Sanitize:ClearHistory"); - registerEventListener("Update:Check"); - registerEventListener("Update:Download"); - registerEventListener("Update:Install"); - registerEventListener("PrivateBrowsing:Data"); - registerEventListener("Contact:Add"); - - if (SmsManager.getInstance() != null) { - SmsManager.getInstance().start(); - } - - mPromptService = new PromptService(this); - - mTextSelection = new TextSelection((TextSelectionHandle) findViewById(R.id.start_handle), - (TextSelectionHandle) findViewById(R.id.middle_handle), - (TextSelectionHandle) findViewById(R.id.end_handle), - GeckoAppShell.getEventDispatcher(), - this); - - PrefsHelper.getPref("app.update.autodownload", new PrefsHelper.PrefHandlerBase() { - @Override public void prefValue(String pref, String value) { - UpdateServiceHelper.registerForUpdates(GeckoApp.this, value); - } - }); - - ThreadUtils.getBackgroundHandler().postDelayed(new Runnable() { - @Override - public void run() { - // Sync settings need Gecko to be loaded, so - // no hurry in starting this. - checkMigrateSync(); - - // Kick off our background services that upload health reports. - // We do this by invoking the broadcast receiver, which uses the - // system alarm infrastructure to perform tasks at intervals. - GeckoPreferences.broadcastHealthReportUploadPref(GeckoApp.this); - - /* - XXXX see bug 635342 - We want to disable this code if possible. It is about 145ms in runtime - SharedPreferences settings = getPreferences(Activity.MODE_PRIVATE); - String localeCode = settings.getString(getPackageName() + ".locale", ""); - if (localeCode != null && localeCode.length() > 0) - GeckoAppShell.setSelectedLocale(localeCode); - */ - - if (!GeckoThread.checkLaunchState(GeckoThread.LaunchState.Launched)) { - return; - } - } - }, 50); - - if (mIsRestoringActivity) { - GeckoThread.setLaunchState(GeckoThread.LaunchState.GeckoRunning); - Tab selectedTab = Tabs.getInstance().getSelectedTab(); - if (selectedTab != null) - Tabs.getInstance().notifyListeners(selectedTab, Tabs.TabEvents.SELECTED); - geckoConnected(); - GeckoAppShell.setLayerClient(mLayerView.getLayerClient()); - GeckoAppShell.sendEventToGecko(GeckoEvent.createBroadcastEvent("Viewport:Flush", null)); - } - - if (ACTION_ALERT_CALLBACK.equals(action)) { - processAlertCallback(intent); - } - } - - private String restoreSessionTabs(final boolean isExternalURL) throws SessionRestoreException { - try { - String sessionString = getProfile().readSessionFile(false); - if (sessionString == null) { - throw new SessionRestoreException("Could not read from session file"); - } - - // If we are doing an OOM restore, parse the session data and - // stub the restored tabs immediately. This allows the UI to be - // updated before Gecko has restored. - if (mRestoreMode == RESTORE_NORMAL) { - final JSONArray tabs = new JSONArray(); - SessionParser parser = new SessionParser() { - @Override - public void onTabRead(SessionTab sessionTab) { - JSONObject tabObject = sessionTab.getTabObject(); - - int flags = Tabs.LOADURL_NEW_TAB; - flags |= ((isExternalURL || !sessionTab.isSelected()) ? Tabs.LOADURL_DELAY_LOAD : 0); - flags |= (tabObject.optBoolean("desktopMode") ? Tabs.LOADURL_DESKTOP : 0); - flags |= (tabObject.optBoolean("isPrivate") ? Tabs.LOADURL_PRIVATE : 0); - - Tab tab = Tabs.getInstance().loadUrl(sessionTab.getUrl(), flags); - tab.updateTitle(sessionTab.getTitle()); - - try { - tabObject.put("tabId", tab.getId()); - } catch (JSONException e) { - Log.e(LOGTAG, "JSON error", e); - } - tabs.put(tabObject); - } - }; - - if (mPrivateBrowsingSession == null) { - parser.parse(sessionString); - } else { - parser.parse(sessionString, mPrivateBrowsingSession); - } - - if (tabs.length() > 0) { - sessionString = new JSONObject().put("windows", new JSONArray().put(new JSONObject().put("tabs", tabs))).toString(); - } else { - throw new SessionRestoreException("No tabs could be read from session file"); - } - } - - JSONObject restoreData = new JSONObject(); - restoreData.put("normalRestore", mRestoreMode == RESTORE_NORMAL); - restoreData.put("sessionString", sessionString); - return restoreData.toString(); - - } catch (JSONException e) { - throw new SessionRestoreException(e); - } - } - - public GeckoProfile getProfile() { - // fall back to default profile if we didn't load a specific one - if (mProfile == null) { - mProfile = GeckoProfile.get(this); - } - return mProfile; - } - - protected int getSessionRestoreState(Bundle savedInstanceState) { - final SharedPreferences prefs = GeckoApp.getAppSharedPreferences(); - int restoreMode = RESTORE_NONE; - - // If the version has changed, the user has done an upgrade, so restore - // previous tabs. - final int versionCode = getVersionCode(); - if (prefs.getInt(PREFS_VERSION_CODE, 0) != versionCode) { - ThreadUtils.postToBackgroundThread(new Runnable() { - @Override - public void run() { - prefs.edit() - .putInt(PREFS_VERSION_CODE, versionCode) - .commit(); - } - }); - - restoreMode = RESTORE_NORMAL; - } - - // We record crashes in the crash reporter. If sessionstore.js - // exists, but we didn't flag a crash in the crash reporter, we - // were probably just force killed by the user, so we shouldn't do - // a restore... - if (prefs.getBoolean(PREFS_CRASHED, false)) { - ThreadUtils.postToBackgroundThread(new Runnable() { - @Override - public void run() { - prefs.edit() - .putBoolean(PREFS_CRASHED, false) - .commit(); - } - }); - - restoreMode = RESTORE_CRASH; - } - - // ...except for when the user chooses to. - if (savedInstanceState != null || - PreferenceManager.getDefaultSharedPreferences(this).getBoolean(GeckoPreferences.PREFS_RESTORE_SESSION, false)) { - restoreMode = RESTORE_NORMAL; - } - - return restoreMode; - } - - /** - * Enable Android StrictMode checks (for supported OS versions). - * http://developer.android.com/reference/android/os/StrictMode.html - */ - private void enableStrictMode() { - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.GINGERBREAD) { - return; - } - - Log.d(LOGTAG, "Enabling Android StrictMode"); - - StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder() - .detectAll() - .penaltyLog() - .build()); - - StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder() - .detectAll() - .penaltyLog() - .build()); - } - - public void enableCameraView() { - // Start listening for orientation events - mCameraOrientationEventListener = new OrientationEventListener(this) { - @Override - public void onOrientationChanged(int orientation) { - if (mAppStateListeners != null) { - for (GeckoAppShell.AppStateListener listener: mAppStateListeners) { - listener.onOrientationChanged(); - } - } - } - }; - mCameraOrientationEventListener.enable(); - - // Try to make it fully transparent. - if (mCameraView instanceof SurfaceView) { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) { - mCameraView.setAlpha(0.0f); - } - } else if (mCameraView instanceof TextureView) { - mCameraView.setAlpha(0.0f); - } - RelativeLayout mCameraLayout = (RelativeLayout) findViewById(R.id.camera_layout); - // Some phones (eg. nexus S) need at least a 8x16 preview size - mCameraLayout.addView(mCameraView, - new AbsoluteLayout.LayoutParams(8, 16, 0, 0)); - } - - public void disableCameraView() { - if (mCameraOrientationEventListener != null) { - mCameraOrientationEventListener.disable(); - mCameraOrientationEventListener = null; - } - RelativeLayout mCameraLayout = (RelativeLayout) findViewById(R.id.camera_layout); - mCameraLayout.removeView(mCameraView); - } - - public String getDefaultUAString() { - return HardwareUtils.isTablet() ? AppConstants.USER_AGENT_FENNEC_TABLET : - AppConstants.USER_AGENT_FENNEC_MOBILE; - } - - public String getUAStringForHost(String host) { - // With our standard UA String, we get a 200 response code and - // client-side redirect from t.co. This bot-like UA gives us a - // 301 response code - if ("t.co".equals(host)) { - return AppConstants.USER_AGENT_BOT_LIKE; - } - return getDefaultUAString(); - } - - class PrefetchRunnable implements Runnable { - private String mPrefetchUrl; - - PrefetchRunnable(String prefetchUrl) { - mPrefetchUrl = prefetchUrl; - } - - @Override - public void run() { - HttpURLConnection connection = null; - try { - URL url = new URL(mPrefetchUrl); - // data url should have an http scheme - connection = (HttpURLConnection) url.openConnection(); - connection.setRequestProperty("User-Agent", getUAStringForHost(url.getHost())); - connection.setInstanceFollowRedirects(false); - connection.setRequestMethod("GET"); - connection.connect(); - } catch (Exception e) { - Log.e(LOGTAG, "Exception prefetching URL", e); - } finally { - if (connection != null) - connection.disconnect(); - } - } - } - - private void processAlertCallback(Intent intent) { - String alertName = ""; - String alertCookie = ""; - Uri data = intent.getData(); - if (data != null) { - alertName = data.getQueryParameter("name"); - if (alertName == null) - alertName = ""; - alertCookie = data.getQueryParameter("cookie"); - if (alertCookie == null) - alertCookie = ""; - } - handleNotification(ACTION_ALERT_CALLBACK, alertName, alertCookie); - - if (intent.hasExtra(NotificationHelper.NOTIFICATION_ID)) { - String id = intent.getStringExtra(NotificationHelper.NOTIFICATION_ID); - mNotificationHelper.hideNotification(id); - } - } - - @Override - protected void onNewIntent(Intent intent) { - if (GeckoThread.checkLaunchState(GeckoThread.LaunchState.GeckoExiting)) { - // We're exiting and shouldn't try to do anything else just incase - // we're hung for some reason we'll force the process to exit - System.exit(0); - return; - } - - // if we were previously OOM killed, we can end up here when launching - // from external shortcuts, so set this as the intent for initialization - if (!mInitialized) { - setIntent(intent); - return; - } - - // don't perform any actions if launching from recent apps - if ((intent.getFlags() & Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY) != 0) - return; - - final String action = intent.getAction(); - - if (Intent.ACTION_MAIN.equals(action)) { - GeckoAppShell.sendEventToGecko(GeckoEvent.createURILoadEvent("")); - } else if (ACTION_LOAD.equals(action)) { - String uri = intent.getDataString(); - Tabs.getInstance().loadUrl(uri); - } else if (Intent.ACTION_VIEW.equals(action)) { - String uri = intent.getDataString(); - GeckoAppShell.sendEventToGecko(GeckoEvent.createURILoadEvent(uri)); - } else if (action != null && action.startsWith(ACTION_WEBAPP_PREFIX)) { - String uri = getURIFromIntent(intent); - GeckoAppShell.sendEventToGecko(GeckoEvent.createWebappLoadEvent(uri)); - } else if (ACTION_BOOKMARK.equals(action)) { - String uri = getURIFromIntent(intent); - GeckoAppShell.sendEventToGecko(GeckoEvent.createBookmarkLoadEvent(uri)); - } else if (Intent.ACTION_SEARCH.equals(action)) { - String uri = getURIFromIntent(intent); - GeckoAppShell.sendEventToGecko(GeckoEvent.createURILoadEvent(uri)); - } else if (ACTION_ALERT_CALLBACK.equals(action)) { - processAlertCallback(intent); - } else if (ACTION_LAUNCH_SETTINGS.equals(action)) { - mIntentHandled = true; - // Check if launched from data reporting notification. - Intent settingsIntent = new Intent(GeckoApp.this, GeckoPreferences.class); - // Copy extras. - settingsIntent.putExtras(intent); - startActivity(settingsIntent); - } - } - - /* - * Handles getting a uri from and intent in a way that is backwards - * compatable with our previous implementations - */ - protected String getURIFromIntent(Intent intent) { - final String action = intent.getAction(); - if (ACTION_ALERT_CALLBACK.equals(action)) - return null; - - String uri = intent.getDataString(); - if (uri != null) - return uri; - - if ((action != null && action.startsWith(ACTION_WEBAPP_PREFIX)) || ACTION_BOOKMARK.equals(action)) { - uri = intent.getStringExtra("args"); - if (uri != null && uri.startsWith("--url=")) { - uri.replace("--url=", ""); - } - } - return uri; - } - - @Override - public void onResume() - { - // After an onPause, the activity is back in the foreground. - // Undo whatever we did in onPause. - super.onResume(); - - int newOrientation = getResources().getConfiguration().orientation; - - if (mOrientation != newOrientation) { - mOrientation = newOrientation; - refreshChrome(); - } - - GeckoScreenOrientationListener.getInstance().start(); - - // User may have enabled/disabled accessibility. - GeckoAccessibility.updateAccessibilitySettings(this); - - if (mAppStateListeners != null) { - for (GeckoAppShell.AppStateListener listener: mAppStateListeners) { - listener.onResume(); - } - } - - // We use two times: a pseudo-unique wall-clock time to identify the - // current session across power cycles, and the elapsed realtime to - // track the duration of the session. - final long now = System.currentTimeMillis(); - final long realTime = android.os.SystemClock.elapsedRealtime(); - -/* ThreadUtils.postToBackgroundThread(new Runnable() { - @Override - public void run() { - // Now construct the new session on BrowserHealthRecorder's behalf. We do this here - // so it can benefit from a single near-startup prefs commit. - SessionInformation currentSession = new SessionInformation(now, realTime); - - SharedPreferences prefs = GeckoApp.getAppSharedPreferences(); - SharedPreferences.Editor editor = prefs.edit(); - editor.putBoolean(GeckoApp.PREFS_WAS_STOPPED, false); - currentSession.recordBegin(editor); - editor.commit(); - - final BrowserHealthRecorder rec = mHealthRecorder; - if (rec != null) { - rec.setCurrentSession(currentSession); - } else { - Log.w(LOGTAG, "Can't record session: rec is null."); - } - } - }); */ - } - - @Override - public void onWindowFocusChanged(boolean hasFocus) { - super.onWindowFocusChanged(hasFocus); - - if (!mInitialized && hasFocus) { - initialize(); - getWindow().setBackgroundDrawable(null); - } - } - - @Override - public void onPause() - { - // final BrowserHealthRecorder rec = mHealthRecorder; - - // In some way it's sad that Android will trigger StrictMode warnings - // here as the whole point is to save to disk while the activity is not - // interacting with the user. - /* ThreadUtils.postToBackgroundThread(new Runnable() { - @Override - public void run() { - SharedPreferences prefs = GeckoApp.getAppSharedPreferences(); - SharedPreferences.Editor editor = prefs.edit(); - editor.putBoolean(GeckoApp.PREFS_WAS_STOPPED, true); - if (rec != null) { - rec.recordSessionEnd("P", editor); - } - editor.commit(); - } - }); */ - - GeckoScreenOrientationListener.getInstance().stop(); - - if (mAppStateListeners != null) { - for(GeckoAppShell.AppStateListener listener: mAppStateListeners) { - listener.onPause(); - } - } - - super.onPause(); - } - - @Override - public void onRestart() - { - ThreadUtils.postToBackgroundThread(new Runnable() { - @Override - public void run() { - SharedPreferences prefs = GeckoApp.getAppSharedPreferences(); - SharedPreferences.Editor editor = prefs.edit(); - editor.putBoolean(GeckoApp.PREFS_WAS_STOPPED, false); - editor.commit(); - } - }); - - super.onRestart(); - } - - @Override - public void onDestroy() - { - unregisterEventListener("log"); - unregisterEventListener("Reader:ListCountRequest"); - unregisterEventListener("Reader:Added"); - unregisterEventListener("Reader:Removed"); - unregisterEventListener("Reader:Share"); - unregisterEventListener("Reader:FaviconRequest"); - unregisterEventListener("Reader:GoToReadingList"); - unregisterEventListener("onCameraCapture"); - unregisterEventListener("Menu:Add"); - unregisterEventListener("Menu:Remove"); - unregisterEventListener("Menu:Update"); - unregisterEventListener("Gecko:Ready"); - unregisterEventListener("Toast:Show"); - unregisterEventListener("DOMFullScreen:Start"); - unregisterEventListener("DOMFullScreen:Stop"); - unregisterEventListener("ToggleChrome:Hide"); - unregisterEventListener("ToggleChrome:Show"); - unregisterEventListener("ToggleChrome:Focus"); - unregisterEventListener("Permissions:Data"); - unregisterEventListener("Tab:ViewportMetadata"); - unregisterEventListener("Session:StatePurged"); - unregisterEventListener("Bookmark:Insert"); - unregisterEventListener("Accessibility:Event"); - unregisterEventListener("Accessibility:Ready"); - unregisterEventListener("Shortcut:Remove"); - unregisterEventListener("WebApps:Open"); - unregisterEventListener("WebApps:PreInstall"); - unregisterEventListener("WebApps:PostInstall"); - unregisterEventListener("WebApps:Install"); - unregisterEventListener("WebApps:Uninstall"); - unregisterEventListener("Share:Text"); - unregisterEventListener("Share:Image"); - unregisterEventListener("Wallpaper:Set"); - unregisterEventListener("Sanitize:ClearHistory"); - unregisterEventListener("Update:Check"); - unregisterEventListener("Update:Download"); - unregisterEventListener("Update:Install"); - unregisterEventListener("PrivateBrowsing:Data"); - unregisterEventListener("Contact:Add"); - - deleteTempFiles(); - - if (mLayerView != null) - mLayerView.destroy(); - if (mDoorHangerPopup != null) - mDoorHangerPopup.destroy(); - if (mFormAssistPopup != null) - mFormAssistPopup.destroy(); - if (mPromptService != null) - mPromptService.destroy(); - if (mTextSelection != null) - mTextSelection.destroy(); - if (mNotificationHelper != null) - mNotificationHelper.destroy(); - - Tabs.getInstance().detachFromActivity(this); - - if (SmsManager.getInstance() != null) { - SmsManager.getInstance().stop(); - if (isFinishing()) - SmsManager.getInstance().shutdown(); - } - -/* final BrowserHealthRecorder rec = mHealthRecorder; - mHealthRecorder = null; - if (rec != null) { - // Closing a BrowserHealthRecorder could incur a write. - ThreadUtils.postToBackgroundThread(new Runnable() { - @Override - public void run() { - rec.close(); - } - }); - } */ - - super.onDestroy(); - - Tabs.unregisterOnTabsChangedListener(this); - } - - protected void registerEventListener(String event) { - GeckoAppShell.getEventDispatcher().registerEventListener(event, this); - } - - protected void unregisterEventListener(String event) { - GeckoAppShell.getEventDispatcher().unregisterEventListener(event, this); - } - - // Get a temporary directory, may return null - public static File getTempDirectory() { - File dir = sAppContext.getExternalFilesDir("temp"); - return dir; - } - - // Delete any files in our temporary directory - public static void deleteTempFiles() { - File dir = getTempDirectory(); - if (dir == null) - return; - File[] files = dir.listFiles(); - if (files == null) - return; - for (File file : files) { - file.delete(); - } - } - - @Override - public void onConfigurationChanged(Configuration newConfig) { - super.onConfigurationChanged(newConfig); - - if (mOrientation != newConfig.orientation) { - mOrientation = newConfig.orientation; - if (mFormAssistPopup != null) - mFormAssistPopup.hide(); - refreshChrome(); - } - } - - public String getContentProcessName() { - return AppConstants.MOZ_CHILD_PROCESS_NAME; - } - - /* - * Only one factory can be set on the inflater; however, we want to use two - * factories (GeckoViewsFactory and the FragmentActivity factory). - * Overriding onCreateView() here allows us to dispatch view creation to - * both factories. - */ - @Override - public View onCreateView(String name, Context context, AttributeSet attrs) { - View view = GeckoViewsFactory.getInstance().onCreateView(name, context, attrs); - if (view == null) { - view = super.onCreateView(name, context, attrs); - } - return view; - } - - public void addEnvToIntent(Intent intent) { - Map<String,String> envMap = System.getenv(); - Set<Map.Entry<String,String>> envSet = envMap.entrySet(); - Iterator<Map.Entry<String,String>> envIter = envSet.iterator(); - int c = 0; - while (envIter.hasNext()) { - Map.Entry<String,String> entry = envIter.next(); - intent.putExtra("env" + c, entry.getKey() + "=" - + entry.getValue()); - c++; - } - } - - public void doRestart() { - doRestart(RESTARTER_ACTION); - } - - public void doRestart(String action) { - Log.d(LOGTAG, "doRestart(\"" + action + "\")"); - try { - Intent intent = new Intent(action); - intent.setClassName(AppConstants.ANDROID_PACKAGE_NAME, RESTARTER_CLASS); - /* TODO: addEnvToIntent(intent); */ - intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | - Intent.FLAG_ACTIVITY_MULTIPLE_TASK); - Log.d(LOGTAG, "Restart intent: " + intent.toString()); - GeckoAppShell.killAnyZombies(); - startActivity(intent); - } catch (Exception e) { - Log.e(LOGTAG, "Error effecting restart.", e); - } - finish(); - // Give the restart process time to start before we die - GeckoAppShell.waitForAnotherGeckoProc(); - } - - public void handleNotification(String action, String alertName, String alertCookie) { - // If Gecko isn't running yet, we ignore the notification. Note that - // even if Gecko is running but it was restarted since the notification - // was created, the notification won't be handled (bug 849653). - if (GeckoThread.checkLaunchState(GeckoThread.LaunchState.GeckoRunning)) { - GeckoAppShell.handleNotification(action, alertName, alertCookie); - } - } - - private void checkMigrateProfile() { - final File profileDir = getProfile().getDir(); - - if (profileDir != null) { - final GeckoApp app = GeckoApp.sAppContext; - - ThreadUtils.postToBackgroundThread(new Runnable() { - @Override - public void run() { - ProfileMigrator profileMigrator = new ProfileMigrator(app); - - // Do a migration run on the first start after an upgrade. - if (!GeckoApp.sIsUsingCustomProfile && - !profileMigrator.hasMigrationRun()) { - // Show the "Setting up Fennec" screen if this takes - // a while. - - // Create a "final" holder for the setup screen so that we can - // create it in startCallback and still find a reference to it - // in stopCallback. (We must create it on the UI thread to fix - // bug 788216). Note that synchronization is not a problem here - // since it is only ever touched on the UI thread. - final SetupScreen[] setupScreenHolder = new SetupScreen[1]; - - final Runnable startCallback = new Runnable() { - @Override - public void run() { - ThreadUtils.postToUiThread(new Runnable() { - @Override - public void run() { - setupScreenHolder[0] = new SetupScreen(app); - setupScreenHolder[0].show(); - } - }); - } - }; - - final Runnable stopCallback = new Runnable() { - @Override - public void run() { - ThreadUtils.postToUiThread(new Runnable() { - @Override - public void run() { - SetupScreen screen = setupScreenHolder[0]; - // screen will never be null if this code runs, but - // stranger things have happened... - if (screen != null) { - screen.dismiss(); - } - } - }); - } - }; - - profileMigrator.setLongOperationCallbacks(startCallback, - stopCallback); - profileMigrator.launchPlaces(profileDir); - finishProfileMigration(); - } - }} - ); - } - } - - protected void finishProfileMigration() { - } - - private void checkMigrateSync() { - final File profileDir = getProfile().getDir(); - if (!GeckoApp.sIsUsingCustomProfile && profileDir != null) { - final GeckoApp app = GeckoApp.sAppContext; - ProfileMigrator profileMigrator = new ProfileMigrator(app); - if (!profileMigrator.hasSyncMigrated()) { - profileMigrator.launchSyncPrefs(); - } - } - } - - public PromptService getPromptService() { - return mPromptService; - } - - public void showReadingList() { - Intent intent = new Intent(getBaseContext(), AwesomeBar.class); - intent.addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION | Intent.FLAG_ACTIVITY_NO_HISTORY); - intent.putExtra(AwesomeBar.TARGET_KEY, AwesomeBar.Target.CURRENT_TAB.toString()); - intent.putExtra(AwesomeBar.READING_LIST_KEY, true); - - int requestCode = GeckoAppShell.sActivityHelper.makeRequestCodeForAwesomebar(); - startActivityForResult(intent, requestCode); - } - - @Override - public void onBackPressed() { - if (autoHideTabs()) { - return; - } - - if (mDoorHangerPopup != null && mDoorHangerPopup.isShowing()) { - mDoorHangerPopup.dismiss(); - return; - } - - if (mFullScreenPluginView != null) { - GeckoAppShell.onFullScreenPluginHidden(mFullScreenPluginView); - removeFullScreenPluginView(mFullScreenPluginView); - return; - } - - if (mLayerView != null && mLayerView.isFullScreen()) { - GeckoAppShell.sendEventToGecko(GeckoEvent.createBroadcastEvent("FullScreen:Exit", null)); - return; - } - - Tabs tabs = Tabs.getInstance(); - Tab tab = tabs.getSelectedTab(); - if (tab == null) { - moveTaskToBack(true); - return; - } - - if (tab.doBack()) - return; - - if (tab.isExternal()) { - moveTaskToBack(true); - tabs.closeTab(tab); - return; - } - - int parentId = tab.getParentId(); - Tab parent = tabs.getTab(parentId); - if (parent != null) { - // The back button should always return to the parent (not a sibling). - tabs.closeTab(tab, parent); - return; - } - - moveTaskToBack(true); - } - - @Override - protected void onActivityResult(int requestCode, int resultCode, Intent data) { - if (!GeckoAppShell.sActivityHelper.handleActivityResult(requestCode, resultCode, data)) { - super.onActivityResult(requestCode, resultCode, data); - } - } - - public AbsoluteLayout getPluginContainer() { return mPluginContainer; } - - // Accelerometer. - @Override - public void onAccuracyChanged(Sensor sensor, int accuracy) { - } - - @Override - public void onSensorChanged(SensorEvent event) { - GeckoAppShell.sendEventToGecko(GeckoEvent.createSensorEvent(event)); - } - - // Geolocation. - @Override - public void onLocationChanged(Location location) { - // No logging here: user-identifying information. - GeckoAppShell.sendEventToGecko(GeckoEvent.createLocationEvent(location)); - } - - @Override - public void onProviderDisabled(String provider) - { - } - - @Override - public void onProviderEnabled(String provider) - { - } - - @Override - public void onStatusChanged(String provider, int status, Bundle extras) - { - } - - // Called when a Gecko Hal WakeLock is changed - public void notifyWakeLockChanged(String topic, String state) { - PowerManager.WakeLock wl = mWakeLocks.get(topic); - if (state.equals("locked-foreground") && wl == null) { - PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE); - - if (CPU.equals(topic)) { - wl = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, topic); - } else if (SCREEN.equals(topic)) { - wl = pm.newWakeLock(PowerManager.SCREEN_BRIGHT_WAKE_LOCK, topic); - } - - if (wl != null) { - wl.acquire(); - mWakeLocks.put(topic, wl); - } - } else if (!state.equals("locked-foreground") && wl != null) { - wl.release(); - mWakeLocks.remove(topic); - } - } - - public void notifyCheckUpdateResult(String result) { - GeckoAppShell.sendEventToGecko(GeckoEvent.createBroadcastEvent("Update:CheckResult", result)); - } - - protected void geckoConnected() { - mLayerView.geckoConnected(); - } - - public void setAccessibilityEnabled(boolean enabled) { - } - - public static class MainLayout extends RelativeLayout { - private TouchEventInterceptor mTouchEventInterceptor; - private MotionEventInterceptor mMotionEventInterceptor; - - public MainLayout(Context context, AttributeSet attrs) { - super(context, attrs); - } - - public void setTouchEventInterceptor(TouchEventInterceptor interceptor) { - mTouchEventInterceptor = interceptor; - } - - public void setMotionEventInterceptor(MotionEventInterceptor interceptor) { - mMotionEventInterceptor = interceptor; - } - - @Override - public boolean onInterceptTouchEvent(MotionEvent event) { - if (mTouchEventInterceptor != null && mTouchEventInterceptor.onInterceptTouchEvent(this, event)) { - return true; - } - return super.onInterceptTouchEvent(event); - } - - @Override - public boolean onTouchEvent(MotionEvent event) { - if (mTouchEventInterceptor != null && mTouchEventInterceptor.onTouch(this, event)) { - return true; - } - return super.onTouchEvent(event); - } - - @Override - public boolean onGenericMotionEvent(MotionEvent event) { - if (mMotionEventInterceptor != null && mMotionEventInterceptor.onInterceptMotionEvent(this, event)) { - return true; - } - return super.onGenericMotionEvent(event); - } - - @Override - public void setDrawingCacheEnabled(boolean enabled) { - // Instead of setting drawing cache in the view itself, we simply - // enable drawing caching on its children. This is mainly used in - // animations (see PropertyAnimator) - super.setChildrenDrawnWithCacheEnabled(enabled); - } - } - - private class FullScreenHolder extends FrameLayout { - - public FullScreenHolder(Context ctx) { - super(ctx); - } - - @Override - public void addView(View view, int index) { - /** - * This normally gets called when Flash adds a separate SurfaceView - * for the video. It is unhappy if we have the LayerView underneath - * it for some reason so we need to hide that. Hiding the LayerView causes - * its surface to be destroyed, which causes a pause composition - * event to be sent to Gecko. We synchronously wait for that to be - * processed. Simultaneously, however, Flash is waiting on a mutex so - * the post() below is an attempt to avoid a deadlock. - */ - super.addView(view, index); - - ThreadUtils.postToUiThread(new Runnable() { - @Override - public void run() { - mLayerView.hide(); - } - }); - } - - /** - * The methods below are simply copied from what Android WebKit does. - * It wasn't ever called in my testing, but might as well - * keep it in case it is for some reason. The methods - * all return true because we don't want any events - * leaking out from the fullscreen view. - */ - @Override - public boolean onKeyDown(int keyCode, KeyEvent event) { - if (event.isSystem()) { - return super.onKeyDown(keyCode, event); - } - mFullScreenPluginView.onKeyDown(keyCode, event); - return true; - } - - @Override - public boolean onKeyUp(int keyCode, KeyEvent event) { - if (event.isSystem()) { - return super.onKeyUp(keyCode, event); - } - mFullScreenPluginView.onKeyUp(keyCode, event); - return true; - } - - @Override - public boolean onTouchEvent(MotionEvent event) { - return true; - } - - @Override - public boolean onTrackballEvent(MotionEvent event) { - mFullScreenPluginView.onTrackballEvent(event); - return true; - } - } - - protected NotificationClient makeNotificationClient() { - // Don't use a notification service; we may be killed in the background - // during downloads. - return new AppNotificationClient(getApplicationContext()); - } - - private int getVersionCode() { - int versionCode = 0; - try { - versionCode = getPackageManager().getPackageInfo(getPackageName(), 0).versionCode; - } catch (NameNotFoundException e) { - Log.wtf(LOGTAG, getPackageName() + " not found", e); - } - return versionCode; - } -} |