This commit is contained in:
Doug Turner 2011-10-10 17:40:17 -07:00
parent 0e5f5831f8
commit 952b4094a1
39 changed files with 1471 additions and 4716 deletions

View File

@ -4343,7 +4343,7 @@ MOZ_RDF=1
MOZ_REFLOW_PERF=
MOZ_SAFE_BROWSING=
MOZ_HELP_VIEWER=
MOZ_SPELLCHECK=1
MOZ_SPELLCHECK=
MOZ_SVG_DLISTS=
MOZ_TOOLKIT_SEARCH=1
MOZ_UI_LOCALE=en-US

View File

@ -249,6 +249,10 @@
#include "nsLocation.h"
#include "nsWrapperCacheInlines.h"
#if defined(ANDROID) && defined(DEBUG)
#include <android/log.h>
#endif
#ifdef PR_LOGGING
static PRLogModuleInfo* gDOMLeakPRLog;
#endif
@ -4525,6 +4529,9 @@ nsGlobalWindow::Dump(const nsAString& aStr)
nsMemory::Free(cstr);
}
#if defined(ANDROID) && defined(DEBUG)
__android_log_print(ANDROID_LOG_INFO, "GeckoDump", "%s", cstr);
#endif
return NS_OK;
}

View File

@ -51,9 +51,13 @@
#include "nsReadableUtils.h"
#include "nsIObserverService.h"
#include "mozilla/Services.h"
#ifdef MOZ_SPELLCHECK
#include "mozISpellCheckingEngine.h"
#include "nsIEditorSpellCheck.h"
#include "mozInlineSpellChecker.h"
#include "nsIInlineSpellChecker.h"
#endif
#include "nsIDOMText.h"
#include "nsIDOMElement.h"
@ -107,7 +111,6 @@
#include "nsEditorUtils.h"
#include "nsEditorEventListener.h"
#include "nsISelectionDisplay.h"
#include "nsIInlineSpellChecker.h"
#include "nsINameSpaceManager.h"
#include "nsIHTMLDocument.h"
#include "nsIParserService.h"
@ -308,12 +311,14 @@ nsEditor::PostCreate()
NotifyDocumentListeners(eDocumentCreated);
NotifyDocumentListeners(eDocumentStateChanged);
#ifdef MOZ_SPELLCHECK
nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
if (obs) {
obs->AddObserver(this,
SPELLCHECK_DICTIONARY_UPDATE_NOTIFICATION,
PR_FALSE);
}
#endif
}
// update nsTextStateManager and caret if we have focus
@ -426,11 +431,13 @@ nsEditor::PreDestroy(bool aDestroyingFrames)
if (mDidPreDestroy)
return NS_OK;
#ifdef MOZ_SPELLCHECK
nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
if (obs) {
obs->RemoveObserver(this,
SPELLCHECK_DICTIONARY_UPDATE_NOTIFICATION);
}
#endif
// Let spellchecker clean up its observers etc. It is important not to
// actually free the spellchecker here, since the spellchecker could have
@ -1294,6 +1301,7 @@ nsEditor::MarkNodeDirty(nsIDOMNode* aNode)
NS_IMETHODIMP nsEditor::GetInlineSpellChecker(bool autoCreate,
nsIInlineSpellChecker ** aInlineSpellChecker)
{
#ifdef MOZ_SPELLCHECK
NS_ENSURE_ARG_POINTER(aInlineSpellChecker);
if (mDidPreDestroy) {
@ -1326,11 +1334,15 @@ NS_IMETHODIMP nsEditor::GetInlineSpellChecker(bool autoCreate,
NS_IF_ADDREF(*aInlineSpellChecker = mInlineSpellChecker);
return NS_OK;
#else
return NS_ERROR_FAILURE;
#endif
}
NS_IMETHODIMP nsEditor::Observe(nsISupports* aSubj, const char *aTopic,
const PRUnichar *aData)
{
#ifdef MOZ_SPELLCHECK
NS_ASSERTION(!strcmp(aTopic,
SPELLCHECK_DICTIONARY_UPDATE_NOTIFICATION),
"Unexpected observer topic");
@ -1354,6 +1366,9 @@ NS_IMETHODIMP nsEditor::Observe(nsISupports* aSubj, const char *aTopic,
}
return NS_OK;
#else
return NS_OK;
#endif
}
NS_IMETHODIMP nsEditor::SyncRealTimeSpell()

View File

@ -123,5 +123,6 @@
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
<activity android:name="org.mozilla.gecko.AwesomeBar"></activity>
</application>
</manifest>

View File

@ -0,0 +1,211 @@
/* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Mozilla Android code.
*
* The Initial Developer of the Original Code is Mozilla Foundation.
* Portions created by the Initial Developer are Copyright (C) 2011
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Vladimir Vukicevic <vladimir@pobox.com>
* Wes Johnston <wjohnston@mozilla.com>
* Mark Finkle <mfinkle@mozilla.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
package org.mozilla.gecko;
import java.io.*;
import org.mozilla.gecko.*;
import android.os.*;
import android.content.*;
import android.app.*;
import android.text.*;
import android.util.*;
import android.widget.*;
import android.database.sqlite.*;
import android.database.*;
import android.view.*;
import android.net.Uri;
import android.graphics.*;
public class AwesomeBar extends ListActivity {
public static final String URL_KEY = "url";
public static final String TITLE_KEY = "title";
public static final String CURRENT_URL_KEY = "currenturl";
public class AwesomeBarCursorAdapter extends SimpleCursorAdapter {
private Cursor _cursor;
private Context _context;
public AwesomeBarCursorAdapter(Context context, int layout, Cursor c, String[] from, int[] to) {
// Using the older, deprecated constructor so we can work on API < 11
super(context, layout, c, from, to);
_cursor = c;
_context = context;
}
@Override
public void bindView(View view, Context context, Cursor cursor) {
super.bindView(view, context, cursor);
// ImageView imageView = (ImageView) view.findViewById(R.id.favicon);
// byte[] raw = cursor.getBlob(cursor.getColumnIndexOrThrow("favicon"));
// Bitmap bitmap = Bitmap.createScaledBitmap(BitmapFactory.decodeByteArray(raw, 0, raw.length), 48, 48, true);
// imageView.setImageBitmap(bitmap);
}
}
private Cursor mCursor;
private SQLiteDatabase mDb;
private AwesomeBarCursorAdapter adapter;
private String getProfilePath() {
File home = new File(getFilesDir(), "mozilla");
if (!home.exists())
return null;
File profile = null;
String[] files = home.list();
for (int i = 0; i < files.length; i++) {
if (files[i].endsWith(".default")) {
profile = new File(home, files[i]);
break;
}
}
if (profile == null)
return null;
File webapps = new File(profile, "places.sqlite");
if (!webapps.exists())
return null;
return webapps.getPath();
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.d("AwesomeBar", "creating awesomebar");
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.awesomebar_search);
// Load the list using a custom adapter so we can create the bitmaps
adapter = new AwesomeBarCursorAdapter(
this,
R.layout.awesomebar_row,
null,
new String[] { TITLE_KEY, URL_KEY },
new int[] { android.R.id.text1, android.R.id.text2 }
);
setListAdapter(adapter);
final EditText text = (EditText)findViewById(R.id.awesomebar_text);
String currentUrl = getIntent().getStringExtra(CURRENT_URL_KEY);
if (currentUrl != null) {
text.setText(currentUrl);
text.selectAll();
}
text.addTextChangedListener(new TextWatcher() {
public void afterTextChanged(Editable s) {
// do nothing
}
public void beforeTextChanged(CharSequence s, int start, int count,
int after) {
// do nothing
}
public void onTextChanged(CharSequence s, int start, int before,
int count) {
adapter.getFilter().filter(s.toString());
}
});
text.setOnKeyListener(new View.OnKeyListener() {
public boolean onKey(View v, int keyCode, KeyEvent event) {
if (keyCode != KeyEvent.KEYCODE_ENTER)
return false;
Intent resultIntent = new Intent();
resultIntent.putExtra(URL_KEY, text.getText().toString());
setResult(Activity.RESULT_OK, resultIntent);
finish();
return true;
}
});
DatabaseHelper dbHelper = new DatabaseHelper(this);
mDb = dbHelper.getReadableDatabase();
adapter.setFilterQueryProvider(new FilterQueryProvider() {
@Override
public Cursor runQuery(CharSequence constraint) {
// _id column required for CursorAdapter; provide a dummy here
mCursor = mDb.rawQuery(
"SELECT 0 AS _id, title, url "
+ "FROM moz_places "
+ "WHERE (url LIKE ? OR title LIKE ?) "
+ "LIMIT 12",
new String[] {"%" + constraint.toString() + "%", "%" + constraint.toString() + "%",});
return mCursor;
}
});
// show unfiltered results initially
adapter.getFilter().filter("");
}
@Override
public void onDestroy() {
super.onDestroy();
if (mCursor != null) mCursor.close();
if (mDb != null) mDb.close();
}
@Override
public void onListItemClick(ListView l, View v, int position, long id) {
Cursor cursor = (Cursor)l.getItemAtPosition(position);
String url = cursor.getString(cursor.getColumnIndexOrThrow(URL_KEY));
Intent resultIntent = new Intent();
resultIntent.putExtra(URL_KEY, url);
setResult(Activity.RESULT_OK, resultIntent);
finish();
}
}

View File

@ -0,0 +1,174 @@
/*
* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Places code.
*
* The Initial Developer of the Original Code is
* Mozilla Corporation.
* Portions created by the Initial Developer are Copyright (C) 2008
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Shawn Wilsher <me@shawnwilsher.com> (Original Author)
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
package org.mozilla.gecko;
import android.content.*;
import android.database.sqlite.*;
import android.util.*;
class DatabaseHelper extends SQLiteOpenHelper {
private static final String CREATE_MOZ_PLACES =
"CREATE TABLE moz_places ( " +
" id INTEGER PRIMARY KEY" +
", url LONGVARCHAR UNIQUE" +
", title LONGVARCHAR" +
", rev_host LONGVARCHAR" +
", visit_count INTEGER DEFAULT 0" +
", hidden INTEGER DEFAULT 0 NOT NULL" +
", typed INTEGER DEFAULT 0 NOT NULL" +
", favicon_id INTEGER" +
", frecency INTEGER DEFAULT -1 NOT NULL" +
", last_visit_date INTEGER " +
", guid TEXT" +
")";
private static final String CREATE_MOZ_HISTORYVISITS =
"CREATE TABLE moz_historyvisits (" +
" id INTEGER PRIMARY KEY" +
", from_visit INTEGER" +
", place_id INTEGER" +
", visit_date INTEGER" +
", visit_type INTEGER" +
", session INTEGER" +
")";
private static final String CREATE_MOZ_INPUTHISTORY =
"CREATE TABLE moz_inputhistory (" +
" place_id INTEGER NOT NULL" +
", input LONGVARCHAR NOT NULL" +
", use_count INTEGER" +
", PRIMARY KEY (place_id, input)" +
")";
private static final String CREATE_MOZ_ANNOS =
"CREATE TABLE moz_annos (" +
" id INTEGER PRIMARY KEY" +
", place_id INTEGER NOT NULL" +
", anno_attribute_id INTEGER" +
", mime_type VARCHAR(32) DEFAULT NULL" +
", content LONGVARCHAR" +
", flags INTEGER DEFAULT 0" +
", expiration INTEGER DEFAULT 0" +
", type INTEGER DEFAULT 0" +
", dateAdded INTEGER DEFAULT 0" +
", lastModified INTEGER DEFAULT 0" +
")";
private static final String CREATE_MOZ_ANNO_ATTRIBUTES =
"CREATE TABLE moz_anno_attributes (" +
" id INTEGER PRIMARY KEY" +
", name VARCHAR(32) UNIQUE NOT NULL" +
")";
private static final String CREATE_MOZ_ITEMS_ANNOS =
"CREATE TABLE moz_items_annos (" +
" id INTEGER PRIMARY KEY" +
", item_id INTEGER NOT NULL" +
", anno_attribute_id INTEGER" +
", mime_type VARCHAR(32) DEFAULT NULL" +
", content LONGVARCHAR" +
", flags INTEGER DEFAULT 0" +
", expiration INTEGER DEFAULT 0" +
", type INTEGER DEFAULT 0" +
", dateAdded INTEGER DEFAULT 0" +
", lastModified INTEGER DEFAULT 0" +
")";
private static final String CREATE_MOZ_FAVICONS =
"CREATE TABLE moz_favicons (" +
" id INTEGER PRIMARY KEY" +
", url LONGVARCHAR UNIQUE" +
", data BLOB" +
", mime_type VARCHAR(32)" +
", expiration LONG" +
")";
private static final String CREATE_MOZ_BOOKMARKS =
"CREATE TABLE moz_bookmarks (" +
" id INTEGER PRIMARY KEY" +
", type INTEGER" +
", fk INTEGER DEFAULT NULL" +
", parent INTEGER" +
", position INTEGER" +
", title LONGVARCHAR" +
", keyword_id INTEGER" +
", folder_type TEXT" +
", dateAdded INTEGER" +
", lastModified INTEGER" +
", guid TEXT" +
")";
private static final String CREATE_MOZ_BOOKMARKS_ROOTS =
"CREATE TABLE moz_bookmarks_roots (" +
" root_name VARCHAR(16) UNIQUE" +
", folder_id INTEGER" +
")";
private static final String CREATE_MOZ_KEYWORDS =
"CREATE TABLE moz_keywords (" +
" id INTEGER PRIMARY KEY AUTOINCREMENT" +
", keyword TEXT UNIQUE" +
")";
private static final String DATABASE_NAME = "places";
private static final int DATABASE_VERSION = 1;
DatabaseHelper(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
@Override
public void onCreate(SQLiteDatabase db) {
db.execSQL(CREATE_MOZ_PLACES);
db.execSQL(CREATE_MOZ_HISTORYVISITS);
db.execSQL(CREATE_MOZ_BOOKMARKS);
db.execSQL(CREATE_MOZ_BOOKMARKS_ROOTS);
db.execSQL(CREATE_MOZ_FAVICONS);
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
Log.w("DatabaseHelper", "Upgrading database from version " + oldVersion + " to "
+ newVersion + ", which will destroy all old data");
db.execSQL("DROP TABLE IF EXISTS places");
onCreate(db);
}
}

View File

@ -61,6 +61,7 @@ import android.hardware.*;
import android.util.*;
import android.net.*;
import android.database.*;
import android.database.sqlite.*;
import android.provider.*;
import android.content.pm.*;
import android.content.pm.PackageManager.*;
@ -77,21 +78,37 @@ abstract public class GeckoApp
public static final String ACTION_DEBUG = "org.mozilla.gecko.DEBUG";
public static final String ACTION_BOOKMARK = "org.mozilla.gecko.BOOKMARK";
public static AbsoluteLayout mainLayout;
public static LinearLayout mainLayout;
public static AbsoluteLayout geckoLayout;
public static GeckoSurfaceView surfaceView;
public static GeckoApp mAppContext;
public static boolean mFullscreen = false;
public static File sGREDir = null;
static Thread mLibLoadThread = null;
public Handler mMainHandler;
private IntentFilter mConnectivityFilter;
private BroadcastReceiver mConnectivityReceiver;
public static EditText mAwesomeBar;
public static ProgressBar mProgressBar;
private static SQLiteDatabase mDb;
private static DatabaseHelper mDbHelper;
private static Stack<HistoryEntry> sessionHistory;
enum LaunchState {PreLaunch, Launching, WaitForDebugger,
enum LaunchState {Launching, WaitButton,
Launched, GeckoRunning, GeckoExiting};
private static LaunchState sLaunchState = LaunchState.PreLaunch;
private static LaunchState sLaunchState = LaunchState.Launching;
private static boolean sTryCatchAttached = false;
private static final int FILE_PICKER_REQUEST = 1;
private static final int AWESOMEBAR_REQUEST = 2;
public static class HistoryEntry {
public String uri;
public String title;
public HistoryEntry(String uri, String title) {
this.uri = uri;
this.title = title;
}
}
static boolean checkLaunchState(LaunchState checkState) {
synchronized(sLaunchState) {
@ -150,6 +167,8 @@ abstract public class GeckoApp
String[] getPluginDirectories() {
Log.w(LOGTAG, "zerdatime " + new Date().getTime() + " - start of getPluginDirectories");
ArrayList<String> directories = new ArrayList<String>();
PackageManager pm = this.mAppContext.getPackageManager();
List<ResolveInfo> plugins = pm.queryIntentServices(new Intent(PLUGIN_ACTION),
@ -265,7 +284,9 @@ abstract public class GeckoApp
}
}
return directories.toArray(new String[directories.size()]);
String [] result = directories.toArray(new String[directories.size()]);
Log.w(LOGTAG, "zerdatime " + new Date().getTime() + " - end of getPluginDirectories");
return result;
}
Class<?> getPluginClass(String packageName, String className)
@ -280,6 +301,8 @@ abstract public class GeckoApp
// Returns true when the intent is going to be handled by gecko launch
boolean launch(Intent intent)
{
Log.w(LOGTAG, "zerdatime " + new Date().getTime() + " - launch");
if (!checkAndSetLaunchState(LaunchState.Launching, LaunchState.Launched))
return false;
@ -288,37 +311,35 @@ abstract public class GeckoApp
final Intent i = intent;
new Thread() {
public void run() {
try {
if (mLibLoadThread != null)
mLibLoadThread.join();
} catch (InterruptedException ie) {}
File cacheFile = GeckoAppShell.getCacheDir();
File libxulFile = new File(cacheFile, "libxul.so");
// Show the URL we are about to load, if the intent has one
if (Intent.ACTION_VIEW.equals(i.getAction())) {
surfaceView.mSplashURL = i.getDataString();
}
surfaceView.drawSplashScreen();
if ((!libxulFile.exists() ||
new File(getApplication().getPackageResourcePath()).lastModified() >= libxulFile.lastModified())) {
File[] libs = cacheFile.listFiles(new FilenameFilter() {
public boolean accept(File dir, String name) {
return name.endsWith(".so");
}
});
if (libs != null) {
for (int i = 0; i < libs.length; i++) {
libs[i].delete();
}
}
}
// At some point while loading the gecko libs our default locale gets set
// so just save it to locale here and reset it as default after the join
Locale locale = Locale.getDefault();
GeckoAppShell.loadGeckoLibs(
getApplication().getPackageResourcePath());
Locale.setDefault(locale);
Resources res = getBaseContext().getResources();
Configuration config = res.getConfiguration();
config.locale = locale;
res.updateConfiguration(config, res.getDisplayMetrics());
// unpack files in the components directory
try {
unpackComponents();
} catch (FileNotFoundException fnfe) {
Log.e(LOG_FILE_NAME, "error unpacking components", fnfe);
Looper.prepare();
showErrorDialog(getString(R.string.error_loading_file));
Looper.loop();
return;
} catch (IOException ie) {
Log.e(LOG_FILE_NAME, "error unpacking components", ie);
String msg = ie.getMessage();
Looper.prepare();
if (msg != null && msg.equalsIgnoreCase("No space left on device"))
showErrorDialog(getString(R.string.no_space_to_start_error));
else
showErrorDialog(getString(R.string.error_loading_file));
Looper.loop();
return;
}
Log.w(LOGTAG, "zerdatime " + new Date().getTime() + " - runGecko");
// and then fire us up
try {
@ -337,11 +358,62 @@ abstract public class GeckoApp
return true;
}
@Override
public boolean onCreateOptionsMenu(Menu menu)
{
final Activity self = this;
MenuItem quitItem = menu.add("Quit");
quitItem.setIcon(android.R.drawable.ic_menu_close_clear_cancel);
quitItem.setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() {
public boolean onMenuItemClick(MenuItem item) {
quit();
return true;
}
});
return true;
}
private void quit() {
Log.i(LOG_FILE_NAME, "pleaseKillMe");
if (surfaceView != null)
surfaceView.saveLast();
System.exit(0);
}
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState)
{
Log.w(LOGTAG, "zerdatime " + new Date().getTime() + " - onCreate");
super.onCreate(savedInstanceState);
getWindow().setFlags(mFullscreen ?
WindowManager.LayoutParams.FLAG_FULLSCREEN : 0,
WindowManager.LayoutParams.FLAG_FULLSCREEN);
getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN);
setContentView(R.layout.gecko_app);
mAppContext = this;
// setup gecko layout
geckoLayout = (AbsoluteLayout) findViewById(R.id.geckoLayout);
surfaceView = new GeckoSurfaceView(this);
geckoLayout.addView(surfaceView,
new AbsoluteLayout.LayoutParams(AbsoluteLayout.LayoutParams.MATCH_PARENT,
AbsoluteLayout.LayoutParams.MATCH_PARENT,
0,
0));
Log.w(LOGTAG, "zerdatime " + new Date().getTime() + " - UI almost up");
if (sGREDir == null)
sGREDir = new File(this.getApplicationInfo().dataDir);
mDbHelper = new DatabaseHelper(this);
sessionHistory = new Stack<HistoryEntry>();
mMainHandler = new Handler();
if (!sTryCatchAttached) {
@ -362,63 +434,79 @@ abstract public class GeckoApp
});
}
SharedPreferences settings = getPreferences(Activity.MODE_PRIVATE);
String localeCode = settings.getString(getPackageName() + ".locale", "");
if (localeCode != null && localeCode.length() > 0)
GeckoAppShell.setSelectedLocale(localeCode);
mainLayout = (LinearLayout) findViewById(R.id.mainLayout);
mProgressBar = (ProgressBar) findViewById(R.id.progressBar);
Log.i(LOG_FILE_NAME, "create");
super.onCreate(savedInstanceState);
// setup awesome bar
mAwesomeBar = (EditText) findViewById(R.id.awesomeBar);
mAwesomeBar.setOnClickListener(new EditText.OnClickListener() {
public void onClick(View v) {
onSearchRequested();
}
});
if (sGREDir == null)
sGREDir = new File(this.getApplicationInfo().dataDir);
getWindow().setFlags(mFullscreen ?
WindowManager.LayoutParams.FLAG_FULLSCREEN : 0,
WindowManager.LayoutParams.FLAG_FULLSCREEN);
if (surfaceView == null)
surfaceView = new GeckoSurfaceView(this);
else
mainLayout.removeAllViews();
mainLayout = new AbsoluteLayout(this);
mainLayout.addView(surfaceView,
new AbsoluteLayout.LayoutParams(AbsoluteLayout.LayoutParams.MATCH_PARENT, // level 8
AbsoluteLayout.LayoutParams.MATCH_PARENT,
0,
0));
setContentView(mainLayout,
new ViewGroup.LayoutParams(ViewGroup.LayoutParams.FILL_PARENT,
ViewGroup.LayoutParams.FILL_PARENT));
ImageButton reload = (ImageButton) findViewById(R.id.reload);
reload.setOnClickListener(new ImageButton.OnClickListener() {
public void onClick(View v) {
doReload();
}
});
mConnectivityFilter = new IntentFilter();
mConnectivityFilter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
mConnectivityReceiver = new GeckoConnectivityReceiver();
if (!checkAndSetLaunchState(LaunchState.PreLaunch,
LaunchState.Launching))
return;
checkAndLaunchUpdate();
mLibLoadThread = new Thread(new Runnable() {
mMainHandler.post(new Runnable() {
public void run() {
// At some point while loading the gecko libs our default locale gets set
// so just save it to locale here and reset it as default after the join
Locale locale = Locale.getDefault();
GeckoAppShell.loadGeckoLibs(
getApplication().getPackageResourcePath());
Locale.setDefault(locale);
Resources res = getBaseContext().getResources();
Configuration config = res.getConfiguration();
config.locale = locale;
res.updateConfiguration(config, res.getDisplayMetrics());
}});
mLibLoadThread.start();
surfaceView.loadStartupBitmap();
}
});
final GeckoApp self = this;
mMainHandler.postDelayed(new Runnable() {
public void run() {
Log.w(LOGTAG, "zerdatime " + new Date().getTime() + " - pre checkLaunchState");
SharedPreferences settings = getPreferences(Activity.MODE_PRIVATE);
String localeCode = settings.getString(getPackageName() + ".locale", "");
if (localeCode != null && localeCode.length() > 0)
GeckoAppShell.setSelectedLocale(localeCode);
if (!checkLaunchState(LaunchState.Launched)) {
return;
}
if (false) {
checkAndLaunchUpdate();
}
}
}, 50);
}
public static void addHistoryEntry(final HistoryEntry entry) {
new Thread(new Runnable() {
public void run() {
Log.d("GeckoApp", "adding uri=" + entry.uri + ", title=" + entry.title + " to history");
ContentValues values = new ContentValues();
values.put("url", entry.uri);
values.put("title", entry.title);
if (sessionHistory.empty() || !sessionHistory.peek().uri.equals(entry.uri))
sessionHistory.push(entry);
mDb = mDbHelper.getWritableDatabase();
long id = mDb.insertWithOnConflict("moz_places", null, values, SQLiteDatabase.CONFLICT_REPLACE);
values = new ContentValues();
values.put("place_id", id);
mDb.insertWithOnConflict("moz_historyvisits", null, values, SQLiteDatabase.CONFLICT_REPLACE);
}
}).start();
}
@Override
protected void onNewIntent(Intent intent) {
Log.w(LOGTAG, "zerdatime " + new Date().getTime() + " - onNewIntent");
if (checkLaunchState(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
@ -427,19 +515,21 @@ abstract public class GeckoApp
}
final String action = intent.getAction();
if (ACTION_DEBUG.equals(action) &&
checkAndSetLaunchState(LaunchState.Launching, LaunchState.WaitForDebugger)) {
mMainHandler.postDelayed(new Runnable() {
public void run() {
Log.i(LOG_FILE_NAME, "Launching from debug intent after 5s wait");
checkAndSetLaunchState(LaunchState.Launching, LaunchState.WaitButton)) {
final Button launchButton = new Button(this);
launchButton.setText("Launch"); // don't need to localize
launchButton.setOnClickListener(new Button.OnClickListener() {
public void onClick (View v) {
// hide the button so we can't be launched again
mainLayout.removeView(launchButton);
setLaunchState(LaunchState.Launching);
launch(null);
}
}, 1000 * 5 /* 5 seconds */);
Log.i(LOG_FILE_NAME, "Intent : ACTION_DEBUG - waiting 5s before launching");
});
mainLayout.addView(launchButton, 300, 200);
return;
}
if (checkLaunchState(LaunchState.WaitForDebugger) || launch(intent))
if (checkLaunchState(LaunchState.WaitButton) || launch(intent))
return;
if (Intent.ACTION_MAIN.equals(action)) {
@ -492,8 +582,7 @@ abstract public class GeckoApp
super.onResume();
// Just in case. Normally we start in onNewIntent
if (checkLaunchState(LaunchState.PreLaunch) ||
checkLaunchState(LaunchState.Launching))
if (checkLaunchState(LaunchState.Launching))
onNewIntent(getIntent());
registerReceiver(mConnectivityReceiver, mConnectivityFilter);
@ -531,6 +620,8 @@ abstract public class GeckoApp
@Override
public void onStart()
{
Log.w(LOGTAG, "zerdatime " + new Date().getTime() + " - onStart");
Log.i(LOG_FILE_NAME, "start");
GeckoAppShell.sendEventToGecko(new GeckoEvent(GeckoEvent.ACTIVITY_START));
super.onStart();
@ -540,6 +631,10 @@ abstract public class GeckoApp
public void onDestroy()
{
Log.i(LOG_FILE_NAME, "destroy");
if (mDb != null)
mDb.close();
// Tell Gecko to shutting down; we'll end up calling System.exit()
// in onXreExit.
if (isFinishing())
@ -568,97 +663,6 @@ abstract public class GeckoApp
abstract public String getPackageName();
abstract public String getContentProcessName();
protected void unpackComponents()
throws IOException, FileNotFoundException
{
File applicationPackage = new File(getApplication().getPackageResourcePath());
File componentsDir = new File(sGREDir, "components");
if (componentsDir.lastModified() == applicationPackage.lastModified())
return;
componentsDir.mkdir();
componentsDir.setLastModified(applicationPackage.lastModified());
GeckoAppShell.killAnyZombies();
ZipFile zip = new ZipFile(applicationPackage);
byte[] buf = new byte[32768];
try {
if (unpackFile(zip, buf, null, "removed-files"))
removeFiles();
} catch (Exception ex) {
// This file may not be there, so just log any errors and move on
Log.w(LOG_FILE_NAME, "error removing files", ex);
}
unpackFile(zip, buf, null, "application.ini");
unpackFile(zip, buf, null, getContentProcessName());
try {
unpackFile(zip, buf, null, "update.locale");
} catch (Exception e) {/* this is non-fatal */}
// copy any .xpi file into an extensions/ directory
Enumeration<? extends ZipEntry> zipEntries = zip.entries();
while (zipEntries.hasMoreElements()) {
ZipEntry entry = zipEntries.nextElement();
if (entry.getName().startsWith("extensions/") && entry.getName().endsWith(".xpi")) {
Log.i("GeckoAppJava", "installing extension : " + entry.getName());
unpackFile(zip, buf, entry, entry.getName());
}
}
}
void removeFiles() throws IOException {
BufferedReader reader = new BufferedReader(
new FileReader(new File(sGREDir, "removed-files")));
try {
for (String removedFileName = reader.readLine();
removedFileName != null; removedFileName = reader.readLine()) {
File removedFile = new File(sGREDir, removedFileName);
if (removedFile.exists())
removedFile.delete();
}
} finally {
reader.close();
}
}
private boolean unpackFile(ZipFile zip, byte[] buf, ZipEntry fileEntry,
String name)
throws IOException, FileNotFoundException
{
if (fileEntry == null)
fileEntry = zip.getEntry(name);
if (fileEntry == null)
throw new FileNotFoundException("Can't find " + name + " in " +
zip.getName());
File outFile = new File(sGREDir, name);
if (outFile.lastModified() == fileEntry.getTime() &&
outFile.length() == fileEntry.getSize())
return false;
File dir = outFile.getParentFile();
if (!dir.exists())
dir.mkdirs();
InputStream fileStream;
fileStream = zip.getInputStream(fileEntry);
OutputStream outStream = new FileOutputStream(outFile);
while (fileStream.available() > 0) {
int read = fileStream.read(buf, 0, buf.length);
outStream.write(buf, 0, read);
}
fileStream.close();
outStream.close();
outFile.setLastModified(fileEntry.getTime());
return true;
}
public void addEnvToIntent(Intent intent) {
Map<String,String> envMap = System.getenv();
Set<Map.Entry<String,String>> envSet = envMap.entrySet();
@ -767,8 +771,6 @@ abstract public class GeckoApp
return status;
}
static final int FILE_PICKER_REQUEST = 1;
private SynchronousQueue<String> mFilePickerResult = new SynchronousQueue();
public String showFilePicker(String aMimeType) {
Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
@ -793,59 +795,115 @@ abstract public class GeckoApp
}
@Override
protected void onActivityResult(int requestCode, int resultCode,
Intent data) {
String filePickerResult = "";
if (data != null && resultCode == RESULT_OK) {
try {
ContentResolver cr = getContentResolver();
Uri uri = data.getData();
Cursor cursor = GeckoApp.mAppContext.getContentResolver().query(
uri,
new String[] { OpenableColumns.DISPLAY_NAME },
null,
null,
null);
String name = null;
if (cursor != null) {
try {
if (cursor.moveToNext()) {
name = cursor.getString(0);
}
} finally {
cursor.close();
}
}
String fileName = "tmp_";
String fileExt = null;
int period;
if (name == null || (period = name.lastIndexOf('.')) == -1) {
String mimeType = cr.getType(uri);
fileExt = "." + GeckoAppShell.getExtensionFromMimeType(mimeType);
} else {
fileExt = name.substring(period);
fileName = name.substring(0, period);
}
File file = File.createTempFile(fileName, fileExt, sGREDir);
public boolean onSearchRequested() {
Intent searchIntent = new Intent(getBaseContext(), AwesomeBar.class);
searchIntent.addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION | Intent.FLAG_ACTIVITY_NO_HISTORY);
if (!sessionHistory.empty())
searchIntent.putExtra(AwesomeBar.CURRENT_URL_KEY, sessionHistory.peek().uri);
FileOutputStream fos = new FileOutputStream(file);
InputStream is = cr.openInputStream(uri);
byte[] buf = new byte[4096];
int len = is.read(buf);
while (len != -1) {
fos.write(buf, 0, len);
len = is.read(buf);
}
fos.close();
filePickerResult = file.getAbsolutePath();
}catch (Exception e) {
Log.e(LOG_FILE_NAME, "showing file picker", e);
}
}
try {
mFilePickerResult.put(filePickerResult);
} catch (InterruptedException e) {
Log.i(LOG_FILE_NAME, "error returning file picker result", e);
startActivityForResult(searchIntent, AWESOMEBAR_REQUEST);
return true;
}
public boolean doReload() {
Log.i("GeckoApp", "Reload requested");
if (sessionHistory.empty())
return false;
String currUri = sessionHistory.peek().uri;
GeckoAppShell.sendEventToGecko(new GeckoEvent(currUri));
return true;
}
@Override
public void onBackPressed() {
if (sessionHistory.size() > 1) {
sessionHistory.pop();
String uri = sessionHistory.peek().uri;
Log.i("GeckoApp", "going back to page: " + uri);
loadUrl(uri);
} else {
finish();
}
}
@Override
protected void onActivityResult(int requestCode, int resultCode,
Intent data) {
super.onActivityResult(requestCode, resultCode, data);
switch (requestCode) {
case FILE_PICKER_REQUEST:
String filePickerResult = "";
if (data != null && resultCode == RESULT_OK) {
try {
ContentResolver cr = getContentResolver();
Uri uri = data.getData();
Cursor cursor = GeckoApp.mAppContext.getContentResolver().query(
uri,
new String[] { OpenableColumns.DISPLAY_NAME },
null,
null,
null);
String name = null;
if (cursor != null) {
try {
if (cursor.moveToNext()) {
name = cursor.getString(0);
}
} finally {
cursor.close();
}
}
String fileName = "tmp_";
String fileExt = null;
int period;
if (name == null || (period = name.lastIndexOf('.')) == -1) {
String mimeType = cr.getType(uri);
fileExt = "." + GeckoAppShell.getExtensionFromMimeType(mimeType);
} else {
fileExt = name.substring(period);
fileName = name.substring(0, period);
}
File file = File.createTempFile(fileName, fileExt, sGREDir);
FileOutputStream fos = new FileOutputStream(file);
InputStream is = cr.openInputStream(uri);
byte[] buf = new byte[4096];
int len = is.read(buf);
while (len != -1) {
fos.write(buf, 0, len);
len = is.read(buf);
}
fos.close();
filePickerResult = file.getAbsolutePath();
}catch (Exception e) {
Log.e(LOG_FILE_NAME, "showing file picker", e);
}
}
try {
mFilePickerResult.put(filePickerResult);
} catch (InterruptedException e) {
Log.i(LOG_FILE_NAME, "error returning file picker result", e);
}
break;
case AWESOMEBAR_REQUEST:
if (data != null) {
String url = data.getStringExtra(AwesomeBar.URL_KEY);
if (url != null && url.length() > 0) {
mProgressBar.setVisibility(View.VISIBLE);
mProgressBar.setIndeterminate(true);
loadUrl(url);
}
}
break;
}
}
public void loadUrl(String url) {
mAwesomeBar.setText(url);
GeckoAppShell.sendEventToGecko(new GeckoEvent(url));
}
}

View File

@ -71,6 +71,9 @@ import android.net.NetworkInfo;
import android.graphics.drawable.*;
import android.graphics.Bitmap;
import org.json.JSONArray;
import org.json.JSONObject;
public class GeckoAppShell
{
private static final String LOG_FILE_NAME = "GeckoAppShell";
@ -1046,10 +1049,6 @@ public class GeckoAppShell
imm.showInputMethodPicker();
}
public static void hideProgressDialog() {
GeckoApp.surfaceView.mShowingSplashScreen = false;
}
public static void setKeepScreenOn(final boolean on) {
GeckoApp.mAppContext.runOnUiThread(new Runnable() {
public void run() {
@ -1354,17 +1353,17 @@ public class GeckoAppShell
(int)x,
(int)y);
if (GeckoApp.mainLayout.indexOfChild(view) == -1) {
if (GeckoApp.geckoLayout.indexOfChild(view) == -1) {
view.setWillNotDraw(false);
if(view instanceof SurfaceView)
((SurfaceView)view).setZOrderOnTop(true);
GeckoApp.mainLayout.addView(view, lp);
GeckoApp.geckoLayout.addView(view, lp);
}
else
{
try {
GeckoApp.mainLayout.updateViewLayout(view, lp);
GeckoApp.geckoLayout.updateViewLayout(view, lp);
} catch (IllegalArgumentException e) {
Log.i("updateViewLayout - IllegalArgumentException", "e:" + e);
// it can be the case where we
@ -1381,7 +1380,7 @@ public class GeckoAppShell
getMainHandler().post(new Runnable() {
public void run() {
try {
GeckoApp.mainLayout.removeView(view);
GeckoApp.geckoLayout.removeView(view);
} catch (Exception e) {}
}
});
@ -1620,4 +1619,79 @@ public class GeckoAppShell
sCameraBuffer = null;
}
}
public static void handleGeckoMessage(String message) {
//
// {"gecko": {
// "type": "value",
// "event_specific": "value",
// ....
try {
JSONObject json = new JSONObject(message);
JSONObject geckoObject = json.getJSONObject("gecko");
String type = geckoObject.getString("type");
if (type.equals("DOMContentLoaded")) {
final String uri = geckoObject.getString("uri");
final String title = geckoObject.getString("title");
final String stat = geckoObject.getString("stat");
final CharSequence titleText = title;
getMainHandler().post(new Runnable() {
public void run() {
GeckoApp.mAwesomeBar.setText(titleText);
GeckoApp.addHistoryEntry(new GeckoApp.HistoryEntry(uri, title));
GeckoApp.mProgressBar.setVisibility(View.GONE);
}
});
Log.i("GeckoShell", "URI - " + uri + ", title - " + title + ", status - " + stat);
}
else if (type.equals("log")) {
// generic log listener
final String msg = geckoObject.getString("msg");
Log.i("GeckoShell", "Log: " + msg);
}
else if (type.equals("onLocationChange")) {
final String uri = geckoObject.getString("uri");
final CharSequence uriText = uri;
Log.i("GeckoShell", "URI - " + uri);
getMainHandler().post(new Runnable() {
public void run() {
GeckoApp.mAwesomeBar.setText(uriText);
}
});
}
else if (type.equals("onStateChange")) {
String state = geckoObject.getString("state");
String stateIs = geckoObject.getString("stateIs");
if (state == "start") {
GeckoApp.mProgressBar.setVisibility(View.VISIBLE);
GeckoApp.mProgressBar.setIndeterminate(true);
}
}
else if (type.equals("onProgressChange")) {
final int current = geckoObject.getInt("current");
final int total = geckoObject.getInt("total");
getMainHandler().post(new Runnable() {
public void run() {
if (total == -1) {
GeckoApp.mProgressBar.setIndeterminate(true);
} else if (current < total) {
GeckoApp.mProgressBar.setIndeterminate(false);
GeckoApp.mProgressBar.setMax(total);
GeckoApp.mProgressBar.setProgress(current);
}
else {
GeckoApp.mProgressBar.setIndeterminate(false);
}
}
});
Log.i("GeckoShell", "progress - " + current + "/" + total);
}
} catch (Exception e) {
Log.i("GeckoShell", "handleGeckoMessage throws "+e);
}
}
}

View File

@ -73,6 +73,7 @@ public class GeckoEvent {
public static final int SURFACE_DESTROYED = 14;
public static final int GECKO_EVENT_SYNC = 15;
public static final int ACTIVITY_START = 17;
public static final int SAVE_STATE = 18;
public static final int IME_COMPOSITION_END = 0;
public static final int IME_COMPOSITION_BEGIN = 1;

View File

@ -102,91 +102,48 @@ class GeckoSurfaceView
super.finalize();
}
void drawSplashScreen() {
this.drawSplashScreen(getHolder(), mWidth, mHeight);
/*
* Called on main thread
*/
public String getStartupBitmapFilePath() {
File file = new File(Environment.getExternalStorageDirectory(),
"lastScreen.png");
return file.toString();
}
void drawSplashScreen(SurfaceHolder holder, int width, int height) {
// No splash screen for Honeycomb or greater
if (Build.VERSION.SDK_INT >= 11) {
Log.i(LOG_FILE_NAME, "skipping splash screen");
return;
public void loadStartupBitmap() {
try {
String filePath = getStartupBitmapFilePath();
mStartupBitmap = BitmapFactory.decodeFile(filePath);
} catch (Exception e) {
Log.e(LOG_FILE_NAME, e.toString());
}
}
public void drawStartupBitmap(SurfaceHolder holder, int width, int height) {
if (mStartupBitmap == null) {
Log.e(LOG_FILE_NAME, "!!! NO STARTUP BITMAP !!!");
loadStartupBitmap();
if (mStartupBitmap == null) {
mShowingLoadScreen = false;
return;
}
}
Canvas c = holder.lockCanvas();
if (c == null) {
Log.i(LOG_FILE_NAME, "canvas is null");
Log.e(LOG_FILE_NAME, "!!! NO CANVAS !!!");
mShowingLoadScreen = false;
return;
}
Resources res = getResources();
File watchDir = new File(GeckoApp.sGREDir, "components");
if (watchDir.exists() == false) {
// Just show the simple splash screen for "new profile" startup
c.drawColor(res.getColor(R.color.splash_background));
Drawable drawable = res.getDrawable(R.drawable.splash);
int w = drawable.getIntrinsicWidth();
int h = drawable.getIntrinsicHeight();
int x = (width - w) / 2;
int y = (height - h) / 2 - 16;
drawable.setBounds(x, y, x + w, y + h);
drawable.draw(c);
Paint p = new Paint();
p.setTextAlign(Paint.Align.CENTER);
p.setTextSize(32f);
p.setAntiAlias(true);
p.setColor(res.getColor(R.color.splash_msgfont));
c.drawText(res.getString(R.string.splash_firstrun), width / 2, y + h + 16, p);
} else {
// Show the static UI for normal startup
DisplayMetrics metrics = new DisplayMetrics();
GeckoApp.mAppContext.getWindowManager().getDefaultDisplay().getMetrics(metrics);
// Default to DENSITY_HIGH sizes
int toolbarHeight = 80;
int faviconOffset = 25;
float urlHeight = 24f;
int urlOffsetX = 80;
int urlOffsetY = 48;
if (metrics.densityDpi == DisplayMetrics.DENSITY_MEDIUM) {
toolbarHeight = 53;
faviconOffset = 10;
urlHeight = 16f;
urlOffsetX = 53;
urlOffsetY = 32;
}
c.drawColor(res.getColor(R.color.splash_content));
Drawable toolbar = res.getDrawable(Build.VERSION.SDK_INT > 8 ?
R.drawable.splash_v9 :
R.drawable.splash_v8);
toolbar.setBounds(0, 0, width, toolbarHeight);
toolbar.draw(c);
// XUL/CSS always uses 32px width and height for favicon
Drawable favicon = res.getDrawable(R.drawable.favicon32);
favicon.setBounds(faviconOffset, faviconOffset, 32 + faviconOffset, 32 + faviconOffset);
favicon.draw(c);
if (GeckoSurfaceView.mSplashURL != "") {
TextPaint p = new TextPaint();
p.setTextAlign(Paint.Align.LEFT);
p.setTextSize(urlHeight);
p.setAntiAlias(true);
p.setColor(res.getColor(R.color.splash_urlfont));
String url = TextUtils.ellipsize(GeckoSurfaceView.mSplashURL, p, width - urlOffsetX * 2, TextUtils.TruncateAt.END).toString();
c.drawText(url, urlOffsetX, urlOffsetY, p);
}
}
Drawable drawable = new BitmapDrawable(mStartupBitmap);
drawable.setBounds(0, 0, width, height);
drawable.draw(c);
holder.unlockCanvasAndPost(c);
}
/*
* Called on main thread
*/
public void draw(SurfaceHolder holder, ByteBuffer buffer) {
if (buffer == null || buffer.capacity() != (mWidth * mHeight * 2))
return;
@ -199,7 +156,7 @@ class GeckoSurfaceView
if (c == null)
return;
mSoftwareBufferCopy.copyPixelsFromBuffer(buffer);
c.drawBitmap(mSoftwareBufferCopy, 0, 0, null);
c.drawBitmap(mLastBitmap = mSoftwareBufferCopy, 0, 0, null);
holder.unlockCanvasAndPost(c);
}
}
@ -216,12 +173,23 @@ class GeckoSurfaceView
Canvas c = holder.lockCanvas();
if (c == null)
return;
c.drawBitmap(bitmap, 0, 0, null);
c.drawBitmap(mLastBitmap = bitmap, 0, 0, null);
holder.unlockCanvasAndPost(c);
}
}
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
Log.i(LOG_FILE_NAME, "surfaceChanged: fmt: " + format + " dim: " + width + " " + height);
mFormat = format;
mWidth = width;
mHeight = height;
if (mShowingLoadScreen) {
drawStartupBitmap(holder, width, height);
if (mStartupBitmap != null)
return;
}
// Force exactly one frame to render
// because the surface change is only seen after we
@ -243,9 +211,6 @@ class GeckoSurfaceView
mAbortDraw = false;
}
if (mShowingSplashScreen)
drawSplashScreen(holder, width, height);
mSurfaceLock.lock();
if (mInDrawing) {
@ -269,9 +234,6 @@ class GeckoSurfaceView
GeckoApp.checkLaunchState(GeckoApp.LaunchState.GeckoRunning);
mSyncDraw = doSyncDraw;
mFormat = format;
mWidth = width;
mHeight = height;
mSurfaceValid = true;
Log.i(LOG_FILE_NAME, "surfaceChanged: fmt: " + format + " dim: " + width + " " + height);
@ -304,7 +266,7 @@ class GeckoSurfaceView
} else {
Log.e("GeckoSurfaceViewJava", "Synchronised draw object is null");
}
} else if (!mShowingSplashScreen) {
} else if (!mShowingLoadScreen) {
// Make sure a frame is drawn before we return
// otherwise we see artifacts or a black screen
GeckoAppShell.scheduleRedraw();
@ -316,16 +278,26 @@ class GeckoSurfaceView
Log.i(LOG_FILE_NAME, "surface created");
GeckoEvent e = new GeckoEvent(GeckoEvent.SURFACE_CREATED);
GeckoAppShell.sendEventToGecko(e);
if (mShowingSplashScreen)
drawSplashScreen();
}
public void saveLast() {
GeckoEvent event = new GeckoEvent();
event.mType = GeckoEvent.SAVE_STATE;
event.mCharacters = getStartupBitmapFilePath();
GeckoAppShell.sendEventToGecko(event);
}
public void surfaceDestroyed(SurfaceHolder holder) {
Log.i(LOG_FILE_NAME, "surface destroyed");
saveLast();
mShowingLoadScreen = true;
mStartupBitmap = mLastBitmap;
mSurfaceValid = false;
mSoftwareBuffer = null;
mSoftwareBufferCopy = null;
mSoftwareBitmap = null;
mLastBitmap = null;
GeckoEvent e = new GeckoEvent(GeckoEvent.SURFACE_DESTROYED);
if (mDrawMode == DRAW_GLES_2) {
// Ensure GL cleanup occurs before we return.
@ -381,6 +353,8 @@ class GeckoSurfaceView
public static final int DRAW_DISABLED = 3;
public int beginDrawing() {
mStartupBitmap = null;
if (mInDrawing) {
Log.e(LOG_FILE_NAME, "Recursive beginDrawing call!");
return DRAW_ERROR;
@ -635,6 +609,12 @@ class GeckoSurfaceView
// event stuff
public boolean onTouchEvent(MotionEvent event) {
this.requestFocus(FOCUS_UP, null);
if (mShowingLoadScreen == true) {
mShowingLoadScreen = false;
surfaceChanged(getHolder(), mFormat, mWidth, mHeight);
}
GeckoAppShell.sendEventToGecko(new GeckoEvent(event));
return true;
}
@ -670,13 +650,6 @@ class GeckoSurfaceView
return false;
}
case KeyEvent.KEYCODE_MENU:
if (event.getRepeatCount() == 0) {
event.startTracking();
break;
} else if ((event.getFlags() & KeyEvent.FLAG_LONG_PRESS) != 0) {
break;
}
// Ignore repeats for KEYCODE_MENU; they confuse the widget code.
return false;
case KeyEvent.KEYCODE_VOLUME_UP:
case KeyEvent.KEYCODE_VOLUME_DOWN:
@ -723,7 +696,11 @@ class GeckoSurfaceView
case KeyEvent.KEYCODE_BACK:
if (!event.isTracking() || event.isCanceled())
return false;
break;
GeckoApp.mAppContext.onBackPressed();
return true;
case KeyEvent.KEYCODE_SEARCH:
case KeyEvent.KEYCODE_MENU:
return false;
default:
break;
}
@ -782,8 +759,7 @@ class GeckoSurfaceView
// True if gecko requests a buffer
int mDrawMode;
static boolean mShowingSplashScreen = true;
static String mSplashURL = "";
static boolean mShowingLoadScreen = true;
// let's not change stuff around while we're in the middle of
// starting drawing, ending drawing, or changing surface
@ -822,6 +798,8 @@ class GeckoSurfaceView
Bitmap mSoftwareBitmap;
ByteBuffer mSoftwareBuffer;
Bitmap mSoftwareBufferCopy;
Bitmap mStartupBitmap;
Bitmap mLastBitmap;
Geocoder mGeocoder;
Address mLastGeoAddress;

View File

@ -54,6 +54,8 @@ JAVAFILES = \
GeckoInputConnection.java \
AlertNotification.java \
SurfaceLockInfo.java \
AwesomeBar.java \
DatabaseHelper.java \
$(NULL)
PROCESSEDJAVAFILES = \
@ -120,11 +122,14 @@ DEFINES += -DMOZ_ANDROID_SHARED_ID="$(ANDROID_PACKAGE_NAME).sharedID"
endif
RES_LAYOUT = \
res/layout/gecko_app.xml \
res/layout/notification_progress.xml \
res/layout/notification_progress_text.xml \
res/layout/notification_icon_text.xml \
res/layout/launch_app_list.xml \
res/layout/launch_app_listitem.xml \
res/layout/awesomebar_search.xml \
res/layout/awesomebar_row.xml \
$(NULL)
RES_VALUES = res/values/colors.xml res/values/themes.xml
@ -144,7 +149,7 @@ MOZ_ANDROID_DRAWABLES += embedding/android/resources/drawable/crash_reporter.png
RES_LAYOUT += res/layout/crash_reporter.xml
endif
MOZ_ANDROID_DRAWABLES += embedding/android/resources/drawable/desktop_notification.png
MOZ_ANDROID_DRAWABLES += embedding/android/resources/drawable/desktop_notification.png embedding/android/resources/drawable/favicon.png embedding/android/resources/drawable/reload.png
MOZ_ANDROID_DRAWABLES += $(shell if test -e $(topsrcdir)/$(MOZ_BRANDING_DIRECTORY)/android-resources.mn; then cat $(topsrcdir)/$(MOZ_BRANDING_DIRECTORY)/android-resources.mn | tr '\n' ' '; fi)
@ -161,7 +166,7 @@ include $(topsrcdir)/config/android-common.mk
# Instead of on the .class files, since more than one .class file might be produced per .java file
classes.dex: $(JAVAFILES) $(PROCESSEDJAVAFILES) R.java
$(NSINSTALL) -D classes
$(JAVAC) $(JAVAC_FLAGS) -d classes $(addprefix $(srcdir)/,$(JAVAFILES)) $(PROCESSEDJAVAFILES) R.java
$(JAVAC) $(JAVAC_FLAGS) -Xlint:unchecked -Xlint:deprecation -d classes $(addprefix $(srcdir)/,$(JAVAFILES)) $(PROCESSEDJAVAFILES) R.java
$(DX) --dex --output=$@ classes
AndroidManifest.xml $(PROCESSEDJAVAFILES): % : %.in

Binary file not shown.

After

Width:  |  Height:  |  Size: 268 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 567 B

View File

@ -0,0 +1,32 @@
<?xml version="1.0" encoding="utf-8"?>
<TwoLineListItem xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content">
<ImageView
android:id="@+id/favicon"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_marginRight="6dip"/>
<TextView android:id="@android:id/text1"
android:layout_marginTop="1dip"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_toRightOf="@id/favicon"
android:textColor="#fff"
android:textSize="15sp"
android:textStyle="bold" />
<TextView android:id="@android:id/text2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@android:id/text1"
android:layout_alignLeft="@android:id/text1"
android:paddingBottom="4dip"
android:includeFontPadding="false"
android:textColor="#8ac"
android:textSize="15sp"
android:textStyle="normal" />
</TwoLineListItem>

View File

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent" android:weightSum="1">
<EditText android:layout_height="wrap_content" android:layout_width="match_parent" android:id="@+id/awesomebar_text">
<requestFocus/>
</EditText>
<ListView android:layout_height="fill_parent" android:id="@android:id/list" android:layout_width="match_parent"></ListView>
</LinearLayout>

View File

@ -0,0 +1,45 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+android:id/mainLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<ProgressBar android:id="@+android:id/progressBar"
style="@android:style/Widget.ProgressBar.Horizontal"
android:layout_width="fill_parent"
android:layout_height="10dip"
android:visibility="gone"/>
<LinearLayout android:id="@+android:id/addressBar"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<ImageButton android:id="@+android:id/favicon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/favicon"/>
<EditText android:id="@+android:id/awesomeBar"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:layout_weight="1"
android:singleLine="true"
android:imeOptions="actionGo"
android:inputType="textNoSuggestions|textFilter"/>
<ImageButton android:id="@+android:id/reload"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/reload"/>
</LinearLayout>
<AbsoluteLayout android:id="@+android:id/geckoLayout"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_weight="1"/>
</LinearLayout>

View File

@ -674,7 +674,7 @@ pref("browser.firstrun.show.localepicker", true);
// $ adb shell stop
// $ adb shell setprop log.redirect-stdio true
// $ adb shell start
pref("browser.dom.window.dump.enabled", false);
pref("browser.dom.window.dump.enabled", true);
// controls if we want camera support
pref("device.camera.enabled", true);

File diff suppressed because it is too large Load Diff

View File

@ -1,780 +1,14 @@
<?xml version="1.0"?>
<!-- ***** BEGIN LICENSE BLOCK *****
- Version: MPL 1.1/GPL 2.0/LGPL 2.1
-
- The contents of this file are subject to the Mozilla Public License Version
- 1.1 (the "License"); you may not use this file except in compliance with
- the License. You may obtain a copy of the License at
- http://www.mozilla.org/MPL/
-
- Software distributed under the License is distributed on an "AS IS" basis,
- WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- for the specific language governing rights and limitations under the
- License.
-
- The Original Code is Mozilla Mobile Browser.
-
- The Initial Developer of the Original Code is
- Mozilla Corporation.
- Portions created by the Initial Developer are Copyright (C) 2008
- the Initial Developer. All Rights Reserved.
-
- Contributor(s):
- Brad Lassey <blassey@mozilla.com>
- Mark Finkle <mfinkle@mozila.com>
- Matt Brubeck <mbrubeck@mozila.com>
-
- Alternatively, the contents of this file may be used under the terms of
- either the GNU General Public License Version 2 or later (the "GPL"), or
- the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
- in which case the provisions of the GPL or the LGPL are applicable instead
- of those above. If you wish to allow use of your version of this file only
- under the terms of either the GPL or the LGPL, and not to allow others to
- use your version of this file under the terms of the MPL, indicate your
- decision by deleting the provisions above and replace them with the notice
- and other provisions required by the LGPL or the GPL. If you do not delete
- the provisions above, a recipient may use your version of this file under
- the terms of any one of the MPL, the GPL or the LGPL.
-
- ***** END LICENSE BLOCK ***** -->
<?xml-stylesheet href="chrome://browser/skin/platform.css" type="text/css"?>
<?xml-stylesheet href="chrome://browser/skin/browser.css" type="text/css"?>
<?xml-stylesheet href="chrome://browser/skin/forms.css" type="text/css"?>
<?xml-stylesheet href="chrome://browser/content/browser.css" type="text/css"?>
<!DOCTYPE window [
<!ENTITY % globalDTD SYSTEM "chrome://global/locale/global.dtd">
%globalDTD;
<!ENTITY % browserDTD SYSTEM "chrome://browser/locale/browser.dtd">
%browserDTD;
<!ENTITY % brandDTD SYSTEM "chrome://branding/locale/brand.dtd">
%brandDTD;
<!ENTITY % prefsDTD SYSTEM "chrome://browser/locale/preferences.dtd">
%prefsDTD;
#ifdef MOZ_SERVICES_SYNC
<!ENTITY % syncDTD SYSTEM "chrome://browser/locale/sync.dtd">
%syncDTD;
#endif
]>
<window id="main-window"
onload="Browser.startup();"
onunload="Browser.shutdown();"
onclose="return Browser.closing();"
onload="startup();"
windowtype="navigator:browser"
chromedir="&locale.dir;"
title="&brandShortName;"
#ifdef MOZ_PLATFORM_MAEMO
sizemode="fullscreen"
#else
#ifndef ANDROID
width="480"
height="800"
#endif
#endif
onkeypress="onDebugKeyPress(event);"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns:html="http://www.w3.org/1999/xhtml">
<script type="application/javascript" src="chrome://browser/content/browser.js"/>
<script type="application/javascript" src="chrome://browser/content/browser-ui.js"/>
<script type="application/javascript" src="chrome://browser/content/browser-scripts.js"/>
<script type="application/javascript" src="chrome://browser/content/Util.js"/>
<script type="application/javascript" src="chrome://browser/content/input.js"/>
<script type="application/javascript" src="chrome://browser/content/browser.js"/>
<broadcasterset id="broadcasterset">
<broadcaster id="bcast_contentShowing" disabled="false"/>
<broadcaster id="bcast_urlbarState" mode="view" tablet_sidebar="true" persist="tablet_sidebar"/>
<broadcaster id="bcast_uidiscovery"/>
</broadcasterset>
<observerset id="observerset">
<observes id="observe_contentShowing" element="bcast_contentShowing" attribute="disabled" onbroadcast="BrowserUI.updateUIFocus();"/>
</observerset>
<commandset id="mainCommandSet">
<!-- basic navigation -->
<command id="cmd_back" label="&back.label;" disabled="true" oncommand="CommandUpdater.doCommand(this.id);"/>
<command id="cmd_forward" label="&forward.label;" disabled="true" oncommand="CommandUpdater.doCommand(this.id);" observes="bcast_urlbarState"/>
<command id="cmd_reload" label="&reload.label;" oncommand="CommandUpdater.doCommand(this.id);"/>
<command id="cmd_forceReload" oncommand="CommandUpdater.doCommand(this.id);"/>
<command id="cmd_stop" label="&stop.label;" oncommand="CommandUpdater.doCommand(this.id);"/>
<command id="cmd_go" label="&go.label;" oncommand="CommandUpdater.doCommand(this.id);"/>
<command id="cmd_openLocation" oncommand="CommandUpdater.doCommand(this.id);"/>
<!-- tabs -->
<command id="cmd_showTabs" oncommand="CommandUpdater.doCommand(this.id);"/>
<command id="cmd_newTab" label="&newtab.label;" oncommand="CommandUpdater.doCommand(this.id);"/>
<command id="cmd_closeTab" label="&closetab.label;" oncommand="CommandUpdater.doCommand(this.id);"/>
#ifdef MOZ_SERVICES_SYNC
<command id="cmd_remoteTabs" oncommand="CommandUpdater.doCommand(this.id);"/>
#endif
<command id="cmd_undoCloseTab" oncommand="CommandUpdater.doCommand(this.id);"/>
<!-- bookmarking -->
<command id="cmd_star" label="&star.label;" oncommand="CommandUpdater.doCommand(this.id);"/>
<!-- misc -->
<command id="cmd_close" oncommand="CommandUpdater.doCommand(this.id);"/>
<command id="cmd_quit" oncommand="CommandUpdater.doCommand(this.id);"/>
<command id="cmd_menu" oncommand="CommandUpdater.doCommand(this.id);"/>
<command id="cmd_actions" oncommand="CommandUpdater.doCommand(this.id);"/>
<command id="cmd_opensearch" oncommand="CommandUpdater.doCommand(this.id);"/>
<command id="cmd_panel" oncommand="CommandUpdater.doCommand(this.id);"/>
<command id="cmd_bookmarks" oncommand="CommandUpdater.doCommand(this.id);"/>
<command id="cmd_history" oncommand="CommandUpdater.doCommand(this.id);"/>
<command id="cmd_sanitize" oncommand="CommandUpdater.doCommand(this.id);"/>
<!-- screen/display -->
<command id="cmd_fullscreen" oncommand="CommandUpdater.doCommand(this.id);"/>
<command id="cmd_zoomin" observes="bcast_contentShowing" oncommand="CommandUpdater.doCommand(this.id);"/>
<command id="cmd_zoomout" observes="bcast_contentShowing" oncommand="CommandUpdater.doCommand(this.id);"/>
<command id="cmd_lockscreen" oncommand="CommandUpdater.doCommand(this.id);"/>
<command id="cmd_volumeLeft" observes="bcast_contentShowing" oncommand="CommandUpdater.doCommand(this.id);"/>
<command id="cmd_volumeRight" observes="bcast_contentShowing" oncommand="CommandUpdater.doCommand(this.id);"/>
<!-- scrolling -->
<command id="cmd_scrollPageUp" oncommand="CommandUpdater.doCommand(this.id);"/>
<command id="cmd_scrollPageDown" oncommand="CommandUpdater.doCommand(this.id);"/>
<!-- editing -->
<command id="cmd_cut" label="&cut.label;" oncommand="CommandUpdater.doCommand(this.id);"/>
<command id="cmd_copy" label="&copy.label;" oncommand="CommandUpdater.doCommand(this.id);"/>
<command id="cmd_copylink" label="&copylink.label;" oncommand="CommandUpdater.doCommand(this.id);"/>
<command id="cmd_paste" label="&paste.label;" oncommand="CommandUpdater.doCommand(this.id);"/>
<command id="cmd_delete" label="&delete.label;" oncommand="CommandUpdater.doCommand(this.id);"/>
<command id="cmd_selectAll" label="&selectAll.label;" oncommand="CommandUpdater.doCommand(this.id);"/>
<!-- forms navigation -->
<command id="cmd_formPrevious" oncommand="FormHelperUI.goToPrevious();"/>
<command id="cmd_formNext" oncommand="FormHelperUI.goToNext();"/>
<command id="cmd_formClose" oncommand="FormHelperUI.hide();"/>
<!-- find navigation -->
<command id="cmd_findPrevious" oncommand="FindHelperUI.goToPrevious();"/>
<command id="cmd_findNext" oncommand="FindHelperUI.goToNext();"/>
<command id="cmd_findClose" oncommand="FindHelperUI.hide();"/>
<command id="cmd_find" oncommand="FindHelperUI.show();"/>
</commandset>
<keyset id="mainKeyset">
<!-- basic navigation -->
<key id="key_back" keycode="VK_LEFT" command="cmd_back" modifiers="control"/>
<key id="key_forward" keycode="VK_RIGHT" command="cmd_forward" modifiers="control"/>
#ifndef ANDROID
<key id="key_back2" keycode="VK_BACK" command="cmd_back"/>
<key id="key_forward2" keycode="VK_BACK" command="cmd_forward" modifiers="shift"/>
#endif
#ifndef MOZ_PLATFORM_MAEMO
<key id="key_reload" keycode="VK_F5" command="cmd_reload"/>
<key id="key_forceReload" keycode="VK_F5" modifiers="shift" command="cmd_forceReload"/>
#else
<key id="key_lockscreen" key="o" modifiers="accel,shift" command="cmd_lockscreen"/>
<!-- F5 on maemo is "home" which is a task switching key -->
#endif
<key id="key_reload2" key="r" modifiers="accel" command="cmd_reload"/>
<key id="key_forceReload2" key="r" modifiers="accel,shift" command="cmd_forceReload"/>
<key id="key_focusURL" key="l" modifiers="accel" command="cmd_openLocation"/>
<!-- scrolling -->
<key id="key_pageUp" keycode="VK_UP" modifiers="shift" command="cmd_scrollPageUp"/>
<key id="key_pageDown" keycode="VK_DOWN" modifiers="shift" command="cmd_scrollPageDown"/>
<!-- misc -->
<key id="key_zoomin" keycode="VK_UP" modifiers="accel" command="cmd_zoomin"/>
<key id="key_zoomout" keycode="VK_DOWN" modifiers="accel" command="cmd_zoomout"/>
<key id="key_find" key="f" modifiers="accel" command="cmd_find"/>
<key id="key_quit" key="q" modifiers="accel" command="cmd_quit"/>
<key id="key_fullscreen" keycode="VK_F6" command="cmd_fullscreen"/>
<key id="key_zoomin2" keycode="VK_F7" command="cmd_volumeRight"/>
<key id="key_zoomout2" keycode="VK_F8" command="cmd_volumeLeft"/>
<!-- tabs -->
<key id="key_newTab" key="t" modifiers="accel" command="cmd_newTab"/>
<key id="key_closeTab" key="w" modifiers="accel" command="cmd_closeTab"/>
<key id="key_undoCloseTab" key="t" modifiers="accel,shift" command="cmd_undoCloseTab"/>
</keyset>
<stack flex="1" id="stack">
<scrollbox id="controls-scrollbox" style="overflow: hidden; -moz-box-orient: horizontal; position: relative;" flex="1" observes="bcast_urlbarState">
<vbox id="tabs-sidebar" class="sidebar" observes="bcast_uidiscovery">
<spacer class="toolbar-height" id="tabs-spacer" observes="bcast_urlbarState"/>
<!-- Left toolbar -->
<vbox id="tabs-container" class="panel-dark" flex="1" observes="bcast_urlbarState">
<vbox id="tabs" flex="1" observes="bcast_urlbarState"
onselect="BrowserUI.selectTab(this);"
onreloadtab="BrowserUI.undoCloseTab()"
onclosetab="BrowserUI.closeTab(this)"
onclosereloadtab="this._container.removeTab(this)"/>
<hbox id="tabs-controls">
<toolbarbutton id="newtab-button" class="button-control" command="cmd_newTab" label="&newtab.label;" observes="bcast_urlbarState" crop="end"/>
</hbox>
</vbox>
</vbox>
<!-- Page Area -->
<stack id="page-stack" observes="bcast_urlbarState">
<scrollbox id="page-scrollbox">
<vbox>
<!-- Main Toolbar -->
<box id="toolbar-container" class="panel-dark toolbar-height">
<box id="toolbar-moveable-container" observes="bcast_uidiscovery">
<toolbar id="toolbar-main" class="panel-dark viewable-width" observes="bcast_urlbarState">
<toolbarbutton id="tool-tabs" class="button-actionbar" command="cmd_showTabs" anchorPosX="0.3"/>
<toolbarbutton id="tool-back2" class="tool-back button-actionbar" command="cmd_back"/>
<toolbarbutton id="tool-forward2" class="tool-forward button-actionbar" command="cmd_forward"/>
#ifdef MOZ_PLATFORM_MAEMO
#if MOZ_PLATFORM_MAEMO != 6
<toolbarbutton id="tool-app-switch" oncommand="BrowserUI.switchTask();"/>
#endif
#endif
<hbox id="urlbar-container" flex="1" observes="bcast_urlbarState">
<box id="identity-box" class="urlbar-cap-button"
onclick="getIdentityHandler().handleIdentityButtonEvent(event);"
onkeypress="getIdentityHandler().handleIdentityButtonEvent(event);">
<box id="urlbar-image-box" mousethrough="always">
<image id="urlbar-throbber"/>
<image id="urlbar-favicon" hidden="true"/>
</box>
</box>
<label id="urlbar-title" class="uri-element" crop="end" flex="1"
command="cmd_openLocation" onclick="this.doCommand();"
placeholder="&urlbar.emptytext;"/>
<textbox id="urlbar-edit"
type="url"
mozactionhint="go"
class="uri-element"
autocompletesearch="history"
autocompletepopup="popup_autocomplete"
completeselectedindex="true"
minresultsforpopup="0"
onsearchbegin="AwesomeScreen.updateHeader(this.controller.searchString);"
placeholder="&urlbar.emptytext;"
collapsed="true"
flex="1"
readonly="true"
ontextentered="BrowserUI.goToURI();"
clickSelectsAll="true"/>
<hbox id="urlbar-icons" class="urlbar-cap-button" observes="bcast_urlbarState">
<toolbarbutton id="tool-reload" oncommand="CommandUpdater.doCommand(event.shiftKey ? 'cmd_forceReload' : 'cmd_reload');"/>
<toolbarbutton id="tool-stop" command="cmd_stop"/>
<toolbarbutton id="tool-search" command="cmd_opensearch"/>
</hbox>
</hbox>
<toolbarbutton id="tool-star2" class="tool-star button-actionbar" command="cmd_star"/>
<toolbarbutton id="tool-menu" class="button-actionbar" command="cmd_menu"/>
#ifndef ANDROID
<toolbarbutton id="tool-app-close" class="urlbar-button" command="cmd_close"/>
#endif
</toolbar>
</box>
</box>
<!-- Content viewport -->
<vbox id="content-viewport" class="viewable-width viewable-height">
<!-- Content viewport -->
<stack>
<deck id="browsers" flex="1" observes="bcast_uidiscovery"/>
<!-- vertical scrollbar -->
<box id="vertical-scroller" class="scroller" orient="vertical" end="2" top="0"/>
</stack>
</vbox>
</vbox>
</scrollbox>
<!-- popup for content navigator helper -->
<vbox id="content-navigator" top="0">
<textbox id="find-helper-textbox" class="search-bar content-navigator-item" oncommand="FindHelperUI.search(this.value)" oninput="FindHelperUI.updateCommands(this.value);" type="search"/>
</vbox>
<!-- horizontal scrollbar -->
<box id="horizontal-scroller" class="scroller" orient="horizontal" left="0" bottom="2"/>
</stack>
<!-- Right toolbar -->
<vbox id="controls-sidebar" class="sidebar" observes="bcast_uidiscovery">
<!-- Because of the stack + fixed position of the urlbar when it is in
locked mode the event on the top-right part of the urlbar are
swallow by this spacer, but not with the mousethrough attribute
-->
<spacer class="toolbar-height" mousethrough="always"/>
<vbox id="browser-controls" style="overflow: -moz-hidden-unscrollable;" class="panel-dark" flex="1">
<toolbarbutton id="tool-star" class="tool-star button-control" command="cmd_star"/>
<toolbarbutton id="tool-back" class="tool-back button-control" command="cmd_back"/>
<toolbarbutton id="tool-forward" class="tool-forward button-control" command="cmd_forward"/>
<toolbarspring/>
<toolbarbutton id="tool-panel-open" class="button-control" command="cmd_panel"/>
</vbox>
</vbox>
</scrollbox>
<!-- Form Helper suggestions helper popup -->
<arrowbox id="form-helper-suggestions-container" flex="1" hidden="true" offset="0" top="0" left="0">
<arrowscrollbox id="form-helper-suggestions" align="center" flex="1" orient="horizontal" onclick="FormHelperUI.doAutoComplete(event.target);"/>
</arrowbox>
<!-- Tabs sidebar helper popup -->
<arrowbox id="tabs-popup-container" hidden="true" offset="18" type="dialog">
<vbox id="tabs-popup-inner-container" flex="1">
<richlistbox id="tabs-popup-list" flex="1"
onselect="BrowserUI.selectTab(this); TabsPopup.hide();"
onreloadtab="BrowserUI.undoCloseTab(); TabsPopup.hide();"
onclosetab="BrowserUI.closeTab(this); TabsPopup.closeTab(this);"/>
<button id="tabs-popup-newtab-button" class="show-text" command="cmd_newTab"/>
</vbox>
</arrowbox>
<!-- popup for site identity information -->
<arrowbox id="identity-container" hidden="true" mode="unknownIdentity" offset="18" flex="1" type="dialog" observes="bcast_urlbarState">
<box id="identity-popup-container" flex="1" align="top">
<image id="identity-popup-icon"/>
<vbox id="identity-popup-content-box" flex="1">
<box id="identity-popup-connected-box" flex="1">
<label id="identity-popup-connectedToLabel" value="&identity.connectedTo2;"/>
<label id="identity-popup-connectedToLabel2" flex="1">&identity.unverifiedsite2;</label>
<description id="identity-popup-content-host" flex="1"/>
</box>
<box id="identity-popup-runBy-box">
<label id="identity-popup-runByLabel" value="&identity.runBy2;"/>
<description id="identity-popup-content-owner"/>
<description id="identity-popup-content-supplemental"/>
</box>
<description id="identity-popup-content-verifier"/>
</vbox>
<box id="identity-popup-encryption-box">
<image id="identity-popup-encryption-icon"/>
<description id="identity-popup-encryption-label"/>
</box>
</box>
<hbox id="pageactions-container" hidden="true">
#ifndef ANDROID
<pageaction id="pageaction-findinpage" title="&pageactions.findInPage;"
onclick="FindHelperUI.show();"/>
#ifdef NS_PRINTING
<pageaction id="pageaction-saveas" title="&pageactions.saveas.pdf;"
onclick="PageActions.savePageAsPDF();"/>
#endif
<pageaction id="pageaction-share" title="&pageactions.share.page;"
onclick="SharingUI.show(getBrowser().currentURI.spec, getBrowser().contentTitle);"/>
#endif
<pageaction id="pageaction-password" title="&pageactions.password.forget;"
onclick="PageActions.forgetPassword(event);"/>
<pageaction id="pageaction-reset" title="&pageactions.reset;"
onclick="PageActions.clearPagePermissions(event);"/>
<pageaction id="pageaction-search" title="&pageactions.search.addNew;"/>
<pageaction id="pageaction-charset" title="&pageactions.charEncoding;" onclick="CharsetMenu.show();"/>
</hbox>
</arrowbox>
<arrowbox id="bookmark-popup" hidden="true" align="stretch" offset="12" type="dialog">
<hbox id="bookmark-popup-title">
<label value="&bookmarkPopup.label;"/>
</hbox>
<richlistbox id="bookmark-popup-commands" class="action-buttons" onclick="BookmarkPopup.hide();" flex="1">
<richlistitem class="action-button" id="bookmark-popup-edit" onclick="BookmarkHelper.edit();">
<label value="&bookmarkEdit.label;"/>
</richlistitem>
<richlistitem class="action-button" id="bookmark-popup-remove" onclick="BookmarkPopup.hide(); BookmarkHelper.removeBookmarksForURI(getBrowser().currentURI);">
<label value="&bookmarkRemove.label;"/>
</richlistitem>
#ifdef ANDROID
<richlistitem class="action-button" id="bookmark-popup-shortcut" onclick="BookmarkPopup.addToHome();">
<label value="&bookmarkShortcut.label;"/>
</richlistitem>
#endif
</richlistbox>
</arrowbox>
<box id="bookmark-container" class="perm-modal-block" hidden="true">
<dialog id="bookmark-dialog" class="content-dialog" flex="1">
<hbox id="bookmark-form-title" class="prompt-title">
<description>&editBookmarkDialog.title;</description>
</hbox>
<separator id="bookmark-form-line" class="prompt-line"/>
<scrollbox id="bookmark-form" align="start" class="prompt-message" flex="1"/>
<hbox id="bookmark-form-buttons" pack="center" class="prompt-buttons">
<button label="&editBookmarkDone.label;" class="prompt-button" oncommand="BookmarkHelper.save();"/>
</hbox>
</dialog>
</box>
<!-- use an offset to remove the space taken by the invisible callout arrow -->
<arrowbox id="appmenu-popup" hidden="true" type="dialog" offset="18">
<box id="appmenu-popup-sitecommands"/>
<vbox id="appmenu-popup-appcommands"/>
</arrowbox>
<box id="panel-container" hidden="true" class="window-width window-height panel-dark"
style="-moz-stack-sizing: ignore" left="10000">
<box id="panel-container-inner" flex="1" class="panel-dark">
<box id="panel-controls" class="panel-row-header" oncommand="BrowserUI.switchPane(event.target.getAttribute('linkedpanel'));">
<toolbarbutton id="tool-preferences" label="&prefsHeader.label;" class="panel-row-button" type="radio" group="1" checked="true" linkedpanel="prefs-container"/>
<toolbarbutton id="tool-downloads" label="&downloadsHeader.label;" class="panel-row-button" type="radio" group="1" linkedpanel="downloads-container"/>
<toolbarbutton id="tool-addons" label="&addonsHeader.label;" class="panel-row-button" type="radio" group="1" linkedpanel="addons-container"/>
<toolbarbutton id="tool-console" label="&consoleHeader.label;" class="panel-row-button" type="radio" group="1" hidden="true" linkedpanel="console-container"/>
#ifndef ANDROID
<spacer flex="1"/>
<toolbarbutton id="tool-panel-close" class="panel-close" command="cmd_panel"/>
#endif
</box>
<vbox flex="1">
<deck id="panel-items" selectedIndex="2" flex="1">
<vbox id="addons-container" flex="1">
<notificationbox id="addons-messages" flex="1">
<richlistbox id="addons-list" class="panel-list" flex="1" onselect="ExtensionsView.hideOnSelect(event)">
<label id="addons-list-header" class="panel-header" value="&addonsHeader.label;"/>
<richlistitem id="addons-local" class="section-header" align="center" nohighlight="true">
<label value="&addonsLocal.label;" flex="1"/>
<spacer flex="1"/>
<button id="addons-update-all" label="&addonsUpdate.label;" hidden="true"
oncommand="ExtensionsView.updateAll();"/>
</richlistitem>
<richlistitem id="addons-repo" class="section-header" nohighlight="true">
<label value="&addonsRepo.label;" flex="1"/>
<textbox id="addons-search-text" flex="1" class="search-bar" placeholder="&addonsSearch2.emptytext;" type="search" searchbutton="false"
oncommand="ExtensionsView.getAddonsFromRepo(this.value);" onkeypress="if (event.keyCode == event.DOM_VK_RETURN) this.blur();"/>
</richlistitem>
</richlistbox>
</notificationbox>
</vbox>
<vbox id="downloads-container" flex="1">
<richlistbox id="downloads-list" class="panel-list" flex="1" onselect="this.ensureSelectedElementIsVisible()">
<label id="downloads-list-header" class="panel-header" value="&downloadsHeader.label;"/>
</richlistbox>
</vbox>
<vbox id="prefs-container" flex="1">
<notificationbox id="prefs-messages" flex="1">
<richlistbox id="prefs-list" class="panel-list" seltype="single" flex="1" onselect="this.ensureSelectedElementIsVisible()">
<label id="prefs-list-header" class="panel-header" value="&prefsHeader.label;"/>
<setting title="&about.title;" type="control">
<button id="prefs-about-button" label="&about.button;"
#ifdef MOZ_OFFICIAL_BRANDING
# these two point to the same page, this just matters for what shows up in the
# URL bar
oncommand="BrowserUI.newTab('about:firefox', Browser.selectedTab);"/>
#else
oncommand="BrowserUI.newTab('about:fennec', Browser.selectedTab);"/>
#endif
</setting>
<setting id="prefs-uilanguage" title="&language.title;" type="control">
<button id="prefs-uilanguage-button" label="&language.title;" onclick="PreferencesView.showLocalePicker();"/>
</setting>
<setting id="prefs-homepage" title="&homepage.title;" type="menulist">
<menulist id="prefs-homepage-options" oncommand="PreferencesView.updateHomePage();">
<menupopup onpopupshowing="PreferencesView.updateHomePageList();">
<menuitem id="prefs-homepage-default" label="&homepage.default;" value="default"/>
<menuitem id="prefs-homepage-none" label="&homepage.none;" value="none"/>
<menuitem id="prefs-homepage-currentpage" label="&homepage.currentpage;" value="currentpage"/>
</menupopup>
</menulist>
</setting>
#ifdef MOZ_SERVICES_SYNC
<settings id="prefs-sync" label="&sync.title;">
<setting id="sync-connect" title="&sync.notconnected;" type="control">
<button label="&sync.connect;" oncommand="WeaveGlue.tryConnect();" />
</setting>
<setting id="sync-connected" class="setting-group" title="&sync.connected;" type="control" collapsed="true">
<button id="sync-details" label="&sync.details;" type="checkbox" autocheck="false" checked="false" oncommand="WeaveGlue.showDetails();" />
</setting>
<setting id="sync-sync" class="setting-subgroup" type="control" collapsed="true">
<button id="sync-syncButton" label="&sync.syncNow;" oncommand="WeaveGlue.sync();"/>
</setting>
<setting id="sync-device" class="setting-subgroup" type="string" title="&sync.deviceName;" onchange="WeaveGlue.changeName(this);" collapsed="true"/>
<setting id="sync-disconnect" class="setting-subgroup" type="control" collapsed="true">
<button label="&sync.disconnect;" oncommand="WeaveGlue.disconnect();" />
</setting>
</settings>
#endif
<settings id="prefs-privacy" label="&privacy.title;">
<setting pref="network.cookie.cookieBehavior" title="&allowCookies.title;" type="boolint" on="0" off="2"/>
<setting pref="signon.rememberSignons" title="&rememberPasswords.title;" type="bool"/>
<setting pref="privacy.donottrackheader.enabled" title="&doNotTrack.title;" type="bool"/>
<setting id="prefs-master-password" title="&masterPassword.title;" type="bool" oncommand="MasterPasswordUI.show(this.value);"/>
<setting title="&clearPrivateData2.title;" type="control">
<button id="prefs-clear-data" label="&clearPrivateData.button;" command="cmd_sanitize"/>
</setting>
</settings>
<settings id="prefs-content" label="&content.title;">
<setting pref="browser.ui.zoom.reflow" title="&reflowZoom.title;" type="bool"/>
<setting pref="permissions.default.image" title="&showImages.title;" type="boolint" on="1" off="2"/>
<setting pref="javascript.enabled" type="bool" title="&enableJavaScript.title;"/>
<setting pref="browser.menu.showCharacterEncoding" type="bool" localized="true" title="&showCharsetEncoding.title;"/>
</settings>
</richlistbox>
</notificationbox>
</vbox>
<vbox id="console-container" flex="1">
<vbox id="console-header" class="panel-list">
<label class="panel-header" value="&consoleHeader.label;"/>
<hbox align="center">
<label value="&consoleCodeEval.label;" control="console-eval-textbox"/>
<textbox id="console-eval-textbox" class="toolbar search-bar" value="" onkeypress="ConsoleView.onEvalKeyPress(event)" flex="1"/>
<button id="console-button-eval" class="show-text" label="&consoleEvaluate.label;" oncommand="ConsoleView.evaluateTypein()"/>
</hbox>
<hbox align="center" pack="end">
<radiogroup id="console-filter" oncommand="ConsoleView.changeMode();">
<radio id="console-filter-all" label="&consoleAll.label;" value="all" selected="true"/>
<radio id="console-filter-messages" label="&consoleMessages.label;" value="message"/>
<radio id="console-filter-warnings" label="&consoleWarnings.label;" value="warning"/>
<radio id="console-filter-errors" label="&consoleErrors.label;" value="error"/>
</radiogroup>
<button id="console-clear" class="show-text" oncommand="ConsoleView.clearConsole();" label="&consoleClear.label;"/>
</hbox>
</vbox>
<richlistbox id="console-box" class="panel-list console-box" flex="1" onkeypress="ConsoleView.onConsoleBoxKeyPress(event)" oncontextmenu="ConsoleView.onContextMenu(event);"/>
</vbox>
</deck>
</vbox>
</box>
</box>
<vbox id="awesome-panels" hidden="true">
<!-- Awesome header row -->
<hbox id="awesome-header" class="panel-row-header">
<toolbarbutton id="allpages-button" type="radio" group="awesome-header" label="&allPagesHeader.label;" command="cmd_openLocation" class="choice-all panel-row-button show-text"/>
<toolbarbutton id="bookmarks-button" type="radio" group="awesome-header" label="&bookmarksHeader.label;" command="cmd_bookmarks" class="choice-bookmarks panel-row-button show-text"/>
<toolbarbutton id="history-button" type="radio" group="awesome-header" label="&historyHeader.label;" command="cmd_history" class="choice-history panel-row-button show-text"/>
#ifdef MOZ_SERVICES_SYNC
<toolbarbutton id="remotetabs-button" type="radio" group="awesome-header" label="&desktopHeader.label;" command="cmd_remoteTabs" class="choice-remotetabs panel-row-button show-text"/>
#endif
</hbox>
<!-- titlebar autocomplete results -->
<vbox id="popup_autocomplete" class="panel-dark place-list" flex="1" onshow="BrowserUI._edit.showHistoryPopup();" hidden="true"/>
<placelist id="bookmarks-items" class="place-list" type="bookmarks" onopen="BookmarkList.openLink(event);" onhide="BrowserUI.updateStar();" flex="1" hidden="true"/>
<historylist id="history-items" class="place-list" onopen="HistoryList.openLink(event);" flex="1" hidden="true"/>
#ifdef MOZ_SERVICES_SYNC
<remotetabslist id="remotetabs-items" class="place-list" onopen="RemoteTabsList.openLink(event)" flex="1" hidden="true"/>
#endif
</vbox>
<!-- Form Helper form validation helper popup -->
<arrowbox id="form-helper-validation-container" class="arrowbox-dark" flex="1" hidden="true" offset="0" top="0" left="0">
<label/>
</arrowbox>
#ifdef MOZ_SERVICES_SYNC
<box id="syncsetup-container" class="perm-modal-block" hidden="true">
<dialog id="syncsetup-dialog" class="content-dialog" flex="1">
<hbox class="prompt-title">
<description>&sync.setup.title;</description>
</hbox>
<separator class="prompt-line"/>
<vbox id="syncsetup-simple" class="syncsetup-page" flex="1">
<scrollbox id="sync-message" class="prompt-message" orient="vertical" flex="1">
<description class="syncsetup-desc syncsetup-center" flex="1">&sync.setup.pair;</description>
<description class="syncsetup-center link" flex="1" onclick="WeaveGlue.openTutorial();">&sync.setup.tutorial;</description>
<separator/>
<vbox align="center" flex="1">
<description id="syncsetup-code1" class="syncsetup-code">....</description>
<description id="syncsetup-code2" class="syncsetup-code">....</description>
<description id="syncsetup-code3" class="syncsetup-code">....</description>
</vbox>
<separator/>
<description class="syncsetup-center link" flex="1" onclick="WeaveGlue.openManual();">&sync.fallback;</description>
<separator flex="1"/>
</scrollbox>
<hbox class="prompt-buttons" pack="center">
<button class="prompt-button" oncommand="WeaveGlue.close();">&sync.setup.cancel;</button>
</hbox>
</vbox>
<vbox id="syncsetup-waiting" class="syncsetup-page" flex="1" hidden="true">
<description class="syncsetup-desc syncsetup-center" flex="1">&sync.setup.waiting;</description>
</vbox>
<vbox id="syncsetup-fallback" class="syncsetup-page" flex="1" hidden="true">
<scrollbox class="prompt-message" orient="vertical" flex="1">
<description class="syncsetup-desc syncsetup-center" flex="1">&sync.setup.manual;</description>
<separator/>
<textbox id="syncsetup-account" class="prompt-edit" placeholder="&sync.account;" oninput="WeaveGlue.canConnect();"/>
<textbox id="syncsetup-password" class="prompt-edit" placeholder="&sync.password;" type="password" oninput="WeaveGlue.canConnect();"/>
<textbox id="syncsetup-synckey" class="prompt-edit" placeholder="&sync.recoveryKey;" oninput="WeaveGlue.canConnect();"/>
<separator class="thin"/>
<button id="syncsetup-usecustomserver" type="checkbox" class="button-checkbox" pack="start" oncommand="WeaveGlue.toggleCustomServer();">
<image class="button-image-icon"/>
<description class="syncsetup-label prompt-checkbox-label" flex="1">&sync.customServer;</description>
</button>
<textbox id="syncsetup-customserver" class="prompt-edit" placeholder="&sync.serverURL;"/>
<separator flex="1"/>
</scrollbox>
<hbox class="prompt-buttons" pack="center">
<button class="prompt-button" oncommand="WeaveGlue.close();">&sync.setup.cancel;</button>
<separator/>
<button id="syncsetup-button-connect" class="prompt-button" oncommand="WeaveGlue.close(); WeaveGlue.connect();">&sync.setup.connect;</button>
</hbox>
</vbox>
</dialog>
</box>
#endif
<arrowbox id="search-engines-popup" hidden="true" offset="18" flex="1" type="dialog">
<hbox id="search-engines-list" class="action-buttons" flex="1"/>
</arrowbox>
<arrowbox id="newtab-popup" class="arrowbox-dark" hidden="true" onclick="NewTabPopup.selectTab()" align="center" start="0">
<label/>
</arrowbox>
<!-- options dialog for select form field -->
<vbox id="select-container" class="context-block" hidden="true">
<vbox id="select-popup" class="dialog-dark">
<hbox pack="center">
<label id="select-title" class="options-title" align="center" crop="center" flex="1"/>
</hbox>
<scrollbox id="select-commands" onclick="if (event.target != this) SelectHelperUI.selectByIndex(event.target.optionIndex);" orient="vertical" flex="1"/>
<hbox pack="center">
<button label="&selectHelper.done;" oncommand="SelectHelperUI.hide();"/>
</hbox>
</vbox>
</vbox>
<hbox id="context-container" class="context-block" hidden="true">
<vbox id="context-popup" class="dialog-dark">
<hbox id="context-header">
<label id="context-hint" crop="center" flex="1"/>
</hbox>
<richlistbox id="context-commands" onclick="ContextHelper.hide();" flex="1">
<richlistitem class="context-command" id="context-copy" type="copy" onclick="ContextCommands.copy();">
<label value="&copy.label;"/>
</richlistitem>
<richlistitem class="context-command" id="context-copy-all" type="copy-all" onclick="ContextCommands.copy();">
<label value="&copyAll.label;"/>
</richlistitem>
<richlistitem class="context-command" id="context-paste" type="paste" onclick="ContextCommands.paste();">
<label value="&paste.label;"/>
</richlistitem>
<richlistitem class="context-command" id="context-paste-n-go" type="paste-url" onclick="ContextCommands.pasteAndGo();">
<label value="&pasteAndGo.label;"/>
</richlistitem>
<richlistitem class="context-command" id="context-select-all" type="select-all" onclick="ContextCommands.selectAll();">
<label value="&selectAll.label;"/>
</richlistitem>
<richlistitem class="context-command" id="context-openinnewtab" type="link-openable" onclick="ContextCommands.openInNewTab();">
<label value="&contextOpenInNewTab.label;"/>
</richlistitem>
<richlistitem class="context-command" id="context-bookmark-link" type="link" onclick="ContextCommands.bookmarkLink();">
<label value="&contextBookmarkLink.label;"/>
</richlistitem>
<richlistitem class="context-command" id="context-saveimage" type="image-loaded" onclick="ContextCommands.saveImage();">
<label value="&contextSaveImage.label;"/>
</richlistitem>
<richlistitem class="context-command" id="context-copy-link" type="link" onclick="ContextCommands.copyLink();">
<label value="&contextCopyLink.label;"/>
</richlistitem>
<richlistitem class="context-command" id="context-copy-email" type="mailto" onclick="ContextCommands.copyEmail();">
<label value="&contextCopyEmail.label;"/>
</richlistitem>
<richlistitem class="context-command" id="context-copy-phone" type="callto" onclick="ContextCommands.copyPhone();">
<label value="&contextCopyPhone.label;"/>
</richlistitem>
<richlistitem class="context-command" id="context-copy-image-location" type="image" onclick="ContextCommands.copyImageLocation();">
<label value="&contextCopyImageLocation.label;"/>
</richlistitem>
<richlistitem class="context-command" id="context-share-link" type="link-shareable" onclick="ContextCommands.shareLink();">
<label value="&contextShareLink.label;"/>
</richlistitem>
<richlistitem class="context-command" id="context-share-image" type="image-shareable" onclick="ContextCommands.shareMedia();">
<label value="&contextShareImage.label;"/>
</richlistitem>
<richlistitem class="context-command" id="context-play-media" type="media-paused" onclick="ContextCommands.sendCommand('play');">
<label value="&contextPlayMedia.label;"/>
</richlistitem>
<richlistitem class="context-command" id="context-pause-video" type="media-playing" onclick="ContextCommands.sendCommand('pause');">
<label value="&contextPauseMedia.label;"/>
</richlistitem>
<richlistitem class="context-command" id="context-fullscreen" type="video" onclick="ContextCommands.sendCommand('fullscreen');">
<label value="&contextFullScreen.label;"/>
</richlistitem>
<richlistitem class="context-command" id="context-save-video" type="video" onclick="ContextCommands.saveImage();">
<label value="&contextSaveVideo.label;"/>
</richlistitem>
<richlistitem class="context-command" id="context-share-video" type="video-shareable" onclick="ContextCommands.shareMedia();">
<label value="&contextShareVideo.label;"/>
</richlistitem>
<richlistitem class="context-command" id="context-editbookmark" type="edit-bookmark" onclick="ContextCommands.editBookmark();">
<label value="&contextEditBookmark.label;"/>
</richlistitem>
<richlistitem class="context-command" id="context-removebookmark" type="edit-bookmark" onclick="ContextCommands.removeBookmark();">
<label value="&contextRemoveBookmark.label;"/>
</richlistitem>
#ifdef ANDROID
<richlistitem class="context-command" id="context-shortcutbookmark" type="edit-bookmark" onclick="ContextCommands.shortcutBookmark();">
<label value="&contextShortcutBookmark.label;"/>
</richlistitem>
<richlistitem class="context-command" id="context-select-input" type="input-text" onclick="ContextCommands.selectInput();">
<label value="&inputMethod.label;"/>
</richlistitem>
#endif
</richlistbox>
</vbox>
</hbox>
<toolbarbutton id="selectionhandle-start" label="^" left="0" top="0" hidden="true"/>
<toolbarbutton id="selectionhandle-end" label="^" left="0" top="0" hidden="true"/>
<hbox id="menulist-container" class="context-block" hidden="true">
<vbox id="menulist-popup" class="dialog-dark">
<label id="menulist-title" class="options-title" crop="center" flex="1"/>
<richlistbox id="menulist-commands" class="action-buttons" onclick="if (event.target != this) MenuListHelperUI.selectByIndex(this.selectedIndex);" flex="1"/>
</vbox>
</hbox>
<!-- alerts for content -->
<hbox id="alerts-container" hidden="true" align="start" bottom="0" onclick="AlertsHelper.click(event);">
<image id="alerts-image"/>
<vbox flex="1">
<label id="alerts-title" value=""/>
<description id="alerts-text" flex="1"/>
</vbox>
</hbox>
<hbox id="appmenu-overflow" bottom="0" hidden="true" oncommand="AppMenu.hideOverflow();">
<richlistbox id="appmenu-overflow-commands" flex="1"/>
</hbox>
<hbox id="appmenu" bottom="0" hidden="true" align="stretch" oncommand="AppMenu.hide();">
<toolbarbutton class="appmenu-site-button appmenu-button appmenu-pageaction"
label="&appMenu.siteOptions;"
oncommand="getIdentityHandler().show(); event.stopPropagation();"/>
<toolbarbutton class="appmenu-preferences-button appmenu-button"
label="&prefsHeader.label;"
oncommand="BrowserUI.showPanel('prefs-container');"/>
<toolbarbutton class="appmenu-addons-button appmenu-button"
label="&addonsHeader.label;"
oncommand="BrowserUI.showPanel('addons-container');"/>
<toolbarbutton class="appmenu-share-button appmenu-button appmenu-pageaction"
label="&pageactions.share.page;"
oncommand="SharingUI.show(getBrowser().currentURI.spec, getBrowser().contentTitle);"/>
<toolbarbutton class="appmenu-findinpage-button appmenu-button appmenu-pageaction"
label="&pageactions.findInPage;"
oncommand="FindHelperUI.show();"/>
<toolbarbutton class="appmenu-downloads-button appmenu-button"
label="&downloadsHeader.label;"
oncommand="BrowserUI.showPanel('downloads-container');"/>
#ifdef NS_PRINTING
<toolbarbutton class="appmenu-saveas-button appmenu-button appmenu-pageaction"
label="&pageactions.saveas.pdf;"
oncommand="PageActions.savePageAsPDF();"/>
#endif
<toolbarbutton class="appmenu-quit-button appmenu-button"
label="&pageactions.quit;"
oncommand="Browser.quit();"/>
</hbox>
</stack>
<svg:svg height="0">
<svg:mask id="back-button-mask" maskContentUnits="objectBoundingBox">
<svg:rect x="0" y="0" width="1" height="1" fill="white"/>
<svg:circle cx="-0.85" cy="0.5" r="0.96"/>
</svg:mask>
</svg:svg>
<browser id="home" type="content-primary" flex="1"/>
</window>

View File

@ -1,39 +1,3 @@
/* -*- Mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil; -*- */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is BrowserCLH.js
*
* The Initial Developer of the Original Code is Mozilla Foundation.
* Portions created by the Initial Developer are Copyright (C) 2009
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Brian Crowder <crowder@fiverocks.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
const Cc = Components.classes;
const Ci = Components.interfaces;
@ -42,257 +6,46 @@ const Cu = Components.utils;
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/Services.jsm");
function openWindow(aParent, aURL, aTarget, aFeatures, aArgs) {
let argString = null;
if (aArgs && !(aArgs instanceof Ci.nsISupportsArray)) {
argString = Cc["@mozilla.org/supports-string;1"].createInstance(Ci.nsISupportsString);
argString.data = aArgs;
}
return Services.ww.openWindow(aParent, aURL, aTarget, aFeatures, argString || aArgs);
}
function resolveURIInternal(aCmdLine, aArgument) {
let uri = aCmdLine.resolveURI(aArgument);
if (!(uri instanceof Ci.nsIFileURL))
return uri;
try {
if (uri.file.exists())
return uri;
} catch (e) {
Cu.reportError(e);
}
try {
let urifixup = Cc["@mozilla.org/docshell/urifixup;1"].getService(Ci.nsIURIFixup);
uri = urifixup.createFixupURI(aArgument, 0);
} catch (e) {
Cu.reportError(e);
}
return uri;
}
/**
* Determines whether a home page override is needed.
* Returns:
* "new profile" if this is the first run with a new profile.
* "new version" if this is the first run with a build with a different
* Gecko milestone (i.e. right after an upgrade).
* "none" otherwise.
*/
function needHomepageOverride() {
let savedmstone = null;
try {
savedmstone = Services.prefs.getCharPref("browser.startup.homepage_override.mstone");
} catch (e) {}
if (savedmstone == "ignore")
return "none";
#expand let ourmstone = "__MOZ_APP_VERSION__";
if (ourmstone != savedmstone) {
Services.prefs.setCharPref("browser.startup.homepage_override.mstone", ourmstone);
return (savedmstone ? "new version" : "new profile");
}
return "none";
}
function getHomePage() {
let url = "about:home";
try {
url = Services.prefs.getComplexValue("browser.startup.homepage", Ci.nsIPrefLocalizedString).data;
} catch (e) { }
return url;
}
function showPanelWhenReady(aWindow, aPage) {
aWindow.addEventListener("UIReadyDelayed", function(aEvent) {
aWindow.BrowserUI.showPanel(aPage);
}, false);
}
function haveSystemLocale() {
let localeService = Cc["@mozilla.org/intl/nslocaleservice;1"].getService(Ci.nsILocaleService);
let systemLocale = localeService.getSystemLocale().getCategory("NSILOCALE_CTYPE");
return isLocaleAvailable(systemLocale);
}
function checkCurrentLocale() {
if (Services.prefs.prefHasUserValue("general.useragent.locale")) {
// if the user has a compatible locale from a different buildid, we need to update
var buildID = Cc["@mozilla.org/xre/app-info;1"].getService(Ci.nsIXULAppInfo).platformBuildID;
let localeBuildID = Services.prefs.getCharPref("extensions.compatability.locales.buildid");
if (buildID != localeBuildID)
return false;
let currentLocale = Services.prefs.getCharPref("general.useragent.locale");
return isLocaleAvailable(currentLocale);
}
return true;
}
function isLocaleAvailable(aLocale) {
let chrome = Cc["@mozilla.org/chrome/chrome-registry;1"].getService(Ci.nsIXULChromeRegistry);
chrome.QueryInterface(Ci.nsIToolkitChromeRegistry);
let availableLocales = chrome.getLocalesForPackage("browser");
let locale = aLocale.split("-")[0];
let localeRegEx = new RegExp("^" + locale);
while (availableLocales.hasMore()) {
let locale = availableLocales.getNext();
if (localeRegEx.test(locale))
return true;
}
return false;
function dump(a) {
Cc["@mozilla.org/consoleservice;1"]
.getService(Ci.nsIConsoleService)
.logStringMessage(a);
}
function BrowserCLH() { }
BrowserCLH.prototype = {
//
// nsICommandLineHandler
//
handle: function fs_handle(aCmdLine) {
// Instantiate the search service so the search engine cache is created now
// instead when the application is running. The install process will register
// this component by using the -silent command line flag, thereby creating
// the cache during install, not runtime.
// NOTE: This code assumes this CLH is run before the nsDefaultCLH, which
// consumes the "-silent" flag.
if (aCmdLine.findFlag("silent", false) > -1) {
let searchService = Services.search;
let autoComplete = Cc["@mozilla.org/autocomplete/search;1?name=history"].
getService(Ci.nsIAutoCompleteSearch);
return;
}
// Handle chrome windows loaded via commandline
let chromeParam = aCmdLine.handleFlagWithParam("chrome", false);
if (chromeParam) {
try {
// Only load URIs which do not inherit chrome privs
let features = "chrome,dialog=no,all";
let uri = resolveURIInternal(aCmdLine, chromeParam);
let netutil = Cc["@mozilla.org/network/util;1"].getService(Ci.nsINetUtil);
if (!netutil.URIChainHasFlags(uri, Ci.nsIHttpProtocolHandler.URI_INHERITS_SECURITY_CONTEXT)) {
openWindow(null, uri.spec, "_blank", features, null);
// Stop the normal commandline processing from continuing
let urlParam = aCmdLine.handleFlagWithParam("remote", false);
if (urlParam) {
// TODO:
// browserWin.browserDOMWindow will be null if
// the chrome page hasn't loaded yet. We
// should test for this, and reschedule the
// event.
aCmdLine.preventDefault = true;
}
} catch (e) {
Cu.reportError(e);
try {
dump("fs_handle");
let urifixup = Cc["@mozilla.org/docshell/urifixup;1"].getService(Ci.nsIURIFixup);
dump("fs_handle: " + urlParam);
let uri = urifixup.createFixupURI(urlParam, 1);
if (!uri)
return;
dump("fs_handle: " + uri);
let browserWin = Services.wm.getMostRecentWindow("navigator:browser");
browserWin.browserDOMWindow.openURI(uri,
null,
Ci.nsIBrowserDOMWindow.OPEN_CURRENTWINDOW,
Ci.nsIBrowserDOMWindow.OPEN_EXTERNAL);
} catch (x) {
Cc["@mozilla.org/consoleservice;1"]
.getService(Ci.nsIConsoleService)
.logStringMessage("fs_handle exception!: " + x);
}
}
return;
}
// Check and remove the alert flag here, but we'll handle it a bit later - see below
let alertFlag = aCmdLine.handleFlagWithParam("alert", false);
// Check and remove the webapp param
let appFlag = aCmdLine.handleFlagWithParam("webapp", false);
let appURI;
if (appFlag)
appURI = resolveURIInternal(aCmdLine, appFlag);
// Keep an array of possible URL arguments
let uris = [];
// Check for the "url" flag
let uriFlag = aCmdLine.handleFlagWithParam("url", false);
if (uriFlag) {
let uri = resolveURIInternal(aCmdLine, uriFlag);
if (uri)
uris.push(uri);
}
for (let i = 0; i < aCmdLine.length; i++) {
let arg = aCmdLine.getArgument(i);
if (!arg || arg[0] == '-')
continue;
let uri = resolveURIInternal(aCmdLine, arg);
if (uri)
uris.push(uri);
}
// Open the main browser window, if we don't already have one
let browserWin;
try {
let localeWin = Services.wm.getMostRecentWindow("navigator:localepicker");
if (localeWin) {
localeWin.focus();
aCmdLine.preventDefault = true;
return;
}
browserWin = Services.wm.getMostRecentWindow("navigator:browser");
if (!browserWin) {
// Default to the saved homepage
let defaultURL = getHomePage();
// Override the default if we have a URL passed on command line
if (uris.length > 0) {
defaultURL = uris[0].spec;
uris = uris.slice(1);
}
// Show the locale selector if we have a new profile, or if the selected locale is no longer compatible
let showLocalePicker = Services.prefs.getBoolPref("browser.firstrun.show.localepicker")
if ((needHomepageOverride() == "new profile" && showLocalePicker && !haveSystemLocale()) || !checkCurrentLocale()) {
browserWin = openWindow(null, "chrome://browser/content/localePicker.xul", "_blank", "chrome,dialog=no,all", defaultURL);
aCmdLine.preventDefault = true;
return;
}
browserWin = openWindow(null, "chrome://browser/content/browser.xul", "_blank", "chrome,dialog=no,all", defaultURL);
}
browserWin.focus();
// Stop the normal commandline processing from continuing. We just opened the main browser window
aCmdLine.preventDefault = true;
} catch (e) {
Cu.reportError(e);
}
// Assumption: All remaining command line arguments have been sent remotely (browser is already running)
// Action: Open any URLs we find into an existing browser window
// First, get a browserDOMWindow object
while (!browserWin.browserDOMWindow)
Services.tm.currentThread.processNextEvent(true);
// Open any URIs into new tabs
for (let i = 0; i < uris.length; i++)
browserWin.browserDOMWindow.openURI(uris[i], null, Ci.nsIBrowserDOMWindow.OPEN_NEWTAB, Ci.nsIBrowserDOMWindow.OPEN_EXTERNAL);
if (appURI)
browserWin.browserDOMWindow.openURI(appURI, null, browserWin.OPEN_APPTAB, Ci.nsIBrowserDOMWindow.OPEN_NEW);
// Handle the notification, if called from it
if (alertFlag) {
if (alertFlag == "update-app") {
// Notification was already displayed and clicked, skip it next time
Services.prefs.setBoolPref("app.update.skipNotification", true);
var updateService = Cc["@mozilla.org/updates/update-service;1"].getService(Ci.nsIApplicationUpdateService);
var updateTimerCallback = updateService.QueryInterface(Ci.nsITimerCallback);
updateTimerCallback.notify(null);
} else if (alertFlag.length >= 9 && alertFlag.substr(0, 9) == "download:") {
showPanelWhenReady(browserWin, "downloads-container");
} else if (alertFlag == "addons") {
showPanelWhenReady(browserWin, "addons-container");
}
}
},
// QI

View File

@ -565,6 +565,10 @@ report_mapping(char *name, void *base, uint32_t len, uint32_t offset)
extern "C" void simple_linker_init(void);
extern "C" struct timeval timings[2];
#define TIMING_RELOC 0
#define TIMING_CONSTRUCTORS 1
static void
loadLibs(const char *apkName)
{
@ -651,6 +655,9 @@ loadLibs(const char *apkName)
(usage2.ru_utime.tv_sec - usage1.ru_utime.tv_sec)*1000 + (usage2.ru_utime.tv_usec - usage1.ru_utime.tv_usec)/1000,
(usage2.ru_stime.tv_sec - usage1.ru_stime.tv_sec)*1000 + (usage2.ru_stime.tv_usec - usage1.ru_stime.tv_usec)/1000,
usage2.ru_majflt-usage1.ru_majflt);
__android_log_print(ANDROID_LOG_ERROR, "GeckoLibLoad", "Spent %dms on relocations, %dms on constructors",
timings[TIMING_RELOC].tv_sec * 1000 + timings[TIMING_RELOC].tv_usec / 1000,
timings[TIMING_CONSTRUCTORS].tv_sec * 1000 + timings[TIMING_CONSTRUCTORS].tv_usec / 1000);
}
extern "C" NS_EXPORT void JNICALL

View File

@ -43,7 +43,6 @@ static const char *dl_errors[] = {
#define unlikely(expr) __builtin_expect (expr, 0)
static pthread_mutex_t dl_lock = PTHREAD_MUTEX_INITIALIZER;
extern int extractLibs;
static void set_dlerror(int err)
{
@ -54,9 +53,6 @@ static void set_dlerror(int err)
void *__wrap_dlopen(const char *filename, int flag)
{
if (extractLibs)
return dlopen(filename, flag);
soinfo *ret;
pthread_mutex_lock(&dl_lock);
@ -88,9 +84,6 @@ void *moz_mapped_dlopen(const char *filename, int flag,
const char *__wrap_dlerror(void)
{
if (extractLibs)
return dlerror();
const char *tmp = dl_err_str;
dl_err_str = NULL;
return (const char *)tmp;
@ -98,9 +91,6 @@ const char *__wrap_dlerror(void)
void *__wrap_dlsym(void *handle, const char *symbol)
{
if (extractLibs)
return dlsym(handle, symbol);
soinfo *found;
Elf32_Sym *sym;
unsigned bind;
@ -183,9 +173,6 @@ int __wrap_dladdr(void *addr, Dl_info *info)
int __wrap_dlclose(void *handle)
{
if (extractLibs)
return dlclose(handle);
pthread_mutex_lock(&dl_lock);
(void)unload_library((soinfo*)handle);
pthread_mutex_unlock(&dl_lock);

View File

@ -96,6 +96,10 @@ static soinfo *sonext = &libdl_info;
static soinfo *somain; /* main process, always the one after libdl_info */
#endif
/* Keep track of cumulative time spent in relocations and static constructors */
#define TIMING_RELOC 0
#define TIMING_CONSTRUCTORS 1
struct timeval timings[2] = { { 0, 0 }, { 0, 0 } };
/* Set up for the buddy allocator managing the non-prelinked libraries. */
static struct ba_bits ba_nonprelink_bitmap[(LIBLAST - LIBBASE) / LIBINC];
@ -1317,9 +1321,11 @@ soinfo *find_library(const char *name)
}
}
si = dlopen(name, RTLD_LAZY);
if (si)
return si;
if (strncmp(name, getenv("CACHE_PATH"), strlen(getenv("CACHE_PATH")))) {
si = dlopen(name, RTLD_LAZY);
if (si)
return si;
}
TRACE("[ %5d '%s' has not been loaded yet. Locating...]\n", pid, name);
si = load_library(name);
@ -1980,6 +1986,7 @@ static int link_image(soinfo *si, unsigned wr_offset)
unsigned *d;
Elf32_Phdr *phdr = si->phdr;
int phnum = si->phnum;
struct timeval t0, t1;
INFO("[ %5d linking %s ]\n", pid, si->name);
DEBUG("%5d si->base = 0x%08x si->flags = 0x%08x\n", pid,
@ -2181,8 +2188,6 @@ static int link_image(soinfo *si, unsigned wr_offset)
memset(preloads, 0, sizeof(preloads));
for(i = 0; ldpreload_names[i] != NULL; i++) {
soinfo *lsi = find_library(ldpreload_names[i]);
if(lsi == 0)
lsi = dlopen(ldpreload_names[i], RTLD_LAZY);
if(lsi == 0) {
strlcpy(tmp_err_buf, linker_get_error(), sizeof(tmp_err_buf));
DL_ERR("%5d could not load needed library '%s' for '%s' (%s)",
@ -2197,9 +2202,7 @@ static int link_image(soinfo *si, unsigned wr_offset)
for(d = si->dynamic; *d; d += 2) {
if(d[0] == DT_NEEDED){
DEBUG("%5d %s needs %s\n", pid, si->name, si->strtab + d[1]);
soinfo *lsi = dlopen(si->strtab + d[1], RTLD_LAZY);
if(lsi == 0)
lsi = find_library(si->strtab + d[1]);
soinfo *lsi = find_library(si->strtab + d[1]);
if(lsi == 0) {
strlcpy(tmp_err_buf, linker_get_error(), sizeof(tmp_err_buf));
DL_ERR("%5d could not load needed library '%s' for '%s' (%s)",
@ -2218,6 +2221,7 @@ static int link_image(soinfo *si, unsigned wr_offset)
}
}
gettimeofday(&t0, 0);
#ifndef ANDROID_NO_RUNTIME_RELOC
/* Initialize GOT[1] and GOT[2], which are used by the PLT trampoline */
Elf32_Addr *got = (Elf32_Addr *)si->plt_got;
@ -2264,6 +2268,10 @@ static int link_image(soinfo *si, unsigned wr_offset)
si->flags |= FLAG_LINKED;
DEBUG("[ %5d finished linking %s ]\n", pid, si->name);
gettimeofday(&t1, 0);
timings[TIMING_RELOC].tv_usec += t1.tv_usec - t0.tv_usec;
timings[TIMING_RELOC].tv_sec += t1.tv_sec - t0.tv_sec;
#if 0
/* This is the way that the old dynamic linker did protection of
* non-writable areas. It would scan section headers and find where
@ -2298,7 +2306,12 @@ static int link_image(soinfo *si, unsigned wr_offset)
*/
if (getuid() != geteuid() || getgid() != getegid())
nullify_closed_stdio ();
gettimeofday(&t0, 0);
call_constructors(si);
gettimeofday(&t1, 0);
timings[TIMING_CONSTRUCTORS].tv_usec += t1.tv_usec - t0.tv_usec;
timings[TIMING_CONSTRUCTORS].tv_sec += t1.tv_sec - t0.tv_sec;
notify_gdb_of_load(si);
return 0;

View File

@ -50,7 +50,6 @@ PARALLEL_DIRS = \
content \
locales \
mozapps/downloads \
mozapps/extensions \
mozapps/handling \
mozapps/preferences \
mozapps/plugins \
@ -63,6 +62,16 @@ PARALLEL_DIRS = \
themes \
$(NULL)
#
# The native front end is not going to use extensions based on this code.
# If it isn't used, it still takes up .5mb in cached statement. fail for me.
# Ideally we start moving other optional stuff into this section.
ifdef XXXXX
PARALLEL_DIRS += \
mozapps/extensions \
$(NULL)
endif
ifneq (,$(filter gtk2 qt,$(MOZ_WIDGET_TOOLKIT)))
PARALLEL_DIRS += system/unixproxy
endif

View File

@ -473,6 +473,13 @@ nsNavHistory::~nsNavHistory()
nsresult
nsNavHistory::Init()
{
// XXX
// For the native ui on android, we will not be using MOZ_PLACES.
// Currently places has deeply weaved it way throughout the gecko codebase.
// Here we disable all database creation and loading of places.
return NS_ERROR_NOT_IMPLEMENTED;
NS_TIME_FUNCTION;
nsCOMPtr<nsIPrefService> prefService =

View File

@ -321,9 +321,9 @@ INNER_MAKE_PACKAGE = \
make -C ../embedding/android gecko.ap_ && \
cp ../embedding/android/gecko.ap_ $(_ABS_DIST) && \
( cd $(STAGEPATH)$(MOZ_PKG_DIR)$(_BINPATH) && \
rm -rf lib && \
mkdir -p lib/$(ABI_DIR) && \
mv libmozutils.so lib/$(ABI_DIR) && \
cp lib*.so lib && \
mv libmozutils.so $(MOZ_CHILD_PROCESS_NAME) lib/$(ABI_DIR) && \
rm -f lib.id && \
for SOMELIB in *.so ; \
do \

View File

@ -251,6 +251,12 @@ GRE_BUILDID := $(shell cat $(DEPTH)/config/buildid)
DEFINES += -DGRE_MILESTONE=$(GRE_MILESTONE) -DGRE_BUILDID=$(GRE_BUILDID)
ifdef MOZILLA_OFFICIAL
DEFINES += -DMOZILLA_OFFICIAL
endif
DEFINES += -DAPP_VERSION=$(MOZ_APP_VERSION)
$(srcdir)/nsAppRunner.cpp: $(DEPTH)/config/buildid $(topsrcdir)/config/milestone.txt
platform.ini: FORCE

View File

@ -57,6 +57,9 @@
#define LOG(args...) __android_log_print(ANDROID_LOG_INFO, MOZ_APP_NAME, args)
#define _STR(s) # s
#define STR(s) _STR(s)
struct AutoAttachJavaThread {
AutoAttachJavaThread() {
attached = mozilla_AndroidBridge_SetMainThread((void*)pthread_self());
@ -97,20 +100,6 @@ GeckoStart(void *data)
LOG("Failed to get GRE_HOME from the env vars");
return 0;
}
nsCAutoString appini_path(greHome);
appini_path.AppendLiteral("/application.ini");
rv = NS_NewNativeLocalFile(appini_path, PR_FALSE, getter_AddRefs(appini));
if (NS_FAILED(rv)) {
LOG("Failed to create nsILocalFile for appdata\n");
return 0;
}
nsXREAppData *appData;
rv = XRE_CreateAppData(appini, &appData);
if (NS_FAILED(rv)) {
LOG("Failed to load application.ini from %s\n", appini_path.get());
return 0;
}
nsCOMPtr<nsILocalFile> xreDir;
rv = NS_NewNativeLocalFile(nsDependentCString(greHome), PR_FALSE, getter_AddRefs(xreDir));
@ -119,7 +108,25 @@ GeckoStart(void *data)
return 0;
}
appData->xreDirectory = xreDir.get();
nsXREAppData appData = {
sizeof(nsXREAppData),
xreDir.get(),
"Mozilla",
"Fennec",
STR(APP_VERSION),
STR(GRE_BUILDID),
"{a23983c0-fd0e-11dc-95ff-0800200c9a66}",
NULL,
#ifdef MOZILLA_OFFICIAL
NS_XRE_ENABLE_EXTENSION_MANAGER | NS_XRE_ENABLE_CRASH_REPORTER,
#else
NS_XRE_ENABLE_EXTENSION_MANAGER,
#endif
xreDir.get(),
STR(GRE_MILESTONE),
STR(GRE_MILESTONE),
"https://crash-reports.mozilla.com/submit"
};
nsTArray<char *> targs;
char *arg = strtok(static_cast<char *>(data), " ");
@ -129,13 +136,11 @@ GeckoStart(void *data)
}
targs.AppendElement(static_cast<char *>(nsnull));
int result = XRE_main(targs.Length() - 1, targs.Elements(), appData);
int result = XRE_main(targs.Length() - 1, targs.Elements(), &appData);
if (result)
LOG("XRE_main returned %d", result);
XRE_FreeAppData(appData);
mozilla::AndroidBridge::Bridge()->NotifyXreExit();
free(targs[0]);

View File

@ -137,7 +137,6 @@ AndroidBridge::Init(JNIEnv *jEnv,
jGetDpi = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "getDpi", "()I");
jSetFullScreen = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "setFullScreen", "(Z)V");
jShowInputMethodPicker = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "showInputMethodPicker", "()V");
jHideProgressDialog = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "hideProgressDialog", "()V");
jPerformHapticFeedback = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "performHapticFeedback", "(Z)V");
jSetKeepScreenOn = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "setKeepScreenOn", "(Z)V");
jIsNetworkLinkUp = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "isNetworkLinkUp", "()Z");
@ -151,6 +150,7 @@ AndroidBridge::Init(JNIEnv *jEnv,
jPostToJavaThread = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "postToJavaThread", "(Z)V");
jInitCamera = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "initCamera", "(Ljava/lang/String;III)[I");
jCloseCamera = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "closeCamera", "()V");
jHandleGeckoMessage = (jmethodID) jEnv->GetStaticMethodID(jGeckoAppShellClass, "handleGeckoMessage", "(Ljava/lang/String;)V");
jEGLContextClass = (jclass) jEnv->NewGlobalRef(jEnv->FindClass("javax/microedition/khronos/egl/EGLContext"));
jEGL10Class = (jclass) jEnv->NewGlobalRef(jEnv->FindClass("javax/microedition/khronos/egl/EGL10"));
@ -650,17 +650,6 @@ AndroidBridge::SetFullScreen(bool aFullScreen)
mJNIEnv->CallStaticVoidMethod(mGeckoAppShellClass, jSetFullScreen, aFullScreen);
}
void
AndroidBridge::HideProgressDialogOnce()
{
static bool once = false;
if (!once) {
ALOG_BRIDGE("AndroidBridge::HideProgressDialogOnce");
mJNIEnv->CallStaticVoidMethod(mGeckoAppShellClass, jHideProgressDialog);
once = true;
}
}
void
AndroidBridge::PerformHapticFeedback(bool aIsLongPress)
{
@ -935,10 +924,10 @@ AndroidBridge::CreateShortcut(const nsAString& aTitle, const nsAString& aURI, co
void
AndroidBridge::PostToJavaThread(nsIRunnable* aRunnable, bool aMainThread)
{
__android_log_print(ANDROID_LOG_INFO, "GeckoBridge", "%s", __PRETTY_FUNCTION__);
ALOG_BRIDGE("GeckoBridge", "%s", __PRETTY_FUNCTION__);
JNIEnv* env = AndroidBridge::AttachThread(false);
if (!env) {
__android_log_print(ANDROID_LOG_INFO, "GeckoBridge", "no jni env in %s!!", __PRETTY_FUNCTION__);
ALOG_BRIDGE("no jni env in %s!!", __PRETTY_FUNCTION__);
return;
}
mRunnableQueue.AppendObject(aRunnable);
@ -949,27 +938,49 @@ AndroidBridge::PostToJavaThread(nsIRunnable* aRunnable, bool aMainThread)
env->ExceptionDescribe();
env->ExceptionClear();
}
__android_log_print(ANDROID_LOG_INFO, "GeckoBridge", "leaving %s", __PRETTY_FUNCTION__);
ALOG_BRIDGE("leaving %s", __PRETTY_FUNCTION__);
}
void
AndroidBridge::ExecuteNextRunnable()
{
__android_log_print(ANDROID_LOG_INFO, "GeckoBridge", "%s", __PRETTY_FUNCTION__);
ALOG_BRIDGE("%s", __PRETTY_FUNCTION__);
JNIEnv* env = AndroidBridge::AttachThread(false);
if (!env) {
__android_log_print(ANDROID_LOG_INFO, "GeckoBridge", "no jni env in %s!!", __PRETTY_FUNCTION__);
ALOG_BRIDGE("no jni env in %s!!", __PRETTY_FUNCTION__);
return;
}
if (mRunnableQueue.Count() > 0) {
nsIRunnable* r = mRunnableQueue[0];
__android_log_print(ANDROID_LOG_INFO, "GeckoBridge", "going to run %p", r);
ALOG_BRIDGE("going to run %p", r);
r->Run();
mRunnableQueue.RemoveObjectAt(0);
}
__android_log_print(ANDROID_LOG_INFO, "GeckoBridge", "leaving %s", __PRETTY_FUNCTION__);
ALOG_BRIDGE("leaving %s", __PRETTY_FUNCTION__);
}
void
AndroidBridge::HandleGeckoMessage(const nsAString& aMessage)
{
ALOG_BRIDGE("%s", __PRETTY_FUNCTION__);
JNIEnv* env = AndroidBridge::AttachThread(false);
if (!env) {
ALOG_BRIDGE("no jni env in %s!!", __PRETTY_FUNCTION__);
return;
}
AutoLocalJNIFrame jniFrame(1);
jstring jMessage = mJNIEnv->NewString(nsPromiseFlatString(aMessage).get(), aMessage.Length());
env->CallStaticVoidMethod(mGeckoAppShellClass, jHandleGeckoMessage, jMessage);
jthrowable ex = env->ExceptionOccurred();
if (ex) {
env->ExceptionDescribe();
env->ExceptionClear();
}
ALOG_BRIDGE("leaving %s", __PRETTY_FUNCTION__);
}
void
@ -1002,9 +1013,7 @@ AndroidBridge::OpenGraphicsLibraries()
ANativeWindow_setBuffersGeometry = (int (*)(void*, int, int, int)) dlsym(handle, "ANativeWindow_setBuffersGeometry");
ANativeWindow_lock = (int (*)(void*, void*, void*)) dlsym(handle, "ANativeWindow_lock");
ANativeWindow_unlockAndPost = (int (*)(void*))dlsym(handle, "ANativeWindow_unlockAndPost");
mHasNativeWindowAccess = ANativeWindow_fromSurface && ANativeWindow_release && ANativeWindow_lock && ANativeWindow_unlockAndPost;
ALOG_BRIDGE("Successfully opened libandroid.so, have native window access? %d", mHasNativeWindowAccess);
}
}
@ -1188,3 +1197,21 @@ AndroidBridge::UnlockWindow(void* window)
return true;
}
/* Implementation file */
NS_IMPL_ISUPPORTS1(nsAndroidBridge, nsIAndroidBridge)
nsAndroidBridge::nsAndroidBridge()
{
}
nsAndroidBridge::~nsAndroidBridge()
{
}
/* void handleGeckoEvent (in AString message); */
NS_IMETHODIMP nsAndroidBridge::HandleGeckoMessage(const nsAString & message)
{
AndroidBridge::Bridge()->HandleGeckoMessage(message);
return NS_OK;
}

View File

@ -52,6 +52,8 @@
#include "nsIMIMEInfo.h"
#include "nsColor.h"
#include "nsIAndroidBridge.h"
// Some debug #defines
// #define DEBUG_ANDROID_EVENTS
// #define DEBUG_ANDROID_WIDGET
@ -199,8 +201,6 @@ public:
void ShowInputMethodPicker();
void HideProgressDialogOnce();
bool IsNetworkLinkUp();
bool IsNetworkLinkKnown();
@ -280,6 +280,8 @@ public:
bool LockWindow(void *window, unsigned char **bits, int *width, int *height, int *format, int *stride);
bool UnlockWindow(void *window);
void HandleGeckoMessage(const nsAString& message);
bool InitCamera(const nsCString& contentType, PRUint32 camera, PRUint32 *width, PRUint32 *height, PRUint32 *fps);
@ -341,7 +343,6 @@ protected:
jmethodID jGetDpi;
jmethodID jSetFullScreen;
jmethodID jShowInputMethodPicker;
jmethodID jHideProgressDialog;
jmethodID jPerformHapticFeedback;
jmethodID jSetKeepScreenOn;
jmethodID jIsNetworkLinkUp;
@ -355,6 +356,7 @@ protected:
jmethodID jPostToJavaThread;
jmethodID jInitCamera;
jmethodID jCloseCamera;
jmethodID jHandleGeckoMessage;
// stuff we need for CallEglCreateWindowSurface
jclass jEGLSurfaceImplClass;
@ -379,6 +381,27 @@ protected:
}
#define NS_ANDROIDBRIDGE_CID \
{ 0x0FE2321D, 0xEBD9, 0x467D, \
{ 0xA7, 0x43, 0x03, 0xA6, 0x8D, 0x40, 0x59, 0x9E } }
class nsAndroidBridge : public nsIAndroidBridge
{
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIANDROIDBRIDGE
nsAndroidBridge();
private:
~nsAndroidBridge();
protected:
};
extern "C" JNIEnv * GetJNIForThread();
extern bool mozilla_AndroidBridge_SetMainThread(void *);
extern jclass GetGeckoAppShellClass();

View File

@ -437,6 +437,11 @@ AndroidGeckoEvent::Init(JNIEnv *jenv, jobject jobj)
break;
}
case SAVE_STATE: {
ReadCharactersField(jenv);
break;
}
default:
break;
}

View File

@ -498,6 +498,7 @@ public:
GECKO_EVENT_SYNC = 15,
FORCED_RESIZE = 16,
ACTIVITY_START = 17,
SAVE_STATE = 18,
dummy_java_enum_list_end
};

View File

@ -44,6 +44,7 @@ include $(DEPTH)/config/autoconf.mk
MODULE = widget
LIBRARY_NAME = widget_android
XPIDL_MODULE = widget
EXPORT_LIBRARY = 1
IS_COMPONENT = 1
MODULE_NAME = nsWidgetAndroidModule
@ -79,6 +80,10 @@ NOT_THERE_YET_CPPSRCS = \
nsSound.cpp \
$(NULL)
XPIDLSRCS = \
nsIAndroidBridge.idl \
$(NULL)
SHARED_LIBRARY_LIBS = ../xpwidgets/libxpwidgets_s.a
EXPORTS = AndroidBridge.h AndroidJavaWrappers.h

View File

@ -374,6 +374,9 @@ nsAppShell::ProcessNextNativeEvent(bool mayWait)
if (!cmdline)
break;
if (curEvent->Characters().Length() == 0)
break;
char *uri = ToNewUTF8String(curEvent->Characters());
if (!uri)
break;

View File

@ -0,0 +1,7 @@
#include "nsISupports.idl"
[scriptable, uuid(32c345d4-9f45-446a-8a93-8939f3453e87)]
interface nsIAndroidBridge : nsISupports
{
void handleGeckoMessage(in AString message);
};

View File

@ -60,6 +60,7 @@
#include "nsIMEPicker.h"
#include "nsFilePickerProxy.h"
#include "nsXULAppAPI.h"
#include "AndroidBridge.h"
NS_GENERIC_FACTORY_CONSTRUCTOR(nsToolkit)
NS_GENERIC_FACTORY_CONSTRUCTOR(nsWindow)
@ -74,6 +75,8 @@ NS_GENERIC_FACTORY_CONSTRUCTOR(nsDeviceContextSpecAndroid)
NS_GENERIC_FACTORY_CONSTRUCTOR(nsHTMLFormatConverter)
NS_GENERIC_FACTORY_CONSTRUCTOR(nsIMEPicker)
NS_GENERIC_FACTORY_CONSTRUCTOR(nsAndroidBridge)
#include "GfxInfo.h"
namespace mozilla {
namespace widget {
@ -116,6 +119,7 @@ NS_DEFINE_NAMED_CID(NS_FILEPICKER_CID);
NS_DEFINE_NAMED_CID(NS_HTMLFORMATCONVERTER_CID);
NS_DEFINE_NAMED_CID(NS_IMEPICKER_CID);
NS_DEFINE_NAMED_CID(NS_GFXINFO_CID);
NS_DEFINE_NAMED_CID(NS_ANDROIDBRIDGE_CID);
static const mozilla::Module::CIDEntry kWidgetCIDs[] = {
{ &kNS_WINDOW_CID, false, NULL, nsWindowConstructor },
@ -133,6 +137,7 @@ static const mozilla::Module::CIDEntry kWidgetCIDs[] = {
{ &kNS_FILEPICKER_CID, false, NULL, nsFilePickerConstructor },
{ &kNS_HTMLFORMATCONVERTER_CID, false, NULL, nsHTMLFormatConverterConstructor },
{ &kNS_IMEPICKER_CID, false, NULL, nsIMEPickerConstructor },
{ &kNS_ANDROIDBRIDGE_CID, false, NULL, nsAndroidBridgeConstructor },
{ &kNS_GFXINFO_CID, false, NULL, mozilla::widget::GfxInfoConstructor },
{ NULL }
};
@ -153,6 +158,7 @@ static const mozilla::Module::ContractIDEntry kWidgetContracts[] = {
{ "@mozilla.org/filepicker;1", &kNS_FILEPICKER_CID },
{ "@mozilla.org/widget/htmlformatconverter;1", &kNS_HTMLFORMATCONVERTER_CID },
{ "@mozilla.org/imepicker;1", &kNS_IMEPICKER_CID },
{ "@mozilla.org/android/bridge;1", &kNS_ANDROIDBRIDGE_CID },
{ "@mozilla.org/gfx/info;1", &kNS_GFXINFO_CID },
{ NULL }
};

View File

@ -74,6 +74,8 @@ using mozilla::unused;
#include "AndroidBridge.h"
#include "imgIEncoder.h"
using namespace mozilla;
NS_IMPL_ISUPPORTS_INHERITED0(nsWindow, nsBaseWidget)
@ -725,6 +727,65 @@ nsWindow::GetThebesSurface()
return new gfxImageSurface(gfxIntSize(5,5), gfxImageSurface::ImageFormatRGB24);
}
bool
nsWindow::DrawToFile(const nsAString &path)
{
if (!IsTopLevel() || !mIsVisible) {
ALOG("### DrawToFile works only for a visible toplevel window!");
return PR_FALSE;
}
if (GetLayerManager(nsnull)->GetBackendType() != LayerManager::LAYERS_BASIC) {
ALOG("### DrawToFile works only for a basic layers!");
return PR_FALSE;
}
nsRefPtr<gfxImageSurface> imgSurface =
new gfxImageSurface(gfxIntSize(mBounds.width, mBounds.height),
gfxImageSurface::ImageFormatARGB32);
if (imgSurface->CairoStatus()) {
ALOG("### Failed to create a valid surface");
return PR_FALSE;
}
bool result = DrawTo(imgSurface);
NS_ENSURE_TRUE(result, PR_FALSE);
nsCOMPtr<imgIEncoder> encoder = do_CreateInstance("@mozilla.org/image/encoder;2?type=image/png");
NS_ENSURE_TRUE(encoder, PR_FALSE);
encoder->InitFromData(imgSurface->Data(),
imgSurface->Stride() * mBounds.height,
mBounds.width,
mBounds.height,
imgSurface->Stride(),
imgIEncoder::INPUT_FORMAT_HOSTARGB,
EmptyString());
nsCOMPtr<nsILocalFile> file;
NS_NewLocalFile(path, true, getter_AddRefs(file));
NS_ENSURE_TRUE(file, PR_FALSE);
PRUint32 length;
encoder->Available(&length);
nsCOMPtr<nsIOutputStream> outputStream;
NS_NewLocalFileOutputStream(getter_AddRefs(outputStream), file);
NS_ENSURE_TRUE(outputStream, PR_FALSE);
nsCOMPtr<nsIOutputStream> bufferedOutputStream;
NS_NewBufferedOutputStream(getter_AddRefs(bufferedOutputStream),
outputStream, length);
NS_ENSURE_TRUE(bufferedOutputStream, PR_FALSE);
PRUint32 numWritten;
bufferedOutputStream->WriteFrom(encoder, length, &numWritten);
NS_ENSURE_SUCCESS(length == numWritten, PR_FALSE);
return PR_TRUE;
}
void
nsWindow::OnGlobalAndroidEvent(AndroidGeckoEvent *ae)
{
@ -877,6 +938,10 @@ nsWindow::OnGlobalAndroidEvent(AndroidGeckoEvent *ae)
AndroidBridge::Bridge()->AcknowledgeEventSync();
break;
case AndroidGeckoEvent::SAVE_STATE:
win->DrawToFile(ae->Characters());
break;
default:
break;
}
@ -1016,8 +1081,6 @@ nsWindow::OnDraw(AndroidGeckoEvent *ae)
NS_ASSERTION(!sview.isNull(), "SurfaceView is null!");
AndroidBridge::Bridge()->HideProgressDialogOnce();
if (GetLayerManager(nsnull)->GetBackendType() == LayerManager::LAYERS_BASIC) {
if (sNativeWindow) {
unsigned char *bits;

View File

@ -174,6 +174,7 @@ protected:
void BringToFront();
nsWindow *FindTopLevel();
bool DrawTo(gfxASurface *targetSurface);
bool DrawToFile(const nsAString &path);
bool IsTopLevel();
void OnIMEAddRange(mozilla::AndroidGeckoEvent *ae);

View File

@ -53,6 +53,10 @@
#include "nsConsoleMessage.h"
#include "nsIClassInfoImpl.h"
#if defined(ANDROID)
#include <android/log.h>
#endif
using namespace mozilla;
NS_IMPL_THREADSAFE_ADDREF(nsConsoleService)
@ -189,6 +193,12 @@ nsConsoleService::LogMessage(nsIConsoleMessage *message)
NS_IMETHODIMP
nsConsoleService::LogStringMessage(const PRUnichar *message)
{
#if defined(ANDROID)
__android_log_print(ANDROID_LOG_ERROR, "nsConsoleService",
"%s",
NS_LossyConvertUTF16toASCII(message).get());
#endif
nsConsoleMessage *msg = new nsConsoleMessage(message);
return this->LogMessage(msg);
}